X-Git-Url: https://vcs.fsf.org/?p=exim.git;a=blobdiff_plain;f=src%2Fsrc%2Flookups%2Fldap.c;h=235af0f937a42a43cfbae145ef9c6c55bda00a9e;hp=b870df14776a18a7450ebedac034496ba8b3cc0b;hb=refs%2Ftags%2Fexim-4_90_RC1;hpb=14b3c5bc64a16df07583fe4b5ef2e0129d063893 diff --git a/src/src/lookups/ldap.c b/src/src/lookups/ldap.c index b870df147..235af0f93 100644 --- a/src/src/lookups/ldap.c +++ b/src/src/lookups/ldap.c @@ -2,11 +2,11 @@ * Exim - an Internet mail transport agent * *************************************************/ -/* Copyright (c) University of Cambridge 1995 - 2015 */ +/* Copyright (c) University of Cambridge 1995 - 2017 */ /* See the file NOTICE for conditions of use and distribution. */ /* Many thanks to Stuart Lynne for contributing the original code for this -driver. Further contibutions from Michael Haardt, Brian Candler, Barry +driver. Further contributions from Michael Haardt, Brian Candler, Barry Pederson, Peter Savitch and Christian Kellner. Particular thanks to Brian for researching how to handle the different kinds of error. */ @@ -145,7 +145,7 @@ struct timeval *timeoutptr = NULL; uschar *attr; uschar **attrp; -uschar *data = NULL; +gstring * data = NULL; uschar *dn = NULL; uschar *host; uschar **values; @@ -156,14 +156,12 @@ uschar *error1 = NULL; /* string representation of errcode (static) */ uschar *error2 = NULL; /* error message from the server */ uschar *matched = NULL; /* partially matched DN */ -int attr_count = 0; +int attrs_requested = 0; int error_yield = DEFER; int msgid; int rc, ldap_rc, ldap_parse_rc; int port; -int ptr = 0; int rescount = 0; -int size = 0; BOOL attribute_found = FALSE; BOOL ldapi = FALSE; @@ -248,7 +246,7 @@ if (host != NULL) /* Count the attributes; we need this later to tell us how to format results */ for (attrp = USS ludp->lud_attrs; attrp != NULL && *attrp != NULL; attrp++) - attr_count++; + attrs_requested++; /* See if we can find a cached connection to this host. The port is not relevant for ldapi. The host name pointer is set to NULL if no host was given @@ -580,7 +578,7 @@ if (!lcp->bound || { DEBUG(D_lookup) debug_printf("%sbinding with user=%s password=%s\n", (lcp->bound)? "re-" : "", user, password); - if (eldap_start_tls && !lcp->is_start_tls_called) + if (eldap_start_tls && !lcp->is_start_tls_called && !ldapi) { #if defined(LDAP_OPT_X_TLS) && !defined(LDAP_LIB_SOLARIS) /* The Oracle LDAP libraries (LDAP_LIB_TYPE=SOLARIS) don't support this. @@ -713,11 +711,16 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == LDAP_RES_SEARCH_ENTRY) { LDAPMessage *e; + int valuecount; /* We can see an attr spread across several + entries. If B is derived from A and we request + A and the directory contains both, A and B, + then we get two entries, one for A and one for B. + Here we just count the values per entry */ - DEBUG(D_lookup) debug_printf("ldap_result loop\n"); + DEBUG(D_lookup) debug_printf("LDAP result loop\n"); - for(e = ldap_first_entry(lcp->ld, result); - e != NULL; + for(e = ldap_first_entry(lcp->ld, result), valuecount = 0; + e; e = ldap_next_entry(lcp->ld, e)) { uschar *new_dn; @@ -729,7 +732,7 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Results for multiple entries values are separated by newlines. */ - if (data != NULL) data = string_cat(data, &size, &ptr, US"\n", 1); + if (data) data = string_catn(data, US"\n", 1); /* Get the DN from the last result. */ @@ -757,73 +760,79 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == { /* condition, because of the else */ if (new_dn != NULL) /* below, that's for the first only */ { - data = string_cat(data, &size, &ptr, new_dn, Ustrlen(new_dn)); - data[ptr] = 0; + data = string_cat(data, new_dn); + (void) string_from_gstring(data); attribute_found = TRUE; } } /* Otherwise, loop through the entry, grabbing attribute values. If there's only one attribute being retrieved, no attribute name is given, and the - result is not quoted. Multiple values are separated by (comma, space). + result is not quoted. Multiple values are separated by (comma). If more than one attribute is being retrieved, the data is given as a - sequence of name=value pairs, with the value always in quotes. If there are - multiple values, they are given within the quotes, comma separated. */ + sequence of name=value pairs, separated by (space), with the value always in quotes. + If there are multiple values, they are given within the quotes, comma separated. */ else for (attr = US ldap_first_attribute(lcp->ld, e, &ber); - attr != NULL; - attr = US ldap_next_attribute(lcp->ld, e, ber)) + attr; attr = US ldap_next_attribute(lcp->ld, e, ber)) { + DEBUG(D_lookup) debug_printf("LDAP attr loop\n"); + + /* In case of attrs_requested == 1 we just count the values, in all other cases + (0, >1) we count the values per attribute */ + if (attrs_requested != 1) valuecount = 0; + if (attr[0] != 0) { /* Get array of values for this attribute. */ - if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr)) - != NULL) + if ((firstval = values = USS ldap_get_values(lcp->ld, e, CS attr))) { - if (attr_count != 1) + + if (attrs_requested != 1) { if (insert_space) - data = string_cat(data, &size, &ptr, US" ", 1); + data = string_catn(data, US" ", 1); else insert_space = TRUE; - data = string_cat(data, &size, &ptr, attr, Ustrlen(attr)); - data = string_cat(data, &size, &ptr, US"=\"", 2); + data = string_cat(data, attr); + data = string_catn(data, US"=\"", 2); } - while (*values != NULL) + while (*values) { uschar *value = *values; int len = Ustrlen(value); + ++valuecount; + + DEBUG(D_lookup) debug_printf("LDAP value loop %s:%s\n", attr, value); - DEBUG(D_lookup) debug_printf("LDAP attr loop %s:%s\n", attr, value); + /* In case we requested one attribute only but got several times + into that attr loop, we need to append the additional values. + (This may happen if you derive attributeTypes B and C from A and + then query for A.) In all other cases we detect the different + attribute and append only every non first value. */ - /* In case we requested one attribute only but got - * several times into that attr loop, we need to append - * the additional values. (This may happen if you derive - * attributeTypes B and C from A and then query for A.) - * In all other cases we detect the different attribute - * and append only every non first value. */ - if ((attr_count == 1 && data) || (values != firstval)) - data = string_cat(data, &size, &ptr, US",", 1); + if (data && valuecount > 1) + data = string_catn(data, US",", 1); /* For multiple attributes, the data is in quotes. We must escape internal quotes, backslashes, newlines, and must double commas. */ - if (attr_count != 1) + if (attrs_requested != 1) { int j; for (j = 0; j < len; j++) { if (value[j] == '\n') - data = string_cat(data, &size, &ptr, US"\\n", 2); + data = string_catn(data, US"\\n", 2); else if (value[j] == ',') - data = string_cat(data, &size, &ptr, US",,", 2); + data = string_catn(data, US",,", 2); else { if (value[j] == '\"' || value[j] == '\\') - data = string_cat(data, &size, &ptr, US"\\", 1); - data = string_cat(data, &size, &ptr, value+j, 1); + data = string_catn(data, US"\\", 1); + data = string_catn(data, value+j, 1); } } } @@ -834,12 +843,10 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == { int j; for (j = 0; j < len; j++) - { if (value[j] == ',') - data = string_cat(data, &size, &ptr, US",,", 2); + data = string_catn(data, US",,", 2); else - data = string_cat(data, &size, &ptr, value+j, 1); - } + data = string_catn(data, value+j, 1); } @@ -851,8 +858,8 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Closing quote at the end of the data for a named attribute. */ - if (attr_count != 1) - data = string_cat(data, &size, &ptr, US"\"", 1); + if (attrs_requested != 1) + data = string_catn(data, US"\"", 1); /* Free the values */ @@ -879,15 +886,15 @@ while ((rc = ldap_result(lcp->ld, msgid, 0, timeoutptr, &result)) == /* Terminate the dynamic string that we have built and reclaim unused store */ -if (data != NULL) +if (data) { - data[ptr] = 0; - store_reset(data + ptr + 1); + (void) string_from_gstring(data); + store_reset(data->s + data->ptr + 1); } /* Copy the last dn into eldap_dn */ -if (dn != NULL) +if (dn) { eldap_dn = string_copy(dn); #if defined LDAP_LIB_NETSCAPE || defined LDAP_LIB_OPENLDAP2 @@ -1066,8 +1073,8 @@ if (!attribute_found) /* Otherwise, it's all worked */ -DEBUG(D_lookup) debug_printf("LDAP search: returning: %s\n", data); -*res = data; +DEBUG(D_lookup) debug_printf("LDAP search: returning: %s\n", data->s); +*res = data->s; RETURN_OK: if (result != NULL) ldap_msgfree(result);