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