ldap.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                      _   _ ____  _
00003  *  Project         ___| | | |  _ \| |
00004  *                 / __| | | | |_) | |
00005  *                | (__| |_| |  _ <| |___
00006  *                 \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
00026 
00027 /*
00028  * Notice that USE_OPENLDAP is only a source code selection switch. When
00029  * libcurl is built with USE_OPENLDAP defined the libcurl source code that
00030  * gets compiled is the code from openldap.c, otherwise the code that gets
00031  * compiled is the code from ldap.c.
00032  *
00033  * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
00034  * might be required for compilation and runtime. In order to use ancient
00035  * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
00036  */
00037 
00038 #ifdef USE_WIN32_LDAP           /* Use Windows LDAP implementation. */
00039 # include <winldap.h>
00040 # ifndef LDAP_VENDOR_NAME
00041 #  error Your Platform SDK is NOT sufficient for LDAP support! \
00042          Update your Platform SDK, or disable LDAP support!
00043 # else
00044 #  include <winber.h>
00045 # endif
00046 #else
00047 # define LDAP_DEPRECATED 1      /* Be sure ldap_init() is defined. */
00048 # ifdef HAVE_LBER_H
00049 #  include <lber.h>
00050 # endif
00051 # include <ldap.h>
00052 # if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
00053 #  include <ldap_ssl.h>
00054 # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
00055 #endif
00056 
00057 /* These are macros in both <wincrypt.h> (in above <winldap.h>) and typedefs
00058  * in BoringSSL's <openssl/x509.h>
00059  */
00060 #ifdef HAVE_BORINGSSL
00061 # undef X509_NAME
00062 # undef X509_CERT_PAIR
00063 # undef X509_EXTENSIONS
00064 #endif
00065 
00066 #include "urldata.h"
00067 #include <curl/curl.h>
00068 #include "sendf.h"
00069 #include "escape.h"
00070 #include "progress.h"
00071 #include "transfer.h"
00072 #include "strcase.h"
00073 #include "strtok.h"
00074 #include "curl_ldap.h"
00075 #include "curl_multibyte.h"
00076 #include "curl_base64.h"
00077 #include "connect.h"
00078 /* The last 3 #include files should be in this order */
00079 #include "curl_printf.h"
00080 #include "curl_memory.h"
00081 #include "memdebug.h"
00082 
00083 #ifndef HAVE_LDAP_URL_PARSE
00084 
00085 /* Use our own implementation. */
00086 
00087 typedef struct {
00088   char   *lud_host;
00089   int     lud_port;
00090 #if defined(USE_WIN32_LDAP)
00091   TCHAR  *lud_dn;
00092   TCHAR **lud_attrs;
00093 #else
00094   char   *lud_dn;
00095   char  **lud_attrs;
00096 #endif
00097   int     lud_scope;
00098 #if defined(USE_WIN32_LDAP)
00099   TCHAR  *lud_filter;
00100 #else
00101   char   *lud_filter;
00102 #endif
00103   char  **lud_exts;
00104   size_t    lud_attrs_dups; /* how many were dup'ed, this field is not in the
00105                                "real" struct so can only be used in code
00106                                without HAVE_LDAP_URL_PARSE defined */
00107 } CURL_LDAPURLDesc;
00108 
00109 #undef LDAPURLDesc
00110 #define LDAPURLDesc             CURL_LDAPURLDesc
00111 
00112 static int  _ldap_url_parse(const struct connectdata *conn,
00113                             LDAPURLDesc **ludp);
00114 static void _ldap_free_urldesc(LDAPURLDesc *ludp);
00115 
00116 #undef ldap_free_urldesc
00117 #define ldap_free_urldesc       _ldap_free_urldesc
00118 #endif
00119 
00120 #ifdef DEBUG_LDAP
00121   #define LDAP_TRACE(x)   do { \
00122                             _ldap_trace("%u: ", __LINE__); \
00123                             _ldap_trace x; \
00124                           } WHILE_FALSE
00125 
00126   static void _ldap_trace(const char *fmt, ...);
00127 #else
00128   #define LDAP_TRACE(x)   Curl_nop_stmt
00129 #endif
00130 
00131 
00132 static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
00133 
00134 /*
00135  * LDAP protocol handler.
00136  */
00137 
00138 const struct Curl_handler Curl_handler_ldap = {
00139   "LDAP",                               /* scheme */
00140   ZERO_NULL,                            /* setup_connection */
00141   Curl_ldap,                            /* do_it */
00142   ZERO_NULL,                            /* done */
00143   ZERO_NULL,                            /* do_more */
00144   ZERO_NULL,                            /* connect_it */
00145   ZERO_NULL,                            /* connecting */
00146   ZERO_NULL,                            /* doing */
00147   ZERO_NULL,                            /* proto_getsock */
00148   ZERO_NULL,                            /* doing_getsock */
00149   ZERO_NULL,                            /* domore_getsock */
00150   ZERO_NULL,                            /* perform_getsock */
00151   ZERO_NULL,                            /* disconnect */
00152   ZERO_NULL,                            /* readwrite */
00153   PORT_LDAP,                            /* defport */
00154   CURLPROTO_LDAP,                       /* protocol */
00155   PROTOPT_NONE                          /* flags */
00156 };
00157 
00158 #ifdef HAVE_LDAP_SSL
00159 /*
00160  * LDAPS protocol handler.
00161  */
00162 
00163 const struct Curl_handler Curl_handler_ldaps = {
00164   "LDAPS",                              /* scheme */
00165   ZERO_NULL,                            /* setup_connection */
00166   Curl_ldap,                            /* do_it */
00167   ZERO_NULL,                            /* done */
00168   ZERO_NULL,                            /* do_more */
00169   ZERO_NULL,                            /* connect_it */
00170   ZERO_NULL,                            /* connecting */
00171   ZERO_NULL,                            /* doing */
00172   ZERO_NULL,                            /* proto_getsock */
00173   ZERO_NULL,                            /* doing_getsock */
00174   ZERO_NULL,                            /* domore_getsock */
00175   ZERO_NULL,                            /* perform_getsock */
00176   ZERO_NULL,                            /* disconnect */
00177   ZERO_NULL,                            /* readwrite */
00178   PORT_LDAPS,                           /* defport */
00179   CURLPROTO_LDAPS,                      /* protocol */
00180   PROTOPT_SSL                           /* flags */
00181 };
00182 #endif
00183 
00184 
00185 static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
00186 {
00187   CURLcode result = CURLE_OK;
00188   int rc = 0;
00189   LDAP *server = NULL;
00190   LDAPURLDesc *ludp = NULL;
00191   LDAPMessage *ldapmsg = NULL;
00192   LDAPMessage *entryIterator;
00193   int num = 0;
00194   struct Curl_easy *data=conn->data;
00195   int ldap_proto = LDAP_VERSION3;
00196   int ldap_ssl = 0;
00197   char *val_b64 = NULL;
00198   size_t val_b64_sz = 0;
00199   curl_off_t dlsize = 0;
00200 #ifdef LDAP_OPT_NETWORK_TIMEOUT
00201   struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
00202 #endif
00203 #if defined(USE_WIN32_LDAP)
00204   TCHAR *host = NULL;
00205   TCHAR *user = NULL;
00206   TCHAR *passwd = NULL;
00207 #else
00208   char *host = NULL;
00209   char *user = NULL;
00210   char *passwd = NULL;
00211 #endif
00212 
00213   *done = TRUE; /* unconditionally */
00214   infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
00215           LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
00216   infof(data, "LDAP local: %s\n", data->change.url);
00217 
00218 #ifdef HAVE_LDAP_URL_PARSE
00219   rc = ldap_url_parse(data->change.url, &ludp);
00220 #else
00221   rc = _ldap_url_parse(conn, &ludp);
00222 #endif
00223   if(rc != 0) {
00224     failf(data, "LDAP local: %s", ldap_err2string(rc));
00225     result = CURLE_LDAP_INVALID_URL;
00226     goto quit;
00227   }
00228 
00229   /* Get the URL scheme (either ldap or ldaps) */
00230   if(conn->given->flags & PROTOPT_SSL)
00231     ldap_ssl = 1;
00232   infof(data, "LDAP local: trying to establish %s connection\n",
00233           ldap_ssl ? "encrypted" : "cleartext");
00234 
00235 #if defined(USE_WIN32_LDAP)
00236   host = Curl_convert_UTF8_to_tchar(conn->host.name);
00237   if(!host) {
00238     result = CURLE_OUT_OF_MEMORY;
00239 
00240     goto quit;
00241   }
00242 
00243   if(conn->bits.user_passwd) {
00244     user = Curl_convert_UTF8_to_tchar(conn->user);
00245     passwd = Curl_convert_UTF8_to_tchar(conn->passwd);
00246     if(!user || !passwd) {
00247       result = CURLE_OUT_OF_MEMORY;
00248 
00249       goto quit;
00250     }
00251   }
00252 #else
00253   host = conn->host.name;
00254 
00255   if(conn->bits.user_passwd) {
00256     user = conn->user;
00257     passwd = conn->passwd;
00258   }
00259 #endif
00260 
00261 #ifdef LDAP_OPT_NETWORK_TIMEOUT
00262   ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
00263 #endif
00264   ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
00265 
00266   if(ldap_ssl) {
00267 #ifdef HAVE_LDAP_SSL
00268 #ifdef USE_WIN32_LDAP
00269     /* Win32 LDAP SDK doesn't support insecure mode without CA! */
00270     server = ldap_sslinit(host, (int)conn->port, 1);
00271     ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
00272 #else
00273     int ldap_option;
00274     char *ldap_ca = conn->ssl_config.CAfile;
00275 #if defined(CURL_HAS_NOVELL_LDAPSDK)
00276     rc = ldapssl_client_init(NULL, NULL);
00277     if(rc != LDAP_SUCCESS) {
00278       failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
00279       result = CURLE_SSL_CERTPROBLEM;
00280       goto quit;
00281     }
00282     if(conn->ssl_config.verifypeer) {
00283       /* Novell SDK supports DER or BASE64 files. */
00284       int cert_type = LDAPSSL_CERT_FILETYPE_B64;
00285       if((data->set.ssl.cert_type) &&
00286          (strcasecompare(data->set.ssl.cert_type, "DER")))
00287         cert_type = LDAPSSL_CERT_FILETYPE_DER;
00288       if(!ldap_ca) {
00289         failf(data, "LDAP local: ERROR %s CA cert not set!",
00290               (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
00291         result = CURLE_SSL_CERTPROBLEM;
00292         goto quit;
00293       }
00294       infof(data, "LDAP local: using %s CA cert '%s'\n",
00295               (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
00296               ldap_ca);
00297       rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
00298       if(rc != LDAP_SUCCESS) {
00299         failf(data, "LDAP local: ERROR setting %s CA cert: %s",
00300                 (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
00301                 ldap_err2string(rc));
00302         result = CURLE_SSL_CERTPROBLEM;
00303         goto quit;
00304       }
00305       ldap_option = LDAPSSL_VERIFY_SERVER;
00306     }
00307     else
00308       ldap_option = LDAPSSL_VERIFY_NONE;
00309     rc = ldapssl_set_verify_mode(ldap_option);
00310     if(rc != LDAP_SUCCESS) {
00311       failf(data, "LDAP local: ERROR setting cert verify mode: %s",
00312               ldap_err2string(rc));
00313       result = CURLE_SSL_CERTPROBLEM;
00314       goto quit;
00315     }
00316     server = ldapssl_init(host, (int)conn->port, 1);
00317     if(server == NULL) {
00318       failf(data, "LDAP local: Cannot connect to %s:%ld",
00319             conn->host.dispname, conn->port);
00320       result = CURLE_COULDNT_CONNECT;
00321       goto quit;
00322     }
00323 #elif defined(LDAP_OPT_X_TLS)
00324     if(conn->ssl_config.verifypeer) {
00325       /* OpenLDAP SDK supports BASE64 files. */
00326       if((data->set.ssl.cert_type) &&
00327          (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
00328         failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
00329         result = CURLE_SSL_CERTPROBLEM;
00330         goto quit;
00331       }
00332       if(!ldap_ca) {
00333         failf(data, "LDAP local: ERROR PEM CA cert not set!");
00334         result = CURLE_SSL_CERTPROBLEM;
00335         goto quit;
00336       }
00337       infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
00338       rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
00339       if(rc != LDAP_SUCCESS) {
00340         failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
00341                 ldap_err2string(rc));
00342         result = CURLE_SSL_CERTPROBLEM;
00343         goto quit;
00344       }
00345       ldap_option = LDAP_OPT_X_TLS_DEMAND;
00346     }
00347     else
00348       ldap_option = LDAP_OPT_X_TLS_NEVER;
00349 
00350     rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
00351     if(rc != LDAP_SUCCESS) {
00352       failf(data, "LDAP local: ERROR setting cert verify mode: %s",
00353               ldap_err2string(rc));
00354       result = CURLE_SSL_CERTPROBLEM;
00355       goto quit;
00356     }
00357     server = ldap_init(host, (int)conn->port);
00358     if(server == NULL) {
00359       failf(data, "LDAP local: Cannot connect to %s:%ld",
00360             conn->host.dispname, conn->port);
00361       result = CURLE_COULDNT_CONNECT;
00362       goto quit;
00363     }
00364     ldap_option = LDAP_OPT_X_TLS_HARD;
00365     rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
00366     if(rc != LDAP_SUCCESS) {
00367       failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
00368               ldap_err2string(rc));
00369       result = CURLE_SSL_CERTPROBLEM;
00370       goto quit;
00371     }
00372 /*
00373     rc = ldap_start_tls_s(server, NULL, NULL);
00374     if(rc != LDAP_SUCCESS) {
00375       failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
00376               ldap_err2string(rc));
00377       result = CURLE_SSL_CERTPROBLEM;
00378       goto quit;
00379     }
00380 */
00381 #else
00382     /* we should probably never come up to here since configure
00383        should check in first place if we can support LDAP SSL/TLS */
00384     failf(data, "LDAP local: SSL/TLS not supported with this version "
00385             "of the OpenLDAP toolkit\n");
00386     result = CURLE_SSL_CERTPROBLEM;
00387     goto quit;
00388 #endif
00389 #endif
00390 #endif /* CURL_LDAP_USE_SSL */
00391   }
00392   else {
00393     server = ldap_init(host, (int)conn->port);
00394     if(server == NULL) {
00395       failf(data, "LDAP local: Cannot connect to %s:%ld",
00396             conn->host.dispname, conn->port);
00397       result = CURLE_COULDNT_CONNECT;
00398       goto quit;
00399     }
00400   }
00401 #ifdef USE_WIN32_LDAP
00402   ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
00403 #endif
00404 
00405   rc = ldap_simple_bind_s(server, user, passwd);
00406   if(!ldap_ssl && rc != 0) {
00407     ldap_proto = LDAP_VERSION2;
00408     ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
00409     rc = ldap_simple_bind_s(server, user, passwd);
00410   }
00411   if(rc != 0) {
00412     failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc));
00413     result = CURLE_LDAP_CANNOT_BIND;
00414     goto quit;
00415   }
00416 
00417   rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
00418                      ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
00419 
00420   if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
00421     failf(data, "LDAP remote: %s", ldap_err2string(rc));
00422     result = CURLE_LDAP_SEARCH_FAILED;
00423     goto quit;
00424   }
00425 
00426   for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
00427       entryIterator;
00428       entryIterator = ldap_next_entry(server, entryIterator), num++) {
00429     BerElement *ber = NULL;
00430 #if defined(USE_WIN32_LDAP)
00431     TCHAR *attribute;
00432 #else
00433     char  *attribute;       
00434 #endif
00435     int i;
00436 
00437     /* Get the DN and write it to the client */
00438     {
00439       char *name;
00440       size_t name_len;
00441 #if defined(USE_WIN32_LDAP)
00442       TCHAR *dn = ldap_get_dn(server, entryIterator);
00443       name = Curl_convert_tchar_to_UTF8(dn);
00444       if(!name) {
00445         ldap_memfree(dn);
00446 
00447         result = CURLE_OUT_OF_MEMORY;
00448 
00449         goto quit;
00450       }
00451 #else
00452       char *dn = name = ldap_get_dn(server, entryIterator);
00453 #endif
00454       name_len = strlen(name);
00455 
00456       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
00457       if(result) {
00458 #if defined(USE_WIN32_LDAP)
00459         Curl_unicodefree(name);
00460 #endif
00461         ldap_memfree(dn);
00462 
00463         goto quit;
00464       }
00465 
00466       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
00467                                  name_len);
00468       if(result) {
00469 #if defined(USE_WIN32_LDAP)
00470         Curl_unicodefree(name);
00471 #endif
00472         ldap_memfree(dn);
00473 
00474         goto quit;
00475       }
00476 
00477       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
00478       if(result) {
00479 #if defined(USE_WIN32_LDAP)
00480         Curl_unicodefree(name);
00481 #endif
00482         ldap_memfree(dn);
00483 
00484         goto quit;
00485       }
00486 
00487       dlsize += name_len + 5;
00488 
00489 #if defined(USE_WIN32_LDAP)
00490       Curl_unicodefree(name);
00491 #endif
00492       ldap_memfree(dn);
00493     }
00494 
00495     /* Get the attributes and write them to the client */
00496     for(attribute = ldap_first_attribute(server, entryIterator, &ber);
00497         attribute;
00498         attribute = ldap_next_attribute(server, entryIterator, ber)) {
00499       BerValue **vals;
00500       size_t attr_len;
00501 #if defined(USE_WIN32_LDAP)
00502       char *attr = Curl_convert_tchar_to_UTF8(attribute);
00503       if(!attr) {
00504         if(ber)
00505           ber_free(ber, 0);
00506 
00507         result = CURLE_OUT_OF_MEMORY;
00508 
00509         goto quit;
00510     }
00511 #else
00512       char *attr = attribute;
00513 #endif
00514       attr_len = strlen(attr);
00515 
00516       vals = ldap_get_values_len(server, entryIterator, attribute);
00517       if(vals != NULL) {
00518         for(i = 0; (vals[i] != NULL); i++) {
00519           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
00520           if(result) {
00521             ldap_value_free_len(vals);
00522 #if defined(USE_WIN32_LDAP)
00523             Curl_unicodefree(attr);
00524 #endif
00525             ldap_memfree(attribute);
00526             if(ber)
00527               ber_free(ber, 0);
00528 
00529             goto quit;
00530           }
00531 
00532           result = Curl_client_write(conn, CLIENTWRITE_BODY,
00533                                      (char *) attr, attr_len);
00534           if(result) {
00535             ldap_value_free_len(vals);
00536 #if defined(USE_WIN32_LDAP)
00537             Curl_unicodefree(attr);
00538 #endif
00539             ldap_memfree(attribute);
00540             if(ber)
00541               ber_free(ber, 0);
00542 
00543             goto quit;
00544           }
00545 
00546           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
00547           if(result) {
00548             ldap_value_free_len(vals);
00549 #if defined(USE_WIN32_LDAP)
00550             Curl_unicodefree(attr);
00551 #endif
00552             ldap_memfree(attribute);
00553             if(ber)
00554               ber_free(ber, 0);
00555 
00556             goto quit;
00557           }
00558 
00559           dlsize += attr_len + 3;
00560 
00561           if((attr_len > 7) &&
00562              (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
00563             /* Binary attribute, encode to base64. */
00564             result = Curl_base64_encode(data,
00565                                         vals[i]->bv_val,
00566                                         vals[i]->bv_len,
00567                                         &val_b64,
00568                                         &val_b64_sz);
00569             if(result) {
00570               ldap_value_free_len(vals);
00571 #if defined(USE_WIN32_LDAP)
00572               Curl_unicodefree(attr);
00573 #endif
00574               ldap_memfree(attribute);
00575               if(ber)
00576                 ber_free(ber, 0);
00577 
00578               goto quit;
00579             }
00580 
00581             if(val_b64_sz > 0) {
00582               result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
00583                                          val_b64_sz);
00584               free(val_b64);
00585               if(result) {
00586                 ldap_value_free_len(vals);
00587 #if defined(USE_WIN32_LDAP)
00588                 Curl_unicodefree(attr);
00589 #endif
00590                 ldap_memfree(attribute);
00591                 if(ber)
00592                   ber_free(ber, 0);
00593 
00594                 goto quit;
00595               }
00596 
00597               dlsize += val_b64_sz;
00598             }
00599           }
00600           else {
00601             result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
00602                                        vals[i]->bv_len);
00603             if(result) {
00604               ldap_value_free_len(vals);
00605 #if defined(USE_WIN32_LDAP)
00606               Curl_unicodefree(attr);
00607 #endif
00608               ldap_memfree(attribute);
00609               if(ber)
00610                 ber_free(ber, 0);
00611 
00612               goto quit;
00613             }
00614 
00615             dlsize += vals[i]->bv_len;
00616           }
00617 
00618           result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
00619           if(result) {
00620             ldap_value_free_len(vals);
00621 #if defined(USE_WIN32_LDAP)
00622             Curl_unicodefree(attr);
00623 #endif
00624             ldap_memfree(attribute);
00625             if(ber)
00626               ber_free(ber, 0);
00627 
00628             goto quit;
00629           }
00630 
00631           dlsize++;
00632         }
00633 
00634         /* Free memory used to store values */
00635         ldap_value_free_len(vals);
00636       }
00637 
00638       /* Free the attribute as we are done with it */
00639 #if defined(USE_WIN32_LDAP)
00640       Curl_unicodefree(attr);
00641 #endif
00642       ldap_memfree(attribute);
00643 
00644       result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
00645       if(result)
00646         goto quit;
00647       dlsize++;
00648       Curl_pgrsSetDownloadCounter(data, dlsize);
00649     }
00650 
00651     if(ber)
00652        ber_free(ber, 0);
00653   }
00654 
00655 quit:
00656   if(ldapmsg) {
00657     ldap_msgfree(ldapmsg);
00658     LDAP_TRACE(("Received %d entries\n", num));
00659   }
00660   if(rc == LDAP_SIZELIMIT_EXCEEDED)
00661     infof(data, "There are more than %d entries\n", num);
00662   if(ludp)
00663     ldap_free_urldesc(ludp);
00664   if(server)
00665     ldap_unbind_s(server);
00666 #if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
00667   if(ldap_ssl)
00668     ldapssl_client_deinit();
00669 #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
00670 
00671 #if defined(USE_WIN32_LDAP)
00672   Curl_unicodefree(passwd);
00673   Curl_unicodefree(user);
00674   Curl_unicodefree(host);
00675 #endif
00676 
00677   /* no data to transfer */
00678   Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL);
00679   connclose(conn, "LDAP connection always disable re-use");
00680 
00681   return result;
00682 }
00683 
00684 #ifdef DEBUG_LDAP
00685 static void _ldap_trace(const char *fmt, ...)
00686 {
00687   static int do_trace = -1;
00688   va_list args;
00689 
00690   if(do_trace == -1) {
00691     const char *env = getenv("CURL_TRACE");
00692     do_trace = (env && strtol(env, NULL, 10) > 0);
00693   }
00694   if(!do_trace)
00695     return;
00696 
00697   va_start(args, fmt);
00698   vfprintf(stderr, fmt, args);
00699   va_end(args);
00700 }
00701 #endif
00702 
00703 #ifndef HAVE_LDAP_URL_PARSE
00704 
00705 /*
00706  * Return scope-value for a scope-string.
00707  */
00708 static int str2scope(const char *p)
00709 {
00710   if(strcasecompare(p, "one"))
00711     return LDAP_SCOPE_ONELEVEL;
00712   if(strcasecompare(p, "onetree"))
00713     return LDAP_SCOPE_ONELEVEL;
00714   if(strcasecompare(p, "base"))
00715     return LDAP_SCOPE_BASE;
00716   if(strcasecompare(p, "sub"))
00717     return LDAP_SCOPE_SUBTREE;
00718   if(strcasecompare(p, "subtree"))
00719     return LDAP_SCOPE_SUBTREE;
00720   return (-1);
00721 }
00722 
00723 /*
00724  * Split 'str' into strings separated by commas.
00725  * Note: out[] points into 'str'.
00726  */
00727 static bool split_str(char *str, char ***out, size_t *count)
00728 {
00729   char **res;
00730   char *lasts;
00731   char *s;
00732   size_t  i;
00733   size_t items = 1;
00734 
00735   s = strchr(str, ',');
00736   while(s) {
00737     items++;
00738     s = strchr(++s, ',');
00739   }
00740 
00741   res = calloc(items, sizeof(char *));
00742   if(!res)
00743     return FALSE;
00744 
00745   for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
00746       s = strtok_r(NULL, ",", &lasts), i++)
00747     res[i] = s;
00748 
00749   *out = res;
00750   *count = items;
00751 
00752   return TRUE;
00753 }
00754 
00755 /*
00756  * Break apart the pieces of an LDAP URL.
00757  * Syntax:
00758  *   ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
00759  *
00760  * <hostname> already known from 'conn->host.name'.
00761  * <port>     already known from 'conn->remote_port'.
00762  * extract the rest from 'conn->data->state.path+1'. All fields are optional.
00763  * e.g.
00764  *   ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
00765  * yields ludp->lud_dn = "".
00766  *
00767  * Defined in RFC4516 section 2.
00768  */
00769 static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
00770 {
00771   int rc = LDAP_SUCCESS;
00772   char *path;
00773   char *p;
00774   char *q;
00775   size_t i;
00776 
00777   if(!conn->data ||
00778      !conn->data->state.path ||
00779      conn->data->state.path[0] != '/' ||
00780      !checkprefix("LDAP", conn->data->change.url))
00781     return LDAP_INVALID_SYNTAX;
00782 
00783   ludp->lud_scope = LDAP_SCOPE_BASE;
00784   ludp->lud_port  = conn->remote_port;
00785   ludp->lud_host  = conn->host.name;
00786 
00787   /* Duplicate the path */
00788   p = path = strdup(conn->data->state.path + 1);
00789   if(!path)
00790     return LDAP_NO_MEMORY;
00791 
00792   /* Parse the DN (Distinguished Name) */
00793   q = strchr(p, '?');
00794   if(q)
00795     *q++ = '\0';
00796 
00797   if(*p) {
00798     char *dn = p;
00799     char *unescaped;
00800     CURLcode result;
00801 
00802     LDAP_TRACE(("DN '%s'\n", dn));
00803 
00804     /* Unescape the DN */
00805     result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE);
00806     if(result) {
00807       rc = LDAP_NO_MEMORY;
00808 
00809       goto quit;
00810     }
00811 
00812 #if defined(USE_WIN32_LDAP)
00813     /* Convert the unescaped string to a tchar */
00814     ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);
00815 
00816     /* Free the unescaped string as we are done with it */
00817     Curl_unicodefree(unescaped);
00818 
00819     if(!ludp->lud_dn) {
00820       rc = LDAP_NO_MEMORY;
00821 
00822       goto quit;
00823     }
00824 #else
00825     ludp->lud_dn = unescaped;
00826 #endif
00827   }
00828 
00829   p = q;
00830   if(!p)
00831     goto quit;
00832 
00833   /* Parse the attributes. skip "??" */
00834   q = strchr(p, '?');
00835   if(q)
00836     *q++ = '\0';
00837 
00838   if(*p) {
00839     char **attributes;
00840     size_t count = 0;
00841 
00842     /* Split the string into an array of attributes */
00843     if(!split_str(p, &attributes, &count)) {
00844       rc = LDAP_NO_MEMORY;
00845 
00846       goto quit;
00847     }
00848 
00849     /* Allocate our array (+1 for the NULL entry) */
00850 #if defined(USE_WIN32_LDAP)
00851     ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
00852 #else
00853     ludp->lud_attrs = calloc(count + 1, sizeof(char *));
00854 #endif
00855     if(!ludp->lud_attrs) {
00856       free(attributes);
00857 
00858       rc = LDAP_NO_MEMORY;
00859 
00860       goto quit;
00861     }
00862 
00863     for(i = 0; i < count; i++) {
00864       char *unescaped;
00865       CURLcode result;
00866 
00867       LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i]));
00868 
00869       /* Unescape the attribute */
00870       result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
00871                               FALSE);
00872       if(result) {
00873         free(attributes);
00874 
00875         rc = LDAP_NO_MEMORY;
00876 
00877         goto quit;
00878       }
00879 
00880 #if defined(USE_WIN32_LDAP)
00881       /* Convert the unescaped string to a tchar */
00882       ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);
00883 
00884       /* Free the unescaped string as we are done with it */
00885       Curl_unicodefree(unescaped);
00886 
00887       if(!ludp->lud_attrs[i]) {
00888         free(attributes);
00889 
00890         rc = LDAP_NO_MEMORY;
00891 
00892         goto quit;
00893       }
00894 #else
00895       ludp->lud_attrs[i] = unescaped;
00896 #endif
00897 
00898       ludp->lud_attrs_dups++;
00899     }
00900 
00901     free(attributes);
00902   }
00903 
00904   p = q;
00905   if(!p)
00906     goto quit;
00907 
00908   /* Parse the scope. skip "??" */
00909   q = strchr(p, '?');
00910   if(q)
00911     *q++ = '\0';
00912 
00913   if(*p) {
00914     ludp->lud_scope = str2scope(p);
00915     if(ludp->lud_scope == -1) {
00916       rc = LDAP_INVALID_SYNTAX;
00917 
00918       goto quit;
00919     }
00920     LDAP_TRACE(("scope %d\n", ludp->lud_scope));
00921   }
00922 
00923   p = q;
00924   if(!p)
00925     goto quit;
00926 
00927   /* Parse the filter */
00928   q = strchr(p, '?');
00929   if(q)
00930     *q++ = '\0';
00931 
00932   if(*p) {
00933     char *filter = p;
00934     char *unescaped;
00935     CURLcode result;
00936 
00937     LDAP_TRACE(("filter '%s'\n", filter));
00938 
00939     /* Unescape the filter */
00940     result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE);
00941     if(result) {
00942       rc = LDAP_NO_MEMORY;
00943 
00944       goto quit;
00945     }
00946 
00947 #if defined(USE_WIN32_LDAP)
00948     /* Convert the unescaped string to a tchar */
00949     ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);
00950 
00951     /* Free the unescaped string as we are done with it */
00952     Curl_unicodefree(unescaped);
00953 
00954     if(!ludp->lud_filter) {
00955       rc = LDAP_NO_MEMORY;
00956 
00957       goto quit;
00958     }
00959 #else
00960     ludp->lud_filter = unescaped;
00961 #endif
00962   }
00963 
00964   p = q;
00965   if(p && !*p) {
00966     rc = LDAP_INVALID_SYNTAX;
00967 
00968     goto quit;
00969   }
00970 
00971 quit:
00972   free(path);
00973 
00974   return rc;
00975 }
00976 
00977 static int _ldap_url_parse(const struct connectdata *conn,
00978                            LDAPURLDesc **ludpp)
00979 {
00980   LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
00981   int rc;
00982 
00983   *ludpp = NULL;
00984   if(!ludp)
00985      return LDAP_NO_MEMORY;
00986 
00987   rc = _ldap_url_parse2(conn, ludp);
00988   if(rc != LDAP_SUCCESS) {
00989     _ldap_free_urldesc(ludp);
00990     ludp = NULL;
00991   }
00992   *ludpp = ludp;
00993   return (rc);
00994 }
00995 
00996 static void _ldap_free_urldesc(LDAPURLDesc *ludp)
00997 {
00998   size_t i;
00999 
01000   if(!ludp)
01001     return;
01002 
01003   free(ludp->lud_dn);
01004   free(ludp->lud_filter);
01005 
01006   if(ludp->lud_attrs) {
01007     for(i = 0; i < ludp->lud_attrs_dups; i++)
01008       free(ludp->lud_attrs[i]);
01009     free(ludp->lud_attrs);
01010   }
01011 
01012   free(ludp);
01013 }
01014 #endif  /* !HAVE_LDAP_URL_PARSE */
01015 #endif  /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:05