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