[BACK]Return to ber.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ldap

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: }