diff options
Diffstat (limited to 'lib/ldap.c')
-rw-r--r-- | lib/ldap.c | 622 |
1 files changed, 463 insertions, 159 deletions
@@ -5,7 +5,7 @@ * | (__| |_| | _ <| |___ * \___|\___/|_| \_\_____| * - * Copyright (C) 1998 - 2014, Daniel Stenberg, <daniel@haxx.se>, et al. + * Copyright (C) 1998 - 2015, Daniel Stenberg, <daniel@haxx.se>, et al. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms @@ -35,7 +35,7 @@ * OpenLDAP library versions, USE_OPENLDAP shall not be defined. */ -#ifdef CURL_LDAP_WIN /* Use Windows LDAP implementation. */ +#ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */ # include <winldap.h> # ifndef LDAP_VENDOR_NAME # error Your Platform SDK is NOT sufficient for LDAP support! \ @@ -54,6 +54,15 @@ # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */ #endif +/* These are macros in both <wincrypt.h> (in above <winldap.h>) and typedefs + * in BoringSSL's <openssl/x509.h> + */ +#ifdef HAVE_BORINGSSL +# undef X509_NAME +# undef X509_CERT_PAIR +# undef X509_EXTENSIONS +#endif + #include "urldata.h" #include <curl/curl.h> #include "sendf.h" @@ -63,14 +72,14 @@ #include "strequal.h" #include "strtok.h" #include "curl_ldap.h" -#include "curl_memory.h" +#include "curl_multibyte.h" #include "curl_base64.h" #include "rawstr.h" #include "connect.h" +#include "curl_printf.h" -#define _MPRINTF_REPLACE /* use our functions only */ -#include <curl/mprintf.h> - +/* The last #include files should be: */ +#include "curl_memory.h" #include "memdebug.h" #ifndef HAVE_LDAP_URL_PARSE @@ -80,10 +89,19 @@ typedef struct { char *lud_host; int lud_port; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_dn; + TCHAR **lud_attrs; +#else char *lud_dn; char **lud_attrs; +#endif int lud_scope; +#if defined(USE_WIN32_LDAP) + TCHAR *lud_filter; +#else char *lud_filter; +#endif char **lud_exts; size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the "real" struct so can only be used in code @@ -168,11 +186,11 @@ const struct Curl_handler Curl_handler_ldaps = { static CURLcode Curl_ldap(struct connectdata *conn, bool *done) { - CURLcode status = CURLE_OK; + CURLcode result = CURLE_OK; int rc = 0; LDAP *server = NULL; LDAPURLDesc *ludp = NULL; - LDAPMessage *result = NULL; + LDAPMessage *ldapmsg = NULL; LDAPMessage *entryIterator; int num = 0; struct SessionHandle *data=conn->data; @@ -182,7 +200,16 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) size_t val_b64_sz = 0; curl_off_t dlsize = 0; #ifdef LDAP_OPT_NETWORK_TIMEOUT - struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ + struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */ +#endif +#if defined(USE_WIN32_LDAP) + TCHAR *host = NULL; + TCHAR *user = NULL; + TCHAR *passwd = NULL; +#else + char *host = NULL; + char *user = NULL; + char *passwd = NULL; #endif *done = TRUE; /* unconditionally */ @@ -197,7 +224,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) #endif if(rc != 0) { failf(data, "LDAP local: %s", ldap_err2string(rc)); - status = CURLE_LDAP_INVALID_URL; + result = CURLE_LDAP_INVALID_URL; goto quit; } @@ -207,6 +234,32 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) infof(data, "LDAP local: trying to establish %s connection\n", ldap_ssl ? "encrypted" : "cleartext"); +#if defined(USE_WIN32_LDAP) + host = Curl_convert_UTF8_to_tchar(conn->host.name); + if(!host) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + + if(conn->bits.user_passwd) { + user = Curl_convert_UTF8_to_tchar(conn->user); + passwd = Curl_convert_UTF8_to_tchar(conn->passwd); + if(!user || !passwd) { + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } + } +#else + host = conn->host.name; + + if(conn->bits.user_passwd) { + user = conn->user; + passwd = conn->passwd; + } +#endif + #ifdef LDAP_OPT_NETWORK_TIMEOUT ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); #endif @@ -214,9 +267,9 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(ldap_ssl) { #ifdef HAVE_LDAP_SSL -#ifdef CURL_LDAP_WIN +#ifdef USE_WIN32_LDAP /* Win32 LDAP SDK doesn't support insecure mode without CA! */ - server = ldap_sslinit(conn->host.name, (int)conn->port, 1); + server = ldap_sslinit(host, (int)conn->port, 1); ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); #else int ldap_option; @@ -225,7 +278,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) rc = ldapssl_client_init(NULL, NULL); if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(data->set.ssl.verifypeer) { @@ -237,7 +290,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(!ldap_ca) { failf(data, "LDAP local: ERROR %s CA cert not set!", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using %s CA cert '%s'\n", @@ -248,7 +301,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) failf(data, "LDAP local: ERROR setting %s CA cert: %s", (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAPSSL_VERIFY_SERVER; @@ -259,14 +312,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldapssl_init(conn->host.name, (int)conn->port, 1); + server = ldapssl_init(host, (int)conn->port, 1); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } #elif defined(LDAP_OPT_X_TLS) @@ -275,12 +328,12 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if((data->set.str[STRING_CERT_TYPE]) && (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } if(!ldap_ca) { failf(data, "LDAP local: ERROR PEM CA cert not set!"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); @@ -288,7 +341,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting PEM CA cert: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } ldap_option = LDAP_OPT_X_TLS_DEMAND; @@ -300,14 +353,14 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting cert verify mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } - server = ldap_init(conn->host.name, (int)conn->port); + server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } ldap_option = LDAP_OPT_X_TLS_HARD; @@ -315,7 +368,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } /* @@ -323,7 +376,7 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) if(rc != LDAP_SUCCESS) { failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", ldap_err2string(rc)); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; } */ @@ -332,126 +385,278 @@ static CURLcode Curl_ldap(struct connectdata *conn, bool *done) should check in first place if we can support LDAP SSL/TLS */ failf(data, "LDAP local: SSL/TLS not supported with this version " "of the OpenLDAP toolkit\n"); - status = CURLE_SSL_CERTPROBLEM; + result = CURLE_SSL_CERTPROBLEM; goto quit; #endif #endif #endif /* CURL_LDAP_USE_SSL */ } else { - server = ldap_init(conn->host.name, (int)conn->port); + server = ldap_init(host, (int)conn->port); if(server == NULL) { failf(data, "LDAP local: Cannot connect to %s:%ld", - conn->host.name, conn->port); - status = CURLE_COULDNT_CONNECT; + conn->host.dispname, conn->port); + result = CURLE_COULDNT_CONNECT; goto quit; } } -#ifdef CURL_LDAP_WIN +#ifdef USE_WIN32_LDAP ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); #endif - rc = ldap_simple_bind_s(server, - conn->bits.user_passwd ? conn->user : NULL, - conn->bits.user_passwd ? conn->passwd : NULL); + rc = ldap_simple_bind_s(server, user, passwd); if(!ldap_ssl && 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); + rc = ldap_simple_bind_s(server, user, passwd); } if(rc != 0) { failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); - status = CURLE_LDAP_CANNOT_BIND; + result = CURLE_LDAP_CANNOT_BIND; goto quit; } rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, - ludp->lud_filter, ludp->lud_attrs, 0, &result); + ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg); if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { failf(data, "LDAP remote: %s", ldap_err2string(rc)); - status = CURLE_LDAP_SEARCH_FAILED; + result = CURLE_LDAP_SEARCH_FAILED; goto quit; } - for(num = 0, entryIterator = ldap_first_entry(server, result); + for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg); entryIterator; entryIterator = ldap_next_entry(server, entryIterator), num++) { BerElement *ber = NULL; +#if defined(USE_WIN32_LDAP) + TCHAR *attribute; +#else char *attribute; /*! suspicious that this isn't 'const' */ - char *dn = ldap_get_dn(server, entryIterator); +#endif int i; - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + /* Get the DN and write it to the client */ + { + char *name; + size_t name_len; +#if defined(USE_WIN32_LDAP) + TCHAR *dn = ldap_get_dn(server, entryIterator); + name = Curl_convert_tchar_to_UTF8(dn); + if(!name) { + ldap_memfree(dn); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *dn = name = ldap_get_dn(server, entryIterator); +#endif + name_len = strlen(name); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name, + name_len); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + + goto quit; + } - dlsize += strlen(dn)+5; + dlsize += name_len + 5; +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(name); +#endif + ldap_memfree(dn); + } + + /* Get the attributes and write them to the client */ for(attribute = ldap_first_attribute(server, entryIterator, &ber); attribute; attribute = ldap_next_attribute(server, entryIterator, ber)) { - BerValue **vals = ldap_get_values_len(server, entryIterator, attribute); + BerValue **vals; + size_t attr_len; +#if defined(USE_WIN32_LDAP) + char *attr = Curl_convert_tchar_to_UTF8(attribute); + if(!attr) { + if(ber) + ber_free(ber, 0); + + result = CURLE_OUT_OF_MEMORY; + + goto quit; + } +#else + char *attr = attribute; +#endif + attr_len = strlen(attr); + vals = ldap_get_values_len(server, entryIterator, attribute); if(vals != NULL) { for(i = 0; (vals[i] != NULL); i++) { - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); - dlsize += strlen(attribute)+3; - - if((strlen(attribute) > 7) && - (strcmp(";binary", - (char *)attribute + - (strlen((char *)attribute) - 7)) == 0)) { + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, + (char *) attr, attr_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + + dlsize += attr_len + 3; + + if((attr_len > 7) && + (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) { /* Binary attribute, encode to base64. */ - CURLcode error = Curl_base64_encode(data, - vals[i]->bv_val, - vals[i]->bv_len, - &val_b64, - &val_b64_sz); - if(error) { + result = Curl_base64_encode(data, + vals[i]->bv_val, + vals[i]->bv_len, + &val_b64, + &val_b64_sz); + if(result) { ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif ldap_memfree(attribute); - ldap_memfree(dn); if(ber) ber_free(ber, 0); - status = error; + goto quit; } + if(val_b64_sz > 0) { - Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); + result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, + val_b64_sz); free(val_b64); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += val_b64_sz; } } else { - Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, - vals[i]->bv_len); + result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, + vals[i]->bv_len); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize += vals[i]->bv_len; } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) { + ldap_value_free_len(vals); +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + if(ber) + ber_free(ber, 0); + + goto quit; + } + dlsize++; } /* Free memory used to store values */ ldap_value_free_len(vals); } - Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + + /* Free the attribute as we are done with it */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(attr); +#endif + ldap_memfree(attribute); + + result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); + if(result) + goto quit; dlsize++; Curl_pgrsSetDownloadCounter(data, dlsize); - ldap_memfree(attribute); } - ldap_memfree(dn); + if(ber) ber_free(ber, 0); } quit: - if(result) { - ldap_msgfree(result); + if(ldapmsg) { + ldap_msgfree(ldapmsg); LDAP_TRACE (("Received %d entries\n", num)); } if(rc == LDAP_SIZELIMIT_EXCEEDED) @@ -465,11 +670,17 @@ quit: ldapssl_client_deinit(); #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ +#if defined(USE_WIN32_LDAP) + Curl_unicodefree(passwd); + Curl_unicodefree(user); + Curl_unicodefree(host); +#endif + /* no data to transfer */ Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); connclose(conn, "LDAP connection always disable re-use"); - return status; + return result; } #ifdef DEBUG_LDAP @@ -513,57 +724,34 @@ static int str2scope (const char *p) /* * Split 'str' into strings separated by commas. - * Note: res[] points into 'str'. + * Note: out[] points into 'str'. */ -static char **split_str (char *str) +static bool split_str(char *str, char ***out, size_t *count) { - char **res, *lasts, *s; - int i; - - for(i = 2, s = strchr(str,','); s; i++) - s = strchr(++s,','); + char **res; + char *lasts; + char *s; + size_t i; + size_t items = 1; + + s = strchr(str, ','); + while(s) { + items++; + s = strchr(++s, ','); + } - res = calloc(i, sizeof(char*)); + res = calloc(items, sizeof(char *)); if(!res) - return NULL; + return FALSE; - for(i = 0, s = strtok_r(str, ",", &lasts); s; + for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items; s = strtok_r(NULL, ",", &lasts), i++) res[i] = s; - return res; -} - -/* - * Unescape the LDAP-URL components - */ -static bool unescape_elements (void *data, LDAPURLDesc *ludp) -{ - int i; - - if(ludp->lud_filter) { - ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); - if(!ludp->lud_filter) - return FALSE; - } - - for(i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { - ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], - 0, NULL); - if(!ludp->lud_attrs[i]) - return FALSE; - ludp->lud_attrs_dups++; - } - if(ludp->lud_dn) { - char *dn = ludp->lud_dn; - char *new_dn = curl_easy_unescape(data, dn, 0, NULL); + *out = res; + *count = items; - free(dn); - ludp->lud_dn = new_dn; - if(!new_dn) - return (FALSE); - } - return (TRUE); + return TRUE; } /* @@ -582,8 +770,11 @@ static bool unescape_elements (void *data, LDAPURLDesc *ludp) */ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) { - char *p, *q; - int i; + int rc = LDAP_SUCCESS; + char *path; + char *p; + char *q; + size_t i; if(!conn->data || !conn->data->state.path || @@ -595,74 +786,190 @@ static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) ludp->lud_port = conn->remote_port; ludp->lud_host = conn->host.name; - /* parse DN (Distinguished Name). - */ - ludp->lud_dn = strdup(conn->data->state.path+1); - if(!ludp->lud_dn) + /* Duplicate the path */ + p = path = strdup(conn->data->state.path + 1); + if(!path) 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)); + /* Parse the DN (Distinguished Name) */ + q = strchr(p, '?'); + if(q) + *q++ = '\0'; + + if(*p) { + char *dn = p; + char *unescaped; - if(!p) - goto success; + LDAP_TRACE (("DN '%s'\n", dn)); - *p++ = '\0'; + /* Unescape the DN */ + unescaped = curl_easy_unescape(conn->data, dn, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; - /* parse attributes. skip "??". - */ + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_dn) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_dn = unescaped; +#endif + } + + p = q; + if(!p) + goto quit; + + /* Parse the attributes. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { - ludp->lud_attrs = split_str(p); - if(!ludp->lud_attrs) - return LDAP_NO_MEMORY; + if(*p) { + char **attributes; + size_t count = 0; + + /* Split the string into an array of attributes */ + if(!split_str(p, &attributes, &count)) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + + /* Allocate our array (+1 for the NULL entry) */ +#if defined(USE_WIN32_LDAP) + ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *)); +#else + ludp->lud_attrs = calloc(count + 1, sizeof(char *)); +#endif + if(!ludp->lud_attrs) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + + for(i = 0; i < count; i++) { + char *unescaped; + + LDAP_TRACE (("attr[%d] '%s'\n", i, attributes[i])); + + /* Unescape the attribute */ + unescaped = curl_easy_unescape(conn->data, attributes[i], 0, NULL); + if(!unescaped) { + free(attributes); + + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_attrs[i]) { + free(attributes); - for(i = 0; ludp->lud_attrs[i]; i++) - LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_attrs[i] = unescaped; +#endif + + ludp->lud_attrs_dups++; + } + + free(attributes); } p = q; if(!p) - goto success; + goto quit; - /* parse scope. skip "??" - */ + /* Parse the scope. skip "??" */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(*p && *p != '?') { + if(*p) { ludp->lud_scope = str2scope(p); if(ludp->lud_scope == -1) { - return LDAP_INVALID_SYNTAX; + rc = LDAP_INVALID_SYNTAX; + + goto quit; } LDAP_TRACE (("scope %d\n", ludp->lud_scope)); } p = q; if(!p) - goto success; + goto quit; - /* parse filter - */ + /* Parse the filter */ q = strchr(p, '?'); if(q) *q++ = '\0'; - if(!*p) { - return LDAP_INVALID_SYNTAX; + + if(*p) { + char *filter = p; + char *unescaped; + + LDAP_TRACE (("filter '%s'\n", filter)); + + /* Unescape the filter */ + unescaped = curl_easy_unescape(conn->data, filter, 0, NULL); + if(!unescaped) { + rc = LDAP_NO_MEMORY; + + goto quit; + } + +#if defined(USE_WIN32_LDAP) + /* Convert the unescaped string to a tchar */ + ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped); + + /* Free the unescaped string as we are done with it */ + Curl_unicodefree(unescaped); + + if(!ludp->lud_filter) { + rc = LDAP_NO_MEMORY; + + goto quit; + } +#else + ludp->lud_filter = unescaped; +#endif } - ludp->lud_filter = p; - LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); + p = q; + if(p && !*p) { + rc = LDAP_INVALID_SYNTAX; - success: - if(!unescape_elements(conn->data, ludp)) - return LDAP_NO_MEMORY; - return LDAP_SUCCESS; + goto quit; + } + +quit: + free(path); + + return rc; } static int _ldap_url_parse (const struct connectdata *conn, @@ -691,11 +998,8 @@ static void _ldap_free_urldesc (LDAPURLDesc *ludp) if(!ludp) return; - if(ludp->lud_dn) - free(ludp->lud_dn); - - if(ludp->lud_filter) - free(ludp->lud_filter); + free(ludp->lud_dn); + free(ludp->lud_filter); if(ludp->lud_attrs) { for(i = 0; i < ludp->lud_attrs_dups; i++) |