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