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