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