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