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