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