aldap.c revision 290931
1/*	$Id: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
2/*	$OpenBSD: aldap.c,v 1.30 2012/04/30 21:40:03 jmatthew Exp $ */
3/*	$FreeBSD: head/usr.sbin/ypldap/aldap.c 290931 2015-11-16 16:48:43Z rodrigc $ */
4
5/*
6 * Copyright (c) 2008 Alexander Schrijver <aschrijver@openbsd.org>
7 * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
8 *
9 * Permission to use, copy, modify, and distribute this software for any
10 * purpose with or without fee is hereby granted, provided that the above
11 * copyright notice and this permission notice appear in all copies.
12 *
13 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 */
21
22#include <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 *);
41char				*parseval(char *, size_t);
42int				aldap_create_page_control(struct ber_element *,
43				    int, struct aldap_page_control *);
44
45#ifdef DEBUG
46void			 ldap_debug_elements(struct ber_element *);
47#endif
48
49#ifdef DEBUG
50#define DPRINTF(x...)	printf(x)
51#define LDAP_DEBUG(x, y)	do { fprintf(stderr, "*** " x "\n"); ldap_debug_elements(y); } while (0)
52#else
53#define DPRINTF(x...)	do { } while (0)
54#define LDAP_DEBUG(x, y)	do { } while (0)
55#endif
56
57int
58aldap_close(struct aldap *al)
59{
60	if (close(al->ber.fd) == -1)
61		return (-1);
62
63	ber_free(&al->ber);
64	free(al);
65
66	return (0);
67}
68
69struct aldap *
70aldap_init(int fd)
71{
72	struct aldap *a;
73
74	if ((a = calloc(1, sizeof(*a))) == NULL)
75		return NULL;
76	a->ber.fd = fd;
77
78	return a;
79}
80
81int
82aldap_bind(struct aldap *ldap, char *binddn, char *bindcred)
83{
84	struct ber_element *root = NULL, *elm;
85	int error;
86
87	if (binddn == NULL)
88		binddn = "";
89	if (bindcred == NULL)
90		bindcred = "";
91
92	if ((root = ber_add_sequence(NULL)) == NULL)
93		goto fail;
94
95	elm = ber_printf_elements(root, "d{tdsst", ++ldap->msgid, BER_CLASS_APP,
96	    (unsigned long)LDAP_REQ_BIND, VERSION, binddn, bindcred,
97	    BER_CLASS_CONTEXT, (unsigned long)LDAP_AUTH_SIMPLE);
98	if (elm == NULL)
99		goto fail;
100
101	LDAP_DEBUG("aldap_bind", root);
102
103	error = ber_write_elements(&ldap->ber, root);
104	ber_free_elements(root);
105	root = NULL;
106	if (error == -1)
107		goto fail;
108
109	return (ldap->msgid);
110fail:
111	if (root != NULL)
112		ber_free_elements(root);
113
114	ldap->err = ALDAP_ERR_OPERATION_FAILED;
115	return (-1);
116}
117
118int
119aldap_unbind(struct aldap *ldap)
120{
121	struct ber_element *root = NULL, *elm;
122	int error;
123
124	if ((root = ber_add_sequence(NULL)) == NULL)
125		goto fail;
126	elm = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
127	    LDAP_REQ_UNBIND_30);
128	if (elm == NULL)
129		goto fail;
130
131	LDAP_DEBUG("aldap_unbind", root);
132
133	error = ber_write_elements(&ldap->ber, root);
134	ber_free_elements(root);
135	root = NULL;
136	if (error == -1)
137		goto fail;
138
139	return (ldap->msgid);
140fail:
141	if (root != NULL)
142		ber_free_elements(root);
143
144	ldap->err = ALDAP_ERR_OPERATION_FAILED;
145
146	return (-1);
147}
148
149int
150aldap_search(struct aldap *ldap, char *basedn, enum scope scope, char *filter,
151    char **attrs, int typesonly, int sizelimit, int timelimit,
152    struct aldap_page_control *page)
153{
154	struct ber_element *root = NULL, *ber, *c;
155	int i, error;
156
157	if ((root = ber_add_sequence(NULL)) == NULL)
158		goto fail;
159
160	ber = ber_printf_elements(root, "d{t", ++ldap->msgid, BER_CLASS_APP,
161	    (unsigned long) LDAP_REQ_SEARCH);
162	if (ber == NULL) {
163		ldap->err = ALDAP_ERR_OPERATION_FAILED;
164		goto fail;
165	}
166
167	c = ber;
168	ber = ber_printf_elements(ber, "sEEddb", basedn, (long long)scope,
169	                         (long long)LDAP_DEREF_NEVER, sizelimit,
170				 timelimit, typesonly);
171	if (ber == NULL) {
172		ldap->err = ALDAP_ERR_OPERATION_FAILED;
173		goto fail;
174	}
175
176	if ((ber = ldap_parse_search_filter(ber, filter)) == NULL) {
177		ldap->err = ALDAP_ERR_PARSER_ERROR;
178		goto fail;
179	}
180
181	if ((ber = ber_add_sequence(ber)) == NULL)
182		goto fail;
183	if (attrs != NULL)
184		for (i = 0; attrs[i] != NULL; i++) {
185			if ((ber = ber_add_string(ber, attrs[i])) == NULL)
186				goto fail;
187		}
188
189	aldap_create_page_control(c, 100, page);
190
191	LDAP_DEBUG("aldap_search", root);
192
193	error = ber_write_elements(&ldap->ber, root);
194	ber_free_elements(root);
195	root = NULL;
196	if (error == -1) {
197		ldap->err = ALDAP_ERR_OPERATION_FAILED;
198		goto fail;
199	}
200
201	return (ldap->msgid);
202
203fail:
204	if (root != NULL)
205		ber_free_elements(root);
206
207	return (-1);
208}
209
210int
211aldap_create_page_control(struct ber_element *elm, int size,
212    struct aldap_page_control *page)
213{
214	int len;
215	struct ber c;
216	struct ber_element *ber = NULL;
217
218	c.br_wbuf = NULL;
219	c.fd = -1;
220
221	ber = ber_add_sequence(NULL);
222
223	if (page == NULL) {
224		if (ber_printf_elements(ber, "ds", 50, "") == NULL)
225			goto fail;
226	} else {
227		if (ber_printf_elements(ber, "dx", 50, page->cookie,
228			    page->cookie_len) == NULL)
229			goto fail;
230	}
231
232	if ((len = ber_write_elements(&c, ber)) < 1)
233		goto fail;
234	if (ber_printf_elements(elm, "{t{sx", 2, 0, LDAP_PAGED_OID,
235		                c.br_wbuf, (size_t)len) == NULL)
236		goto fail;
237
238	ber_free_elements(ber);
239	ber_free(&c);
240	return len;
241fail:
242	if (ber != NULL)
243		ber_free_elements(ber);
244	ber_free(&c);
245
246	return (-1);
247}
248
249struct aldap_message *
250aldap_parse(struct aldap *ldap)
251{
252	int			 class;
253	unsigned long		 type;
254	long long		 msgid = 0;
255	struct aldap_message	*m;
256	struct ber_element	*a = NULL, *ep;
257
258	if ((m = calloc(1, sizeof(struct aldap_message))) == NULL)
259		return NULL;
260
261	if ((m->msg = ber_read_elements(&ldap->ber, NULL)) == NULL)
262		goto parsefail;
263
264	LDAP_DEBUG("message", m->msg);
265
266	if (ber_scanf_elements(m->msg, "{ite", &msgid, &class, &type, &a) != 0)
267		goto parsefail;
268	m->msgid = msgid;
269	m->message_type = type;
270	m->protocol_op = a;
271
272	switch (m->message_type) {
273	case LDAP_RES_BIND:
274	case LDAP_RES_MODIFY:
275	case LDAP_RES_ADD:
276	case LDAP_RES_DELETE:
277	case LDAP_RES_MODRDN:
278	case LDAP_RES_COMPARE:
279	case LDAP_RES_SEARCH_RESULT:
280		if (ber_scanf_elements(m->protocol_op, "{EeSeSe",
281		    &m->body.res.rescode, &m->dn, &m->body.res.diagmsg, &a) != 0)
282			goto parsefail;
283		if (m->body.res.rescode == LDAP_REFERRAL)
284			if (ber_scanf_elements(a, "{e", &m->references) != 0)
285				goto parsefail;
286		if (m->msg->be_sub) {
287			for (ep = m->msg->be_sub; ep != NULL; ep = ep->be_next) {
288				ber_scanf_elements(ep, "t", &class, &type);
289				if (class == 2 && type == 0)
290					m->page = aldap_parse_page_control(ep->be_sub->be_sub,
291					    ep->be_sub->be_sub->be_len);
292			}
293		} else
294			m->page = NULL;
295		break;
296	case LDAP_RES_SEARCH_ENTRY:
297		if (ber_scanf_elements(m->protocol_op, "{eS{e", &m->dn,
298		    &m->body.search.attrs) != 0)
299			goto parsefail;
300		break;
301	case LDAP_RES_SEARCH_REFERENCE:
302		if (ber_scanf_elements(m->protocol_op, "{e", &m->references) != 0)
303			goto parsefail;
304		break;
305	}
306
307	return m;
308parsefail:
309	ldap->err = ALDAP_ERR_PARSER_ERROR;
310	aldap_freemsg(m);
311	return NULL;
312}
313
314struct aldap_page_control *
315aldap_parse_page_control(struct ber_element *control, size_t len)
316{
317	char *oid, *s;
318	char *encoded;
319	struct ber b;
320	struct ber_element *elm;
321	struct aldap_page_control *page;
322
323	b.br_wbuf = NULL;
324	b.fd = -1;
325	ber_scanf_elements(control, "ss", &oid, &encoded);
326	ber_set_readbuf(&b, encoded, control->be_next->be_len);
327	elm = ber_read_elements(&b, NULL);
328
329	if ((page = malloc(sizeof(struct aldap_page_control))) == NULL) {
330		if (elm != NULL)
331			ber_free_elements(elm);
332		ber_free(&b);
333		return NULL;
334	}
335
336	ber_scanf_elements(elm->be_sub, "is", &page->size, &s);
337	page->cookie_len = elm->be_sub->be_next->be_len;
338
339	if ((page->cookie = malloc(page->cookie_len)) == NULL) {
340		if (elm != NULL)
341			ber_free_elements(elm);
342		ber_free(&b);
343		free(page);
344		return NULL;
345	}
346	memcpy(page->cookie, s, page->cookie_len);
347
348	ber_free_elements(elm);
349	ber_free(&b);
350	return page;
351}
352
353void
354aldap_freepage(struct aldap_page_control *page)
355{
356	if (page->cookie)
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, 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 */
735static struct ber_element *
736ldap_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 */
777static struct ber_element *
778ldap_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
944syntaxfail:		/* XXX -- error reporting */
945callfail:
946bad:
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 */
958void
959ldap_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 * Convert UTF-8 to ASCII.
1166 * notes:
1167 *	non-ASCII characters are displayed as '?'
1168 *	the argument u should be a NULL terminated sequence of UTF-8 bytes.
1169 */
1170char *
1171utoa(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'; ) {
1178		if ((u[i] & 0xF0) == 0xF0)
1179			i += 4;
1180		else if ((u[i] & 0xE0) == 0xE0)
1181			i += 3;
1182		else if ((u[i] & 0xC0) == 0xC0)
1183			i += 2;
1184		else
1185			i += 1;
1186		len++;
1187	}
1188
1189	if ((str = calloc(len + 1, sizeof(char))) == NULL)
1190		return NULL;
1191
1192	/* copy the ASCII characters to the newly allocated string */
1193	for (i = 0, j = 0; u[i] != '\0'; j++) {
1194		if ((u[i] & 0xF0) == 0xF0) {
1195			str[j] = '?';
1196			i += 4;
1197		} else if ((u[i] & 0xE0) == 0xE0) {
1198			str[j] = '?';
1199			i += 3;
1200		} else if ((u[i] & 0xC0) == 0xC0) {
1201			str[j] = '?';
1202			i += 2;
1203		} else {
1204			str[j] =  u[i];
1205			i += 1;
1206		}
1207	}
1208
1209	return str;
1210}
1211
1212/*
1213 * Parse a LDAP value
1214 * notes:
1215 *	the argument u should be a NULL terminated sequence of ASCII bytes.
1216 */
1217char *
1218parseval(char *p, size_t len)
1219{
1220	char	 hex[3];
1221	char	*cp = p, *buffer, *newbuffer;
1222	size_t	 size, newsize, i, j;
1223
1224	size = 50;
1225	if ((buffer = calloc(1, size)) == NULL)
1226		return NULL;
1227
1228	for (i = j = 0; j < len; i++) {
1229		if (i >= size) {
1230			newsize = size + 1024;
1231			if ((newbuffer = realloc(buffer, newsize)) == NULL) {
1232				free(buffer);
1233				return (NULL);
1234			}
1235			buffer = newbuffer;
1236			size = newsize;
1237		}
1238
1239		if (cp[j] == '\\') {
1240			strlcpy(hex, cp + j + 1, sizeof(hex));
1241			buffer[i] = (char)strtoumax(hex, NULL, 16);
1242			j += 3;
1243		} else {
1244			buffer[i] = cp[j];
1245			j++;
1246		}
1247	}
1248
1249	return buffer;
1250}
1251
1252int
1253aldap_get_errno(struct aldap *a, const char **estr)
1254{
1255	switch (a->err) {
1256	case ALDAP_ERR_SUCCESS:
1257		*estr = "success";
1258		break;
1259	case ALDAP_ERR_PARSER_ERROR:
1260		*estr = "parser failed";
1261		break;
1262	case ALDAP_ERR_INVALID_FILTER:
1263		*estr = "invalid filter";
1264		break;
1265	case ALDAP_ERR_OPERATION_FAILED:
1266		*estr = "operation failed";
1267		break;
1268	default:
1269		*estr = "unknown";
1270		break;
1271	}
1272	return (a->err);
1273}
1274