summaryrefslogtreecommitdiffstats
path: root/src/back-sch-pam.c
diff options
context:
space:
mode:
authorNalin Dahyabhai <nalin@dahyabhai.net>2013-08-06 16:05:04 -0400
committerNalin Dahyabhai <nalin@dahyabhai.net>2013-08-12 15:43:31 -0400
commitd24756948f1c59d9f6d4be943e2cc21683d085d5 (patch)
tree0fb4462e51a71372cfe6fd642e222261645ee5cf /src/back-sch-pam.c
parent4bc0ce64e49f61b36f9f70c708aff7937957b638 (diff)
downloadslapi-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.c252
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;
-}