1/*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 1998 - 2011, 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 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 "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 CURL_LDAP_WIN /* 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#ifdef HAVE_UNISTD_H 58# include <unistd.h> 59#endif 60 61#include "urldata.h" 62#include <curl/curl.h> 63#include "sendf.h" 64#include "escape.h" 65#include "progress.h" 66#include "transfer.h" 67#include "strequal.h" 68#include "strtok.h" 69#include "curl_ldap.h" 70#include "curl_memory.h" 71#include "curl_base64.h" 72#include "rawstr.h" 73 74#define _MPRINTF_REPLACE /* use our functions only */ 75#include <curl/mprintf.h> 76 77#include "memdebug.h" 78 79#ifndef HAVE_LDAP_URL_PARSE 80 81/* Use our own implementation. */ 82 83typedef struct { 84 char *lud_host; 85 int lud_port; 86 char *lud_dn; 87 char **lud_attrs; 88 int lud_scope; 89 char *lud_filter; 90 char **lud_exts; 91} CURL_LDAPURLDesc; 92 93#undef LDAPURLDesc 94#define LDAPURLDesc CURL_LDAPURLDesc 95 96static int _ldap_url_parse (const struct connectdata *conn, 97 LDAPURLDesc **ludp); 98static void _ldap_free_urldesc (LDAPURLDesc *ludp); 99 100#undef ldap_free_urldesc 101#define ldap_free_urldesc _ldap_free_urldesc 102#endif 103 104#ifdef DEBUG_LDAP 105 #define LDAP_TRACE(x) do { \ 106 _ldap_trace ("%u: ", __LINE__); \ 107 _ldap_trace x; \ 108 } WHILE_FALSE 109 110 static void _ldap_trace (const char *fmt, ...); 111#else 112 #define LDAP_TRACE(x) Curl_nop_stmt 113#endif 114 115 116static CURLcode Curl_ldap(struct connectdata *conn, bool *done); 117 118/* 119 * LDAP protocol handler. 120 */ 121 122const struct Curl_handler Curl_handler_ldap = { 123 "LDAP", /* scheme */ 124 ZERO_NULL, /* setup_connection */ 125 Curl_ldap, /* do_it */ 126 ZERO_NULL, /* done */ 127 ZERO_NULL, /* do_more */ 128 ZERO_NULL, /* connect_it */ 129 ZERO_NULL, /* connecting */ 130 ZERO_NULL, /* doing */ 131 ZERO_NULL, /* proto_getsock */ 132 ZERO_NULL, /* doing_getsock */ 133 ZERO_NULL, /* domore_getsock */ 134 ZERO_NULL, /* perform_getsock */ 135 ZERO_NULL, /* disconnect */ 136 ZERO_NULL, /* readwrite */ 137 PORT_LDAP, /* defport */ 138 CURLPROTO_LDAP, /* protocol */ 139 PROTOPT_NONE /* flags */ 140}; 141 142#ifdef HAVE_LDAP_SSL 143/* 144 * LDAPS protocol handler. 145 */ 146 147const struct Curl_handler Curl_handler_ldaps = { 148 "LDAPS", /* scheme */ 149 ZERO_NULL, /* setup_connection */ 150 Curl_ldap, /* do_it */ 151 ZERO_NULL, /* done */ 152 ZERO_NULL, /* do_more */ 153 ZERO_NULL, /* connect_it */ 154 ZERO_NULL, /* connecting */ 155 ZERO_NULL, /* doing */ 156 ZERO_NULL, /* proto_getsock */ 157 ZERO_NULL, /* doing_getsock */ 158 ZERO_NULL, /* domore_getsock */ 159 ZERO_NULL, /* perform_getsock */ 160 ZERO_NULL, /* disconnect */ 161 ZERO_NULL, /* readwrite */ 162 PORT_LDAPS, /* defport */ 163 CURLPROTO_LDAP | CURLPROTO_LDAPS, /* protocol */ 164 PROTOPT_SSL /* flags */ 165}; 166#endif 167 168 169static CURLcode Curl_ldap(struct connectdata *conn, bool *done) 170{ 171 CURLcode status = CURLE_OK; 172 int rc = 0; 173 LDAP *server = NULL; 174 LDAPURLDesc *ludp = NULL; 175 LDAPMessage *result = NULL; 176 LDAPMessage *entryIterator; 177 int num = 0; 178 struct SessionHandle *data=conn->data; 179 int ldap_proto = LDAP_VERSION3; 180 int ldap_ssl = 0; 181 char *val_b64 = NULL; 182 size_t val_b64_sz = 0; 183 curl_off_t dlsize = 0; 184#ifdef LDAP_OPT_NETWORK_TIMEOUT 185 struct timeval ldap_timeout = {10,0}; /* 10 sec connection/search timeout */ 186#endif 187 188 *done = TRUE; /* unconditionally */ 189 infof(data, "LDAP local: LDAP Vendor = %s ; LDAP Version = %d\n", 190 LDAP_VENDOR_NAME, LDAP_VENDOR_VERSION); 191 infof(data, "LDAP local: %s\n", data->change.url); 192 193#ifdef HAVE_LDAP_URL_PARSE 194 rc = ldap_url_parse(data->change.url, &ludp); 195#else 196 rc = _ldap_url_parse(conn, &ludp); 197#endif 198 if(rc != 0) { 199 failf(data, "LDAP local: %s", ldap_err2string(rc)); 200 status = CURLE_LDAP_INVALID_URL; 201 goto quit; 202 } 203 204 /* Get the URL scheme ( either ldap or ldaps ) */ 205 if(conn->given->flags & PROTOPT_SSL) 206 ldap_ssl = 1; 207 infof(data, "LDAP local: trying to establish %s connection\n", 208 ldap_ssl ? "encrypted" : "cleartext"); 209 210#ifdef LDAP_OPT_NETWORK_TIMEOUT 211 ldap_set_option(NULL, LDAP_OPT_NETWORK_TIMEOUT, &ldap_timeout); 212#endif 213 ldap_set_option(NULL, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); 214 215 if(ldap_ssl) { 216#ifdef HAVE_LDAP_SSL 217#ifdef CURL_LDAP_WIN 218 /* Win32 LDAP SDK doesn't support insecure mode without CA! */ 219 server = ldap_sslinit(conn->host.name, (int)conn->port, 1); 220 ldap_set_option(server, LDAP_OPT_SSL, LDAP_OPT_ON); 221#else 222 int ldap_option; 223 char* ldap_ca = data->set.str[STRING_SSL_CAFILE]; 224#if defined(CURL_HAS_NOVELL_LDAPSDK) 225 rc = ldapssl_client_init(NULL, NULL); 226 if(rc != LDAP_SUCCESS) { 227 failf(data, "LDAP local: ldapssl_client_init %s", ldap_err2string(rc)); 228 status = CURLE_SSL_CERTPROBLEM; 229 goto quit; 230 } 231 if(data->set.ssl.verifypeer) { 232 /* Novell SDK supports DER or BASE64 files. */ 233 int cert_type = LDAPSSL_CERT_FILETYPE_B64; 234 if((data->set.str[STRING_CERT_TYPE]) && 235 (Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "DER"))) 236 cert_type = LDAPSSL_CERT_FILETYPE_DER; 237 if(!ldap_ca) { 238 failf(data, "LDAP local: ERROR %s CA cert not set!", 239 (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM")); 240 status = CURLE_SSL_CERTPROBLEM; 241 goto quit; 242 } 243 infof(data, "LDAP local: using %s CA cert '%s'\n", 244 (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), 245 ldap_ca); 246 rc = ldapssl_add_trusted_cert(ldap_ca, cert_type); 247 if(rc != LDAP_SUCCESS) { 248 failf(data, "LDAP local: ERROR setting %s CA cert: %s", 249 (cert_type == LDAPSSL_CERT_FILETYPE_DER ? "DER" : "PEM"), 250 ldap_err2string(rc)); 251 status = CURLE_SSL_CERTPROBLEM; 252 goto quit; 253 } 254 ldap_option = LDAPSSL_VERIFY_SERVER; 255 } 256 else 257 ldap_option = LDAPSSL_VERIFY_NONE; 258 rc = ldapssl_set_verify_mode(ldap_option); 259 if(rc != LDAP_SUCCESS) { 260 failf(data, "LDAP local: ERROR setting cert verify mode: %s", 261 ldap_err2string(rc)); 262 status = CURLE_SSL_CERTPROBLEM; 263 goto quit; 264 } 265 server = ldapssl_init(conn->host.name, (int)conn->port, 1); 266 if(server == NULL) { 267 failf(data, "LDAP local: Cannot connect to %s:%hu", 268 conn->host.name, conn->port); 269 status = CURLE_COULDNT_CONNECT; 270 goto quit; 271 } 272#elif defined(LDAP_OPT_X_TLS) 273 if(data->set.ssl.verifypeer) { 274 /* OpenLDAP SDK supports BASE64 files. */ 275 if((data->set.str[STRING_CERT_TYPE]) && 276 (!Curl_raw_equal(data->set.str[STRING_CERT_TYPE], "PEM"))) { 277 failf(data, "LDAP local: ERROR OpenLDAP only supports PEM cert-type!"); 278 status = CURLE_SSL_CERTPROBLEM; 279 goto quit; 280 } 281 if(!ldap_ca) { 282 failf(data, "LDAP local: ERROR PEM CA cert not set!"); 283 status = CURLE_SSL_CERTPROBLEM; 284 goto quit; 285 } 286 infof(data, "LDAP local: using PEM CA cert: %s\n", ldap_ca); 287 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_CACERTFILE, ldap_ca); 288 if(rc != LDAP_SUCCESS) { 289 failf(data, "LDAP local: ERROR setting PEM CA cert: %s", 290 ldap_err2string(rc)); 291 status = CURLE_SSL_CERTPROBLEM; 292 goto quit; 293 } 294 ldap_option = LDAP_OPT_X_TLS_DEMAND; 295 } 296 else 297 ldap_option = LDAP_OPT_X_TLS_NEVER; 298 299 rc = ldap_set_option(NULL, LDAP_OPT_X_TLS_REQUIRE_CERT, &ldap_option); 300 if(rc != LDAP_SUCCESS) { 301 failf(data, "LDAP local: ERROR setting cert verify mode: %s", 302 ldap_err2string(rc)); 303 status = CURLE_SSL_CERTPROBLEM; 304 goto quit; 305 } 306 server = ldap_init(conn->host.name, (int)conn->port); 307 if(server == NULL) { 308 failf(data, "LDAP local: Cannot connect to %s:%hu", 309 conn->host.name, conn->port); 310 status = CURLE_COULDNT_CONNECT; 311 goto quit; 312 } 313 ldap_option = LDAP_OPT_X_TLS_HARD; 314 rc = ldap_set_option(server, LDAP_OPT_X_TLS, &ldap_option); 315 if(rc != LDAP_SUCCESS) { 316 failf(data, "LDAP local: ERROR setting SSL/TLS mode: %s", 317 ldap_err2string(rc)); 318 status = CURLE_SSL_CERTPROBLEM; 319 goto quit; 320 } 321/* 322 rc = ldap_start_tls_s(server, NULL, NULL); 323 if(rc != LDAP_SUCCESS) { 324 failf(data, "LDAP local: ERROR starting SSL/TLS mode: %s", 325 ldap_err2string(rc)); 326 status = CURLE_SSL_CERTPROBLEM; 327 goto quit; 328 } 329*/ 330#else 331 /* we should probably never come up to here since configure 332 should check in first place if we can support LDAP SSL/TLS */ 333 failf(data, "LDAP local: SSL/TLS not supported with this version " 334 "of the OpenLDAP toolkit\n"); 335 status = CURLE_SSL_CERTPROBLEM; 336 goto quit; 337#endif 338#endif 339#endif /* CURL_LDAP_USE_SSL */ 340 } 341 else { 342 server = ldap_init(conn->host.name, (int)conn->port); 343 if(server == NULL) { 344 failf(data, "LDAP local: Cannot connect to %s:%hu", 345 conn->host.name, conn->port); 346 status = CURLE_COULDNT_CONNECT; 347 goto quit; 348 } 349 } 350#ifdef CURL_LDAP_WIN 351 ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); 352#endif 353 354 rc = ldap_simple_bind_s(server, 355 conn->bits.user_passwd ? conn->user : NULL, 356 conn->bits.user_passwd ? conn->passwd : NULL); 357 if(!ldap_ssl && rc != 0) { 358 ldap_proto = LDAP_VERSION2; 359 ldap_set_option(server, LDAP_OPT_PROTOCOL_VERSION, &ldap_proto); 360 rc = ldap_simple_bind_s(server, 361 conn->bits.user_passwd ? conn->user : NULL, 362 conn->bits.user_passwd ? conn->passwd : NULL); 363 } 364 if(rc != 0) { 365 failf(data, "LDAP local: ldap_simple_bind_s %s", ldap_err2string(rc)); 366 status = CURLE_LDAP_CANNOT_BIND; 367 goto quit; 368 } 369 370 rc = ldap_search_s(server, ludp->lud_dn, ludp->lud_scope, 371 ludp->lud_filter, ludp->lud_attrs, 0, &result); 372 373 if(rc != 0 && rc != LDAP_SIZELIMIT_EXCEEDED) { 374 failf(data, "LDAP remote: %s", ldap_err2string(rc)); 375 status = CURLE_LDAP_SEARCH_FAILED; 376 goto quit; 377 } 378 379 for(num = 0, entryIterator = ldap_first_entry(server, result); 380 entryIterator; 381 entryIterator = ldap_next_entry(server, entryIterator), num++) { 382 BerElement *ber = NULL; 383 char *attribute; /*! suspicious that this isn't 'const' */ 384 char *dn = ldap_get_dn(server, entryIterator); 385 int i; 386 387 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4); 388 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)dn, 0); 389 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); 390 391 dlsize += strlen(dn)+5; 392 393 for(attribute = ldap_first_attribute(server, entryIterator, &ber); 394 attribute; 395 attribute = ldap_next_attribute(server, entryIterator, ber)) { 396 BerValue **vals = ldap_get_values_len(server, entryIterator, attribute); 397 398 if(vals != NULL) { 399 for(i = 0; (vals[i] != NULL); i++) { 400 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1); 401 Curl_client_write(conn, CLIENTWRITE_BODY, (char *) attribute, 0); 402 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)": ", 2); 403 dlsize += strlen(attribute)+3; 404 405 if((strlen(attribute) > 7) && 406 (strcmp(";binary", 407 (char *)attribute + 408 (strlen((char *)attribute) - 7)) == 0)) { 409 /* Binary attribute, encode to base64. */ 410 CURLcode error = Curl_base64_encode(data, 411 vals[i]->bv_val, 412 vals[i]->bv_len, 413 &val_b64, 414 &val_b64_sz); 415 if(error) { 416 ldap_value_free_len(vals); 417 ldap_memfree(attribute); 418 ldap_memfree(dn); 419 if(ber) 420 ber_free(ber, 0); 421 status = error; 422 goto quit; 423 } 424 if(val_b64_sz > 0) { 425 Curl_client_write(conn, CLIENTWRITE_BODY, val_b64, val_b64_sz); 426 free(val_b64); 427 dlsize += val_b64_sz; 428 } 429 } 430 else { 431 Curl_client_write(conn, CLIENTWRITE_BODY, vals[i]->bv_val, 432 vals[i]->bv_len); 433 dlsize += vals[i]->bv_len; 434 } 435 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0); 436 dlsize++; 437 } 438 439 /* Free memory used to store values */ 440 ldap_value_free_len(vals); 441 } 442 Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1); 443 dlsize++; 444 Curl_pgrsSetDownloadCounter(data, dlsize); 445 ldap_memfree(attribute); 446 } 447 ldap_memfree(dn); 448 if(ber) 449 ber_free(ber, 0); 450 } 451 452quit: 453 if(result) { 454 ldap_msgfree(result); 455 LDAP_TRACE (("Received %d entries\n", num)); 456 } 457 if(rc == LDAP_SIZELIMIT_EXCEEDED) 458 infof(data, "There are more than %d entries\n", num); 459 if(ludp) 460 ldap_free_urldesc(ludp); 461 if(server) 462 ldap_unbind_s(server); 463#if defined(HAVE_LDAP_SSL) && defined(CURL_HAS_NOVELL_LDAPSDK) 464 if(ldap_ssl) 465 ldapssl_client_deinit(); 466#endif /* HAVE_LDAP_SSL && CURL_HAS_NOVELL_LDAPSDK */ 467 468 /* no data to transfer */ 469 Curl_setup_transfer(conn, -1, -1, FALSE, NULL, -1, NULL); 470 conn->bits.close = TRUE; 471 472 return status; 473} 474 475#ifdef DEBUG_LDAP 476static void _ldap_trace (const char *fmt, ...) 477{ 478 static int do_trace = -1; 479 va_list args; 480 481 if(do_trace == -1) { 482 const char *env = getenv("CURL_TRACE"); 483 do_trace = (env && strtol(env, NULL, 10) > 0); 484 } 485 if(!do_trace) 486 return; 487 488 va_start (args, fmt); 489 vfprintf (stderr, fmt, args); 490 va_end (args); 491} 492#endif 493 494#ifndef HAVE_LDAP_URL_PARSE 495 496/* 497 * Return scope-value for a scope-string. 498 */ 499static int str2scope (const char *p) 500{ 501 if(strequal(p, "one")) 502 return LDAP_SCOPE_ONELEVEL; 503 if(strequal(p, "onetree")) 504 return LDAP_SCOPE_ONELEVEL; 505 if(strequal(p, "base")) 506 return LDAP_SCOPE_BASE; 507 if(strequal(p, "sub")) 508 return LDAP_SCOPE_SUBTREE; 509 if(strequal( p, "subtree")) 510 return LDAP_SCOPE_SUBTREE; 511 return (-1); 512} 513 514/* 515 * Split 'str' into strings separated by commas. 516 * Note: res[] points into 'str'. 517 */ 518static char **split_str (char *str) 519{ 520 char **res, *lasts, *s; 521 int i; 522 523 for(i = 2, s = strchr(str,','); s; i++) 524 s = strchr(++s,','); 525 526 res = calloc(i, sizeof(char*)); 527 if(!res) 528 return NULL; 529 530 for(i = 0, s = strtok_r(str, ",", &lasts); s; 531 s = strtok_r(NULL, ",", &lasts), i++) 532 res[i] = s; 533 return res; 534} 535 536/* 537 * Unescape the LDAP-URL components 538 */ 539static bool unescape_elements (void *data, LDAPURLDesc *ludp) 540{ 541 int i; 542 543 if(ludp->lud_filter) { 544 ludp->lud_filter = curl_easy_unescape(data, ludp->lud_filter, 0, NULL); 545 if(!ludp->lud_filter) 546 return (FALSE); 547 } 548 549 for(i = 0; ludp->lud_attrs && ludp->lud_attrs[i]; i++) { 550 ludp->lud_attrs[i] = curl_easy_unescape(data, ludp->lud_attrs[i], 0, NULL); 551 if(!ludp->lud_attrs[i]) 552 return (FALSE); 553 } 554 555 for(i = 0; ludp->lud_exts && ludp->lud_exts[i]; i++) { 556 ludp->lud_exts[i] = curl_easy_unescape(data, ludp->lud_exts[i], 0, NULL); 557 if(!ludp->lud_exts[i]) 558 return (FALSE); 559 } 560 561 if(ludp->lud_dn) { 562 char *dn = ludp->lud_dn; 563 char *new_dn = curl_easy_unescape(data, dn, 0, NULL); 564 565 free(dn); 566 ludp->lud_dn = new_dn; 567 if(!new_dn) 568 return (FALSE); 569 } 570 return (TRUE); 571} 572 573/* 574 * Break apart the pieces of an LDAP URL. 575 * Syntax: 576 * ldap://<hostname>:<port>/<base_dn>?<attributes>?<scope>?<filter>?<ext> 577 * 578 * <hostname> already known from 'conn->host.name'. 579 * <port> already known from 'conn->remote_port'. 580 * extract the rest from 'conn->data->state.path+1'. All fields are optional. 581 * e.g. 582 * ldap://<hostname>:<port>/?<attributes>?<scope>?<filter> 583 * yields ludp->lud_dn = "". 584 * 585 * Defined in RFC4516 section 2. 586 */ 587static int _ldap_url_parse2 (const struct connectdata *conn, LDAPURLDesc *ludp) 588{ 589 char *p, *q; 590 int i; 591 592 if(!conn->data || 593 !conn->data->state.path || 594 conn->data->state.path[0] != '/' || 595 !checkprefix("LDAP", conn->data->change.url)) 596 return LDAP_INVALID_SYNTAX; 597 598 ludp->lud_scope = LDAP_SCOPE_BASE; 599 ludp->lud_port = conn->remote_port; 600 ludp->lud_host = conn->host.name; 601 602 /* parse DN (Distinguished Name). 603 */ 604 ludp->lud_dn = strdup(conn->data->state.path+1); 605 if(!ludp->lud_dn) 606 return LDAP_NO_MEMORY; 607 608 p = strchr(ludp->lud_dn, '?'); 609 LDAP_TRACE (("DN '%.*s'\n", p ? (size_t)(p-ludp->lud_dn) : 610 strlen(ludp->lud_dn), ludp->lud_dn)); 611 612 if(!p) 613 goto success; 614 615 *p++ = '\0'; 616 617 /* parse attributes. skip "??". 618 */ 619 q = strchr(p, '?'); 620 if(q) 621 *q++ = '\0'; 622 623 if(*p && *p != '?') { 624 ludp->lud_attrs = split_str(p); 625 if(!ludp->lud_attrs) 626 return LDAP_NO_MEMORY; 627 628 for(i = 0; ludp->lud_attrs[i]; i++) 629 LDAP_TRACE (("attr[%d] '%s'\n", i, ludp->lud_attrs[i])); 630 } 631 632 p = q; 633 if(!p) 634 goto success; 635 636 /* parse scope. skip "??" 637 */ 638 q = strchr(p, '?'); 639 if(q) 640 *q++ = '\0'; 641 642 if(*p && *p != '?') { 643 ludp->lud_scope = str2scope(p); 644 if(ludp->lud_scope == -1) 645 return LDAP_INVALID_SYNTAX; 646 LDAP_TRACE (("scope %d\n", ludp->lud_scope)); 647 } 648 649 p = q; 650 if(!p) 651 goto success; 652 653 /* parse filter 654 */ 655 q = strchr(p, '?'); 656 if(q) 657 *q++ = '\0'; 658 if(!*p) 659 return LDAP_INVALID_SYNTAX; 660 661 ludp->lud_filter = p; 662 LDAP_TRACE (("filter '%s'\n", ludp->lud_filter)); 663 664 p = q; 665 if(!p) 666 goto success; 667 668 /* parse extensions 669 */ 670 ludp->lud_exts = split_str(p); 671 if(!ludp->lud_exts) 672 return LDAP_NO_MEMORY; 673 674 for(i = 0; ludp->lud_exts[i]; i++) 675 LDAP_TRACE (("exts[%d] '%s'\n", i, ludp->lud_exts[i])); 676 677 success: 678 if(!unescape_elements(conn->data, ludp)) 679 return LDAP_NO_MEMORY; 680 return LDAP_SUCCESS; 681} 682 683static int _ldap_url_parse (const struct connectdata *conn, 684 LDAPURLDesc **ludpp) 685{ 686 LDAPURLDesc *ludp = calloc(1, sizeof(*ludp)); 687 int rc; 688 689 *ludpp = NULL; 690 if(!ludp) 691 return LDAP_NO_MEMORY; 692 693 rc = _ldap_url_parse2 (conn, ludp); 694 if(rc != LDAP_SUCCESS) { 695 _ldap_free_urldesc(ludp); 696 ludp = NULL; 697 } 698 *ludpp = ludp; 699 return (rc); 700} 701 702static void _ldap_free_urldesc (LDAPURLDesc *ludp) 703{ 704 int i; 705 706 if(!ludp) 707 return; 708 709 if(ludp->lud_dn) 710 free(ludp->lud_dn); 711 712 if(ludp->lud_filter) 713 free(ludp->lud_filter); 714 715 if(ludp->lud_attrs) { 716 for(i = 0; ludp->lud_attrs[i]; i++) 717 free(ludp->lud_attrs[i]); 718 free(ludp->lud_attrs); 719 } 720 721 if(ludp->lud_exts) { 722 for(i = 0; ludp->lud_exts[i]; i++) 723 free(ludp->lud_exts[i]); 724 free(ludp->lud_exts); 725 } 726 free (ludp); 727} 728#endif /* !HAVE_LDAP_URL_PARSE */ 729#endif /* !CURL_DISABLE_LDAP && !USE_OPENLDAP */ 730