source: UsbWattMeter/trunk/curl-7.47.1/lib/openldap.c@ 167

Last change on this file since 167 was 167, checked in by coas-nagasima, 8 years ago

MIMEにSJISを設定

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