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