xref: /freebsd/usr.sbin/ypldap/aldap.c (revision 1f4bcc459a76b7aa664f3fd557684cd0ba6da352)
1 /*	$Id: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
2 /*	$OpenBSD: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
3 /*	$FreeBSD$ */
4 
5 /*
6  * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
7  * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
8  *
9  * Permission to use, copy, modify, and distribute this software for any
10  * purpose with or without fee is hereby granted, provided that the above
11  * copyright notice and this permission notice appear in all copies.
12  *
13  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20  */
21 
22 #include <errno.h>
23 #include <inttypes.h>
24 #include <string.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27 
28 #include "aldap.h"
29 
30 #if 0
31 #define DEBUG
32 #endif
33 #define VERSION 3
34 
35 static struct ber_element	*ldap_parse_search_filter(struct ber_element *,
36 				    char *);
37 static struct ber_element	*ldap_do_parse_search_filter(
38 				    struct ber_element *, char **);
39 char				**aldap_get_stringset(struct ber_element *);
40 char				*utoa(char *);
41 char				*parseval(char *, size_t);
42 int				aldap_create_page_control(struct ber_element *,
43 				    int, struct aldap_page_control *);
44 
45 #ifdef DEBUG
46 void			 ldap_debug_elements(struct ber_element *);
47 #endif
48 
49 #ifdef DEBUG
50 #define DPRINTF(x...)	printf(x)
51 #define LDAP_DEBUG(x, y)	do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0)
52 #else
53 #define DPRINTF(x...)	do { } while (0)
54 #define LDAP_DEBUG(x, y)	do { } while (0)
55 #endif
56 
57 int
58 aldap_close(struct aldap *al)
59 {
60 	if (close(al->ber.fd) == -1)
61 		return (-1);
62 
63 	ber_free(&al->ber);
64 	free(al);
65 
66 	return (0);
67 }
68 
69 struct aldap *
70 aldap_init(int fd)
71 {
72 	struct aldap *a;
73 
74 	if ((a = calloc(1, sizeof(*a))) == NULL)
75 		return NULL;
76 	a->ber.fd = fd;
77 
78 	return a;
79 }
80 
81 int
82 aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
83 {
84 	struct ber_element *root = NULL, *elm;
85 	int error;
86 
87 	if (binddn == NULL)
88 		binddn = "";
89 	if (bindcred == NULL)
90 		bindcred = "";
91 
92 	if ((root = ber_add_sequence(NULL)) == NULL)
93 		goto fail;
94 
95 	elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP,
96 	    (unsigned long)LDAP_REQ_BIND, VERSION, binddn, bindcred,
97 	    BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE);
98 	if (elm == NULL)
99 		goto fail;
100 
101 	LDAP_DEBUG("aldap_bind", root);
102 
103 	error = ber_write_elements(&ldap->ber, root);
104 	ber_free_elements(root);
105 	root = NULL;
106 	if (error == -1)
107 		goto fail;
108 
109 	return (ldap->msgid);
110 fail:
111 	if (root != NULL)
112 		ber_free_elements(root);
113 
114 	ldap->err = ALDAP_ERR_OPERATION_FAILED;
115 	return (-1);
116 }
117 
118 int
119 aldap_unbind(struct aldap *ldap)
120 {
121 	struct ber_element *root = NULL, *elm;
122 	int error;
123 
124 	if ((root = ber_add_sequence(NULL)) == NULL)
125 		goto fail;
126 	elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
127 	    LDAP_REQ_UNBIND_30);
128 	if (elm == NULL)
129 		goto fail;
130 
131 	LDAP_DEBUG("aldap_unbind", root);
132 
133 	error = ber_write_elements(&ldap->ber, root);
134 	ber_free_elements(root);
135 	root = NULL;
136 	if (error == -1)
137 		goto fail;
138 
139 	return (ldap->msgid);
140 fail:
141 	if (root != NULL)
142 		ber_free_elements(root);
143 
144 	ldap->err = ALDAP_ERR_OPERATION_FAILED;
145 
146 	return (-1);
147 }
148 
149 int
150 aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
151     char **attrs, int typesonly, int sizelimit, int timelimit,
152     struct aldap_page_control *page)
153 {
154 	struct ber_element *root = NULL, *ber, *c;
155 	int i, error;
156 
157 	if ((root = ber_add_sequence(NULL)) == NULL)
158 		goto fail;
159 
160 	ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
161 	    (unsigned long) LDAP_REQ_SEARCH);
162 	if (ber == NULL) {
163 		ldap->err = ALDAP_ERR_OPERATION_FAILED;
164 		goto fail;
165 	}
166 
167 	c = ber;
168 	ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope,
169 	                         (long long)LDAP_DEREF_NEVER, sizelimit,
170 				 timelimit, typesonly);
171 	if (ber == NULL) {
172 		ldap->err = ALDAP_ERR_OPERATION_FAILED;
173 		goto fail;
174 	}
175 
176 	if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) {
177 		ldap->err = ALDAP_ERR_PARSER_ERROR;
178 		goto fail;
179 	}
180 
181 	if ((ber = ber_add_sequence(ber)) == NULL)
182 		goto fail;
183 	if (attrs != NULL)
184 		for (i = 0; attrs[i] != NULL; i++) {
185 			if ((ber = ber_add_string(ber, attrs[i])) == NULL)
186 				goto fail;
187 		}
188 
189 	aldap_create_page_control(c, 100, page);
190 
191 	LDAP_DEBUG("aldap_search", root);
192 
193 	error = ber_write_elements(&ldap->ber, root);
194 	ber_free_elements(root);
195 	root = NULL;
196 	if (error == -1) {
197 		ldap->err = ALDAP_ERR_OPERATION_FAILED;
198 		goto fail;
199 	}
200 
201 	return (ldap->msgid);
202 
203 fail:
204 	if (root != NULL)
205 		ber_free_elements(root);
206 
207 	return (-1);
208 }
209 
210 int
211 aldap_create_page_control(struct ber_element *elm, int size,
212     struct aldap_page_control *page)
213 {
214 	int len;
215 	struct ber c;
216 	struct ber_element *ber = NULL;
217 
218 	c.br_wbuf = NULL;
219 	c.fd = -1;
220 
221 	ber = ber_add_sequence(NULL);
222 
223 	if (page == NULL) {
224 		if (ber_printf_elements(ber, "ds", 50, "") == NULL)
225 			goto fail;
226 	} else {
227 		if (ber_printf_elements(ber, "dx", 50, page->cookie,
228 			    page->cookie_len) == NULL)
229 			goto fail;
230 	}
231 
232 	if ((len = ber_write_elements(&c, ber)) < 1)
233 		goto fail;
234 	if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
235 		                c.br_wbuf, (size_t)len) == NULL)
236 		goto fail;
237 
238 	ber_free_elements(ber);
239 	ber_free(&c);
240 	return len;
241 fail:
242 	if (ber != NULL)
243 		ber_free_elements(ber);
244 	ber_free(&c);
245 
246 	return (-1);
247 }
248 
249 struct aldap_message *
250 aldap_parse(struct aldap *ldap)
251 {
252 	int			 class;
253 	unsigned long		 type;
254 	long long		 msgid = 0;
255 	struct aldap_message	*m;
256 	struct ber_element	*a = NULL, *ep;
257 
258 	if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
259 		return NULL;
260 
261 	if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL)
262 		goto parsefail;
263 
264 	LDAP_DEBUG("message", m->msg);
265 
266 	if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
267 		goto parsefail;
268 	m->msgid = msgid;
269 	m->message_type = type;
270 	m->protocol_op = a;
271 
272 	switch (m->message_type) {
273 	case LDAP_RES_BIND:
274 	case LDAP_RES_MODIFY:
275 	case LDAP_RES_ADD:
276 	case LDAP_RES_DELETE:
277 	case LDAP_RES_MODRDN:
278 	case LDAP_RES_COMPARE:
279 	case LDAP_RES_SEARCH_RESULT:
280 		if (ber_scanf_elements(m->protocol_op, "{EeSeSe",
281 		    &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0)
282 			goto parsefail;
283 		if (m->body.res.rescode == LDAP_REFERRAL)
284 			if (ber_scanf_elements(a, "{e", &m->references) != 0)
285 				goto parsefail;
286 		if (m->msg->be_sub) {
287 			for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
288 				ber_scanf_elements(ep, "t", &class, &type);
289 				if (class == 2 && type == 0)
290 					m->page = aldap_parse_page_control(ep->be_sub->be_sub,
291 					    ep->be_sub->be_sub->be_len);
292 			}
293 		} else
294 			m->page = NULL;
295 		break;
296 	case LDAP_RES_SEARCH_ENTRY:
297 		if (ber_scanf_elements(m->protocol_op, "{eS{e", &m->dn,
298 		    &m->body.search.attrs) != 0)
299 			goto parsefail;
300 		break;
301 	case LDAP_RES_SEARCH_REFERENCE:
302 		if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
303 			goto parsefail;
304 		break;
305 	}
306 
307 	return m;
308 parsefail:
309 	ldap->err = ALDAP_ERR_PARSER_ERROR;
310 	aldap_freemsg(m);
311 	return NULL;
312 }
313 
314 struct aldap_page_control *
315 aldap_parse_page_control(struct ber_element *control, size_t len)
316 {
317 	char *oid, *s;
318 	char *encoded;
319 	struct ber b;
320 	struct ber_element *elm;
321 	struct aldap_page_control *page;
322 
323 	b.br_wbuf = NULL;
324 	b.fd = -1;
325 	ber_scanf_elements(control, "ss", &oid, &encoded);
326 	ber_set_readbuf(&b, encoded, control->be_next->be_len);
327 	elm = ber_read_elements(&b, NULL);
328 
329 	if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
330 		if (elm != NULL)
331 			ber_free_elements(elm);
332 		ber_free(&b);
333 		return NULL;
334 	}
335 
336 	ber_scanf_elements(elm->be_sub, "is", &page->size, &s);
337 	page->cookie_len = elm->be_sub->be_next->be_len;
338 
339 	if ((page->cookie = malloc(page->cookie_len)) == NULL) {
340 		if (elm != NULL)
341 			ber_free_elements(elm);
342 		ber_free(&b);
343 		free(page);
344 		return NULL;
345 	}
346 	memcpy(page->cookie, s, page->cookie_len);
347 
348 	ber_free_elements(elm);
349 	ber_free(&b);
350 	return page;
351 }
352 
353 void
354 aldap_freepage(struct aldap_page_control *page)
355 {
356 	free(page->cookie);
357 	free(page);
358 }
359 
360 void
361 aldap_freemsg(struct aldap_message *msg)
362 {
363 	if (msg->msg)
364 		ber_free_elements(msg->msg);
365 	free(msg);
366 }
367 
368 int
369 aldap_get_resultcode(struct aldap_message *msg)
370 {
371 	return msg->body.res.rescode;
372 }
373 
374 char *
375 aldap_get_dn(struct aldap_message *msg)
376 {
377 	char *dn;
378 
379 	if (msg->dn == NULL)
380 		return NULL;
381 
382 	if (ber_get_string(msg->dn, &dn) == -1)
383 		return NULL;
384 
385 	return utoa(dn);
386 }
387 
388 char **
389 aldap_get_references(struct aldap_message *msg)
390 {
391 	if (msg->references == NULL)
392 		return NULL;
393 	return aldap_get_stringset(msg->references);
394 }
395 
396 void
397 aldap_free_references(char **values)
398 {
399 	int i;
400 
401 	if (values == NULL)
402 		return;
403 
404 	for (i = 0; values[i] != NULL; i++)
405 		free(values[i]);
406 
407 	free(values);
408 }
409 
410 char *
411 aldap_get_diagmsg(struct aldap_message *msg)
412 {
413 	char *s;
414 
415 	if (msg->body.res.diagmsg == NULL)
416 		return NULL;
417 
418 	if (ber_get_string(msg->body.res.diagmsg, &s) == -1)
419 		return NULL;
420 
421 	return utoa(s);
422 }
423 
424 int
425 aldap_count_attrs(struct aldap_message *msg)
426 {
427 	int i;
428 	struct ber_element *a;
429 
430 	if (msg->body.search.attrs == NULL)
431 		return (-1);
432 
433 	for (i = 0, a = msg->body.search.attrs;
434 	    a != NULL && ber_get_eoc(a) != 0;
435 	    i++, a = a->be_next)
436 		;
437 
438 	return i;
439 }
440 
441 int
442 aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
443 {
444 	struct ber_element *b, *c;
445 	char *key;
446 	char **ret;
447 
448 	if (msg->body.search.attrs == NULL)
449 		goto fail;
450 
451 	if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e",
452 	    &key, &b, &c) != 0)
453 		goto fail;
454 
455 	msg->body.search.iter = msg->body.search.attrs->be_next;
456 
457 	if ((ret = aldap_get_stringset(b)) == NULL)
458 		goto fail;
459 
460 	(*outvalues) = ret;
461 	(*outkey) = utoa(key);
462 
463 	return (1);
464 fail:
465 	(*outkey) = NULL;
466 	(*outvalues) = NULL;
467 	return (-1);
468 }
469 
470 int
471 aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
472 {
473 	struct ber_element *a, *b;
474 	char *key;
475 	char **ret;
476 
477 	if (msg->body.search.iter == NULL)
478 		goto notfound;
479 
480 	LDAP_DEBUG("attr", msg->body.search.iter);
481 
482 	if (ber_get_eoc(msg->body.search.iter) == 0)
483 		goto notfound;
484 
485 	if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b)
486 	    != 0)
487 		goto fail;
488 
489 	msg->body.search.iter = msg->body.search.iter->be_next;
490 
491 	if ((ret = aldap_get_stringset(a)) == NULL)
492 		goto fail;
493 
494 	(*outvalues) = ret;
495 	(*outkey) = utoa(key);
496 
497 	return (1);
498 fail:
499 notfound:
500 	(*outkey) = NULL;
501 	(*outvalues) = NULL;
502 	return (-1);
503 }
504 
505 int
506 aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues)
507 {
508 	struct ber_element *a, *b;
509 	char *descr = NULL;
510 	char **ret;
511 
512 	if (msg->body.search.attrs == NULL)
513 		goto fail;
514 
515 	LDAP_DEBUG("attr", msg->body.search.attrs);
516 
517 	for (a = msg->body.search.attrs;;) {
518 		if (a == NULL)
519 			goto notfound;
520 		if (ber_get_eoc(a) == 0)
521 			goto notfound;
522 		if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0)
523 			goto fail;
524 		if (strcasecmp(descr, inkey) == 0)
525 			goto attrfound;
526 		a = a->be_next;
527 	}
528 
529 attrfound:
530 	if ((ret = aldap_get_stringset(b)) == NULL)
531 		goto fail;
532 
533 	(*outvalues) = ret;
534 
535 	return (1);
536 fail:
537 notfound:
538 	(*outvalues) = NULL;
539 	return (-1);
540 }
541 
542 int
543 aldap_free_attr(char **values)
544 {
545 	int i;
546 
547 	if (values == NULL)
548 		return -1;
549 
550 	for (i = 0; values[i] != NULL; i++)
551 		free(values[i]);
552 
553 	free(values);
554 
555 	return (1);
556 }
557 
558 #if 0
559 void
560 aldap_free_url(struct aldap_url *lu)
561 {
562 	free(lu->buffer);
563 	free(lu->filter);
564 }
565 
566 int
567 aldap_parse_url(char *url, struct aldap_url *lu)
568 {
569 	char		*p, *forward, *forward2;
570 	const char	*errstr = NULL;
571 	int		 i;
572 
573 	if ((lu->buffer = p = strdup(url)) == NULL)
574 		return (-1);
575 
576 	/* protocol */
577 	if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) != 0)
578 		goto fail;
579 	lu->protocol = LDAP;
580 	p += strlen(LDAP_URL);
581 
582 	/* host and optional port */
583 	if ((forward = strchr(p, '/')) != NULL)
584 		*forward = '\0';
585 	/* find the optional port */
586 	if ((forward2 = strchr(p, ':')) != NULL) {
587 		*forward2 = '\0';
588 		/* if a port is given */
589 		if (*(forward2+1) != '\0') {
590 #define PORT_MAX UINT16_MAX
591 			lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
592 			if (errstr)
593 				goto fail;
594 		}
595 	}
596 	/* fail if no host is given */
597 	if (strlen(p) == 0)
598 		goto fail;
599 	lu->host = p;
600 	if (forward == NULL)
601 		goto done;
602 	/* p is assigned either a pointer to a character or to '\0' */
603 	p = ++forward;
604 	if (strlen(p) == 0)
605 		goto done;
606 
607 	/* dn */
608 	if ((forward = strchr(p, '?')) != NULL)
609 		*forward = '\0';
610 	lu->dn = p;
611 	if (forward == NULL)
612 		goto done;
613 	/* p is assigned either a pointer to a character or to '\0' */
614 	p = ++forward;
615 	if (strlen(p) == 0)
616 		goto done;
617 
618 	/* attributes */
619 	if ((forward = strchr(p, '?')) != NULL)
620 		*forward = '\0';
621 	for (i = 0; i < MAXATTR; i++) {
622 		if ((forward2 = strchr(p, ',')) == NULL) {
623 			if (strlen(p) == 0)
624 				break;
625 			lu->attributes[i] = p;
626 			break;
627 		}
628 		*forward2 = '\0';
629 		lu->attributes[i] = p;
630 		p = ++forward2;
631 	}
632 	if (forward == NULL)
633 		goto done;
634 	/* p is assigned either a pointer to a character or to '\0' */
635 	p = ++forward;
636 	if (strlen(p) == 0)
637 		goto done;
638 
639 	/* scope */
640 	if ((forward = strchr(p, '?')) != NULL)
641 		*forward = '\0';
642 	if (strcmp(p, "base") == 0)
643 		lu->scope = LDAP_SCOPE_BASE;
644 	else if (strcmp(p, "one") == 0)
645 		lu->scope = LDAP_SCOPE_ONELEVEL;
646 	else if (strcmp(p, "sub") == 0)
647 		lu->scope = LDAP_SCOPE_SUBTREE;
648 	else
649 		goto fail;
650 	if (forward == NULL)
651 		goto done;
652 	p = ++forward;
653 	if (strlen(p) == 0)
654 		goto done;
655 
656 	/* filter */
657 	if (p)
658 		lu->filter = p;
659 done:
660 	free(url);
661 	return (1);
662 fail:
663 	free(lu->buffer);
664 	lu->buffer = NULL;
665 	return (-1);
666 }
667 
668 int
669 aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit,
670     int timelimit)
671 {
672 	struct aldap_url *lu;
673 
674 	if ((lu = calloc(1, sizeof(*lu))) == NULL)
675 		return (-1);
676 
677 	if (aldap_parse_url(url, lu))
678 		goto fail;
679 
680 	if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes,
681 	    typesonly, sizelimit, timelimit) == -1)
682 		goto fail;
683 
684 	aldap_free_url(lu);
685 	return (ldap->msgid);
686 fail:
687 	aldap_free_url(lu);
688 	return (-1);
689 }
690 #endif /* 0 */
691 
692 /*
693  * internal functions
694  */
695 
696 char **
697 aldap_get_stringset(struct ber_element *elm)
698 {
699 	struct ber_element *a;
700 	int i;
701 	char **ret;
702 	char *s;
703 
704 	if (elm->be_type != BER_TYPE_OCTETSTRING)
705 		return NULL;
706 
707 	for (a = elm, i = 1; i > 0 && a != NULL && a->be_type ==
708 	    BER_TYPE_OCTETSTRING; a = a->be_next, i++)
709 		;
710 	if (i == 1)
711 		return NULL;
712 
713 	if ((ret = calloc(i + 1, sizeof(char *))) == NULL)
714 		return NULL;
715 
716 	for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
717 	    a = a->be_next, i++) {
718 
719 		ber_get_string(a, &s);
720 		ret[i] = utoa(s);
721 	}
722 	ret[i + 1] = NULL;
723 
724 	return ret;
725 }
726 
727 /*
728  * Base case for ldap_do_parse_search_filter
729  *
730  * returns:
731  *	struct ber_element *, ber_element tree
732  *	NULL, parse failed
733  */
734 static struct ber_element *
735 ldap_parse_search_filter(struct ber_element *ber, char *filter)
736 {
737 	struct ber_element *elm;
738 	char *cp;
739 
740 	cp = filter;
741 
742 	if (cp == NULL || *cp == '\0') {
743 		errno = EINVAL;
744 		return (NULL);
745 	}
746 
747 	if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL)
748 		return (NULL);
749 
750 	if (*cp != '\0') {
751 		ber_free_elements(elm);
752 		ber_link_elements(ber, NULL);
753 		errno = EINVAL;
754 		return (NULL);
755 	}
756 
757 	return (elm);
758 }
759 
760 /*
761  * Translate RFC4515 search filter string into ber_element tree
762  *
763  * returns:
764  *	struct ber_element *, ber_element tree
765  *	NULL, parse failed
766  *
767  * notes:
768  *	when cp is passed to a recursive invocation, it is updated
769  *	    to point one character beyond the filter that was passed
770  *	    i.e., cp jumps to "(filter)" upon return
771  *	                               ^
772  *	goto's used to discriminate error-handling based on error type
773  *	doesn't handle extended filters (yet)
774  *
775  */
776 static struct ber_element *
777 ldap_do_parse_search_filter(struct ber_element *prev, char **cpp)
778 {
779 	struct ber_element *elm, *root = NULL;
780 	char *attr_desc, *attr_val, *parsed_val, *cp;
781 	size_t len;
782 	unsigned long type;
783 
784 	root = NULL;
785 
786 	/* cpp should pass in pointer to opening parenthesis of "(filter)" */
787 	cp = *cpp;
788 	if (*cp != '(')
789 		goto syntaxfail;
790 
791 	switch (*++cp) {
792 	case '&':		/* AND */
793 	case '|':		/* OR */
794 		if (*cp == '&')
795 			type = LDAP_FILT_AND;
796 		else
797 			type = LDAP_FILT_OR;
798 
799 		if ((elm = ber_add_set(prev)) == NULL)
800 			goto callfail;
801 		root = elm;
802 		ber_set_header(elm, BER_CLASS_CONTEXT, type);
803 
804 		if (*++cp != '(')		/* opening `(` of filter */
805 			goto syntaxfail;
806 
807 		while (*cp == '(') {
808 			if ((elm =
809 			    ldap_do_parse_search_filter(elm, &cp)) == NULL)
810 				goto bad;
811 		}
812 
813 		if (*cp != ')')			/* trailing `)` of filter */
814 			goto syntaxfail;
815 		break;
816 
817 	case '!':		/* NOT */
818 		if ((root = ber_add_sequence(prev)) == NULL)
819 			goto callfail;
820 		ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
821 
822 		cp++;				/* now points to sub-filter */
823 		if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL)
824 			goto bad;
825 
826 		if (*cp != ')')			/* trailing `)` of filter */
827 			goto syntaxfail;
828 		break;
829 
830 	default:	/* SIMPLE || PRESENCE */
831 		attr_desc = cp;
832 
833 		len = strcspn(cp, "()<>~=");
834 		cp += len;
835 		switch (*cp) {
836 		case '~':
837 			type = LDAP_FILT_APPR;
838 			cp++;
839 			break;
840 		case '<':
841 			type = LDAP_FILT_LE;
842 			cp++;
843 			break;
844 		case '>':
845 			type = LDAP_FILT_GE;
846 			cp++;
847 			break;
848 		case '=':
849 			type = LDAP_FILT_EQ;	/* assume EQ until disproven */
850 			break;
851 		case '(':
852 		case ')':
853 		default:
854 			goto syntaxfail;
855 		}
856 		attr_val = ++cp;
857 
858 		/* presence filter */
859 		if (strncmp(attr_val, "*)", 2) == 0) {
860 			cp++;			/* point to trailing `)` */
861 			if ((root =
862 			    ber_add_nstring(prev, attr_desc, len)) == NULL)
863 				goto bad;
864 
865 			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
866 			break;
867 		}
868 
869 		if ((root = ber_add_sequence(prev)) == NULL)
870 			goto callfail;
871 		ber_set_header(root, BER_CLASS_CONTEXT, type);
872 
873 		if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL)
874 			goto callfail;
875 
876 		len = strcspn(attr_val, "*)");
877 		if (len == 0 && *cp != '*')
878 			goto syntaxfail;
879 		cp += len;
880 		if (*cp == '\0')
881 			goto syntaxfail;
882 
883 		if (*cp == '*') {	/* substring filter */
884 			int initial;
885 
886 			cp = attr_val;
887 
888 			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
889 
890 			if ((elm = ber_add_sequence(elm)) == NULL)
891 				goto callfail;
892 
893 			for (initial = 1;; cp++, initial = 0) {
894 				attr_val = cp;
895 
896 				len = strcspn(attr_val, "*)");
897 				if (len == 0) {
898 					if (*cp == ')')
899 						break;
900 					else
901 						continue;
902 				}
903 				cp += len;
904 				if (*cp == '\0')
905 					goto syntaxfail;
906 
907 				if (initial)
908 					type = LDAP_FILT_SUBS_INIT;
909 				else if (*cp == ')')
910 					type = LDAP_FILT_SUBS_FIN;
911 				else
912 					type = LDAP_FILT_SUBS_ANY;
913 
914 				if ((parsed_val = parseval(attr_val, len)) ==
915 				    NULL)
916 					goto callfail;
917 				elm = ber_add_nstring(elm, parsed_val,
918 				    strlen(parsed_val));
919 				free(parsed_val);
920 				if (elm == NULL)
921 					goto callfail;
922 				ber_set_header(elm, BER_CLASS_CONTEXT, type);
923 				if (type == LDAP_FILT_SUBS_FIN)
924 					break;
925 			}
926 			break;
927 		}
928 
929 		if ((parsed_val = parseval(attr_val, len)) == NULL)
930 			goto callfail;
931 		elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val));
932 		free(parsed_val);
933 		if (elm == NULL)
934 			goto callfail;
935 		break;
936 	}
937 
938 	cp++;		/* now points one char beyond the trailing `)` */
939 
940 	*cpp = cp;
941 	return (root);
942 
943 syntaxfail:		/* XXX -- error reporting */
944 callfail:
945 bad:
946 	if (root != NULL)
947 		ber_free_elements(root);
948 	ber_link_elements(prev, NULL);
949 	return (NULL);
950 }
951 
952 #ifdef DEBUG
953 /*
954  * Display a list of ber elements.
955  *
956  */
957 void
958 ldap_debug_elements(struct ber_element *root)
959 {
960 	static int	 indent = 0;
961 	long long	 v;
962 	int		 d;
963 	char		*buf;
964 	size_t		 len;
965 	u_int		 i;
966 	int		 constructed;
967 	struct ber_oid	 o;
968 
969 	/* calculate lengths */
970 	ber_calc_len(root);
971 
972 	switch (root->be_encoding) {
973 	case BER_TYPE_SEQUENCE:
974 	case BER_TYPE_SET:
975 		constructed = root->be_encoding;
976 		break;
977 	default:
978 		constructed = 0;
979 		break;
980 	}
981 
982 	fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
983 	switch (root->be_class) {
984 	case BER_CLASS_UNIVERSAL:
985 		fprintf(stderr, "class: universal(%u) type: ", root->be_class);
986 		switch (root->be_type) {
987 		case BER_TYPE_EOC:
988 			fprintf(stderr, "end-of-content");
989 			break;
990 		case BER_TYPE_BOOLEAN:
991 			fprintf(stderr, "boolean");
992 			break;
993 		case BER_TYPE_INTEGER:
994 			fprintf(stderr, "integer");
995 			break;
996 		case BER_TYPE_BITSTRING:
997 			fprintf(stderr, "bit-string");
998 			break;
999 		case BER_TYPE_OCTETSTRING:
1000 			fprintf(stderr, "octet-string");
1001 			break;
1002 		case BER_TYPE_NULL:
1003 			fprintf(stderr, "null");
1004 			break;
1005 		case BER_TYPE_OBJECT:
1006 			fprintf(stderr, "object");
1007 			break;
1008 		case BER_TYPE_ENUMERATED:
1009 			fprintf(stderr, "enumerated");
1010 			break;
1011 		case BER_TYPE_SEQUENCE:
1012 			fprintf(stderr, "sequence");
1013 			break;
1014 		case BER_TYPE_SET:
1015 			fprintf(stderr, "set");
1016 			break;
1017 		}
1018 		break;
1019 	case BER_CLASS_APPLICATION:
1020 		fprintf(stderr, "class: application(%u) type: ",
1021 		    root->be_class);
1022 		switch (root->be_type) {
1023 		case LDAP_REQ_BIND:
1024 			fprintf(stderr, "bind");
1025 			break;
1026 		case LDAP_RES_BIND:
1027 			fprintf(stderr, "bind");
1028 			break;
1029 		case LDAP_REQ_UNBIND_30:
1030 			break;
1031 		case LDAP_REQ_SEARCH:
1032 			fprintf(stderr, "search");
1033 			break;
1034 		case LDAP_RES_SEARCH_ENTRY:
1035 			fprintf(stderr, "search_entry");
1036 			break;
1037 		case LDAP_RES_SEARCH_RESULT:
1038 			fprintf(stderr, "search_result");
1039 			break;
1040 		case LDAP_REQ_MODIFY:
1041 			fprintf(stderr, "modify");
1042 			break;
1043 		case LDAP_RES_MODIFY:
1044 			fprintf(stderr, "modify");
1045 			break;
1046 		case LDAP_REQ_ADD:
1047 			fprintf(stderr, "add");
1048 			break;
1049 		case LDAP_RES_ADD:
1050 			fprintf(stderr, "add");
1051 			break;
1052 		case LDAP_REQ_DELETE_30:
1053 			fprintf(stderr, "delete");
1054 			break;
1055 		case LDAP_RES_DELETE:
1056 			fprintf(stderr, "delete");
1057 			break;
1058 		case LDAP_REQ_MODRDN:
1059 			fprintf(stderr, "modrdn");
1060 			break;
1061 		case LDAP_RES_MODRDN:
1062 			fprintf(stderr, "modrdn");
1063 			break;
1064 		case LDAP_REQ_COMPARE:
1065 			fprintf(stderr, "compare");
1066 			break;
1067 		case LDAP_RES_COMPARE:
1068 			fprintf(stderr, "compare");
1069 			break;
1070 		case LDAP_REQ_ABANDON_30:
1071 			fprintf(stderr, "abandon");
1072 			break;
1073 		}
1074 		break;
1075 	case BER_CLASS_PRIVATE:
1076 		fprintf(stderr, "class: private(%u) type: ", root->be_class);
1077 		fprintf(stderr, "encoding (%lu) type: ", root->be_encoding);
1078 		break;
1079 	case BER_CLASS_CONTEXT:
1080 		/* XXX: this is not correct */
1081 		fprintf(stderr, "class: context(%u) type: ", root->be_class);
1082 		switch(root->be_type) {
1083 		case LDAP_AUTH_SIMPLE:
1084 			fprintf(stderr, "auth simple");
1085 			break;
1086 		}
1087 		break;
1088 	default:
1089 		fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
1090 		break;
1091 	}
1092 	fprintf(stderr, "(%lu) encoding %lu ",
1093 	    root->be_type, root->be_encoding);
1094 
1095 	if (constructed)
1096 		root->be_encoding = constructed;
1097 
1098 	switch (root->be_encoding) {
1099 	case BER_TYPE_BOOLEAN:
1100 		if (ber_get_boolean(root, &d) == -1) {
1101 			fprintf(stderr, "<INVALID>\n");
1102 			break;
1103 		}
1104 		fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d);
1105 		break;
1106 	case BER_TYPE_INTEGER:
1107 		if (ber_get_integer(root, &v) == -1) {
1108 			fprintf(stderr, "<INVALID>\n");
1109 			break;
1110 		}
1111 		fprintf(stderr, "value %lld\n", v);
1112 		break;
1113 	case BER_TYPE_ENUMERATED:
1114 		if (ber_get_enumerated(root, &v) == -1) {
1115 			fprintf(stderr, "<INVALID>\n");
1116 			break;
1117 		}
1118 		fprintf(stderr, "value %lld\n", v);
1119 		break;
1120 	case BER_TYPE_BITSTRING:
1121 		if (ber_get_bitstring(root, (void *)&buf, &len) == -1) {
1122 			fprintf(stderr, "<INVALID>\n");
1123 			break;
1124 		}
1125 		fprintf(stderr, "hexdump ");
1126 		for (i = 0; i < len; i++)
1127 			fprintf(stderr, "%02x", buf[i]);
1128 		fprintf(stderr, "\n");
1129 		break;
1130 	case BER_TYPE_OBJECT:
1131 		if (ber_get_oid(root, &o) == -1) {
1132 			fprintf(stderr, "<INVALID>\n");
1133 			break;
1134 		}
1135 		fprintf(stderr, "\n");
1136 		break;
1137 	case BER_TYPE_OCTETSTRING:
1138 		if (ber_get_nstring(root, (void *)&buf, &len) == -1) {
1139 			fprintf(stderr, "<INVALID>\n");
1140 			break;
1141 		}
1142 		fprintf(stderr, "string \"%.*s\"\n",  len, buf);
1143 		break;
1144 	case BER_TYPE_NULL:	/* no payload */
1145 	case BER_TYPE_EOC:
1146 	case BER_TYPE_SEQUENCE:
1147 	case BER_TYPE_SET:
1148 	default:
1149 		fprintf(stderr, "\n");
1150 		break;
1151 	}
1152 
1153 	if (constructed && root->be_sub) {
1154 		indent += 2;
1155 		ldap_debug_elements(root->be_sub);
1156 		indent -= 2;
1157 	}
1158 	if (root->be_next)
1159 		ldap_debug_elements(root->be_next);
1160 }
1161 #endif
1162 
1163 /*
1164  * Convert UTF-8 to ASCII.
1165  * notes:
1166  *	non-ASCII characters are displayed as '?'
1167  *	the argument u should be a NULL terminated sequence of UTF-8 bytes.
1168  */
1169 char *
1170 utoa(char *u)
1171 {
1172 	int	 len, i, j;
1173 	char	*str;
1174 
1175 	/* calculate the length to allocate */
1176 	for (len = 0, i = 0; u[i] != '\0'; ) {
1177 		if ((u[i] & 0xF0) == 0xF0)
1178 			i += 4;
1179 		else if ((u[i] & 0xE0) == 0xE0)
1180 			i += 3;
1181 		else if ((u[i] & 0xC0) == 0xC0)
1182 			i += 2;
1183 		else
1184 			i += 1;
1185 		len++;
1186 	}
1187 
1188 	if ((str = calloc(len + 1, sizeof(char))) == NULL)
1189 		return NULL;
1190 
1191 	/* copy the ASCII characters to the newly allocated string */
1192 	for (i = 0, j = 0; u[i] != '\0'; j++) {
1193 		if ((u[i] & 0xF0) == 0xF0) {
1194 			str[j] = '?';
1195 			i += 4;
1196 		} else if ((u[i] & 0xE0) == 0xE0) {
1197 			str[j] = '?';
1198 			i += 3;
1199 		} else if ((u[i] & 0xC0) == 0xC0) {
1200 			str[j] = '?';
1201 			i += 2;
1202 		} else {
1203 			str[j] =  u[i];
1204 			i += 1;
1205 		}
1206 	}
1207 
1208 	return str;
1209 }
1210 
1211 /*
1212  * Parse a LDAP value
1213  * notes:
1214  *	the argument u should be a NULL terminated sequence of ASCII bytes.
1215  */
1216 char *
1217 parseval(char *p, size_t len)
1218 {
1219 	char	 hex[3];
1220 	char	*cp = p, *buffer, *newbuffer;
1221 	size_t	 size, newsize, i, j;
1222 
1223 	size = 50;
1224 	if ((buffer = calloc(1, size)) == NULL)
1225 		return NULL;
1226 
1227 	for (i = j = 0; j < len; i++) {
1228 		if (i >= size) {
1229 			newsize = size + 1024;
1230 			if ((newbuffer = realloc(buffer, newsize)) == NULL) {
1231 				free(buffer);
1232 				return (NULL);
1233 			}
1234 			buffer = newbuffer;
1235 			size = newsize;
1236 		}
1237 
1238 		if (cp[j] == '\\') {
1239 			strlcpy(hex, cp + j + 1, sizeof(hex));
1240 			buffer[i] = (char)strtoumax(hex, NULL, 16);
1241 			j += 3;
1242 		} else {
1243 			buffer[i] = cp[j];
1244 			j++;
1245 		}
1246 	}
1247 
1248 	return buffer;
1249 }
1250 
1251 int
1252 aldap_get_errno(struct aldap *a, const char **estr)
1253 {
1254 	switch (a->err) {
1255 	case ALDAP_ERR_SUCCESS:
1256 		*estr = "success";
1257 		break;
1258 	case ALDAP_ERR_PARSER_ERROR:
1259 		*estr = "parser failed";
1260 		break;
1261 	case ALDAP_ERR_INVALID_FILTER:
1262 		*estr = "invalid filter";
1263 		break;
1264 	case ALDAP_ERR_OPERATION_FAILED:
1265 		*estr = "operation failed";
1266 		break;
1267 	default:
1268 		*estr = "unknown";
1269 		break;
1270 	}
1271 	return (a->err);
1272 }
1273