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