diff options
Diffstat (limited to 'usr/src/lib/pam_modules/krb5/krb5_authenticate.c')
| -rw-r--r-- | usr/src/lib/pam_modules/krb5/krb5_authenticate.c | 157 |
1 files changed, 94 insertions, 63 deletions
diff --git a/usr/src/lib/pam_modules/krb5/krb5_authenticate.c b/usr/src/lib/pam_modules/krb5/krb5_authenticate.c index ce56893697..8ff80bb8b0 100644 --- a/usr/src/lib/pam_modules/krb5/krb5_authenticate.c +++ b/usr/src/lib/pam_modules/krb5/krb5_authenticate.c @@ -20,8 +20,7 @@ */ /* - * Copyright 2010 Sun Microsystems, Inc. All rights reserved. - * Use is subject to license terms. + * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved. */ #include <security/pam_appl.h> @@ -381,45 +380,42 @@ pam_krb5_prompter( int num_prompts, krb5_prompt prompts[]) { - krb5_error_code rc; + krb5_error_code rc = KRB5_LIBOS_CANTREADPWD; pam_handle_t *pamh = (pam_handle_t *)data; struct pam_conv *pam_convp; - struct pam_message *msgs; - struct pam_response *ret_respp; + struct pam_message *msgs = NULL; + struct pam_response *ret_respp = NULL; int i; krb5_prompt_type *prompt_type = krb5_get_prompt_types(ctx); char tmpbuf[PAM_MAX_MSG_SIZE]; + if (prompts) { + assert(num_prompts > 0); + } /* * Because this function should never be used for password prompts, * disallow password prompts. */ for (i = 0; i < num_prompts; i++) { - if (prompt_type[i] == KRB5_PROMPT_TYPE_PASSWORD) - return (KRB5_LIBOS_CANTREADPWD); - } - - if (num_prompts == 0) { - if (prompts) { - /* This shouldn't happen */ - return (PAM_SYSTEM_ERR); - } else { - /* no prompts so return */ - return (0); + switch (prompt_type[i]) { + case KRB5_PROMPT_TYPE_PASSWORD: + case KRB5_PROMPT_TYPE_NEW_PASSWORD: + case KRB5_PROMPT_TYPE_NEW_PASSWORD_AGAIN: + return (rc); } } - if ((rc = pam_get_item(pamh, PAM_CONV, (void **)&pam_convp)) - != PAM_SUCCESS) { + + if (pam_get_item(pamh, PAM_CONV, (void **)&pam_convp) != PAM_SUCCESS) { return (rc); } if (pam_convp == NULL) { - return (PAM_SYSTEM_ERR); + return (rc); } msgs = (struct pam_message *)calloc(num_prompts, sizeof (struct pam_message)); if (msgs == NULL) { - return (PAM_BUF_ERR); + return (rc); } (void) memset(msgs, 0, sizeof (struct pam_message) * num_prompts); @@ -436,12 +432,10 @@ pam_krb5_prompter( */ if (snprintf(tmpbuf, sizeof (tmpbuf), "%s: ", prompts[i].prompt) < 0) { - rc = PAM_BUF_ERR; goto cleanup; } msgs[i].msg = strdup(tmpbuf); if (msgs[i].msg == NULL) { - rc = PAM_BUF_ERR; goto cleanup; } } @@ -449,21 +443,40 @@ pam_krb5_prompter( /* * Call PAM conv function to display the prompt. */ - rc = (pam_convp->conv)(num_prompts, &msgs, &ret_respp, - pam_convp->appdata_ptr); - if (rc == PAM_SUCCESS) { + if ((pam_convp->conv)(num_prompts, &msgs, &ret_respp, + pam_convp->appdata_ptr) == PAM_SUCCESS) { for (i = 0; i < num_prompts; i++) { /* convert PAM response to krb prompt reply format */ - prompts[i].reply->length = strlen(ret_respp[i].resp) + - 1; /* adding 1 for NULL terminator */ - prompts[i].reply->data = ret_respp[i].resp; + assert(prompts[i].reply->data != NULL); + assert(ret_respp[i].resp != NULL); + + if (strlcpy(prompts[i].reply->data, + ret_respp[i].resp, prompts[i].reply->length) >= + prompts[i].reply->length) { + char errmsg[1][PAM_MAX_MSG_SIZE]; + + (void) snprintf(errmsg[0], PAM_MAX_MSG_SIZE, + "%s", dgettext(TEXT_DOMAIN, + "Reply too long: ")); + (void) __pam_display_msg(pamh, PAM_ERROR_MSG, + 1, errmsg, NULL); + goto cleanup; + } else { + char *retp; + + /* + * newline must be replaced with \0 terminator + */ + retp = strchr(prompts[i].reply->data, '\n'); + if (retp != NULL) + *retp = '\0'; + /* NULL terminator should not be counted */ + prompts[i].reply->length = + strlen(prompts[i].reply->data); + } } - /* - * Note, just free ret_respp, not the resp data since that is - * being referenced by the krb prompt reply data pointer. - */ - free(ret_respp); + rc = 0; } cleanup: @@ -471,8 +484,15 @@ cleanup: if (msgs[i].msg) { free(msgs[i].msg); } + if (ret_respp[i].resp) { + /* 0 out sensitive data before free() */ + (void) memset(ret_respp[i].resp, 0, + strlen(ret_respp[i].resp)); + free(ret_respp[i].resp); + } } free(msgs); + free(ret_respp); return (rc); } @@ -499,7 +519,7 @@ attempt_krb5_auth( KRB5_TGS_NAME_SIZE, KRB5_TGS_NAME }; - krb5_get_init_creds_opt opts; + krb5_get_init_creds_opt *opts = NULL; krb5_kdc_rep *as_reply = NULL; /* * "result" should not be assigned PAM_SUCCESS unless @@ -515,8 +535,6 @@ attempt_krb5_auth( "PAM-KRB5 (auth): attempt_krb5_auth: start: user='%s'", user ? user : "<null>"); - krb5_get_init_creds_opt_init(&opts); - /* need to free context with krb5_free_context */ if (code = krb5_init_secure_context(&kmd->kcontext)) { __pam_log(LOG_AUTH | LOG_ERR, @@ -632,35 +650,44 @@ attempt_krb5_auth( } else my_creds->times.renew_till = 0; - krb5_get_init_creds_opt_set_tkt_life(&opts, lifetime); + code = krb5_get_init_creds_opt_alloc(kmd->kcontext, &opts); + if (code != 0) { + __pam_log(LOG_AUTH | LOG_ERR, + "Error allocating gic opts: %s", + error_message(code)); + result = PAM_SYSTEM_ERR; + goto out; + } + + krb5_get_init_creds_opt_set_tkt_life(opts, lifetime); if (proxiable_flag) { /* Set in config file */ if (kmd->debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (auth): Proxiable tickets " "requested"); - krb5_get_init_creds_opt_set_proxiable(&opts, TRUE); + krb5_get_init_creds_opt_set_proxiable(opts, TRUE); } if (forwardable_flag) { if (kmd->debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (auth): Forwardable tickets " "requested"); - krb5_get_init_creds_opt_set_forwardable(&opts, TRUE); + krb5_get_init_creds_opt_set_forwardable(opts, TRUE); } if (renewable_flag) { if (kmd->debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (auth): Renewable tickets " "requested"); - krb5_get_init_creds_opt_set_renew_life(&opts, rlife); + krb5_get_init_creds_opt_set_renew_life(opts, rlife); } if (no_address_flag) { if (kmd->debug) __pam_log(LOG_AUTH | LOG_DEBUG, "PAM-KRB5 (auth): Addressless tickets " "requested"); - krb5_get_init_creds_opt_set_address_list(&opts, NULL); + krb5_get_init_creds_opt_set_address_list(opts, NULL); } /* @@ -686,28 +713,30 @@ attempt_krb5_auth( KRB5_PADATA_PK_AS_REQ, KRB5_PADATA_PK_AS_REQ_OLD }; - krb5_get_init_creds_opt_set_preauth_list(&opts, pk_pa_list, 2); + krb5_get_init_creds_opt_set_preauth_list(opts, pk_pa_list, 2); - if (*krb5_pass == NULL) { - /* let preauth plugin prompt for PIN */ - code = __krb5_get_init_creds_password(kmd->kcontext, - my_creds, - me, - NULL, /* clear text passwd */ - pam_krb5_prompter, /* prompter */ - pamh, /* prompter data */ - 0, /* start time */ - NULL, /* defaults to krbtgt@REALM */ - &opts, - &as_reply); + if (*krb5_pass == NULL || strlen(*krb5_pass) != 0) { + if (*krb5_pass != NULL) { + /* treat the krb5_pass as a PIN */ + code = krb5_get_init_creds_opt_set_pa( + kmd->kcontext, opts, "PIN", *krb5_pass); + } + + if (!code) { + code = __krb5_get_init_creds_password( + kmd->kcontext, + my_creds, + me, + NULL, /* clear text passwd */ + pam_krb5_prompter, /* prompter */ + pamh, /* prompter data */ + 0, /* start time */ + NULL, /* defaults to krbtgt@REALM */ + opts, + &as_reply); + } } else { - /* - * krb pkinit does not support setting the PIN so we - * punt on trying to use krb5_pass as the PIN for now. - * Note that once this is supported by pkinit the code - * should make sure krb5_pass isn't empty and if it is - * then that's an error. - */ + /* invalid PIN */ code = KRB5KRB_AP_ERR_BAD_INTEGRITY; } } else { @@ -725,7 +754,7 @@ attempt_krb5_auth( KRB5_PADATA_ENC_TIMESTAMP }; - krb5_get_init_creds_opt_set_preauth_list(&opts, + krb5_get_init_creds_opt_set_preauth_list(opts, pk_pa_list, 1); /* @@ -743,7 +772,7 @@ attempt_krb5_auth( NULL, /* data */ 0, /* start time */ NULL, /* defaults to krbtgt@REALM */ - &opts, + opts, &as_reply); } } @@ -951,6 +980,8 @@ out: krb5_free_context(kmd->kcontext); kmd->kcontext = NULL; } + if (opts) + krb5_get_init_creds_opt_free(kmd->kcontext, opts); if (kmd->debug) __pam_log(LOG_AUTH | LOG_DEBUG, |
