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