Annotation of embedaddon/curl/lib/ldap.c, revision 1.1
1.1 ! misho 1: /***************************************************************************
! 2: * _ _ ____ _
! 3: * Project ___| | | | _ \| |
! 4: * / __| | | | |_) | |
! 5: * | (__| |_| | _ <| |___
! 6: * \___|\___/|_| \_\_____|
! 7: *
! 8: * Copyright (C) 1998 - 2019, Daniel Stenberg, <daniel@haxx.se>, et al.
! 9: *
! 10: * This software is licensed as described in the file COPYING, which
! 11: * you should have received as part of this distribution. The terms
! 12: * are also available at https://curl.haxx.se/docs/copyright.html.
! 13: *
! 14: * You may opt to use, copy, modify, merge, publish, distribute and/or sell
! 15: * copies of the Software, and permit persons to whom the Software is
! 16: * furnished to do so, under the terms of the COPYING file.
! 17: *
! 18: * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
! 19: * KIND, either express or implied.
! 20: *
! 21: ***************************************************************************/
! 22:
! 23: #include "curl_setup.h"
! 24:
! 25: #if !defined(CURL_DISABLE_LDAP) && !defined(USE_OPENLDAP)
! 26:
! 27: /*
! 28: * Notice that USE_OPENLDAP is only a source code selection switch. When
! 29: * libcurl is built with USE_OPENLDAP defined the libcurl source code that
! 30: * gets compiled is the code from openldap.c, otherwise the code that gets
! 31: * compiled is the code from ldap.c.
! 32: *
! 33: * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
! 34: * might be required for compilation and runtime. In order to use ancient
! 35: * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
! 36: */
! 37:
! 38: #ifdef USE_WIN32_LDAP /* Use Windows LDAP implementation. */
! 39: # include <winldap.h>
! 40: # ifndef LDAP_VENDOR_NAME
! 41: # error Your Platform SDK is NOT sufficient for LDAP support! \
! 42: Update your Platform SDK, or disable LDAP support!
! 43: # else
! 44: # include <winber.h>
! 45: # endif
! 46: #else
! 47: # define LDAP_DEPRECATED 1 /* Be sure ldap_init() is defined. */
! 48: # ifdef HAVE_LBER_H
! 49: # include <lber.h>
! 50: # endif
! 51: # include <ldap.h>
! 52: # if (defined(HAVE_LDAP_SSL) && defined(HAVE_LDAP_SSL_H))
! 53: # include <ldap_ssl.h>
! 54: # endif /* HAVE_LDAP_SSL && HAVE_LDAP_SSL_H */
! 55: #endif
! 56:
! 57: #include "urldata.h"
! 58: #include <curl/curl.h>
! 59: #include "sendf.h"
! 60: #include "escape.h"
! 61: #include "progress.h"
! 62: #include "transfer.h"
! 63: #include "strcase.h"
! 64: #include "strtok.h"
! 65: #include "curl_ldap.h"
! 66: #include "curl_multibyte.h"
! 67: #include "curl_base64.h"
! 68: #include "connect.h"
! 69: /* The last 3 #include files should be in this order */
! 70: #include "curl_printf.h"
! 71: #include "curl_memory.h"
! 72: #include "memdebug.h"
! 73:
! 74: #ifndef HAVE_LDAP_URL_PARSE
! 75:
! 76: /* Use our own implementation. */
! 77:
! 78: typedef struct {
! 79: char *lud_host;
! 80: int lud_port;
! 81: #if defined(USE_WIN32_LDAP)
! 82: TCHAR *lud_dn;
! 83: TCHAR **lud_attrs;
! 84: #else
! 85: char *lud_dn;
! 86: char **lud_attrs;
! 87: #endif
! 88: int lud_scope;
! 89: #if defined(USE_WIN32_LDAP)
! 90: TCHAR *lud_filter;
! 91: #else
! 92: char *lud_filter;
! 93: #endif
! 94: char **lud_exts;
! 95: size_t lud_attrs_dups; /* how many were dup'ed, this field is not in the
! 96: "real" struct so can only be used in code
! 97: without HAVE_LDAP_URL_PARSE defined */
! 98: } CURL_LDAPURLDesc;
! 99:
! 100: #undef LDAPURLDesc
! 101: #define LDAPURLDesc CURL_LDAPURLDesc
! 102:
! 103: static int _ldap_url_parse(const struct connectdata *conn,
! 104: LDAPURLDesc **ludp);
! 105: static void _ldap_free_urldesc(LDAPURLDesc *ludp);
! 106:
! 107: #undef ldap_free_urldesc
! 108: #define ldap_free_urldesc _ldap_free_urldesc
! 109: #endif
! 110:
! 111: #ifdef DEBUG_LDAP
! 112: #define LDAP_TRACE(x) do { \
! 113: _ldap_trace("%u: ", __LINE__); \
! 114: _ldap_trace x; \
! 115: } while(0)
! 116:
! 117: static void _ldap_trace(const char *fmt, ...);
! 118: #else
! 119: #define LDAP_TRACE(x) Curl_nop_stmt
! 120: #endif
! 121:
! 122: #if defined(USE_WIN32_LDAP) && defined(ldap_err2string)
! 123: /* Use ansi error strings in UNICODE builds */
! 124: #undef ldap_err2string
! 125: #define ldap_err2string ldap_err2stringA
! 126: #endif
! 127:
! 128:
! 129: static CURLcode Curl_ldap(struct connectdata *conn, bool *done);
! 130:
! 131: /*
! 132: * LDAP protocol handler.
! 133: */
! 134:
! 135: const struct Curl_handler Curl_handler_ldap = {
! 136: "LDAP", /* scheme */
! 137: ZERO_NULL, /* setup_connection */
! 138: Curl_ldap, /* do_it */
! 139: ZERO_NULL, /* done */
! 140: ZERO_NULL, /* do_more */
! 141: ZERO_NULL, /* connect_it */
! 142: ZERO_NULL, /* connecting */
! 143: ZERO_NULL, /* doing */
! 144: ZERO_NULL, /* proto_getsock */
! 145: ZERO_NULL, /* doing_getsock */
! 146: ZERO_NULL, /* domore_getsock */
! 147: ZERO_NULL, /* perform_getsock */
! 148: ZERO_NULL, /* disconnect */
! 149: ZERO_NULL, /* readwrite */
! 150: ZERO_NULL, /* connection_check */
! 151: PORT_LDAP, /* defport */
! 152: CURLPROTO_LDAP, /* protocol */
! 153: PROTOPT_NONE /* flags */
! 154: };
! 155:
! 156: #ifdef HAVE_LDAP_SSL
! 157: /*
! 158: * LDAPS protocol handler.
! 159: */
! 160:
! 161: const struct Curl_handler Curl_handler_ldaps = {
! 162: "LDAPS", /* scheme */
! 163: ZERO_NULL, /* setup_connection */
! 164: Curl_ldap, /* do_it */
! 165: ZERO_NULL, /* done */
! 166: ZERO_NULL, /* do_more */
! 167: ZERO_NULL, /* connect_it */
! 168: ZERO_NULL, /* connecting */
! 169: ZERO_NULL, /* doing */
! 170: ZERO_NULL, /* proto_getsock */
! 171: ZERO_NULL, /* doing_getsock */
! 172: ZERO_NULL, /* domore_getsock */
! 173: ZERO_NULL, /* perform_getsock */
! 174: ZERO_NULL, /* disconnect */
! 175: ZERO_NULL, /* readwrite */
! 176: ZERO_NULL, /* connection_check */
! 177: PORT_LDAPS, /* defport */
! 178: CURLPROTO_LDAPS, /* protocol */
! 179: PROTOPT_SSL /* flags */
! 180: };
! 181: #endif
! 182:
! 183: #if defined(USE_WIN32_LDAP)
! 184:
! 185: #if defined(USE_WINDOWS_SSPI)
! 186: static int ldap_win_bind_auth(LDAP *server, const char *user,
! 187: const char *passwd, unsigned long authflags)
! 188: {
! 189: ULONG method = 0;
! 190: SEC_WINNT_AUTH_IDENTITY cred;
! 191: int rc = LDAP_AUTH_METHOD_NOT_SUPPORTED;
! 192:
! 193: memset(&cred, 0, sizeof(cred));
! 194:
! 195: #if defined(USE_SPNEGO)
! 196: if(authflags & CURLAUTH_NEGOTIATE) {
! 197: method = LDAP_AUTH_NEGOTIATE;
! 198: }
! 199: else
! 200: #endif
! 201: #if defined(USE_NTLM)
! 202: if(authflags & CURLAUTH_NTLM) {
! 203: method = LDAP_AUTH_NTLM;
! 204: }
! 205: else
! 206: #endif
! 207: #if !defined(CURL_DISABLE_CRYPTO_AUTH)
! 208: if(authflags & CURLAUTH_DIGEST) {
! 209: method = LDAP_AUTH_DIGEST;
! 210: }
! 211: else
! 212: #endif
! 213: {
! 214: /* required anyway if one of upper preprocessor definitions enabled */
! 215: }
! 216:
! 217: if(method && user && passwd) {
! 218: rc = Curl_create_sspi_identity(user, passwd, &cred);
! 219: if(!rc) {
! 220: rc = ldap_bind_s(server, NULL, (TCHAR *)&cred, method);
! 221: Curl_sspi_free_identity(&cred);
! 222: }
! 223: }
! 224: else {
! 225: /* proceed with current user credentials */
! 226: method = LDAP_AUTH_NEGOTIATE;
! 227: rc = ldap_bind_s(server, NULL, NULL, method);
! 228: }
! 229: return rc;
! 230: }
! 231: #endif /* #if defined(USE_WINDOWS_SSPI) */
! 232:
! 233: static int ldap_win_bind(struct connectdata *conn, LDAP *server,
! 234: const char *user, const char *passwd)
! 235: {
! 236: int rc = LDAP_INVALID_CREDENTIALS;
! 237:
! 238: PTCHAR inuser = NULL;
! 239: PTCHAR inpass = NULL;
! 240:
! 241: if(user && passwd && (conn->data->set.httpauth & CURLAUTH_BASIC)) {
! 242: inuser = Curl_convert_UTF8_to_tchar((char *) user);
! 243: inpass = Curl_convert_UTF8_to_tchar((char *) passwd);
! 244:
! 245: rc = ldap_simple_bind_s(server, inuser, inpass);
! 246:
! 247: Curl_unicodefree(inuser);
! 248: Curl_unicodefree(inpass);
! 249: }
! 250: #if defined(USE_WINDOWS_SSPI)
! 251: else {
! 252: rc = ldap_win_bind_auth(server, user, passwd, conn->data->set.httpauth);
! 253: }
! 254: #endif
! 255:
! 256: return rc;
! 257: }
! 258: #endif /* #if defined(USE_WIN32_LDAP) */
! 259:
! 260: static CURLcode Curl_ldap(struct connectdata *conn, bool *done)
! 261: {
! 262: CURLcode result = CURLE_OK;
! 263: int rc = 0;
! 264: LDAP *server = NULL;
! 265: LDAPURLDesc *ludp = NULL;
! 266: LDAPMessage *ldapmsg = NULL;
! 267: LDAPMessage *entryIterator;
! 268: int num = 0;
! 269: struct Curl_easy *data = conn->data;
! 270: int ldap_proto = LDAP_VERSION3;
! 271: int ldap_ssl = 0;
! 272: char *val_b64 = NULL;
! 273: size_t val_b64_sz = 0;
! 274: curl_off_t dlsize = 0;
! 275: #ifdef LDAP_OPT_NETWORK_TIMEOUT
! 276: struct timeval ldap_timeout = {10, 0}; /* 10 sec connection/search timeout */
! 277: #endif
! 278: #if defined(USE_WIN32_LDAP)
! 279: TCHAR *host = NULL;
! 280: #else
! 281: char *host = NULL;
! 282: #endif
! 283: char *user = NULL;
! 284: char *passwd = NULL;
! 285:
! 286: *done = TRUE; /* unconditionally */
! 287: infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n",
! 288: LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION);
! 289: infof(data, "LDAP local: %s\n", data->change.url);
! 290:
! 291: #ifdef HAVE_LDAP_URL_PARSE
! 292: rc = ldap_url_parse(data->change.url, &ludp);
! 293: #else
! 294: rc = _ldap_url_parse(conn, &ludp);
! 295: #endif
! 296: if(rc != 0) {
! 297: failf(data, "LDAP local: %s", ldap_err2string(rc));
! 298: result = CURLE_LDAP_INVALID_URL;
! 299: goto quit;
! 300: }
! 301:
! 302: /* Get the URL scheme (either ldap or ldaps) */
! 303: if(conn->given->flags & PROTOPT_SSL)
! 304: ldap_ssl = 1;
! 305: infof(data, "LDAP local: trying to establish %s connection\n",
! 306: ldap_ssl ? "encrypted" : "cleartext");
! 307:
! 308: #if defined(USE_WIN32_LDAP)
! 309: host = Curl_convert_UTF8_to_tchar(conn->host.name);
! 310: if(!host) {
! 311: result = CURLE_OUT_OF_MEMORY;
! 312:
! 313: goto quit;
! 314: }
! 315: #else
! 316: host = conn->host.name;
! 317: #endif
! 318:
! 319: if(conn->bits.user_passwd) {
! 320: user = conn->user;
! 321: passwd = conn->passwd;
! 322: }
! 323:
! 324: #ifdef LDAP_OPT_NETWORK_TIMEOUT
! 325: ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout);
! 326: #endif
! 327: ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
! 328:
! 329: if(ldap_ssl) {
! 330: #ifdef HAVE_LDAP_SSL
! 331: #ifdef USE_WIN32_LDAP
! 332: /* Win32 LDAP SDK doesn't support insecure mode without CA! */
! 333: server = ldap_sslinit(host, (int)conn->port, 1);
! 334: ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON);
! 335: #else
! 336: int ldap_option;
! 337: char *ldap_ca = conn->ssl_config.CAfile;
! 338: #if defined(CURL_HAS_NOVELL_LDAPSDK)
! 339: rc = ldapssl_client_init(NULL, NULL);
! 340: if(rc != LDAP_SUCCESS) {
! 341: failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc));
! 342: result = CURLE_SSL_CERTPROBLEM;
! 343: goto quit;
! 344: }
! 345: if(conn->ssl_config.verifypeer) {
! 346: /* Novell SDK supports DER or BASE64 files. */
! 347: int cert_type = LDAPSSL_CERT_FILETYPE_B64;
! 348: if((data->set.ssl.cert_type) &&
! 349: (strcasecompare(data->set.ssl.cert_type, "DER")))
! 350: cert_type = LDAPSSL_CERT_FILETYPE_DER;
! 351: if(!ldap_ca) {
! 352: failf(data, "LDAP local: ERROR %s CA cert not set!",
! 353: (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"));
! 354: result = CURLE_SSL_CERTPROBLEM;
! 355: goto quit;
! 356: }
! 357: infof(data, "LDAP local: using %s CA cert '%s'\n",
! 358: (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
! 359: ldap_ca);
! 360: rc = ldapssl_add_trusted_cert(ldap_ca, cert_type);
! 361: if(rc != LDAP_SUCCESS) {
! 362: failf(data, "LDAP local: ERROR setting %s CA cert: %s",
! 363: (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"),
! 364: ldap_err2string(rc));
! 365: result = CURLE_SSL_CERTPROBLEM;
! 366: goto quit;
! 367: }
! 368: ldap_option = LDAPSSL_VERIFY_SERVER;
! 369: }
! 370: else
! 371: ldap_option = LDAPSSL_VERIFY_NONE;
! 372: rc = ldapssl_set_verify_mode(ldap_option);
! 373: if(rc != LDAP_SUCCESS) {
! 374: failf(data, "LDAP local: ERROR setting cert verify mode: %s",
! 375: ldap_err2string(rc));
! 376: result = CURLE_SSL_CERTPROBLEM;
! 377: goto quit;
! 378: }
! 379: server = ldapssl_init(host, (int)conn->port, 1);
! 380: if(server == NULL) {
! 381: failf(data, "LDAP local: Cannot connect to %s:%ld",
! 382: conn->host.dispname, conn->port);
! 383: result = CURLE_COULDNT_CONNECT;
! 384: goto quit;
! 385: }
! 386: #elif defined(LDAP_OPT_X_TLS)
! 387: if(conn->ssl_config.verifypeer) {
! 388: /* OpenLDAP SDK supports BASE64 files. */
! 389: if((data->set.ssl.cert_type) &&
! 390: (!strcasecompare(data->set.ssl.cert_type, "PEM"))) {
! 391: failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!");
! 392: result = CURLE_SSL_CERTPROBLEM;
! 393: goto quit;
! 394: }
! 395: if(!ldap_ca) {
! 396: failf(data, "LDAP local: ERROR PEM CA cert not set!");
! 397: result = CURLE_SSL_CERTPROBLEM;
! 398: goto quit;
! 399: }
! 400: infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca);
! 401: rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca);
! 402: if(rc != LDAP_SUCCESS) {
! 403: failf(data, "LDAP local: ERROR setting PEM CA cert: %s",
! 404: ldap_err2string(rc));
! 405: result = CURLE_SSL_CERTPROBLEM;
! 406: goto quit;
! 407: }
! 408: ldap_option = LDAP_OPT_X_TLS_DEMAND;
! 409: }
! 410: else
! 411: ldap_option = LDAP_OPT_X_TLS_NEVER;
! 412:
! 413: rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option);
! 414: if(rc != LDAP_SUCCESS) {
! 415: failf(data, "LDAP local: ERROR setting cert verify mode: %s",
! 416: ldap_err2string(rc));
! 417: result = CURLE_SSL_CERTPROBLEM;
! 418: goto quit;
! 419: }
! 420: server = ldap_init(host, (int)conn->port);
! 421: if(server == NULL) {
! 422: failf(data, "LDAP local: Cannot connect to %s:%ld",
! 423: conn->host.dispname, conn->port);
! 424: result = CURLE_COULDNT_CONNECT;
! 425: goto quit;
! 426: }
! 427: ldap_option = LDAP_OPT_X_TLS_HARD;
! 428: rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option);
! 429: if(rc != LDAP_SUCCESS) {
! 430: failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s",
! 431: ldap_err2string(rc));
! 432: result = CURLE_SSL_CERTPROBLEM;
! 433: goto quit;
! 434: }
! 435: /*
! 436: rc = ldap_start_tls_s(server, NULL, NULL);
! 437: if(rc != LDAP_SUCCESS) {
! 438: failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s",
! 439: ldap_err2string(rc));
! 440: result = CURLE_SSL_CERTPROBLEM;
! 441: goto quit;
! 442: }
! 443: */
! 444: #else
! 445: /* we should probably never come up to here since configure
! 446: should check in first place if we can support LDAP SSL/TLS */
! 447: failf(data, "LDAP local: SSL/TLS not supported with this version "
! 448: "of the OpenLDAP toolkit\n");
! 449: result = CURLE_SSL_CERTPROBLEM;
! 450: goto quit;
! 451: #endif
! 452: #endif
! 453: #endif /* CURL_LDAP_USE_SSL */
! 454: }
! 455: else {
! 456: server = ldap_init(host, (int)conn->port);
! 457: if(server == NULL) {
! 458: failf(data, "LDAP local: Cannot connect to %s:%ld",
! 459: conn->host.dispname, conn->port);
! 460: result = CURLE_COULDNT_CONNECT;
! 461: goto quit;
! 462: }
! 463: }
! 464: #ifdef USE_WIN32_LDAP
! 465: ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
! 466: #endif
! 467:
! 468: #ifdef USE_WIN32_LDAP
! 469: rc = ldap_win_bind(conn, server, user, passwd);
! 470: #else
! 471: rc = ldap_simple_bind_s(server, user, passwd);
! 472: #endif
! 473: if(!ldap_ssl && rc != 0) {
! 474: ldap_proto = LDAP_VERSION2;
! 475: ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto);
! 476: #ifdef USE_WIN32_LDAP
! 477: rc = ldap_win_bind(conn, server, user, passwd);
! 478: #else
! 479: rc = ldap_simple_bind_s(server, user, passwd);
! 480: #endif
! 481: }
! 482: if(rc != 0) {
! 483: #ifdef USE_WIN32_LDAP
! 484: failf(data, "LDAP local: bind via ldap_win_bind %s",
! 485: ldap_err2string(rc));
! 486: #else
! 487: failf(data, "LDAP local: bind via ldap_simple_bind_s %s",
! 488: ldap_err2string(rc));
! 489: #endif
! 490: result = CURLE_LDAP_CANNOT_BIND;
! 491: goto quit;
! 492: }
! 493:
! 494: rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope,
! 495: ludp->lud_filter, ludp->lud_attrs, 0, &ldapmsg);
! 496:
! 497: if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) {
! 498: failf(data, "LDAP remote: %s", ldap_err2string(rc));
! 499: result = CURLE_LDAP_SEARCH_FAILED;
! 500: goto quit;
! 501: }
! 502:
! 503: for(num = 0, entryIterator = ldap_first_entry(server, ldapmsg);
! 504: entryIterator;
! 505: entryIterator = ldap_next_entry(server, entryIterator), num++) {
! 506: BerElement *ber = NULL;
! 507: #if defined(USE_WIN32_LDAP)
! 508: TCHAR *attribute;
! 509: #else
! 510: char *attribute; /*! suspicious that this isn't 'const' */
! 511: #endif
! 512: int i;
! 513:
! 514: /* Get the DN and write it to the client */
! 515: {
! 516: char *name;
! 517: size_t name_len;
! 518: #if defined(USE_WIN32_LDAP)
! 519: TCHAR *dn = ldap_get_dn(server, entryIterator);
! 520: name = Curl_convert_tchar_to_UTF8(dn);
! 521: if(!name) {
! 522: ldap_memfree(dn);
! 523:
! 524: result = CURLE_OUT_OF_MEMORY;
! 525:
! 526: goto quit;
! 527: }
! 528: #else
! 529: char *dn = name = ldap_get_dn(server, entryIterator);
! 530: #endif
! 531: name_len = strlen(name);
! 532:
! 533: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
! 534: if(result) {
! 535: #if defined(USE_WIN32_LDAP)
! 536: Curl_unicodefree(name);
! 537: #endif
! 538: ldap_memfree(dn);
! 539:
! 540: goto quit;
! 541: }
! 542:
! 543: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *) name,
! 544: name_len);
! 545: if(result) {
! 546: #if defined(USE_WIN32_LDAP)
! 547: Curl_unicodefree(name);
! 548: #endif
! 549: ldap_memfree(dn);
! 550:
! 551: goto quit;
! 552: }
! 553:
! 554: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
! 555: if(result) {
! 556: #if defined(USE_WIN32_LDAP)
! 557: Curl_unicodefree(name);
! 558: #endif
! 559: ldap_memfree(dn);
! 560:
! 561: goto quit;
! 562: }
! 563:
! 564: dlsize += name_len + 5;
! 565:
! 566: #if defined(USE_WIN32_LDAP)
! 567: Curl_unicodefree(name);
! 568: #endif
! 569: ldap_memfree(dn);
! 570: }
! 571:
! 572: /* Get the attributes and write them to the client */
! 573: for(attribute = ldap_first_attribute(server, entryIterator, &ber);
! 574: attribute;
! 575: attribute = ldap_next_attribute(server, entryIterator, ber)) {
! 576: BerValue **vals;
! 577: size_t attr_len;
! 578: #if defined(USE_WIN32_LDAP)
! 579: char *attr = Curl_convert_tchar_to_UTF8(attribute);
! 580: if(!attr) {
! 581: if(ber)
! 582: ber_free(ber, 0);
! 583:
! 584: result = CURLE_OUT_OF_MEMORY;
! 585:
! 586: goto quit;
! 587: }
! 588: #else
! 589: char *attr = attribute;
! 590: #endif
! 591: attr_len = strlen(attr);
! 592:
! 593: vals = ldap_get_values_len(server, entryIterator, attribute);
! 594: if(vals != NULL) {
! 595: for(i = 0; (vals[i] != NULL); i++) {
! 596: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
! 597: if(result) {
! 598: ldap_value_free_len(vals);
! 599: #if defined(USE_WIN32_LDAP)
! 600: Curl_unicodefree(attr);
! 601: #endif
! 602: ldap_memfree(attribute);
! 603: if(ber)
! 604: ber_free(ber, 0);
! 605:
! 606: goto quit;
! 607: }
! 608:
! 609: result = Curl_client_write(conn, CLIENTWRITE_BODY,
! 610: (char *) attr, attr_len);
! 611: if(result) {
! 612: ldap_value_free_len(vals);
! 613: #if defined(USE_WIN32_LDAP)
! 614: Curl_unicodefree(attr);
! 615: #endif
! 616: ldap_memfree(attribute);
! 617: if(ber)
! 618: ber_free(ber, 0);
! 619:
! 620: goto quit;
! 621: }
! 622:
! 623: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2);
! 624: if(result) {
! 625: ldap_value_free_len(vals);
! 626: #if defined(USE_WIN32_LDAP)
! 627: Curl_unicodefree(attr);
! 628: #endif
! 629: ldap_memfree(attribute);
! 630: if(ber)
! 631: ber_free(ber, 0);
! 632:
! 633: goto quit;
! 634: }
! 635:
! 636: dlsize += attr_len + 3;
! 637:
! 638: if((attr_len > 7) &&
! 639: (strcmp(";binary", (char *) attr + (attr_len - 7)) == 0)) {
! 640: /* Binary attribute, encode to base64. */
! 641: result = Curl_base64_encode(data,
! 642: vals[i]->bv_val,
! 643: vals[i]->bv_len,
! 644: &val_b64,
! 645: &val_b64_sz);
! 646: if(result) {
! 647: ldap_value_free_len(vals);
! 648: #if defined(USE_WIN32_LDAP)
! 649: Curl_unicodefree(attr);
! 650: #endif
! 651: ldap_memfree(attribute);
! 652: if(ber)
! 653: ber_free(ber, 0);
! 654:
! 655: goto quit;
! 656: }
! 657:
! 658: if(val_b64_sz > 0) {
! 659: result = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
! 660: val_b64_sz);
! 661: free(val_b64);
! 662: if(result) {
! 663: ldap_value_free_len(vals);
! 664: #if defined(USE_WIN32_LDAP)
! 665: Curl_unicodefree(attr);
! 666: #endif
! 667: ldap_memfree(attribute);
! 668: if(ber)
! 669: ber_free(ber, 0);
! 670:
! 671: goto quit;
! 672: }
! 673:
! 674: dlsize += val_b64_sz;
! 675: }
! 676: }
! 677: else {
! 678: result = Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val,
! 679: vals[i]->bv_len);
! 680: if(result) {
! 681: ldap_value_free_len(vals);
! 682: #if defined(USE_WIN32_LDAP)
! 683: Curl_unicodefree(attr);
! 684: #endif
! 685: ldap_memfree(attribute);
! 686: if(ber)
! 687: ber_free(ber, 0);
! 688:
! 689: goto quit;
! 690: }
! 691:
! 692: dlsize += vals[i]->bv_len;
! 693: }
! 694:
! 695: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
! 696: if(result) {
! 697: ldap_value_free_len(vals);
! 698: #if defined(USE_WIN32_LDAP)
! 699: Curl_unicodefree(attr);
! 700: #endif
! 701: ldap_memfree(attribute);
! 702: if(ber)
! 703: ber_free(ber, 0);
! 704:
! 705: goto quit;
! 706: }
! 707:
! 708: dlsize++;
! 709: }
! 710:
! 711: /* Free memory used to store values */
! 712: ldap_value_free_len(vals);
! 713: }
! 714:
! 715: /* Free the attribute as we are done with it */
! 716: #if defined(USE_WIN32_LDAP)
! 717: Curl_unicodefree(attr);
! 718: #endif
! 719: ldap_memfree(attribute);
! 720:
! 721: result = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
! 722: if(result)
! 723: goto quit;
! 724: dlsize++;
! 725: Curl_pgrsSetDownloadCounter(data, dlsize);
! 726: }
! 727:
! 728: if(ber)
! 729: ber_free(ber, 0);
! 730: }
! 731:
! 732: quit:
! 733: if(ldapmsg) {
! 734: ldap_msgfree(ldapmsg);
! 735: LDAP_TRACE(("Received %d entries\n", num));
! 736: }
! 737: if(rc == LDAP_SIZELIMIT_EXCEEDED)
! 738: infof(data, "There are more than %d entries\n", num);
! 739: if(ludp)
! 740: ldap_free_urldesc(ludp);
! 741: if(server)
! 742: ldap_unbind_s(server);
! 743: #if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK)
! 744: if(ldap_ssl)
! 745: ldapssl_client_deinit();
! 746: #endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */
! 747:
! 748: #if defined(USE_WIN32_LDAP)
! 749: Curl_unicodefree(host);
! 750: #endif
! 751:
! 752: /* no data to transfer */
! 753: Curl_setup_transfer(data, -1, -1, FALSE, -1);
! 754: connclose(conn, "LDAP connection always disable re-use");
! 755:
! 756: return result;
! 757: }
! 758:
! 759: #ifdef DEBUG_LDAP
! 760: static void _ldap_trace(const char *fmt, ...)
! 761: {
! 762: static int do_trace = -1;
! 763: va_list args;
! 764:
! 765: if(do_trace == -1) {
! 766: const char *env = getenv("CURL_TRACE");
! 767: do_trace = (env && strtol(env, NULL, 10) > 0);
! 768: }
! 769: if(!do_trace)
! 770: return;
! 771:
! 772: va_start(args, fmt);
! 773: vfprintf(stderr, fmt, args);
! 774: va_end(args);
! 775: }
! 776: #endif
! 777:
! 778: #ifndef HAVE_LDAP_URL_PARSE
! 779:
! 780: /*
! 781: * Return scope-value for a scope-string.
! 782: */
! 783: static int str2scope(const char *p)
! 784: {
! 785: if(strcasecompare(p, "one"))
! 786: return LDAP_SCOPE_ONELEVEL;
! 787: if(strcasecompare(p, "onetree"))
! 788: return LDAP_SCOPE_ONELEVEL;
! 789: if(strcasecompare(p, "base"))
! 790: return LDAP_SCOPE_BASE;
! 791: if(strcasecompare(p, "sub"))
! 792: return LDAP_SCOPE_SUBTREE;
! 793: if(strcasecompare(p, "subtree"))
! 794: return LDAP_SCOPE_SUBTREE;
! 795: return (-1);
! 796: }
! 797:
! 798: /*
! 799: * Split 'str' into strings separated by commas.
! 800: * Note: out[] points into 'str'.
! 801: */
! 802: static bool split_str(char *str, char ***out, size_t *count)
! 803: {
! 804: char **res;
! 805: char *lasts;
! 806: char *s;
! 807: size_t i;
! 808: size_t items = 1;
! 809:
! 810: s = strchr(str, ',');
! 811: while(s) {
! 812: items++;
! 813: s = strchr(++s, ',');
! 814: }
! 815:
! 816: res = calloc(items, sizeof(char *));
! 817: if(!res)
! 818: return FALSE;
! 819:
! 820: for(i = 0, s = strtok_r(str, ",", &lasts); s && i < items;
! 821: s = strtok_r(NULL, ",", &lasts), i++)
! 822: res[i] = s;
! 823:
! 824: *out = res;
! 825: *count = items;
! 826:
! 827: return TRUE;
! 828: }
! 829:
! 830: /*
! 831: * Break apart the pieces of an LDAP URL.
! 832: * Syntax:
! 833: * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext>
! 834: *
! 835: * <hostname> already known from 'conn->host.name'.
! 836: * <port> already known from 'conn->remote_port'.
! 837: * extract the rest from 'conn->data->state.path+1'. All fields are optional.
! 838: * e.g.
! 839: * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter>
! 840: * yields ludp->lud_dn = "".
! 841: *
! 842: * Defined in RFC4516 section 2.
! 843: */
! 844: static int _ldap_url_parse2(const struct connectdata *conn, LDAPURLDesc *ludp)
! 845: {
! 846: int rc = LDAP_SUCCESS;
! 847: char *p;
! 848: char *path;
! 849: char *q = NULL;
! 850: char *query = NULL;
! 851: size_t i;
! 852:
! 853: if(!conn->data ||
! 854: !conn->data->state.up.path ||
! 855: conn->data->state.up.path[0] != '/' ||
! 856: !strncasecompare("LDAP", conn->data->state.up.scheme, 4))
! 857: return LDAP_INVALID_SYNTAX;
! 858:
! 859: ludp->lud_scope = LDAP_SCOPE_BASE;
! 860: ludp->lud_port = conn->remote_port;
! 861: ludp->lud_host = conn->host.name;
! 862:
! 863: /* Duplicate the path */
! 864: p = path = strdup(conn->data->state.up.path + 1);
! 865: if(!path)
! 866: return LDAP_NO_MEMORY;
! 867:
! 868: /* Duplicate the query if present */
! 869: if(conn->data->state.up.query) {
! 870: q = query = strdup(conn->data->state.up.query);
! 871: if(!query) {
! 872: free(path);
! 873: return LDAP_NO_MEMORY;
! 874: }
! 875: }
! 876:
! 877: /* Parse the DN (Distinguished Name) */
! 878: if(*p) {
! 879: char *dn = p;
! 880: char *unescaped;
! 881: CURLcode result;
! 882:
! 883: LDAP_TRACE(("DN '%s'\n", dn));
! 884:
! 885: /* Unescape the DN */
! 886: result = Curl_urldecode(conn->data, dn, 0, &unescaped, NULL, FALSE);
! 887: if(result) {
! 888: rc = LDAP_NO_MEMORY;
! 889:
! 890: goto quit;
! 891: }
! 892:
! 893: #if defined(USE_WIN32_LDAP)
! 894: /* Convert the unescaped string to a tchar */
! 895: ludp->lud_dn = Curl_convert_UTF8_to_tchar(unescaped);
! 896:
! 897: /* Free the unescaped string as we are done with it */
! 898: Curl_unicodefree(unescaped);
! 899:
! 900: if(!ludp->lud_dn) {
! 901: rc = LDAP_NO_MEMORY;
! 902:
! 903: goto quit;
! 904: }
! 905: #else
! 906: ludp->lud_dn = unescaped;
! 907: #endif
! 908: }
! 909:
! 910: p = q;
! 911: if(!p)
! 912: goto quit;
! 913:
! 914: /* Parse the attributes. skip "??" */
! 915: q = strchr(p, '?');
! 916: if(q)
! 917: *q++ = '\0';
! 918:
! 919: if(*p) {
! 920: char **attributes;
! 921: size_t count = 0;
! 922:
! 923: /* Split the string into an array of attributes */
! 924: if(!split_str(p, &attributes, &count)) {
! 925: rc = LDAP_NO_MEMORY;
! 926:
! 927: goto quit;
! 928: }
! 929:
! 930: /* Allocate our array (+1 for the NULL entry) */
! 931: #if defined(USE_WIN32_LDAP)
! 932: ludp->lud_attrs = calloc(count + 1, sizeof(TCHAR *));
! 933: #else
! 934: ludp->lud_attrs = calloc(count + 1, sizeof(char *));
! 935: #endif
! 936: if(!ludp->lud_attrs) {
! 937: free(attributes);
! 938:
! 939: rc = LDAP_NO_MEMORY;
! 940:
! 941: goto quit;
! 942: }
! 943:
! 944: for(i = 0; i < count; i++) {
! 945: char *unescaped;
! 946: CURLcode result;
! 947:
! 948: LDAP_TRACE(("attr[%d] '%s'\n", i, attributes[i]));
! 949:
! 950: /* Unescape the attribute */
! 951: result = Curl_urldecode(conn->data, attributes[i], 0, &unescaped, NULL,
! 952: FALSE);
! 953: if(result) {
! 954: free(attributes);
! 955:
! 956: rc = LDAP_NO_MEMORY;
! 957:
! 958: goto quit;
! 959: }
! 960:
! 961: #if defined(USE_WIN32_LDAP)
! 962: /* Convert the unescaped string to a tchar */
! 963: ludp->lud_attrs[i] = Curl_convert_UTF8_to_tchar(unescaped);
! 964:
! 965: /* Free the unescaped string as we are done with it */
! 966: Curl_unicodefree(unescaped);
! 967:
! 968: if(!ludp->lud_attrs[i]) {
! 969: free(attributes);
! 970:
! 971: rc = LDAP_NO_MEMORY;
! 972:
! 973: goto quit;
! 974: }
! 975: #else
! 976: ludp->lud_attrs[i] = unescaped;
! 977: #endif
! 978:
! 979: ludp->lud_attrs_dups++;
! 980: }
! 981:
! 982: free(attributes);
! 983: }
! 984:
! 985: p = q;
! 986: if(!p)
! 987: goto quit;
! 988:
! 989: /* Parse the scope. skip "??" */
! 990: q = strchr(p, '?');
! 991: if(q)
! 992: *q++ = '\0';
! 993:
! 994: if(*p) {
! 995: ludp->lud_scope = str2scope(p);
! 996: if(ludp->lud_scope == -1) {
! 997: rc = LDAP_INVALID_SYNTAX;
! 998:
! 999: goto quit;
! 1000: }
! 1001: LDAP_TRACE(("scope %d\n", ludp->lud_scope));
! 1002: }
! 1003:
! 1004: p = q;
! 1005: if(!p)
! 1006: goto quit;
! 1007:
! 1008: /* Parse the filter */
! 1009: q = strchr(p, '?');
! 1010: if(q)
! 1011: *q++ = '\0';
! 1012:
! 1013: if(*p) {
! 1014: char *filter = p;
! 1015: char *unescaped;
! 1016: CURLcode result;
! 1017:
! 1018: LDAP_TRACE(("filter '%s'\n", filter));
! 1019:
! 1020: /* Unescape the filter */
! 1021: result = Curl_urldecode(conn->data, filter, 0, &unescaped, NULL, FALSE);
! 1022: if(result) {
! 1023: rc = LDAP_NO_MEMORY;
! 1024:
! 1025: goto quit;
! 1026: }
! 1027:
! 1028: #if defined(USE_WIN32_LDAP)
! 1029: /* Convert the unescaped string to a tchar */
! 1030: ludp->lud_filter = Curl_convert_UTF8_to_tchar(unescaped);
! 1031:
! 1032: /* Free the unescaped string as we are done with it */
! 1033: Curl_unicodefree(unescaped);
! 1034:
! 1035: if(!ludp->lud_filter) {
! 1036: rc = LDAP_NO_MEMORY;
! 1037:
! 1038: goto quit;
! 1039: }
! 1040: #else
! 1041: ludp->lud_filter = unescaped;
! 1042: #endif
! 1043: }
! 1044:
! 1045: p = q;
! 1046: if(p && !*p) {
! 1047: rc = LDAP_INVALID_SYNTAX;
! 1048:
! 1049: goto quit;
! 1050: }
! 1051:
! 1052: quit:
! 1053: free(path);
! 1054: free(query);
! 1055:
! 1056: return rc;
! 1057: }
! 1058:
! 1059: static int _ldap_url_parse(const struct connectdata *conn,
! 1060: LDAPURLDesc **ludpp)
! 1061: {
! 1062: LDAPURLDesc *ludp = calloc(1, sizeof(*ludp));
! 1063: int rc;
! 1064:
! 1065: *ludpp = NULL;
! 1066: if(!ludp)
! 1067: return LDAP_NO_MEMORY;
! 1068:
! 1069: rc = _ldap_url_parse2(conn, ludp);
! 1070: if(rc != LDAP_SUCCESS) {
! 1071: _ldap_free_urldesc(ludp);
! 1072: ludp = NULL;
! 1073: }
! 1074: *ludpp = ludp;
! 1075: return (rc);
! 1076: }
! 1077:
! 1078: static void _ldap_free_urldesc(LDAPURLDesc *ludp)
! 1079: {
! 1080: if(!ludp)
! 1081: return;
! 1082:
! 1083: free(ludp->lud_dn);
! 1084: free(ludp->lud_filter);
! 1085:
! 1086: if(ludp->lud_attrs) {
! 1087: size_t i;
! 1088: for(i = 0; i < ludp->lud_attrs_dups; i++)
! 1089: free(ludp->lud_attrs[i]);
! 1090: free(ludp->lud_attrs);
! 1091: }
! 1092:
! 1093: free(ludp);
! 1094: }
! 1095: #endif /* !HAVE_LDAP_URL_PARSE */
! 1096: #endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>