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