| @@ -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 | |
86 | static void log_krb5(krb5_context, krb5_error_code, struct syslog_data *, | | 86 | static void log_krb5(krb5_context, krb5_error_code, struct syslog_data *, |
87 | const char *, ...) __printflike(4, 5); | | 87 | const char *, ...) __printflike(4, 5); |
88 | static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int); | | 88 | static int verify_krb_v5_tgt_begin(krb5_context, char *, int, |
| | | 89 | const char **, krb5_principal *, char[static BUFSIZ], struct syslog_data *); |
| | | 90 | static int verify_krb_v5_tgt(krb5_context, krb5_ccache, char *, int, |
| | | 91 | const char *, krb5_principal, char[static BUFSIZ], struct syslog_data *); |
| | | 92 | static void verify_krb_v5_tgt_cleanup(krb5_context, int, |
| | | 93 | const char *, krb5_principal, char[static BUFSIZ], struct syslog_data *); |
89 | static void cleanup_cache(pam_handle_t *, void *, int); | | 94 | static void cleanup_cache(pam_handle_t *, void *, int); |
90 | static const char *compat_princ_component(krb5_context, krb5_principal, int); | | 95 | static const char *compat_princ_component(krb5_context, krb5_principal, int); |
91 | static void compat_free_data_contents(krb5_context, krb5_data *); | | 96 | static 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 | */ |
107 | PAM_EXTERN int | | 113 | PAM_EXTERN int |
108 | pam_sm_authenticate(pam_handle_t *pamh, int flags __unused, | | 114 | pam_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 | |
345 | cleanup: | | 381 | cleanup: |
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"); |
348 | cleanup2: | | 384 | cleanup2: |
349 | krb5_free_principal(pam_context, princ); | | 385 | krb5_free_principal(pam_context, princ); |
350 | PAM_LOG("Done cleanup2"); | | 386 | PAM_LOG("Done cleanup2"); |
351 | cleanup3: | | 387 | cleanup3: |
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); |
| | | 393 | cleanup4: |
| | | 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); |
| | | 398 | cleanup5: |
| | | 399 | free(srvdup); |
359 | | | 400 | |
360 | PAM_LOG("Done cleanup3"); | | 401 | PAM_LOG("Done cleanup5"); |
361 | | | 402 | cleanup6: |
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 | |
368 | PAM_EXTERN int | | 409 | PAM_EXTERN int |
369 | pam_sm_setcred(pam_handle_t *pamh, int flags, | | 410 | pam_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 */ |
890 | static int | | 932 | static int |
891 | verify_krb_v5_tgt(krb5_context context, krb5_ccache ccache, | | 933 | verify_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 | |
| | | 993 | static int |
| | | 994 | verify_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 | |
990 | cleanup: | | 1038 | cleanup: |
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 | |
| | | 1048 | static void |
| | | 1049 | verify_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 */ |
1005 | static void | | 1062 | static void |
1006 | cleanup_cache(pam_handle_t *pamh __unused, void *data, int pam_end_status __unused) | | 1063 | cleanup_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; |