diff options
author | Nalin Dahyabhai <nalin@dahyabhai.net> | 2013-08-06 16:05:04 -0400 |
---|---|---|
committer | Nalin Dahyabhai <nalin@dahyabhai.net> | 2013-08-12 15:43:31 -0400 |
commit | d24756948f1c59d9f6d4be943e2cc21683d085d5 (patch) | |
tree | 0fb4462e51a71372cfe6fd642e222261645ee5cf /src/back-sch-pam.c | |
parent | 4bc0ce64e49f61b36f9f70c708aff7937957b638 (diff) | |
download | slapi-nis-d24756948f1c59d9f6d4be943e2cc21683d085d5.tar.gz slapi-nis-d24756948f1c59d9f6d4be943e2cc21683d085d5.tar.xz slapi-nis-d24756948f1c59d9f6d4be943e2cc21683d085d5.zip |
Consolidate PAM error checking/handling/reporting
Don't bother to fetch the full set of request controls, since we don't
do anything with them. Merge what's left of backend_sch_do_pam_auth()
and do_pam_auth(). Separate the concoct-an-error-message logic out into
a helper that we call after both pam_authenticate() and pam_acct_mgmt().
Diffstat (limited to 'src/back-sch-pam.c')
-rw-r--r-- | src/back-sch-pam.c | 252 |
1 files changed, 108 insertions, 144 deletions
diff --git a/src/back-sch-pam.c b/src/back-sch-pam.c index 980c25f..9e9b085 100644 --- a/src/back-sch-pam.c +++ b/src/back-sch-pam.c @@ -33,7 +33,6 @@ * statement from your version and license this file solely under the GPL without * exception. * - * * Copyright (C) 2005 Red Hat, Inc. * All rights reserved. * END COPYRIGHT BLOCK **/ @@ -56,13 +55,12 @@ #include <slapi-plugin.h> #endif - #include <security/pam_appl.h> /* for third arg to pam_start */ -struct my_pam_conv_str { +struct conv_data { Slapi_PBlock *pb; - const char *pam_identity; + const char *user; }; static void @@ -84,11 +82,12 @@ free_pam_response(int nresp, struct pam_response *resp) * tell if this is actually the case. */ static int -pam_conv_func(int num_msg, const struct pam_message **msg, struct pam_response **resp, void *mydata) +converse(int num_msg, const struct pam_message **msg, + struct pam_response **resp, void *data) { int ii; struct berval *creds; - struct my_pam_conv_str *my_data = (struct my_pam_conv_str *)mydata; + struct conv_data *conv = data; struct pam_response *reply; int ret = PAM_SUCCESS; @@ -97,36 +96,36 @@ pam_conv_func(int num_msg, const struct pam_message **msg, struct pam_response * } /* empty reply structure. We have to use malloc/free due to the caller freeing the response */ - reply = (struct pam_response *) calloc(num_msg, sizeof(struct pam_response)); - slapi_pblock_get(my_data->pb, SLAPI_BIND_CREDENTIALS, &creds); /* the password */ + reply = calloc(num_msg, sizeof(reply[0])); + slapi_pblock_get(conv->pb, SLAPI_BIND_CREDENTIALS, &creds); /* the password */ for (ii = 0; ii < num_msg; ++ii) { /* hard to tell what prompt is for . . . */ /* assume prompts for password are either BINARY or ECHO_OFF */ switch (msg[ii]->msg_style) { - case PAM_PROMPT_ECHO_OFF: + case PAM_PROMPT_ECHO_OFF: #ifdef LINUX - case PAM_BINARY_PROMPT: + case PAM_BINARY_PROMPT: #endif - reply[ii].resp = malloc(creds->bv_len + 1); - if (reply[ii].resp != NULL) { - memcpy(reply[ii].resp, creds->bv_val, creds->bv_len); - reply[ii].resp[creds->bv_len] = '\0'; - } else { - ret = PAM_CONV_ERR; - } - break; - case PAM_PROMPT_ECHO_ON: - reply[ii].resp = strdup(my_data->pam_identity); - if (reply[ii].resp == NULL) { - ret = PAM_CONV_ERR; - } - break; - case PAM_ERROR_MSG: - case PAM_TEXT_INFO: - break; - default: + reply[ii].resp = malloc(creds->bv_len + 1); + if (reply[ii].resp != NULL) { + memcpy(reply[ii].resp, creds->bv_val, creds->bv_len); + reply[ii].resp[creds->bv_len] = '\0'; + } else { ret = PAM_CONV_ERR; - break; + } + break; + case PAM_PROMPT_ECHO_ON: + reply[ii].resp = strdup(conv->user); + if (reply[ii].resp == NULL) { + ret = PAM_CONV_ERR; + } + break; + case PAM_ERROR_MSG: + case PAM_TEXT_INFO: + break; + default: + ret = PAM_CONV_ERR; + break; } } @@ -140,126 +139,107 @@ pam_conv_func(int num_msg, const struct pam_message **msg, struct pam_response * return ret; } -/* - * Do the actual work of authenticating with PAM. - * Set up the structures that pam_start needs and call pam_start(). After - * that, call pam_authenticate and pam_acct_mgmt. Check the various return - * values from these functions and map them to their corresponding LDAP BIND - * return values. Return the appropriate LDAP error code. - * This function will also set the appropriate LDAP response controls in - * the given pblock. - */ -static int -do_pam_auth(Slapi_PBlock *pb, const char *pam_service, /* name of service for pam_start() */ - int pw_response_requested, /* do we need to send pwd policy resp control */ - const char *username) +/* Map a PAM error code to an LDAP error code and text, adding response + * controls to the given pblock if a control would be suited to the result + * code. */ +static void +map_pam_error(Slapi_PBlock *pb, const char *user, const char *binddn, + int rc, int pw_response_requested, pam_handle_t *pamh, + char **errmsg, int *retcode) +{ + *errmsg = PR_smprintf("PAM error for user \"%s\" (bind DN \"%s\"): %s", + user, binddn, pam_strerror(pamh, rc)); + switch (rc) { + case PAM_USER_UNKNOWN: + *retcode = LDAP_NO_SUCH_OBJECT; + break; + case PAM_AUTH_ERR: + *retcode = LDAP_INVALID_CREDENTIALS; + break; + case PAM_MAXTRIES: + if (pw_response_requested) { + slapi_pwpolicy_make_response_control(pb, -1, -1, + LDAP_PWPOLICY_ACCTLOCKED); + } + *retcode = LDAP_CONSTRAINT_VIOLATION; /* max retries */ + break; + case PAM_PERM_DENIED: + if (pw_response_requested) { + slapi_pwpolicy_make_response_control(pb, -1, -1, + LDAP_PWPOLICY_ACCTLOCKED); + } + *retcode = LDAP_UNWILLING_TO_PERFORM; + break; + case PAM_ACCT_EXPIRED: + case PAM_NEW_AUTHTOK_REQD: + slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); + if (pw_response_requested) { + slapi_pwpolicy_make_response_control(pb, -1, -1, + LDAP_PWPOLICY_PWDEXPIRED); + } + *retcode = LDAP_INVALID_CREDENTIALS; + break; + default: + *retcode = LDAP_OPERATIONS_ERROR; /* assume config or network problem */ + break; + } +} + +/* Use the supplied simple-bind credentials to attempt PAM authentication as + * the specified user. */ +int +backend_sch_do_pam_auth(Slapi_PBlock *pb, const char *username) { const char *binddn = NULL; Slapi_DN *bindsdn = NULL; int rc = PAM_SUCCESS; int retcode = LDAP_SUCCESS; - pam_handle_t *pam_handle; - struct my_pam_conv_str my_data; - struct pam_conv my_pam_conv = {pam_conv_func, NULL}; - char *errmsg = NULL; /* free with PR_smprintf_free */ + pam_handle_t *pamh; + struct conv_data conv_data; + struct pam_conv conv; + int pw_response_requested = 0; + char *errmsg = NULL; + slapi_pblock_get(pb, SLAPI_PWPOLICY, &pw_response_requested); slapi_pblock_get(pb, SLAPI_BIND_TARGET_SDN, &bindsdn); if (NULL == bindsdn) { - errmsg = PR_smprintf("Null bind dn"); + errmsg = PR_smprintf("NULL bind dn"); retcode = LDAP_OPERATIONS_ERROR; - goto done; /* skip the pam stuff */ + goto done; } binddn = slapi_sdn_get_dn(bindsdn); - /* do the pam stuff */ - my_data.pb = pb; - my_data.pam_identity = username; - my_pam_conv.appdata_ptr = &my_data; - rc = pam_start(pam_service, username, &my_pam_conv, &pam_handle); + memset(&conv_data, 0, sizeof(conv_data)); + conv_data.pb = pb; + conv_data.user = username; + memset(&conv, 0, sizeof(conv)); + conv.conv = &converse; + conv.appdata_ptr = &conv_data; + rc = pam_start(DEFAULT_PAM_SERVICE, username, &conv, &pamh); if (rc == PAM_SUCCESS) { - /* use PAM_SILENT - there is no user interaction at this point */ - rc = pam_authenticate(pam_handle, 0); - /* check different types of errors here */ - switch (rc) { - case PAM_USER_UNKNOWN: - errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", - username, binddn); - retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ - break; - case PAM_AUTH_ERR: - errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", - username, binddn); - retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ - break; - case PAM_MAXTRIES: - errmsg = PR_smprintf("Authentication retry limit exceeded in PAM for " - "user id [%s], bind DN [%s]", username, binddn); - if (pw_response_requested) { - slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); - } - retcode = LDAP_CONSTRAINT_VIOLATION; /* max retries */ - break; - case PAM_SUCCESS: - break; - default: - errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", - pam_strerror(pam_handle, rc), username, binddn); - retcode = LDAP_OPERATIONS_ERROR; /* pam config or network problem */ - break; + rc = pam_authenticate(pamh, PAM_SILENT); + if (rc != PAM_SUCCESS) { + map_pam_error(pb, username, binddn, rc, + pw_response_requested != 0, + pamh, &errmsg, &retcode); } } - - /* if user authenticated successfully, see if there is anything we need - to report back w.r.t. password or account lockout */ if (rc == PAM_SUCCESS) { - rc = pam_acct_mgmt(pam_handle, 0); - /* check different types of errors here */ - switch (rc) { - case PAM_USER_UNKNOWN: - errmsg = PR_smprintf("User id [%s] for bind DN [%s] does not exist in PAM", - username, binddn); - retcode = LDAP_NO_SUCH_OBJECT; /* user unknown */ - break; - case PAM_AUTH_ERR: - errmsg = PR_smprintf("Invalid PAM password for user id [%s], bind DN [%s]", - username, binddn); - retcode = LDAP_INVALID_CREDENTIALS; /* invalid creds */ - break; - case PAM_PERM_DENIED: - errmsg = PR_smprintf("Access denied for PAM user id [%s], bind DN [%s]" - " - see administrator", username, binddn); - if (pw_response_requested) { - slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_ACCTLOCKED); - } - retcode = LDAP_UNWILLING_TO_PERFORM; - break; - case PAM_ACCT_EXPIRED: - case PAM_NEW_AUTHTOK_REQD: - errmsg = PR_smprintf("Expired PAM password for user id [%s], bind DN [%s]: " - "reset required", username, binddn); - slapi_add_pwd_control(pb, LDAP_CONTROL_PWEXPIRED, 0); - if (pw_response_requested) { - slapi_pwpolicy_make_response_control(pb, -1, -1, LDAP_PWPOLICY_PWDEXPIRED); - } - retcode = LDAP_INVALID_CREDENTIALS; - break; - case PAM_SUCCESS: - break; - default: - errmsg = PR_smprintf("Unknown PAM error [%s] for user id [%s], bind DN [%s]", - pam_strerror(pam_handle, rc), username, binddn); - retcode = LDAP_OPERATIONS_ERROR; /* unknown */ - break; + rc = pam_acct_mgmt(pamh, PAM_SILENT); + if (rc != PAM_SUCCESS) { + map_pam_error(pb, username, binddn, rc, + pw_response_requested != 0, + pamh, &errmsg, &retcode); } } - - rc = pam_end(pam_handle, rc); + pam_end(pamh, rc); done: if ((retcode == LDAP_SUCCESS) && (rc != PAM_SUCCESS)) { - errmsg = PR_smprintf("Unknown PAM error [%d] for user id [%s], bind DN [%s]", - rc, username, binddn); + errmsg = PR_smprintf("PAM error for user \"%s\" " + "(bind DN \"%s\"): %s", + username, binddn, pam_strerror(pamh, rc)); retcode = LDAP_OPERATIONS_ERROR; } @@ -267,25 +247,9 @@ done: slapi_send_ldap_result(pb, retcode, NULL, errmsg, 0, NULL); } - if (errmsg) { + if (errmsg != NULL) { PR_smprintf_free(errmsg); } return retcode; } - -int -backend_sch_do_pam_auth(Slapi_PBlock *pb, const char *username) -{ - int rc = LDAP_SUCCESS; - int pw_response_requested; - LDAPControl **reqctrls = NULL; - - slapi_pblock_get (pb, SLAPI_REQCONTROLS, &reqctrls); - slapi_pblock_get (pb, SLAPI_PWPOLICY, &pw_response_requested); - - rc = do_pam_auth(pb, DEFAULT_PAM_SERVICE, pw_response_requested, - username); - - return rc; -} |