VirtualBox

source: vbox/trunk/src/libs/curl-8.7.1/lib/openldap.c@ 106165

最後變更 在這個檔案從106165是 104083,由 vboxsync 提交於 8 月 前

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

  • 屬性 svn:eol-style 設為 native
檔案大小: 34.5 KB
 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) Daniel Stenberg, <[email protected]>, et al.
9 * Copyright (C) Howard Chu, <[email protected]>
10 *
11 * This software is licensed as described in the file COPYING, which
12 * you should have received as part of this distribution. The terms
13 * are also available at https://curl.se/docs/copyright.html.
14 *
15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
16 * copies of the Software, and permit persons to whom the Software is
17 * furnished to do so, under the terms of the COPYING file.
18 *
19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
20 * KIND, either express or implied.
21 *
22 * SPDX-License-Identifier: curl
23 *
24 ***************************************************************************/
25
26#include "curl_setup.h"
27
28#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
29
30/*
31 * Notice that USE_OPENLDAP is only a source code selection switch. When
32 * libcurl is built with USE_OPENLDAP defined the libcurl source code that
33 * gets compiled is the code from openldap.c, otherwise the code that gets
34 * compiled is the code from ldap.c.
35 *
36 * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
37 * might be required for compilation and runtime. In order to use ancient
38 * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
39 */
40
41#include <ldap.h>
42
43#include "urldata.h"
44#include <curl/curl.h>
45#include "sendf.h"
46#include "vtls/vtls.h"
47#include "transfer.h"
48#include "curl_ldap.h"
49#include "curl_base64.h"
50#include "cfilters.h"
51#include "connect.h"
52#include "curl_sasl.h"
53#include "strcase.h"
54/* The last 3 #include files should be in this order */
55#include "curl_printf.h"
56#include "curl_memory.h"
57#include "memdebug.h"
58
59/*
60 * Uncommenting this will enable the built-in debug logging of the openldap
61 * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
62 * environment variable. The debug output is written to stderr.
63 *
64 * The library supports the following debug flags:
65 * LDAP_DEBUG_NONE 0x0000
66 * LDAP_DEBUG_TRACE 0x0001
67 * LDAP_DEBUG_CONSTRUCT 0x0002
68 * LDAP_DEBUG_DESTROY 0x0004
69 * LDAP_DEBUG_PARAMETER 0x0008
70 * LDAP_DEBUG_ANY 0xffff
71 *
72 * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
73 * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
74 * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
75 */
76/* #define CURL_OPENLDAP_DEBUG */
77
78/* Machine states. */
79typedef enum {
80 OLDAP_STOP, /* Do nothing state, stops the state machine */
81 OLDAP_SSL, /* Performing SSL handshake. */
82 OLDAP_STARTTLS, /* STARTTLS request sent. */
83 OLDAP_TLS, /* Performing TLS handshake. */
84 OLDAP_MECHS, /* Get SASL authentication mechanisms. */
85 OLDAP_SASL, /* SASL binding reply. */
86 OLDAP_BIND, /* Simple bind reply. */
87 OLDAP_BINDV2, /* Simple bind reply in protocol version 2. */
88 OLDAP_LAST /* Never used */
89} ldapstate;
90
91#ifndef _LDAP_PVT_H
92extern int ldap_pvt_url_scheme2proto(const char *);
93extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
94 LDAP **ld);
95#endif
96
97static CURLcode oldap_setup_connection(struct Curl_easy *data,
98 struct connectdata *conn);
99static CURLcode oldap_do(struct Curl_easy *data, bool *done);
100static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
101static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
102static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
103static CURLcode oldap_disconnect(struct Curl_easy *data,
104 struct connectdata *conn, bool dead);
105
106static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
107 const struct bufref *initresp);
108static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
109 const struct bufref *resp);
110static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech);
111static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out);
112
113static Curl_recv oldap_recv;
114
115/*
116 * LDAP protocol handler.
117 */
118
119const struct Curl_handler Curl_handler_ldap = {
120 "LDAP", /* scheme */
121 oldap_setup_connection, /* setup_connection */
122 oldap_do, /* do_it */
123 oldap_done, /* done */
124 ZERO_NULL, /* do_more */
125 oldap_connect, /* connect_it */
126 oldap_connecting, /* connecting */
127 ZERO_NULL, /* doing */
128 ZERO_NULL, /* proto_getsock */
129 ZERO_NULL, /* doing_getsock */
130 ZERO_NULL, /* domore_getsock */
131 ZERO_NULL, /* perform_getsock */
132 oldap_disconnect, /* disconnect */
133 ZERO_NULL, /* write_resp */
134 ZERO_NULL, /* connection_check */
135 ZERO_NULL, /* attach connection */
136 PORT_LDAP, /* defport */
137 CURLPROTO_LDAP, /* protocol */
138 CURLPROTO_LDAP, /* family */
139 PROTOPT_NONE /* flags */
140};
141
142#ifdef USE_SSL
143/*
144 * LDAPS protocol handler.
145 */
146
147const struct Curl_handler Curl_handler_ldaps = {
148 "LDAPS", /* scheme */
149 oldap_setup_connection, /* setup_connection */
150 oldap_do, /* do_it */
151 oldap_done, /* done */
152 ZERO_NULL, /* do_more */
153 oldap_connect, /* connect_it */
154 oldap_connecting, /* connecting */
155 ZERO_NULL, /* doing */
156 ZERO_NULL, /* proto_getsock */
157 ZERO_NULL, /* doing_getsock */
158 ZERO_NULL, /* domore_getsock */
159 ZERO_NULL, /* perform_getsock */
160 oldap_disconnect, /* disconnect */
161 ZERO_NULL, /* write_resp */
162 ZERO_NULL, /* connection_check */
163 ZERO_NULL, /* attach connection */
164 PORT_LDAPS, /* defport */
165 CURLPROTO_LDAPS, /* protocol */
166 CURLPROTO_LDAP, /* family */
167 PROTOPT_SSL /* flags */
168};
169#endif
170
171/* SASL parameters for the ldap protocol */
172static const struct SASLproto saslldap = {
173 "ldap", /* The service name */
174 oldap_perform_auth, /* Send authentication command */
175 oldap_continue_auth, /* Send authentication continuation */
176 oldap_cancel_auth, /* Send authentication cancellation */
177 oldap_get_message, /* Get SASL response message */
178 0, /* Maximum initial response length (no max) */
179 LDAP_SASL_BIND_IN_PROGRESS, /* Code received when continuation is expected */
180 LDAP_SUCCESS, /* Code to receive upon authentication success */
181 SASL_AUTH_NONE, /* Default mechanisms */
182 0 /* Configuration flags */
183};
184
185struct ldapconninfo {
186 struct SASL sasl; /* SASL-related parameters */
187 LDAP *ld; /* Openldap connection handle. */
188 Curl_recv *recv; /* For stacking SSL handler */
189 Curl_send *send;
190 struct berval *servercred; /* SASL data from server. */
191 ldapstate state; /* Current machine state. */
192 int proto; /* LDAP_PROTO_TCP/LDAP_PROTO_UDP/LDAP_PROTO_IPC */
193 int msgid; /* Current message id. */
194};
195
196struct ldapreqinfo {
197 int msgid;
198 int nument;
199};
200
201/*
202 * oldap_state()
203 *
204 * This is the ONLY way to change LDAP state!
205 */
206static void oldap_state(struct Curl_easy *data, ldapstate newstate)
207{
208 struct ldapconninfo *ldapc = data->conn->proto.ldapc;
209
210#if defined(DEBUGBUILD) && !defined(CURL_DISABLE_VERBOSE_STRINGS)
211 /* for debug purposes */
212 static const char * const names[] = {
213 "STOP",
214 "SSL",
215 "STARTTLS",
216 "TLS",
217 "MECHS",
218 "SASL",
219 "BIND",
220 "BINDV2",
221 /* LAST */
222 };
223
224 if(ldapc->state != newstate)
225 infof(data, "LDAP %p state change from %s to %s",
226 (void *)ldapc, names[ldapc->state], names[newstate]);
227#endif
228
229 ldapc->state = newstate;
230}
231
232/* Map some particular LDAP error codes to CURLcode values. */
233static CURLcode oldap_map_error(int rc, CURLcode result)
234{
235 switch(rc) {
236 case LDAP_NO_MEMORY:
237 result = CURLE_OUT_OF_MEMORY;
238 break;
239 case LDAP_INVALID_CREDENTIALS:
240 result = CURLE_LOGIN_DENIED;
241 break;
242 case LDAP_PROTOCOL_ERROR:
243 result = CURLE_UNSUPPORTED_PROTOCOL;
244 break;
245 case LDAP_INSUFFICIENT_ACCESS:
246 result = CURLE_REMOTE_ACCESS_DENIED;
247 break;
248 }
249 return result;
250}
251
252static CURLcode oldap_url_parse(struct Curl_easy *data, LDAPURLDesc **ludp)
253{
254 CURLcode result = CURLE_OK;
255 int rc = LDAP_URL_ERR_BADURL;
256 static const char * const url_errs[] = {
257 "success",
258 "out of memory",
259 "bad parameter",
260 "unrecognized scheme",
261 "unbalanced delimiter",
262 "bad URL",
263 "bad host or port",
264 "bad or missing attributes",
265 "bad or missing scope",
266 "bad or missing filter",
267 "bad or missing extensions"
268 };
269
270 *ludp = NULL;
271 if(!data->state.up.user && !data->state.up.password &&
272 !data->state.up.options)
273 rc = ldap_url_parse(data->state.url, ludp);
274 if(rc != LDAP_URL_SUCCESS) {
275 const char *msg = "url parsing problem";
276
277 result = rc == LDAP_URL_ERR_MEM? CURLE_OUT_OF_MEMORY: CURLE_URL_MALFORMAT;
278 rc -= LDAP_URL_SUCCESS;
279 if((size_t) rc < sizeof(url_errs) / sizeof(url_errs[0]))
280 msg = url_errs[rc];
281 failf(data, "LDAP local: %s", msg);
282 }
283 return result;
284}
285
286/* Parse the login options. */
287static CURLcode oldap_parse_login_options(struct connectdata *conn)
288{
289 CURLcode result = CURLE_OK;
290 struct ldapconninfo *li = conn->proto.ldapc;
291 const char *ptr = conn->options;
292
293 while(!result && ptr && *ptr) {
294 const char *key = ptr;
295 const char *value;
296
297 while(*ptr && *ptr != '=')
298 ptr++;
299
300 value = ptr + 1;
301
302 while(*ptr && *ptr != ';')
303 ptr++;
304
305 if(checkprefix("AUTH=", key))
306 result = Curl_sasl_parse_url_auth_option(&li->sasl, value, ptr - value);
307 else
308 result = CURLE_SETOPT_OPTION_SYNTAX;
309
310 if(*ptr == ';')
311 ptr++;
312 }
313
314 return result == CURLE_URL_MALFORMAT? CURLE_SETOPT_OPTION_SYNTAX: result;
315}
316
317static CURLcode oldap_setup_connection(struct Curl_easy *data,
318 struct connectdata *conn)
319{
320 CURLcode result;
321 LDAPURLDesc *lud;
322 (void)conn;
323
324 /* Early URL syntax check. */
325 result = oldap_url_parse(data, &lud);
326 ldap_free_urldesc(lud);
327
328 return result;
329}
330
331/*
332 * Get the SASL authentication challenge from the server credential buffer.
333 */
334static CURLcode oldap_get_message(struct Curl_easy *data, struct bufref *out)
335{
336 struct berval *servercred = data->conn->proto.ldapc->servercred;
337
338 if(!servercred || !servercred->bv_val)
339 return CURLE_WEIRD_SERVER_REPLY;
340 Curl_bufref_set(out, servercred->bv_val, servercred->bv_len, NULL);
341 return CURLE_OK;
342}
343
344/*
345 * Sends an initial SASL bind request to the server.
346 */
347static CURLcode oldap_perform_auth(struct Curl_easy *data, const char *mech,
348 const struct bufref *initresp)
349{
350 struct connectdata *conn = data->conn;
351 struct ldapconninfo *li = conn->proto.ldapc;
352 CURLcode result = CURLE_OK;
353 struct berval cred;
354 struct berval *pcred = &cred;
355 int rc;
356
357 cred.bv_val = (char *) Curl_bufref_ptr(initresp);
358 cred.bv_len = Curl_bufref_len(initresp);
359 if(!cred.bv_val)
360 pcred = NULL;
361 rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
362 if(rc != LDAP_SUCCESS)
363 result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
364 return result;
365}
366
367/*
368 * Sends SASL continuation.
369 */
370static CURLcode oldap_continue_auth(struct Curl_easy *data, const char *mech,
371 const struct bufref *resp)
372{
373 struct connectdata *conn = data->conn;
374 struct ldapconninfo *li = conn->proto.ldapc;
375 CURLcode result = CURLE_OK;
376 struct berval cred;
377 struct berval *pcred = &cred;
378 int rc;
379
380 cred.bv_val = (char *) Curl_bufref_ptr(resp);
381 cred.bv_len = Curl_bufref_len(resp);
382 if(!cred.bv_val)
383 pcred = NULL;
384 rc = ldap_sasl_bind(li->ld, NULL, mech, pcred, NULL, NULL, &li->msgid);
385 if(rc != LDAP_SUCCESS)
386 result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
387 return result;
388}
389
390/*
391 * Sends SASL bind cancellation.
392 */
393static CURLcode oldap_cancel_auth(struct Curl_easy *data, const char *mech)
394{
395 struct ldapconninfo *li = data->conn->proto.ldapc;
396 CURLcode result = CURLE_OK;
397 int rc = ldap_sasl_bind(li->ld, NULL, LDAP_SASL_NULL, NULL, NULL, NULL,
398 &li->msgid);
399
400 (void)mech;
401 if(rc != LDAP_SUCCESS)
402 result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
403 return result;
404}
405
406/* Starts LDAP simple bind. */
407static CURLcode oldap_perform_bind(struct Curl_easy *data, ldapstate newstate)
408{
409 CURLcode result = CURLE_OK;
410 struct connectdata *conn = data->conn;
411 struct ldapconninfo *li = conn->proto.ldapc;
412 char *binddn = NULL;
413 struct berval passwd;
414 int rc;
415
416 passwd.bv_val = NULL;
417 passwd.bv_len = 0;
418
419 if(data->state.aptr.user) {
420 binddn = conn->user;
421 passwd.bv_val = conn->passwd;
422 passwd.bv_len = strlen(passwd.bv_val);
423 }
424
425 rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
426 NULL, NULL, &li->msgid);
427 if(rc == LDAP_SUCCESS)
428 oldap_state(data, newstate);
429 else
430 result = oldap_map_error(rc,
431 data->state.aptr.user?
432 CURLE_LOGIN_DENIED: CURLE_LDAP_CANNOT_BIND);
433 return result;
434}
435
436/* Query the supported SASL authentication mechanisms. */
437static CURLcode oldap_perform_mechs(struct Curl_easy *data)
438{
439 CURLcode result = CURLE_OK;
440 struct ldapconninfo *li = data->conn->proto.ldapc;
441 int rc;
442 static const char * const supportedSASLMechanisms[] = {
443 "supportedSASLMechanisms",
444 NULL
445 };
446
447 rc = ldap_search_ext(li->ld, "", LDAP_SCOPE_BASE, "(objectclass=*)",
448 (char **) supportedSASLMechanisms, 0,
449 NULL, NULL, NULL, 0, &li->msgid);
450 if(rc == LDAP_SUCCESS)
451 oldap_state(data, OLDAP_MECHS);
452 else
453 result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
454 return result;
455}
456
457/* Starts SASL bind. */
458static CURLcode oldap_perform_sasl(struct Curl_easy *data)
459{
460 saslprogress progress = SASL_IDLE;
461 struct ldapconninfo *li = data->conn->proto.ldapc;
462 CURLcode result = Curl_sasl_start(&li->sasl, data, TRUE, &progress);
463
464 oldap_state(data, OLDAP_SASL);
465 if(!result && progress != SASL_INPROGRESS)
466 result = CURLE_LOGIN_DENIED;
467 return result;
468}
469
470#ifdef USE_SSL
471static Sockbuf_IO ldapsb_tls;
472
473static bool ssl_installed(struct connectdata *conn)
474{
475 return conn->proto.ldapc->recv != NULL;
476}
477
478static CURLcode oldap_ssl_connect(struct Curl_easy *data, ldapstate newstate)
479{
480 CURLcode result = CURLE_OK;
481 struct connectdata *conn = data->conn;
482 struct ldapconninfo *li = conn->proto.ldapc;
483 bool ssldone = 0;
484
485 result = Curl_conn_connect(data, FIRSTSOCKET, FALSE, &ssldone);
486 if(!result) {
487 oldap_state(data, newstate);
488
489 if(ssldone) {
490 Sockbuf *sb;
491
492 /* Install the libcurl SSL handlers into the sockbuf. */
493 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
494 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
495 li->recv = conn->recv[FIRSTSOCKET];
496 li->send = conn->send[FIRSTSOCKET];
497 }
498 }
499
500 return result;
501}
502
503/* Send the STARTTLS request */
504static CURLcode oldap_perform_starttls(struct Curl_easy *data)
505{
506 CURLcode result = CURLE_OK;
507 struct ldapconninfo *li = data->conn->proto.ldapc;
508 int rc = ldap_start_tls(li->ld, NULL, NULL, &li->msgid);
509
510 if(rc == LDAP_SUCCESS)
511 oldap_state(data, OLDAP_STARTTLS);
512 else
513 result = oldap_map_error(rc, CURLE_USE_SSL_FAILED);
514 return result;
515}
516#endif
517
518static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
519{
520 struct connectdata *conn = data->conn;
521 struct ldapconninfo *li;
522 static const int version = LDAP_VERSION3;
523 int rc;
524 char *hosturl;
525#ifdef CURL_OPENLDAP_DEBUG
526 static int do_trace = -1;
527#endif
528
529 (void)done;
530
531 DEBUGASSERT(!conn->proto.ldapc);
532 li = calloc(1, sizeof(struct ldapconninfo));
533 if(!li)
534 return CURLE_OUT_OF_MEMORY;
535 else {
536 CURLcode result;
537 li->proto = ldap_pvt_url_scheme2proto(data->state.up.scheme);
538 conn->proto.ldapc = li;
539
540 /* Initialize the SASL storage */
541 Curl_sasl_init(&li->sasl, data, &saslldap);
542
543 /* Clear the TLS upgraded flag */
544 conn->bits.tls_upgraded = FALSE;
545
546 result = oldap_parse_login_options(conn);
547 if(result)
548 return result;
549 }
550
551 hosturl = aprintf("ldap%s://%s:%d",
552 conn->handler->flags & PROTOPT_SSL? "s": "",
553 conn->host.name, conn->remote_port);
554 if(!hosturl)
555 return CURLE_OUT_OF_MEMORY;
556
557 rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
558 if(rc) {
559 failf(data, "LDAP local: Cannot connect to %s, %s",
560 hosturl, ldap_err2string(rc));
561 free(hosturl);
562 return CURLE_COULDNT_CONNECT;
563 }
564
565 free(hosturl);
566
567#ifdef CURL_OPENLDAP_DEBUG
568 if(do_trace < 0) {
569 const char *env = getenv("CURL_OPENLDAP_TRACE");
570 do_trace = (env && strtol(env, NULL, 10) > 0);
571 }
572 if(do_trace)
573 ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
574#endif
575
576 /* Try version 3 first. */
577 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
578
579 /* Do not chase referrals. */
580 ldap_set_option(li->ld, LDAP_OPT_REFERRALS, LDAP_OPT_OFF);
581
582#ifdef USE_SSL
583 if(conn->handler->flags & PROTOPT_SSL)
584 return oldap_ssl_connect(data, OLDAP_SSL);
585
586 if(data->set.use_ssl) {
587 CURLcode result = oldap_perform_starttls(data);
588
589 if(!result || data->set.use_ssl != CURLUSESSL_TRY)
590 return result;
591 }
592#endif
593
594 if(li->sasl.prefmech != SASL_AUTH_NONE)
595 return oldap_perform_mechs(data);
596
597 /* Force bind even if anonymous bind is not needed in protocol version 3
598 to detect missing version 3 support. */
599 return oldap_perform_bind(data, OLDAP_BIND);
600}
601
602/* Handle the supported SASL mechanisms query response */
603static CURLcode oldap_state_mechs_resp(struct Curl_easy *data,
604 LDAPMessage *msg, int code)
605{
606 struct connectdata *conn = data->conn;
607 struct ldapconninfo *li = conn->proto.ldapc;
608 int rc;
609 BerElement *ber = NULL;
610 CURLcode result = CURLE_OK;
611 struct berval bv, *bvals;
612
613 switch(ldap_msgtype(msg)) {
614 case LDAP_RES_SEARCH_ENTRY:
615 /* Got a list of supported SASL mechanisms. */
616 if(code != LDAP_SUCCESS && code != LDAP_NO_RESULTS_RETURNED)
617 return CURLE_LOGIN_DENIED;
618
619 rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
620 if(rc < 0)
621 return oldap_map_error(rc, CURLE_BAD_CONTENT_ENCODING);
622 for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
623 rc == LDAP_SUCCESS;
624 rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
625 int i;
626
627 if(!bv.bv_val)
628 break;
629
630 if(bvals) {
631 for(i = 0; bvals[i].bv_val; i++) {
632 size_t llen;
633 unsigned short mech = Curl_sasl_decode_mech((char *) bvals[i].bv_val,
634 bvals[i].bv_len, &llen);
635 if(bvals[i].bv_len == llen)
636 li->sasl.authmechs |= mech;
637 }
638 ber_memfree(bvals);
639 }
640 }
641 ber_free(ber, 0);
642 break;
643
644 case LDAP_RES_SEARCH_RESULT:
645 switch(code) {
646 case LDAP_SIZELIMIT_EXCEEDED:
647 infof(data, "Too many authentication mechanisms\n");
648 FALLTHROUGH();
649 case LDAP_SUCCESS:
650 case LDAP_NO_RESULTS_RETURNED:
651 if(Curl_sasl_can_authenticate(&li->sasl, data))
652 result = oldap_perform_sasl(data);
653 else
654 result = CURLE_LOGIN_DENIED;
655 break;
656 default:
657 result = oldap_map_error(code, CURLE_LOGIN_DENIED);
658 break;
659 }
660 break;
661 default:
662 break;
663 }
664 return result;
665}
666
667/* Handle a SASL bind response. */
668static CURLcode oldap_state_sasl_resp(struct Curl_easy *data,
669 LDAPMessage *msg, int code)
670{
671 struct connectdata *conn = data->conn;
672 struct ldapconninfo *li = conn->proto.ldapc;
673 CURLcode result = CURLE_OK;
674 saslprogress progress;
675 int rc;
676
677 li->servercred = NULL;
678 rc = ldap_parse_sasl_bind_result(li->ld, msg, &li->servercred, 0);
679 if(rc != LDAP_SUCCESS) {
680 failf(data, "LDAP local: sasl ldap_parse_result %s", ldap_err2string(rc));
681 result = oldap_map_error(rc, CURLE_LOGIN_DENIED);
682 }
683 else {
684 result = Curl_sasl_continue(&li->sasl, data, code, &progress);
685 if(!result && progress != SASL_INPROGRESS)
686 oldap_state(data, OLDAP_STOP);
687 }
688
689 if(li->servercred)
690 ber_bvfree(li->servercred);
691 return result;
692}
693
694/* Handle a simple bind response. */
695static CURLcode oldap_state_bind_resp(struct Curl_easy *data, LDAPMessage *msg,
696 int code)
697{
698 struct connectdata *conn = data->conn;
699 struct ldapconninfo *li = conn->proto.ldapc;
700 CURLcode result = CURLE_OK;
701 struct berval *bv = NULL;
702 int rc;
703
704 if(code != LDAP_SUCCESS)
705 return oldap_map_error(code, CURLE_LDAP_CANNOT_BIND);
706
707 rc = ldap_parse_sasl_bind_result(li->ld, msg, &bv, 0);
708 if(rc != LDAP_SUCCESS) {
709 failf(data, "LDAP local: bind ldap_parse_sasl_bind_result %s",
710 ldap_err2string(rc));
711 result = oldap_map_error(rc, CURLE_LDAP_CANNOT_BIND);
712 }
713 else
714 oldap_state(data, OLDAP_STOP);
715
716 if(bv)
717 ber_bvfree(bv);
718 return result;
719}
720
721static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
722{
723 CURLcode result = CURLE_OK;
724 struct connectdata *conn = data->conn;
725 struct ldapconninfo *li = conn->proto.ldapc;
726 LDAPMessage *msg = NULL;
727 struct timeval tv = {0, 0};
728 int code = LDAP_SUCCESS;
729 int rc;
730
731 if(li->state != OLDAP_SSL && li->state != OLDAP_TLS) {
732 /* Get response to last command. */
733 rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, &tv, &msg);
734 switch(rc) {
735 case 0: /* Timed out. */
736 return CURLE_OK;
737 case LDAP_RES_SEARCH_ENTRY:
738 case LDAP_RES_SEARCH_REFERENCE:
739 break;
740 default:
741 li->msgid = 0; /* Nothing to abandon upon error. */
742 if(rc < 0) {
743 failf(data, "LDAP local: connecting ldap_result %s",
744 ldap_err2string(rc));
745 return oldap_map_error(rc, CURLE_COULDNT_CONNECT);
746 }
747 break;
748 }
749
750 /* Get error code from message. */
751 rc = ldap_parse_result(li->ld, msg, &code, NULL, NULL, NULL, NULL, 0);
752 if(rc)
753 code = rc;
754 else {
755 /* store the latest code for later retrieval */
756 data->info.httpcode = code;
757 }
758
759 /* If protocol version 3 is not supported, fallback to version 2. */
760 if(code == LDAP_PROTOCOL_ERROR && li->state != OLDAP_BINDV2 &&
761#ifdef USE_SSL
762 (ssl_installed(conn) || data->set.use_ssl <= CURLUSESSL_TRY) &&
763#endif
764 li->sasl.prefmech == SASL_AUTH_NONE) {
765 static const int version = LDAP_VERSION2;
766
767 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &version);
768 ldap_msgfree(msg);
769 return oldap_perform_bind(data, OLDAP_BINDV2);
770 }
771 }
772
773 /* Handle response message according to current state. */
774 switch(li->state) {
775
776#ifdef USE_SSL
777 case OLDAP_SSL:
778 result = oldap_ssl_connect(data, OLDAP_SSL);
779 if(!result && ssl_installed(conn)) {
780 if(li->sasl.prefmech != SASL_AUTH_NONE)
781 result = oldap_perform_mechs(data);
782 else
783 result = oldap_perform_bind(data, OLDAP_BIND);
784 }
785 break;
786 case OLDAP_STARTTLS:
787 if(code != LDAP_SUCCESS) {
788 if(data->set.use_ssl != CURLUSESSL_TRY)
789 result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
790 else if(li->sasl.prefmech != SASL_AUTH_NONE)
791 result = oldap_perform_mechs(data);
792 else
793 result = oldap_perform_bind(data, OLDAP_BIND);
794 break;
795 }
796 result = Curl_ssl_cfilter_add(data, conn, FIRSTSOCKET);
797 if(result)
798 break;
799 FALLTHROUGH();
800 case OLDAP_TLS:
801 result = oldap_ssl_connect(data, OLDAP_TLS);
802 if(result)
803 result = oldap_map_error(code, CURLE_USE_SSL_FAILED);
804 else if(ssl_installed(conn)) {
805 conn->bits.tls_upgraded = TRUE;
806 if(li->sasl.prefmech != SASL_AUTH_NONE)
807 result = oldap_perform_mechs(data);
808 else if(data->state.aptr.user)
809 result = oldap_perform_bind(data, OLDAP_BIND);
810 else {
811 /* Version 3 supported: no bind required */
812 oldap_state(data, OLDAP_STOP);
813 result = CURLE_OK;
814 }
815 }
816 break;
817#endif
818
819 case OLDAP_MECHS:
820 result = oldap_state_mechs_resp(data, msg, code);
821 break;
822 case OLDAP_SASL:
823 result = oldap_state_sasl_resp(data, msg, code);
824 break;
825 case OLDAP_BIND:
826 case OLDAP_BINDV2:
827 result = oldap_state_bind_resp(data, msg, code);
828 break;
829 default:
830 /* internal error */
831 result = CURLE_COULDNT_CONNECT;
832 break;
833 }
834
835 ldap_msgfree(msg);
836
837 *done = li->state == OLDAP_STOP;
838 if(*done)
839 conn->recv[FIRSTSOCKET] = oldap_recv;
840
841 if(result && li->msgid) {
842 ldap_abandon_ext(li->ld, li->msgid, NULL, NULL);
843 li->msgid = 0;
844 }
845 return result;
846}
847
848static CURLcode oldap_disconnect(struct Curl_easy *data,
849 struct connectdata *conn,
850 bool dead_connection)
851{
852 struct ldapconninfo *li = conn->proto.ldapc;
853 (void) dead_connection;
854#ifndef USE_SSL
855 (void)data;
856#endif
857
858 if(li) {
859 if(li->ld) {
860#ifdef USE_SSL
861 if(ssl_installed(conn)) {
862 Sockbuf *sb;
863 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
864 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
865 }
866#endif
867 ldap_unbind_ext(li->ld, NULL, NULL);
868 li->ld = NULL;
869 }
870 Curl_sasl_cleanup(conn, li->sasl.authused);
871 conn->proto.ldapc = NULL;
872 free(li);
873 }
874 return CURLE_OK;
875}
876
877static CURLcode oldap_do(struct Curl_easy *data, bool *done)
878{
879 struct connectdata *conn = data->conn;
880 struct ldapconninfo *li = conn->proto.ldapc;
881 struct ldapreqinfo *lr;
882 CURLcode result;
883 int rc;
884 LDAPURLDesc *lud;
885 int msgid;
886
887 connkeep(conn, "OpenLDAP do");
888
889 infof(data, "LDAP local: %s", data->state.url);
890
891 result = oldap_url_parse(data, &lud);
892 if(!result) {
893#ifdef USE_SSL
894 if(ssl_installed(conn)) {
895 Sockbuf *sb;
896 /* re-install the libcurl SSL handlers into the sockbuf. */
897 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
898 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
899 }
900#endif
901
902 rc = ldap_search_ext(li->ld, lud->lud_dn, lud->lud_scope,
903 lud->lud_filter, lud->lud_attrs, 0,
904 NULL, NULL, NULL, 0, &msgid);
905 ldap_free_urldesc(lud);
906 if(rc != LDAP_SUCCESS) {
907 failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
908 result = CURLE_LDAP_SEARCH_FAILED;
909 }
910 else {
911 lr = calloc(1, sizeof(struct ldapreqinfo));
912 if(!lr) {
913 ldap_abandon_ext(li->ld, msgid, NULL, NULL);
914 result = CURLE_OUT_OF_MEMORY;
915 }
916 else {
917 lr->msgid = msgid;
918 data->req.p.ldap = lr;
919 Curl_xfer_setup(data, FIRSTSOCKET, -1, FALSE, -1);
920 *done = TRUE;
921 }
922 }
923 }
924 return result;
925}
926
927static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
928 bool premature)
929{
930 struct connectdata *conn = data->conn;
931 struct ldapreqinfo *lr = data->req.p.ldap;
932
933 (void)res;
934 (void)premature;
935
936 if(lr) {
937 /* if there was a search in progress, abandon it */
938 if(lr->msgid) {
939 struct ldapconninfo *li = conn->proto.ldapc;
940 ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
941 lr->msgid = 0;
942 }
943 data->req.p.ldap = NULL;
944 free(lr);
945 }
946
947 return CURLE_OK;
948}
949
950static CURLcode client_write(struct Curl_easy *data,
951 const char *prefix, size_t plen,
952 const char *value, size_t len,
953 const char *suffix, size_t slen)
954{
955 CURLcode result = CURLE_OK;
956
957 if(prefix) {
958 /* If we have a zero-length value and the prefix ends with a space
959 separator, drop the latter. */
960 if(!len && plen && prefix[plen - 1] == ' ')
961 plen--;
962 result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) prefix, plen);
963 }
964 if(!result && value) {
965 result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) value, len);
966 }
967 if(!result && suffix) {
968 result = Curl_client_write(data, CLIENTWRITE_BODY, (char *) suffix, slen);
969 }
970 return result;
971}
972
973static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
974 size_t len, CURLcode *err)
975{
976 struct connectdata *conn = data->conn;
977 struct ldapconninfo *li = conn->proto.ldapc;
978 struct ldapreqinfo *lr = data->req.p.ldap;
979 int rc;
980 LDAPMessage *msg = NULL;
981 BerElement *ber = NULL;
982 struct timeval tv = {0, 0};
983 struct berval bv, *bvals;
984 int binary = 0;
985 CURLcode result = CURLE_AGAIN;
986 int code;
987 char *info = NULL;
988
989 (void)len;
990 (void)buf;
991 (void)sockindex;
992
993 rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_ONE, &tv, &msg);
994 if(rc < 0) {
995 failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
996 result = CURLE_RECV_ERROR;
997 }
998
999 *err = result;
1000
1001 /* error or timed out */
1002 if(!msg)
1003 return -1;
1004
1005 result = CURLE_OK;
1006
1007 switch(ldap_msgtype(msg)) {
1008 case LDAP_RES_SEARCH_RESULT:
1009 lr->msgid = 0;
1010 rc = ldap_parse_result(li->ld, msg, &code, NULL, &info, NULL, NULL, 0);
1011 if(rc) {
1012 failf(data, "LDAP local: search ldap_parse_result %s",
1013 ldap_err2string(rc));
1014 result = CURLE_LDAP_SEARCH_FAILED;
1015 break;
1016 }
1017
1018 /* store the latest code for later retrieval */
1019 data->info.httpcode = code;
1020
1021 switch(code) {
1022 case LDAP_SIZELIMIT_EXCEEDED:
1023 infof(data, "There are more than %d entries", lr->nument);
1024 FALLTHROUGH();
1025 case LDAP_SUCCESS:
1026 data->req.size = data->req.bytecount;
1027 break;
1028 default:
1029 failf(data, "LDAP remote: search failed %s %s", ldap_err2string(code),
1030 info ? info : "");
1031 result = CURLE_LDAP_SEARCH_FAILED;
1032 break;
1033 }
1034 if(info)
1035 ldap_memfree(info);
1036 break;
1037 case LDAP_RES_SEARCH_ENTRY:
1038 lr->nument++;
1039 rc = ldap_get_dn_ber(li->ld, msg, &ber, &bv);
1040 if(rc < 0) {
1041 result = CURLE_RECV_ERROR;
1042 break;
1043 }
1044
1045 result = client_write(data, STRCONST("DN: "), bv.bv_val, bv.bv_len,
1046 STRCONST("\n"));
1047 if(result)
1048 break;
1049
1050 for(rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals);
1051 rc == LDAP_SUCCESS;
1052 rc = ldap_get_attribute_ber(li->ld, msg, ber, &bv, &bvals)) {
1053 int i;
1054
1055 if(!bv.bv_val)
1056 break;
1057
1058 if(!bvals) {
1059 result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
1060 STRCONST(":\n"));
1061 if(result)
1062 break;
1063 continue;
1064 }
1065
1066 binary = bv.bv_len > 7 &&
1067 !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7);
1068
1069 for(i = 0; bvals[i].bv_val != NULL; i++) {
1070 int binval = 0;
1071
1072 result = client_write(data, STRCONST("\t"), bv.bv_val, bv.bv_len,
1073 STRCONST(":"));
1074 if(result)
1075 break;
1076
1077 if(!binary) {
1078 /* check for leading or trailing whitespace */
1079 if(ISBLANK(bvals[i].bv_val[0]) ||
1080 ISBLANK(bvals[i].bv_val[bvals[i].bv_len - 1]))
1081 binval = 1;
1082 else {
1083 /* check for unprintable characters */
1084 unsigned int j;
1085 for(j = 0; j < bvals[i].bv_len; j++)
1086 if(!ISPRINT(bvals[i].bv_val[j])) {
1087 binval = 1;
1088 break;
1089 }
1090 }
1091 }
1092 if(binary || binval) {
1093 char *val_b64 = NULL;
1094 size_t val_b64_sz = 0;
1095
1096 /* Binary value, encode to base64. */
1097 if(bvals[i].bv_len)
1098 result = Curl_base64_encode(bvals[i].bv_val, bvals[i].bv_len,
1099 &val_b64, &val_b64_sz);
1100 if(!result)
1101 result = client_write(data, STRCONST(": "), val_b64, val_b64_sz,
1102 STRCONST("\n"));
1103 free(val_b64);
1104 }
1105 else
1106 result = client_write(data, STRCONST(" "),
1107 bvals[i].bv_val, bvals[i].bv_len,
1108 STRCONST("\n"));
1109 if(result)
1110 break;
1111 }
1112
1113 ber_memfree(bvals);
1114 bvals = NULL;
1115 if(!result)
1116 result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
1117 if(result)
1118 break;
1119 }
1120
1121 ber_free(ber, 0);
1122
1123 if(!result)
1124 result = client_write(data, STRCONST("\n"), NULL, 0, NULL, 0);
1125 if(!result)
1126 result = CURLE_AGAIN;
1127 break;
1128 }
1129
1130 ldap_msgfree(msg);
1131 *err = result;
1132 return result? -1: 0;
1133}
1134
1135#ifdef USE_SSL
1136static int
1137ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
1138{
1139 sbiod->sbiod_pvt = arg;
1140 return 0;
1141}
1142
1143static int
1144ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
1145{
1146 sbiod->sbiod_pvt = NULL;
1147 return 0;
1148}
1149
1150/* We don't need to do anything because libcurl does it already */
1151static int
1152ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
1153{
1154 (void)sbiod;
1155 return 0;
1156}
1157
1158static int
1159ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
1160{
1161 (void)arg;
1162 if(opt == LBER_SB_OPT_DATA_READY) {
1163 struct Curl_easy *data = sbiod->sbiod_pvt;
1164 return Curl_conn_data_pending(data, FIRSTSOCKET);
1165 }
1166 return 0;
1167}
1168
1169static ber_slen_t
1170ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1171{
1172 struct Curl_easy *data = sbiod->sbiod_pvt;
1173 ber_slen_t ret = 0;
1174 if(data) {
1175 struct connectdata *conn = data->conn;
1176 if(conn) {
1177 struct ldapconninfo *li = conn->proto.ldapc;
1178 CURLcode err = CURLE_RECV_ERROR;
1179
1180 ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
1181 if(ret < 0 && err == CURLE_AGAIN) {
1182 SET_SOCKERRNO(EWOULDBLOCK);
1183 }
1184 }
1185 }
1186 return ret;
1187}
1188
1189static ber_slen_t
1190ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
1191{
1192 struct Curl_easy *data = sbiod->sbiod_pvt;
1193 ber_slen_t ret = 0;
1194 if(data) {
1195 struct connectdata *conn = data->conn;
1196 if(conn) {
1197 struct ldapconninfo *li = conn->proto.ldapc;
1198 CURLcode err = CURLE_SEND_ERROR;
1199 ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
1200 if(ret < 0 && err == CURLE_AGAIN) {
1201 SET_SOCKERRNO(EWOULDBLOCK);
1202 }
1203 }
1204 }
1205 return ret;
1206}
1207
1208static Sockbuf_IO ldapsb_tls =
1209{
1210 ldapsb_tls_setup,
1211 ldapsb_tls_remove,
1212 ldapsb_tls_ctrl,
1213 ldapsb_tls_read,
1214 ldapsb_tls_write,
1215 ldapsb_tls_close
1216};
1217#endif /* USE_SSL */
1218
1219#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

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