Imported Upstream version 7.59.0
[platform/upstream/curl.git] / lib / openldap.c
1 /***************************************************************************
2  *                      _   _ ____  _
3  *  Project         ___| | | |  _ \| |
4  *                 / __| | | | |_) | |
5  *                | (__| |_| |  _ <| |___
6  *                 \___|\___/|_| \_\_____|
7  *
8  * Copyright (C) 2010, Howard Chu, <hyc@openldap.org>
9  * Copyright (C) 2011 - 2018, 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
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
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   snprintf(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
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
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
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(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
418   *done = TRUE;
419   return CURLE_OK;
420 }
421
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
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) && bvals;
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       for(i = 0; bvals[i].bv_val != NULL; i++) {
552         int binval = 0;
553         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
554         if(writeerr) {
555           *err = writeerr;
556           return -1;
557         }
558
559         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
560                                      bv.bv_len);
561         if(writeerr) {
562           *err = writeerr;
563           return -1;
564         }
565
566         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
567         if(writeerr) {
568           *err = writeerr;
569           return -1;
570         }
571         data->req.bytecount += bv.bv_len + 2;
572
573         if(!binary) {
574           /* check for leading or trailing whitespace */
575           if(ISSPACE(bvals[i].bv_val[0]) ||
576              ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
577             binval = 1;
578           else {
579             /* check for unprintable characters */
580             unsigned int j;
581             for(j = 0; j<bvals[i].bv_len; j++)
582               if(!ISPRINT(bvals[i].bv_val[j])) {
583                 binval = 1;
584                 break;
585               }
586           }
587         }
588         if(binary || binval) {
589           char *val_b64 = NULL;
590           size_t val_b64_sz = 0;
591           /* Binary value, encode to base64. */
592           CURLcode error = Curl_base64_encode(data,
593                                               bvals[i].bv_val,
594                                               bvals[i].bv_len,
595                                               &val_b64,
596                                               &val_b64_sz);
597           if(error) {
598             ber_memfree(bvals);
599             ber_free(ber, 0);
600             ldap_msgfree(msg);
601             *err = error;
602             return -1;
603           }
604           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
605                                        (char *)": ", 2);
606           if(writeerr) {
607             *err = writeerr;
608             return -1;
609           }
610
611           data->req.bytecount += 2;
612           if(val_b64_sz > 0) {
613             writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
614                                          val_b64_sz);
615             if(writeerr) {
616               *err = writeerr;
617               return -1;
618             }
619             free(val_b64);
620             data->req.bytecount += val_b64_sz;
621           }
622         }
623         else {
624           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
625           if(writeerr) {
626             *err = writeerr;
627             return -1;
628           }
629
630           writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
631                                        bvals[i].bv_len);
632           if(writeerr) {
633             *err = writeerr;
634             return -1;
635           }
636
637           data->req.bytecount += bvals[i].bv_len + 1;
638         }
639         writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
640         if(writeerr) {
641           *err = writeerr;
642           return -1;
643         }
644
645         data->req.bytecount++;
646       }
647       ber_memfree(bvals);
648       writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
649       if(writeerr) {
650         *err = writeerr;
651         return -1;
652       }
653       data->req.bytecount++;
654     }
655     writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
656     if(writeerr) {
657       *err = writeerr;
658       return -1;
659     }
660     data->req.bytecount++;
661     ber_free(ber, 0);
662   }
663   ldap_msgfree(msg);
664   return ret;
665 }
666
667 #ifdef USE_SSL
668 static int
669 ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
670 {
671   sbiod->sbiod_pvt = arg;
672   return 0;
673 }
674
675 static int
676 ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
677 {
678   sbiod->sbiod_pvt = NULL;
679   return 0;
680 }
681
682 /* We don't need to do anything because libcurl does it already */
683 static int
684 ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
685 {
686   (void)sbiod;
687   return 0;
688 }
689
690 static int
691 ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
692 {
693   (void)arg;
694   if(opt == LBER_SB_OPT_DATA_READY) {
695     struct connectdata *conn = sbiod->sbiod_pvt;
696     return Curl_ssl_data_pending(conn, FIRSTSOCKET);
697   }
698   return 0;
699 }
700
701 static ber_slen_t
702 ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
703 {
704   struct connectdata *conn = sbiod->sbiod_pvt;
705   ldapconninfo *li = conn->proto.generic;
706   ber_slen_t ret;
707   CURLcode err = CURLE_RECV_ERROR;
708
709   ret = (li->recv)(conn, FIRSTSOCKET, buf, len, &err);
710   if(ret < 0 && err == CURLE_AGAIN) {
711     SET_SOCKERRNO(EWOULDBLOCK);
712   }
713   return ret;
714 }
715
716 static ber_slen_t
717 ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
718 {
719   struct connectdata *conn = sbiod->sbiod_pvt;
720   ldapconninfo *li = conn->proto.generic;
721   ber_slen_t ret;
722   CURLcode err = CURLE_SEND_ERROR;
723
724   ret = (li->send)(conn, FIRSTSOCKET, buf, len, &err);
725   if(ret < 0 && err == CURLE_AGAIN) {
726     SET_SOCKERRNO(EWOULDBLOCK);
727   }
728   return ret;
729 }
730
731 static Sockbuf_IO ldapsb_tls =
732 {
733   ldapsb_tls_setup,
734   ldapsb_tls_remove,
735   ldapsb_tls_ctrl,
736   ldapsb_tls_read,
737   ldapsb_tls_write,
738   ldapsb_tls_close
739 };
740 #endif /* USE_SSL */
741
742 #endif /* !CURL_DISABLE_LDAP && USE_OPENLDAP */