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


rc_tagdetect_client
Author(s): Monika Florek-Jasinska , Raphael Schaller
autogenerated on Sat Feb 13 2021 03:42:15