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