Annotation of src/usr.bin/ldap/aldap.c, Revision 1.1.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: }