diff --git a/CHANGES b/CHANGES index 9748b662c..c6e46d924 100644 --- a/CHANGES +++ b/CHANGES @@ -8,6 +8,21 @@ +Daniel (31 October 2005) +- Vilmos Nebehaj improved libcurl's LDAP abilities: + + The LDAP code in libcurl can't handle LDAP servers of LDAPv3 nor binary + attributes in LDAP objects. So, I made a quick patch to address these + problems. + + The solution is simple: if we connect to an LDAP server, first try LDAPv3 + (which is the preferred protocol as of now) and then fall back to LDAPv2. + In case of binary attributes, we first convert them to base64, just like the + openldap client does. It uses ldap_get_values_len() instead of + ldap_get_values() to be able to retrieve binary attributes correctly. I + defined the necessary LDAP macros in lib/ldap.c to be able to compile + libcurl without the presence of libldap + Daniel (27 October 2005) - Nis Jorgensen filed bug report #1338648 (http://curl.haxx.se/bug/view.cgi?id=1338648) which really is more of a diff --git a/RELEASE-NOTES b/RELEASE-NOTES index 70e2b8fa4..06bbe468f 100644 --- a/RELEASE-NOTES +++ b/RELEASE-NOTES @@ -11,11 +11,13 @@ Curl and libcurl 7.15.1 This release includes the following changes: + o LDAPv3 is now the preferred LDAP protocol version o --max-redirs and CURLOPT_MAXREDIRS set to 0 limits redirects o improved MSVC makefile This release includes the following bugfixes: + o binary LDAP properties are now shown base64 encoded o Windows uploads from stdin using curl can now contain ctrl-Z bytes o -r [num] would produce an invalid HTTP Range: header o multi interface with multi IP hosts could leak socket descriptors @@ -36,6 +38,6 @@ This release would not have looked like this without help, code, reports and advice from friends like these: Dave Dribin, Bradford Bruce, Temprimus, Ofer, Dima Barsky, Amol Pattekar, Jaz - Fresh, tommink[at]post.pl, Gisle Vanem, Nis Jorgensen + Fresh, tommink[at]post.pl, Gisle Vanem, Nis Jorgensen, Vilmos Nebehaj Thanks! (and sorry if I forgot to mention someone) diff --git a/lib/ldap.c b/lib/ldap.c index bb8a84933..729b4e2ab 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -61,6 +61,7 @@ #include "strtok.h" #include "ldap.h" #include "memory.h" +#include "base64.h" #define _MPRINTF_REPLACE /* use our functions only */ #include @@ -78,6 +79,15 @@ #ifndef LDAP_SIZELIMIT_EXCEEDED #define LDAP_SIZELIMIT_EXCEEDED 4 #endif +#ifndef LDAP_VERSION2 +#define LDAP_VERSION2 2 +#endif +#ifndef LDAP_VERSION3 +#define LDAP_VERSION3 3 +#endif +#ifndef LDAP_OPT_PROTOCOL_VERSION +#define LDAP_OPT_PROTOCOL_VERSION 0x0011 +#endif #define DLOPEN_MODE RTLD_LAZY /*! assume all dlopen() implementations have this */ @@ -115,6 +125,11 @@ static void *liblber = NULL; #endif #endif +struct bv { + unsigned long bv_len; + char *bv_val; +}; + static int DynaOpen(const char **mod_name) { #if defined(HAVE_DLOPEN) || defined(HAVE_LIBDL) @@ -247,10 +262,11 @@ CURLcode Curl_ldap(struct connectdata *conn, bool *done) char *(__cdecl *ldap_get_dn)(void *, void *); char *(__cdecl *ldap_first_attribute)(void *, void *, void **); char *(__cdecl *ldap_next_attribute)(void *, void *, void *); - char **(__cdecl *ldap_get_values)(void *, void *, const char *); - void (__cdecl *ldap_value_free)(char **); + void **(__cdecl *ldap_get_values_len)(void *, void *, const char *); + void (__cdecl *ldap_value_free_len)(void **); void (__cdecl *ldap_memfree)(void *); void (__cdecl *ber_free)(void *, int); + int (__cdecl *ldap_set_option)(void *, int, void *); void *server; LDAPURLDesc *ludp = NULL; @@ -259,6 +275,9 @@ CURLcode Curl_ldap(struct connectdata *conn, bool *done) void *entryIterator; /*! type should be 'LDAPMessage *' */ int num = 0; struct SessionHandle *data=conn->data; + int ldap_proto; + char *val_b64; + size_t val_b64_sz; *done = TRUE; /* unconditionally */ infof(data, "LDAP local: %s\n", data->change.url); @@ -272,24 +291,29 @@ CURLcode Curl_ldap(struct connectdata *conn, bool *done) * pointer-to-object (data) and pointer-to-function. */ DYNA_GET_FUNCTION(void *(__cdecl *)(char *, int), ldap_init); - DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *), ldap_simple_bind_s); + DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, char *), + ldap_simple_bind_s); DYNA_GET_FUNCTION(int (__cdecl *)(void *), ldap_unbind_s); #ifndef WIN32 DYNA_GET_FUNCTION(int (*)(char *, LDAPURLDesc **), ldap_url_parse); DYNA_GET_FUNCTION(void (*)(void *), ldap_free_urldesc); #endif DYNA_GET_FUNCTION(int (__cdecl *)(void *, char *, int, char *, char **, int, - void **), ldap_search_s); + void **), ldap_search_s); DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_first_entry); DYNA_GET_FUNCTION(void *(__cdecl *)(void *, void *), ldap_next_entry); DYNA_GET_FUNCTION(char *(__cdecl *)(int), ldap_err2string); DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *), ldap_get_dn); - DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **), ldap_first_attribute); - DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *), ldap_next_attribute); - DYNA_GET_FUNCTION(char **(__cdecl *)(void *, void *, const char *), ldap_get_values); - DYNA_GET_FUNCTION(void (__cdecl *)(char **), ldap_value_free); + DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void **), + ldap_first_attribute); + DYNA_GET_FUNCTION(char *(__cdecl *)(void *, void *, void *), + ldap_next_attribute); + DYNA_GET_FUNCTION(void **(__cdecl *)(void *, void *, const char *), + ldap_get_values_len); + DYNA_GET_FUNCTION(void (__cdecl *)(void **), ldap_value_free_len); DYNA_GET_FUNCTION(void (__cdecl *)(void *), ldap_memfree); DYNA_GET_FUNCTION(void (__cdecl *)(void *, int), ber_free); + DYNA_GET_FUNCTION(int (__cdecl *)(void *, int, void *), ldap_set_option); server = (*ldap_init)(conn->host.name, (int)conn->port); if (server == NULL) { @@ -299,9 +323,18 @@ CURLcode Curl_ldap(struct connectdata *conn, bool *done) goto quit; } + ldap_proto = LDAP_VERSION3; + (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); rc = (*ldap_simple_bind_s)(server, conn->bits.user_passwd ? conn->user : NULL, conn->bits.user_passwd ? conn->passwd : NULL); + if (rc != 0) { + ldap_proto = LDAP_VERSION2; + (*ldap_set_option)(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); + rc = (*ldap_simple_bind_s)(server, + conn->bits.user_passwd ? conn->user : NULL, + conn->bits.user_passwd ? conn->passwd : NULL); + } if (rc != 0) { failf(data, "LDAP local: %s", (*ldap_err2string)(rc)); status = CURLE_LDAP_CANNOT_BIND; @@ -346,21 +379,35 @@ CURLcode Curl_ldap(struct connectdata *conn, bool *done) attribute; attribute = (*ldap_next_attribute)(server, entryIterator, ber)) { - char **vals = (*ldap_get_values)(server, entryIterator, attribute); + struct bv **vals = (struct bv **) + (*ldap_get_values_len)(server, entryIterator, attribute); if (vals != NULL) { for (i = 0; (vals[i] != NULL); i++) { Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(data, CLIENTWRITE_BODY, (char*) attribute, 0); + Curl_client_write(data, CLIENTWRITE_BODY, (char *) attribute, 0); Curl_client_write(data, CLIENTWRITE_BODY, (char *)": ", 2); - Curl_client_write(data, CLIENTWRITE_BODY, vals[i], 0); + if ((strlen(attribute) > 7) && + (strcmp(";binary", + (char *)attribute + + (strlen((char *)attribute) - 7)) == 0)) { + /* Binary attribute, encode to base64. */ + val_b64_sz = Curl_base64_encode(vals[i]->bv_val, vals[i]->bv_len, + &val_b64); + if (val_b64_sz > 0) { + Curl_client_write(data, CLIENTWRITE_BODY, val_b64, val_b64_sz); + free(val_b64); + } + } else + Curl_client_write(data, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 0); } /* Free memory used to store values */ - (*ldap_value_free)(vals); + (*ldap_value_free_len)((void **)vals); } Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1); @@ -518,8 +565,8 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) return LDAP_NO_MEMORY; p = strchr(ludp->lud_dn, '?'); - LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : strlen(ludp->lud_dn), - ludp->lud_dn)); + LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : + strlen(ludp->lud_dn), ludp->lud_dn)); if (!p) goto success;