1 | |
2 | |
3 | |
4 | |
5 | |
6 | |
7 | |
8 | |
9 | |
10 | |
11 | |
12 | |
13 | |
14 | |
15 | |
16 | |
17 | |
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 |
64 | aldap_application(struct ber_element *elm) |
65 | { |
66 | return BER_TYPE_OCTETSTRING; |
67 | } |
68 | |
69 | int |
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 * |
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 |
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 |
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 |
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 |
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 |
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 |
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 |
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 * |
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 * |
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 |
492 | aldap_freepage(struct aldap_page_control *page) |
493 | { |
494 | free(page->cookie); |
495 | free(page); |
496 | } |
497 | |
498 | void |
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 |
507 | aldap_get_resultcode(struct aldap_message *msg) |
508 | { |
509 | return msg->body.res.rescode; |
510 | } |
511 | |
512 | char * |
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 * |
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 |
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 * |
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 |
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 |
580 | aldap_first_attr(struct aldap_message *msg, char **outkey, |
581 | struct aldap_stringset **outvalues) |
582 | { |
583 | struct ber_element *b, *c; |
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)}e", |
591 | &key, &b, &c) != 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 |
610 | aldap_next_attr(struct aldap_message *msg, char **outkey, |
611 | struct aldap_stringset **outvalues) |
612 | { |
613 | struct ber_element *a, *b; |
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)}e", &key, &a, &b) |
626 | != 0) |
627 | goto fail; |
628 | |
629 | msg->body.search.iter = msg->body.search.iter->be_next; |
630 | |
631 | if ((ret = aldap_get_stringset(a)) == NULL) |
632 | goto fail; |
633 | |
634 | (*outvalues) = ret; |
635 | (*outkey) = utoa(key); |
636 | |
637 | return (1); |
638 | fail: |
639 | notfound: |
640 | (*outkey) = NULL; |
641 | (*outvalues) = NULL; |
642 | return (-1); |
643 | } |
644 | |
645 | int |
646 | aldap_match_attr(struct aldap_message *msg, char *inkey, |
647 | struct aldap_stringset **outvalues) |
648 | { |
649 | struct ber_element *a, *b; |
650 | char *descr = NULL; |
651 | struct aldap_stringset *ret; |
652 | |
653 | if (msg->body.search.attrs == NULL) |
654 | goto fail; |
655 | |
656 | LDAP_DEBUG("attr", msg->body.search.attrs); |
657 | |
658 | for (a = msg->body.search.attrs;;) { |
659 | if (a == NULL) |
660 | goto notfound; |
661 | if (ober_get_eoc(a) == 0) |
662 | goto notfound; |
663 | if (ober_scanf_elements(a, "{s(e", &descr, &b) != 0) |
664 | goto fail; |
665 | if (strcasecmp(descr, inkey) == 0) |
666 | goto attrfound; |
667 | a = a->be_next; |
668 | } |
669 | |
670 | attrfound: |
671 | if ((ret = aldap_get_stringset(b)) == NULL) |
672 | goto fail; |
673 | |
674 | (*outvalues) = ret; |
675 | |
676 | return (1); |
677 | fail: |
678 | notfound: |
679 | (*outvalues) = NULL; |
680 | return (-1); |
681 | } |
682 | |
683 | int |
684 | aldap_free_attr(struct aldap_stringset *values) |
685 | { |
686 | if (values == NULL) |
687 | return -1; |
688 | |
689 | free(values->str); |
690 | free(values); |
691 | |
692 | return (1); |
693 | } |
694 | |
695 | void |
696 | aldap_free_url(struct aldap_url *lu) |
697 | { |
698 | free(lu->buffer); |
699 | } |
700 | |
701 | int |
702 | aldap_parse_url(const char *url, struct aldap_url *lu) |
703 | { |
704 | char *p, *forward, *forward2; |
705 | const char *errstr = NULL; |
706 | int i; |
707 | |
708 | if ((lu->buffer = p = strdup(url)) == NULL) |
709 | return (-1); |
710 | |
711 | |
712 | if (strncasecmp(LDAP_URL, p, strlen(LDAP_URL)) == 0) { |
713 | lu->protocol = LDAP; |
714 | p += strlen(LDAP_URL); |
715 | } else if (strncasecmp(LDAPS_URL, p, strlen(LDAPS_URL)) == 0) { |
716 | lu->protocol = LDAPS; |
717 | p += strlen(LDAPS_URL); |
718 | } else if (strncasecmp(LDAPTLS_URL, p, strlen(LDAPTLS_URL)) == 0) { |
719 | lu->protocol = LDAPTLS; |
720 | p += strlen(LDAPTLS_URL); |
721 | } else if (strncasecmp(LDAPI_URL, p, strlen(LDAPI_URL)) == 0) { |
722 | lu->protocol = LDAPI; |
723 | p += strlen(LDAPI_URL); |
724 | } else |
725 | lu->protocol = -1; |
726 | |
727 | |
728 | if ((forward = strchr(p, '/')) != NULL) |
729 | *forward = '\0'; |
730 | |
731 | if ((forward2 = strchr(p, ':')) != NULL) { |
732 | *forward2 = '\0'; |
733 | |
734 | if (*(forward2+1) != '\0') { |
735 | #define PORT_MAX UINT16_MAX |
736 | lu->port = strtonum(++forward2, 0, PORT_MAX, &errstr); |
737 | if (errstr) |
738 | goto fail; |
739 | } |
740 | } |
741 | |
742 | if (strlen(p) == 0) |
743 | goto fail; |
744 | lu->host = p; |
745 | if (forward == NULL) |
746 | goto done; |
747 | |
748 | p = ++forward; |
749 | if (strlen(p) == 0) |
750 | goto done; |
751 | |
752 | |
753 | if ((forward = strchr(p, '?')) != NULL) |
754 | *forward = '\0'; |
755 | lu->dn = p; |
756 | if (forward == NULL) |
757 | goto done; |
758 | |
759 | p = ++forward; |
760 | if (strlen(p) == 0) |
761 | goto done; |
762 | |
763 | |
764 | if ((forward = strchr(p, '?')) != NULL) |
765 | *forward = '\0'; |
766 | for (i = 0; i < MAXATTR; i++) { |
767 | if ((forward2 = strchr(p, ',')) == NULL) { |
768 | if (strlen(p) == 0) |
769 | break; |
770 | lu->attributes[i] = p; |
771 | break; |
772 | } |
773 | *forward2 = '\0'; |
774 | lu->attributes[i] = p; |
775 | p = ++forward2; |
776 | } |
777 | if (forward == NULL) |
778 | goto done; |
779 | |
780 | p = ++forward; |
781 | if (strlen(p) == 0) |
782 | goto done; |
783 | |
784 | |
785 | if ((forward = strchr(p, '?')) != NULL) |
786 | *forward = '\0'; |
787 | if (strcmp(p, "base") == 0) |
788 | lu->scope = LDAP_SCOPE_BASE; |
789 | else if (strcmp(p, "one") == 0) |
790 | lu->scope = LDAP_SCOPE_ONELEVEL; |
791 | else if (strcmp(p, "sub") == 0) |
792 | lu->scope = LDAP_SCOPE_SUBTREE; |
793 | else |
794 | goto fail; |
795 | if (forward == NULL) |
796 | goto done; |
797 | p = ++forward; |
798 | if (strlen(p) == 0) |
799 | goto done; |
800 | |
801 | |
802 | if (p) |
803 | lu->filter = p; |
804 | done: |
805 | return (1); |
806 | fail: |
807 | free(lu->buffer); |
808 | lu->buffer = NULL; |
809 | return (-1); |
810 | } |
811 | |
812 | int |
813 | aldap_search_url(struct aldap *ldap, char *url, int typesonly, int sizelimit, |
814 | int timelimit, struct aldap_page_control *page) |
815 | { |
816 | struct aldap_url *lu; |
817 | |
818 | if ((lu = calloc(1, sizeof(*lu))) == NULL) |
| |
| 2 | | Assuming the condition is false | |
|
| |
819 | return (-1); |
820 | |
821 | if (aldap_parse_url(url, lu)) |
| |
822 | goto fail; |
| 5 | | Control jumps to line 831 | |
|
823 | |
824 | if (aldap_search(ldap, lu->dn, lu->scope, lu->filter, lu->attributes, |
825 | typesonly, sizelimit, timelimit, page) == -1) |
826 | goto fail; |
827 | |
828 | aldap_free_url(lu); |
829 | return (ldap->msgid); |
830 | fail: |
831 | aldap_free_url(lu); |
832 | return (-1); |
| 6 | | Potential leak of memory pointed to by 'lu' |
|
833 | } |
834 | |
835 | |
836 | |
837 | |
838 | |
839 | struct aldap_stringset * |
840 | aldap_get_stringset(struct ber_element *elm) |
841 | { |
842 | struct ber_element *a; |
843 | int i; |
844 | struct aldap_stringset *ret; |
845 | |
846 | if (elm->be_type != BER_TYPE_OCTETSTRING) |
847 | return NULL; |
848 | |
849 | if ((ret = malloc(sizeof(*ret))) == NULL) |
850 | return NULL; |
851 | for (a = elm, ret->len = 0; a != NULL && a->be_type == |
852 | BER_TYPE_OCTETSTRING; a = a->be_next, ret->len++) |
853 | ; |
854 | if (ret->len == 0) { |
855 | free(ret); |
856 | return NULL; |
857 | } |
858 | |
859 | if ((ret->str = reallocarray(NULL, ret->len, |
860 | sizeof(*(ret->str)))) == NULL) { |
861 | free(ret); |
862 | return NULL; |
863 | } |
864 | |
865 | for (a = elm, i = 0; a != NULL && a->be_type == BER_TYPE_OCTETSTRING; |
866 | a = a->be_next, i++) |
867 | (void) ober_get_ostring(a, &(ret->str[i])); |
868 | |
869 | return ret; |
870 | } |
871 | |
872 | |
873 | |
874 | |
875 | |
876 | |
877 | |
878 | |
879 | static struct ber_element * |
880 | ldap_parse_search_filter(struct ber_element *ber, char *filter) |
881 | { |
882 | struct ber_element *elm; |
883 | char *cp; |
884 | |
885 | cp = filter; |
886 | |
887 | if (cp == NULL || *cp == '\0') { |
888 | errno = EINVAL; |
889 | return (NULL); |
890 | } |
891 | |
892 | if ((elm = ldap_do_parse_search_filter(ber, &cp)) == NULL) |
893 | return (NULL); |
894 | |
895 | if (*cp != '\0') { |
896 | ober_free_elements(elm); |
897 | ober_link_elements(ber, NULL); |
898 | errno = EINVAL; |
899 | return (NULL); |
900 | } |
901 | |
902 | return (elm); |
903 | } |
904 | |
905 | |
906 | |
907 | |
908 | |
909 | |
910 | |
911 | |
912 | |
913 | |
914 | |
915 | |
916 | |
917 | |
918 | |
919 | |
920 | |
921 | static struct ber_element * |
922 | ldap_do_parse_search_filter(struct ber_element *prev, char **cpp) |
923 | { |
924 | struct ber_element *elm, *root = NULL; |
925 | char *attr_desc, *attr_val, *parsed_val, *cp; |
926 | size_t len; |
927 | unsigned long type; |
928 | |
929 | root = NULL; |
930 | |
931 | |
932 | cp = *cpp; |
933 | if (*cp != '(') |
934 | goto syntaxfail; |
935 | |
936 | switch (*++cp) { |
937 | case '&': |
938 | case '|': |
939 | if (*cp == '&') |
940 | type = LDAP_FILT_AND; |
941 | else |
942 | type = LDAP_FILT_OR; |
943 | |
944 | if ((elm = ober_add_set(prev)) == NULL) |
945 | goto callfail; |
946 | root = elm; |
947 | ober_set_header(elm, BER_CLASS_CONTEXT, type); |
948 | |
949 | if (*++cp != '(') |
950 | goto syntaxfail; |
951 | |
952 | while (*cp == '(') { |
953 | if ((elm = |
954 | ldap_do_parse_search_filter(elm, &cp)) == NULL) |
955 | goto bad; |
956 | } |
957 | |
958 | if (*cp != ')') |
959 | goto syntaxfail; |
960 | break; |
961 | |
962 | case '!': |
963 | if ((root = ober_add_sequence(prev)) == NULL) |
964 | goto callfail; |
965 | ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_NOT); |
966 | |
967 | cp++; |
968 | if ((elm = ldap_do_parse_search_filter(root, &cp)) == NULL) |
969 | goto bad; |
970 | |
971 | if (*cp != ')') |
972 | goto syntaxfail; |
973 | break; |
974 | |
975 | default: |
976 | attr_desc = cp; |
977 | |
978 | len = strcspn(cp, "()<>~="); |
979 | cp += len; |
980 | switch (*cp) { |
981 | case '~': |
982 | type = LDAP_FILT_APPR; |
983 | cp++; |
984 | break; |
985 | case '<': |
986 | type = LDAP_FILT_LE; |
987 | cp++; |
988 | break; |
989 | case '>': |
990 | type = LDAP_FILT_GE; |
991 | cp++; |
992 | break; |
993 | case '=': |
994 | type = LDAP_FILT_EQ; |
995 | break; |
996 | case '(': |
997 | case ')': |
998 | default: |
999 | goto syntaxfail; |
1000 | } |
1001 | attr_val = ++cp; |
1002 | |
1003 | |
1004 | if (strncmp(attr_val, "*)", 2) == 0) { |
1005 | cp++; |
1006 | if ((root = |
1007 | ober_add_nstring(prev, attr_desc, len)) == NULL) |
1008 | goto bad; |
1009 | |
1010 | ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_PRES); |
1011 | break; |
1012 | } |
1013 | |
1014 | if ((root = ober_add_sequence(prev)) == NULL) |
1015 | goto callfail; |
1016 | ober_set_header(root, BER_CLASS_CONTEXT, type); |
1017 | |
1018 | if ((elm = ober_add_nstring(root, attr_desc, len)) == NULL) |
1019 | goto callfail; |
1020 | |
1021 | len = strcspn(attr_val, "*)"); |
1022 | if (len == 0 && *cp != '*') |
1023 | goto syntaxfail; |
1024 | cp += len; |
1025 | if (*cp == '\0') |
1026 | goto syntaxfail; |
1027 | |
1028 | if (*cp == '*') { |
1029 | int initial; |
1030 | |
1031 | cp = attr_val; |
1032 | |
1033 | ober_set_header(root, BER_CLASS_CONTEXT, LDAP_FILT_SUBS); |
1034 | |
1035 | if ((elm = ober_add_sequence(elm)) == NULL) |
1036 | goto callfail; |
1037 | |
1038 | for (initial = 1;; cp++, initial = 0) { |
1039 | attr_val = cp; |
1040 | |
1041 | len = strcspn(attr_val, "*)"); |
1042 | if (len == 0) { |
1043 | if (*cp == ')') |
1044 | break; |
1045 | else |
1046 | continue; |
1047 | } |
1048 | cp += len; |
1049 | if (*cp == '\0') |
1050 | goto syntaxfail; |
1051 | |
1052 | if (initial) |
1053 | type = LDAP_FILT_SUBS_INIT; |
1054 | else if (*cp == ')') |
1055 | type = LDAP_FILT_SUBS_FIN; |
1056 | else |
1057 | type = LDAP_FILT_SUBS_ANY; |
1058 | |
1059 | if ((parsed_val = parseval(attr_val, len)) == |
1060 | NULL) |
1061 | goto callfail; |
1062 | elm = ober_add_nstring(elm, parsed_val, |
1063 | strlen(parsed_val)); |
1064 | free(parsed_val); |
1065 | if (elm == NULL) |
1066 | goto callfail; |
1067 | ober_set_header(elm, BER_CLASS_CONTEXT, type); |
1068 | if (type == LDAP_FILT_SUBS_FIN) |
1069 | break; |
1070 | } |
1071 | break; |
1072 | } |
1073 | |
1074 | if ((parsed_val = parseval(attr_val, len)) == NULL) |
1075 | goto callfail; |
1076 | elm = ober_add_nstring(elm, parsed_val, strlen(parsed_val)); |
1077 | free(parsed_val); |
1078 | if (elm == NULL) |
1079 | goto callfail; |
1080 | break; |
1081 | } |
1082 | |
1083 | cp++; |
1084 | |
1085 | *cpp = cp; |
1086 | return (root); |
1087 | |
1088 | syntaxfail: |
1089 | callfail: |
1090 | bad: |
1091 | if (root != NULL) |
1092 | ober_free_elements(root); |
1093 | ober_link_elements(prev, NULL); |
1094 | return (NULL); |
1095 | } |
1096 | |
1097 | #ifdef DEBUG |
1098 | |
1099 | |
1100 | |
1101 | |
1102 | void |
1103 | ldap_debug_elements(struct ber_element *root) |
1104 | { |
1105 | static int indent = 0; |
1106 | long long v; |
1107 | int d; |
1108 | char *buf; |
1109 | size_t len; |
1110 | u_int i; |
1111 | int constructed; |
1112 | struct ber_oid o; |
1113 | |
1114 | |
1115 | ober_calc_len(root); |
1116 | |
1117 | switch (root->be_encoding) { |
1118 | case BER_TYPE_SEQUENCE: |
1119 | case BER_TYPE_SET: |
1120 | constructed = root->be_encoding; |
1121 | break; |
1122 | default: |
1123 | constructed = 0; |
1124 | break; |
1125 | } |
1126 | |
1127 | fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); |
1128 | switch (root->be_class) { |
1129 | case BER_CLASS_UNIVERSAL: |
1130 | fprintf(stderr, "class: universal(%u) type: ", root->be_class); |
1131 | switch (root->be_type) { |
1132 | case BER_TYPE_EOC: |
1133 | fprintf(stderr, "end-of-content"); |
1134 | break; |
1135 | case BER_TYPE_BOOLEAN: |
1136 | fprintf(stderr, "boolean"); |
1137 | break; |
1138 | case BER_TYPE_INTEGER: |
1139 | fprintf(stderr, "integer"); |
1140 | break; |
1141 | case BER_TYPE_BITSTRING: |
1142 | fprintf(stderr, "bit-string"); |
1143 | break; |
1144 | case BER_TYPE_OCTETSTRING: |
1145 | fprintf(stderr, "octet-string"); |
1146 | break; |
1147 | case BER_TYPE_NULL: |
1148 | fprintf(stderr, "null"); |
1149 | break; |
1150 | case BER_TYPE_OBJECT: |
1151 | fprintf(stderr, "object"); |
1152 | break; |
1153 | case BER_TYPE_ENUMERATED: |
1154 | fprintf(stderr, "enumerated"); |
1155 | break; |
1156 | case BER_TYPE_SEQUENCE: |
1157 | fprintf(stderr, "sequence"); |
1158 | break; |
1159 | case BER_TYPE_SET: |
1160 | fprintf(stderr, "set"); |
1161 | break; |
1162 | } |
1163 | break; |
1164 | case BER_CLASS_APPLICATION: |
1165 | fprintf(stderr, "class: application(%u) type: ", |
1166 | root->be_class); |
1167 | switch (root->be_type) { |
1168 | case LDAP_REQ_BIND: |
1169 | fprintf(stderr, "bind"); |
1170 | break; |
1171 | case LDAP_RES_BIND: |
1172 | fprintf(stderr, "bind"); |
1173 | break; |
1174 | case LDAP_REQ_UNBIND_30: |
1175 | break; |
1176 | case LDAP_REQ_SEARCH: |
1177 | fprintf(stderr, "search"); |
1178 | break; |
1179 | case LDAP_RES_SEARCH_ENTRY: |
1180 | fprintf(stderr, "search_entry"); |
1181 | break; |
1182 | case LDAP_RES_SEARCH_RESULT: |
1183 | fprintf(stderr, "search_result"); |
1184 | break; |
1185 | case LDAP_REQ_MODIFY: |
1186 | fprintf(stderr, "modify"); |
1187 | break; |
1188 | case LDAP_RES_MODIFY: |
1189 | fprintf(stderr, "modify"); |
1190 | break; |
1191 | case LDAP_REQ_ADD: |
1192 | fprintf(stderr, "add"); |
1193 | break; |
1194 | case LDAP_RES_ADD: |
1195 | fprintf(stderr, "add"); |
1196 | break; |
1197 | case LDAP_REQ_DELETE_30: |
1198 | fprintf(stderr, "delete"); |
1199 | break; |
1200 | case LDAP_RES_DELETE: |
1201 | fprintf(stderr, "delete"); |
1202 | break; |
1203 | case LDAP_REQ_MODRDN: |
1204 | fprintf(stderr, "modrdn"); |
1205 | break; |
1206 | case LDAP_RES_MODRDN: |
1207 | fprintf(stderr, "modrdn"); |
1208 | break; |
1209 | case LDAP_REQ_COMPARE: |
1210 | fprintf(stderr, "compare"); |
1211 | break; |
1212 | case LDAP_RES_COMPARE: |
1213 | fprintf(stderr, "compare"); |
1214 | break; |
1215 | case LDAP_REQ_ABANDON_30: |
1216 | fprintf(stderr, "abandon"); |
1217 | break; |
1218 | } |
1219 | break; |
1220 | case BER_CLASS_PRIVATE: |
1221 | fprintf(stderr, "class: private(%u) type: ", root->be_class); |
1222 | fprintf(stderr, "encoding (%u) type: ", root->be_encoding); |
1223 | break; |
1224 | case BER_CLASS_CONTEXT: |
1225 | |
1226 | fprintf(stderr, "class: context(%u) type: ", root->be_class); |
1227 | switch(root->be_type) { |
1228 | case LDAP_AUTH_SIMPLE: |
1229 | fprintf(stderr, "auth simple"); |
1230 | break; |
1231 | } |
1232 | break; |
1233 | default: |
1234 | fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); |
1235 | break; |
1236 | } |
1237 | fprintf(stderr, "(%u) encoding %u ", |
1238 | root->be_type, root->be_encoding); |
1239 | |
1240 | if (constructed) |
1241 | root->be_encoding = constructed; |
1242 | |
1243 | switch (root->be_encoding) { |
1244 | case BER_TYPE_BOOLEAN: |
1245 | if (ober_get_boolean(root, &d) == -1) { |
1246 | fprintf(stderr, "<INVALID>\n"); |
1247 | break; |
1248 | } |
1249 | fprintf(stderr, "%s(%d)\n", d ? "true" : "false", d); |
1250 | break; |
1251 | case BER_TYPE_INTEGER: |
1252 | if (ober_get_integer(root, &v) == -1) { |
1253 | fprintf(stderr, "<INVALID>\n"); |
1254 | break; |
1255 | } |
1256 | fprintf(stderr, "value %lld\n", v); |
1257 | break; |
1258 | case BER_TYPE_ENUMERATED: |
1259 | if (ober_get_enumerated(root, &v) == -1) { |
1260 | fprintf(stderr, "<INVALID>\n"); |
1261 | break; |
1262 | } |
1263 | fprintf(stderr, "value %lld\n", v); |
1264 | break; |
1265 | case BER_TYPE_BITSTRING: |
1266 | if (ober_get_bitstring(root, (void *)&buf, &len) == -1) { |
1267 | fprintf(stderr, "<INVALID>\n"); |
1268 | break; |
1269 | } |
1270 | fprintf(stderr, "hexdump "); |
1271 | for (i = 0; i < len; i++) |
1272 | fprintf(stderr, "%02x", buf[i]); |
1273 | fprintf(stderr, "\n"); |
1274 | break; |
1275 | case BER_TYPE_OBJECT: |
1276 | if (ober_get_oid(root, &o) == -1) { |
1277 | fprintf(stderr, "<INVALID>\n"); |
1278 | break; |
1279 | } |
1280 | fprintf(stderr, "\n"); |
1281 | break; |
1282 | case BER_TYPE_OCTETSTRING: |
1283 | if (ober_get_nstring(root, (void *)&buf, &len) == -1) { |
1284 | fprintf(stderr, "<INVALID>\n"); |
1285 | break; |
1286 | } |
1287 | fprintf(stderr, "string \"%.*s\"\n", (int)len, buf); |
1288 | break; |
1289 | case BER_TYPE_NULL: |
1290 | case BER_TYPE_EOC: |
1291 | case BER_TYPE_SEQUENCE: |
1292 | case BER_TYPE_SET: |
1293 | default: |
1294 | fprintf(stderr, "\n"); |
1295 | break; |
1296 | } |
1297 | |
1298 | if (constructed && root->be_sub) { |
1299 | indent += 2; |
1300 | ldap_debug_elements(root->be_sub); |
1301 | indent -= 2; |
1302 | } |
1303 | if (root->be_next) |
1304 | ldap_debug_elements(root->be_next); |
1305 | } |
1306 | #endif |
1307 | |
1308 | |
1309 | |
1310 | |
1311 | |
1312 | |
1313 | |
1314 | char * |
1315 | utoa(char *u) |
1316 | { |
1317 | int len, i, j; |
1318 | char *str; |
1319 | |
1320 | |
1321 | for (len = 0, i = 0; u[i] != '\0'; i++) |
1322 | if (!isu8cont(u[i])) |
1323 | len++; |
1324 | |
1325 | if ((str = calloc(len + 1, sizeof(char))) == NULL) |
1326 | return NULL; |
1327 | |
1328 | |
1329 | for (i = 0, j = 0; u[i] != '\0'; i++) |
1330 | if (!isu8cont(u[i])) |
1331 | str[j++] = isascii((unsigned char)u[i]) ? u[i] : '?'; |
1332 | |
1333 | return str; |
1334 | } |
1335 | |
1336 | static int |
1337 | isu8cont(unsigned char c) |
1338 | { |
1339 | return (c & (0x80 | 0x40)) == 0x80; |
1340 | } |
1341 | |
1342 | |
1343 | |
1344 | |
1345 | |
1346 | |
1347 | char * |
1348 | parseval(char *p, size_t len) |
1349 | { |
1350 | char hex[3]; |
1351 | char *buffer; |
1352 | size_t i, j; |
1353 | |
1354 | if ((buffer = calloc(1, len + 1)) == NULL) |
1355 | return NULL; |
1356 | |
1357 | for (i = j = 0; j < len; i++) { |
1358 | if (p[j] == '\\') { |
1359 | strlcpy(hex, p + j + 1, sizeof(hex)); |
1360 | buffer[i] = (char)strtoumax(hex, NULL, 16); |
1361 | j += 3; |
1362 | } else { |
1363 | buffer[i] = p[j]; |
1364 | j++; |
1365 | } |
1366 | } |
1367 | |
1368 | return buffer; |
1369 | } |
1370 | |
1371 | int |
1372 | aldap_get_errno(struct aldap *a, const char **estr) |
1373 | { |
1374 | switch (a->err) { |
1375 | case ALDAP_ERR_SUCCESS: |
1376 | *estr = "success"; |
1377 | break; |
1378 | case ALDAP_ERR_PARSER_ERROR: |
1379 | *estr = "parser failed"; |
1380 | break; |
1381 | case ALDAP_ERR_INVALID_FILTER: |
1382 | *estr = "invalid filter"; |
1383 | break; |
1384 | case ALDAP_ERR_OPERATION_FAILED: |
1385 | *estr = "operation failed"; |
1386 | break; |
1387 | case ALDAP_ERR_TLS_ERROR: |
1388 | *estr = tls_error(a->tls); |
1389 | break; |
1390 | default: |
1391 | *estr = "unknown"; |
1392 | break; |
1393 | } |
1394 | return (a->err); |
1395 | } |