Arthur de Jong

Open Source / Free Software developer

summaryrefslogtreecommitdiffstats
path: root/nslcd
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2017-06-14 23:50:46 +0200
committerArthur de Jong <arthur@arthurdejong.org>2017-06-15 23:08:15 +0200
commit0cafb084aa05368daa2e69ccf42540643bc36bb7 (patch)
tree4a26fcfd6fa6f5f21d17a99cf839745afbcdf6a4 /nslcd
parent9564dd0c2de567efd4a5fe2b0de796f7e5f135f7 (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.c45
-rw-r--r--nslcd/myldap.h16
-rw-r--r--nslcd/pam.c107
-rw-r--r--nslcd/usermod.c19
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);