diff options
author | Arthur de Jong <arthur@arthurdejong.org> | 2014-01-05 14:15:21 +0100 |
---|---|---|
committer | Arthur de Jong <arthur@arthurdejong.org> | 2014-01-05 22:08:40 +0100 |
commit | c973834328baa69dbd3352182431421b2b9a2319 (patch) | |
tree | fccc955c9fe8349ad897030b06a20635b664d076 | |
parent | 3992e15ffd0a4f0d8130b6ac25163ab90d064c27 (diff) |
Provide a myldap_get_deref_values() function
This function looks for deref response controls (LDAP_CONTROL_X_DEREF)
in the entry and returns the information from the dereferenced attribute
in two lists: dereferenced values and attribute values that could not be
dereferenced.
-rw-r--r-- | configure.ac | 3 | ||||
-rw-r--r-- | nslcd/myldap.c | 148 | ||||
-rw-r--r-- | nslcd/myldap.h | 9 |
3 files changed, 158 insertions, 2 deletions
diff --git a/configure.ac b/configure.ac index 907446e..cd776e0 100644 --- a/configure.ac +++ b/configure.ac @@ -804,9 +804,10 @@ then AC_CHECK_FUNCS(ldap_get_values_len ldap_count_values_len ldap_value_free_len) AC_CHECK_FUNCS(ldap_err2string ldap_abandon) AC_CHECK_FUNCS(ldap_control_create ldap_create_control ldap_control_find) - AC_CHECK_FUNCS(ldap_controls_free ldap_control_free) + AC_CHECK_FUNCS(ldap_controls_free ldap_control_free ldap_get_entry_controls) AC_CHECK_FUNCS(ldap_parse_passwordpolicy_control ldap_passwordpolicy_err2txt) AC_CHECK_FUNCS(ldap_create_deref_control ldap_create_deref_control_value) + AC_CHECK_FUNCS(ldap_parse_deref_control ldap_derefresponse_free) # replace ldap_create_page_control() and ldap_parse_page_control() AC_CHECK_FUNCS(ldap_create_page_control ldap_parse_page_control,, [AC_LIBOBJ(pagectrl)]) diff --git a/nslcd/myldap.c b/nslcd/myldap.c index 722109d..9e0bc6e 100644 --- a/nslcd/myldap.c +++ b/nslcd/myldap.c @@ -2080,6 +2080,154 @@ int myldap_has_objectclass(MYLDAP_ENTRY *entry, const char *objectclass) return 0; } +#ifdef HAVE_LDAP_PARSE_DEREF_CONTROL +const char ***myldap_get_deref_values(MYLDAP_ENTRY *entry, + const char *derefattr, const char *getattr) +{ + LDAPControl **entryctrls; + LDAPDerefRes *deref, *d; + LDAPDerefVal *a; + int i, pass; + int rc; + int found; + int counts[2]; + size_t sizes[2], size; + char *buffer = NULL; + char ***results = NULL; + rc = ldap_get_entry_controls(entry->search->session->ld, entry->search->msg, + &entryctrls); + if (rc != LDAP_SUCCESS) + { + myldap_err(LOG_WARNING, entry->search->session->ld, rc, + "ldap_get_entry_controls() failed"); + return NULL; + } + if (entryctrls == NULL) + return NULL; + /* see if we can find a deref control */ + rc = ldap_parse_deref_control(entry->search->session->ld, entryctrls, + &deref); + if ((rc != LDAP_SUCCESS) || (deref == NULL)) + { + if ((rc != LDAP_SUCCESS) && (rc != LDAP_CONTROL_NOT_FOUND)) + myldap_err(LOG_WARNING, entry->search->session->ld, rc, + "ldap_parse_deref_control() failed"); + /* clear error flag */ + rc = LDAP_SUCCESS; + if (ldap_set_option(entry->search->session->ld, LDAP_OPT_ERROR_NUMBER, + &rc) != LDAP_SUCCESS) + log_log(LOG_WARNING, "failed to clear the error flag"); + ldap_controls_free(entryctrls); + return NULL; + } + /* two passes: one to calculate size, one to store data */ + for (pass=0; pass < 2; pass++) + { + /* reset counters and size */ + for (i = 0; i < 2; i++) + { + counts[i] = 0; + sizes[i] = 0; + } + /* go over all deref'd attributes and find the one we're looking for */ + for (d = deref; d != NULL; d = d->next) + if ((d->derefAttr != NULL) && (d->derefVal.bv_val != NULL) && + (strcasecmp(derefattr, d->derefAttr) == 0)) + { + /* we should have one d per original attribute value */ + found = 0; + /* go over deref'd attribute values to find the ones we're looking for */ + for (a = d->attrVals; a != NULL; a = a->next) + if ((a->type != NULL) && (a->vals != NULL) && + (strcasecmp(getattr, a->type) == 0)) + for (i=0; a->vals[i].bv_val != NULL; i++) + { + found = 1; + if (results == NULL) + { + log_log(LOG_DEBUG, "deref %s %s=%s -> %s=%s", + myldap_get_dn(entry), d->derefAttr, d->derefVal.bv_val, + a->type, a->vals[i].bv_val); + counts[0]++; + sizes[0] += strlen(a->vals[i].bv_val) + 1; + } + else + { + strcpy(buffer, a->vals[i].bv_val); + results[0][counts[0]++] = buffer; + buffer += strlen(buffer) + 1; + } + } + if (!found) + { + if (results == NULL) + { + log_log(LOG_DEBUG, "no %s deref %s %s=%s", getattr, + myldap_get_dn(entry), d->derefAttr, d->derefVal.bv_val); + counts[1]++; + sizes[1] += strlen(d->derefVal.bv_val) + 1; + } + else + { + strcpy(buffer, d->derefVal.bv_val); + results[1][counts[1]++] = buffer; + buffer += strlen(buffer) + 1; + } + } + } + /* allocate memory after first pass */ + if (results == NULL) + { + size = sizeof(char **) * 3; + for (i = 0; i < 2; i++) + size += sizeof(char *) * (counts[i] + 1); + for (i = 0; i < 2; i++) + size += sizeof(char) * sizes[i]; + buffer = (char *)malloc(size); + if (buffer == NULL) + { + log_log(LOG_CRIT, "myldap_get_deref_values(): malloc() failed to allocate memory"); + return NULL; + } + /* allocate the list of lists */ + results = (void *)buffer; + buffer += sizeof(char **) * 3; + /* allocate the lists */ + for (i = 0; i < 2; i++) + { + results[i] = (char **)buffer; + buffer += sizeof(char *) * (counts[i] + 1); + } + results[i] = NULL; + } + } + /* NULL terminate the lists */ + results[0][counts[0]] = NULL; + results[1][counts[1]] = NULL; + /* free control data */ + ldap_derefresponse_free(deref); + ldap_controls_free(entryctrls); + /* store results so we can free it later on */ + for (i = 0; i < MAX_BUFFERS_PER_ENTRY; i++) + if (entry->buffers[i] == NULL) + { + entry->buffers[i] = (void *)results; + return (const char ***)results; + } + /* we found no room to store the values */ + log_log(LOG_ERR, "myldap_get_deref_values() couldn't store results, " + "increase MAX_BUFFERS_PER_ENTRY"); + free(results); + return NULL; +} +#else /* not HAVE_LDAP_PARSE_DEREF_CONTROL */ +const char ***myldap_get_deref_values(MYLDAP_ENTRY UNUSED(*entry), + const char UNUSED(*derefattr), const char UNUSED(*getattr)) +{ + return NULL; +} +#endif /* not HAVE_LDAP_PARSE_DEREF_CONTROL */ + int myldap_escape(const char *src, char *buffer, size_t buflen) { size_t pos = 0; diff --git a/nslcd/myldap.h b/nslcd/myldap.h index 8c4551a..c7358af 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, 2008, 2009, 2010, 2011, 2012, 2013 Arthur de Jong + Copyright (C) 2007-2014 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 @@ -133,6 +133,13 @@ MUST_USE const char **myldap_get_values_len(MYLDAP_ENTRY *entry, const char *att /* Checks to see if the entry has the specified object class. */ MUST_USE int myldap_has_objectclass(MYLDAP_ENTRY *entry, const char *objectclass); +/* See if the entry has any deref controls attached to it and deref attr + derefattr to get the getattr values. Will return two lists of attribute + values. One list of deref'ed attribute values and one list of original + attribute values that could not be deref'ed. */ +MUST_USE const char ***myldap_get_deref_values(MYLDAP_ENTRY *entry, + const char *derefattr, const char *getattr); + /* Get the RDN's value: eg. if the DN was cn=lukeh, ou=People, dc=example, dc=com getrdnvalue(entry, cn) would return lukeh. If the attribute was not found in the DN or if some error occurs NULL is returned. This method may |