]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.sbin/ypldap/ber.c
Merge llvm-project release/17.x llvmorg-17.0.1-25-g098e653a5bed
[FreeBSD/FreeBSD.git] / usr.sbin / ypldap / ber.c
1 /*      $OpenBSD: ber.c,v 1.9 2015/02/12 00:30:38 pelikan Exp $ */
2
3 /*
4  * Copyright (c) 2007 Reyk Floeter <reyk@vantronix.net>
5  * Copyright (c) 2006, 2007 Claudio Jeker <claudio@openbsd.org>
6  * Copyright (c) 2006, 2007 Marc Balmer <mbalmer@openbsd.org>
7  *
8  * Permission to use, copy, modify, and distribute this software for any
9  * purpose with or without fee is hereby granted, provided that the above
10  * copyright notice and this permission notice appear in all copies.
11  *
12  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
19  */
20
21 #include <sys/types.h>
22
23 #include <errno.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <err.h>        /* XXX for debug output */
27 #include <stdio.h>      /* XXX for debug output */
28 #include <string.h>
29 #include <unistd.h>
30 #include <stdarg.h>
31
32 #include "ber.h"
33
34 #define MINIMUM(a, b)   (((a) < (b)) ? (a) : (b))
35
36 #define BER_TYPE_CONSTRUCTED    0x20    /* otherwise primitive */
37 #define BER_TYPE_SINGLE_MAX     30
38 #define BER_TAG_MASK            0x1f
39 #define BER_TAG_MORE            0x80    /* more subsequent octets */
40 #define BER_TAG_TYPE_MASK       0x7f
41 #define BER_CLASS_SHIFT         6
42
43 static int      ber_dump_element(struct ber *ber, struct ber_element *root);
44 static void     ber_dump_header(struct ber *ber, struct ber_element *root);
45 static void     ber_putc(struct ber *ber, u_char c);
46 static void     ber_write(struct ber *ber, void *buf, size_t len);
47 static ssize_t  get_id(struct ber *b, unsigned long *tag, int *class,
48     int *cstruct);
49 static ssize_t  get_len(struct ber *b, ssize_t *len);
50 static ssize_t  ber_read_element(struct ber *ber, struct ber_element *elm);
51 static ssize_t  ber_readbuf(struct ber *b, void *buf, size_t nbytes);
52 static ssize_t  ber_getc(struct ber *b, u_char *c);
53 static ssize_t  ber_read(struct ber *ber, void *buf, size_t len);
54
55 #ifdef DEBUG
56 #define DPRINTF(...)    printf(__VA_ARGS__)
57 #else
58 #define DPRINTF(...)    do { } while (0)
59 #endif
60
61 struct ber_element *
62 ber_get_element(unsigned long encoding)
63 {
64         struct ber_element *elm;
65
66         if ((elm = calloc(1, sizeof(*elm))) == NULL)
67                 return NULL;
68
69         elm->be_encoding = encoding;
70         ber_set_header(elm, BER_CLASS_UNIVERSAL, BER_TYPE_DEFAULT);
71
72         return elm;
73 }
74
75 void
76 ber_set_header(struct ber_element *elm, int class, unsigned long type)
77 {
78         elm->be_class = class & BER_CLASS_MASK;
79         if (type == BER_TYPE_DEFAULT)
80                 type = elm->be_encoding;
81         elm->be_type = type;
82 }
83
84 void
85 ber_link_elements(struct ber_element *prev, struct ber_element *elm)
86 {
87         if (prev != NULL) {
88                 if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
89                     prev->be_encoding == BER_TYPE_SET) &&
90                     prev->be_sub == NULL)
91                         prev->be_sub = elm;
92                 else
93                         prev->be_next = elm;
94         }
95 }
96
97 struct ber_element *
98 ber_unlink_elements(struct ber_element *prev)
99 {
100         struct ber_element *elm;
101
102         if ((prev->be_encoding == BER_TYPE_SEQUENCE ||
103             prev->be_encoding == BER_TYPE_SET) &&
104             prev->be_sub != NULL) {
105                 elm = prev->be_sub;
106                 prev->be_sub = NULL;
107         } else {
108                 elm = prev->be_next;
109                 prev->be_next = NULL;
110         }
111
112         return (elm);
113 }
114
115 void
116 ber_replace_elements(struct ber_element *prev, struct ber_element *new)
117 {
118         struct ber_element *ber, *next;
119
120         ber = ber_unlink_elements(prev);
121         next = ber_unlink_elements(ber);
122         ber_link_elements(new, next);
123         ber_link_elements(prev, new);
124
125         /* cleanup old element */
126         ber_free_elements(ber);
127 }
128
129 struct ber_element *
130 ber_add_sequence(struct ber_element *prev)
131 {
132         struct ber_element *elm;
133
134         if ((elm = ber_get_element(BER_TYPE_SEQUENCE)) == NULL)
135                 return NULL;
136
137         ber_link_elements(prev, elm);
138
139         return elm;
140 }
141
142 struct ber_element *
143 ber_add_set(struct ber_element *prev)
144 {
145         struct ber_element *elm;
146
147         if ((elm = ber_get_element(BER_TYPE_SET)) == NULL)
148                 return NULL;
149
150         ber_link_elements(prev, elm);
151
152         return elm;
153 }
154
155 struct ber_element *
156 ber_add_enumerated(struct ber_element *prev, long long val)
157 {
158         struct ber_element *elm;
159         u_int i, len = 0;
160         u_char cur, last = 0;
161
162         if ((elm = ber_get_element(BER_TYPE_ENUMERATED)) == NULL)
163                 return NULL;
164
165         elm->be_numeric = val;
166
167         for (i = 0; i < sizeof(long long); i++) {
168                 cur = val & 0xff;
169                 if (cur != 0 && cur != 0xff)
170                         len = i;
171                 if ((cur == 0 && last & 0x80) ||
172                     (cur == 0xff && (last & 0x80) == 0))
173                         len = i;
174                 val >>= 8;
175                 last = cur;
176         }
177         elm->be_len = len + 1;
178
179         ber_link_elements(prev, elm);
180
181         return elm;
182 }
183
184 struct ber_element *
185 ber_add_integer(struct ber_element *prev, long long val)
186 {
187         struct ber_element *elm;
188         u_int i, len = 0;
189         u_char cur, last = 0;
190
191         if ((elm = ber_get_element(BER_TYPE_INTEGER)) == NULL)
192                 return NULL;
193
194         elm->be_numeric = val;
195
196         for (i = 0; i < sizeof(long long); i++) {
197                 cur = val & 0xff;
198                 if (cur != 0 && cur != 0xff)
199                         len = i;
200                 if ((cur == 0 && last & 0x80) ||
201                     (cur == 0xff && (last & 0x80) == 0))
202                         len = i;
203                 val >>= 8;
204                 last = cur;
205         }
206         elm->be_len = len + 1;
207
208         ber_link_elements(prev, elm);
209
210         return elm;
211 }
212
213 int
214 ber_get_integer(struct ber_element *elm, long long *n)
215 {
216         if (elm->be_encoding != BER_TYPE_INTEGER)
217                 return -1;
218
219         *n = elm->be_numeric;
220         return 0;
221 }
222
223 int
224 ber_get_enumerated(struct ber_element *elm, long long *n)
225 {
226         if (elm->be_encoding != BER_TYPE_ENUMERATED)
227                 return -1;
228
229         *n = elm->be_numeric;
230         return 0;
231 }
232
233
234 struct ber_element *
235 ber_add_boolean(struct ber_element *prev, int bool)
236 {
237         struct ber_element *elm;
238
239         if ((elm = ber_get_element(BER_TYPE_BOOLEAN)) == NULL)
240                 return NULL;
241
242         elm->be_numeric = bool ? 0xff : 0;
243         elm->be_len = 1;
244
245         ber_link_elements(prev, elm);
246
247         return elm;
248 }
249
250 int
251 ber_get_boolean(struct ber_element *elm, int *b)
252 {
253         if (elm->be_encoding != BER_TYPE_BOOLEAN)
254                 return -1;
255
256         *b = !(elm->be_numeric == 0);
257         return 0;
258 }
259
260 struct ber_element *
261 ber_add_string(struct ber_element *prev, const char *string)
262 {
263         return ber_add_nstring(prev, string, strlen(string));
264 }
265
266 struct ber_element *
267 ber_add_nstring(struct ber_element *prev, const char *string0, size_t len)
268 {
269         struct ber_element *elm;
270         char *string;
271
272         if ((string = calloc(1, len)) == NULL)
273                 return NULL;
274         if ((elm = ber_get_element(BER_TYPE_OCTETSTRING)) == NULL) {
275                 free(string);
276                 return NULL;
277         }
278
279         bcopy(string0, string, len);
280         elm->be_val = string;
281         elm->be_len = len;
282         elm->be_free = 1;               /* free string on cleanup */
283
284         ber_link_elements(prev, elm);
285
286         return elm;
287 }
288
289 int
290 ber_get_string(struct ber_element *elm, char **s)
291 {
292         if (elm->be_encoding != BER_TYPE_OCTETSTRING)
293                 return -1;
294
295         *s = elm->be_val;
296         return 0;
297 }
298
299 int
300 ber_get_nstring(struct ber_element *elm, void **p, size_t *len)
301 {
302         if (elm->be_encoding != BER_TYPE_OCTETSTRING)
303                 return -1;
304
305         *p = elm->be_val;
306         *len = elm->be_len;
307         return 0;
308 }
309
310 struct ber_element *
311 ber_add_bitstring(struct ber_element *prev, const void *v0, size_t len)
312 {
313         struct ber_element *elm;
314         void *v;
315
316         if ((v = calloc(1, len)) == NULL)
317                 return NULL;
318         if ((elm = ber_get_element(BER_TYPE_BITSTRING)) == NULL) {
319                 free(v);
320                 return NULL;
321         }
322
323         bcopy(v0, v, len);
324         elm->be_val = v;
325         elm->be_len = len;
326         elm->be_free = 1;               /* free string on cleanup */
327
328         ber_link_elements(prev, elm);
329
330         return elm;
331 }
332
333 int
334 ber_get_bitstring(struct ber_element *elm, void **v, size_t *len)
335 {
336         if (elm->be_encoding != BER_TYPE_BITSTRING)
337                 return -1;
338
339         *v = elm->be_val;
340         *len = elm->be_len;
341         return 0;
342 }
343
344 struct ber_element *
345 ber_add_null(struct ber_element *prev)
346 {
347         struct ber_element *elm;
348
349         if ((elm = ber_get_element(BER_TYPE_NULL)) == NULL)
350                 return NULL;
351
352         ber_link_elements(prev, elm);
353
354         return elm;
355 }
356
357 int
358 ber_get_null(struct ber_element *elm)
359 {
360         if (elm->be_encoding != BER_TYPE_NULL)
361                 return -1;
362
363         return 0;
364 }
365
366 struct ber_element *
367 ber_add_eoc(struct ber_element *prev)
368 {
369         struct ber_element *elm;
370
371         if ((elm = ber_get_element(BER_TYPE_EOC)) == NULL)
372                 return NULL;
373
374         ber_link_elements(prev, elm);
375
376         return elm;
377 }
378
379 int
380 ber_get_eoc(struct ber_element *elm)
381 {
382         if (elm->be_encoding != BER_TYPE_EOC)
383                 return -1;
384
385         return 0;
386 }
387
388 size_t
389 ber_oid2ber(struct ber_oid *o, u_int8_t *buf, size_t len)
390 {
391         u_int32_t        v;
392         u_int            i, j = 0, k;
393
394         if (o->bo_n < BER_MIN_OID_LEN || o->bo_n > BER_MAX_OID_LEN ||
395             o->bo_id[0] > 2 || o->bo_id[1] > 40)
396                 return (0);
397
398         v = (o->bo_id[0] * 40) + o->bo_id[1];
399         for (i = 2, j = 0; i <= o->bo_n; v = o->bo_id[i], i++) {
400                 for (k = 28; k >= 7; k -= 7) {
401                         if (v >= (u_int)(1 << k)) {
402                                 if (len)
403                                         buf[j] = v >> k | BER_TAG_MORE;
404                                 j++;
405                         }
406                 }
407                 if (len)
408                         buf[j] = v & BER_TAG_TYPE_MASK;
409                 j++;
410         }
411
412         return (j);
413 }
414
415 int
416 ber_string2oid(const char *oidstr, struct ber_oid *o)
417 {
418         char                    *sp, *p, str[BUFSIZ];
419         const char              *errstr;
420
421         if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
422                 return (-1);
423         bzero(o, sizeof(*o));
424
425         /* Parse OID strings in the common forms n.n.n, n_n_n_n, or n-n-n */
426         for (p = sp = str; p != NULL; sp = p) {
427                 if ((p = strpbrk(p, "._-")) != NULL)
428                         *p++ = '\0';
429                 o->bo_id[o->bo_n++] = strtonum(sp, 0, UINT_MAX, &errstr);
430                 if (errstr || o->bo_n > BER_MAX_OID_LEN)
431                         return (-1);
432         }
433
434         return (0);
435 }
436
437 struct ber_element *
438 ber_add_oid(struct ber_element *prev, struct ber_oid *o)
439 {
440         struct ber_element      *elm;
441         u_int8_t                *buf;
442         size_t                   len;
443
444         if ((elm = ber_get_element(BER_TYPE_OBJECT)) == NULL)
445                 return (NULL);
446
447         if ((len = ber_oid2ber(o, NULL, 0)) == 0)
448                 goto fail;
449
450         if ((buf = calloc(1, len)) == NULL)
451                 goto fail;
452
453         elm->be_val = buf;
454         elm->be_len = len;
455         elm->be_free = 1;
456
457         if (ber_oid2ber(o, buf, len) != len)
458                 goto fail;
459
460         ber_link_elements(prev, elm);
461
462         return (elm);
463
464  fail:
465         ber_free_elements(elm);
466         return (NULL);
467 }
468
469 struct ber_element *
470 ber_add_noid(struct ber_element *prev, struct ber_oid *o, int n)
471 {
472         struct ber_oid           no;
473
474         if (n > BER_MAX_OID_LEN)
475                 return (NULL);
476         no.bo_n = n;
477         bcopy(&o->bo_id, &no.bo_id, sizeof(no.bo_id));
478
479         return (ber_add_oid(prev, &no));
480 }
481
482 struct ber_element *
483 ber_add_oidstring(struct ber_element *prev, const char *oidstr)
484 {
485         struct ber_oid           o;
486
487         if (ber_string2oid(oidstr, &o) == -1)
488                 return (NULL);
489
490         return (ber_add_oid(prev, &o));
491 }
492
493 int
494 ber_get_oid(struct ber_element *elm, struct ber_oid *o)
495 {
496         u_int8_t        *buf;
497         size_t           len, i = 0, j = 0;
498
499         if (elm->be_encoding != BER_TYPE_OBJECT)
500                 return (-1);
501
502         buf = elm->be_val;
503         len = elm->be_len;
504
505         if (!buf[i])
506                 return (-1);
507
508         bzero(o, sizeof(*o));
509         o->bo_id[j++] = buf[i] / 40;
510         o->bo_id[j++] = buf[i++] % 40;
511         for (; i < len && j < BER_MAX_OID_LEN; i++) {
512                 o->bo_id[j] = (o->bo_id[j] << 7) + (buf[i] & ~0x80);
513                 if (buf[i] & 0x80)
514                         continue;
515                 j++;
516         }
517         o->bo_n = j;
518
519         return (0);
520 }
521
522 struct ber_element *
523 ber_printf_elements(struct ber_element *ber, char *fmt, ...)
524 {
525         va_list                  ap;
526         int                      d, class;
527         size_t                   len;
528         unsigned long            type;
529         long long                i;
530         char                    *s;
531         void                    *p;
532         struct ber_oid          *o;
533         struct ber_element      *sub = ber, *e;
534
535         va_start(ap, fmt);
536         while (*fmt) {
537                 switch (*fmt++) {
538                 case 'B':
539                         p = va_arg(ap, void *);
540                         len = va_arg(ap, size_t);
541                         if ((ber = ber_add_bitstring(ber, p, len)) == NULL)
542                                 goto fail;
543                         break;
544                 case 'b':
545                         d = va_arg(ap, int);
546                         if ((ber = ber_add_boolean(ber, d)) == NULL)
547                                 goto fail;
548                         break;
549                 case 'd':
550                         d = va_arg(ap, int);
551                         if ((ber = ber_add_integer(ber, d)) == NULL)
552                                 goto fail;
553                         break;
554                 case 'e':
555                         e = va_arg(ap, struct ber_element *);
556                         ber_link_elements(ber, e);
557                         break;
558                 case 'E':
559                         i = va_arg(ap, long long);
560                         if ((ber = ber_add_enumerated(ber, i)) == NULL)
561                                 goto fail;
562                         break;
563                 case 'i':
564                         i = va_arg(ap, long long);
565                         if ((ber = ber_add_integer(ber, i)) == NULL)
566                                 goto fail;
567                         break;
568                 case 'O':
569                         o = va_arg(ap, struct ber_oid *);
570                         if ((ber = ber_add_oid(ber, o)) == NULL)
571                                 goto fail;
572                         break;
573                 case 'o':
574                         s = va_arg(ap, char *);
575                         if ((ber = ber_add_oidstring(ber, s)) == NULL)
576                                 goto fail;
577                         break;
578                 case 's':
579                         s = va_arg(ap, char *);
580                         if ((ber = ber_add_string(ber, s)) == NULL)
581                                 goto fail;
582                         break;
583                 case 't':
584                         class = va_arg(ap, int);
585                         type = va_arg(ap, unsigned long);
586                         ber_set_header(ber, class, type);
587                         break;
588                 case 'x':
589                         s = va_arg(ap, char *);
590                         len = va_arg(ap, size_t);
591                         if ((ber = ber_add_nstring(ber, s, len)) == NULL)
592                                 goto fail;
593                         break;
594                 case '0':
595                         if ((ber = ber_add_null(ber)) == NULL)
596                                 goto fail;
597                         break;
598                 case '{':
599                         if ((ber = sub = ber_add_sequence(ber)) == NULL)
600                                 goto fail;
601                         break;
602                 case '(':
603                         if ((ber = sub = ber_add_set(ber)) == NULL)
604                                 goto fail;
605                         break;
606                 case '}':
607                 case ')':
608                         ber = sub;
609                         break;
610                 case '.':
611                         if ((e = ber_add_eoc(ber)) == NULL)
612                                 goto fail;
613                         ber = e;
614                         break;
615                 default:
616                         break;
617                 }
618         }
619         va_end(ap);
620
621         return (ber);
622  fail:
623         va_end(ap);
624         return (NULL);
625 }
626
627 int
628 ber_scanf_elements(struct ber_element *ber, char *fmt, ...)
629 {
630 #define _MAX_SEQ                 128
631         va_list                  ap;
632         int                     *d, level = -1;
633         unsigned long           *t;
634         long long               *i;
635         void                    **ptr;
636         size_t                  *len, ret = 0, n = strlen(fmt);
637         char                    **s;
638         struct ber_oid          *o;
639         struct ber_element      *parent[_MAX_SEQ], **e;
640
641         bzero(parent, sizeof(struct ber_element *) * _MAX_SEQ);
642
643         va_start(ap, fmt);
644         while (*fmt) {
645                 switch (*fmt++) {
646                 case 'B':
647                         ptr = va_arg(ap, void **);
648                         len = va_arg(ap, size_t *);
649                         if (ber_get_bitstring(ber, ptr, len) == -1)
650                                 goto fail;
651                         ret++;
652                         break;
653                 case 'b':
654                         d = va_arg(ap, int *);
655                         if (ber_get_boolean(ber, d) == -1)
656                                 goto fail;
657                         ret++;
658                         break;
659                 case 'e':
660                         e = va_arg(ap, struct ber_element **);
661                         *e = ber;
662                         ret++;
663                         continue;
664                 case 'E':
665                         i = va_arg(ap, long long *);
666                         if (ber_get_enumerated(ber, i) == -1)
667                                 goto fail;
668                         ret++;
669                         break;
670                 case 'i':
671                         i = va_arg(ap, long long *);
672                         if (ber_get_integer(ber, i) == -1)
673                                 goto fail;
674                         ret++;
675                         break;
676                 case 'o':
677                         o = va_arg(ap, struct ber_oid *);
678                         if (ber_get_oid(ber, o) == -1)
679                                 goto fail;
680                         ret++;
681                         break;
682                 case 'S':
683                         ret++;
684                         break;
685                 case 's':
686                         s = va_arg(ap, char **);
687                         if (ber_get_string(ber, s) == -1)
688                                 goto fail;
689                         ret++;
690                         break;
691                 case 't':
692                         d = va_arg(ap, int *);
693                         t = va_arg(ap, unsigned long *);
694                         *d = ber->be_class;
695                         *t = ber->be_type;
696                         ret++;
697                         continue;
698                 case 'x':
699                         ptr = va_arg(ap, void **);
700                         len = va_arg(ap, size_t *);
701                         if (ber_get_nstring(ber, ptr, len) == -1)
702                                 goto fail;
703                         ret++;
704                         break;
705                 case '0':
706                         if (ber->be_encoding != BER_TYPE_NULL)
707                                 goto fail;
708                         ret++;
709                         break;
710                 case '.':
711                         if (ber->be_encoding != BER_TYPE_EOC)
712                                 goto fail;
713                         ret++;
714                         break;
715                 case '{':
716                 case '(':
717                         if (ber->be_encoding != BER_TYPE_SEQUENCE &&
718                             ber->be_encoding != BER_TYPE_SET)
719                                 goto fail;
720                         if (ber->be_sub == NULL || level >= _MAX_SEQ-1)
721                                 goto fail;
722                         parent[++level] = ber;
723                         ber = ber->be_sub;
724                         ret++;
725                         continue;
726                 case '}':
727                 case ')':
728                         if (level < 0 || parent[level] == NULL)
729                                 goto fail;
730                         ber = parent[level--];
731                         ret++;
732                         continue;
733                 default:
734                         goto fail;
735                 }
736
737                 if (ber->be_next == NULL)
738                         continue;
739                 ber = ber->be_next;
740         }
741         va_end(ap);
742         return (ret == n ? 0 : -1);
743
744  fail:
745         va_end(ap);
746         return (-1);
747
748 }
749
750 /*
751  * write ber elements to the socket
752  *
753  * params:
754  *      ber     holds the socket
755  *      root    fully populated element tree
756  *
757  * returns:
758  *      >=0     number of bytes written
759  *      -1      on failure and sets errno
760  */
761 int
762 ber_write_elements(struct ber *ber, struct ber_element *root)
763 {
764         size_t len;
765
766         /* calculate length because only the definite form is required */
767         len = ber_calc_len(root);
768         DPRINTF("write ber element of %zd bytes length\n", len);
769
770         if (ber->br_wbuf != NULL && ber->br_wbuf + len > ber->br_wend) {
771                 free(ber->br_wbuf);
772                 ber->br_wbuf = NULL;
773         }
774         if (ber->br_wbuf == NULL) {
775                 if ((ber->br_wbuf = malloc(len)) == NULL)
776                         return -1;
777                 ber->br_wend = ber->br_wbuf + len;
778         }
779
780         /* reset write pointer */
781         ber->br_wptr = ber->br_wbuf;
782
783         if (ber_dump_element(ber, root) == -1)
784                 return -1;
785
786         /* XXX this should be moved to a different function */
787         if (ber->fd != -1)
788                 return write(ber->fd, ber->br_wbuf, len);
789
790         return (len);
791 }
792
793 /*
794  * read ber elements from the socket
795  *
796  * params:
797  *      ber     holds the socket and lot more
798  *      root    if NULL, build up an element tree from what we receive on
799  *              the wire. If not null, use the specified encoding for the
800  *              elements received.
801  *
802  * returns:
803  *      !=NULL, elements read and store in the ber_element tree
804  *      NULL, type mismatch or read error
805  */
806 struct ber_element *
807 ber_read_elements(struct ber *ber, struct ber_element *elm)
808 {
809         struct ber_element *root = elm;
810
811         if (root == NULL) {
812                 if ((root = ber_get_element(0)) == NULL)
813                         return NULL;
814         }
815
816         DPRINTF("read ber elements, root %p\n", root);
817
818         if (ber_read_element(ber, root) == -1) {
819                 /* Cleanup if root was allocated by us */
820                 if (elm == NULL)
821                         ber_free_elements(root);
822                 return NULL;
823         }
824
825         return root;
826 }
827
828 void
829 ber_free_elements(struct ber_element *root)
830 {
831         if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
832             root->be_encoding == BER_TYPE_SET))
833                 ber_free_elements(root->be_sub);
834         if (root->be_next)
835                 ber_free_elements(root->be_next);
836         if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
837             root->be_encoding == BER_TYPE_BITSTRING ||
838             root->be_encoding == BER_TYPE_OBJECT))
839                 free(root->be_val);
840         free(root);
841 }
842
843 size_t
844 ber_calc_len(struct ber_element *root)
845 {
846         unsigned long t;
847         size_t s;
848         size_t size = 2;        /* minimum 1 byte head and 1 byte size */
849
850         /* calculate the real length of a sequence or set */
851         if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
852             root->be_encoding == BER_TYPE_SET))
853                 root->be_len = ber_calc_len(root->be_sub);
854
855         /* fix header length for extended types */
856         if (root->be_type > BER_TYPE_SINGLE_MAX)
857                 for (t = root->be_type; t > 0; t >>= 7)
858                         size++;
859         if (root->be_len >= BER_TAG_MORE)
860                 for (s = root->be_len; s > 0; s >>= 8)
861                         size++;
862
863         /* calculate the length of the following elements */
864         if (root->be_next)
865                 size += ber_calc_len(root->be_next);
866
867         /* This is an empty element, do not use a minimal size */
868         if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
869                 return (0);
870
871         return (root->be_len + size);
872 }
873
874 /*
875  * internal functions
876  */
877
878 static int
879 ber_dump_element(struct ber *ber, struct ber_element *root)
880 {
881         unsigned long long l;
882         int i;
883         uint8_t u;
884
885         ber_dump_header(ber, root);
886
887         switch (root->be_encoding) {
888         case BER_TYPE_BOOLEAN:
889         case BER_TYPE_INTEGER:
890         case BER_TYPE_ENUMERATED:
891                 l = (unsigned long long)root->be_numeric;
892                 for (i = root->be_len; i > 0; i--) {
893                         u = (l >> ((i - 1) * 8)) & 0xff;
894                         ber_putc(ber, u);
895                 }
896                 break;
897         case BER_TYPE_BITSTRING:
898                 return -1;
899         case BER_TYPE_OCTETSTRING:
900         case BER_TYPE_OBJECT:
901                 ber_write(ber, root->be_val, root->be_len);
902                 break;
903         case BER_TYPE_NULL:     /* no payload */
904         case BER_TYPE_EOC:
905                 break;
906         case BER_TYPE_SEQUENCE:
907         case BER_TYPE_SET:
908                 if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
909                         return -1;
910                 break;
911         }
912
913         if (root->be_next == NULL)
914                 return 0;
915         return ber_dump_element(ber, root->be_next);
916 }
917
918 static void
919 ber_dump_header(struct ber *ber, struct ber_element *root)
920 {
921         u_char  id = 0, t, buf[8];
922         unsigned long type;
923         size_t size;
924
925         /* class universal, type encoding depending on type value */
926         /* length encoding */
927         if (root->be_type <= BER_TYPE_SINGLE_MAX) {
928                 id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
929                 if (root->be_encoding == BER_TYPE_SEQUENCE ||
930                     root->be_encoding == BER_TYPE_SET)
931                         id |= BER_TYPE_CONSTRUCTED;
932
933                 ber_putc(ber, id);
934         } else {
935                 id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
936                 if (root->be_encoding == BER_TYPE_SEQUENCE ||
937                     root->be_encoding == BER_TYPE_SET)
938                         id |= BER_TYPE_CONSTRUCTED;
939
940                 ber_putc(ber, id);
941
942                 for (t = 0, type = root->be_type; type > 0; type >>= 7)
943                         buf[t++] = type & ~BER_TAG_MORE;
944
945                 while (t-- > 0) {
946                         if (t > 0)
947                                 buf[t] |= BER_TAG_MORE;
948                         ber_putc(ber, buf[t]);
949                 }
950         }
951
952         if (root->be_len < BER_TAG_MORE) {
953                 /* short form */
954                 ber_putc(ber, root->be_len);
955         } else {
956                 for (t = 0, size = root->be_len; size > 0; size >>= 8)
957                         buf[t++] = size & 0xff;
958
959                 ber_putc(ber, t | BER_TAG_MORE);
960
961                 while (t > 0)
962                         ber_putc(ber, buf[--t]);
963         }
964 }
965
966 static void
967 ber_putc(struct ber *ber, u_char c)
968 {
969         if (ber->br_wptr + 1 <= ber->br_wend)
970                 *ber->br_wptr = c;
971         ber->br_wptr++;
972 }
973
974 static void
975 ber_write(struct ber *ber, void *buf, size_t len)
976 {
977         if (ber->br_wptr + len <= ber->br_wend)
978                 bcopy(buf, ber->br_wptr, len);
979         ber->br_wptr += len;
980 }
981
982 /*
983  * extract a BER encoded tag. There are two types, a short and long form.
984  */
985 static ssize_t
986 get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
987 {
988         u_char u;
989         size_t i = 0;
990         unsigned long t = 0;
991
992         if (ber_getc(b, &u) == -1)
993                 return -1;
994
995         *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
996         *cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
997
998         if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
999                 *tag = u & BER_TAG_MASK;
1000                 return 1;
1001         }
1002
1003         do {
1004                 if (ber_getc(b, &u) == -1)
1005                         return -1;
1006                 t = (t << 7) | (u & ~BER_TAG_MORE);
1007                 i++;
1008         } while (u & BER_TAG_MORE);
1009
1010         if (i > sizeof(unsigned long)) {
1011                 errno = ERANGE;
1012                 return -1;
1013         }
1014
1015         *tag = t;
1016         return i + 1;
1017 }
1018
1019 /*
1020  * extract length of a ber object -- if length is unknown an error is returned.
1021  */
1022 static ssize_t
1023 get_len(struct ber *b, ssize_t *len)
1024 {
1025         u_char  u, n;
1026         ssize_t s, r;
1027
1028         if (ber_getc(b, &u) == -1)
1029                 return -1;
1030         if ((u & BER_TAG_MORE) == 0) {
1031                 /* short form */
1032                 *len = u;
1033                 return 1;
1034         }
1035
1036         n = u & ~BER_TAG_MORE;
1037         if (sizeof(ssize_t) < n) {
1038                 errno = ERANGE;
1039                 return -1;
1040         }
1041         r = n + 1;
1042
1043         for (s = 0; n > 0; n--) {
1044                 if (ber_getc(b, &u) == -1)
1045                         return -1;
1046                 s = (s << 8) | u;
1047         }
1048
1049         if (s < 0) {
1050                 /* overflow */
1051                 errno = ERANGE;
1052                 return -1;
1053         }
1054
1055         if (s == 0) {
1056                 /* invalid encoding */
1057                 errno = EINVAL;
1058                 return -1;
1059         }
1060
1061         *len = s;
1062         return r;
1063 }
1064
1065 static ssize_t
1066 ber_read_element(struct ber *ber, struct ber_element *elm)
1067 {
1068         long long val = 0;
1069         struct ber_element *next;
1070         unsigned long type;
1071         int i, class, cstruct;
1072         ssize_t len, r, totlen = 0;
1073         u_char c;
1074
1075         if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
1076                 return -1;
1077         DPRINTF("ber read got class %d type %lu, %s\n",
1078             class, type, cstruct ? "constructive" : "primitive");
1079         totlen += r;
1080         if ((r = get_len(ber, &len)) == -1)
1081                 return -1;
1082         DPRINTF("ber read element size %zd\n", len);
1083         totlen += r + len;
1084
1085         /*
1086          * If using an external buffer and the total size of the element
1087          * is larger, then the external buffer don't bother to continue.
1088          */
1089         if (ber->fd == -1 && len > ber->br_rend - ber->br_rptr) {
1090                 errno = ECANCELED;
1091                 return -1;
1092         }
1093
1094         elm->be_type = type;
1095         elm->be_len = len;
1096         elm->be_class = class;
1097
1098         if (elm->be_encoding == 0) {
1099                 /* try to figure out the encoding via class, type and cstruct */
1100                 if (cstruct)
1101                         elm->be_encoding = BER_TYPE_SEQUENCE;
1102                 else if (class == BER_CLASS_UNIVERSAL)
1103                         elm->be_encoding = type;
1104                 else if (ber->br_application != NULL) {
1105                         /*
1106                          * Ask the application to map the encoding to a
1107                          * universal type. For example, a SMI IpAddress
1108                          * type is defined as 4 byte OCTET STRING.
1109                          */
1110                         elm->be_encoding = (*ber->br_application)(elm);
1111                 } else
1112                         /* last resort option */
1113                         elm->be_encoding = BER_TYPE_NULL;
1114         }
1115
1116         switch (elm->be_encoding) {
1117         case BER_TYPE_EOC:      /* End-Of-Content */
1118                 break;
1119         case BER_TYPE_BOOLEAN:
1120         case BER_TYPE_INTEGER:
1121         case BER_TYPE_ENUMERATED:
1122                 if (len > (ssize_t)sizeof(long long))
1123                         return -1;
1124                 for (i = 0; i < len; i++) {
1125                         if (ber_getc(ber, &c) != 1)
1126                                 return -1;
1127                         val <<= 8;
1128                         val |= c;
1129                 }
1130
1131                 /* sign extend if MSB is set */
1132                 if (val >> ((i - 1) * 8) & 0x80)
1133                         val |= ULLONG_MAX << (i * 8);
1134                 elm->be_numeric = val;
1135                 break;
1136         case BER_TYPE_BITSTRING:
1137                 elm->be_val = malloc(len);
1138                 if (elm->be_val == NULL)
1139                         return -1;
1140                 elm->be_free = 1;
1141                 elm->be_len = len;
1142                 ber_read(ber, elm->be_val, len);
1143                 break;
1144         case BER_TYPE_OCTETSTRING:
1145         case BER_TYPE_OBJECT:
1146                 elm->be_val = malloc(len + 1);
1147                 if (elm->be_val == NULL)
1148                         return -1;
1149                 elm->be_free = 1;
1150                 elm->be_len = len;
1151                 ber_read(ber, elm->be_val, len);
1152                 ((u_char *)elm->be_val)[len] = '\0';
1153                 break;
1154         case BER_TYPE_NULL:     /* no payload */
1155                 if (len != 0)
1156                         return -1;
1157                 break;
1158         case BER_TYPE_SEQUENCE:
1159         case BER_TYPE_SET:
1160                 if (elm->be_sub == NULL) {
1161                         if ((elm->be_sub = ber_get_element(0)) == NULL)
1162                                 return -1;
1163                 }
1164                 next = elm->be_sub;
1165                 while (len > 0) {
1166                         r = ber_read_element(ber, next);
1167                         if (r == -1)
1168                                 return -1;
1169                         len -= r;
1170                         if (len > 0 && next->be_next == NULL) {
1171                                 if ((next->be_next = ber_get_element(0)) ==
1172                                     NULL)
1173                                         return -1;
1174                         }
1175                         next = next->be_next;
1176                 }
1177                 break;
1178         }
1179         return totlen;
1180 }
1181
1182 static ssize_t
1183 ber_readbuf(struct ber *b, void *buf, size_t nbytes)
1184 {
1185         size_t   sz;
1186         size_t   len;
1187
1188         if (b->br_rbuf == NULL)
1189                 return -1;
1190
1191         sz = b->br_rend - b->br_rptr;
1192         len = MINIMUM(nbytes, sz);
1193         if (len == 0) {
1194                 errno = ECANCELED;
1195                 return (-1);    /* end of buffer and parser wants more data */
1196         }
1197
1198         bcopy(b->br_rptr, buf, len);
1199         b->br_rptr += len;
1200
1201         return (len);
1202 }
1203
1204 void
1205 ber_set_readbuf(struct ber *b, void *buf, size_t len)
1206 {
1207         b->br_rbuf = b->br_rptr = buf;
1208         b->br_rend = (u_int8_t *)buf + len;
1209 }
1210
1211 ssize_t
1212 ber_get_writebuf(struct ber *b, void **buf)
1213 {
1214         if (b->br_wbuf == NULL)
1215                 return -1;
1216         *buf = b->br_wbuf;
1217         return (b->br_wend - b->br_wbuf);
1218 }
1219
1220 void
1221 ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
1222 {
1223         b->br_application = cb;
1224 }
1225
1226 void
1227 ber_free(struct ber *b)
1228 {
1229         free(b->br_wbuf);
1230 }
1231
1232 static ssize_t
1233 ber_getc(struct ber *b, u_char *c)
1234 {
1235         ssize_t r;
1236         /*
1237          * XXX calling read here is wrong in many ways. The most obvious one
1238          * being that we will block till data arrives.
1239          * But for now it is _good enough_ *gulp*
1240          */
1241         if (b->fd == -1)
1242                 r = ber_readbuf(b, c, 1);
1243         else
1244                 r = read(b->fd, c, 1);
1245         return r;
1246 }
1247
1248 static ssize_t
1249 ber_read(struct ber *ber, void *buf, size_t len)
1250 {
1251         u_char *b = buf;
1252         ssize_t r, remain = len;
1253
1254         /*
1255          * XXX calling read here is wrong in many ways. The most obvious one
1256          * being that we will block till data arrives.
1257          * But for now it is _good enough_ *gulp*
1258          */
1259
1260         while (remain > 0) {
1261                 if (ber->fd == -1)
1262                         r = ber_readbuf(ber, b, remain);
1263                 else
1264                         r = read(ber->fd, b, remain);
1265                 if (r == -1) {
1266                         if (errno == EINTR || errno == EAGAIN)
1267                                 continue;
1268                         return -1;
1269                 }
1270                 if (r == 0)
1271                         return (b - (u_char *)buf);
1272                 b += r;
1273                 remain -= r;
1274         }
1275         return (b - (u_char *)buf);
1276 }