1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 2011 - 2021, Daniel Stenberg, <daniel@haxx.se>, et al.
9 * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
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 ***************************************************************************/
23
24#include "curl_setup.h"
25
26#if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
27
28/*
29 * Notice that USE_OPENLDAP is only a source code selection switch. When
30 * libcurl is built with USE_OPENLDAP defined the libcurl source code that
31 * gets compiled is the code from openldap.c, otherwise the code that gets
32 * compiled is the code from ldap.c.
33 *
34 * When USE_OPENLDAP is defined a recent version of the OpenLDAP library
35 * might be required for compilation and runtime. In order to use ancient
36 * OpenLDAP library versions, USE_OPENLDAP shall not be defined.
37 */
38
39#include <ldap.h>
40
41#include "urldata.h"
42#include <curl/curl.h>
43#include "sendf.h"
44#include "vtls/vtls.h"
45#include "transfer.h"
46#include "curl_ldap.h"
47#include "curl_base64.h"
48#include "connect.h"
49/* The last 3 #include files should be in this order */
50#include "curl_printf.h"
51#include "curl_memory.h"
52#include "memdebug.h"
53
54/*
55 * Uncommenting this will enable the built-in debug logging of the openldap
56 * library. The debug log level can be set using the CURL_OPENLDAP_TRACE
57 * environment variable. The debug output is written to stderr.
58 *
59 * The library supports the following debug flags:
60 * LDAP_DEBUG_NONE 0x0000
61 * LDAP_DEBUG_TRACE 0x0001
62 * LDAP_DEBUG_CONSTRUCT 0x0002
63 * LDAP_DEBUG_DESTROY 0x0004
64 * LDAP_DEBUG_PARAMETER 0x0008
65 * LDAP_DEBUG_ANY 0xffff
66 *
67 * For example, use CURL_OPENLDAP_TRACE=0 for no debug,
68 * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only,
69 * CURL_OPENLDAP_TRACE=65535 for all debug message levels.
70 */
71/* #define CURL_OPENLDAP_DEBUG */
72
73#ifndef _LDAP_PVT_H
74extern int ldap_pvt_url_scheme2proto(const char *);
75extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
76 LDAP **ld);
77#endif
78
79static CURLcode oldap_setup_connection(struct Curl_easy *data,
80 struct connectdata *conn);
81static CURLcode oldap_do(struct Curl_easy *data, bool *done);
82static CURLcode oldap_done(struct Curl_easy *data, CURLcode, bool);
83static CURLcode oldap_connect(struct Curl_easy *data, bool *done);
84static CURLcode oldap_connecting(struct Curl_easy *data, bool *done);
85static CURLcode oldap_disconnect(struct Curl_easy *data,
86 struct connectdata *conn, bool dead);
87
88static Curl_recv oldap_recv;
89
90/*
91 * LDAP protocol handler.
92 */
93
94const struct Curl_handler Curl_handler_ldap = {
95 "LDAP", /* scheme */
96 oldap_setup_connection, /* setup_connection */
97 oldap_do, /* do_it */
98 oldap_done, /* done */
99 ZERO_NULL, /* do_more */
100 oldap_connect, /* connect_it */
101 oldap_connecting, /* connecting */
102 ZERO_NULL, /* doing */
103 ZERO_NULL, /* proto_getsock */
104 ZERO_NULL, /* doing_getsock */
105 ZERO_NULL, /* domore_getsock */
106 ZERO_NULL, /* perform_getsock */
107 oldap_disconnect, /* disconnect */
108 ZERO_NULL, /* readwrite */
109 ZERO_NULL, /* connection_check */
110 ZERO_NULL, /* attach connection */
111 PORT_LDAP, /* defport */
112 CURLPROTO_LDAP, /* protocol */
113 CURLPROTO_LDAP, /* family */
114 PROTOPT_NONE /* flags */
115};
116
117#ifdef USE_SSL
118/*
119 * LDAPS protocol handler.
120 */
121
122const struct Curl_handler Curl_handler_ldaps = {
123 "LDAPS", /* scheme */
124 oldap_setup_connection, /* setup_connection */
125 oldap_do, /* do_it */
126 oldap_done, /* done */
127 ZERO_NULL, /* do_more */
128 oldap_connect, /* connect_it */
129 oldap_connecting, /* connecting */
130 ZERO_NULL, /* doing */
131 ZERO_NULL, /* proto_getsock */
132 ZERO_NULL, /* doing_getsock */
133 ZERO_NULL, /* domore_getsock */
134 ZERO_NULL, /* perform_getsock */
135 oldap_disconnect, /* disconnect */
136 ZERO_NULL, /* readwrite */
137 ZERO_NULL, /* connection_check */
138 ZERO_NULL, /* attach connection */
139 PORT_LDAPS, /* defport */
140 CURLPROTO_LDAPS, /* protocol */
141 CURLPROTO_LDAP, /* family */
142 PROTOPT_SSL /* flags */
143};
144#endif
145
146static const char *url_errs[] = {
147 "success",
148 "out of memory",
149 "bad parameter",
150 "unrecognized scheme",
151 "unbalanced delimiter",
152 "bad URL",
153 "bad host or port",
154 "bad or missing attributes",
155 "bad or missing scope",
156 "bad or missing filter",
157 "bad or missing extensions"
158};
159
160struct ldapconninfo {
161 LDAP *ld;
162 Curl_recv *recv; /* for stacking SSL handler */
163 Curl_send *send;
164 int proto;
165 int msgid;
166 bool ssldone;
167 bool sslinst;
168 bool didbind;
169};
170
171struct ldapreqinfo {
172 int msgid;
173 int nument;
174};
175
176static CURLcode oldap_setup_connection(struct Curl_easy *data,
177 struct connectdata *conn)
178{
179 struct ldapconninfo *li;
180 LDAPURLDesc *lud;
181 int rc, proto;
182 CURLcode status;
183
184 rc = ldap_url_parse(data->state.url, &lud);
185 if(rc != LDAP_URL_SUCCESS) {
186 const char *msg = "url parsing problem";
187 status = CURLE_URL_MALFORMAT;
188 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
189 if(rc == LDAP_URL_ERR_MEM)
190 status = CURLE_OUT_OF_MEMORY;
191 msg = url_errs[rc];
192 }
193 failf(data, "LDAP local: %s", msg);
194 return status;
195 }
196 proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
197 ldap_free_urldesc(lud);
198
199 li = calloc(1, sizeof(struct ldapconninfo));
200 if(!li)
201 return CURLE_OUT_OF_MEMORY;
202 li->proto = proto;
203 conn->proto.ldapc = li;
204 connkeep(conn, "OpenLDAP default");
205 return CURLE_OK;
206}
207
208#ifdef USE_SSL
209static Sockbuf_IO ldapsb_tls;
210#endif
211
212static CURLcode oldap_connect(struct Curl_easy *data, bool *done)
213{
214 struct connectdata *conn = data->conn;
215 struct ldapconninfo *li = conn->proto.ldapc;
216 int rc, proto = LDAP_VERSION3;
217 char hosturl[1024];
218 char *ptr;
219
220 (void)done;
221
222 strcpy(hosturl, "ldap");
223 ptr = hosturl + 4;
224 if(conn->handler->flags & PROTOPT_SSL)
225 *ptr++ = 's';
226 msnprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
227 conn->host.name, conn->remote_port);
228
229#ifdef CURL_OPENLDAP_DEBUG
230 static int do_trace = 0;
231 const char *env = getenv("CURL_OPENLDAP_TRACE");
232 do_trace = (env && strtol(env, NULL, 10) > 0);
233 if(do_trace) {
234 ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace);
235 }
236#endif
237
238 rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
239 if(rc) {
240 failf(data, "LDAP local: Cannot connect to %s, %s",
241 hosturl, ldap_err2string(rc));
242 return CURLE_COULDNT_CONNECT;
243 }
244
245 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
246
247#ifdef USE_SSL
248 if(conn->handler->flags & PROTOPT_SSL) {
249 CURLcode result;
250 result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
251 FIRSTSOCKET, &li->ssldone);
252 if(result)
253 return result;
254 }
255#endif
256
257 return CURLE_OK;
258}
259
260static CURLcode oldap_connecting(struct Curl_easy *data, bool *done)
261{
262 struct connectdata *conn = data->conn;
263 struct ldapconninfo *li = conn->proto.ldapc;
264 LDAPMessage *msg = NULL;
265 struct timeval tv = {0, 1}, *tvp;
266 int rc, err;
267 char *info = NULL;
268
269#ifdef USE_SSL
270 if(conn->handler->flags & PROTOPT_SSL) {
271 /* Is the SSL handshake complete yet? */
272 if(!li->ssldone) {
273 CURLcode result = Curl_ssl_connect_nonblocking(data, conn, FALSE,
274 FIRSTSOCKET,
275 &li->ssldone);
276 if(result || !li->ssldone)
277 return result;
278 }
279
280 /* Have we installed the libcurl SSL handlers into the sockbuf yet? */
281 if(!li->sslinst) {
282 Sockbuf *sb;
283 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
284 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
285 li->sslinst = TRUE;
286 li->recv = conn->recv[FIRSTSOCKET];
287 li->send = conn->send[FIRSTSOCKET];
288 }
289 }
290#endif
291
292 tvp = &tv;
293
294 retry:
295 if(!li->didbind) {
296 char *binddn;
297 struct berval passwd;
298
299 if(conn->bits.user_passwd) {
300 binddn = conn->user;
301 passwd.bv_val = conn->passwd;
302 passwd.bv_len = strlen(passwd.bv_val);
303 }
304 else {
305 binddn = NULL;
306 passwd.bv_val = NULL;
307 passwd.bv_len = 0;
308 }
309 rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
310 NULL, NULL, &li->msgid);
311 if(rc)
312 return CURLE_LDAP_CANNOT_BIND;
313 li->didbind = TRUE;
314 if(tvp)
315 return CURLE_OK;
316 }
317
318 rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
319 if(rc < 0) {
320 failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
321 return CURLE_LDAP_CANNOT_BIND;
322 }
323 if(rc == 0) {
324 /* timed out */
325 return CURLE_OK;
326 }
327
328 rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
329 if(rc) {
330 failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
331 return CURLE_LDAP_CANNOT_BIND;
332 }
333
334 /* Try to fallback to LDAPv2? */
335 if(err == LDAP_PROTOCOL_ERROR) {
336 int proto;
337 ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
338 if(proto == LDAP_VERSION3) {
339 if(info) {
340 ldap_memfree(info);
341 info = NULL;
342 }
343 proto = LDAP_VERSION2;
344 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
345 li->didbind = FALSE;
346 goto retry;
347 }
348 }
349
350 if(err) {
351 failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
352 info ? info : "");
353 if(info)
354 ldap_memfree(info);
355 return CURLE_LOGIN_DENIED;
356 }
357
358 if(info)
359 ldap_memfree(info);
360 conn->recv[FIRSTSOCKET] = oldap_recv;
361 *done = TRUE;
362
363 return CURLE_OK;
364}
365
366static CURLcode oldap_disconnect(struct Curl_easy *data,
367 struct connectdata *conn,
368 bool dead_connection)
369{
370 struct ldapconninfo *li = conn->proto.ldapc;
371 (void) dead_connection;
372
373 if(li) {
374 if(li->ld) {
375#ifdef USE_SSL
376 if(conn->ssl[FIRSTSOCKET].use) {
377 Sockbuf *sb;
378 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
379 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, data);
380 }
381#endif
382 ldap_unbind_ext(li->ld, NULL, NULL);
383 li->ld = NULL;
384 }
385 conn->proto.ldapc = NULL;
386 free(li);
387 }
388 return CURLE_OK;
389}
390
391static CURLcode oldap_do(struct Curl_easy *data, bool *done)
392{
393 struct connectdata *conn = data->conn;
394 struct ldapconninfo *li = conn->proto.ldapc;
395 struct ldapreqinfo *lr;
396 CURLcode status = CURLE_OK;
397 int rc = 0;
398 LDAPURLDesc *ludp = NULL;
399 int msgid;
400
401 connkeep(conn, "OpenLDAP do");
402
403 infof(data, "LDAP local: %s", data->state.url);
404
405 rc = ldap_url_parse(data->state.url, &ludp);
406 if(rc != LDAP_URL_SUCCESS) {
407 const char *msg = "url parsing problem";
408 status = CURLE_URL_MALFORMAT;
409 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
410 if(rc == LDAP_URL_ERR_MEM)
411 status = CURLE_OUT_OF_MEMORY;
412 msg = url_errs[rc];
413 }
414 failf(data, "LDAP local: %s", msg);
415 return status;
416 }
417
418 rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
419 ludp->lud_filter, ludp->lud_attrs, 0,
420 NULL, NULL, NULL, 0, &msgid);
421 ldap_free_urldesc(ludp);
422 if(rc != LDAP_SUCCESS) {
423 failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
424 return CURLE_LDAP_SEARCH_FAILED;
425 }
426 lr = calloc(1, sizeof(struct ldapreqinfo));
427 if(!lr)
428 return CURLE_OUT_OF_MEMORY;
429 lr->msgid = msgid;
430 data->req.p.ldap = lr;
431 Curl_setup_transfer(data, FIRSTSOCKET, -1, FALSE, -1);
432 *done = TRUE;
433 return CURLE_OK;
434}
435
436static CURLcode oldap_done(struct Curl_easy *data, CURLcode res,
437 bool premature)
438{
439 struct connectdata *conn = data->conn;
440 struct ldapreqinfo *lr = data->req.p.ldap;
441
442 (void)res;
443 (void)premature;
444
445 if(lr) {
446 /* if there was a search in progress, abandon it */
447 if(lr->msgid) {
448 struct ldapconninfo *li = conn->proto.ldapc;
449 ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
450 lr->msgid = 0;
451 }
452 data->req.p.ldap = NULL;
453 free(lr);
454 }
455
456 return CURLE_OK;
457}
458
459static ssize_t oldap_recv(struct Curl_easy *data, int sockindex, char *buf,
460 size_t len, CURLcode *err)
461{
462 struct connectdata *conn = data->conn;
463 struct ldapconninfo *li = conn->proto.ldapc;
464 struct ldapreqinfo *lr = data->req.p.ldap;
465 int rc, ret;
466 LDAPMessage *msg = NULL;
467 LDAPMessage *ent;
468 BerElement *ber = NULL;
469 struct timeval tv = {0, 1};
470
471 (void)len;
472 (void)buf;
473 (void)sockindex;
474
475 rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
476 if(rc < 0) {
477 failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
478 *err = CURLE_RECV_ERROR;
479 return -1;
480 }
481
482 *err = CURLE_AGAIN;
483 ret = -1;
484
485 /* timed out */
486 if(!msg)
487 return ret;
488
489 for(ent = ldap_first_message(li->ld, msg); ent;
490 ent = ldap_next_message(li->ld, ent)) {
491 struct berval bv, *bvals;
492 int binary = 0, msgtype;
493 CURLcode writeerr;
494
495 msgtype = ldap_msgtype(ent);
496 if(msgtype == LDAP_RES_SEARCH_RESULT) {
497 int code;
498 char *info = NULL;
499 rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
500 if(rc) {
501 failf(data, "LDAP local: search ldap_parse_result %s",
502 ldap_err2string(rc));
503 *err = CURLE_LDAP_SEARCH_FAILED;
504 }
505 else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
506 failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
507 info ? info : "");
508 *err = CURLE_LDAP_SEARCH_FAILED;
509 }
510 else {
511 /* successful */
512 if(code == LDAP_SIZELIMIT_EXCEEDED)
513 infof(data, "There are more than %d entries", lr->nument);
514 data->req.size = data->req.bytecount;
515 *err = CURLE_OK;
516 ret = 0;
517 }
518 lr->msgid = 0;
519 ldap_memfree(info);
520 break;
521 }
522 else if(msgtype != LDAP_RES_SEARCH_ENTRY)
523 continue;
524
525 lr->nument++;
526 rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
527 if(rc < 0) {
528 *err = CURLE_RECV_ERROR;
529 return -1;
530 }
531 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"DN: ", 4);
532 if(writeerr) {
533 *err = writeerr;
534 return -1;
535 }
536
537 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
538 bv.bv_len);
539 if(writeerr) {
540 *err = writeerr;
541 return -1;
542 }
543
544 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
545 if(writeerr) {
546 *err = writeerr;
547 return -1;
548 }
549 data->req.bytecount += bv.bv_len + 5;
550
551 for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals);
552 rc == LDAP_SUCCESS;
553 rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, &bvals)) {
554 int i;
555
556 if(!bv.bv_val)
557 break;
558
559 if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
560 binary = 1;
561 else
562 binary = 0;
563
564 if(!bvals) {
565 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
566 if(writeerr) {
567 *err = writeerr;
568 return -1;
569 }
570 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
571 bv.bv_len);
572 if(writeerr) {
573 *err = writeerr;
574 return -1;
575 }
576 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":\n", 2);
577 if(writeerr) {
578 *err = writeerr;
579 return -1;
580 }
581 data->req.bytecount += bv.bv_len + 3;
582 continue;
583 }
584
585 for(i = 0; bvals[i].bv_val != NULL; i++) {
586 int binval = 0;
587 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\t", 1);
588 if(writeerr) {
589 *err = writeerr;
590 return -1;
591 }
592
593 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)bv.bv_val,
594 bv.bv_len);
595 if(writeerr) {
596 *err = writeerr;
597 return -1;
598 }
599
600 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)":", 1);
601 if(writeerr) {
602 *err = writeerr;
603 return -1;
604 }
605 data->req.bytecount += bv.bv_len + 2;
606
607 if(!binary) {
608 /* check for leading or trailing whitespace */
609 if(ISSPACE(bvals[i].bv_val[0]) ||
610 ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
611 binval = 1;
612 else {
613 /* check for unprintable characters */
614 unsigned int j;
615 for(j = 0; j<bvals[i].bv_len; j++)
616 if(!ISPRINT(bvals[i].bv_val[j])) {
617 binval = 1;
618 break;
619 }
620 }
621 }
622 if(binary || binval) {
623 char *val_b64 = NULL;
624 size_t val_b64_sz = 0;
625 /* Binary value, encode to base64. */
626 CURLcode error = Curl_base64_encode(data,
627 bvals[i].bv_val,
628 bvals[i].bv_len,
629 &val_b64,
630 &val_b64_sz);
631 if(error) {
632 ber_memfree(bvals);
633 ber_free(ber, 0);
634 ldap_msgfree(msg);
635 *err = error;
636 return -1;
637 }
638 writeerr = Curl_client_write(data, CLIENTWRITE_BODY,
639 (char *)": ", 2);
640 if(writeerr) {
641 *err = writeerr;
642 return -1;
643 }
644
645 data->req.bytecount += 2;
646 if(val_b64_sz > 0) {
647 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, val_b64,
648 val_b64_sz);
649 if(writeerr) {
650 *err = writeerr;
651 return -1;
652 }
653 free(val_b64);
654 data->req.bytecount += val_b64_sz;
655 }
656 }
657 else {
658 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)" ", 1);
659 if(writeerr) {
660 *err = writeerr;
661 return -1;
662 }
663
664 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, bvals[i].bv_val,
665 bvals[i].bv_len);
666 if(writeerr) {
667 *err = writeerr;
668 return -1;
669 }
670
671 data->req.bytecount += bvals[i].bv_len + 1;
672 }
673 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
674 if(writeerr) {
675 *err = writeerr;
676 return -1;
677 }
678
679 data->req.bytecount++;
680 }
681 ber_memfree(bvals);
682 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
683 if(writeerr) {
684 *err = writeerr;
685 return -1;
686 }
687 data->req.bytecount++;
688 }
689 writeerr = Curl_client_write(data, CLIENTWRITE_BODY, (char *)"\n", 1);
690 if(writeerr) {
691 *err = writeerr;
692 return -1;
693 }
694 data->req.bytecount++;
695 ber_free(ber, 0);
696 }
697 ldap_msgfree(msg);
698 return ret;
699}
700
701#ifdef USE_SSL
702static int
703ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
704{
705 sbiod->sbiod_pvt = arg;
706 return 0;
707}
708
709static int
710ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
711{
712 sbiod->sbiod_pvt = NULL;
713 return 0;
714}
715
716/* We don't need to do anything because libcurl does it already */
717static int
718ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
719{
720 (void)sbiod;
721 return 0;
722}
723
724static int
725ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
726{
727 (void)arg;
728 if(opt == LBER_SB_OPT_DATA_READY) {
729 struct Curl_easy *data = sbiod->sbiod_pvt;
730 return Curl_ssl_data_pending(data->conn, FIRSTSOCKET);
731 }
732 return 0;
733}
734
735static ber_slen_t
736ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
737{
738 struct Curl_easy *data = sbiod->sbiod_pvt;
739 ber_slen_t ret = 0;
740 if(data) {
741 struct connectdata *conn = data->conn;
742 if(conn) {
743 struct ldapconninfo *li = conn->proto.ldapc;
744 CURLcode err = CURLE_RECV_ERROR;
745
746 ret = (li->recv)(data, FIRSTSOCKET, buf, len, &err);
747 if(ret < 0 && err == CURLE_AGAIN) {
748 SET_SOCKERRNO(EWOULDBLOCK);
749 }
750 }
751 }
752 return ret;
753}
754
755static ber_slen_t
756ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
757{
758 struct Curl_easy *data = sbiod->sbiod_pvt;
759 ber_slen_t ret = 0;
760 if(data) {
761 struct connectdata *conn = data->conn;
762 if(conn) {
763 struct ldapconninfo *li = conn->proto.ldapc;
764 CURLcode err = CURLE_SEND_ERROR;
765 ret = (li->send)(data, FIRSTSOCKET, buf, len, &err);
766 if(ret < 0 && err == CURLE_AGAIN) {
767 SET_SOCKERRNO(EWOULDBLOCK);
768 }
769 }
770 }
771 return ret;
772}
773
774static Sockbuf_IO ldapsb_tls =
775{
776 ldapsb_tls_setup,
777 ldapsb_tls_remove,
778 ldapsb_tls_ctrl,
779 ldapsb_tls_read,
780 ldapsb_tls_write,
781 ldapsb_tls_close
782};
783#endif /* USE_SSL */
784
785#endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */
786