Annotation of src/usr.bin/ldap/aldap.c, Revision 1.7
1.7 ! tedu 1: /* $OpenBSD: aldap.c,v 1.6 2018/11/27 12:04:57 martijn 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);
77: ber_free(&al->ber);
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;
93: ber_set_application(&a->ber, aldap_application);
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:
133: len = ber_calc_len(root);
134: error = ber_write_elements(&ldap->ber, root);
135: ber_free_elements(root);
136: if (error == -1)
137: return -1;
138:
139: ber_get_writebuf(&ldap->ber, &ptr);
140: done = 0;
141: data = ptr;
142: while (len > 0) {
143: if (ldap->tls != NULL) {
144: wrote = tls_write(ldap->tls, data + done, len);
145: if (wrote == TLS_WANT_POLLIN ||
146: wrote == TLS_WANT_POLLOUT)
147: continue;
148: } else
149: wrote = write(ldap->fd, data + done, len);
150:
151: if (wrote == -1)
152: return -1;
153:
154: len -= wrote;
155: done += wrote;
156: }
157:
158: return 0;
159: }
160:
161: int
162: aldap_req_starttls(struct aldap *ldap)
163: {
164: struct ber_element *root = NULL, *ber;
165:
166: if ((root = ber_add_sequence(NULL)) == NULL)
167: goto fail;
168:
169: ber = ber_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)
182: ber_free_elements(root);
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:
198: if ((root = ber_add_sequence(NULL)) == NULL)
199: goto fail;
200:
201: elm = ber_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)
216: ber_free_elements(root);
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:
227: if ((root = ber_add_sequence(NULL)) == NULL)
228: goto fail;
229: elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
230: LDAP_REQ_UNBIND_30);
231: if (elm == NULL)
232: goto fail;
233:
234: LDAP_DEBUG("aldap_unbind", root);
235:
236: if (aldap_send(ldap, root) == -1) {
237: root = NULL;
238: goto fail;
239: }
240: return (ldap->msgid);
241: fail:
242: if (root != NULL)
243: ber_free_elements(root);
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:
258: if ((root = ber_add_sequence(NULL)) == NULL)
259: goto fail;
260:
261: ber = ber_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;
269: ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope,
270: (long long)LDAP_DEREF_NEVER, sizelimit,
271: timelimit, typesonly);
272: if (ber == NULL) {
273: ldap->err = ALDAP_ERR_OPERATION_FAILED;
274: goto fail;
275: }
276:
277: if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) {
278: ldap->err = ALDAP_ERR_PARSER_ERROR;
279: goto fail;
280: }
281:
282: if ((ber = ber_add_sequence(ber)) == NULL)
283: goto fail;
284: if (attrs != NULL)
285: for (i = 0; attrs[i] != NULL; i++) {
286: if ((ber = ber_add_string(ber, attrs[i])) == NULL)
287: goto fail;
288: }
289:
290: aldap_create_page_control(c, 100, page);
291:
292: LDAP_DEBUG("aldap_search", root);
293:
294: if (aldap_send(ldap, root) == -1) {
295: root = NULL;
296: ldap->err = ALDAP_ERR_OPERATION_FAILED;
297: goto fail;
298: }
299:
300: return (ldap->msgid);
301:
302: fail:
303: if (root != NULL)
304: ber_free_elements(root);
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:
319: ber = ber_add_sequence(NULL);
320:
321: if (page == NULL) {
322: if (ber_printf_elements(ber, "ds", 50, "") == NULL)
323: goto fail;
324: } else {
325: if (ber_printf_elements(ber, "dx", 50, page->cookie,
326: page->cookie_len) == NULL)
327: goto fail;
328: }
329:
330: if ((len = ber_write_elements(&c, ber)) < 1)
331: goto fail;
332: if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
333: c.br_wbuf, (size_t)len) == NULL)
334: goto fail;
335:
336: ber_free_elements(ber);
337: ber_free(&c);
338: return len;
339: fail:
340: if (ber != NULL)
341: ber_free_elements(ber);
342: ber_free(&c);
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) {
380: ber_set_readbuf(&ldap->ber, EVBUFFER_DATA(ldap->buf),
381: EVBUFFER_LENGTH(ldap->buf));
382: errno = 0;
383: m->msg = ber_read_elements(&ldap->ber, NULL);
384: if (errno != 0 && errno != ECANCELED) {
385: goto parsefail;
386: }
387:
388: retry = 1;
389: }
390: }
391:
392: evbuffer_drain(ldap->buf, ldap->ber.br_rptr - ldap->ber.br_rbuf);
393:
394: LDAP_DEBUG("message", m->msg);
395:
396: if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
397: goto parsefail;
398: m->msgid = msgid;
399: m->message_type = type;
400: m->protocol_op = a;
401:
402: switch (m->message_type) {
403: case LDAP_RES_BIND:
404: case LDAP_RES_MODIFY:
405: case LDAP_RES_ADD:
406: case LDAP_RES_DELETE:
407: case LDAP_RES_MODRDN:
408: case LDAP_RES_COMPARE:
409: case LDAP_RES_SEARCH_RESULT:
410: if (ber_scanf_elements(m->protocol_op, "{EeSeSe",
411: &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0)
412: goto parsefail;
413: if (m->body.res.rescode == LDAP_REFERRAL)
414: if (ber_scanf_elements(a, "{e", &m->references) != 0)
415: goto parsefail;
416: if (m->msg->be_sub) {
417: for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
418: ber_scanf_elements(ep, "t", &class, &type);
419: if (class == 2 && type == 0)
420: m->page = aldap_parse_page_control(ep->be_sub->be_sub,
421: ep->be_sub->be_sub->be_len);
422: }
423: } else
424: m->page = NULL;
425: break;
426: case LDAP_RES_SEARCH_ENTRY:
427: if (ber_scanf_elements(m->protocol_op, "{eS{e", &m->dn,
428: &m->body.search.attrs) != 0)
429: goto parsefail;
430: break;
431: case LDAP_RES_SEARCH_REFERENCE:
432: if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
433: goto parsefail;
434: break;
435: case LDAP_RES_EXTENDED:
436: if (ber_scanf_elements(m->protocol_op, "{E",
437: &m->body.res.rescode) != 0) {
438: goto parsefail;
439: }
440: break;
441: }
442:
443: return m;
444: parsefail:
445: evbuffer_drain(ldap->buf, EVBUFFER_LENGTH(ldap->buf));
446: ldap->err = ALDAP_ERR_PARSER_ERROR;
447: aldap_freemsg(m);
448: return NULL;
449: }
450:
451: struct aldap_page_control *
452: aldap_parse_page_control(struct ber_element *control, size_t len)
453: {
454: char *oid, *s;
455: char *encoded;
456: struct ber b;
457: struct ber_element *elm;
458: struct aldap_page_control *page;
459:
460: b.br_wbuf = NULL;
461: ber_scanf_elements(control, "ss", &oid, &encoded);
462: ber_set_readbuf(&b, encoded, control->be_next->be_len);
463: elm = ber_read_elements(&b, NULL);
464:
465: if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
466: if (elm != NULL)
467: ber_free_elements(elm);
468: ber_free(&b);
469: return NULL;
470: }
471:
472: ber_scanf_elements(elm->be_sub, "is", &page->size, &s);
473: page->cookie_len = elm->be_sub->be_next->be_len;
474:
475: if ((page->cookie = malloc(page->cookie_len)) == NULL) {
476: if (elm != NULL)
477: ber_free_elements(elm);
478: ber_free(&b);
479: free(page);
480: return NULL;
481: }
482: memcpy(page->cookie, s, page->cookie_len);
483:
484: ber_free_elements(elm);
485: ber_free(&b);
486: return page;
487: }
488:
489: void
490: aldap_freepage(struct aldap_page_control *page)
491: {
492: free(page->cookie);
493: free(page);
494: }
495:
496: void
497: aldap_freemsg(struct aldap_message *msg)
498: {
499: if (msg->msg)
500: ber_free_elements(msg->msg);
501: free(msg);
502: }
503:
504: int
505: aldap_get_resultcode(struct aldap_message *msg)
506: {
507: return msg->body.res.rescode;
508: }
509:
510: char *
511: aldap_get_dn(struct aldap_message *msg)
512: {
513: char *dn;
514:
515: if (msg->dn == NULL)
516: return NULL;
517:
518: if (ber_get_string(msg->dn, &dn) == -1)
519: return NULL;
520:
521: return utoa(dn);
522: }
523:
1.6 martijn 524: struct aldap_stringset *
1.1 reyk 525: aldap_get_references(struct aldap_message *msg)
526: {
527: if (msg->references == NULL)
528: return NULL;
529: return aldap_get_stringset(msg->references);
530: }
531:
532: void
533: aldap_free_references(char **values)
534: {
535: int i;
536:
537: if (values == NULL)
538: return;
539:
540: for (i = 0; values[i] != NULL; i++)
541: free(values[i]);
542:
543: free(values);
544: }
545:
546: char *
547: aldap_get_diagmsg(struct aldap_message *msg)
548: {
549: char *s;
550:
551: if (msg->body.res.diagmsg == NULL)
552: return NULL;
553:
554: if (ber_get_string(msg->body.res.diagmsg, &s) == -1)
555: return NULL;
556:
557: return utoa(s);
558: }
559:
560: int
561: aldap_count_attrs(struct aldap_message *msg)
562: {
563: int i;
564: struct ber_element *a;
565:
566: if (msg->body.search.attrs == NULL)
567: return (-1);
568:
569: for (i = 0, a = msg->body.search.attrs;
570: a != NULL && ber_get_eoc(a) != 0;
571: i++, a = a->be_next)
572: ;
573:
574: return i;
575: }
576:
577: int
1.6 martijn 578: aldap_first_attr(struct aldap_message *msg, char **outkey,
579: struct aldap_stringset **outvalues)
1.1 reyk 580: {
581: struct ber_element *b, *c;
582: char *key;
1.6 martijn 583: struct aldap_stringset *ret;
1.1 reyk 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
1.6 martijn 608: aldap_next_attr(struct aldap_message *msg, char **outkey,
609: struct aldap_stringset **outvalues)
1.1 reyk 610: {
611: struct ber_element *a, *b;
612: char *key;
1.6 martijn 613: struct aldap_stringset *ret;
1.1 reyk 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
1.6 martijn 644: aldap_match_attr(struct aldap_message *msg, char *inkey,
645: struct aldap_stringset **outvalues)
1.1 reyk 646: {
647: struct ber_element *a, *b;
648: char *descr = NULL;
1.6 martijn 649: struct aldap_stringset *ret;
1.1 reyk 650:
651: if (msg->body.search.attrs == NULL)
652: goto fail;
653:
654: LDAP_DEBUG("attr", msg->body.search.attrs);
655:
656: for (a = msg->body.search.attrs;;) {
657: if (a == NULL)
658: goto notfound;
659: if (ber_get_eoc(a) == 0)
660: goto notfound;
661: if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0)
662: goto fail;
663: if (strcasecmp(descr, inkey) == 0)
664: goto attrfound;
665: a = a->be_next;
666: }
667:
668: attrfound:
669: if ((ret = aldap_get_stringset(b)) == NULL)
670: goto fail;
671:
672: (*outvalues) = ret;
673:
674: return (1);
675: fail:
676: notfound:
677: (*outvalues) = NULL;
678: return (-1);
679: }
680:
681: int
1.6 martijn 682: aldap_free_attr(struct aldap_stringset *values)
1.1 reyk 683: {
684: if (values == NULL)
685: return -1;
686:
1.6 martijn 687: free(values->str);
1.1 reyk 688: free(values);
689:
690: return (1);
691: }
692:
693: void
694: aldap_free_url(struct aldap_url *lu)
695: {
696: free(lu->buffer);
697: }
698:
699: int
700: aldap_parse_url(const char *url, struct aldap_url *lu)
701: {
702: char *p, *forward, *forward2;
703: const char *errstr = NULL;
704: int i;
705:
706: if ((lu->buffer = p = strdup(url)) == NULL)
707: return (-1);
708:
709: /* protocol */
710: if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) {
711: lu->protocol = LDAP;
712: p += strlen(LDAP_URL);
713: } else if (strncasecmp(LDAPS_URL, p, strlen(LDAPS_URL)) == 0) {
714: lu->protocol = LDAPS;
715: p += strlen(LDAPS_URL);
716: } else if (strncasecmp(LDAPTLS_URL, p, strlen(LDAPTLS_URL)) == 0) {
717: lu->protocol = LDAPTLS;
718: p += strlen(LDAPTLS_URL);
719: } else if (strncasecmp(LDAPI_URL, p, strlen(LDAPI_URL)) == 0) {
720: lu->protocol = LDAPI;
721: p += strlen(LDAPI_URL);
722: } else
723: lu->protocol = -1;
724:
725: /* host and optional port */
726: if ((forward = strchr(p, '/')) != NULL)
727: *forward = '\0';
728: /* find the optional port */
729: if ((forward2 = strchr(p, ':')) != NULL) {
730: *forward2 = '\0';
731: /* if a port is given */
732: if (*(forward2+1) != '\0') {
733: #define PORT_MAX UINT16_MAX
734: lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
735: if (errstr)
736: goto fail;
737: }
738: }
739: /* fail if no host is given */
740: if (strlen(p) == 0)
741: goto fail;
742: lu->host = p;
743: if (forward == NULL)
744: goto done;
745: /* p is assigned either a pointer to a character or to '\0' */
746: p = ++forward;
747: if (strlen(p) == 0)
748: goto done;
749:
750: /* dn */
751: if ((forward = strchr(p, '?')) != NULL)
752: *forward = '\0';
753: lu->dn = p;
754: if (forward == NULL)
755: goto done;
756: /* p is assigned either a pointer to a character or to '\0' */
757: p = ++forward;
758: if (strlen(p) == 0)
759: goto done;
760:
761: /* attributes */
762: if ((forward = strchr(p, '?')) != NULL)
763: *forward = '\0';
764: for (i = 0; i < MAXATTR; i++) {
765: if ((forward2 = strchr(p, ',')) == NULL) {
766: if (strlen(p) == 0)
767: break;
768: lu->attributes[i] = p;
769: break;
770: }
771: *forward2 = '\0';
772: lu->attributes[i] = p;
773: p = ++forward2;
774: }
775: if (forward == NULL)
776: goto done;
777: /* p is assigned either a pointer to a character or to '\0' */
778: p = ++forward;
779: if (strlen(p) == 0)
780: goto done;
781:
782: /* scope */
783: if ((forward = strchr(p, '?')) != NULL)
784: *forward = '\0';
785: if (strcmp(p, "base") == 0)
786: lu->scope = LDAP_SCOPE_BASE;
787: else if (strcmp(p, "one") == 0)
788: lu->scope = LDAP_SCOPE_ONELEVEL;
789: else if (strcmp(p, "sub") == 0)
790: lu->scope = LDAP_SCOPE_SUBTREE;
791: else
792: goto fail;
793: if (forward == NULL)
794: goto done;
795: p = ++forward;
796: if (strlen(p) == 0)
797: goto done;
798:
799: /* filter */
800: if (p)
801: lu->filter = p;
802: done:
803: return (1);
804: fail:
805: free(lu->buffer);
806: lu->buffer = NULL;
807: return (-1);
808: }
809:
810: int
811: aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit,
812: int timelimit, struct aldap_page_control *page)
813: {
814: struct aldap_url *lu;
815:
816: if ((lu = calloc(1, sizeof(*lu))) == NULL)
817: return (-1);
818:
819: if (aldap_parse_url(url, lu))
820: goto fail;
821:
822: if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes,
823: typesonly, sizelimit, timelimit, page) == -1)
824: goto fail;
825:
826: aldap_free_url(lu);
827: return (ldap->msgid);
828: fail:
829: aldap_free_url(lu);
830: return (-1);
831: }
832:
833: /*
834: * internal functions
835: */
836:
1.6 martijn 837: struct aldap_stringset *
1.1 reyk 838: aldap_get_stringset(struct ber_element *elm)
839: {
840: struct ber_element *a;
841: int i;
1.6 martijn 842: struct aldap_stringset *ret;
1.1 reyk 843:
844: if (elm->be_type != BER_TYPE_OCTETSTRING)
845: return NULL;
846:
1.6 martijn 847: if ((ret = malloc(sizeof(*ret))) == NULL)
848: return NULL;
849: for (a = elm, ret->len = 0; a != NULL && a->be_type ==
850: BER_TYPE_OCTETSTRING; a = a->be_next, ret->len++)
1.1 reyk 851: ;
1.6 martijn 852: if (ret->len == 0) {
853: free(ret);
1.1 reyk 854: return NULL;
1.6 martijn 855: }
1.1 reyk 856:
1.6 martijn 857: if ((ret->str = reallocarray(NULL, ret->len,
858: sizeof(*(ret->str)))) == NULL) {
859: free(ret);
1.1 reyk 860: return NULL;
1.6 martijn 861: }
1.1 reyk 862:
863: for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
1.6 martijn 864: a = a->be_next, i++)
865: (void) ber_get_ostring(a, &(ret->str[i]));
1.1 reyk 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: }