Annotation of src/usr.bin/ldap/aldap.c, Revision 1.1
1.1 ! reyk 1: /* $Id: aldap.c,v 1.39 2018/02/08 18:02:06 jca Exp $ */
! 2: /* $OpenBSD: aldap.c,v 1.39 2018/02/08 18:02:06 jca Exp $ */
! 3:
! 4: /*
! 5: * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
! 6: * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
! 7: *
! 8: * Permission to use, copy, modify, and distribute this software for any
! 9: * purpose with or without fee is hereby granted, provided that the above
! 10: * copyright notice and this permission notice appear in all copies.
! 11: *
! 12: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 13: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 14: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 15: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 16: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 17: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 18: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 19: */
! 20:
! 21: #include <arpa/inet.h>
! 22: #include <ctype.h>
! 23: #include <errno.h>
! 24: #include <inttypes.h>
! 25: #include <string.h>
! 26: #include <stdlib.h>
! 27: #include <unistd.h>
! 28:
! 29: #include <event.h>
! 30:
! 31: #include "aldap.h"
! 32:
! 33: #if 0
! 34: #define DEBUG
! 35: #endif
! 36: #define VERSION 3
! 37:
! 38: static struct ber_element *ldap_parse_search_filter(struct ber_element *,
! 39: char *);
! 40: static struct ber_element *ldap_do_parse_search_filter(
! 41: struct ber_element *, char **);
! 42: char **aldap_get_stringset(struct ber_element *);
! 43: char *utoa(char *);
! 44: static int isu8cont(unsigned char);
! 45: char *parseval(char *, size_t);
! 46: int aldap_create_page_control(struct ber_element *,
! 47: int, struct aldap_page_control *);
! 48: int aldap_send(struct aldap *,
! 49: struct ber_element *);
! 50: unsigned long aldap_application(struct ber_element *);
! 51:
! 52: #ifdef DEBUG
! 53: void ldap_debug_elements(struct ber_element *);
! 54: #endif
! 55:
! 56: #ifdef DEBUG
! 57: #define DPRINTF(x...) printf(x)
! 58: #define LDAP_DEBUG(x, y) do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0)
! 59: #else
! 60: #define DPRINTF(x...) do { } while (0)
! 61: #define LDAP_DEBUG(x, y) do { } while (0)
! 62: #endif
! 63:
! 64: unsigned long
! 65: aldap_application(struct ber_element *elm)
! 66: {
! 67: return BER_TYPE_OCTETSTRING;
! 68: }
! 69:
! 70: int
! 71: aldap_close(struct aldap *al)
! 72: {
! 73: if (al->tls != NULL) {
! 74: tls_close(al->tls);
! 75: tls_free(al->tls);
! 76: }
! 77: close(al->fd);
! 78: ber_free(&al->ber);
! 79: evbuffer_free(al->buf);
! 80: free(al);
! 81:
! 82: return (0);
! 83: }
! 84:
! 85: struct aldap *
! 86: aldap_init(int fd)
! 87: {
! 88: struct aldap *a;
! 89:
! 90: if ((a = calloc(1, sizeof(*a))) == NULL)
! 91: return NULL;
! 92: a->buf = evbuffer_new();
! 93: a->fd = fd;
! 94: ber_set_application(&a->ber, aldap_application);
! 95:
! 96: return a;
! 97: }
! 98:
! 99: int
! 100: aldap_tls(struct aldap *ldap, struct tls_config *cfg, const char *name)
! 101: {
! 102: ldap->tls = tls_client();
! 103: if (ldap->tls == NULL) {
! 104: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 105: return (-1);
! 106: }
! 107:
! 108: if (tls_configure(ldap->tls, cfg) == -1) {
! 109: ldap->err = ALDAP_ERR_TLS_ERROR;
! 110: return (-1);
! 111: }
! 112:
! 113: if (tls_connect_socket(ldap->tls, ldap->fd, name) == -1) {
! 114: ldap->err = ALDAP_ERR_TLS_ERROR;
! 115: return (-1);
! 116: }
! 117:
! 118: if (tls_handshake(ldap->tls) == -1) {
! 119: ldap->err = ALDAP_ERR_TLS_ERROR;
! 120: return (-1);
! 121: }
! 122:
! 123: return (0);
! 124: }
! 125:
! 126: int
! 127: aldap_send(struct aldap *ldap, struct ber_element *root)
! 128: {
! 129: int error, wrote;
! 130: void *ptr;
! 131: char *data;
! 132: size_t len, done;
! 133:
! 134: len = ber_calc_len(root);
! 135: error = ber_write_elements(&ldap->ber, root);
! 136: ber_free_elements(root);
! 137: if (error == -1)
! 138: return -1;
! 139:
! 140: ber_get_writebuf(&ldap->ber, &ptr);
! 141: done = 0;
! 142: data = ptr;
! 143: while (len > 0) {
! 144: if (ldap->tls != NULL) {
! 145: wrote = tls_write(ldap->tls, data + done, len);
! 146: if (wrote == TLS_WANT_POLLIN ||
! 147: wrote == TLS_WANT_POLLOUT)
! 148: continue;
! 149: } else
! 150: wrote = write(ldap->fd, data + done, len);
! 151:
! 152: if (wrote == -1)
! 153: return -1;
! 154:
! 155: len -= wrote;
! 156: done += wrote;
! 157: }
! 158:
! 159: return 0;
! 160: }
! 161:
! 162: int
! 163: aldap_req_starttls(struct aldap *ldap)
! 164: {
! 165: struct ber_element *root = NULL, *ber;
! 166:
! 167: if ((root = ber_add_sequence(NULL)) == NULL)
! 168: goto fail;
! 169:
! 170: ber = ber_printf_elements(root, "d{tst", ++ldap->msgid, BER_CLASS_APP,
! 171: (unsigned long) LDAP_REQ_EXTENDED, LDAP_STARTTLS_OID,
! 172: BER_CLASS_CONTEXT, (unsigned long) 0);
! 173: if (ber == NULL) {
! 174: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 175: goto fail;
! 176: }
! 177:
! 178: if (aldap_send(ldap, root) == -1)
! 179: goto fail;
! 180:
! 181: return (ldap->msgid);
! 182: fail:
! 183: if (root != NULL)
! 184: ber_free_elements(root);
! 185:
! 186: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 187: return (-1);
! 188: }
! 189:
! 190: int
! 191: aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
! 192: {
! 193: struct ber_element *root = NULL, *elm;
! 194:
! 195: if (binddn == NULL)
! 196: binddn = "";
! 197: if (bindcred == NULL)
! 198: bindcred = "";
! 199:
! 200: if ((root = ber_add_sequence(NULL)) == NULL)
! 201: goto fail;
! 202:
! 203: elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP,
! 204: (unsigned long)LDAP_REQ_BIND, VERSION, binddn, bindcred,
! 205: BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE);
! 206: if (elm == NULL)
! 207: goto fail;
! 208:
! 209: LDAP_DEBUG("aldap_bind", root);
! 210:
! 211: if (aldap_send(ldap, root) == -1) {
! 212: root = NULL;
! 213: goto fail;
! 214: }
! 215: return (ldap->msgid);
! 216: fail:
! 217: if (root != NULL)
! 218: ber_free_elements(root);
! 219:
! 220: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 221: return (-1);
! 222: }
! 223:
! 224: int
! 225: aldap_unbind(struct aldap *ldap)
! 226: {
! 227: struct ber_element *root = NULL, *elm;
! 228:
! 229: if ((root = ber_add_sequence(NULL)) == NULL)
! 230: goto fail;
! 231: elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
! 232: LDAP_REQ_UNBIND_30);
! 233: if (elm == NULL)
! 234: goto fail;
! 235:
! 236: LDAP_DEBUG("aldap_unbind", root);
! 237:
! 238: if (aldap_send(ldap, root) == -1) {
! 239: root = NULL;
! 240: goto fail;
! 241: }
! 242: return (ldap->msgid);
! 243: fail:
! 244: if (root != NULL)
! 245: ber_free_elements(root);
! 246:
! 247: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 248:
! 249: return (-1);
! 250: }
! 251:
! 252: int
! 253: aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
! 254: char **attrs, int typesonly, int sizelimit, int timelimit,
! 255: struct aldap_page_control *page)
! 256: {
! 257: struct ber_element *root = NULL, *ber, *c;
! 258: int i;
! 259:
! 260: if ((root = ber_add_sequence(NULL)) == NULL)
! 261: goto fail;
! 262:
! 263: ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
! 264: (unsigned long) LDAP_REQ_SEARCH);
! 265: if (ber == NULL) {
! 266: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 267: goto fail;
! 268: }
! 269:
! 270: c = ber;
! 271: ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope,
! 272: (long long)LDAP_DEREF_NEVER, sizelimit,
! 273: timelimit, typesonly);
! 274: if (ber == NULL) {
! 275: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 276: goto fail;
! 277: }
! 278:
! 279: if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) {
! 280: ldap->err = ALDAP_ERR_PARSER_ERROR;
! 281: goto fail;
! 282: }
! 283:
! 284: if ((ber = ber_add_sequence(ber)) == NULL)
! 285: goto fail;
! 286: if (attrs != NULL)
! 287: for (i = 0; attrs[i] != NULL; i++) {
! 288: if ((ber = ber_add_string(ber, attrs[i])) == NULL)
! 289: goto fail;
! 290: }
! 291:
! 292: aldap_create_page_control(c, 100, page);
! 293:
! 294: LDAP_DEBUG("aldap_search", root);
! 295:
! 296: if (aldap_send(ldap, root) == -1) {
! 297: root = NULL;
! 298: ldap->err = ALDAP_ERR_OPERATION_FAILED;
! 299: goto fail;
! 300: }
! 301:
! 302: return (ldap->msgid);
! 303:
! 304: fail:
! 305: if (root != NULL)
! 306: ber_free_elements(root);
! 307:
! 308: return (-1);
! 309: }
! 310:
! 311: int
! 312: aldap_create_page_control(struct ber_element *elm, int size,
! 313: struct aldap_page_control *page)
! 314: {
! 315: int len;
! 316: struct ber c;
! 317: struct ber_element *ber = NULL;
! 318:
! 319: c.br_wbuf = NULL;
! 320:
! 321: ber = ber_add_sequence(NULL);
! 322:
! 323: if (page == NULL) {
! 324: if (ber_printf_elements(ber, "ds", 50, "") == NULL)
! 325: goto fail;
! 326: } else {
! 327: if (ber_printf_elements(ber, "dx", 50, page->cookie,
! 328: page->cookie_len) == NULL)
! 329: goto fail;
! 330: }
! 331:
! 332: if ((len = ber_write_elements(&c, ber)) < 1)
! 333: goto fail;
! 334: if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
! 335: c.br_wbuf, (size_t)len) == NULL)
! 336: goto fail;
! 337:
! 338: ber_free_elements(ber);
! 339: ber_free(&c);
! 340: return len;
! 341: fail:
! 342: if (ber != NULL)
! 343: ber_free_elements(ber);
! 344: ber_free(&c);
! 345:
! 346: return (-1);
! 347: }
! 348:
! 349: struct aldap_message *
! 350: aldap_parse(struct aldap *ldap)
! 351: {
! 352: int class;
! 353: unsigned long type;
! 354: long long msgid = 0;
! 355: struct aldap_message *m;
! 356: struct ber_element *a = NULL, *ep;
! 357: char rbuf[512];
! 358: int ret, retry;
! 359:
! 360: if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
! 361: return NULL;
! 362:
! 363: retry = 0;
! 364: while (m->msg == NULL) {
! 365: if (retry || EVBUFFER_LENGTH(ldap->buf) == 0) {
! 366: if (ldap->tls) {
! 367: ret = tls_read(ldap->tls, rbuf, sizeof(rbuf));
! 368: if (ret == TLS_WANT_POLLIN ||
! 369: ret == TLS_WANT_POLLOUT)
! 370: continue;
! 371: } else
! 372: ret = read(ldap->fd, rbuf, sizeof(rbuf));
! 373:
! 374: if (ret == -1) {
! 375: goto parsefail;
! 376: }
! 377:
! 378: evbuffer_add(ldap->buf, rbuf, ret);
! 379: }
! 380:
! 381: if (EVBUFFER_LENGTH(ldap->buf) > 0) {
! 382: ber_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf),
! 383: EVBUFFER_LENGTH(ldap->buf));
! 384: errno = 0;
! 385: m->msg = ber_read_elements(&ldap->ber, NULL);
! 386: if (errno != 0 && errno != ECANCELED) {
! 387: goto parsefail;
! 388: }
! 389:
! 390: retry = 1;
! 391: }
! 392: }
! 393:
! 394: evbuffer_drain(ldap->buf, ldap->ber.br_rptr - ldap->ber.br_rbuf);
! 395:
! 396: LDAP_DEBUG("message", m->msg);
! 397:
! 398: if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
! 399: goto parsefail;
! 400: m->msgid = msgid;
! 401: m->message_type = type;
! 402: m->protocol_op = a;
! 403:
! 404: switch (m->message_type) {
! 405: case LDAP_RES_BIND:
! 406: case LDAP_RES_MODIFY:
! 407: case LDAP_RES_ADD:
! 408: case LDAP_RES_DELETE:
! 409: case LDAP_RES_MODRDN:
! 410: case LDAP_RES_COMPARE:
! 411: case LDAP_RES_SEARCH_RESULT:
! 412: if (ber_scanf_elements(m->protocol_op, "{EeSeSe",
! 413: &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0)
! 414: goto parsefail;
! 415: if (m->body.res.rescode == LDAP_REFERRAL)
! 416: if (ber_scanf_elements(a, "{e", &m->references) != 0)
! 417: goto parsefail;
! 418: if (m->msg->be_sub) {
! 419: for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
! 420: ber_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 (ber_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 (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
! 435: goto parsefail;
! 436: break;
! 437: case LDAP_RES_EXTENDED:
! 438: if (ber_scanf_elements(m->protocol_op, "{E",
! 439: &m->body.res.rescode) != 0) {
! 440: goto parsefail;
! 441: }
! 442: break;
! 443: }
! 444:
! 445: return m;
! 446: parsefail:
! 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:
! 453: struct aldap_page_control *
! 454: aldap_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: ber_scanf_elements(control, "ss", &oid, &encoded);
! 464: ber_set_readbuf(&b, encoded, control->be_next->be_len);
! 465: elm = ber_read_elements(&b, NULL);
! 466:
! 467: if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
! 468: if (elm != NULL)
! 469: ber_free_elements(elm);
! 470: ber_free(&b);
! 471: return NULL;
! 472: }
! 473:
! 474: ber_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: ber_free_elements(elm);
! 480: ber_free(&b);
! 481: free(page);
! 482: return NULL;
! 483: }
! 484: memcpy(page->cookie, s, page->cookie_len);
! 485:
! 486: ber_free_elements(elm);
! 487: ber_free(&b);
! 488: return page;
! 489: }
! 490:
! 491: void
! 492: aldap_freepage(struct aldap_page_control *page)
! 493: {
! 494: free(page->cookie);
! 495: free(page);
! 496: }
! 497:
! 498: void
! 499: aldap_freemsg(struct aldap_message *msg)
! 500: {
! 501: if (msg->msg)
! 502: ber_free_elements(msg->msg);
! 503: free(msg);
! 504: }
! 505:
! 506: int
! 507: aldap_get_resultcode(struct aldap_message *msg)
! 508: {
! 509: return msg->body.res.rescode;
! 510: }
! 511:
! 512: char *
! 513: aldap_get_dn(struct aldap_message *msg)
! 514: {
! 515: char *dn;
! 516:
! 517: if (msg->dn == NULL)
! 518: return NULL;
! 519:
! 520: if (ber_get_string(msg->dn, &dn) == -1)
! 521: return NULL;
! 522:
! 523: return utoa(dn);
! 524: }
! 525:
! 526: char **
! 527: aldap_get_references(struct aldap_message *msg)
! 528: {
! 529: if (msg->references == NULL)
! 530: return NULL;
! 531: return aldap_get_stringset(msg->references);
! 532: }
! 533:
! 534: void
! 535: aldap_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:
! 548: char *
! 549: aldap_get_diagmsg(struct aldap_message *msg)
! 550: {
! 551: char *s;
! 552:
! 553: if (msg->body.res.diagmsg == NULL)
! 554: return NULL;
! 555:
! 556: if (ber_get_string(msg->body.res.diagmsg, &s) == -1)
! 557: return NULL;
! 558:
! 559: return utoa(s);
! 560: }
! 561:
! 562: int
! 563: aldap_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 && ber_get_eoc(a) != 0;
! 573: i++, a = a->be_next)
! 574: ;
! 575:
! 576: return i;
! 577: }
! 578:
! 579: int
! 580: aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
! 581: {
! 582: struct ber_element *b, *c;
! 583: char *key;
! 584: char **ret;
! 585:
! 586: if (msg->body.search.attrs == NULL)
! 587: goto fail;
! 588:
! 589: if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e",
! 590: &key, &b, &c) != 0)
! 591: goto fail;
! 592:
! 593: msg->body.search.iter = msg->body.search.attrs->be_next;
! 594:
! 595: if ((ret = aldap_get_stringset(b)) == NULL)
! 596: goto fail;
! 597:
! 598: (*outvalues) = ret;
! 599: (*outkey) = utoa(key);
! 600:
! 601: return (1);
! 602: fail:
! 603: (*outkey) = NULL;
! 604: (*outvalues) = NULL;
! 605: return (-1);
! 606: }
! 607:
! 608: int
! 609: aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
! 610: {
! 611: struct ber_element *a, *b;
! 612: char *key;
! 613: char **ret;
! 614:
! 615: if (msg->body.search.iter == NULL)
! 616: goto notfound;
! 617:
! 618: LDAP_DEBUG("attr", msg->body.search.iter);
! 619:
! 620: if (ber_get_eoc(msg->body.search.iter) == 0)
! 621: goto notfound;
! 622:
! 623: if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b)
! 624: != 0)
! 625: goto fail;
! 626:
! 627: msg->body.search.iter = msg->body.search.iter->be_next;
! 628:
! 629: if ((ret = aldap_get_stringset(a)) == NULL)
! 630: goto fail;
! 631:
! 632: (*outvalues) = ret;
! 633: (*outkey) = utoa(key);
! 634:
! 635: return (1);
! 636: fail:
! 637: notfound:
! 638: (*outkey) = NULL;
! 639: (*outvalues) = NULL;
! 640: return (-1);
! 641: }
! 642:
! 643: int
! 644: aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues)
! 645: {
! 646: struct ber_element *a, *b;
! 647: char *descr = NULL;
! 648: char **ret;
! 649:
! 650: if (msg->body.search.attrs == NULL)
! 651: goto fail;
! 652:
! 653: LDAP_DEBUG("attr", msg->body.search.attrs);
! 654:
! 655: for (a = msg->body.search.attrs;;) {
! 656: if (a == NULL)
! 657: goto notfound;
! 658: if (ber_get_eoc(a) == 0)
! 659: goto notfound;
! 660: if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0)
! 661: goto fail;
! 662: if (strcasecmp(descr, inkey) == 0)
! 663: goto attrfound;
! 664: a = a->be_next;
! 665: }
! 666:
! 667: attrfound:
! 668: if ((ret = aldap_get_stringset(b)) == NULL)
! 669: goto fail;
! 670:
! 671: (*outvalues) = ret;
! 672:
! 673: return (1);
! 674: fail:
! 675: notfound:
! 676: (*outvalues) = NULL;
! 677: return (-1);
! 678: }
! 679:
! 680: int
! 681: aldap_free_attr(char **values)
! 682: {
! 683: int i;
! 684:
! 685: if (values == NULL)
! 686: return -1;
! 687:
! 688: for (i = 0; values[i] != NULL; i++)
! 689: free(values[i]);
! 690:
! 691: free(values);
! 692:
! 693: return (1);
! 694: }
! 695:
! 696: void
! 697: aldap_free_url(struct aldap_url *lu)
! 698: {
! 699: free(lu->buffer);
! 700: }
! 701:
! 702: int
! 703: aldap_parse_url(const char *url, struct aldap_url *lu)
! 704: {
! 705: char *p, *forward, *forward2;
! 706: const char *errstr = NULL;
! 707: int i;
! 708:
! 709: if ((lu->buffer = p = strdup(url)) == NULL)
! 710: return (-1);
! 711:
! 712: /* protocol */
! 713: if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) {
! 714: lu->protocol = LDAP;
! 715: p += strlen(LDAP_URL);
! 716: } else if (strncasecmp(LDAPS_URL, p, strlen(LDAPS_URL)) == 0) {
! 717: lu->protocol = LDAPS;
! 718: p += strlen(LDAPS_URL);
! 719: } else if (strncasecmp(LDAPTLS_URL, p, strlen(LDAPTLS_URL)) == 0) {
! 720: lu->protocol = LDAPTLS;
! 721: p += strlen(LDAPTLS_URL);
! 722: } else if (strncasecmp(LDAPI_URL, p, strlen(LDAPI_URL)) == 0) {
! 723: lu->protocol = LDAPI;
! 724: p += strlen(LDAPI_URL);
! 725: } else
! 726: lu->protocol = -1;
! 727:
! 728: /* host and optional port */
! 729: if ((forward = strchr(p, '/')) != NULL)
! 730: *forward = '\0';
! 731: /* find the optional port */
! 732: if ((forward2 = strchr(p, ':')) != NULL) {
! 733: *forward2 = '\0';
! 734: /* if a port is given */
! 735: if (*(forward2+1) != '\0') {
! 736: #define PORT_MAX UINT16_MAX
! 737: lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
! 738: if (errstr)
! 739: goto fail;
! 740: }
! 741: }
! 742: /* fail if no host is given */
! 743: if (strlen(p) == 0)
! 744: goto fail;
! 745: lu->host = p;
! 746: if (forward == NULL)
! 747: goto done;
! 748: /* p is assigned either a pointer to a character or to '\0' */
! 749: p = ++forward;
! 750: if (strlen(p) == 0)
! 751: goto done;
! 752:
! 753: /* dn */
! 754: if ((forward = strchr(p, '?')) != NULL)
! 755: *forward = '\0';
! 756: lu->dn = p;
! 757: if (forward == NULL)
! 758: goto done;
! 759: /* p is assigned either a pointer to a character or to '\0' */
! 760: p = ++forward;
! 761: if (strlen(p) == 0)
! 762: goto done;
! 763:
! 764: /* attributes */
! 765: if ((forward = strchr(p, '?')) != NULL)
! 766: *forward = '\0';
! 767: for (i = 0; i < MAXATTR; i++) {
! 768: if ((forward2 = strchr(p, ',')) == NULL) {
! 769: if (strlen(p) == 0)
! 770: break;
! 771: lu->attributes[i] = p;
! 772: break;
! 773: }
! 774: *forward2 = '\0';
! 775: lu->attributes[i] = p;
! 776: p = ++forward2;
! 777: }
! 778: if (forward == NULL)
! 779: goto done;
! 780: /* p is assigned either a pointer to a character or to '\0' */
! 781: p = ++forward;
! 782: if (strlen(p) == 0)
! 783: goto done;
! 784:
! 785: /* scope */
! 786: if ((forward = strchr(p, '?')) != NULL)
! 787: *forward = '\0';
! 788: if (strcmp(p, "base") == 0)
! 789: lu->scope = LDAP_SCOPE_BASE;
! 790: else if (strcmp(p, "one") == 0)
! 791: lu->scope = LDAP_SCOPE_ONELEVEL;
! 792: else if (strcmp(p, "sub") == 0)
! 793: lu->scope = LDAP_SCOPE_SUBTREE;
! 794: else
! 795: goto fail;
! 796: if (forward == NULL)
! 797: goto done;
! 798: p = ++forward;
! 799: if (strlen(p) == 0)
! 800: goto done;
! 801:
! 802: /* filter */
! 803: if (p)
! 804: lu->filter = p;
! 805: done:
! 806: return (1);
! 807: fail:
! 808: free(lu->buffer);
! 809: lu->buffer = NULL;
! 810: return (-1);
! 811: }
! 812:
! 813: int
! 814: aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit,
! 815: int timelimit, struct aldap_page_control *page)
! 816: {
! 817: struct aldap_url *lu;
! 818:
! 819: if ((lu = calloc(1, sizeof(*lu))) == NULL)
! 820: return (-1);
! 821:
! 822: if (aldap_parse_url(url, lu))
! 823: goto fail;
! 824:
! 825: if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes,
! 826: typesonly, sizelimit, timelimit, page) == -1)
! 827: goto fail;
! 828:
! 829: aldap_free_url(lu);
! 830: return (ldap->msgid);
! 831: fail:
! 832: aldap_free_url(lu);
! 833: return (-1);
! 834: }
! 835:
! 836: /*
! 837: * internal functions
! 838: */
! 839:
! 840: char **
! 841: aldap_get_stringset(struct ber_element *elm)
! 842: {
! 843: struct ber_element *a;
! 844: int i;
! 845: char **ret;
! 846: char *s;
! 847:
! 848: if (elm->be_type != BER_TYPE_OCTETSTRING)
! 849: return NULL;
! 850:
! 851: for (a = elm, i = 1; i > 0 && a != NULL && a->be_type ==
! 852: BER_TYPE_OCTETSTRING; a = a->be_next, i++)
! 853: ;
! 854: if (i == 1)
! 855: return NULL;
! 856:
! 857: if ((ret = calloc(i + 1, sizeof(char *))) == NULL)
! 858: return NULL;
! 859:
! 860: for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
! 861: a = a->be_next, i++) {
! 862:
! 863: ber_get_string(a, &s);
! 864: ret[i] = utoa(s);
! 865: }
! 866: ret[i + 1] = NULL;
! 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: */
! 878: static struct ber_element *
! 879: ldap_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: ber_free_elements(elm);
! 896: ber_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: */
! 920: static struct ber_element *
! 921: ldap_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 = ber_add_set(prev)) == NULL)
! 944: goto callfail;
! 945: root = elm;
! 946: ber_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 = ber_add_sequence(prev)) == NULL)
! 963: goto callfail;
! 964: ber_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: ber_add_nstring(prev, attr_desc, len)) == NULL)
! 1007: goto bad;
! 1008:
! 1009: ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
! 1010: break;
! 1011: }
! 1012:
! 1013: if ((root = ber_add_sequence(prev)) == NULL)
! 1014: goto callfail;
! 1015: ber_set_header(root, BER_CLASS_CONTEXT, type);
! 1016:
! 1017: if ((elm = ber_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: ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
! 1033:
! 1034: if ((elm = ber_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 = ber_add_nstring(elm, parsed_val,
! 1062: strlen(parsed_val));
! 1063: free(parsed_val);
! 1064: if (elm == NULL)
! 1065: goto callfail;
! 1066: ber_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 = ber_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:
! 1087: syntaxfail: /* XXX -- error reporting */
! 1088: callfail:
! 1089: bad:
! 1090: if (root != NULL)
! 1091: ber_free_elements(root);
! 1092: ber_link_elements(prev, NULL);
! 1093: return (NULL);
! 1094: }
! 1095:
! 1096: #ifdef DEBUG
! 1097: /*
! 1098: * Display a list of ber elements.
! 1099: *
! 1100: */
! 1101: void
! 1102: ldap_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: ber_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 (%lu) 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, "(%lu) encoding %lu ",
! 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 (ber_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 (ber_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 (ber_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 (ber_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 (ber_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 (ber_get_nstring(root, (void *)&buf, &len) == -1) {
! 1283: fprintf(stderr, "<INVALID>\n");
! 1284: break;
! 1285: }
! 1286: fprintf(stderr, "string \"%.*s\"\n", 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: */
! 1313: char *
! 1314: utoa(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:
! 1335: static int
! 1336: isu8cont(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: */
! 1346: char *
! 1347: parseval(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:
! 1370: int
! 1371: aldap_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: }