Wed Jun 21 22:04:13 2023 UTC ()
Pull up following revision(s) (requested by riastradh in ticket #1844):

	lib/libpam/modules/pam_krb5/pam_krb5.c: revision 1.31
	lib/libpam/modules/pam_krb5/pam_krb5.8: revision 1.13

pam_krb5: Refuse to operate without a key to verify tickets.

New allow_kdc_spoof overrides this to restore previous behaviour
which was vulnerable to KDC spoofing, because without a host or
service key, pam_krb5 can't distinguish the legitimate KDC from a
spoofed one.

This way, having pam_krb5 enabled isn't dangerous even if you create
an empty /etc/krb5.conf to use client SSO without any host services.

Perhaps this should use krb5_verify_init_creds(3) instead, and
thereby respect the rather obscurely named krb5.conf option
verify_ap_req_nofail like the Linux pam_krb5 does, but:
- verify_ap_req_nofail is default-off (i.e., vulnerable by default),
- changing verify_ap_req_nofail to default-on would probably affect
  more things and therefore be riskier,
- allow_kdc_spoof is a much clearer way to spell the idea,
- this patch is a smaller semantic change and thus less risky, and
- a security change with compatibility issues shouldn't have a
  workaround that might introduce potentially worse security issues
  or more compatibility issues.

Perhaps this should use krb5_verify_user(3) with secure=1 instead,
for simplicity, but it's not clear how to do that without first
prompting for the password -- which we shouldn't do at all if we
later decide we won't be able to use it anyway -- and without
repeating a bunch of the logic here anyway to pick the service name.

References about verify_ap_req_nofail:
- mit-krb5 discussion about verify_ap_req_nofail:
  https://mailman.mit.edu/pipermail/krbdev/2011-January/009778.html
- Oracle has the default-secure setting in their krb5 system:
  https://docs.oracle.com/cd/E26505_01/html/E27224/setup-148.html
  https://docs.oracle.com/cd/E26505_01/html/816-5174/krb5.conf-4.html#REFMAN4krb5.conf-4
  https://docs.oracle.com/cd/E19253-01/816-4557/gihyu/
- Heimdal issue on verify_ap_req_nofail default:
  https://github.com/heimdal/heimdal/issues/1129


(martin)
diff -r1.11 -r1.11.40.1 src/lib/libpam/modules/pam_krb5/pam_krb5.8
diff -r1.26 -r1.26.18.1 src/lib/libpam/modules/pam_krb5/pam_krb5.c

cvs diff -r1.11 -r1.11.40.1 src/lib/libpam/modules/pam_krb5/pam_krb5.8 (expand / switch to unified diff)

--- src/lib/libpam/modules/pam_krb5/pam_krb5.8 2008/12/02 22:52:06 1.11
+++ src/lib/libpam/modules/pam_krb5/pam_krb5.8 2023/06/21 22:04:13 1.11.40.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1.\" $NetBSD: pam_krb5.8,v 1.11 2008/12/02 22:52:06 reed Exp $ 1.\" $NetBSD: pam_krb5.8,v 1.11.40.1 2023/06/21 22:04:13 martin Exp $
2.\" $FreeBSD: src/lib/libpam/modules/pam_krb5/pam_krb5.8,v 1.6 2001/11/24 23:41:32 dd Exp $ 2.\" $FreeBSD: src/lib/libpam/modules/pam_krb5/pam_krb5.8,v 1.6 2001/11/24 23:41:32 dd Exp $
3.\" 3.\"
4.\" Copyright (c) Frank Cusack, 1999-2001. All rights reserved. 4.\" Copyright (c) Frank Cusack, 1999-2001. All rights reserved.
5.\" 5.\"
6.\" Redistribution and use in source and binary forms, with or without 6.\" Redistribution and use in source and binary forms, with or without
7.\" modification, are permitted provided that the following conditions 7.\" modification, are permitted provided that the following conditions
8.\" are met: 8.\" are met:
9.\" 1. Redistributions of source code must retain the above copyright 9.\" 1. Redistributions of source code must retain the above copyright
10.\" notices, and the entire permission notice in its entirety, 10.\" notices, and the entire permission notice in its entirety,
11.\" including the disclaimer of warranties. 11.\" including the disclaimer of warranties.
12.\" 2. Redistributions in binary form must reproduce the above copyright 12.\" 2. Redistributions in binary form must reproduce the above copyright
13.\" notice, this list of conditions and the following disclaimer in the 13.\" notice, this list of conditions and the following disclaimer in the
14.\" documentation and/or other materials provided with the distribution. 14.\" documentation and/or other materials provided with the distribution.
@@ -132,26 +132,41 @@ is not a recommendation to use the modul @@ -132,26 +132,41 @@ is not a recommendation to use the modul
132Use 132Use
133.Ar name 133.Ar name
134as the credentials cache. 134as the credentials cache.
135.Ar name 135.Ar name
136must be in the form 136must be in the form
137.Ar type : Ns Ar residual . 137.Ar type : Ns Ar residual .
138The special tokens 138The special tokens
139.Ql %u , 139.Ql %u ,
140to designate the decimal UID of the user; 140to designate the decimal UID of the user;
141and 141and
142.Ql %p , 142.Ql %p ,
143to designate the current process ID; can be used in 143to designate the current process ID; can be used in
144.Ar name . 144.Ar name .
 145.It Cm allow_kdc_spoof
 146Allow
 147.Nm
 148to succeed even if there is no host or service key available in a
 149keytab to authenticate the Kerberos KDC's ticket.
 150If there is no such key, for example on a host with no keytabs,
 151.Nm
 152will fail immediately without prompting the user.
 153.Pp
 154.Sy Warning :
 155If the host has not been configured with a keytab from the KDC, setting
 156this option makes it vulnerable to malicious KDCs, e.g. via DNS
 157flooding, because
 158.Nm
 159has no way to distinguish the legitimate KDC from a spoofed KDC.
145.El 160.El
146.Ss Kerberos 5 Account Management Module 161.Ss Kerberos 5 Account Management Module
147The Kerberos 5 account management component 162The Kerberos 5 account management component
148provides a function to perform account management, 163provides a function to perform account management,
149.Fn pam_sm_acct_mgmt . 164.Fn pam_sm_acct_mgmt .
150The function verifies that the authenticated principal is allowed 165The function verifies that the authenticated principal is allowed
151to login to the local user account by calling 166to login to the local user account by calling
152.Fn krb5_kuserok 167.Fn krb5_kuserok
153(which checks the user's 168(which checks the user's
154.Pa .k5login 169.Pa .k5login
155file). 170file).
156.Ss Kerberos 5 Password Management Module 171.Ss Kerberos 5 Password Management Module
157The Kerberos 5 password management component 172The Kerberos 5 password management component

cvs diff -r1.26 -r1.26.18.1 src/lib/libpam/modules/pam_krb5/pam_krb5.c (expand / switch to unified diff)

--- src/lib/libpam/modules/pam_krb5/pam_krb5.c 2013/12/28 18:04:03 1.26
+++ src/lib/libpam/modules/pam_krb5/pam_krb5.c 2023/06/21 22:04:13 1.26.18.1
@@ -1,14 +1,14 @@ @@ -1,14 +1,14 @@
1/* $NetBSD: pam_krb5.c,v 1.26 2013/12/28 18:04:03 christos Exp $ */ 1/* $NetBSD: pam_krb5.c,v 1.26.18.1 2023/06/21 22:04:13 martin Exp $ */
2 2
3/*- 3/*-
4 * This pam_krb5 module contains code that is: 4 * This pam_krb5 module contains code that is:
5 * Copyright (c) Derrick J. Brashear, 1996. All rights reserved. 5 * Copyright (c) Derrick J. Brashear, 1996. All rights reserved.
6 * Copyright (c) Frank Cusack, 1999-2001. All rights reserved. 6 * Copyright (c) Frank Cusack, 1999-2001. All rights reserved.
7 * Copyright (c) Jacques A. Vidrine, 2000-2001. All rights reserved. 7 * Copyright (c) Jacques A. Vidrine, 2000-2001. All rights reserved.
8 * Copyright (c) Nicolas Williams, 2001. All rights reserved. 8 * Copyright (c) Nicolas Williams, 2001. All rights reserved.
9 * Copyright (c) Perot Systems Corporation, 2001. All rights reserved. 9 * Copyright (c) Perot Systems Corporation, 2001. All rights reserved.
10 * Copyright (c) Mark R V Murray, 2001. All rights reserved. 10 * Copyright (c) Mark R V Murray, 2001. All rights reserved.
11 * Copyright (c) Networks Associates Technology, Inc., 2002-2005. 11 * Copyright (c) Networks Associates Technology, Inc., 2002-2005.
12 * All rights reserved. 12 * All rights reserved.
13 * 13 *
14 * Portions of this software were developed for the FreeBSD Project by 14 * Portions of this software were developed for the FreeBSD Project by
@@ -43,27 +43,27 @@ @@ -43,27 +43,27 @@
43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 43 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
44 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 44 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, 45 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 46 * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED 47 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
48 * OF THE POSSIBILITY OF SUCH DAMAGE. 48 * OF THE POSSIBILITY OF SUCH DAMAGE.
49 * 49 *
50 */ 50 */
51 51
52#include <sys/cdefs.h> 52#include <sys/cdefs.h>
53#ifdef __FreeBSD__ 53#ifdef __FreeBSD__
54__FBSDID("$FreeBSD: src/lib/libpam/modules/pam_krb5/pam_krb5.c,v 1.22 2005/01/24 16:49:50 rwatson Exp $"); 54__FBSDID("$FreeBSD: src/lib/libpam/modules/pam_krb5/pam_krb5.c,v 1.22 2005/01/24 16:49:50 rwatson Exp $");
55#else 55#else
56__RCSID("$NetBSD: pam_krb5.c,v 1.26 2013/12/28 18:04:03 christos Exp $"); 56__RCSID("$NetBSD: pam_krb5.c,v 1.26.18.1 2023/06/21 22:04:13 martin Exp $");
57#endif 57#endif
58 58
59#include <sys/types.h> 59#include <sys/types.h>
60#include <sys/stat.h> 60#include <sys/stat.h>
61#include <errno.h> 61#include <errno.h>
62#include <limits.h> 62#include <limits.h>
63#include <pwd.h> 63#include <pwd.h>
64#include <stdio.h> 64#include <stdio.h>
65#include <stdlib.h> 65#include <stdlib.h>
66#include <string.h> 66#include <string.h>
67#include <syslog.h> 67#include <syslog.h>
68#include <unistd.h> 68#include <unistd.h>
69 69
@@ -75,51 +75,62 @@ __RCSID("$NetBSD: pam_krb5.c,v 1.26 2013 @@ -75,51 +75,62 @@ __RCSID("$NetBSD: pam_krb5.c,v 1.26 2013
75#define PAM_SM_ACCOUNT 75#define PAM_SM_ACCOUNT
76#define PAM_SM_PASSWORD 76#define PAM_SM_PASSWORD
77 77
78#include <security/pam_appl.h> 78#include <security/pam_appl.h>
79#include <security/pam_modules.h> 79#include <security/pam_modules.h>
80#include <security/pam_mod_misc.h> 80#include <security/pam_mod_misc.h>
81#include <security/openpam.h> 81#include <security/openpam.h>
82 82
83#define COMPAT_HEIMDAL 83#define COMPAT_HEIMDAL
84/* #define COMPAT_MIT */ 84/* #define COMPAT_MIT */
85 85
86static void log_krb5(krb5_context, krb5_error_code, struct syslog_data *, 86static void log_krb5(krb5_context, krb5_error_code, struct syslog_data *,
87 const char *, ...) __printflike(4, 5); 87 const char *, ...) __printflike(4, 5);
88static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int); 88static int verify_krb_v5_tgt_begin(krb5_context, char *, int,
 89 const char **, krb5_principal *, char[static BUFSIZ], struct syslog_data *);
 90static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int,
 91 const char *, krb5_principal, char[static BUFSIZ], struct syslog_data *);
 92static void verify_krb_v5_tgt_cleanup(krb5_context, int,
 93 const char *, krb5_principal, char[static BUFSIZ], struct syslog_data *);
89static void cleanup_cache(pam_handle_t *, void *, int); 94static void cleanup_cache(pam_handle_t *, void *, int);
90static const char *compat_princ_component(krb5_context, krb5_principal, int); 95static const char *compat_princ_component(krb5_context, krb5_principal, int);
91static void compat_free_data_contents(krb5_context, krb5_data *); 96static void compat_free_data_contents(krb5_context, krb5_data *);
92 97
93#define USER_PROMPT "Username: " 98#define USER_PROMPT "Username: "
94#define PASSWORD_PROMPT "%s's password:" 99#define PASSWORD_PROMPT "%s's password:"
95#define NEW_PASSWORD_PROMPT "New Password:" 100#define NEW_PASSWORD_PROMPT "New Password:"
96 101
97#define PAM_OPT_CCACHE "ccache" 102#define PAM_OPT_CCACHE "ccache"
98#define PAM_OPT_DEBUG "debug" 103#define PAM_OPT_DEBUG "debug"
99#define PAM_OPT_FORWARDABLE "forwardable" 104#define PAM_OPT_FORWARDABLE "forwardable"
100#define PAM_OPT_RENEWABLE "renewable" 105#define PAM_OPT_RENEWABLE "renewable"
101#define PAM_OPT_NO_CCACHE "no_ccache" 106#define PAM_OPT_NO_CCACHE "no_ccache"
102#define PAM_OPT_REUSE_CCACHE "reuse_ccache" 107#define PAM_OPT_REUSE_CCACHE "reuse_ccache"
 108#define PAM_OPT_ALLOW_KDC_SPOOF "allow_kdc_spoof"
103 109
104/* 110/*
105 * authentication management 111 * authentication management
106 */ 112 */
107PAM_EXTERN int 113PAM_EXTERN int
108pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, 114pam_sm_authenticate(pam_handle_t *pamh, int flags __unused,
109 int argc __unused, const char *argv[] __unused) 115 int argc __unused, const char *argv[] __unused)
110{ 116{
111 krb5_error_code krbret; 117 krb5_error_code krbret;
112 krb5_context pam_context; 118 krb5_context pam_context;
 119 int debug;
 120 const char *auth_service;
 121 krb5_principal auth_princ;
 122 char auth_phost[BUFSIZ];
 123 struct syslog_data auth_data = SYSLOG_DATA_INIT;
113 krb5_creds creds; 124 krb5_creds creds;
114 krb5_principal princ; 125 krb5_principal princ;
115 krb5_ccache ccache; 126 krb5_ccache ccache;
116 krb5_get_init_creds_opt *opts = NULL; 127 krb5_get_init_creds_opt *opts = NULL;
117 struct passwd *pwd, pwres; 128 struct passwd *pwd, pwres;
118 int retval; 129 int retval;
119 const void *ccache_data; 130 const void *ccache_data;
120 const char *user, *pass; 131 const char *user, *pass;
121 const void *sourceuser, *service; 132 const void *sourceuser, *service;
122 char *principal, *princ_name, *ccache_name, luser[32], *srvdup; 133 char *principal, *princ_name, *ccache_name, luser[32], *srvdup;
123 char password_prompt[80]; 134 char password_prompt[80];
124 char pwbuf[1024]; 135 char pwbuf[1024];
125 const char *rtime; 136 const char *rtime;
@@ -134,38 +145,66 @@ pam_sm_authenticate(pam_handle_t *pamh,  @@ -134,38 +145,66 @@ pam_sm_authenticate(pam_handle_t *pamh,
134 retval = pam_get_item(pamh, PAM_RUSER, &sourceuser); 145 retval = pam_get_item(pamh, PAM_RUSER, &sourceuser);
135 if (retval != PAM_SUCCESS) 146 if (retval != PAM_SUCCESS)
136 return (retval); 147 return (retval);
137 148
138 PAM_LOG("Got ruser: %s", (const char *)sourceuser); 149 PAM_LOG("Got ruser: %s", (const char *)sourceuser);
139 150
140 service = NULL; 151 service = NULL;
141 pam_get_item(pamh, PAM_SERVICE, &service); 152 pam_get_item(pamh, PAM_SERVICE, &service);
142 if (service == NULL) 153 if (service == NULL)
143 service = "unknown"; 154 service = "unknown";
144 155
145 PAM_LOG("Got service: %s", (const char *)service); 156 PAM_LOG("Got service: %s", (const char *)service);
146 157
 158 if ((srvdup = strdup(service)) == NULL) {
 159 retval = PAM_BUF_ERR;
 160 goto cleanup6;
 161 }
 162
147 krbret = krb5_init_context(&pam_context); 163 krbret = krb5_init_context(&pam_context);
148 if (krbret != 0) { 164 if (krbret != 0) {
149 PAM_VERBOSE_ERROR("Kerberos 5 error"); 165 PAM_VERBOSE_ERROR("Kerberos 5 error");
150 return (PAM_SERVICE_ERR); 166 retval = PAM_SERVICE_ERR;
 167 goto cleanup5;
151 } 168 }
152 169
153 PAM_LOG("Context initialised"); 170 PAM_LOG("Context initialised");
154 171
 172 debug = openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0;
 173 krbret = verify_krb_v5_tgt_begin(pam_context, srvdup, debug,
 174 &auth_service, &auth_princ, auth_phost, &auth_data);
 175 if (krbret != 0) { /* failed to find key */
 176 /* Keytab or service key does not exist */
 177 if (debug)
 178 log_krb5(pam_context, krbret, &auth_data,
 179 "pam_krb5: verify_krb_v5_tgt: "
 180 "krb5_kt_read_service_key");
 181 /*
 182 * Give up now because we can't authenticate the KDC
 183 * with a keytab, unless the administrator asked to
 184 * have the traditional behaviour of being vulnerable
 185 * to spoofed KDCs.
 186 */
 187 if (!openpam_get_option(pamh, PAM_OPT_ALLOW_KDC_SPOOF)) {
 188 retval = PAM_SERVICE_ERR;
 189 goto cleanup4;
 190 }
 191 }
 192
155 krbret = krb5_get_init_creds_opt_alloc(pam_context, &opts); 193 krbret = krb5_get_init_creds_opt_alloc(pam_context, &opts);
156 if (krbret != 0) { 194 if (krbret != 0) {
157 PAM_VERBOSE_ERROR("Kerberos 5 error"); 195 PAM_VERBOSE_ERROR("Kerberos 5 error");
158 return (PAM_SERVICE_ERR); 196 retval = PAM_SERVICE_ERR;
 197 goto cleanup4;
159 } 198 }
160 199
161 if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE)) 200 if (openpam_get_option(pamh, PAM_OPT_FORWARDABLE))
162 krb5_get_init_creds_opt_set_forwardable(opts, 1); 201 krb5_get_init_creds_opt_set_forwardable(opts, 1);
163 202
164 if ((rtime = openpam_get_option(pamh, PAM_OPT_RENEWABLE)) != NULL) { 203 if ((rtime = openpam_get_option(pamh, PAM_OPT_RENEWABLE)) != NULL) {
165 krb5_deltat renew; 204 krb5_deltat renew;
166 char rbuf[80], *rp; 205 char rbuf[80], *rp;
167 206
168 if (*rtime) { 207 if (*rtime) {
169 (void)strlcpy(rbuf, rtime, sizeof(rbuf)); 208 (void)strlcpy(rbuf, rtime, sizeof(rbuf));
170 rtime = rbuf; 209 rtime = rbuf;
171 for (rp = rbuf; *rp; rp++) 210 for (rp = rbuf; *rp; rp++)
@@ -289,32 +328,29 @@ pam_sm_authenticate(pam_handle_t *pamh,  @@ -289,32 +328,29 @@ pam_sm_authenticate(pam_handle_t *pamh,
289 } 328 }
290 krbret = krb5_cc_store_cred(pam_context, ccache, &creds); 329 krbret = krb5_cc_store_cred(pam_context, ccache, &creds);
291 if (krbret != 0) { 330 if (krbret != 0) {
292 PAM_VERBOSE_ERROR("Kerberos 5 error"); 331 PAM_VERBOSE_ERROR("Kerberos 5 error");
293 log_krb5(pam_context, krbret, NULL, "krb5_cc_store_cred"); 332 log_krb5(pam_context, krbret, NULL, "krb5_cc_store_cred");
294 krb5_cc_destroy(pam_context, ccache); 333 krb5_cc_destroy(pam_context, ccache);
295 retval = PAM_SERVICE_ERR; 334 retval = PAM_SERVICE_ERR;
296 goto cleanup; 335 goto cleanup;
297 } 336 }
298 337
299 PAM_LOG("Credentials stashed"); 338 PAM_LOG("Credentials stashed");
300 339
301 /* Verify them */ 340 /* Verify them */
302 if ((srvdup = strdup(service)) == NULL) { 
303 retval = PAM_BUF_ERR; 
304 goto cleanup; 
305 } 
306 krbret = verify_krb_v5_tgt(pam_context, ccache, srvdup, 341 krbret = verify_krb_v5_tgt(pam_context, ccache, srvdup,
307 openpam_get_option(pamh, PAM_OPT_DEBUG) ? 1 : 0); 342 debug,
 343 auth_service, auth_princ, auth_phost, &auth_data);
308 free(srvdup); 344 free(srvdup);
309 if (krbret == -1) { 345 if (krbret == -1) {
310 PAM_VERBOSE_ERROR("Kerberos 5 error"); 346 PAM_VERBOSE_ERROR("Kerberos 5 error");
311 krb5_cc_destroy(pam_context, ccache); 347 krb5_cc_destroy(pam_context, ccache);
312 retval = PAM_AUTH_ERR; 348 retval = PAM_AUTH_ERR;
313 goto cleanup; 349 goto cleanup;
314 } 350 }
315 351
316 PAM_LOG("Credentials stash verified"); 352 PAM_LOG("Credentials stash verified");
317 353
318 retval = pam_get_data(pamh, "ccache", &ccache_data); 354 retval = pam_get_data(pamh, "ccache", &ccache_data);
319 if (retval == PAM_SUCCESS) { 355 if (retval == PAM_SUCCESS) {
320 krb5_cc_destroy(pam_context, ccache); 356 krb5_cc_destroy(pam_context, ccache);
@@ -344,31 +380,36 @@ pam_sm_authenticate(pam_handle_t *pamh,  @@ -344,31 +380,36 @@ pam_sm_authenticate(pam_handle_t *pamh,
344 380
345cleanup: 381cleanup:
346 krb5_free_cred_contents(pam_context, &creds); 382 krb5_free_cred_contents(pam_context, &creds);
347 PAM_LOG("Done cleanup"); 383 PAM_LOG("Done cleanup");
348cleanup2: 384cleanup2:
349 krb5_free_principal(pam_context, princ); 385 krb5_free_principal(pam_context, princ);
350 PAM_LOG("Done cleanup2"); 386 PAM_LOG("Done cleanup2");
351cleanup3: 387cleanup3:
352 if (princ_name) 388 if (princ_name)
353 free(princ_name); 389 free(princ_name);
354 390
355 if (opts) 391 if (opts)
356 krb5_get_init_creds_opt_free(pam_context, opts); 392 krb5_get_init_creds_opt_free(pam_context, opts);
 393cleanup4:
 394 verify_krb_v5_tgt_cleanup(pam_context, debug,
 395 auth_service, auth_princ, auth_phost, &auth_data);
357 396
358 krb5_free_context(pam_context); 397 krb5_free_context(pam_context);
 398cleanup5:
 399 free(srvdup);
359 400
360 PAM_LOG("Done cleanup3"); 401 PAM_LOG("Done cleanup5");
361 402cleanup6:
362 if (retval != PAM_SUCCESS) 403 if (retval != PAM_SUCCESS)
363 PAM_VERBOSE_ERROR("Kerberos 5 refuses you"); 404 PAM_VERBOSE_ERROR("Kerberos 5 refuses you");
364 405
365 return (retval); 406 return (retval);
366} 407}
367 408
368PAM_EXTERN int 409PAM_EXTERN int
369pam_sm_setcred(pam_handle_t *pamh, int flags, 410pam_sm_setcred(pam_handle_t *pamh, int flags,
370 int argc __unused, const char *argv[] __unused) 411 int argc __unused, const char *argv[] __unused)
371{ 412{
372 413
373 krb5_error_code krbret; 414 krb5_error_code krbret;
374 krb5_context pam_context; 415 krb5_context pam_context;
@@ -874,140 +915,156 @@ log_krb5(krb5_context ctx, krb5_error_co @@ -874,140 +915,156 @@ log_krb5(krb5_context ctx, krb5_error_co
874 915
875/* 916/*
876 * This routine with some modification is from the MIT V5B6 appl/bsd/login.c 917 * This routine with some modification is from the MIT V5B6 appl/bsd/login.c
877 * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services 918 * Modified by Sam Hartman <hartmans@mit.edu> to support PAM services
878 * for Debian. 919 * for Debian.
879 * 920 *
880 * Verify the Kerberos ticket-granting ticket just retrieved for the 921 * Verify the Kerberos ticket-granting ticket just retrieved for the
881 * user. If the Kerberos server doesn't respond, assume the user is 922 * user. If the Kerberos server doesn't respond, assume the user is
882 * trying to fake us out (since we DID just get a TGT from what is 923 * trying to fake us out (since we DID just get a TGT from what is
883 * supposedly our KDC). If the host/<host> service is unknown (i.e., 924 * supposedly our KDC). If the host/<host> service is unknown (i.e.,
884 * the local keytab doesn't have it), and we cannot find another 925 * the local keytab doesn't have it), and we cannot find another
885 * service we do have, let her in. 926 * service we do have, let her in.
886 * 927 *
887 * Returns 1 for confirmation, -1 for failure, 0 for uncertainty. 928 * - verify_krb_v5_tgt_begin returns a krb5 error code.
 929 * - verify_krb_v5_tgt returns 0 on success, -1 on failure.
888 */ 930 */
889/* ARGSUSED */ 931/* ARGSUSED */
890static int 932static int
891verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache, 933verify_krb_v5_tgt_begin(krb5_context context, char *pam_service, int debug,
892 char *pam_service, int debug) 934 const char **servicep, krb5_principal *princp, char phost[static BUFSIZ],
 935 struct syslog_data *datap)
893{ 936{
894 krb5_error_code retval; 937 krb5_error_code retval;
895 krb5_principal princ; 938 krb5_principal princ;
896 krb5_keyblock *keyblock; 939 krb5_keyblock *keyblock;
897 krb5_data packet; 
898 krb5_auth_context auth_context = NULL; 
899 char phost[BUFSIZ]; 
900 const char *services[3], **service; 940 const char *services[3], **service;
901 struct syslog_data data = SYSLOG_DATA_INIT; 
902 941
903 packet.data = 0; 942 *servicep = NULL;
904 943
905 if (debug) 944 if (debug)
906 openlog_r("pam_krb5", LOG_PID, LOG_AUTHPRIV, &data); 945 openlog_r("pam_krb5", LOG_PID, LOG_AUTHPRIV, datap);
907 946
908 /* If possible we want to try and verify the ticket we have 947 /* If possible we want to try and verify the ticket we have
909 * received against a keytab. We will try multiple service 948 * received against a keytab. We will try multiple service
910 * principals, including at least the host principal and the PAM 949 * principals, including at least the host principal and the PAM
911 * service principal. The host principal is preferred because access 950 * service principal. The host principal is preferred because access
912 * to that key is generally sufficient to compromise root, while the 951 * to that key is generally sufficient to compromise root, while the
913 * service key for this PAM service may be less carefully guarded. 952 * service key for this PAM service may be less carefully guarded.
914 * It is important to check the keytab first before the KDC so we do 953 * It is important to check the keytab first before the KDC so we do
915 * not get spoofed by a fake KDC. 954 * not get spoofed by a fake KDC.
916 */ 955 */
917 services[0] = "host"; 956 services[0] = "host";
918 services[1] = pam_service; 957 services[1] = pam_service;
919 services[2] = NULL; 958 services[2] = NULL;
920 keyblock = 0; 959 keyblock = 0;
921 retval = -1; 960 retval = -1;
922 for (service = &services[0]; *service != NULL; service++) { 961 for (service = &services[0]; *service != NULL; service++) {
923 retval = krb5_sname_to_principal(context, NULL, *service, 962 retval = krb5_sname_to_principal(context, NULL, *service,
924 KRB5_NT_SRV_HST, &princ); 963 KRB5_NT_SRV_HST, &princ);
925 if (retval != 0 && debug) 964 if (retval != 0 && debug)
926 log_krb5(context, retval, &data, 965 log_krb5(context, retval, datap,
927 "pam_krb5: verify_krb_v5_tgt: " 966 "pam_krb5: verify_krb_v5_tgt: "
928 "krb5_sname_to_principal"); 967 "krb5_sname_to_principal");
929 if (retval != 0) 968 if (retval != 0)
930 return -1; 969 return (retval);
931 970
932 /* Extract the name directly. */ 971 /* Extract the name directly. */
933 strncpy(phost, compat_princ_component(context, princ, 1), 972 strncpy(phost, compat_princ_component(context, princ, 1),
934 BUFSIZ); 973 BUFSIZ);
935 phost[BUFSIZ - 1] = '\0'; 974 phost[BUFSIZ - 1] = '\0';
936 975
937 /* 976 /*
938 * Do we have service/<host> keys? 977 * Do we have service/<host> keys?
939 * (use default/configured keytab, kvno IGNORE_VNO to get the 978 * (use default/configured keytab, kvno IGNORE_VNO to get the
940 * first match, and ignore enctype.) 979 * first match, and ignore enctype.)
941 */ 980 */
942 retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0, 981 retval = krb5_kt_read_service_key(context, NULL, princ, 0, 0,
943 &keyblock); 982 &keyblock);
944 if (retval != 0) 983 if (retval != 0)
945 continue; 984 continue;
946 break; 985 break;
947 } 986 }
948 if (retval != 0) { /* failed to find key */ 
949 /* Keytab or service key does not exist */ 
950 if (debug) 
951 log_krb5(context, retval, &data, 
952 "pam_krb5: verify_krb_v5_tgt: " 
953 "krb5_kt_read_service_key"); 
954 retval = 0; 
955 goto cleanup; 
956 } 
957 if (keyblock) 987 if (keyblock)
958 krb5_free_keyblock(context, keyblock); 988 krb5_free_keyblock(context, keyblock);
959 989
 990 return (retval);
 991}
 992
 993static int
 994verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache,
 995 char *pam_service, int debug,
 996 const char *service, krb5_principal princ, char phost[static BUFSIZ],
 997 struct syslog_data *datap)
 998{
 999 krb5_error_code retval;
 1000 krb5_auth_context auth_context = NULL;
 1001 krb5_data packet;
 1002
 1003 if (service == NULL)
 1004 return (0); /* uncertain, can't authenticate KDC */
 1005
 1006 packet.data = 0;
 1007
960 /* Talk to the kdc and construct the ticket. */ 1008 /* Talk to the kdc and construct the ticket. */
961 auth_context = NULL; 1009 auth_context = NULL;
962 retval = krb5_mk_req(context, &auth_context, 0, *service, phost, 1010 retval = krb5_mk_req(context, &auth_context, 0, service, phost,
963 NULL, ccache, &packet); 1011 NULL, ccache, &packet);
964 if (auth_context) { 1012 if (auth_context) {
965 krb5_auth_con_free(context, auth_context); 1013 krb5_auth_con_free(context, auth_context);
966 auth_context = NULL; /* setup for rd_req */ 1014 auth_context = NULL; /* setup for rd_req */
967 } 1015 }
968 if (retval) { 1016 if (retval) {
969 if (debug) 1017 if (debug)
970 log_krb5(context, retval, &data, 1018 log_krb5(context, retval, datap,
971 "pam_krb5: verify_krb_v5_tgt: " 1019 "pam_krb5: verify_krb_v5_tgt: "
972 "krb5_mk_req"); 1020 "krb5_mk_req");
973 retval = -1; 1021 retval = -1;
974 goto cleanup; 1022 goto cleanup;
975 } 1023 }
976 1024
977 /* Try to use the ticket. */ 1025 /* Try to use the ticket. */
978 retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL, 1026 retval = krb5_rd_req(context, &auth_context, &packet, princ, NULL,
979 NULL, NULL); 1027 NULL, NULL);
980 if (retval) { 1028 if (retval) {
981 if (debug) 1029 if (debug)
982 log_krb5(context, retval, &data, 1030 log_krb5(context, retval, datap,
983 "pam_krb5: verify_krb_v5_tgt: " 1031 "pam_krb5: verify_krb_v5_tgt: "
984 "krb5_rd_req"); 1032 "krb5_rd_req");
985 retval = -1; 1033 retval = -1;
986 } 1034 }
987 else 1035 else
988 retval = 1; 1036 retval = 1;
989 1037
990cleanup: 1038cleanup:
991 if (debug) 
992 closelog_r(&data); 
993 if (packet.data) 1039 if (packet.data)
994 compat_free_data_contents(context, &packet); 1040 compat_free_data_contents(context, &packet);
995 if (auth_context) { 1041 if (auth_context) {
996 krb5_auth_con_free(context, auth_context); 1042 krb5_auth_con_free(context, auth_context);
997 auth_context = NULL; /* setup for rd_req */ 1043 auth_context = NULL; /* setup for rd_req */
998 } 1044 }
999 krb5_free_principal(context, princ); 1045 return (retval);
1000 return retval; 1046}
 1047
 1048static void
 1049verify_krb_v5_tgt_cleanup(krb5_context context, int debug,
 1050 const char *service, krb5_principal princ, char phost[static BUFSIZ],
 1051 struct syslog_data *datap)
 1052{
 1053
 1054 if (service)
 1055 krb5_free_principal(context, princ);
 1056 if (debug)
 1057 closelog_r(datap);
1001} 1058}
1002 1059
1003/* Free the memory for cache_name. Called by pam_end() */ 1060/* Free the memory for cache_name. Called by pam_end() */
1004/* ARGSUSED */ 1061/* ARGSUSED */
1005static void 1062static void
1006cleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused) 1063cleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused)
1007{ 1064{
1008 krb5_context pam_context; 1065 krb5_context pam_context;
1009 krb5_ccache ccache; 1066 krb5_ccache ccache;
1010 krb5_error_code krbret; 1067 krb5_error_code krbret;
1011 1068
1012 if (krb5_init_context(&pam_context)) 1069 if (krb5_init_context(&pam_context))
1013 return; 1070 return;