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