summaryrefslogtreecommitdiff
path: root/usr/src/lib/pam_modules/krb5/krb5_authenticate.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr/src/lib/pam_modules/krb5/krb5_authenticate.c')
-rw-r--r--usr/src/lib/pam_modules/krb5/krb5_authenticate.c157
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,