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