00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "curl_setup.h"
00025
00026 #if !defined(CURL_DISABLE_LDAP) && defined(USE_OPENLDAP)
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <ldap.h>
00040
00041 #include "urldata.h"
00042 #include <curl/curl.h>
00043 #include "sendf.h"
00044 #include "vtls/vtls.h"
00045 #include "transfer.h"
00046 #include "curl_ldap.h"
00047 #include "curl_base64.h"
00048 #include "connect.h"
00049
00050 #include "curl_printf.h"
00051 #include "curl_memory.h"
00052 #include "memdebug.h"
00053
00054 #ifndef _LDAP_PVT_H
00055 extern int ldap_pvt_url_scheme2proto(const char *);
00056 extern int ldap_init_fd(ber_socket_t fd, int proto, const char *url,
00057 LDAP **ld);
00058 #endif
00059
00060 static CURLcode ldap_setup_connection(struct connectdata *conn);
00061 static CURLcode ldap_do(struct connectdata *conn, bool *done);
00062 static CURLcode ldap_done(struct connectdata *conn, CURLcode, bool);
00063 static CURLcode ldap_connect(struct connectdata *conn, bool *done);
00064 static CURLcode ldap_connecting(struct connectdata *conn, bool *done);
00065 static CURLcode ldap_disconnect(struct connectdata *conn, bool dead);
00066
00067 static Curl_recv ldap_recv;
00068
00069
00070
00071
00072
00073 const struct Curl_handler Curl_handler_ldap = {
00074 "LDAP",
00075 ldap_setup_connection,
00076 ldap_do,
00077 ldap_done,
00078 ZERO_NULL,
00079 ldap_connect,
00080 ldap_connecting,
00081 ZERO_NULL,
00082 ZERO_NULL,
00083 ZERO_NULL,
00084 ZERO_NULL,
00085 ZERO_NULL,
00086 ldap_disconnect,
00087 ZERO_NULL,
00088 PORT_LDAP,
00089 CURLPROTO_LDAP,
00090 PROTOPT_NONE
00091 };
00092
00093 #ifdef USE_SSL
00094
00095
00096
00097
00098 const struct Curl_handler Curl_handler_ldaps = {
00099 "LDAPS",
00100 ldap_setup_connection,
00101 ldap_do,
00102 ldap_done,
00103 ZERO_NULL,
00104 ldap_connect,
00105 ldap_connecting,
00106 ZERO_NULL,
00107 ZERO_NULL,
00108 ZERO_NULL,
00109 ZERO_NULL,
00110 ZERO_NULL,
00111 ldap_disconnect,
00112 ZERO_NULL,
00113 PORT_LDAPS,
00114 CURLPROTO_LDAP,
00115 PROTOPT_SSL
00116 };
00117 #endif
00118
00119 static const char *url_errs[] = {
00120 "success",
00121 "out of memory",
00122 "bad parameter",
00123 "unrecognized scheme",
00124 "unbalanced delimiter",
00125 "bad URL",
00126 "bad host or port",
00127 "bad or missing attributes",
00128 "bad or missing scope",
00129 "bad or missing filter",
00130 "bad or missing extensions"
00131 };
00132
00133 typedef struct ldapconninfo {
00134 LDAP *ld;
00135 Curl_recv *recv;
00136 Curl_send *send;
00137 int proto;
00138 int msgid;
00139 bool ssldone;
00140 bool sslinst;
00141 bool didbind;
00142 } ldapconninfo;
00143
00144 typedef struct ldapreqinfo {
00145 int msgid;
00146 int nument;
00147 } ldapreqinfo;
00148
00149 static CURLcode ldap_setup_connection(struct connectdata *conn)
00150 {
00151 ldapconninfo *li;
00152 LDAPURLDesc *lud;
00153 struct Curl_easy *data=conn->data;
00154 int rc, proto;
00155 CURLcode status;
00156
00157 rc = ldap_url_parse(data->change.url, &lud);
00158 if(rc != LDAP_URL_SUCCESS) {
00159 const char *msg = "url parsing problem";
00160 status = CURLE_URL_MALFORMAT;
00161 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
00162 if(rc == LDAP_URL_ERR_MEM)
00163 status = CURLE_OUT_OF_MEMORY;
00164 msg = url_errs[rc];
00165 }
00166 failf(conn->data, "LDAP local: %s", msg);
00167 return status;
00168 }
00169 proto = ldap_pvt_url_scheme2proto(lud->lud_scheme);
00170 ldap_free_urldesc(lud);
00171
00172 li = calloc(1, sizeof(ldapconninfo));
00173 if(!li)
00174 return CURLE_OUT_OF_MEMORY;
00175 li->proto = proto;
00176 conn->proto.generic = li;
00177 connkeep(conn, "OpenLDAP default");
00178
00179
00180
00181 return CURLE_OK;
00182 }
00183
00184 #ifdef USE_SSL
00185 static Sockbuf_IO ldapsb_tls;
00186 #endif
00187
00188 static CURLcode ldap_connect(struct connectdata *conn, bool *done)
00189 {
00190 ldapconninfo *li = conn->proto.generic;
00191 struct Curl_easy *data = conn->data;
00192 int rc, proto = LDAP_VERSION3;
00193 char hosturl[1024];
00194 char *ptr;
00195
00196 (void)done;
00197
00198 strcpy(hosturl, "ldap");
00199 ptr = hosturl+4;
00200 if(conn->handler->flags & PROTOPT_SSL)
00201 *ptr++ = 's';
00202 snprintf(ptr, sizeof(hosturl)-(ptr-hosturl), "://%s:%d",
00203 conn->host.name, conn->remote_port);
00204
00205 rc = ldap_init_fd(conn->sock[FIRSTSOCKET], li->proto, hosturl, &li->ld);
00206 if(rc) {
00207 failf(data, "LDAP local: Cannot connect to %s, %s",
00208 hosturl, ldap_err2string(rc));
00209 return CURLE_COULDNT_CONNECT;
00210 }
00211
00212 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
00213
00214 #ifdef USE_SSL
00215 if(conn->handler->flags & PROTOPT_SSL) {
00216 CURLcode result;
00217 result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET, &li->ssldone);
00218 if(result)
00219 return result;
00220 }
00221 #endif
00222
00223 return CURLE_OK;
00224 }
00225
00226 static CURLcode ldap_connecting(struct connectdata *conn, bool *done)
00227 {
00228 ldapconninfo *li = conn->proto.generic;
00229 struct Curl_easy *data = conn->data;
00230 LDAPMessage *msg = NULL;
00231 struct timeval tv = {0, 1}, *tvp;
00232 int rc, err;
00233 char *info = NULL;
00234
00235 #ifdef USE_SSL
00236 if(conn->handler->flags & PROTOPT_SSL) {
00237
00238 if(!li->ssldone) {
00239 CURLcode result = Curl_ssl_connect_nonblocking(conn, FIRSTSOCKET,
00240 &li->ssldone);
00241 if(result || !li->ssldone)
00242 return result;
00243 }
00244
00245
00246 if(!li->sslinst) {
00247 Sockbuf *sb;
00248 ldap_get_option(li->ld, LDAP_OPT_SOCKBUF, &sb);
00249 ber_sockbuf_add_io(sb, &ldapsb_tls, LBER_SBIOD_LEVEL_TRANSPORT, conn);
00250 li->sslinst = TRUE;
00251 li->recv = conn->recv[FIRSTSOCKET];
00252 li->send = conn->send[FIRSTSOCKET];
00253 }
00254 }
00255 #endif
00256
00257 tvp = &tv;
00258
00259 retry:
00260 if(!li->didbind) {
00261 char *binddn;
00262 struct berval passwd;
00263
00264 if(conn->bits.user_passwd) {
00265 binddn = conn->user;
00266 passwd.bv_val = conn->passwd;
00267 passwd.bv_len = strlen(passwd.bv_val);
00268 }
00269 else {
00270 binddn = NULL;
00271 passwd.bv_val = NULL;
00272 passwd.bv_len = 0;
00273 }
00274 rc = ldap_sasl_bind(li->ld, binddn, LDAP_SASL_SIMPLE, &passwd,
00275 NULL, NULL, &li->msgid);
00276 if(rc)
00277 return CURLE_LDAP_CANNOT_BIND;
00278 li->didbind = TRUE;
00279 if(tvp)
00280 return CURLE_OK;
00281 }
00282
00283 rc = ldap_result(li->ld, li->msgid, LDAP_MSG_ONE, tvp, &msg);
00284 if(rc < 0) {
00285 failf(data, "LDAP local: bind ldap_result %s", ldap_err2string(rc));
00286 return CURLE_LDAP_CANNOT_BIND;
00287 }
00288 if(rc == 0) {
00289
00290 return CURLE_OK;
00291 }
00292
00293 rc = ldap_parse_result(li->ld, msg, &err, NULL, &info, NULL, NULL, 1);
00294 if(rc) {
00295 failf(data, "LDAP local: bind ldap_parse_result %s", ldap_err2string(rc));
00296 return CURLE_LDAP_CANNOT_BIND;
00297 }
00298
00299
00300 if(err == LDAP_PROTOCOL_ERROR) {
00301 int proto;
00302 ldap_get_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
00303 if(proto == LDAP_VERSION3) {
00304 if(info) {
00305 ldap_memfree(info);
00306 info = NULL;
00307 }
00308 proto = LDAP_VERSION2;
00309 ldap_set_option(li->ld, LDAP_OPT_PROTOCOL_VERSION, &proto);
00310 li->didbind = FALSE;
00311 goto retry;
00312 }
00313 }
00314
00315 if(err) {
00316 failf(data, "LDAP remote: bind failed %s %s", ldap_err2string(rc),
00317 info ? info : "");
00318 if(info)
00319 ldap_memfree(info);
00320 return CURLE_LOGIN_DENIED;
00321 }
00322
00323 if(info)
00324 ldap_memfree(info);
00325 conn->recv[FIRSTSOCKET] = ldap_recv;
00326 *done = TRUE;
00327
00328 return CURLE_OK;
00329 }
00330
00331 static CURLcode ldap_disconnect(struct connectdata *conn, bool dead_connection)
00332 {
00333 ldapconninfo *li = conn->proto.generic;
00334 (void) dead_connection;
00335
00336 if(li) {
00337 if(li->ld) {
00338 ldap_unbind_ext(li->ld, NULL, NULL);
00339 li->ld = NULL;
00340 }
00341 conn->proto.generic = NULL;
00342 free(li);
00343 }
00344 return CURLE_OK;
00345 }
00346
00347 static CURLcode ldap_do(struct connectdata *conn, bool *done)
00348 {
00349 ldapconninfo *li = conn->proto.generic;
00350 ldapreqinfo *lr;
00351 CURLcode status = CURLE_OK;
00352 int rc = 0;
00353 LDAPURLDesc *ludp = NULL;
00354 int msgid;
00355 struct Curl_easy *data=conn->data;
00356
00357 connkeep(conn, "OpenLDAP do");
00358
00359 infof(data, "LDAP local: %s\n", data->change.url);
00360
00361 rc = ldap_url_parse(data->change.url, &ludp);
00362 if(rc != LDAP_URL_SUCCESS) {
00363 const char *msg = "url parsing problem";
00364 status = CURLE_URL_MALFORMAT;
00365 if(rc > LDAP_URL_SUCCESS && rc <= LDAP_URL_ERR_BADEXTS) {
00366 if(rc == LDAP_URL_ERR_MEM)
00367 status = CURLE_OUT_OF_MEMORY;
00368 msg = url_errs[rc];
00369 }
00370 failf(conn->data, "LDAP local: %s", msg);
00371 return status;
00372 }
00373
00374 rc = ldap_search_ext(li->ld, ludp->lud_dn, ludp->lud_scope,
00375 ludp->lud_filter, ludp->lud_attrs, 0,
00376 NULL, NULL, NULL, 0, &msgid);
00377 ldap_free_urldesc(ludp);
00378 if(rc != LDAP_SUCCESS) {
00379 failf(data, "LDAP local: ldap_search_ext %s", ldap_err2string(rc));
00380 return CURLE_LDAP_SEARCH_FAILED;
00381 }
00382 lr = calloc(1, sizeof(ldapreqinfo));
00383 if(!lr)
00384 return CURLE_OUT_OF_MEMORY;
00385 lr->msgid = msgid;
00386 data->req.protop = lr;
00387 Curl_setup_transfer(conn, FIRSTSOCKET, -1, FALSE, NULL, -1, NULL);
00388 *done = TRUE;
00389 return CURLE_OK;
00390 }
00391
00392 static CURLcode ldap_done(struct connectdata *conn, CURLcode res,
00393 bool premature)
00394 {
00395 ldapreqinfo *lr = conn->data->req.protop;
00396
00397 (void)res;
00398 (void)premature;
00399
00400 if(lr) {
00401
00402 if(lr->msgid) {
00403 ldapconninfo *li = conn->proto.generic;
00404 ldap_abandon_ext(li->ld, lr->msgid, NULL, NULL);
00405 lr->msgid = 0;
00406 }
00407 conn->data->req.protop = NULL;
00408 free(lr);
00409 }
00410
00411 return CURLE_OK;
00412 }
00413
00414 static ssize_t ldap_recv(struct connectdata *conn, int sockindex, char *buf,
00415 size_t len, CURLcode *err)
00416 {
00417 ldapconninfo *li = conn->proto.generic;
00418 struct Curl_easy *data = conn->data;
00419 ldapreqinfo *lr = data->req.protop;
00420 int rc, ret;
00421 LDAPMessage *msg = NULL;
00422 LDAPMessage *ent;
00423 BerElement *ber = NULL;
00424 struct timeval tv = {0, 1};
00425
00426 (void)len;
00427 (void)buf;
00428 (void)sockindex;
00429
00430 rc = ldap_result(li->ld, lr->msgid, LDAP_MSG_RECEIVED, &tv, &msg);
00431 if(rc < 0) {
00432 failf(data, "LDAP local: search ldap_result %s", ldap_err2string(rc));
00433 *err = CURLE_RECV_ERROR;
00434 return -1;
00435 }
00436
00437 *err = CURLE_AGAIN;
00438 ret = -1;
00439
00440
00441 if(!msg)
00442 return ret;
00443
00444 for(ent = ldap_first_message(li->ld, msg); ent;
00445 ent = ldap_next_message(li->ld, ent)) {
00446 struct berval bv, *bvals, **bvp = &bvals;
00447 int binary = 0, msgtype;
00448 CURLcode writeerr;
00449
00450 msgtype = ldap_msgtype(ent);
00451 if(msgtype == LDAP_RES_SEARCH_RESULT) {
00452 int code;
00453 char *info = NULL;
00454 rc = ldap_parse_result(li->ld, ent, &code, NULL, &info, NULL, NULL, 0);
00455 if(rc) {
00456 failf(data, "LDAP local: search ldap_parse_result %s",
00457 ldap_err2string(rc));
00458 *err = CURLE_LDAP_SEARCH_FAILED;
00459 }
00460 else if(code && code != LDAP_SIZELIMIT_EXCEEDED) {
00461 failf(data, "LDAP remote: search failed %s %s", ldap_err2string(rc),
00462 info ? info : "");
00463 *err = CURLE_LDAP_SEARCH_FAILED;
00464 }
00465 else {
00466
00467 if(code == LDAP_SIZELIMIT_EXCEEDED)
00468 infof(data, "There are more than %d entries\n", lr->nument);
00469 data->req.size = data->req.bytecount;
00470 *err = CURLE_OK;
00471 ret = 0;
00472 }
00473 lr->msgid = 0;
00474 ldap_memfree(info);
00475 break;
00476 }
00477 else if(msgtype != LDAP_RES_SEARCH_ENTRY)
00478 continue;
00479
00480 lr->nument++;
00481 rc = ldap_get_dn_ber(li->ld, ent, &ber, &bv);
00482 if(rc < 0) {
00483
00484
00485 *err = CURLE_RECV_ERROR;
00486 return -1;
00487 }
00488 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"DN: ", 4);
00489 if(writeerr) {
00490 *err = writeerr;
00491 return -1;
00492 }
00493
00494 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
00495 bv.bv_len);
00496 if(writeerr) {
00497 *err = writeerr;
00498 return -1;
00499 }
00500
00501 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 1);
00502 if(writeerr) {
00503 *err = writeerr;
00504 return -1;
00505 }
00506 data->req.bytecount += bv.bv_len + 5;
00507
00508 for(rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp);
00509 rc == LDAP_SUCCESS;
00510 rc = ldap_get_attribute_ber(li->ld, ent, ber, &bv, bvp)) {
00511 int i;
00512
00513 if(bv.bv_val == NULL) break;
00514
00515 if(bv.bv_len > 7 && !strncmp(bv.bv_val + bv.bv_len - 7, ";binary", 7))
00516 binary = 1;
00517 else
00518 binary = 0;
00519
00520 for(i=0; bvals[i].bv_val != NULL; i++) {
00521 int binval = 0;
00522 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\t", 1);
00523 if(writeerr) {
00524 *err = writeerr;
00525 return -1;
00526 }
00527
00528 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)bv.bv_val,
00529 bv.bv_len);
00530 if(writeerr) {
00531 *err = writeerr;
00532 return -1;
00533 }
00534
00535 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)":", 1);
00536 if(writeerr) {
00537 *err = writeerr;
00538 return -1;
00539 }
00540 data->req.bytecount += bv.bv_len + 2;
00541
00542 if(!binary) {
00543
00544 if(ISSPACE(bvals[i].bv_val[0]) ||
00545 ISSPACE(bvals[i].bv_val[bvals[i].bv_len-1]))
00546 binval = 1;
00547 else {
00548
00549 unsigned int j;
00550 for(j=0; j<bvals[i].bv_len; j++)
00551 if(!ISPRINT(bvals[i].bv_val[j])) {
00552 binval = 1;
00553 break;
00554 }
00555 }
00556 }
00557 if(binary || binval) {
00558 char *val_b64 = NULL;
00559 size_t val_b64_sz = 0;
00560
00561 CURLcode error = Curl_base64_encode(data,
00562 bvals[i].bv_val,
00563 bvals[i].bv_len,
00564 &val_b64,
00565 &val_b64_sz);
00566 if(error) {
00567 ber_memfree(bvals);
00568 ber_free(ber, 0);
00569 ldap_msgfree(msg);
00570 *err = error;
00571 return -1;
00572 }
00573 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY,
00574 (char *)": ", 2);
00575 if(writeerr) {
00576 *err = writeerr;
00577 return -1;
00578 }
00579
00580 data->req.bytecount += 2;
00581 if(val_b64_sz > 0) {
00582 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, val_b64,
00583 val_b64_sz);
00584 if(writeerr) {
00585 *err = writeerr;
00586 return -1;
00587 }
00588 free(val_b64);
00589 data->req.bytecount += val_b64_sz;
00590 }
00591 }
00592 else {
00593 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)" ", 1);
00594 if(writeerr) {
00595 *err = writeerr;
00596 return -1;
00597 }
00598
00599 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, bvals[i].bv_val,
00600 bvals[i].bv_len);
00601 if(writeerr) {
00602 *err = writeerr;
00603 return -1;
00604 }
00605
00606 data->req.bytecount += bvals[i].bv_len + 1;
00607 }
00608 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
00609 if(writeerr) {
00610 *err = writeerr;
00611 return -1;
00612 }
00613
00614 data->req.bytecount++;
00615 }
00616 ber_memfree(bvals);
00617 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
00618 if(writeerr) {
00619 *err = writeerr;
00620 return -1;
00621 }
00622 data->req.bytecount++;
00623 }
00624 writeerr = Curl_client_write(conn, CLIENTWRITE_BODY, (char *)"\n", 0);
00625 if(writeerr) {
00626 *err = writeerr;
00627 return -1;
00628 }
00629 data->req.bytecount++;
00630 ber_free(ber, 0);
00631 }
00632 ldap_msgfree(msg);
00633 return ret;
00634 }
00635
00636 #ifdef USE_SSL
00637 static int
00638 ldapsb_tls_setup(Sockbuf_IO_Desc *sbiod, void *arg)
00639 {
00640 sbiod->sbiod_pvt = arg;
00641 return 0;
00642 }
00643
00644 static int
00645 ldapsb_tls_remove(Sockbuf_IO_Desc *sbiod)
00646 {
00647 sbiod->sbiod_pvt = NULL;
00648 return 0;
00649 }
00650
00651
00652 static int
00653 ldapsb_tls_close(Sockbuf_IO_Desc *sbiod)
00654 {
00655 (void)sbiod;
00656 return 0;
00657 }
00658
00659 static int
00660 ldapsb_tls_ctrl(Sockbuf_IO_Desc *sbiod, int opt, void *arg)
00661 {
00662 (void)arg;
00663 if(opt == LBER_SB_OPT_DATA_READY) {
00664 struct connectdata *conn = sbiod->sbiod_pvt;
00665 return Curl_ssl_data_pending(conn, FIRSTSOCKET);
00666 }
00667 return 0;
00668 }
00669
00670 static ber_slen_t
00671 ldapsb_tls_read(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
00672 {
00673 struct connectdata *conn = sbiod->sbiod_pvt;
00674 ldapconninfo *li = conn->proto.generic;
00675 ber_slen_t ret;
00676 CURLcode err = CURLE_RECV_ERROR;
00677
00678 ret = li->recv(conn, FIRSTSOCKET, buf, len, &err);
00679 if(ret < 0 && err == CURLE_AGAIN) {
00680 SET_SOCKERRNO(EWOULDBLOCK);
00681 }
00682 return ret;
00683 }
00684
00685 static ber_slen_t
00686 ldapsb_tls_write(Sockbuf_IO_Desc *sbiod, void *buf, ber_len_t len)
00687 {
00688 struct connectdata *conn = sbiod->sbiod_pvt;
00689 ldapconninfo *li = conn->proto.generic;
00690 ber_slen_t ret;
00691 CURLcode err = CURLE_SEND_ERROR;
00692
00693 ret = li->send(conn, FIRSTSOCKET, buf, len, &err);
00694 if(ret < 0 && err == CURLE_AGAIN) {
00695 SET_SOCKERRNO(EWOULDBLOCK);
00696 }
00697 return ret;
00698 }
00699
00700 static Sockbuf_IO ldapsb_tls =
00701 {
00702 ldapsb_tls_setup,
00703 ldapsb_tls_remove,
00704 ldapsb_tls_ctrl,
00705 ldapsb_tls_read,
00706 ldapsb_tls_write,
00707 ldapsb_tls_close
00708 };
00709 #endif
00710
00711 #endif