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