diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2017-06-14 23:50:46 +0200 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2017-06-15 23:08:15 +0200 |
commit | 0cafb084aa05368daa2e69ccf42540643bc36bb7 (patch) | |
tree | 4a26fcfd6fa6f5f21d17a99cf839745afbcdf6a4 /nslcd | |
parent | 9564dd0c2de567efd4a5fe2b0de796f7e5f135f7 (diff) |
Implement myldap_bind() function
This function integrates the myldap_set_credentials() and
myldap_get_policy_response() and performs the bind operation witout
actually performing a search.
The function performs a "fake" search that returns after performing the
LDAP BIND operation.
This replaces a number of dummy search operations that were there to
ensure that the connection was open. This allows us to skip the search
operation after authentication.
Diffstat (limited to 'nslcd')
-rw-r--r-- | nslcd/myldap.c | 45 | ||||
-rw-r--r-- | nslcd/myldap.h | 16 | ||||
-rw-r--r-- | nslcd/pam.c | 107 | ||||
-rw-r--r-- | nslcd/usermod.c | 19 |
4 files changed, 84 insertions, 103 deletions
diff --git a/nslcd/myldap.c b/nslcd/myldap.c index dddb0d7..6b98a21 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-2017 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_BINDONLY 0x1972 /* magic number: should never be a real scope */ + /* This refers to a current LDAP session that contains the connection information. */ struct ldap_session { @@ -1121,42 +1125,44 @@ static int do_open(MYLDAP_SESSION *session) return LDAP_SUCCESS; } -/* Set alternative credentials for the session. */ -int myldap_set_credentials(MYLDAP_SESSION *session, const char *dn, - const char *password) +/* Perform a simple bind operation and return the ppolicy results. */ +int myldap_bind(MYLDAP_SESSION *session, const char *dn, const char *password, + int *response, const char **message) { + MYLDAP_SEARCH *search; + static const char *attrs[2]; + int rc; /* error out when buffers are too small */ if (strlen(dn) >= sizeof(session->binddn)) { - log_log(LOG_ERR, - "myldap_set_credentials(): binddn buffer too small (%lu required)", + log_log(LOG_ERR, "myldap_bind(): binddn buffer too small (%lu required)", (unsigned long) strlen(dn)); - return -1; + return LDAP_LOCAL_ERROR; } if (strlen(password) >= sizeof(session->bindpw)) { - log_log(LOG_ERR, - "myldap_set_credentials(): bindpw buffer too small (%lu required)", + log_log(LOG_ERR, "myldap_bind(): bindpw buffer too small (%lu required)", (unsigned long) strlen(password)); - return -1; + return LDAP_LOCAL_ERROR; } /* copy dn and password into session */ strncpy(session->binddn, dn, sizeof(session->binddn)); session->binddn[sizeof(session->binddn) - 1] = '\0'; strncpy(session->bindpw, password, sizeof(session->bindpw)); session->bindpw[sizeof(session->bindpw) - 1] = '\0'; - return 0; -} - -/* 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) -{ + /* construct a fake search to trigger the BIND operation */ + attrs[0] = "dn"; + attrs[1] = NULL; + search = myldap_search(session, session->binddn, MYLDAP_SCOPE_BINDONLY, + "(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 */ @@ -1334,7 +1340,8 @@ static int do_retry_search(MYLDAP_SEARCH *search) pthread_mutex_unlock(&uris_mutex); /* ensure that we have an open connection and start a search */ rc = do_open(search->session); - if (rc == LDAP_SUCCESS) + /* perform the actual search, unless we were only binding */ + if ((rc == LDAP_SUCCESS) && (search->scope != MYLDAP_SCOPE_BINDONLY)) rc = do_try_search(search); /* if we are authenticating a user and get an error regarding failed password we should error out instead of trying all servers */ diff --git a/nslcd/myldap.h b/nslcd/myldap.h index e54ae52..62c9350 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-2017 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 @@ -68,14 +68,12 @@ typedef struct myldap_entry MYLDAP_ENTRY; uses the configuration to find the URLs to attempt connections to. */ MUST_USE MYLDAP_SESSION *myldap_create_session(void); -/* Set alternative credentials for the session. Returns 0 on success. */ -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); +/* Perform a simple bind operation and return the ppolicy results. + This function returns an LDAP status code while response is an NSLCD_PAM_* + code with accompanying message. */ +MUST_USE int myldap_bind(MYLDAP_SESSION *session, const char *dn, + const char *password, + 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 58be0de..6c27bb8 100644 --- a/nslcd/pam.c +++ b/nslcd/pam.c @@ -173,7 +173,7 @@ static int try_bind(const char *userdn, const char *password, MYLDAP_SEARCH *search; MYLDAP_ENTRY *entry; static const char *attrs[2]; - int rc = LDAP_SUCCESS; + int rc; const char *msg; DICT *dict; char filter[BUFLEN_FILTER]; @@ -182,58 +182,55 @@ static int try_bind(const char *userdn, const char *password, session = myldap_create_session(); if (session == NULL) return LDAP_UNAVAILABLE; - /* set up credentials for the session */ - if (myldap_set_credentials(session, userdn, password)) - { - myldap_session_close(session); - return LDAP_LOCAL_ERROR; - } - /* perform a search to trigger the BIND operation */ - attrs[0] = "dn"; - attrs[1] = NULL; - if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0) - { - /* do a simple search to check userdn existence */ - search = myldap_search(session, userdn, LDAP_SCOPE_BASE, - "(objectClass=*)", attrs, &rc); - if ((search == NULL) && (rc == LDAP_SUCCESS)) - rc = LDAP_LOCAL_ERROR; - if (rc == LDAP_SUCCESS) - { - entry = myldap_get_entry(search, &rc); - if ((entry == NULL) && (rc == LDAP_SUCCESS)) - rc = LDAP_NO_RESULTS_RETURNED; - } - } - else + /* perform a BIND operation with user credentials */ + rc = myldap_bind(session, userdn, password, authzrc, &msg); + if (rc == LDAP_SUCCESS) { - /* build the search filter */ - dict = search_vars_new(userdn, username, service, ruser, rhost, tty); - if (dict == NULL) + /* perform a search to trigger the BIND operation */ + attrs[0] = "dn"; + attrs[1] = NULL; + if (strcasecmp(nslcd_cfg->pam_authc_search, "BASE") == 0) { - myldap_session_close(session); - return LDAP_LOCAL_ERROR; + /* do a simple search to check userdn existence */ + search = myldap_search(session, userdn, LDAP_SCOPE_BASE, + "(objectClass=*)", attrs, &rc); + if ((search == NULL) && (rc == LDAP_SUCCESS)) + rc = LDAP_LOCAL_ERROR; + if (rc == LDAP_SUCCESS) + { + entry = myldap_get_entry(search, &rc); + if ((entry == NULL) && (rc == LDAP_SUCCESS)) + rc = LDAP_NO_RESULTS_RETURNED; + } } - res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter), - search_var_get, (void *)dict); - if (res == NULL) + else { + /* build the search filter */ + dict = search_vars_new(userdn, username, service, ruser, rhost, tty); + if (dict == NULL) + { + myldap_session_close(session); + return LDAP_LOCAL_ERROR; + } + res = expr_parse(nslcd_cfg->pam_authc_search, filter, sizeof(filter), + search_var_get, (void *)dict); + if (res == NULL) + { + search_vars_free(dict); + myldap_session_close(session); + log_log(LOG_ERR, "invalid pam_authc_search \"%s\"", + nslcd_cfg->pam_authc_search); + return LDAP_LOCAL_ERROR; + } + /* perform a search for each search base */ + rc = do_searches(session, "pam_authc_search", filter); + /* free search variables */ search_vars_free(dict); - myldap_session_close(session); - log_log(LOG_ERR, "invalid pam_authc_search \"%s\"", - nslcd_cfg->pam_authc_search); - return LDAP_LOCAL_ERROR; } - /* perform a search for each search base */ - rc = do_searches(session, "pam_authc_search", filter); - /* free search variables */ - search_vars_free(dict); } - /* check search result */ + /* log any authentication, search or authorsiation messages */ if (rc != LDAP_SUCCESS) log_log(LOG_WARNING, "%s: %s", userdn, ldap_err2string(rc)); - /* get any policy response from the bind */ - myldap_get_policy_response(session, authzrc, &msg); if ((msg != NULL) && (msg[0] != '\0')) { mysnprintf(authzmsg, authzmsgsz - 1, "%s", msg); @@ -738,15 +735,9 @@ static int try_pwmod(MYLDAP_SESSION *oldsession, session = myldap_create_session(); if (session == NULL) return LDAP_UNAVAILABLE; - /* set up credentials for the session */ - if (myldap_set_credentials(session, binddn, oldpassword)) - { - 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)) + /* perform a BIND operation */ + rc = myldap_bind(session, binddn, oldpassword, NULL, NULL); + if (rc == LDAP_SUCCESS) { /* if doing password modification as admin, don't pass old password along */ if ((nslcd_cfg->rootpwmoddn != NULL) && @@ -756,16 +747,6 @@ static int try_pwmod(MYLDAP_SESSION *oldsession, rc = myldap_passwd(session, userdn, oldpassword, newpassword); if (rc == LDAP_SUCCESS) { - /* if user modifies own password, update credentials for the session */ - if (binddn == userdn) - if (myldap_set_credentials(session, binddn, newpassword)) - { - rc = LDAP_LOCAL_ERROR; - log_log(LOG_WARNING, "%s: shadowLastChange: modification failed: %s", - userdn, ldap_err2string(rc)); - myldap_session_close(session); - return rc; - } /* try to update the shadowLastChange attribute */ if (update_lastchange(session, userdn) != LDAP_SUCCESS) /* retry with the normal session */ diff --git a/nslcd/usermod.c b/nslcd/usermod.c index e0de4d4..ad82e7d 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-2017 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) @@ -116,13 +115,9 @@ static MYLDAP_SESSION *get_session(const char *binddn, const char *userdn, *rcp = LDAP_UNAVAILABLE; return NULL; } - /* 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, binddn, password, NULL, NULL); + if (*rcp != LDAP_SUCCESS) { myldap_session_close(session); return NULL; @@ -274,7 +269,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); |