Annotation of src/usr.bin/ldap/ber.c, Revision 1.1
1.1 ! reyk 1: /* $OpenBSD: ber.c,v 1.13 2018/02/08 18:02:06 jca 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: memset(o, 0, 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: memset(o, 0, 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: ber_free_elements(ber);
! 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: memset(parent, 0, 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 (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: return (len);
! 787: }
! 788:
! 789: /*
! 790: * read ber elements from the socket
! 791: *
! 792: * params:
! 793: * ber holds the socket and lot more
! 794: * root if NULL, build up an element tree from what we receive on
! 795: * the wire. If not null, use the specified encoding for the
! 796: * elements received.
! 797: *
! 798: * returns:
! 799: * !=NULL, elements read and store in the ber_element tree
! 800: * NULL, type mismatch or read error
! 801: */
! 802: struct ber_element *
! 803: ber_read_elements(struct ber *ber, struct ber_element *elm)
! 804: {
! 805: struct ber_element *root = elm;
! 806:
! 807: if (root == NULL) {
! 808: if ((root = ber_get_element(0)) == NULL)
! 809: return NULL;
! 810: }
! 811:
! 812: DPRINTF("read ber elements, root %p\n", root);
! 813:
! 814: if (ber_read_element(ber, root) == -1) {
! 815: /* Cleanup if root was allocated by us */
! 816: if (elm == NULL)
! 817: ber_free_elements(root);
! 818: return NULL;
! 819: }
! 820:
! 821: return root;
! 822: }
! 823:
! 824: void
! 825: ber_free_elements(struct ber_element *root)
! 826: {
! 827: if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
! 828: root->be_encoding == BER_TYPE_SET))
! 829: ber_free_elements(root->be_sub);
! 830: if (root->be_next)
! 831: ber_free_elements(root->be_next);
! 832: if (root->be_free && (root->be_encoding == BER_TYPE_OCTETSTRING ||
! 833: root->be_encoding == BER_TYPE_BITSTRING ||
! 834: root->be_encoding == BER_TYPE_OBJECT))
! 835: free(root->be_val);
! 836: free(root);
! 837: }
! 838:
! 839: size_t
! 840: ber_calc_len(struct ber_element *root)
! 841: {
! 842: unsigned long t;
! 843: size_t s;
! 844: size_t size = 2; /* minimum 1 byte head and 1 byte size */
! 845:
! 846: /* calculate the real length of a sequence or set */
! 847: if (root->be_sub && (root->be_encoding == BER_TYPE_SEQUENCE ||
! 848: root->be_encoding == BER_TYPE_SET))
! 849: root->be_len = ber_calc_len(root->be_sub);
! 850:
! 851: /* fix header length for extended types */
! 852: if (root->be_type > BER_TYPE_SINGLE_MAX)
! 853: for (t = root->be_type; t > 0; t >>= 7)
! 854: size++;
! 855: if (root->be_len >= BER_TAG_MORE)
! 856: for (s = root->be_len; s > 0; s >>= 8)
! 857: size++;
! 858:
! 859: /* calculate the length of the following elements */
! 860: if (root->be_next)
! 861: size += ber_calc_len(root->be_next);
! 862:
! 863: /* This is an empty element, do not use a minimal size */
! 864: if (root->be_type == BER_TYPE_EOC && root->be_len == 0)
! 865: return (0);
! 866:
! 867: return (root->be_len + size);
! 868: }
! 869:
! 870: /*
! 871: * internal functions
! 872: */
! 873:
! 874: static int
! 875: ber_dump_element(struct ber *ber, struct ber_element *root)
! 876: {
! 877: unsigned long long l;
! 878: int i;
! 879: uint8_t u;
! 880:
! 881: ber_dump_header(ber, root);
! 882:
! 883: switch (root->be_encoding) {
! 884: case BER_TYPE_BOOLEAN:
! 885: case BER_TYPE_INTEGER:
! 886: case BER_TYPE_ENUMERATED:
! 887: l = (unsigned long long)root->be_numeric;
! 888: for (i = root->be_len; i > 0; i--) {
! 889: u = (l >> ((i - 1) * 8)) & 0xff;
! 890: ber_putc(ber, u);
! 891: }
! 892: break;
! 893: case BER_TYPE_BITSTRING:
! 894: return -1;
! 895: case BER_TYPE_OCTETSTRING:
! 896: case BER_TYPE_OBJECT:
! 897: ber_write(ber, root->be_val, root->be_len);
! 898: break;
! 899: case BER_TYPE_NULL: /* no payload */
! 900: case BER_TYPE_EOC:
! 901: break;
! 902: case BER_TYPE_SEQUENCE:
! 903: case BER_TYPE_SET:
! 904: if (root->be_sub && ber_dump_element(ber, root->be_sub) == -1)
! 905: return -1;
! 906: break;
! 907: }
! 908:
! 909: if (root->be_next == NULL)
! 910: return 0;
! 911: return ber_dump_element(ber, root->be_next);
! 912: }
! 913:
! 914: static void
! 915: ber_dump_header(struct ber *ber, struct ber_element *root)
! 916: {
! 917: u_char id = 0, t, buf[8];
! 918: unsigned long type;
! 919: size_t size;
! 920:
! 921: /* class universal, type encoding depending on type value */
! 922: /* length encoding */
! 923: if (root->be_type <= BER_TYPE_SINGLE_MAX) {
! 924: id = root->be_type | (root->be_class << BER_CLASS_SHIFT);
! 925: if (root->be_encoding == BER_TYPE_SEQUENCE ||
! 926: root->be_encoding == BER_TYPE_SET)
! 927: id |= BER_TYPE_CONSTRUCTED;
! 928:
! 929: ber_putc(ber, id);
! 930: } else {
! 931: id = BER_TAG_MASK | (root->be_class << BER_CLASS_SHIFT);
! 932: if (root->be_encoding == BER_TYPE_SEQUENCE ||
! 933: root->be_encoding == BER_TYPE_SET)
! 934: id |= BER_TYPE_CONSTRUCTED;
! 935:
! 936: ber_putc(ber, id);
! 937:
! 938: for (t = 0, type = root->be_type; type > 0; type >>= 7)
! 939: buf[t++] = type & ~BER_TAG_MORE;
! 940:
! 941: while (t-- > 0) {
! 942: if (t > 0)
! 943: buf[t] |= BER_TAG_MORE;
! 944: ber_putc(ber, buf[t]);
! 945: }
! 946: }
! 947:
! 948: if (root->be_len < BER_TAG_MORE) {
! 949: /* short form */
! 950: ber_putc(ber, root->be_len);
! 951: } else {
! 952: for (t = 0, size = root->be_len; size > 0; size >>= 8)
! 953: buf[t++] = size & 0xff;
! 954:
! 955: ber_putc(ber, t | BER_TAG_MORE);
! 956:
! 957: while (t > 0)
! 958: ber_putc(ber, buf[--t]);
! 959: }
! 960: }
! 961:
! 962: static void
! 963: ber_putc(struct ber *ber, u_char c)
! 964: {
! 965: if (ber->br_wptr + 1 <= ber->br_wend)
! 966: *ber->br_wptr = c;
! 967: ber->br_wptr++;
! 968: }
! 969:
! 970: static void
! 971: ber_write(struct ber *ber, void *buf, size_t len)
! 972: {
! 973: if (ber->br_wptr + len <= ber->br_wend)
! 974: bcopy(buf, ber->br_wptr, len);
! 975: ber->br_wptr += len;
! 976: }
! 977:
! 978: /*
! 979: * extract a BER encoded tag. There are two types, a short and long form.
! 980: */
! 981: static ssize_t
! 982: get_id(struct ber *b, unsigned long *tag, int *class, int *cstruct)
! 983: {
! 984: u_char u;
! 985: size_t i = 0;
! 986: unsigned long t = 0;
! 987:
! 988: if (ber_getc(b, &u) == -1)
! 989: return -1;
! 990:
! 991: *class = (u >> BER_CLASS_SHIFT) & BER_CLASS_MASK;
! 992: *cstruct = (u & BER_TYPE_CONSTRUCTED) == BER_TYPE_CONSTRUCTED;
! 993:
! 994: if ((u & BER_TAG_MASK) != BER_TAG_MASK) {
! 995: *tag = u & BER_TAG_MASK;
! 996: return 1;
! 997: }
! 998:
! 999: do {
! 1000: if (ber_getc(b, &u) == -1)
! 1001: return -1;
! 1002: t = (t << 7) | (u & ~BER_TAG_MORE);
! 1003: i++;
! 1004: } while (u & BER_TAG_MORE);
! 1005:
! 1006: if (i > sizeof(unsigned long)) {
! 1007: errno = ERANGE;
! 1008: return -1;
! 1009: }
! 1010:
! 1011: *tag = t;
! 1012: return i + 1;
! 1013: }
! 1014:
! 1015: /*
! 1016: * extract length of a ber object -- if length is unknown an error is returned.
! 1017: */
! 1018: static ssize_t
! 1019: get_len(struct ber *b, ssize_t *len)
! 1020: {
! 1021: u_char u, n;
! 1022: ssize_t s, r;
! 1023:
! 1024: if (ber_getc(b, &u) == -1)
! 1025: return -1;
! 1026: if ((u & BER_TAG_MORE) == 0) {
! 1027: /* short form */
! 1028: *len = u;
! 1029: return 1;
! 1030: }
! 1031:
! 1032: n = u & ~BER_TAG_MORE;
! 1033: if (sizeof(ssize_t) < n) {
! 1034: errno = ERANGE;
! 1035: return -1;
! 1036: }
! 1037: r = n + 1;
! 1038:
! 1039: for (s = 0; n > 0; n--) {
! 1040: if (ber_getc(b, &u) == -1)
! 1041: return -1;
! 1042: s = (s << 8) | u;
! 1043: }
! 1044:
! 1045: if (s < 0) {
! 1046: /* overflow */
! 1047: errno = ERANGE;
! 1048: return -1;
! 1049: }
! 1050:
! 1051: if (s == 0) {
! 1052: /* invalid encoding */
! 1053: errno = EINVAL;
! 1054: return -1;
! 1055: }
! 1056:
! 1057: *len = s;
! 1058: return r;
! 1059: }
! 1060:
! 1061: static ssize_t
! 1062: ber_read_element(struct ber *ber, struct ber_element *elm)
! 1063: {
! 1064: long long val = 0;
! 1065: struct ber_element *next;
! 1066: unsigned long type;
! 1067: int i, class, cstruct;
! 1068: ssize_t len, r, totlen = 0;
! 1069: u_char c;
! 1070:
! 1071: if ((r = get_id(ber, &type, &class, &cstruct)) == -1)
! 1072: return -1;
! 1073: DPRINTF("ber read got class %d type %lu, %s\n",
! 1074: class, type, cstruct ? "constructive" : "primitive");
! 1075: totlen += r;
! 1076: if ((r = get_len(ber, &len)) == -1)
! 1077: return -1;
! 1078: DPRINTF("ber read element size %zd\n", len);
! 1079: totlen += r + len;
! 1080:
! 1081: /* If the total size of the element is larger than external
! 1082: * buffer don't bother to continue. */
! 1083: if (len > ber->br_rend - ber->br_rptr) {
! 1084: errno = ECANCELED;
! 1085: return -1;
! 1086: }
! 1087:
! 1088: elm->be_type = type;
! 1089: elm->be_len = len;
! 1090: elm->be_class = class;
! 1091:
! 1092: if (elm->be_encoding == 0) {
! 1093: /* try to figure out the encoding via class, type and cstruct */
! 1094: if (cstruct)
! 1095: elm->be_encoding = BER_TYPE_SEQUENCE;
! 1096: else if (class == BER_CLASS_UNIVERSAL)
! 1097: elm->be_encoding = type;
! 1098: else if (ber->br_application != NULL) {
! 1099: /*
! 1100: * Ask the application to map the encoding to a
! 1101: * universal type. For example, a SMI IpAddress
! 1102: * type is defined as 4 byte OCTET STRING.
! 1103: */
! 1104: elm->be_encoding = (*ber->br_application)(elm);
! 1105: } else
! 1106: /* last resort option */
! 1107: elm->be_encoding = BER_TYPE_NULL;
! 1108: }
! 1109:
! 1110: switch (elm->be_encoding) {
! 1111: case BER_TYPE_EOC: /* End-Of-Content */
! 1112: break;
! 1113: case BER_TYPE_BOOLEAN:
! 1114: case BER_TYPE_INTEGER:
! 1115: case BER_TYPE_ENUMERATED:
! 1116: if (len > (ssize_t)sizeof(long long))
! 1117: return -1;
! 1118: for (i = 0; i < len; i++) {
! 1119: if (ber_getc(ber, &c) != 1)
! 1120: return -1;
! 1121: val <<= 8;
! 1122: val |= c;
! 1123: }
! 1124:
! 1125: /* sign extend if MSB is set */
! 1126: if (val >> ((i - 1) * 8) & 0x80)
! 1127: val |= ULLONG_MAX << (i * 8);
! 1128: elm->be_numeric = val;
! 1129: break;
! 1130: case BER_TYPE_BITSTRING:
! 1131: elm->be_val = malloc(len);
! 1132: if (elm->be_val == NULL)
! 1133: return -1;
! 1134: elm->be_free = 1;
! 1135: elm->be_len = len;
! 1136: ber_read(ber, elm->be_val, len);
! 1137: break;
! 1138: case BER_TYPE_OCTETSTRING:
! 1139: case BER_TYPE_OBJECT:
! 1140: elm->be_val = malloc(len + 1);
! 1141: if (elm->be_val == NULL)
! 1142: return -1;
! 1143: elm->be_free = 1;
! 1144: elm->be_len = len;
! 1145: ber_read(ber, elm->be_val, len);
! 1146: ((u_char *)elm->be_val)[len] = '\0';
! 1147: break;
! 1148: case BER_TYPE_NULL: /* no payload */
! 1149: if (len != 0)
! 1150: return -1;
! 1151: break;
! 1152: case BER_TYPE_SEQUENCE:
! 1153: case BER_TYPE_SET:
! 1154: if (elm->be_sub == NULL) {
! 1155: if ((elm->be_sub = ber_get_element(0)) == NULL)
! 1156: return -1;
! 1157: }
! 1158: next = elm->be_sub;
! 1159: while (len > 0) {
! 1160: r = ber_read_element(ber, next);
! 1161: if (r == -1)
! 1162: return -1;
! 1163: len -= r;
! 1164: if (len > 0 && next->be_next == NULL) {
! 1165: if ((next->be_next = ber_get_element(0)) ==
! 1166: NULL)
! 1167: return -1;
! 1168: }
! 1169: next = next->be_next;
! 1170: }
! 1171: break;
! 1172: }
! 1173: return totlen;
! 1174: }
! 1175:
! 1176: static ssize_t
! 1177: ber_readbuf(struct ber *b, void *buf, size_t nbytes)
! 1178: {
! 1179: size_t sz;
! 1180: size_t len;
! 1181:
! 1182: if (b->br_rbuf == NULL)
! 1183: return -1;
! 1184:
! 1185: sz = b->br_rend - b->br_rptr;
! 1186: len = MINIMUM(nbytes, sz);
! 1187: if (len == 0) {
! 1188: errno = ECANCELED;
! 1189: return (-1); /* end of buffer and parser wants more data */
! 1190: }
! 1191:
! 1192: bcopy(b->br_rptr, buf, len);
! 1193: b->br_rptr += len;
! 1194:
! 1195: return (len);
! 1196: }
! 1197:
! 1198: void
! 1199: ber_set_readbuf(struct ber *b, void *buf, size_t len)
! 1200: {
! 1201: b->br_rbuf = b->br_rptr = buf;
! 1202: b->br_rend = (u_int8_t *)buf + len;
! 1203: }
! 1204:
! 1205: ssize_t
! 1206: ber_get_writebuf(struct ber *b, void **buf)
! 1207: {
! 1208: if (b->br_wbuf == NULL)
! 1209: return -1;
! 1210: *buf = b->br_wbuf;
! 1211: return (b->br_wend - b->br_wbuf);
! 1212: }
! 1213:
! 1214: void
! 1215: ber_set_application(struct ber *b, unsigned long (*cb)(struct ber_element *))
! 1216: {
! 1217: b->br_application = cb;
! 1218: }
! 1219:
! 1220: void
! 1221: ber_free(struct ber *b)
! 1222: {
! 1223: free(b->br_wbuf);
! 1224: }
! 1225:
! 1226: static ssize_t
! 1227: ber_getc(struct ber *b, u_char *c)
! 1228: {
! 1229: return ber_readbuf(b, c, 1);
! 1230: }
! 1231:
! 1232: static ssize_t
! 1233: ber_read(struct ber *ber, void *buf, size_t len)
! 1234: {
! 1235: u_char *b = buf;
! 1236: ssize_t r, remain = len;
! 1237:
! 1238: while (remain > 0) {
! 1239: r = ber_readbuf(ber, b, remain);
! 1240: if (r == -1)
! 1241: return -1;
! 1242: if (r == 0)
! 1243: return (b - (u_char *)buf);
! 1244: b += r;
! 1245: remain -= r;
! 1246: }
! 1247: return (b - (u_char *)buf);
! 1248: }