1/* $OpenBSD: aldap.c,v 1.10 2022/03/31 09:03:48 martijn Exp $ */ 2 3/* 4 * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org> 5 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20#include <arpa/inet.h> 21#include <ctype.h> 22#include <errno.h> 23#include <inttypes.h> 24#include <string.h> 25#include <stdlib.h> 26#include <unistd.h> 27 28#include <event.h> 29 30#include "aldap.h" 31 32#if 0 33#define DEBUG 34#endif 35#define VERSION 3 36 37static struct ber_element *ldap_parse_search_filter(struct ber_element *, 38 char *); 39static struct ber_element *ldap_do_parse_search_filter( 40 struct ber_element *, char **); 41struct aldap_stringset *aldap_get_stringset(struct ber_element *); 42char *utoa(char *); 43static int isu8cont(unsigned char); 44char *parseval(char *, size_t); 45int aldap_create_page_control(struct ber_element *, 46 int, struct aldap_page_control *); 47int aldap_send(struct aldap *, 48 struct ber_element *); 49unsigned int aldap_application(struct ber_element *); 50 51#ifdef DEBUG 52void ldap_debug_elements(struct ber_element *); 53#endif 54 55#ifdef DEBUG 56#define DPRINTF(x...) printf(x) 57#define LDAP_DEBUG(x, y) do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0) 58#else 59#define DPRINTF(x...) do { } while (0) 60#define LDAP_DEBUG(x, y) do { } while (0) 61#endif 62 63unsigned int 64aldap_application(struct ber_element *elm) 65{ 66 return BER_TYPE_OCTETSTRING; 67} 68 69int 70aldap_close(struct aldap *al) 71{ 72 if (al->tls != NULL) { 73 tls_close(al->tls); 74 tls_free(al->tls); 75 } 76 close(al->fd); 77 ober_free(&al->ber); 78 evbuffer_free(al->buf); 79 free(al); 80 81 return (0); 82} 83 84struct aldap * 85aldap_init(int fd) 86{ 87 struct aldap *a; 88 89 if ((a = calloc(1, sizeof(*a))) == NULL) 90 return NULL; 91 a->buf = evbuffer_new(); 92 a->fd = fd; 93 ober_set_application(&a->ber, aldap_application); 94 95 return a; 96} 97 98int 99aldap_tls(struct aldap *ldap, struct tls_config *cfg, const char *name) 100{ 101 ldap->tls = tls_client(); 102 if (ldap->tls == NULL) { 103 ldap->err = ALDAP_ERR_OPERATION_FAILED; 104 return (-1); 105 } 106 107 if (tls_configure(ldap->tls, cfg) == -1) { 108 ldap->err = ALDAP_ERR_TLS_ERROR; 109 return (-1); 110 } 111 112 if (tls_connect_socket(ldap->tls, ldap->fd, name) == -1) { 113 ldap->err = ALDAP_ERR_TLS_ERROR; 114 return (-1); 115 } 116 117 if (tls_handshake(ldap->tls) == -1) { 118 ldap->err = ALDAP_ERR_TLS_ERROR; 119 return (-1); 120 } 121 122 return (0); 123} 124 125int 126aldap_send(struct aldap *ldap, struct ber_element *root) 127{ 128 void *ptr; 129 char *data; 130 size_t len, done; 131 ssize_t error, wrote; 132 133 len = ober_calc_len(root); 134 error = ober_write_elements(&ldap->ber, root); 135 ober_free_elements(root); 136 if (error == -1) 137 return -1; 138 139 ober_get_writebuf(&ldap->ber, &ptr); 140 done = 0; 141 data = ptr; 142 while (len > 0) { 143 if (ldap->tls != NULL) { 144 wrote = tls_write(ldap->tls, data + done, len); 145 if (wrote == TLS_WANT_POLLIN || 146 wrote == TLS_WANT_POLLOUT) 147 continue; 148 } else 149 wrote = write(ldap->fd, data + done, len); 150 151 if (wrote == -1) 152 return -1; 153 154 len -= wrote; 155 done += wrote; 156 } 157 158 return 0; 159} 160 161int 162aldap_req_starttls(struct aldap *ldap) 163{ 164 struct ber_element *root = NULL, *ber; 165 166 if ((root = ober_add_sequence(NULL)) == NULL) 167 goto fail; 168 169 ber = ober_printf_elements(root, "d{tst", ++ldap->msgid, BER_CLASS_APP, 170 LDAP_REQ_EXTENDED, LDAP_STARTTLS_OID, BER_CLASS_CONTEXT, 0); 171 if (ber == NULL) { 172 ldap->err = ALDAP_ERR_OPERATION_FAILED; 173 goto fail; 174 } 175 176 if (aldap_send(ldap, root) == -1) 177 goto fail; 178 179 return (ldap->msgid); 180fail: 181 if (root != NULL) 182 ober_free_elements(root); 183 184 ldap->err = ALDAP_ERR_OPERATION_FAILED; 185 return (-1); 186} 187 188int 189aldap_bind(struct aldap *ldap, char *binddn, char *bindcred) 190{ 191 struct ber_element *root = NULL, *elm; 192 193 if (binddn == NULL) 194 binddn = ""; 195 if (bindcred == NULL) 196 bindcred = ""; 197 198 if ((root = ober_add_sequence(NULL)) == NULL) 199 goto fail; 200 201 elm = ober_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP, 202 LDAP_REQ_BIND, VERSION, binddn, bindcred, BER_CLASS_CONTEXT, 203 LDAP_AUTH_SIMPLE); 204 if (elm == NULL) 205 goto fail; 206 207 LDAP_DEBUG("aldap_bind", root); 208 209 if (aldap_send(ldap, root) == -1) { 210 root = NULL; 211 goto fail; 212 } 213 return (ldap->msgid); 214fail: 215 if (root != NULL) 216 ober_free_elements(root); 217 218 ldap->err = ALDAP_ERR_OPERATION_FAILED; 219 return (-1); 220} 221 222int 223aldap_unbind(struct aldap *ldap) 224{ 225 struct ber_element *root = NULL, *elm; 226 227 if ((root = ober_add_sequence(NULL)) == NULL) 228 goto fail; 229 elm = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, 230 LDAP_REQ_UNBIND_30); 231 if (elm == NULL) 232 goto fail; 233 234 LDAP_DEBUG("aldap_unbind", root); 235 236 if (aldap_send(ldap, root) == -1) { 237 root = NULL; 238 goto fail; 239 } 240 return (ldap->msgid); 241fail: 242 if (root != NULL) 243 ober_free_elements(root); 244 245 ldap->err = ALDAP_ERR_OPERATION_FAILED; 246 247 return (-1); 248} 249 250int 251aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter, 252 char **attrs, int typesonly, int sizelimit, int timelimit, 253 struct aldap_page_control *page) 254{ 255 struct ber_element *root = NULL, *ber, *c; 256 int i; 257 258 if ((root = ober_add_sequence(NULL)) == NULL) 259 goto fail; 260 261 ber = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP, 262 LDAP_REQ_SEARCH); 263 if (ber == NULL) { 264 ldap->err = ALDAP_ERR_OPERATION_FAILED; 265 goto fail; 266 } 267 268 c = ber; 269 ber = ober_printf_elements(ber, "sEEddb", basedn, (long long)scope, 270 (long long)LDAP_DEREF_NEVER, sizelimit, 271 timelimit, typesonly); 272 if (ber == NULL) { 273 ldap->err = ALDAP_ERR_OPERATION_FAILED; 274 goto fail; 275 } 276 277 if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) { 278 ldap->err = ALDAP_ERR_PARSER_ERROR; 279 goto fail; 280 } 281 282 if ((ber = ober_add_sequence(ber)) == NULL) 283 goto fail; 284 if (attrs != NULL) 285 for (i = 0; attrs[i] != NULL; i++) { 286 if ((ber = ober_add_string(ber, attrs[i])) == NULL) 287 goto fail; 288 } 289 290 aldap_create_page_control(c, 100, page); 291 292 LDAP_DEBUG("aldap_search", root); 293 294 if (aldap_send(ldap, root) == -1) { 295 root = NULL; 296 ldap->err = ALDAP_ERR_OPERATION_FAILED; 297 goto fail; 298 } 299 300 return (ldap->msgid); 301 302fail: 303 if (root != NULL) 304 ober_free_elements(root); 305 306 return (-1); 307} 308 309int 310aldap_create_page_control(struct ber_element *elm, int size, 311 struct aldap_page_control *page) 312{ 313 ssize_t len; 314 struct ber c; 315 struct ber_element *ber = NULL; 316 317 c.br_wbuf = NULL; 318 319 ber = ober_add_sequence(NULL); 320 321 if (page == NULL) { 322 if (ober_printf_elements(ber, "ds", 50, "") == NULL) 323 goto fail; 324 } else { 325 if (ober_printf_elements(ber, "dx", 50, page->cookie, 326 page->cookie_len) == NULL) 327 goto fail; 328 } 329 330 if ((len = ober_write_elements(&c, ber)) < 1) 331 goto fail; 332 if (ober_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID, 333 c.br_wbuf, (size_t)len) == NULL) 334 goto fail; 335 336 ober_free_elements(ber); 337 ober_free(&c); 338 return len; 339fail: 340 if (ber != NULL) 341 ober_free_elements(ber); 342 ober_free(&c); 343 344 return (-1); 345} 346 347struct aldap_message * 348aldap_parse(struct aldap *ldap) 349{ 350 int class; 351 unsigned int type; 352 long long msgid = 0; 353 struct aldap_message *m; 354 struct ber_element *a = NULL, *ep; 355 char rbuf[512]; 356 int ret, retry; 357 358 if ((m = calloc(1, sizeof(struct aldap_message))) == NULL) 359 return NULL; 360 361 retry = 0; 362 while (m->msg == NULL) { 363 if (retry || EVBUFFER_LENGTH(ldap->buf) == 0) { 364 if (ldap->tls) { 365 ret = tls_read(ldap->tls, rbuf, sizeof(rbuf)); 366 if (ret == TLS_WANT_POLLIN || 367 ret == TLS_WANT_POLLOUT) 368 continue; 369 } else 370 ret = read(ldap->fd, rbuf, sizeof(rbuf)); 371 372 if (ret == -1) { 373 goto parsefail; 374 } 375 376 evbuffer_add(ldap->buf, rbuf, ret); 377 } 378 379 if (EVBUFFER_LENGTH(ldap->buf) > 0) { 380 ober_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf), 381 EVBUFFER_LENGTH(ldap->buf)); 382 errno = 0; 383 m->msg = ober_read_elements(&ldap->ber, NULL); 384 if (errno != 0 && errno != ECANCELED) { 385 goto parsefail; 386 } 387 388 retry = 1; 389 } 390 } 391 392 evbuffer_drain(ldap->buf, ldap->ber.br_rptr - ldap->ber.br_rbuf); 393 394 LDAP_DEBUG("message", m->msg); 395 396 if (ober_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0) 397 goto parsefail; 398 m->msgid = msgid; 399 m->message_type = type; 400 m->protocol_op = a; 401 402 switch (m->message_type) { 403 case LDAP_RES_BIND: 404 case LDAP_RES_MODIFY: 405 case LDAP_RES_ADD: 406 case LDAP_RES_DELETE: 407 case LDAP_RES_MODRDN: 408 case LDAP_RES_COMPARE: 409 case LDAP_RES_SEARCH_RESULT: 410 if (ober_scanf_elements(m->protocol_op, "{EeSe", 411 &m->body.res.rescode, &m->dn, &m->body.res.diagmsg) != 0) 412 goto parsefail; 413 if (m->body.res.rescode == LDAP_REFERRAL) { 414 a = m->body.res.diagmsg->be_next; 415 if (ober_scanf_elements(a, "{e", &m->references) != 0) 416 goto parsefail; 417 } 418 if (m->msg->be_sub) { 419 for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) { 420 ober_scanf_elements(ep, "t", &class, &type); 421 if (class == 2 && type == 0) 422 m->page = aldap_parse_page_control(ep->be_sub->be_sub, 423 ep->be_sub->be_sub->be_len); 424 } 425 } else 426 m->page = NULL; 427 break; 428 case LDAP_RES_SEARCH_ENTRY: 429 if (ober_scanf_elements(m->protocol_op, "{eS{e", &m->dn, 430 &m->body.search.attrs) != 0) 431 goto parsefail; 432 break; 433 case LDAP_RES_SEARCH_REFERENCE: 434 if (ober_scanf_elements(m->protocol_op, "{e", &m->references) != 0) 435 goto parsefail; 436 break; 437 case LDAP_RES_EXTENDED: 438 if (ober_scanf_elements(m->protocol_op, "{E", 439 &m->body.res.rescode) != 0) { 440 goto parsefail; 441 } 442 break; 443 } 444 445 return m; 446parsefail: 447 evbuffer_drain(ldap->buf, EVBUFFER_LENGTH(ldap->buf)); 448 ldap->err = ALDAP_ERR_PARSER_ERROR; 449 aldap_freemsg(m); 450 return NULL; 451} 452 453struct aldap_page_control * 454aldap_parse_page_control(struct ber_element *control, size_t len) 455{ 456 char *oid, *s; 457 char *encoded; 458 struct ber b; 459 struct ber_element *elm; 460 struct aldap_page_control *page; 461 462 b.br_wbuf = NULL; 463 ober_scanf_elements(control, "ss", &oid, &encoded); 464 ober_set_readbuf(&b, encoded, control->be_next->be_len); 465 elm = ober_read_elements(&b, NULL); 466 467 if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) { 468 if (elm != NULL) 469 ober_free_elements(elm); 470 ober_free(&b); 471 return NULL; 472 } 473 474 ober_scanf_elements(elm->be_sub, "is", &page->size, &s); 475 page->cookie_len = elm->be_sub->be_next->be_len; 476 477 if ((page->cookie = malloc(page->cookie_len)) == NULL) { 478 if (elm != NULL) 479 ober_free_elements(elm); 480 ober_free(&b); 481 free(page); 482 return NULL; 483 } 484 memcpy(page->cookie, s, page->cookie_len); 485 486 ober_free_elements(elm); 487 ober_free(&b); 488 return page; 489} 490 491void 492aldap_freepage(struct aldap_page_control *page) 493{ 494 free(page->cookie); 495 free(page); 496} 497 498void 499aldap_freemsg(struct aldap_message *msg) 500{ 501 if (msg->msg) 502 ober_free_elements(msg->msg); 503 free(msg); 504} 505 506int 507aldap_get_resultcode(struct aldap_message *msg) 508{ 509 return msg->body.res.rescode; 510} 511 512char * 513aldap_get_dn(struct aldap_message *msg) 514{ 515 char *dn; 516 517 if (msg->dn == NULL) 518 return NULL; 519 520 if (ober_get_string(msg->dn, &dn) == -1) 521 return NULL; 522 523 return utoa(dn); 524} 525 526struct aldap_stringset * 527aldap_get_references(struct aldap_message *msg) 528{ 529 if (msg->references == NULL) 530 return NULL; 531 return aldap_get_stringset(msg->references); 532} 533 534void 535aldap_free_references(char **values) 536{ 537 int i; 538 539 if (values == NULL) 540 return; 541 542 for (i = 0; values[i] != NULL; i++) 543 free(values[i]); 544 545 free(values); 546} 547 548char * 549aldap_get_diagmsg(struct aldap_message *msg) 550{ 551 char *s; 552 553 if (msg->body.res.diagmsg == NULL) 554 return NULL; 555 556 if (ober_get_string(msg->body.res.diagmsg, &s) == -1) 557 return NULL; 558 559 return utoa(s); 560} 561 562int 563aldap_count_attrs(struct aldap_message *msg) 564{ 565 int i; 566 struct ber_element *a; 567 568 if (msg->body.search.attrs == NULL) 569 return (-1); 570 571 for (i = 0, a = msg->body.search.attrs; 572 a != NULL && ober_get_eoc(a) != 0; 573 i++, a = a->be_next) 574 ; 575 576 return i; 577} 578 579int 580aldap_first_attr(struct aldap_message *msg, char **outkey, 581 struct aldap_stringset **outvalues) 582{ 583 struct ber_element *b; 584 char *key; 585 struct aldap_stringset *ret; 586 587 if (msg->body.search.attrs == NULL) 588 goto fail; 589 590 if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}", 591 &key, &b) != 0) 592 goto fail; 593 594 msg->body.search.iter = msg->body.search.attrs->be_next; 595 596 if ((ret = aldap_get_stringset(b)) == NULL) 597 goto fail; 598 599 (*outvalues) = ret; 600 (*outkey) = utoa(key); 601 602 return (1); 603fail: 604 (*outkey) = NULL; 605 (*outvalues) = NULL; 606 return (-1); 607} 608 609int 610aldap_next_attr(struct aldap_message *msg, char **outkey, 611 struct aldap_stringset **outvalues) 612{ 613 struct ber_element *a; 614 char *key; 615 struct aldap_stringset *ret; 616 617 if (msg->body.search.iter == NULL) 618 goto notfound; 619 620 LDAP_DEBUG("attr", msg->body.search.iter); 621 622 if (ober_get_eoc(msg->body.search.iter) == 0) 623 goto notfound; 624 625 if (ober_scanf_elements(msg->body.search.iter, "{s(e)}", &key, &a) != 0) 626 goto fail; 627 628 msg->body.search.iter = msg->body.search.iter->be_next; 629 630 if ((ret = aldap_get_stringset(a)) == NULL) 631 goto fail; 632 633 (*outvalues) = ret; 634 (*outkey) = utoa(key); 635 636 return (1); 637fail: 638notfound: 639 (*outkey) = NULL; 640 (*outvalues) = NULL; 641 return (-1); 642} 643 644int 645aldap_match_attr(struct aldap_message *msg, char *inkey, 646 struct aldap_stringset **outvalues) 647{ 648 struct ber_element *a, *b; 649 char *descr = NULL; 650 struct aldap_stringset *ret; 651 652 if (msg->body.search.attrs == NULL) 653 goto fail; 654 655 LDAP_DEBUG("attr", msg->body.search.attrs); 656 657 for (a = msg->body.search.attrs;;) { 658 if (a == NULL) 659 goto notfound; 660 if (ober_get_eoc(a) == 0) 661 goto notfound; 662 if (ober_scanf_elements(a, "{s(e", &descr, &b) != 0) 663 goto fail; 664 if (strcasecmp(descr, inkey) == 0) 665 goto attrfound; 666 a = a->be_next; 667 } 668 669attrfound: 670 if ((ret = aldap_get_stringset(b)) == NULL) 671 goto fail; 672 673 (*outvalues) = ret; 674 675 return (1); 676fail: 677notfound: 678 (*outvalues) = NULL; 679 return (-1); 680} 681 682int 683aldap_free_attr(struct aldap_stringset *values) 684{ 685 if (values == NULL) 686 return -1; 687 688 free(values->str); 689 free(values); 690 691 return (1); 692} 693 694void 695aldap_free_url(struct aldap_url *lu) 696{ 697 free(lu->buffer); 698} 699 700int 701aldap_parse_url(const char *url, struct aldap_url *lu) 702{ 703 char *p, *forward, *forward2; 704 const char *errstr = NULL; 705 int i; 706 707 if ((lu->buffer = p = strdup(url)) == NULL) 708 return (-1); 709 710 /* protocol */ 711 if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) { 712 lu->protocol = LDAP; 713 p += strlen(LDAP_URL); 714 } else if (strncasecmp(LDAPS_URL, p, strlen(LDAPS_URL)) == 0) { 715 lu->protocol = LDAPS; 716 p += strlen(LDAPS_URL); 717 } else if (strncasecmp(LDAPTLS_URL, p, strlen(LDAPTLS_URL)) == 0) { 718 lu->protocol = LDAPTLS; 719 p += strlen(LDAPTLS_URL); 720 } else if (strncasecmp(LDAPI_URL, p, strlen(LDAPI_URL)) == 0) { 721 lu->protocol = LDAPI; 722 p += strlen(LDAPI_URL); 723 } else 724 lu->protocol = -1; 725 726 /* host and optional port */ 727 if ((forward = strchr(p, '/')) != NULL) 728 *forward = '\0'; 729 /* find the optional port */ 730 if ((forward2 = strchr(p, ':')) != NULL) { 731 *forward2 = '\0'; 732 /* if a port is given */ 733 if (*(forward2+1) != '\0') { 734#define PORT_MAX UINT16_MAX 735 lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr); 736 if (errstr) 737 goto fail; 738 } 739 } 740 /* fail if no host is given */ 741 if (strlen(p) == 0) 742 goto fail; 743 lu->host = p; 744 if (forward == NULL) 745 goto done; 746 /* p is assigned either a pointer to a character or to '\0' */ 747 p = ++forward; 748 if (strlen(p) == 0) 749 goto done; 750 751 /* dn */ 752 if ((forward = strchr(p, '?')) != NULL) 753 *forward = '\0'; 754 lu->dn = p; 755 if (forward == NULL) 756 goto done; 757 /* p is assigned either a pointer to a character or to '\0' */ 758 p = ++forward; 759 if (strlen(p) == 0) 760 goto done; 761 762 /* attributes */ 763 if ((forward = strchr(p, '?')) != NULL) 764 *forward = '\0'; 765 for (i = 0; i < MAXATTR; i++) { 766 if ((forward2 = strchr(p, ',')) == NULL) { 767 if (strlen(p) == 0) 768 break; 769 lu->attributes[i] = p; 770 break; 771 } 772 *forward2 = '\0'; 773 lu->attributes[i] = p; 774 p = ++forward2; 775 } 776 if (forward == NULL) 777 goto done; 778 /* p is assigned either a pointer to a character or to '\0' */ 779 p = ++forward; 780 if (strlen(p) == 0) 781 goto done; 782 783 /* scope */ 784 if ((forward = strchr(p, '?')) != NULL) 785 *forward = '\0'; 786 if (strcmp(p, "base") == 0) 787 lu->scope = LDAP_SCOPE_BASE; 788 else if (strcmp(p, "one") == 0) 789 lu->scope = LDAP_SCOPE_ONELEVEL; 790 else if (strcmp(p, "sub") == 0) 791 lu->scope = LDAP_SCOPE_SUBTREE; 792 else 793 goto fail; 794 if (forward == NULL) 795 goto done; 796 p = ++forward; 797 if (strlen(p) == 0) 798 goto done; 799 800 /* filter */ 801 if (p) 802 lu->filter = p; 803done: 804 return (1); 805fail: 806 free(lu->buffer); 807 lu->buffer = NULL; 808 return (-1); 809} 810 811int 812aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit, 813 int timelimit, struct aldap_page_control *page) 814{ 815 struct aldap_url *lu; 816 817 if ((lu = calloc(1, sizeof(*lu))) == NULL) 818 return (-1); 819 820 if (aldap_parse_url(url, lu)) 821 goto fail; 822 823 if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes, 824 typesonly, sizelimit, timelimit, page) == -1) 825 goto fail; 826 827 aldap_free_url(lu); 828 return (ldap->msgid); 829fail: 830 aldap_free_url(lu); 831 return (-1); 832} 833 834/* 835 * internal functions 836 */ 837 838struct aldap_stringset * 839aldap_get_stringset(struct ber_element *elm) 840{ 841 struct ber_element *a; 842 int i; 843 struct aldap_stringset *ret; 844 845 if (elm->be_type != BER_TYPE_OCTETSTRING) 846 return NULL; 847 848 if ((ret = malloc(sizeof(*ret))) == NULL) 849 return NULL; 850 for (a = elm, ret->len = 0; a != NULL && a->be_type == 851 BER_TYPE_OCTETSTRING; a = a->be_next, ret->len++) 852 ; 853 if (ret->len == 0) { 854 free(ret); 855 return NULL; 856 } 857 858 if ((ret->str = reallocarray(NULL, ret->len, 859 sizeof(*(ret->str)))) == NULL) { 860 free(ret); 861 return NULL; 862 } 863 864 for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING; 865 a = a->be_next, i++) 866 (void) ober_get_ostring(a, &(ret->str[i])); 867 868 return ret; 869} 870 871/* 872 * Base case for ldap_do_parse_search_filter 873 * 874 * returns: 875 * struct ber_element *, ber_element tree 876 * NULL, parse failed 877 */ 878static struct ber_element * 879ldap_parse_search_filter(struct ber_element *ber, char *filter) 880{ 881 struct ber_element *elm; 882 char *cp; 883 884 cp = filter; 885 886 if (cp == NULL || *cp == '\0') { 887 errno = EINVAL; 888 return (NULL); 889 } 890 891 if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL) 892 return (NULL); 893 894 if (*cp != '\0') { 895 ober_free_elements(elm); 896 ober_link_elements(ber, NULL); 897 errno = EINVAL; 898 return (NULL); 899 } 900 901 return (elm); 902} 903 904/* 905 * Translate RFC4515 search filter string into ber_element tree 906 * 907 * returns: 908 * struct ber_element *, ber_element tree 909 * NULL, parse failed 910 * 911 * notes: 912 * when cp is passed to a recursive invocation, it is updated 913 * to point one character beyond the filter that was passed 914 * i.e., cp jumps to "(filter)" upon return 915 * ^ 916 * goto's used to discriminate error-handling based on error type 917 * doesn't handle extended filters (yet) 918 * 919 */ 920static struct ber_element * 921ldap_do_parse_search_filter(struct ber_element *prev, char **cpp) 922{ 923 struct ber_element *elm, *root = NULL; 924 char *attr_desc, *attr_val, *parsed_val, *cp; 925 size_t len; 926 unsigned long type; 927 928 root = NULL; 929 930 /* cpp should pass in pointer to opening parenthesis of "(filter)" */ 931 cp = *cpp; 932 if (*cp != '(') 933 goto syntaxfail; 934 935 switch (*++cp) { 936 case '&': /* AND */ 937 case '|': /* OR */ 938 if (*cp == '&') 939 type = LDAP_FILT_AND; 940 else 941 type = LDAP_FILT_OR; 942 943 if ((elm = ober_add_set(prev)) == NULL) 944 goto callfail; 945 root = elm; 946 ober_set_header(elm, BER_CLASS_CONTEXT, type); 947 948 if (*++cp != '(') /* opening `(` of filter */ 949 goto syntaxfail; 950 951 while (*cp == '(') { 952 if ((elm = 953 ldap_do_parse_search_filter(elm, &cp)) == NULL) 954 goto bad; 955 } 956 957 if (*cp != ')') /* trailing `)` of filter */ 958 goto syntaxfail; 959 break; 960 961 case '!': /* NOT */ 962 if ((root = ober_add_sequence(prev)) == NULL) 963 goto callfail; 964 ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT); 965 966 cp++; /* now points to sub-filter */ 967 if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL) 968 goto bad; 969 970 if (*cp != ')') /* trailing `)` of filter */ 971 goto syntaxfail; 972 break; 973 974 default: /* SIMPLE || PRESENCE */ 975 attr_desc = cp; 976 977 len = strcspn(cp, "()<>~="); 978 cp += len; 979 switch (*cp) { 980 case '~': 981 type = LDAP_FILT_APPR; 982 cp++; 983 break; 984 case '<': 985 type = LDAP_FILT_LE; 986 cp++; 987 break; 988 case '>': 989 type = LDAP_FILT_GE; 990 cp++; 991 break; 992 case '=': 993 type = LDAP_FILT_EQ; /* assume EQ until disproven */ 994 break; 995 case '(': 996 case ')': 997 default: 998 goto syntaxfail; 999 } 1000 attr_val = ++cp; 1001 1002 /* presence filter */ 1003 if (strncmp(attr_val, "*)", 2) == 0) { 1004 cp++; /* point to trailing `)` */ 1005 if ((root = 1006 ober_add_nstring(prev, attr_desc, len)) == NULL) 1007 goto bad; 1008 1009 ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES); 1010 break; 1011 } 1012 1013 if ((root = ober_add_sequence(prev)) == NULL) 1014 goto callfail; 1015 ober_set_header(root, BER_CLASS_CONTEXT, type); 1016 1017 if ((elm = ober_add_nstring(root, attr_desc, len)) == NULL) 1018 goto callfail; 1019 1020 len = strcspn(attr_val, "*)"); 1021 if (len == 0 && *cp != '*') 1022 goto syntaxfail; 1023 cp += len; 1024 if (*cp == '\0') 1025 goto syntaxfail; 1026 1027 if (*cp == '*') { /* substring filter */ 1028 int initial; 1029 1030 cp = attr_val; 1031 1032 ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS); 1033 1034 if ((elm = ober_add_sequence(elm)) == NULL) 1035 goto callfail; 1036 1037 for (initial = 1;; cp++, initial = 0) { 1038 attr_val = cp; 1039 1040 len = strcspn(attr_val, "*)"); 1041 if (len == 0) { 1042 if (*cp == ')') 1043 break; 1044 else 1045 continue; 1046 } 1047 cp += len; 1048 if (*cp == '\0') 1049 goto syntaxfail; 1050 1051 if (initial) 1052 type = LDAP_FILT_SUBS_INIT; 1053 else if (*cp == ')') 1054 type = LDAP_FILT_SUBS_FIN; 1055 else 1056 type = LDAP_FILT_SUBS_ANY; 1057 1058 if ((parsed_val = parseval(attr_val, len)) == 1059 NULL) 1060 goto callfail; 1061 elm = ober_add_nstring(elm, parsed_val, 1062 strlen(parsed_val)); 1063 free(parsed_val); 1064 if (elm == NULL) 1065 goto callfail; 1066 ober_set_header(elm, BER_CLASS_CONTEXT, type); 1067 if (type == LDAP_FILT_SUBS_FIN) 1068 break; 1069 } 1070 break; 1071 } 1072 1073 if ((parsed_val = parseval(attr_val, len)) == NULL) 1074 goto callfail; 1075 elm = ober_add_nstring(elm, parsed_val, strlen(parsed_val)); 1076 free(parsed_val); 1077 if (elm == NULL) 1078 goto callfail; 1079 break; 1080 } 1081 1082 cp++; /* now points one char beyond the trailing `)` */ 1083 1084 *cpp = cp; 1085 return (root); 1086 1087syntaxfail: /* XXX -- error reporting */ 1088callfail: 1089bad: 1090 if (root != NULL) 1091 ober_free_elements(root); 1092 ober_link_elements(prev, NULL); 1093 return (NULL); 1094} 1095 1096#ifdef DEBUG 1097/* 1098 * Display a list of ber elements. 1099 * 1100 */ 1101void 1102ldap_debug_elements(struct ber_element *root) 1103{ 1104 static int indent = 0; 1105 long long v; 1106 int d; 1107 char *buf; 1108 size_t len; 1109 u_int i; 1110 int constructed; 1111 struct ber_oid o; 1112 1113 /* calculate lengths */ 1114 ober_calc_len(root); 1115 1116 switch (root->be_encoding) { 1117 case BER_TYPE_SEQUENCE: 1118 case BER_TYPE_SET: 1119 constructed = root->be_encoding; 1120 break; 1121 default: 1122 constructed = 0; 1123 break; 1124 } 1125 1126 fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); 1127 switch (root->be_class) { 1128 case BER_CLASS_UNIVERSAL: 1129 fprintf(stderr, "class: universal(%u) type: ", root->be_class); 1130 switch (root->be_type) { 1131 case BER_TYPE_EOC: 1132 fprintf(stderr, "end-of-content"); 1133 break; 1134 case BER_TYPE_BOOLEAN: 1135 fprintf(stderr, "boolean"); 1136 break; 1137 case BER_TYPE_INTEGER: 1138 fprintf(stderr, "integer"); 1139 break; 1140 case BER_TYPE_BITSTRING: 1141 fprintf(stderr, "bit-string"); 1142 break; 1143 case BER_TYPE_OCTETSTRING: 1144 fprintf(stderr, "octet-string"); 1145 break; 1146 case BER_TYPE_NULL: 1147 fprintf(stderr, "null"); 1148 break; 1149 case BER_TYPE_OBJECT: 1150 fprintf(stderr, "object"); 1151 break; 1152 case BER_TYPE_ENUMERATED: 1153 fprintf(stderr, "enumerated"); 1154 break; 1155 case BER_TYPE_SEQUENCE: 1156 fprintf(stderr, "sequence"); 1157 break; 1158 case BER_TYPE_SET: 1159 fprintf(stderr, "set"); 1160 break; 1161 } 1162 break; 1163 case BER_CLASS_APPLICATION: 1164 fprintf(stderr, "class: application(%u) type: ", 1165 root->be_class); 1166 switch (root->be_type) { 1167 case LDAP_REQ_BIND: 1168 fprintf(stderr, "bind"); 1169 break; 1170 case LDAP_RES_BIND: 1171 fprintf(stderr, "bind"); 1172 break; 1173 case LDAP_REQ_UNBIND_30: 1174 break; 1175 case LDAP_REQ_SEARCH: 1176 fprintf(stderr, "search"); 1177 break; 1178 case LDAP_RES_SEARCH_ENTRY: 1179 fprintf(stderr, "search_entry"); 1180 break; 1181 case LDAP_RES_SEARCH_RESULT: 1182 fprintf(stderr, "search_result"); 1183 break; 1184 case LDAP_REQ_MODIFY: 1185 fprintf(stderr, "modify"); 1186 break; 1187 case LDAP_RES_MODIFY: 1188 fprintf(stderr, "modify"); 1189 break; 1190 case LDAP_REQ_ADD: 1191 fprintf(stderr, "add"); 1192 break; 1193 case LDAP_RES_ADD: 1194 fprintf(stderr, "add"); 1195 break; 1196 case LDAP_REQ_DELETE_30: 1197 fprintf(stderr, "delete"); 1198 break; 1199 case LDAP_RES_DELETE: 1200 fprintf(stderr, "delete"); 1201 break; 1202 case LDAP_REQ_MODRDN: 1203 fprintf(stderr, "modrdn"); 1204 break; 1205 case LDAP_RES_MODRDN: 1206 fprintf(stderr, "modrdn"); 1207 break; 1208 case LDAP_REQ_COMPARE: 1209 fprintf(stderr, "compare"); 1210 break; 1211 case LDAP_RES_COMPARE: 1212 fprintf(stderr, "compare"); 1213 break; 1214 case LDAP_REQ_ABANDON_30: 1215 fprintf(stderr, "abandon"); 1216 break; 1217 } 1218 break; 1219 case BER_CLASS_PRIVATE: 1220 fprintf(stderr, "class: private(%u) type: ", root->be_class); 1221 fprintf(stderr, "encoding (%u) type: ", root->be_encoding); 1222 break; 1223 case BER_CLASS_CONTEXT: 1224 /* XXX: this is not correct */ 1225 fprintf(stderr, "class: context(%u) type: ", root->be_class); 1226 switch(root->be_type) { 1227 case LDAP_AUTH_SIMPLE: 1228 fprintf(stderr, "auth simple"); 1229 break; 1230 } 1231 break; 1232 default: 1233 fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); 1234 break; 1235 } 1236 fprintf(stderr, "(%u) encoding %u ", 1237 root->be_type, root->be_encoding); 1238 1239 if (constructed) 1240 root->be_encoding = constructed; 1241 1242 switch (root->be_encoding) { 1243 case BER_TYPE_BOOLEAN: 1244 if (ober_get_boolean(root, &d) == -1) { 1245 fprintf(stderr, "<INVALID>\n"); 1246 break; 1247 } 1248 fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); 1249 break; 1250 case BER_TYPE_INTEGER: 1251 if (ober_get_integer(root, &v) == -1) { 1252 fprintf(stderr, "<INVALID>\n"); 1253 break; 1254 } 1255 fprintf(stderr, "value %lld\n", v); 1256 break; 1257 case BER_TYPE_ENUMERATED: 1258 if (ober_get_enumerated(root, &v) == -1) { 1259 fprintf(stderr, "<INVALID>\n"); 1260 break; 1261 } 1262 fprintf(stderr, "value %lld\n", v); 1263 break; 1264 case BER_TYPE_BITSTRING: 1265 if (ober_get_bitstring(root, (void *)&buf, &len) == -1) { 1266 fprintf(stderr, "<INVALID>\n"); 1267 break; 1268 } 1269 fprintf(stderr, "hexdump "); 1270 for (i = 0; i < len; i++) 1271 fprintf(stderr, "%02x", buf[i]); 1272 fprintf(stderr, "\n"); 1273 break; 1274 case BER_TYPE_OBJECT: 1275 if (ober_get_oid(root, &o) == -1) { 1276 fprintf(stderr, "<INVALID>\n"); 1277 break; 1278 } 1279 fprintf(stderr, "\n"); 1280 break; 1281 case BER_TYPE_OCTETSTRING: 1282 if (ober_get_nstring(root, (void *)&buf, &len) == -1) { 1283 fprintf(stderr, "<INVALID>\n"); 1284 break; 1285 } 1286 fprintf(stderr, "string \"%.*s\"\n", (int)len, buf); 1287 break; 1288 case BER_TYPE_NULL: /* no payload */ 1289 case BER_TYPE_EOC: 1290 case BER_TYPE_SEQUENCE: 1291 case BER_TYPE_SET: 1292 default: 1293 fprintf(stderr, "\n"); 1294 break; 1295 } 1296 1297 if (constructed && root->be_sub) { 1298 indent += 2; 1299 ldap_debug_elements(root->be_sub); 1300 indent -= 2; 1301 } 1302 if (root->be_next) 1303 ldap_debug_elements(root->be_next); 1304} 1305#endif 1306 1307/* 1308 * Strip UTF-8 down to ASCII without validation. 1309 * notes: 1310 * non-ASCII characters are displayed as '?' 1311 * the argument u should be a NULL terminated sequence of UTF-8 bytes. 1312 */ 1313char * 1314utoa(char *u) 1315{ 1316 int len, i, j; 1317 char *str; 1318 1319 /* calculate the length to allocate */ 1320 for (len = 0, i = 0; u[i] != '\0'; i++) 1321 if (!isu8cont(u[i])) 1322 len++; 1323 1324 if ((str = calloc(len + 1, sizeof(char))) == NULL) 1325 return NULL; 1326 1327 /* copy the ASCII characters to the newly allocated string */ 1328 for (i = 0, j = 0; u[i] != '\0'; i++) 1329 if (!isu8cont(u[i])) 1330 str[j++] = isascii((unsigned char)u[i]) ? u[i] : '?'; 1331 1332 return str; 1333} 1334 1335static int 1336isu8cont(unsigned char c) 1337{ 1338 return (c & (0x80 | 0x40)) == 0x80; 1339} 1340 1341/* 1342 * Parse a LDAP value 1343 * notes: 1344 * the argument p should be a NUL-terminated sequence of ASCII bytes 1345 */ 1346char * 1347parseval(char *p, size_t len) 1348{ 1349 char hex[3]; 1350 char *buffer; 1351 size_t i, j; 1352 1353 if ((buffer = calloc(1, len + 1)) == NULL) 1354 return NULL; 1355 1356 for (i = j = 0; j < len; i++) { 1357 if (p[j] == '\\') { 1358 strlcpy(hex, p + j + 1, sizeof(hex)); 1359 buffer[i] = (char)strtoumax(hex, NULL, 16); 1360 j += 3; 1361 } else { 1362 buffer[i] = p[j]; 1363 j++; 1364 } 1365 } 1366 1367 return buffer; 1368} 1369 1370int 1371aldap_get_errno(struct aldap *a, const char **estr) 1372{ 1373 switch (a->err) { 1374 case ALDAP_ERR_SUCCESS: 1375 *estr = "success"; 1376 break; 1377 case ALDAP_ERR_PARSER_ERROR: 1378 *estr = "parser failed"; 1379 break; 1380 case ALDAP_ERR_INVALID_FILTER: 1381 *estr = "invalid filter"; 1382 break; 1383 case ALDAP_ERR_OPERATION_FAILED: 1384 *estr = "operation failed"; 1385 break; 1386 case ALDAP_ERR_TLS_ERROR: 1387 *estr = tls_error(a->tls); 1388 break; 1389 default: 1390 *estr = "unknown"; 1391 break; 1392 } 1393 return (a->err); 1394} 1395