From 985cd11fe3e10b35066822f9d0fad2fd9aeb1473 Mon Sep 17 00:00:00 2001 From: Arthur de Jong Date: Wed, 6 Jan 2016 21:14:42 +0100 Subject: [PATCH] Implement myldap_bind() function This function performs a "fake" search that only performs the LDAP BIND operation and nothing more and provides any returned password policy control information. This replaces a number of dummy search operations that were just there to ensure that the connection was open. --- nslcd/myldap.c | 28 +++++++++++++++++++++++++--- nslcd/myldap.h | 11 ++++++----- nslcd/pam.c | 53 +++++++++++++++++++++++++++++------------------------ nslcd/usermod.c | 16 +++++++--------- 4 files changed, 67 insertions(+), 41 deletions(-) diff --git a/nslcd/myldap.c b/nslcd/myldap.c index 926a51d..ca90b82 100644 --- a/nslcd/myldap.c +++ b/nslcd/myldap.c @@ -5,7 +5,7 @@ Copyright (C) 1997-2006 Luke Howard Copyright (C) 2006-2007 West Consulting - Copyright (C) 2006-2015 Arthur de Jong + Copyright (C) 2006-2016 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -80,6 +80,10 @@ /* the maximum number of dn's to log to the debug log for each search */ #define MAX_DEBUG_LOG_DNS 10 +/* a fake scope that is used to not perform an actual search but only + simulate the handling of the search (used for authentication) */ +#define MYLDAP_SCOPE_FAKE 0x1972 /* magic number: should never be a real scope */ + /* This refers to a current LDAP session that contains the connection information. */ struct ldap_session { @@ -1099,13 +1103,24 @@ int myldap_set_credentials(MYLDAP_SESSION *session, const char *dn, /* Get bind ppolicy results from the last bind operation. This function returns a NSLCD_PAM_* code and optional message. */ -void myldap_get_policy_response(MYLDAP_SESSION *session, int *response, - const char **message) +int myldap_bind(MYLDAP_SESSION *session, int *response, const char **message) { + MYLDAP_SEARCH *search; + static const char *attrs[2]; + int rc; + /* construct a fake search to trigger the BIND operation */ + attrs[0] = "dn"; + attrs[1] = NULL; + search = myldap_search(session, session->binddn, MYLDAP_SCOPE_FAKE, + "(objectClass=*)", attrs, &rc); + if (search != NULL) + myldap_search_close(search); + /* return ppolicy results */ if (response != NULL) *response = session->policy_response; if (message != NULL) *message = session->policy_message; + return rc; } /* perform a search operation, the connection is assumed to be open */ @@ -1120,6 +1135,13 @@ static int do_try_search(MYLDAP_SEARCH *search) char *deref_attrs[2]; #endif /* HAVE_LDAP_CREATE_DEREF_CONTROL */ int msgid; + /* if we are at pam_sm_authenticate phase, return immediately. + The search will be retried if ppolicy permits it */ + if (search->scope == MYLDAP_SCOPE_FAKE) + { + log_log(LOG_DEBUG, "do_try_search(): skipping actual search"); + return LDAP_SUCCESS; + } /* if we're using paging, build a page control */ if ((nslcd_cfg->pagesize > 0) && (search->scope != LDAP_SCOPE_BASE)) { diff --git a/nslcd/myldap.h b/nslcd/myldap.h index e54ae52..0f0f2f7 100644 --- a/nslcd/myldap.h +++ b/nslcd/myldap.h @@ -2,7 +2,7 @@ myldap.h - simple interface to do LDAP requests This file is part of the nss-pam-ldapd library. - Copyright (C) 2007-2014 Arthur de Jong + Copyright (C) 2007-2016 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -72,10 +72,11 @@ MUST_USE MYLDAP_SESSION *myldap_create_session(void); MUST_USE int myldap_set_credentials(MYLDAP_SESSION *session, const char *dn, const char *password); -/* Get bind ppolicy results from the last bind operation. This function - returns a NSLCD_PAM_* code and optional message. */ -void myldap_get_policy_response(MYLDAP_SESSION *session, int *response, - const char **message); +/* Ensure that a bind operation is done and provide the ppolicy results. This + function returns an LDAP status code and the response is an NSLCD_PAM_* + code with accompanying message. */ +MUST_USE int myldap_bind(MYLDAP_SESSION *session, + int *response, const char **message); /* Closes all pending searches and deallocates any memory that is allocated with these searches. This does not close the session. */ diff --git a/nslcd/pam.c b/nslcd/pam.c index 3c7df2c..af451a2 100644 --- a/nslcd/pam.c +++ b/nslcd/pam.c @@ -2,7 +2,7 @@ pam.c - pam processing routines Copyright (C) 2009 Howard Chu - Copyright (C) 2009-2014 Arthur de Jong + Copyright (C) 2009-2016 Arthur de Jong Copyright (C) 2015 Nokia Solutions and Networks This library is free software; you can redistribute it and/or @@ -61,29 +61,33 @@ static int try_bind(const char *userdn, const char *password, myldap_session_close(session); return LDAP_LOCAL_ERROR; } - /* perform search for own object (just to do any kind of search) */ - attrs[0] = "dn"; - attrs[1] = NULL; - search = myldap_search(session, userdn, LDAP_SCOPE_BASE, - "(objectClass=*)", attrs, &rc); - if ((search == NULL) || (rc != LDAP_SUCCESS)) - { - if (rc == LDAP_SUCCESS) - rc = LDAP_LOCAL_ERROR; - log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc)); - } - else + /* check that we can bind */ + rc = myldap_bind(session, authzrc, &msg); + if (rc == LDAP_SUCCESS) { - entry = myldap_get_entry(search, &rc); - if ((entry == NULL) || (rc != LDAP_SUCCESS)) + /* perform a search for user object to verify bind */ + attrs[0] = "dn"; + attrs[1] = NULL; + search = myldap_search(session, userdn, LDAP_SCOPE_BASE, + "(objectClass=*)", attrs, &rc); + if ((search == NULL) || (rc != LDAP_SUCCESS)) { if (rc == LDAP_SUCCESS) - rc = LDAP_NO_RESULTS_RETURNED; - log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc)); + rc = LDAP_LOCAL_ERROR; + } + else + { + entry = myldap_get_entry(search, &rc); + if ((entry == NULL) || (rc != LDAP_SUCCESS)) + { + if (rc == LDAP_SUCCESS) + rc = LDAP_NO_RESULTS_RETURNED; + } } } - /* get any policy response from the bind */ - myldap_get_policy_response(session, authzrc, &msg); + /* log any quthentication errors or authorsiation messages */ + if (rc != LDAP_SUCCESS) + log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc)); if ((msg != NULL) && (msg[0] != '\0')) { mysnprintf(authzmsg, authzmsgsz - 1, "%s", msg); @@ -329,8 +333,9 @@ int nslcd_pam_authc(TFILE *fp, MYLDAP_SESSION *session, uid_t calleruid) } /* try authentication */ rc = try_bind(userdn, password, &authzrc, authzmsg, sizeof(authzmsg)); - if (rc == LDAP_SUCCESS) - log_log(LOG_DEBUG, "bind successful"); + log_log(LOG_DEBUG, "bind authc %s authz %s", + (rc == LDAP_SUCCESS) ? "successful" : "failed", + (authzrc == NSLCD_PAM_SUCCESS) ? "successful" : "failed"); /* map result code */ switch (rc) { @@ -700,9 +705,9 @@ static int try_pwmod(MYLDAP_SESSION *oldsession, myldap_session_close(session); return LDAP_LOCAL_ERROR; } - /* perform search for own object (just to do any kind of search) */ - if ((lookup_dn2uid(session, userdn, &rc, buffer, sizeof(buffer)) != NULL) && - (rc == LDAP_SUCCESS)) + /* check that we can bind */ + rc = myldap_bind(session, NULL, NULL); + if (rc == LDAP_SUCCESS) { /* if doing password modification as admin, don't pass old password along */ if ((nslcd_cfg->rootpwmoddn != NULL) && diff --git a/nslcd/usermod.c b/nslcd/usermod.c index e0de4d4..4d74838 100644 --- a/nslcd/usermod.c +++ b/nslcd/usermod.c @@ -2,7 +2,7 @@ usermod.c - routines for changing user information such as full name, login shell, etc - Copyright (C) 2013-2014 Arthur de Jong + Copyright (C) 2013-2016 Arthur de Jong This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public @@ -104,11 +104,10 @@ static int is_valid_shell(const char *shell) return valid; } -static MYLDAP_SESSION *get_session(const char *binddn, const char *userdn, - const char *password, int *rcp) +static MYLDAP_SESSION *get_session(const char *binddn, const char *password, + int *rcp) { MYLDAP_SESSION *session; - char buffer[BUFLEN_DN]; /* set up a new connection */ session = myldap_create_session(); if (session == NULL) @@ -119,10 +118,9 @@ static MYLDAP_SESSION *get_session(const char *binddn, const char *userdn, /* set up credentials for the session */ if (myldap_set_credentials(session, binddn, password)) return NULL; - /* perform search for own object (just to do any kind of search to set - up the connection with fail-over) */ - if ((lookup_dn2uid(session, userdn, rcp, buffer, sizeof(buffer)) == NULL) || - (*rcp != LDAP_SUCCESS)) + /* check that we can bind */ + *rcp = myldap_bind(session, NULL, NULL); + if (*rcp != LDAP_SUCCESS) { myldap_session_close(session); return NULL; @@ -274,7 +272,7 @@ int nslcd_usermod(TFILE *fp, MYLDAP_SESSION *session, uid_t calleruid) shell = NULL; } /* perform requested changes */ - newsession = get_session(binddn, myldap_get_dn(entry), password, &rc); + newsession = get_session(binddn, password, &rc); if (newsession != NULL) { rc = change(newsession, myldap_get_dn(entry), homedir, shell); -- 2.6.4