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