VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/ldap.c@ 104083

Last change on this file since 104083 was 104083, checked in by vboxsync, 10 months ago

curl-8.7.1: Applied and adjusted our curl changes to 8.4.0. bugref:10639

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette