1 /*************************************************************************** 2 * _ _ ____ _ 3 * Project ___| | | | _ \| | 4 * / __| | | | |_) | | 5 * | (__| |_| | _ <| |___ 6 * \___|\___/|_| \_\_____| 7 * 8 * Copyright (C) 2010, 2017, Howard Chu, <hyc (at) openldap.org> 9 * Copyright (C) 2011 - 2016, Daniel Stenberg, <daniel (at) haxx.se>, et al. 10 * 11 * This software is licensed as described in the file COPYING, which 12 * you should have received as part of this distribution. The terms 13 * are also available at https://curl.haxx.se/docs/copyright.html. 14 * 15 * You may opt to use, copy, modify, merge, publish, distribute and/or sell 16 * copies of the Software, and permit persons to whom the Software is 17 * furnished to do so, under the terms of the COPYING file. 18 * 19 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY 20 * KIND, either express or implied. 21 * 22 ***************************************************************************/ 23 24 #include "curl_setup.h" 25 26 #if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP) 27 28 /* 29 * Notice that USE_OPENLDAP is only a source code selection switch. When 30 * libcurl is built with USE_OPENLDAP defined the libcurl source code that 31 * gets compiled is the code from openldap.c, otherwise the code that gets 32 * compiled is the code from ldap.c. 33 * 34 * When USE_OPENLDAP is defined a recent version of the OpenLDAP library 35 * might be required for compilation and runtime. In order to use ancient 36 * OpenLDAP library versions, USE_OPENLDAP shall not be defined. 37 */ 38 39 #include <ldap.h> 40 41 #include "urldata.h" 42 #include <curl/curl.h> 43 #include "sendf.h" 44 #include "vtls/vtls.h" 45 #include "transfer.h" 46 #include "curl_ldap.h" 47 #include "curl_base64.h" 48 #include "connect.h" 49 /* The last 3 #include files should be in this order */ 50 #include "curl_printf.h" 51 #include "curl_memory.h" 52 #include "memdebug.h" 53 54 /* 55 * Uncommenting this will enable the built-in debug logging of the openldap 56 * library. The debug log level can be set using the CURL_OPENLDAP_TRACE 57 * environment variable. The debug output is written to stderr. 58 * 59 * The library supports the following debug flags: 60 * LDAP_DEBUG_NONE 0x0000 61 * LDAP_DEBUG_TRACE 0x0001 62 * LDAP_DEBUG_CONSTRUCT 0x0002 63 * LDAP_DEBUG_DESTROY 0x0004 64 * LDAP_DEBUG_PARAMETER 0x0008 65 * LDAP_DEBUG_ANY 0xffff 66 * 67 * For example, use CURL_OPENLDAP_TRACE=0 for no debug, 68 * CURL_OPENLDAP_TRACE=2 for LDAP_DEBUG_CONSTRUCT messages only, 69 * CURL_OPENLDAP_TRACE=65535 for all debug message levels. 70 */ 71 /* #define CURL_OPENLDAP_DEBUG */ 72 73 #ifndef _LDAP_PVT_H 74 extern int ldap_pvt_url_scheme2proto(const char *); 75 extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url, 76 LDAP **ld); 77 #endif 78 79 static CURLcode ldap_setup_connection(struct connectdata *conn); 80 static CURLcode ldap_do(struct connectdata *conn, bool *done); 81 static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool); 82 static CURLcode ldap_connect(struct connectdata *conn, bool *done); 83 static CURLcode ldap_connecting(struct connectdata *conn, bool *done); 84 static CURLcode ldap_disconnect(struct connectdata *conn, bool dead); 85 86 static Curl_recv ldap_recv; 87 88 /* 89 * LDAP protocol handler. 90 */ 91 92 const struct Curl_handler Curl_handler_ldap = { 93 "LDAP", /* scheme */ 94 ldap_setup_connection, /* setup_connection */ 95 ldap_do, /* do_it */ 96 ldap_done, /* done */ 97 ZERO_NULL, /* do_more */ 98 ldap_connect, /* connect_it */ 99 ldap_connecting, /* connecting */ 100 ZERO_NULL, /* doing */ 101 ZERO_NULL, /* proto_getsock */ 102 ZERO_NULL, /* doing_getsock */ 103 ZERO_NULL, /* domore_getsock */ 104 ZERO_NULL, /* perform_getsock */ 105 ldap_disconnect, /* disconnect */ 106 ZERO_NULL, /* readwrite */ 107 ZERO_NULL, /* connection_check */ 108 PORT_LDAP, /* defport */ 109 CURLPROTO_LDAP, /* protocol */ 110 PROTOPT_NONE /* flags */ 111 }; 112 113 #ifdef USE_SSL 114 /* 115 * LDAPS protocol handler. 116 */ 117 118 const struct Curl_handler Curl_handler_ldaps = { 119 "LDAPS", /* scheme */ 120 ldap_setup_connection, /* setup_connection */ 121 ldap_do, /* do_it */ 122 ldap_done, /* done */ 123 ZERO_NULL, /* do_more */ 124 ldap_connect, /* connect_it */ 125 ldap_connecting, /* connecting */ 126 ZERO_NULL, /* doing */ 127 ZERO_NULL, /* proto_getsock */ 128 ZERO_NULL, /* doing_getsock */ 129 ZERO_NULL, /* domore_getsock */ 130 ZERO_NULL, /* perform_getsock */ 131 ldap_disconnect, /* disconnect */ 132 ZERO_NULL, /* readwrite */ 133 ZERO_NULL, /* connection_check */ 134 PORT_LDAPS, /* defport */ 135 CURLPROTO_LDAP, /* protocol */ 136 PROTOPT_SSL /* flags */ 137 }; 138 #endif 139 140 static const char *url_errs[] = { 141 "success", 142 "out of memory", 143 "bad parameter", 144 "unrecognized scheme", 145 "unbalanced delimiter", 146 "bad URL", 147 "bad host or port", 148 "bad or missing attributes", 149 "bad or missing scope", 150 "bad or missing filter", 151 "bad or missing extensions" 152 }; 153 154 typedef struct ldapconninfo { 155 LDAP *ld; 156 Curl_recv *recv; /* for stacking SSL handler */ 157 Curl_send *send; 158 int proto; 159 int msgid; 160 bool ssldone; 161 bool sslinst; 162 bool didbind; 163 } ldapconninfo; 164 165 typedef struct ldapreqinfo { 166 int msgid; 167 int nument; 168 } ldapreqinfo; 169 170 static CURLcode ldap_setup_connection(struct connectdata *conn) 171 { 172 ldapconninfo *li; 173 LDAPURLDesc *lud; 174 struct Curl_easy *data = conn->data; 175 int rc, proto; 176 CURLcode status; 177 178 rc = ldap_url_parse(data->change.url, &lud); 179 if(rc != LDAP_URL_SUCCESS) { 180 const char *msg = "url parsing problem"; 181 status = CURLE_URL_MALFORMAT; 182 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { 183 if(rc == LDAP_URL_ERR_MEM) 184 status = CURLE_OUT_OF_MEMORY; 185 msg = url_errs[rc]; 186 } 187 failf(conn->data, "LDAP local: %s", msg); 188 return status; 189 } 190 proto = ldap_pvt_url_scheme2proto(lud->lud_scheme); 191 ldap_free_urldesc(lud); 192 193 li = calloc(1, sizeof(ldapconninfo)); 194 if(!li) 195 return CURLE_OUT_OF_MEMORY; 196 li->proto = proto; 197 conn->proto.generic = li; 198 connkeep(conn, "OpenLDAP default"); 199 /* TODO: 200 * - provide option to choose SASL Binds instead of Simple 201 */ 202 return CURLE_OK; 203 } 204 205 #ifdef USE_SSL 206 static Sockbuf_IO ldapsb_tls; 207 #endif 208 209 static CURLcode ldap_connect(struct connectdata *conn, bool *done) 210 { 211 ldapconninfo *li = conn->proto.generic; 212 struct Curl_easy *data = conn->data; 213 int rc, proto = LDAP_VERSION3; 214 char hosturl[1024]; 215 char *ptr; 216 217 (void)done; 218 219 strcpy(hosturl, "ldap"); 220 ptr = hosturl + 4; 221 if(conn->handler->flags & PROTOPT_SSL) 222 *ptr++ = 's'; 223 snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d", 224 conn->host.name, conn->remote_port); 225 226 #ifdef CURL_OPENLDAP_DEBUG 227 static int do_trace = 0; 228 const char *env = getenv("CURL_OPENLDAP_TRACE"); 229 do_trace = (env && strtol(env, NULL, 10) > 0); 230 if(do_trace) { 231 ldap_set_option(li->ld, LDAP_OPT_DEBUG_LEVEL, &do_trace); 232 } 233 #endif 234 235 rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld); 236 if(rc) { 237 failf(data, "LDAP local: Cannot connect to %s, %s", 238 hosturl, ldap_err2string(rc)); 239 return CURLE_COULDNT_CONNECT; 240 } 241 242 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); 243 244 #ifdef USE_SSL 245 if(conn->handler->flags & PROTOPT_SSL) { 246 CURLcode result; 247 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone); 248 if(result) 249 return result; 250 } 251 #endif 252 253 return CURLE_OK; 254 } 255 256 static CURLcode ldap_connecting(struct connectdata *conn, bool *done) 257 { 258 ldapconninfo *li = conn->proto.generic; 259 struct Curl_easy *data = conn->data; 260 LDAPMessage *msg = NULL; 261 struct timeval tv = {0, 1}, *tvp; 262 int rc, err; 263 char *info = NULL; 264 265 #ifdef USE_SSL 266 if(conn->handler->flags & PROTOPT_SSL) { 267 /* Is the SSL handshake complete yet? */ 268 if(!li->ssldone) { 269 CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, 270 &li->ssldone); 271 if(result || !li->ssldone) 272 return result; 273 } 274 275 /* Have we installed the libcurl SSL handlers into the sockbuf yet? */ 276 if(!li->sslinst) { 277 Sockbuf *sb; 278 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb); 279 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn); 280 li->sslinst = TRUE; 281 li->recv = conn->recv[FIRSTSOCKET]; 282 li->send = conn->send[FIRSTSOCKET]; 283 } 284 } 285 #endif 286 287 tvp = &tv; 288 289 retry: 290 if(!li->didbind) { 291 char *binddn; 292 struct berval passwd; 293 294 if(conn->bits.user_passwd) { 295 binddn = conn->user; 296 passwd.bv_val = conn->passwd; 297 passwd.bv_len = strlen(passwd.bv_val); 298 } 299 else { 300 binddn = NULL; 301 passwd.bv_val = NULL; 302 passwd.bv_len = 0; 303 } 304 rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd, 305 NULL, NULL, &li->msgid); 306 if(rc) 307 return CURLE_LDAP_CANNOT_BIND; 308 li->didbind = TRUE; 309 if(tvp) 310 return CURLE_OK; 311 } 312 313 rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg); 314 if(rc < 0) { 315 failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc)); 316 return CURLE_LDAP_CANNOT_BIND; 317 } 318 if(rc == 0) { 319 /* timed out */ 320 return CURLE_OK; 321 } 322 323 rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1); 324 if(rc) { 325 failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc)); 326 return CURLE_LDAP_CANNOT_BIND; 327 } 328 329 /* Try to fallback to LDAPv2? */ 330 if(err == LDAP_PROTOCOL_ERROR) { 331 int proto; 332 ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); 333 if(proto == LDAP_VERSION3) { 334 if(info) { 335 ldap_memfree(info); 336 info = NULL; 337 } 338 proto = LDAP_VERSION2; 339 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto); 340 li->didbind = FALSE; 341 goto retry; 342 } 343 } 344 345 if(err) { 346 failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc), 347 info ? info : ""); 348 if(info) 349 ldap_memfree(info); 350 return CURLE_LOGIN_DENIED; 351 } 352 353 if(info) 354 ldap_memfree(info); 355 conn->recv[FIRSTSOCKET] = ldap_recv; 356 *done = TRUE; 357 358 return CURLE_OK; 359 } 360 361 static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection) 362 { 363 ldapconninfo *li = conn->proto.generic; 364 (void) dead_connection; 365 366 if(li) { 367 if(li->ld) { 368 ldap_unbind_ext(li->ld, NULL, NULL); 369 li->ld = NULL; 370 } 371 conn->proto.generic = NULL; 372 free(li); 373 } 374 return CURLE_OK; 375 } 376 377 static CURLcode ldap_do(struct connectdata *conn, bool *done) 378 { 379 ldapconninfo *li = conn->proto.generic; 380 ldapreqinfo *lr; 381 CURLcode status = CURLE_OK; 382 int rc = 0; 383 LDAPURLDesc *ludp = NULL; 384 int msgid; 385 struct Curl_easy *data = conn->data; 386 387 connkeep(conn, "OpenLDAP do"); 388 389 infof(data, "LDAP local: %s\n", data->change.url); 390 391 rc = ldap_url_parse(data->change.url, &ludp); 392 if(rc != LDAP_URL_SUCCESS) { 393 const char *msg = "url parsing problem"; 394 status = CURLE_URL_MALFORMAT; 395 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) { 396 if(rc == LDAP_URL_ERR_MEM) 397 status = CURLE_OUT_OF_MEMORY; 398 msg = url_errs[rc]; 399 } 400 failf(conn->data, "LDAP local: %s", msg); 401 return status; 402 } 403 404 rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope, 405 ludp->lud_filter, ludp->lud_attrs, 0, 406 NULL, NULL, NULL, 0, &msgid); 407 ldap_free_urldesc(ludp); 408 if(rc != LDAP_SUCCESS) { 409 failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc)); 410 return CURLE_LDAP_SEARCH_FAILED; 411 } 412 lr = calloc(1, sizeof(ldapreqinfo)); 413 if(!lr) 414 return CURLE_OUT_OF_MEMORY; 415 lr->msgid = msgid; 416 data->req.protop = lr; 417 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL); 418 *done = TRUE; 419 return CURLE_OK; 420 } 421 422 static CURLcode ldap_done(struct connectdata *conn, CURLcode res, 423 bool premature) 424 { 425 ldapreqinfo *lr = conn->data->req.protop; 426 427 (void)res; 428 (void)premature; 429 430 if(lr) { 431 /* if there was a search in progress, abandon it */ 432 if(lr->msgid) { 433 ldapconninfo *li = conn->proto.generic; 434 ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL); 435 lr->msgid = 0; 436 } 437 conn->data->req.protop = NULL; 438 free(lr); 439 } 440 441 return CURLE_OK; 442 } 443 444 static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf, 445 size_t len, CURLcode *err) 446 { 447 ldapconninfo *li = conn->proto.generic; 448 struct Curl_easy *data = conn->data; 449 ldapreqinfo *lr = data->req.protop; 450 int rc, ret; 451 LDAPMessage *msg = NULL; 452 LDAPMessage *ent; 453 BerElement *ber = NULL; 454 struct timeval tv = {0, 1}; 455 456 (void)len; 457 (void)buf; 458 (void)sockindex; 459 460 rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg); 461 if(rc < 0) { 462 failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc)); 463 *err = CURLE_RECV_ERROR; 464 return -1; 465 } 466 467 *err = CURLE_AGAIN; 468 ret = -1; 469 470 /* timed out */ 471 if(!msg) 472 return ret; 473 474 for(ent = ldap_first_message(li->ld, msg); ent; 475 ent = ldap_next_message(li->ld, ent)) { 476 struct berval bv, *bvals, **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 668 ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg) 669 { 670 sbiod->sbiod_pvt = arg; 671 return 0; 672 } 673 674 static int 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 683 ldapsb_tls_close(Sockbuf_IO_Desc *sbiod) 684 { 685 (void)sbiod; 686 return 0; 687 } 688 689 static int 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 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 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