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