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