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