summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorArthur de Jong <arthur@arthurdejong.org>2014-01-05 14:15:21 +0100
committerArthur de Jong <arthur@arthurdejong.org>2014-01-05 22:08:40 +0100
commitc973834328baa69dbd3352182431421b2b9a2319 (patch)
treefccc955c9fe8349ad897030b06a20635b664d076
parent3992e15ffd0a4f0d8130b6ac25163ab90d064c27 (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.ac3
-rw-r--r--nslcd/myldap.c148
-rw-r--r--nslcd/myldap.h9
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