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