xref: /openbsd-src/usr.sbin/ypldap/aldap.c (revision d13be5d47e4149db2549a9828e244d59dbc43f15)
1 /*	$Id: aldap.c,v 1.28 2011/08/28 16:37:28 aschrijver Exp $ */
2 /*	$OpenBSD: aldap.c,v 1.28 2011/08/28 16:37:28 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 	ber_free(&al->ber);
59 	free(al);
60 
61 	return (0);
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; 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.attrs) != 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; 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_attrs(struct aldap_message *msg)
316 {
317 	int i;
318 	struct ber_element *a;
319 
320 	if (msg->body.search.attrs == NULL)
321 		return (-1);
322 
323 	for (i = 0, a = msg->body.search.attrs;
324 	    a != NULL && ber_get_eoc(a) != 0;
325 	    i++, a = a->be_next)
326 		;
327 
328 	return i;
329 }
330 
331 int
332 aldap_first_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
333 {
334 	struct ber_element *b, *c;
335 	char *key;
336 	char **ret;
337 
338 	if (msg->body.search.attrs == NULL)
339 		goto fail;
340 
341 	if (ber_scanf_elements(msg->body.search.attrs, "{s(e)}e",
342 	    &key, &b, &c) != 0)
343 		goto fail;
344 
345 	msg->body.search.iter = msg->body.search.attrs->be_next;
346 
347 	if ((ret = aldap_get_stringset(b)) == NULL)
348 		goto fail;
349 
350 	(*outvalues) = ret;
351 	(*outkey) = utoa(key);
352 
353 	return (1);
354 fail:
355 	(*outkey) = NULL;
356 	(*outvalues) = NULL;
357 	return (-1);
358 }
359 
360 int
361 aldap_next_attr(struct aldap_message *msg, char **outkey, char ***outvalues)
362 {
363 	struct ber_element *a, *b;
364 	char *key;
365 	char **ret;
366 
367 	if (msg->body.search.iter == NULL)
368 		goto notfound;
369 
370 	LDAP_DEBUG("attr", msg->body.search.iter);
371 
372 	if (ber_get_eoc(msg->body.search.iter) == 0)
373 		goto notfound;
374 
375 	if (ber_scanf_elements(msg->body.search.iter, "{s(e)}e", &key, &a, &b)
376 	    != 0)
377 		goto fail;
378 
379 	msg->body.search.iter = msg->body.search.iter->be_next;
380 
381 	if ((ret = aldap_get_stringset(a)) == NULL)
382 		goto fail;
383 
384 	(*outvalues) = ret;
385 	(*outkey) = utoa(key);
386 
387 	return (1);
388 fail:
389 notfound:
390 	(*outkey) = NULL;
391 	(*outvalues) = NULL;
392 	return (-1);
393 }
394 
395 int
396 aldap_match_attr(struct aldap_message *msg, char *inkey, char ***outvalues)
397 {
398 	struct ber_element *a, *b;
399 	char *descr = NULL;
400 	char **ret;
401 
402 	if (msg->body.search.attrs == NULL)
403 		return (-1);
404 
405 	LDAP_DEBUG("attr", msg->body.search.attrs);
406 
407 	for (a = msg->body.search.attrs;;) {
408 		if (a == NULL)
409 			goto notfound;
410 		if (ber_get_eoc(a) == 0)
411 			goto notfound;
412 		if (ber_scanf_elements(a, "{s(e", &descr, &b) != 0)
413 			goto fail;
414 		if (strcasecmp(descr, inkey) == 0)
415 			goto attrfound;
416 		a = a->be_next;
417 	}
418 
419 attrfound:
420 	if ((ret = aldap_get_stringset(b)) == NULL)
421 		goto fail;
422 
423 	(*outvalues) = ret;
424 
425 	return (1);
426 fail:
427 notfound:
428 	(*outvalues) = NULL;
429 	return (-1);
430 }
431 
432 int
433 aldap_free_attr(char **values)
434 {
435 	int i;
436 
437 	if (values == NULL)
438 		return -1;
439 
440 	for (i = 0; values[i] != NULL; i++)
441 		free(values[i]);
442 
443 	free(values);
444 
445 	return (1);
446 }
447 
448 #if 0
449 void
450 aldap_free_url(struct aldap_url *lu)
451 {
452 	free(lu->buffer);
453 	free(lu->filter);
454 }
455 
456 int
457 aldap_parse_url(char *url, struct aldap_url *lu)
458 {
459 	char		*p, *forward, *forward2;
460 	const char	*errstr = NULL;
461 	int		 i;
462 
463 	if ((lu->buffer = p = strdup(url)) == NULL)
464 		return (-1);
465 
466 	/* protocol */
467 	if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) != 0)
468 		goto fail;
469 	lu->protocol = LDAP;
470 	p += strlen(LDAP_URL);
471 
472 	/* host and optional port */
473 	if ((forward = strchr(p, '/')) != NULL)
474 		*forward = '\0';
475 	/* find the optional port */
476 	if ((forward2 = strchr(p, ':')) != NULL) {
477 		*forward2 = '\0';
478 		/* if a port is given */
479 		if (*(forward2+1) != '\0') {
480 #define PORT_MAX UINT16_MAX
481 			lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr);
482 			if (errstr)
483 				goto fail;
484 		}
485 	}
486 	/* fail if no host is given */
487 	if (strlen(p) == 0)
488 		goto fail;
489 	lu->host = p;
490 	if (forward == NULL)
491 		goto done;
492 	/* p is assigned either a pointer to a character or to '\0' */
493 	p = ++forward;
494 	if (strlen(p) == 0)
495 		goto done;
496 
497 	/* dn */
498 	if ((forward = strchr(p, '?')) != NULL)
499 		*forward = '\0';
500 	lu->dn = p;
501 	if (forward == NULL)
502 		goto done;
503 	/* p is assigned either a pointer to a character or to '\0' */
504 	p = ++forward;
505 	if (strlen(p) == 0)
506 		goto done;
507 
508 	/* attributes */
509 	if ((forward = strchr(p, '?')) != NULL)
510 		*forward = '\0';
511 	for (i = 0; i < MAXATTR; i++) {
512 		if ((forward2 = strchr(p, ',')) == NULL) {
513 			if (strlen(p) == 0)
514 				break;
515 			lu->attributes[i] = p;
516 			break;
517 		}
518 		*forward2 = '\0';
519 		lu->attributes[i] = p;
520 		p = ++forward2;
521 	}
522 	if (forward == NULL)
523 		goto done;
524 	/* p is assigned either a pointer to a character or to '\0' */
525 	p = ++forward;
526 	if (strlen(p) == 0)
527 		goto done;
528 
529 	/* scope */
530 	if ((forward = strchr(p, '?')) != NULL)
531 		*forward = '\0';
532 	if (strcmp(p, "base") == 0)
533 		lu->scope = LDAP_SCOPE_BASE;
534 	else if (strcmp(p, "one") == 0)
535 		lu->scope = LDAP_SCOPE_ONELEVEL;
536 	else if (strcmp(p, "sub") == 0)
537 		lu->scope = LDAP_SCOPE_SUBTREE;
538 	else
539 		goto fail;
540 	if (forward == NULL)
541 		goto done;
542 	p = ++forward;
543 	if (strlen(p) == 0)
544 		goto done;
545 
546 	/* filter */
547 	if (p)
548 		lu->filter = p;
549 done:
550 	free(url);
551 	return (1);
552 fail:
553 	free(lu->buffer);
554 	lu->buffer = NULL;
555 	return (-1);
556 }
557 
558 int
559 aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit,
560     int timelimit)
561 {
562 	struct aldap_url *lu;
563 
564 	if ((lu = calloc(1, sizeof(*lu))) == NULL)
565 		return (-1);
566 
567 	if (aldap_parse_url(url, lu))
568 		goto fail;
569 
570 	if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes,
571 	    typesonly, sizelimit, timelimit) == -1)
572 		goto fail;
573 
574 	aldap_free_url(lu);
575 	return (ldap->msgid);
576 fail:
577 	aldap_free_url(lu);
578 	return (-1);
579 }
580 #endif /* 0 */
581 
582 /*
583  * internal functions
584  */
585 
586 char **
587 aldap_get_stringset(struct ber_element *elm)
588 {
589 	struct ber_element *a;
590 	int i;
591 	char **ret;
592 	char *s;
593 
594 	if (elm->be_type != BER_TYPE_OCTETSTRING)
595 		return NULL;
596 
597 	for (a = elm, i = 1; i > 0 && a != NULL && a->be_type ==
598 	    BER_TYPE_OCTETSTRING; a = a->be_next, i++)
599 		;
600 	if (i == 1)
601 		return NULL;
602 
603 	if ((ret = calloc(i + 1, sizeof(char *))) == NULL)
604 		return NULL;
605 
606 	for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING;
607 	    a = a->be_next, i++) {
608 
609 		ber_get_string(a, &s);
610 		ret[i] = utoa(s);
611 	}
612 	ret[i + 1] = NULL;
613 
614 	return ret;
615 }
616 
617 /*
618  * Base case for ldap_do_parse_search_filter
619  *
620  * returns:
621  *	struct ber_element *, ber_element tree
622  *	NULL, parse failed
623  */
624 static struct ber_element *
625 ldap_parse_search_filter(struct ber_element *ber, char *filter)
626 {
627 	struct ber_element *elm;
628 	char *cp;
629 
630 	cp = filter;
631 
632 	if (cp == NULL || *cp == '\0') {
633 		errno = EINVAL;
634 		return (NULL);
635 	}
636 
637 	if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL)
638 		return (NULL);
639 
640 	if (*cp != '\0') {
641 		ber_free_elements(elm);
642 		ber_link_elements(ber, NULL);
643 		errno = EINVAL;
644 		return (NULL);
645 	}
646 
647 	return (elm);
648 }
649 
650 /*
651  * Translate RFC4515 search filter string into ber_element tree
652  *
653  * returns:
654  *	struct ber_element *, ber_element tree
655  *	NULL, parse failed
656  *
657  * notes:
658  *	when cp is passed to a recursive invocation, it is updated
659  *	    to point one character beyond the filter that was passed
660  *	    i.e., cp jumps to "(filter)" upon return
661  *	                               ^
662  *	goto's used to discriminate error-handling based on error type
663  *	doesn't handle extended filters (yet)
664  *
665  */
666 static struct ber_element *
667 ldap_do_parse_search_filter(struct ber_element *prev, char **cpp)
668 {
669 	struct ber_element *elm, *root = NULL;
670 	char *attr_desc, *attr_val, *parsed_val, *cp;
671 	size_t len;
672 	unsigned long type;
673 
674 	root = NULL;
675 
676 	/* cpp should pass in pointer to opening parenthesis of "(filter)" */
677 	cp = *cpp;
678 	if (*cp != '(')
679 		goto syntaxfail;
680 
681 	switch (*++cp) {
682 	case '&':		/* AND */
683 	case '|':		/* OR */
684 		if (*cp == '&')
685 			type = LDAP_FILT_AND;
686 		else
687 			type = LDAP_FILT_OR;
688 
689 		if ((elm = ber_add_set(prev)) == NULL)
690 			goto callfail;
691 		root = elm;
692 		ber_set_header(elm, BER_CLASS_CONTEXT, type);
693 
694 		if (*++cp != '(')		/* opening `(` of filter */
695 			goto syntaxfail;
696 
697 		while (*cp == '(') {
698 			if ((elm =
699 			    ldap_do_parse_search_filter(elm, &cp)) == NULL)
700 				goto bad;
701 		}
702 
703 		if (*cp != ')')			/* trailing `)` of filter */
704 			goto syntaxfail;
705 		break;
706 
707 	case '!':		/* NOT */
708 		if ((root = ber_add_sequence(prev)) == NULL)
709 			goto callfail;
710 		ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
711 
712 		cp++;				/* now points to sub-filter */
713 		if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL)
714 			goto bad;
715 
716 		if (*cp != ')')			/* trailing `)` of filter */
717 			goto syntaxfail;
718 		break;
719 
720 	default:	/* SIMPLE || PRESENCE */
721 		attr_desc = cp;
722 
723 		len = strcspn(cp, "()<>~=");
724 		cp += len;
725 		switch (*cp) {
726 		case '~':
727 			type = LDAP_FILT_APPR;
728 			cp++;
729 			break;
730 		case '<':
731 			type = LDAP_FILT_LE;
732 			cp++;
733 			break;
734 		case '>':
735 			type = LDAP_FILT_GE;
736 			cp++;
737 			break;
738 		case '=':
739 			type = LDAP_FILT_EQ;	/* assume EQ until disproven */
740 			break;
741 		case '(':
742 		case ')':
743 		default:
744 			goto syntaxfail;
745 		}
746 		attr_val = ++cp;
747 
748 		/* presence filter */
749 		if (strncmp(attr_val, "*)", 2) == 0) {
750 			cp++;			/* point to trailing `)` */
751 			if ((root =
752 			    ber_add_nstring(prev, attr_desc, len)) == NULL)
753 				goto bad;
754 
755 			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
756 			break;
757 		}
758 
759 		if ((root = ber_add_sequence(prev)) == NULL)
760 			goto callfail;
761 		ber_set_header(root, BER_CLASS_CONTEXT, type);
762 
763 		if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL)
764 			goto callfail;
765 
766 		len = strcspn(attr_val, "*)");
767 		if (len == 0 && *cp != '*')
768 			goto syntaxfail;
769 		cp += len;
770 		if (*cp == '\0')
771 			goto syntaxfail;
772 
773 		if (*cp == '*') {	/* substring filter */
774 			int initial;
775 
776 			cp = attr_val;
777 
778 			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
779 
780 			if ((elm = ber_add_sequence(elm)) == NULL)
781 				goto callfail;
782 
783 			for (initial = 1;; cp++, initial = 0) {
784 				attr_val = cp;
785 
786 				len = strcspn(attr_val, "*)");
787 				if (len == 0) {
788 					if (*cp == ')')
789 						break;
790 					else
791 						continue;
792 				}
793 				cp += len;
794 				if (*cp == '\0')
795 					goto syntaxfail;
796 
797 				if (initial)
798 					type = LDAP_FILT_SUBS_INIT;
799 				else if (*cp == ')')
800 					type = LDAP_FILT_SUBS_FIN;
801 				else
802 					type = LDAP_FILT_SUBS_ANY;
803 
804 				if ((parsed_val = parseval(attr_val, len)) ==
805 				    NULL)
806 					goto callfail;
807 				elm = ber_add_nstring(elm, parsed_val,
808 				    strlen(parsed_val));
809 				free(parsed_val);
810 				if (elm == NULL)
811 					goto callfail;
812 				ber_set_header(elm, BER_CLASS_CONTEXT, type);
813 				if (type == LDAP_FILT_SUBS_FIN)
814 					break;
815 			}
816 			break;
817 		}
818 
819 		if ((parsed_val = parseval(attr_val, len)) == NULL)
820 			goto callfail;
821 		elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val));
822 		free(parsed_val);
823 		if (elm == NULL)
824 			goto callfail;
825 		break;
826 	}
827 
828 	cp++;		/* now points one char beyond the trailing `)` */
829 
830 	*cpp = cp;
831 	return (root);
832 
833 syntaxfail:		/* XXX -- error reporting */
834 callfail:
835 bad:
836 	if (root != NULL)
837 		ber_free_elements(root);
838 	ber_link_elements(prev, NULL);
839 	return (NULL);
840 }
841 
842 #ifdef DEBUG
843 /*
844  * Display a list of ber elements.
845  *
846  */
847 void
848 ldap_debug_elements(struct ber_element *root)
849 {
850 	static int	 indent = 0;
851 	long long	 v;
852 	int		 d;
853 	char		*buf;
854 	size_t		 len;
855 	u_int		 i;
856 	int		 constructed;
857 	struct ber_oid	 o;
858 
859 	/* calculate lengths */
860 	ber_calc_len(root);
861 
862 	switch (root->be_encoding) {
863 	case BER_TYPE_SEQUENCE:
864 	case BER_TYPE_SET:
865 		constructed = root->be_encoding;
866 		break;
867 	default:
868 		constructed = 0;
869 		break;
870 	}
871 
872 	fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
873 	switch (root->be_class) {
874 	case BER_CLASS_UNIVERSAL:
875 		fprintf(stderr, "class: universal(%u) type: ", root->be_class);
876 		switch (root->be_type) {
877 		case BER_TYPE_EOC:
878 			fprintf(stderr, "end-of-content");
879 			break;
880 		case BER_TYPE_BOOLEAN:
881 			fprintf(stderr, "boolean");
882 			break;
883 		case BER_TYPE_INTEGER:
884 			fprintf(stderr, "integer");
885 			break;
886 		case BER_TYPE_BITSTRING:
887 			fprintf(stderr, "bit-string");
888 			break;
889 		case BER_TYPE_OCTETSTRING:
890 			fprintf(stderr, "octet-string");
891 			break;
892 		case BER_TYPE_NULL:
893 			fprintf(stderr, "null");
894 			break;
895 		case BER_TYPE_OBJECT:
896 			fprintf(stderr, "object");
897 			break;
898 		case BER_TYPE_ENUMERATED:
899 			fprintf(stderr, "enumerated");
900 			break;
901 		case BER_TYPE_SEQUENCE:
902 			fprintf(stderr, "sequence");
903 			break;
904 		case BER_TYPE_SET:
905 			fprintf(stderr, "set");
906 			break;
907 		}
908 		break;
909 	case BER_CLASS_APPLICATION:
910 		fprintf(stderr, "class: application(%u) type: ",
911 		    root->be_class);
912 		switch (root->be_type) {
913 		case LDAP_REQ_BIND:
914 			fprintf(stderr, "bind");
915 			break;
916 		case LDAP_RES_BIND:
917 			fprintf(stderr, "bind");
918 			break;
919 		case LDAP_REQ_UNBIND_30:
920 			break;
921 		case LDAP_REQ_SEARCH:
922 			fprintf(stderr, "search");
923 			break;
924 		case LDAP_RES_SEARCH_ENTRY:
925 			fprintf(stderr, "search_entry");
926 			break;
927 		case LDAP_RES_SEARCH_RESULT:
928 			fprintf(stderr, "search_result");
929 			break;
930 		case LDAP_REQ_MODIFY:
931 			fprintf(stderr, "modify");
932 			break;
933 		case LDAP_RES_MODIFY:
934 			fprintf(stderr, "modify");
935 			break;
936 		case LDAP_REQ_ADD:
937 			fprintf(stderr, "add");
938 			break;
939 		case LDAP_RES_ADD:
940 			fprintf(stderr, "add");
941 			break;
942 		case LDAP_REQ_DELETE_30:
943 			fprintf(stderr, "delete");
944 			break;
945 		case LDAP_RES_DELETE:
946 			fprintf(stderr, "delete");
947 			break;
948 		case LDAP_REQ_MODRDN:
949 			fprintf(stderr, "modrdn");
950 			break;
951 		case LDAP_RES_MODRDN:
952 			fprintf(stderr, "modrdn");
953 			break;
954 		case LDAP_REQ_COMPARE:
955 			fprintf(stderr, "compare");
956 			break;
957 		case LDAP_RES_COMPARE:
958 			fprintf(stderr, "compare");
959 			break;
960 		case LDAP_REQ_ABANDON_30:
961 			fprintf(stderr, "abandon");
962 			break;
963 		}
964 		break;
965 	case BER_CLASS_PRIVATE:
966 		fprintf(stderr, "class: private(%u) type: ", root->be_class);
967 		fprintf(stderr, "encoding (%lu) type: ", root->be_encoding);
968 		break;
969 	case BER_CLASS_CONTEXT:
970 		/* XXX: this is not correct */
971 		fprintf(stderr, "class: context(%u) type: ", root->be_class);
972 		switch(root->be_type) {
973 		case LDAP_AUTH_SIMPLE:
974 			fprintf(stderr, "auth simple");
975 			break;
976 		}
977 		break;
978 	default:
979 		fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
980 		break;
981 	}
982 	fprintf(stderr, "(%lu) encoding %lu ",
983 	    root->be_type, root->be_encoding);
984 
985 	if (constructed)
986 		root->be_encoding = constructed;
987 
988 	switch (root->be_encoding) {
989 	case BER_TYPE_BOOLEAN:
990 		if (ber_get_boolean(root, &d) == -1) {
991 			fprintf(stderr, "<INVALID>\n");
992 			break;
993 		}
994 		fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d);
995 		break;
996 	case BER_TYPE_INTEGER:
997 		if (ber_get_integer(root, &v) == -1) {
998 			fprintf(stderr, "<INVALID>\n");
999 			break;
1000 		}
1001 		fprintf(stderr, "value %lld\n", v);
1002 		break;
1003 	case BER_TYPE_ENUMERATED:
1004 		if (ber_get_enumerated(root, &v) == -1) {
1005 			fprintf(stderr, "<INVALID>\n");
1006 			break;
1007 		}
1008 		fprintf(stderr, "value %lld\n", v);
1009 		break;
1010 	case BER_TYPE_BITSTRING:
1011 		if (ber_get_bitstring(root, (void *)&buf, &len) == -1) {
1012 			fprintf(stderr, "<INVALID>\n");
1013 			break;
1014 		}
1015 		fprintf(stderr, "hexdump ");
1016 		for (i = 0; i < len; i++)
1017 			fprintf(stderr, "%02x", buf[i]);
1018 		fprintf(stderr, "\n");
1019 		break;
1020 	case BER_TYPE_OBJECT:
1021 		if (ber_get_oid(root, &o) == -1) {
1022 			fprintf(stderr, "<INVALID>\n");
1023 			break;
1024 		}
1025 		fprintf(stderr, "\n");
1026 		break;
1027 	case BER_TYPE_OCTETSTRING:
1028 		if (ber_get_nstring(root, (void *)&buf, &len) == -1) {
1029 			fprintf(stderr, "<INVALID>\n");
1030 			break;
1031 		}
1032 		fprintf(stderr, "string \"%.*s\"\n",  len, buf);
1033 		break;
1034 	case BER_TYPE_NULL:	/* no payload */
1035 	case BER_TYPE_EOC:
1036 	case BER_TYPE_SEQUENCE:
1037 	case BER_TYPE_SET:
1038 	default:
1039 		fprintf(stderr, "\n");
1040 		break;
1041 	}
1042 
1043 	if (constructed && root->be_sub) {
1044 		indent += 2;
1045 		ldap_debug_elements(root->be_sub);
1046 		indent -= 2;
1047 	}
1048 	if (root->be_next)
1049 		ldap_debug_elements(root->be_next);
1050 }
1051 #endif
1052 
1053 /*
1054  * Convert UTF-8 to ASCII.
1055  * notes:
1056  *	non-ASCII characters are displayed as '?'
1057  *	the argument u should be a NULL terminated sequence of UTF-8 bytes.
1058  */
1059 char *
1060 utoa(char *u)
1061 {
1062 	int	 len, i, j;
1063 	char	*str;
1064 
1065 	/* calculate the length to allocate */
1066 	for (len = 0, i = 0; u[i] != '\0'; ) {
1067 		if ((u[i] & 0xF0) == 0xF0)
1068 			i += 4;
1069 		else if ((u[i] & 0xE0) == 0xE0)
1070 			i += 3;
1071 		else if ((u[i] & 0xC0) == 0xC0)
1072 			i += 2;
1073 		else
1074 			i += 1;
1075 		len++;
1076 	}
1077 
1078 	if ((str = calloc(len + 1, sizeof(char))) == NULL)
1079 		return NULL;
1080 
1081 	/* copy the ASCII characters to the newly allocated string */
1082 	for (i = 0, j = 0; u[i] != '\0'; j++) {
1083 		if ((u[i] & 0xF0) == 0xF0) {
1084 			str[j] = '?';
1085 			i += 4;
1086 		} else if ((u[i] & 0xE0) == 0xE0) {
1087 			str[j] = '?';
1088 			i += 3;
1089 		} else if ((u[i] & 0xC0) == 0xC0) {
1090 			str[j] = '?';
1091 			i += 2;
1092 		} else {
1093 			str[j] =  u[i];
1094 			i += 1;
1095 		}
1096 	}
1097 
1098 	return str;
1099 }
1100 
1101 /*
1102  * Parse a LDAP value
1103  * notes:
1104  *	the argument u should be a NULL terminated sequence of ASCII bytes.
1105  */
1106 char *
1107 parseval(char *p, size_t len)
1108 {
1109 	char	 hex[3];
1110 	char	*cp = p, *buffer, *newbuffer;
1111 	size_t	 size, newsize, i, j;
1112 
1113 	size = 50;
1114 	if ((buffer = calloc(1, size)) == NULL)
1115 		return NULL;
1116 
1117 	for (i = j = 0; j < len; i++) {
1118 		if (i >= size) {
1119 			newsize = size + 1024;
1120 			if ((newbuffer = realloc(buffer, newsize)) == NULL) {
1121 				free(buffer);
1122 				return (NULL);
1123 			}
1124 			buffer = newbuffer;
1125 			size = newsize;
1126 		}
1127 
1128 		if (cp[j] == '\\') {
1129 			strlcpy(hex, cp + j + 1, sizeof(hex));
1130 			buffer[i] = (char)strtoumax(hex, NULL, 16);
1131 			j += 3;
1132 		} else {
1133 			buffer[i] = cp[j];
1134 			j++;
1135 		}
1136 	}
1137 
1138 	return buffer;
1139 }
1140 
1141 int
1142 aldap_get_errno(struct aldap *a, const char **estr)
1143 {
1144 	switch (a->err) {
1145 	case ALDAP_ERR_SUCCESS:
1146 		*estr = "success";
1147 		break;
1148 	case ALDAP_ERR_PARSER_ERROR:
1149 		*estr = "parser failed";
1150 		break;
1151 	case ALDAP_ERR_INVALID_FILTER:
1152 		*estr = "invalid filter";
1153 		break;
1154 	case ALDAP_ERR_OPERATION_FAILED:
1155 		*estr = "operation failed";
1156 		break;
1157 	default:
1158 		*estr = "unknown";
1159 		break;
1160 	}
1161 	return (a->err);
1162 }
1163