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