Annotation of src/usr.bin/ldap/aldap.c, Revision 1.10
1.10 ! martijn 1: /* $OpenBSD: aldap.c,v 1.9 2019/10/24 12:39:26 tb Exp $ */
1.1 reyk 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:
37: static struct ber_element *ldap_parse_search_filter(struct ber_element *,
38: char *);
39: static struct ber_element *ldap_do_parse_search_filter(
40: struct ber_element *, char **);
1.6 martijn 41: struct aldap_stringset *aldap_get_stringset(struct ber_element *);
1.1 reyk 42: char *utoa(char *);
43: static int isu8cont(unsigned char);
44: char *parseval(char *, size_t);
45: int aldap_create_page_control(struct ber_element *,
46: int, struct aldap_page_control *);
47: int aldap_send(struct aldap *,
48: struct ber_element *);
1.3 claudio 49: unsigned int aldap_application(struct ber_element *);
1.1 reyk 50:
51: #ifdef DEBUG
52: void 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:
1.3 claudio 63: unsigned int
1.1 reyk 64: aldap_application(struct ber_element *elm)
65: {
66: return BER_TYPE_OCTETSTRING;
67: }
68:
69: int
70: aldap_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);
1.9 tb 77: ober_free(&al->ber);
1.1 reyk 78: evbuffer_free(al->buf);
79: free(al);
80:
81: return (0);
82: }
83:
84: struct aldap *
85: aldap_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;
1.9 tb 93: ober_set_application(&a->ber, aldap_application);
1.1 reyk 94:
95: return a;
96: }
97:
98: int
99: aldap_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:
125: int
126: aldap_send(struct aldap *ldap, struct ber_element *root)
127: {
128: void *ptr;
129: char *data;
130: size_t len, done;
1.5 rob 131: ssize_t error, wrote;
1.1 reyk 132:
1.9 tb 133: len = ober_calc_len(root);
134: error = ober_write_elements(&ldap->ber, root);
135: ober_free_elements(root);
1.1 reyk 136: if (error == -1)
137: return -1;
138:
1.9 tb 139: ober_get_writebuf(&ldap->ber, &ptr);
1.1 reyk 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:
161: int
162: aldap_req_starttls(struct aldap *ldap)
163: {
164: struct ber_element *root = NULL, *ber;
165:
1.9 tb 166: if ((root = ober_add_sequence(NULL)) == NULL)
1.1 reyk 167: goto fail;
168:
1.9 tb 169: ber = ober_printf_elements(root, "d{tst", ++ldap->msgid, BER_CLASS_APP,
1.3 claudio 170: LDAP_REQ_EXTENDED, LDAP_STARTTLS_OID, BER_CLASS_CONTEXT, 0);
1.1 reyk 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);
180: fail:
181: if (root != NULL)
1.9 tb 182: ober_free_elements(root);
1.1 reyk 183:
184: ldap->err = ALDAP_ERR_OPERATION_FAILED;
185: return (-1);
186: }
187:
188: int
189: aldap_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:
1.9 tb 198: if ((root = ober_add_sequence(NULL)) == NULL)
1.1 reyk 199: goto fail;
200:
1.9 tb 201: elm = ober_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP,
1.3 claudio 202: LDAP_REQ_BIND, VERSION, binddn, bindcred, BER_CLASS_CONTEXT,
203: LDAP_AUTH_SIMPLE);
1.1 reyk 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);
214: fail:
215: if (root != NULL)
1.9 tb 216: ober_free_elements(root);
1.1 reyk 217:
218: ldap->err = ALDAP_ERR_OPERATION_FAILED;
219: return (-1);
220: }
221:
222: int
223: aldap_unbind(struct aldap *ldap)
224: {
225: struct ber_element *root = NULL, *elm;
226:
1.9 tb 227: if ((root = ober_add_sequence(NULL)) == NULL)
1.1 reyk 228: goto fail;
1.9 tb 229: elm = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
1.1 reyk 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);
241: fail:
242: if (root != NULL)
1.9 tb 243: ober_free_elements(root);
1.1 reyk 244:
245: ldap->err = ALDAP_ERR_OPERATION_FAILED;
246:
247: return (-1);
248: }
249:
250: int
251: aldap_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:
1.9 tb 258: if ((root = ober_add_sequence(NULL)) == NULL)
1.1 reyk 259: goto fail;
260:
1.9 tb 261: ber = ober_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
1.3 claudio 262: LDAP_REQ_SEARCH);
1.1 reyk 263: if (ber == NULL) {
264: ldap->err = ALDAP_ERR_OPERATION_FAILED;
265: goto fail;
266: }
267:
268: c = ber;
1.9 tb 269: ber = ober_printf_elements(ber, "sEEddb", basedn, (long long)scope,
1.1 reyk 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:
1.9 tb 282: if ((ber = ober_add_sequence(ber)) == NULL)
1.1 reyk 283: goto fail;
284: if (attrs != NULL)
285: for (i = 0; attrs[i] != NULL; i++) {
1.9 tb 286: if ((ber = ober_add_string(ber, attrs[i])) == NULL)
1.1 reyk 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:
302: fail:
303: if (root != NULL)
1.9 tb 304: ober_free_elements(root);
1.1 reyk 305:
306: return (-1);
307: }
308:
309: int
310: aldap_create_page_control(struct ber_element *elm, int size,
311: struct aldap_page_control *page)
312: {
1.5 rob 313: ssize_t len;
1.1 reyk 314: struct ber c;
315: struct ber_element *ber = NULL;
316:
317: c.br_wbuf = NULL;
318:
1.9 tb 319: ber = ober_add_sequence(NULL);
1.1 reyk 320:
321: if (page == NULL) {
1.9 tb 322: if (ober_printf_elements(ber, "ds", 50, "") == NULL)
1.1 reyk 323: goto fail;
324: } else {
1.9 tb 325: if (ober_printf_elements(ber, "dx", 50, page->cookie,
1.1 reyk 326: page->cookie_len) == NULL)
327: goto fail;
328: }
329:
1.9 tb 330: if ((len = ober_write_elements(&c, ber)) < 1)
1.1 reyk 331: goto fail;
1.9 tb 332: if (ober_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
1.1 reyk 333: c.br_wbuf, (size_t)len) == NULL)
334: goto fail;
335:
1.9 tb 336: ober_free_elements(ber);
337: ober_free(&c);
1.1 reyk 338: return len;
339: fail:
340: if (ber != NULL)
1.9 tb 341: ober_free_elements(ber);
342: ober_free(&c);
1.1 reyk 343:
344: return (-1);
345: }
346:
347: struct aldap_message *
348: aldap_parse(struct aldap *ldap)
349: {
350: int class;
1.3 claudio 351: unsigned int type;
1.1 reyk 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) {
1.9 tb 380: ober_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf),
1.1 reyk 381: EVBUFFER_LENGTH(ldap->buf));
382: errno = 0;
1.9 tb 383: m->msg = ober_read_elements(&ldap->ber, NULL);
1.1 reyk 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:
1.9 tb 396: if (ober_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
1.1 reyk 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:
1.9 tb 410: if (ober_scanf_elements(m->protocol_op, "{EeSe",
1.8 martijn 411: &m->body.res.rescode, &m->dn, &m->body.res.diagmsg) != 0)
1.1 reyk 412: goto parsefail;
1.8 martijn 413: if (m->body.res.rescode == LDAP_REFERRAL) {
414: a = m->body.res.diagmsg->be_next;
1.9 tb 415: if (ober_scanf_elements(a, "{e", &m->references) != 0)
1.1 reyk 416: goto parsefail;
1.8 martijn 417: }
1.1 reyk 418: if (m->msg->be_sub) {
419: for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
1.9 tb 420: ober_scanf_elements(ep, "t", &class, &type);
1.1 reyk 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:
1.9 tb 429: if (ober_scanf_elements(m->protocol_op, "{eS{e", &m->dn,
1.1 reyk 430: &m->body.search.attrs) != 0)
431: goto parsefail;
432: break;
433: case LDAP_RES_SEARCH_REFERENCE:
1.9 tb 434: if (ober_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
1.1 reyk 435: goto parsefail;
436: break;
437: case LDAP_RES_EXTENDED:
1.9 tb 438: if (ober_scanf_elements(m->protocol_op, "{E",
1.1 reyk 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;
1.9 tb 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);
1.1 reyk 466:
467: if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
468: if (elm != NULL)
1.9 tb 469: ober_free_elements(elm);
470: ober_free(&b);
1.1 reyk 471: return NULL;
472: }
473:
1.9 tb 474: ober_scanf_elements(elm->be_sub, "is", &page->size, &s);
1.1 reyk 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)
1.9 tb 479: ober_free_elements(elm);
480: ober_free(&b);
1.1 reyk 481: free(page);
482: return NULL;
483: }
484: memcpy(page->cookie, s, page->cookie_len);
485:
1.9 tb 486: ober_free_elements(elm);
487: ober_free(&b);
1.1 reyk 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)
1.9 tb 502: ober_free_elements(msg->msg);
1.1 reyk 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:
1.9 tb 520: if (ober_get_string(msg->dn, &dn) == -1)
1.1 reyk 521: return NULL;
522:
523: return utoa(dn);
524: }
525:
1.6 martijn 526: struct aldap_stringset *
1.1 reyk 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:
1.9 tb 556: if (ober_get_string(msg->body.res.diagmsg, &s) == -1)
1.1 reyk 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;
1.9 tb 572: a != NULL && ober_get_eoc(a) != 0;
1.1 reyk 573: i++, a = a->be_next)
574: ;
575:
576: return i;
577: }
578:
579: int
1.6 martijn 580: aldap_first_attr(struct aldap_message *msg, char **outkey,
581: struct aldap_stringset **outvalues)
1.1 reyk 582: {
1.10 ! martijn 583: struct ber_element *b;
1.1 reyk 584: char *key;
1.6 martijn 585: struct aldap_stringset *ret;
1.1 reyk 586:
587: if (msg->body.search.attrs == NULL)
588: goto fail;
589:
1.10 ! martijn 590: if (ober_scanf_elements(msg->body.search.attrs, "{s(e)}",
! 591: &key, &b) != 0)
1.1 reyk 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);
603: fail:
604: (*outkey) = NULL;
605: (*outvalues) = NULL;
606: return (-1);
607: }
608:
609: int
1.6 martijn 610: aldap_next_attr(struct aldap_message *msg, char **outkey,
611: struct aldap_stringset **outvalues)
1.1 reyk 612: {
1.10 ! martijn 613: struct ber_element *a;
1.1 reyk 614: char *key;
1.6 martijn 615: struct aldap_stringset *ret;
1.1 reyk 616:
617: if (msg->body.search.iter == NULL)
618: goto notfound;
619:
620: LDAP_DEBUG("attr", msg->body.search.iter);
621:
1.9 tb 622: if (ober_get_eoc(msg->body.search.iter) == 0)
1.1 reyk 623: goto notfound;
624:
1.10 ! martijn 625: if (ober_scanf_elements(msg->body.search.iter, "{s(e)}", &key, &a) != 0)
1.1 reyk 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);
637: fail:
638: notfound:
639: (*outkey) = NULL;
640: (*outvalues) = NULL;
641: return (-1);
642: }
643:
644: int
1.6 martijn 645: aldap_match_attr(struct aldap_message *msg, char *inkey,
646: struct aldap_stringset **outvalues)
1.1 reyk 647: {
648: struct ber_element *a, *b;
649: char *descr = NULL;
1.6 martijn 650: struct aldap_stringset *ret;
1.1 reyk 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;
1.9 tb 660: if (ober_get_eoc(a) == 0)
1.1 reyk 661: goto notfound;
1.9 tb 662: if (ober_scanf_elements(a, "{s(e", &descr, &b) != 0)
1.1 reyk 663: goto fail;
664: if (strcasecmp(descr, inkey) == 0)
665: goto attrfound;
666: a = a->be_next;
667: }
668:
669: attrfound:
670: if ((ret = aldap_get_stringset(b)) == NULL)
671: goto fail;
672:
673: (*outvalues) = ret;
674:
675: return (1);
676: fail:
677: notfound:
678: (*outvalues) = NULL;
679: return (-1);
680: }
681:
682: int
1.6 martijn 683: aldap_free_attr(struct aldap_stringset *values)
1.1 reyk 684: {
685: if (values == NULL)
686: return -1;
687:
1.6 martijn 688: free(values->str);
1.1 reyk 689: free(values);
690:
691: return (1);
692: }
693:
694: void
695: aldap_free_url(struct aldap_url *lu)
696: {
697: free(lu->buffer);
698: }
699:
700: int
701: aldap_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;
803: done:
804: return (1);
805: fail:
806: free(lu->buffer);
807: lu->buffer = NULL;
808: return (-1);
809: }
810:
811: int
812: aldap_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);
829: fail:
830: aldap_free_url(lu);
831: return (-1);
832: }
833:
834: /*
835: * internal functions
836: */
837:
1.6 martijn 838: struct aldap_stringset *
1.1 reyk 839: aldap_get_stringset(struct ber_element *elm)
840: {
841: struct ber_element *a;
842: int i;
1.6 martijn 843: struct aldap_stringset *ret;
1.1 reyk 844:
845: if (elm->be_type != BER_TYPE_OCTETSTRING)
846: return NULL;
847:
1.6 martijn 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++)
1.1 reyk 852: ;
1.6 martijn 853: if (ret->len == 0) {
854: free(ret);
1.1 reyk 855: return NULL;
1.6 martijn 856: }
1.1 reyk 857:
1.6 martijn 858: if ((ret->str = reallocarray(NULL, ret->len,
859: sizeof(*(ret->str)))) == NULL) {
860: free(ret);
1.1 reyk 861: return NULL;
1.6 martijn 862: }
1.1 reyk 863:
864: for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
1.6 martijn 865: a = a->be_next, i++)
1.9 tb 866: (void) ober_get_ostring(a, &(ret->str[i]));
1.1 reyk 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') {
1.9 tb 895: ober_free_elements(elm);
896: ober_link_elements(ber, NULL);
1.1 reyk 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:
1.9 tb 943: if ((elm = ober_add_set(prev)) == NULL)
1.1 reyk 944: goto callfail;
945: root = elm;
1.9 tb 946: ober_set_header(elm, BER_CLASS_CONTEXT, type);
1.1 reyk 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 */
1.9 tb 962: if ((root = ober_add_sequence(prev)) == NULL)
1.1 reyk 963: goto callfail;
1.9 tb 964: ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
1.1 reyk 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 =
1.9 tb 1006: ober_add_nstring(prev, attr_desc, len)) == NULL)
1.1 reyk 1007: goto bad;
1008:
1.9 tb 1009: ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
1.1 reyk 1010: break;
1011: }
1012:
1.9 tb 1013: if ((root = ober_add_sequence(prev)) == NULL)
1.1 reyk 1014: goto callfail;
1.9 tb 1015: ober_set_header(root, BER_CLASS_CONTEXT, type);
1.1 reyk 1016:
1.9 tb 1017: if ((elm = ober_add_nstring(root, attr_desc, len)) == NULL)
1.1 reyk 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:
1.9 tb 1032: ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
1.1 reyk 1033:
1.9 tb 1034: if ((elm = ober_add_sequence(elm)) == NULL)
1.1 reyk 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;
1.9 tb 1061: elm = ober_add_nstring(elm, parsed_val,
1.1 reyk 1062: strlen(parsed_val));
1063: free(parsed_val);
1064: if (elm == NULL)
1065: goto callfail;
1.9 tb 1066: ober_set_header(elm, BER_CLASS_CONTEXT, type);
1.1 reyk 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;
1.9 tb 1075: elm = ober_add_nstring(elm, parsed_val, strlen(parsed_val));
1.1 reyk 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)
1.9 tb 1091: ober_free_elements(root);
1092: ober_link_elements(prev, NULL);
1.1 reyk 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 */
1.9 tb 1114: ober_calc_len(root);
1.1 reyk 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);
1.4 rob 1221: fprintf(stderr, "encoding (%u) type: ", root->be_encoding);
1.1 reyk 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: }
1.4 rob 1236: fprintf(stderr, "(%u) encoding %u ",
1.1 reyk 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:
1.9 tb 1244: if (ober_get_boolean(root, &d) == -1) {
1.1 reyk 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:
1.9 tb 1251: if (ober_get_integer(root, &v) == -1) {
1.1 reyk 1252: fprintf(stderr, "<INVALID>\n");
1253: break;
1254: }
1255: fprintf(stderr, "value %lld\n", v);
1256: break;
1257: case BER_TYPE_ENUMERATED:
1.9 tb 1258: if (ober_get_enumerated(root, &v) == -1) {
1.1 reyk 1259: fprintf(stderr, "<INVALID>\n");
1260: break;
1261: }
1262: fprintf(stderr, "value %lld\n", v);
1263: break;
1264: case BER_TYPE_BITSTRING:
1.9 tb 1265: if (ober_get_bitstring(root, (void *)&buf, &len) == -1) {
1.1 reyk 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:
1.9 tb 1275: if (ober_get_oid(root, &o) == -1) {
1.1 reyk 1276: fprintf(stderr, "<INVALID>\n");
1277: break;
1278: }
1279: fprintf(stderr, "\n");
1280: break;
1281: case BER_TYPE_OCTETSTRING:
1.9 tb 1282: if (ober_get_nstring(root, (void *)&buf, &len) == -1) {
1.1 reyk 1283: fprintf(stderr, "<INVALID>\n");
1284: break;
1285: }
1.2 reyk 1286: fprintf(stderr, "string \"%.*s\"\n", (int)len, buf);
1.1 reyk 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: }