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
35static struct ber_element	*ldap_parse_search_filter(struct ber_element *,
36				    char *);
37static struct ber_element	*ldap_do_parse_search_filter(
38				    struct ber_element *, char **);
39char				**aldap_get_stringset(struct ber_element *);
40char				*utoa(char *);
41static int			 isu8cont(unsigned char);
42char				*parseval(char *, size_t);
43int				aldap_create_page_control(struct ber_element *,
44				    int, struct aldap_page_control *);
45
46#ifdef DEBUG
47void			 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
58int
59aldap_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
70struct aldap *
71aldap_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
82int
83aldap_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);
111fail:
112	if (root != NULL)
113		ber_free_elements(root);
114
115	ldap->err = ALDAP_ERR_OPERATION_FAILED;
116	return (-1);
117}
118
119int
120aldap_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);
141fail:
142	if (root != NULL)
143		ber_free_elements(root);
144
145	ldap->err = ALDAP_ERR_OPERATION_FAILED;
146
147	return (-1);
148}
149
150int
151aldap_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
204fail:
205	if (root != NULL)
206		ber_free_elements(root);
207
208	return (-1);
209}
210
211int
212aldap_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;
242fail:
243	if (ber != NULL)
244		ber_free_elements(ber);
245	ber_free(&c);
246
247	return (-1);
248}
249
250struct aldap_message *
251aldap_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;
309parsefail:
310	ldap->err = ALDAP_ERR_PARSER_ERROR;
311	aldap_freemsg(m);
312	return NULL;
313}
314
315struct aldap_page_control *
316aldap_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
354void
355aldap_freepage(struct aldap_page_control *page)
356{
357	free(page->cookie);
358	free(page);
359}
360
361void
362aldap_freemsg(struct aldap_message *msg)
363{
364	if (msg->msg)
365		ber_free_elements(msg->msg);
366	free(msg);
367}
368
369int
370aldap_get_resultcode(struct aldap_message *msg)
371{
372	return msg->body.res.rescode;
373}
374
375char *
376aldap_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
389char **
390aldap_get_references(struct aldap_message *msg)
391{
392	if (msg->references == NULL)
393		return NULL;
394	return aldap_get_stringset(msg->references);
395}
396
397void
398aldap_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
411char *
412aldap_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
425int
426aldap_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
442int
443aldap_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);
465fail:
466	(*outkey) = NULL;
467	(*outvalues) = NULL;
468	return (-1);
469}
470
471int
472aldap_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);
499fail:
500notfound:
501	(*outkey) = NULL;
502	(*outvalues) = NULL;
503	return (-1);
504}
505
506int
507aldap_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
530attrfound:
531	if ((ret = aldap_get_stringset(b)) == NULL)
532		goto fail;
533
534	(*outvalues) = ret;
535
536	return (1);
537fail:
538notfound:
539	(*outvalues) = NULL;
540	return (-1);
541}
542
543int
544aldap_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
560void
561aldap_free_url(struct aldap_url *lu)
562{
563	free(lu->buffer);
564	free(lu->filter);
565}
566
567int
568aldap_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;
660done:
661	free(url);
662	return (1);
663fail:
664	free(lu->buffer);
665	lu->buffer = NULL;
666	return (-1);
667}
668
669int
670aldap_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);
687fail:
688	aldap_free_url(lu);
689	return (-1);
690}
691#endif /* 0 */
692
693/*
694 * internal functions
695 */
696
697char **
698aldap_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) {
719
720		ber_get_string(a, &s);
721		ret[i] = utoa(s);
722		if (ret[i] != NULL)
723			i++;
724
725	}
726	if (i == 0) {
727		free(ret);
728		return NULL;
729	}
730	ret[i] = NULL;
731
732	return ret;
733}
734
735/*
736 * Base case for ldap_do_parse_search_filter
737 *
738 * returns:
739 *	struct ber_element *, ber_element tree
740 *	NULL, parse failed
741 */
742static struct ber_element *
743ldap_parse_search_filter(struct ber_element *ber, char *filter)
744{
745	struct ber_element *elm;
746	char *cp;
747
748	cp = filter;
749
750	if (cp == NULL || *cp == '\0') {
751		errno = EINVAL;
752		return (NULL);
753	}
754
755	if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL)
756		return (NULL);
757
758	if (*cp != '\0') {
759		ber_free_elements(elm);
760		ber_link_elements(ber, NULL);
761		errno = EINVAL;
762		return (NULL);
763	}
764
765	return (elm);
766}
767
768/*
769 * Translate RFC4515 search filter string into ber_element tree
770 *
771 * returns:
772 *	struct ber_element *, ber_element tree
773 *	NULL, parse failed
774 *
775 * notes:
776 *	when cp is passed to a recursive invocation, it is updated
777 *	    to point one character beyond the filter that was passed
778 *	    i.e., cp jumps to "(filter)" upon return
779 *	                               ^
780 *	goto's used to discriminate error-handling based on error type
781 *	doesn't handle extended filters (yet)
782 *
783 */
784static struct ber_element *
785ldap_do_parse_search_filter(struct ber_element *prev, char **cpp)
786{
787	struct ber_element *elm, *root = NULL;
788	char *attr_desc, *attr_val, *parsed_val, *cp;
789	size_t len;
790	unsigned long type;
791
792	root = NULL;
793
794	/* cpp should pass in pointer to opening parenthesis of "(filter)" */
795	cp = *cpp;
796	if (*cp != '(')
797		goto syntaxfail;
798
799	switch (*++cp) {
800	case '&':		/* AND */
801	case '|':		/* OR */
802		if (*cp == '&')
803			type = LDAP_FILT_AND;
804		else
805			type = LDAP_FILT_OR;
806
807		if ((elm = ber_add_set(prev)) == NULL)
808			goto callfail;
809		root = elm;
810		ber_set_header(elm, BER_CLASS_CONTEXT, type);
811
812		if (*++cp != '(')		/* opening `(` of filter */
813			goto syntaxfail;
814
815		while (*cp == '(') {
816			if ((elm =
817			    ldap_do_parse_search_filter(elm, &cp)) == NULL)
818				goto bad;
819		}
820
821		if (*cp != ')')			/* trailing `)` of filter */
822			goto syntaxfail;
823		break;
824
825	case '!':		/* NOT */
826		if ((root = ber_add_sequence(prev)) == NULL)
827			goto callfail;
828		ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT);
829
830		cp++;				/* now points to sub-filter */
831		if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL)
832			goto bad;
833
834		if (*cp != ')')			/* trailing `)` of filter */
835			goto syntaxfail;
836		break;
837
838	default:	/* SIMPLE || PRESENCE */
839		attr_desc = cp;
840
841		len = strcspn(cp, "()<>~=");
842		cp += len;
843		switch (*cp) {
844		case '~':
845			type = LDAP_FILT_APPR;
846			cp++;
847			break;
848		case '<':
849			type = LDAP_FILT_LE;
850			cp++;
851			break;
852		case '>':
853			type = LDAP_FILT_GE;
854			cp++;
855			break;
856		case '=':
857			type = LDAP_FILT_EQ;	/* assume EQ until disproven */
858			break;
859		case '(':
860		case ')':
861		default:
862			goto syntaxfail;
863		}
864		attr_val = ++cp;
865
866		/* presence filter */
867		if (strncmp(attr_val, "*)", 2) == 0) {
868			cp++;			/* point to trailing `)` */
869			if ((root =
870			    ber_add_nstring(prev, attr_desc, len)) == NULL)
871				goto bad;
872
873			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES);
874			break;
875		}
876
877		if ((root = ber_add_sequence(prev)) == NULL)
878			goto callfail;
879		ber_set_header(root, BER_CLASS_CONTEXT, type);
880
881		if ((elm = ber_add_nstring(root, attr_desc, len)) == NULL)
882			goto callfail;
883
884		len = strcspn(attr_val, "*)");
885		if (len == 0 && *cp != '*')
886			goto syntaxfail;
887		cp += len;
888		if (*cp == '\0')
889			goto syntaxfail;
890
891		if (*cp == '*') {	/* substring filter */
892			int initial;
893
894			cp = attr_val;
895
896			ber_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS);
897
898			if ((elm = ber_add_sequence(elm)) == NULL)
899				goto callfail;
900
901			for (initial = 1;; cp++, initial = 0) {
902				attr_val = cp;
903
904				len = strcspn(attr_val, "*)");
905				if (len == 0) {
906					if (*cp == ')')
907						break;
908					else
909						continue;
910				}
911				cp += len;
912				if (*cp == '\0')
913					goto syntaxfail;
914
915				if (initial)
916					type = LDAP_FILT_SUBS_INIT;
917				else if (*cp == ')')
918					type = LDAP_FILT_SUBS_FIN;
919				else
920					type = LDAP_FILT_SUBS_ANY;
921
922				if ((parsed_val = parseval(attr_val, len)) ==
923				    NULL)
924					goto callfail;
925				elm = ber_add_nstring(elm, parsed_val,
926				    strlen(parsed_val));
927				free(parsed_val);
928				if (elm == NULL)
929					goto callfail;
930				ber_set_header(elm, BER_CLASS_CONTEXT, type);
931				if (type == LDAP_FILT_SUBS_FIN)
932					break;
933			}
934			break;
935		}
936
937		if ((parsed_val = parseval(attr_val, len)) == NULL)
938			goto callfail;
939		elm = ber_add_nstring(elm, parsed_val, strlen(parsed_val));
940		free(parsed_val);
941		if (elm == NULL)
942			goto callfail;
943		break;
944	}
945
946	cp++;		/* now points one char beyond the trailing `)` */
947
948	*cpp = cp;
949	return (root);
950
951syntaxfail:		/* XXX -- error reporting */
952callfail:
953bad:
954	if (root != NULL)
955		ber_free_elements(root);
956	ber_link_elements(prev, NULL);
957	return (NULL);
958}
959
960#ifdef DEBUG
961/*
962 * Display a list of ber elements.
963 *
964 */
965void
966ldap_debug_elements(struct ber_element *root)
967{
968	static int	 indent = 0;
969	long long	 v;
970	int		 d;
971	char		*buf;
972	size_t		 len;
973	u_int		 i;
974	int		 constructed;
975	struct ber_oid	 o;
976
977	/* calculate lengths */
978	ber_calc_len(root);
979
980	switch (root->be_encoding) {
981	case BER_TYPE_SEQUENCE:
982	case BER_TYPE_SET:
983		constructed = root->be_encoding;
984		break;
985	default:
986		constructed = 0;
987		break;
988	}
989
990	fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
991	switch (root->be_class) {
992	case BER_CLASS_UNIVERSAL:
993		fprintf(stderr, "class: universal(%u) type: ", root->be_class);
994		switch (root->be_type) {
995		case BER_TYPE_EOC:
996			fprintf(stderr, "end-of-content");
997			break;
998		case BER_TYPE_BOOLEAN:
999			fprintf(stderr, "boolean");
1000			break;
1001		case BER_TYPE_INTEGER:
1002			fprintf(stderr, "integer");
1003			break;
1004		case BER_TYPE_BITSTRING:
1005			fprintf(stderr, "bit-string");
1006			break;
1007		case BER_TYPE_OCTETSTRING:
1008			fprintf(stderr, "octet-string");
1009			break;
1010		case BER_TYPE_NULL:
1011			fprintf(stderr, "null");
1012			break;
1013		case BER_TYPE_OBJECT:
1014			fprintf(stderr, "object");
1015			break;
1016		case BER_TYPE_ENUMERATED:
1017			fprintf(stderr, "enumerated");
1018			break;
1019		case BER_TYPE_SEQUENCE:
1020			fprintf(stderr, "sequence");
1021			break;
1022		case BER_TYPE_SET:
1023			fprintf(stderr, "set");
1024			break;
1025		}
1026		break;
1027	case BER_CLASS_APPLICATION:
1028		fprintf(stderr, "class: application(%u) type: ",
1029		    root->be_class);
1030		switch (root->be_type) {
1031		case LDAP_REQ_BIND:
1032			fprintf(stderr, "bind");
1033			break;
1034		case LDAP_RES_BIND:
1035			fprintf(stderr, "bind");
1036			break;
1037		case LDAP_REQ_UNBIND_30:
1038			break;
1039		case LDAP_REQ_SEARCH:
1040			fprintf(stderr, "search");
1041			break;
1042		case LDAP_RES_SEARCH_ENTRY:
1043			fprintf(stderr, "search_entry");
1044			break;
1045		case LDAP_RES_SEARCH_RESULT:
1046			fprintf(stderr, "search_result");
1047			break;
1048		case LDAP_REQ_MODIFY:
1049			fprintf(stderr, "modify");
1050			break;
1051		case LDAP_RES_MODIFY:
1052			fprintf(stderr, "modify");
1053			break;
1054		case LDAP_REQ_ADD:
1055			fprintf(stderr, "add");
1056			break;
1057		case LDAP_RES_ADD:
1058			fprintf(stderr, "add");
1059			break;
1060		case LDAP_REQ_DELETE_30:
1061			fprintf(stderr, "delete");
1062			break;
1063		case LDAP_RES_DELETE:
1064			fprintf(stderr, "delete");
1065			break;
1066		case LDAP_REQ_MODRDN:
1067			fprintf(stderr, "modrdn");
1068			break;
1069		case LDAP_RES_MODRDN:
1070			fprintf(stderr, "modrdn");
1071			break;
1072		case LDAP_REQ_COMPARE:
1073			fprintf(stderr, "compare");
1074			break;
1075		case LDAP_RES_COMPARE:
1076			fprintf(stderr, "compare");
1077			break;
1078		case LDAP_REQ_ABANDON_30:
1079			fprintf(stderr, "abandon");
1080			break;
1081		}
1082		break;
1083	case BER_CLASS_PRIVATE:
1084		fprintf(stderr, "class: private(%u) type: ", root->be_class);
1085		fprintf(stderr, "encoding (%lu) type: ", root->be_encoding);
1086		break;
1087	case BER_CLASS_CONTEXT:
1088		/* XXX: this is not correct */
1089		fprintf(stderr, "class: context(%u) type: ", root->be_class);
1090		switch(root->be_type) {
1091		case LDAP_AUTH_SIMPLE:
1092			fprintf(stderr, "auth simple");
1093			break;
1094		}
1095		break;
1096	default:
1097		fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
1098		break;
1099	}
1100	fprintf(stderr, "(%lu) encoding %lu ",
1101	    root->be_type, root->be_encoding);
1102
1103	if (constructed)
1104		root->be_encoding = constructed;
1105
1106	switch (root->be_encoding) {
1107	case BER_TYPE_BOOLEAN:
1108		if (ber_get_boolean(root, &d) == -1) {
1109			fprintf(stderr, "<INVALID>\n");
1110			break;
1111		}
1112		fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d);
1113		break;
1114	case BER_TYPE_INTEGER:
1115		if (ber_get_integer(root, &v) == -1) {
1116			fprintf(stderr, "<INVALID>\n");
1117			break;
1118		}
1119		fprintf(stderr, "value %lld\n", v);
1120		break;
1121	case BER_TYPE_ENUMERATED:
1122		if (ber_get_enumerated(root, &v) == -1) {
1123			fprintf(stderr, "<INVALID>\n");
1124			break;
1125		}
1126		fprintf(stderr, "value %lld\n", v);
1127		break;
1128	case BER_TYPE_BITSTRING:
1129		if (ber_get_bitstring(root, (void *)&buf, &len) == -1) {
1130			fprintf(stderr, "<INVALID>\n");
1131			break;
1132		}
1133		fprintf(stderr, "hexdump ");
1134		for (i = 0; i < len; i++)
1135			fprintf(stderr, "%02x", buf[i]);
1136		fprintf(stderr, "\n");
1137		break;
1138	case BER_TYPE_OBJECT:
1139		if (ber_get_oid(root, &o) == -1) {
1140			fprintf(stderr, "<INVALID>\n");
1141			break;
1142		}
1143		fprintf(stderr, "\n");
1144		break;
1145	case BER_TYPE_OCTETSTRING:
1146		if (ber_get_nstring(root, (void *)&buf, &len) == -1) {
1147			fprintf(stderr, "<INVALID>\n");
1148			break;
1149		}
1150		fprintf(stderr, "string \"%.*s\"\n",  len, buf);
1151		break;
1152	case BER_TYPE_NULL:	/* no payload */
1153	case BER_TYPE_EOC:
1154	case BER_TYPE_SEQUENCE:
1155	case BER_TYPE_SET:
1156	default:
1157		fprintf(stderr, "\n");
1158		break;
1159	}
1160
1161	if (constructed && root->be_sub) {
1162		indent += 2;
1163		ldap_debug_elements(root->be_sub);
1164		indent -= 2;
1165	}
1166	if (root->be_next)
1167		ldap_debug_elements(root->be_next);
1168}
1169#endif
1170
1171/*
1172 * Strip UTF-8 down to ASCII without validation.
1173 * notes:
1174 *	non-ASCII characters are displayed as '?'
1175 *	the argument u should be a NULL terminated sequence of UTF-8 bytes.
1176 */
1177char *
1178utoa(char *u)
1179{
1180	int	 len, i, j;
1181	char	*str;
1182
1183	/* calculate the length to allocate */
1184	for (len = 0, i = 0; u[i] != '\0'; i++)
1185		if (!isu8cont(u[i]))
1186			len++;
1187
1188	if ((str = calloc(len + 1, sizeof(char))) == NULL)
1189		return NULL;
1190
1191	/* copy the ASCII characters to the newly allocated string */
1192	for (i = 0, j = 0; u[i] != '\0'; i++)
1193		if (!isu8cont(u[i]))
1194			str[j++] = isascii((unsigned char)u[i]) ? u[i] : '?';
1195
1196	return str;
1197}
1198
1199static int
1200isu8cont(unsigned char c)
1201{
1202	return (c & (0x80 | 0x40)) == 0x80;
1203}
1204
1205/*
1206 * Parse a LDAP value
1207 * notes:
1208 *	the argument p should be a NUL-terminated sequence of ASCII bytes.
1209 */
1210char *
1211parseval(char *p, size_t len)
1212{
1213	char	 hex[3];
1214	char	*buffer;
1215	size_t	 i, j;
1216
1217	if ((buffer = calloc(1, len + 1)) == NULL)
1218		return NULL;
1219
1220	for (i = j = 0; j < len; i++) {
1221		if (p[j] == '\\') {
1222			strlcpy(hex, p + j + 1, sizeof(hex));
1223			buffer[i] = (char)strtoumax(hex, NULL, 16);
1224			j += 3;
1225		} else {
1226			buffer[i] = p[j];
1227			j++;
1228		}
1229	}
1230
1231	return buffer;
1232}
1233
1234int
1235aldap_get_errno(struct aldap *a, const char **estr)
1236{
1237	switch (a->err) {
1238	case ALDAP_ERR_SUCCESS:
1239		*estr = "success";
1240		break;
1241	case ALDAP_ERR_PARSER_ERROR:
1242		*estr = "parser failed";
1243		break;
1244	case ALDAP_ERR_INVALID_FILTER:
1245		*estr = "invalid filter";
1246		break;
1247	case ALDAP_ERR_OPERATION_FAILED:
1248		*estr = "operation failed";
1249		break;
1250	default:
1251		*estr = "unknown";
1252		break;
1253	}
1254	return (a->err);
1255}
1256
1257