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