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