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