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

Annotation of src/usr.bin/snmp/snmp.c, Revision 1.6

1.6     ! martijn     1: /*     $OpenBSD: snmp.c,v 1.5 2019/09/18 09:52:47 martijn Exp $        */
1.1       martijn     2:
                      3: /*
                      4:  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
                      5:  * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org>
                      6:  *
                      7:  * Permission to use, copy, modify, and distribute this software for any
                      8:  * purpose with or without fee is hereby granted, provided that the above
                      9:  * copyright notice and this permission notice appear in all copies.
                     10:  *
                     11:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
                     12:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
                     13:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
                     14:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
                     15:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
                     16:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
                     17:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
                     18:  */
                     19:
                     20: #include <sys/socket.h>
                     21:
                     22: #include <errno.h>
                     23: #include <poll.h>
                     24: #include <stdlib.h>
                     25: #include <string.h>
                     26: #include <stdio.h>
                     27: #include <time.h>
                     28:
                     29: #include "ber.h"
                     30: #include "smi.h"
                     31: #include "snmp.h"
                     32:
1.4       martijn    33: #define UDP_MAXPACKET 65535
                     34:
1.1       martijn    35: static struct ber_element *
                     36:     snmp_resolve(struct snmp_agent *, struct ber_element *, int);
1.3       martijn    37: static char *
                     38:     snmp_package(struct snmp_agent *, struct ber_element *, size_t *);
                     39: static struct ber_element *
                     40:     snmp_unpackage(struct snmp_agent *, char *, size_t);
1.4       martijn    41: static void snmp_v3_free(struct snmp_v3 *);
1.5       martijn    42: static void snmp_v3_secparamsoffset(void *, size_t);
1.4       martijn    43:
                     44: struct snmp_v3 *
                     45: snmp_v3_init(int level, const char *ctxname, size_t ctxnamelen,
                     46:     struct snmp_sec *sec)
                     47: {
                     48:        struct snmp_v3 *v3;
                     49:
                     50:        if ((level & (SNMP_MSGFLAG_SECMASK | SNMP_MSGFLAG_REPORT)) != level ||
                     51:            sec == NULL) {
                     52:                errno = EINVAL;
                     53:                return NULL;
                     54:        }
                     55:        if ((v3 = calloc(1, sizeof(*v3))) == NULL)
                     56:                return NULL;
                     57:
                     58:        v3->level = level | SNMP_MSGFLAG_REPORT;
                     59:        v3->ctxnamelen = ctxnamelen;
                     60:        if (ctxnamelen != 0) {
                     61:                if ((v3->ctxname = malloc(ctxnamelen)) == NULL) {
                     62:                        free(v3);
                     63:                        return NULL;
                     64:                }
                     65:                memcpy(v3->ctxname, ctxname, ctxnamelen);
                     66:        }
                     67:        v3->sec = sec;
                     68:        return v3;
                     69: }
                     70:
                     71: int
                     72: snmp_v3_setengineid(struct snmp_v3 *v3, char *engineid, size_t engineidlen)
                     73: {
                     74:        if (v3->engineidset)
                     75:                free(v3->engineid);
                     76:        if ((v3->engineid = malloc(engineidlen)) == NULL)
                     77:                return -1;
                     78:        memcpy(v3->engineid, engineid, engineidlen);
                     79:        v3->engineidlen = engineidlen;
                     80:        v3->engineidset = 1;
                     81:        return 0;
                     82: }
1.1       martijn    83:
                     84: struct snmp_agent *
                     85: snmp_connect_v12(int fd, enum snmp_version version, const char *community)
                     86: {
                     87:        struct snmp_agent *agent;
                     88:
                     89:        if (version != SNMP_V1 && version != SNMP_V2C) {
                     90:                errno = EINVAL;
                     91:                return NULL;
                     92:        }
                     93:        if ((agent = malloc(sizeof(*agent))) == NULL)
                     94:                return NULL;
                     95:        agent->fd = fd;
                     96:        agent->version = version;
                     97:        if ((agent->community = strdup(community)) == NULL)
                     98:                goto fail;
                     99:        agent->timeout = 1;
                    100:        agent->retries = 5;
1.4       martijn   101:        agent->v3 = NULL;
1.1       martijn   102:        return agent;
                    103:
                    104: fail:
                    105:        free(agent);
                    106:        return NULL;
                    107: }
                    108:
1.4       martijn   109: struct snmp_agent *
                    110: snmp_connect_v3(int fd, struct snmp_v3 *v3)
                    111: {
                    112:        struct snmp_agent *agent;
                    113:
                    114:        if ((agent = malloc(sizeof(*agent))) == NULL)
                    115:                return NULL;
                    116:        agent->fd = fd;
                    117:        agent->version = SNMP_V3;
                    118:        agent->v3 = v3;
                    119:        agent->timeout = 1;
                    120:        agent->retries = 5;
                    121:        agent->community = NULL;
                    122:
                    123:        if (v3->sec->init(agent) == -1) {
                    124:                snmp_free_agent(agent);
                    125:                return NULL;
                    126:        }
                    127:        return agent;
                    128: }
                    129:
1.1       martijn   130: void
                    131: snmp_free_agent(struct snmp_agent *agent)
                    132: {
                    133:        free(agent->community);
1.4       martijn   134:        if (agent->v3 != NULL)
                    135:                snmp_v3_free(agent->v3);
1.1       martijn   136:        free(agent);
                    137: }
                    138:
1.4       martijn   139: static void
                    140: snmp_v3_free(struct snmp_v3 *v3)
                    141: {
                    142:        v3->sec->free(v3->sec->data);
                    143:        free(v3->sec);
                    144:        free(v3->ctxname);
                    145:        free(v3->engineid);
                    146:        free(v3);
                    147: }
                    148:
1.1       martijn   149: struct ber_element *
                    150: snmp_get(struct snmp_agent *agent, struct ber_oid *oid, size_t len)
                    151: {
                    152:        struct ber_element *pdu, *varbind;
                    153:        size_t i;
                    154:
                    155:        if ((pdu = ber_add_sequence(NULL)) == NULL)
                    156:                return NULL;
                    157:        if ((varbind = ber_printf_elements(pdu, "tddd{", BER_CLASS_CONTEXT,
                    158:            SNMP_C_GETREQ, arc4random() & 0x7fffffff, 0, 0)) == NULL)
                    159:                goto fail;
                    160:        for (i = 0; i < len; i++)
                    161:                varbind = ber_printf_elements(varbind, "{O0}", &oid[i]);
                    162:                if (varbind == NULL)
                    163:                        goto fail;
                    164:
                    165:        return snmp_resolve(agent, pdu, 1);
                    166: fail:
                    167:        ber_free_elements(pdu);
                    168:        return NULL;
                    169: }
                    170:
                    171: struct ber_element *
                    172: snmp_getnext(struct snmp_agent *agent, struct ber_oid *oid, size_t len)
                    173: {
                    174:        struct ber_element *pdu, *varbind;
                    175:        size_t i;
                    176:
                    177:        if ((pdu = ber_add_sequence(NULL)) == NULL)
                    178:                return NULL;
                    179:        if ((varbind = ber_printf_elements(pdu, "tddd{", BER_CLASS_CONTEXT,
                    180:            SNMP_C_GETNEXTREQ, arc4random() & 0x7fffffff, 0, 0)) == NULL)
                    181:                goto fail;
                    182:        for (i = 0; i < len; i++)
                    183:                varbind = ber_printf_elements(varbind, "{O0}", &oid[i]);
                    184:                if (varbind == NULL)
                    185:                        goto fail;
                    186:
                    187:        return snmp_resolve(agent, pdu, 1);
                    188: fail:
                    189:        ber_free_elements(pdu);
                    190:        return NULL;
                    191: }
                    192:
                    193: int
                    194: snmp_trap(struct snmp_agent *agent, struct timespec *uptime,
                    195:     struct ber_oid *oid, struct ber_element *custvarbind)
                    196: {
                    197:        struct ber_element *pdu, *varbind;
                    198:        struct ber_oid sysuptime, trap;
                    199:        long long ticks;
                    200:
                    201:        if ((pdu = ber_add_sequence(NULL)) == NULL)
                    202:                return -1;
                    203:        if ((varbind = ber_printf_elements(pdu, "tddd{", BER_CLASS_CONTEXT,
                    204:            SNMP_C_TRAPV2, arc4random() & 0x7fffffff, 0, 0)) == NULL)
                    205:                goto fail;
                    206:
                    207:        ticks = uptime->tv_sec * 100;
                    208:        ticks += uptime->tv_nsec / 10000000;
                    209:        if (smi_string2oid("sysUpTime.0", &sysuptime) == -1)
                    210:                goto fail;
                    211:        if ((varbind = ber_printf_elements(varbind, "{Oit}", &sysuptime, ticks,
                    212:            BER_CLASS_APPLICATION, SNMP_T_TIMETICKS)) == NULL)
                    213:                goto fail;
                    214:        if (smi_string2oid("snmpTrapOID.0", &trap) == -1)
                    215:                goto fail;
                    216:        if ((varbind = ber_printf_elements(varbind, "{OO}", &trap, oid)) == NULL)
                    217:                goto fail;
                    218:        if (custvarbind != NULL)
                    219:                ber_link_elements(varbind, custvarbind);
                    220:
                    221:        snmp_resolve(agent, pdu, 0);
                    222:        return 0;
                    223: fail:
                    224:        ber_free_elements(pdu);
                    225:        return -1;
                    226: }
                    227:
                    228: struct ber_element *
                    229: snmp_getbulk(struct snmp_agent *agent, struct ber_oid *oid, size_t len,
                    230:     int non_repeaters, int max_repetitions)
                    231: {
                    232:        struct ber_element *pdu, *varbind;
                    233:        size_t i;
                    234:
                    235:        if ((pdu = ber_add_sequence(NULL)) == NULL)
                    236:                return NULL;
                    237:        if ((varbind = ber_printf_elements(pdu, "tddd{", BER_CLASS_CONTEXT,
                    238:            SNMP_C_GETBULKREQ, arc4random() & 0x7fffffff, non_repeaters,
                    239:            max_repetitions)) == NULL)
                    240:                goto fail;
                    241:        for (i = 0; i < len; i++)
                    242:                varbind = ber_printf_elements(varbind, "{O0}", &oid[i]);
                    243:                if (varbind == NULL)
                    244:                        goto fail;
                    245:
                    246:        return snmp_resolve(agent, pdu, 1);
                    247: fail:
                    248:        ber_free_elements(pdu);
                    249:        return NULL;
                    250: }
                    251:
                    252: static struct ber_element *
                    253: snmp_resolve(struct snmp_agent *agent, struct ber_element *pdu, int reply)
                    254: {
1.3       martijn   255:        struct ber_element *varbind;
1.1       martijn   256:        struct ber_oid oid;
                    257:        struct timespec start, now;
                    258:        struct pollfd pfd;
1.3       martijn   259:        char *message;
1.1       martijn   260:        ssize_t len;
                    261:        long long reqid, rreqid;
                    262:        short direction;
                    263:        int to, nfds, ret;
                    264:        int tries;
                    265:        char buf[READ_BUF_SIZE];
                    266:
                    267:        if (ber_scanf_elements(pdu, "{i", &reqid) != 0) {
                    268:                errno = EINVAL;
                    269:                ber_free_elements(pdu);
                    270:                return NULL;
                    271:        }
                    272:
1.3       martijn   273:        if ((message = snmp_package(agent, pdu, &len)) == NULL)
1.1       martijn   274:                return NULL;
                    275:
                    276:        clock_gettime(CLOCK_MONOTONIC, &start);
                    277:        memcpy(&now, &start, sizeof(now));
                    278:        direction = POLLOUT;
                    279:        tries = agent->retries + 1;
                    280:        while (tries) {
                    281:                pfd.fd = agent->fd;
                    282:                pfd.events = direction;
                    283:                if (agent->timeout > 0) {
                    284:                        to = (agent->timeout - (now.tv_sec - start.tv_sec)) * 1000;
                    285:                        to -= (now.tv_nsec - start.tv_nsec) / 1000000;
                    286:                } else
                    287:                        to = INFTIM;
                    288:                nfds = poll(&pfd, 1, to);
                    289:                if (nfds == 0) {
                    290:                        errno = ETIMEDOUT;
                    291:                        direction = POLLOUT;
                    292:                        tries--;
                    293:                        continue;
                    294:                }
                    295:                if (nfds == -1) {
                    296:                        if (errno == EINTR)
                    297:                                continue;
                    298:                        else
                    299:                                goto fail;
                    300:                }
                    301:                if (direction == POLLOUT) {
1.3       martijn   302:                        ret = send(agent->fd, message, len, MSG_DONTWAIT);
1.1       martijn   303:                        if (ret == -1)
                    304:                                goto fail;
                    305:                        if (ret < len) {
                    306:                                errno = EBADMSG;
                    307:                                goto fail;
                    308:                        }
                    309:                        if (!reply)
                    310:                                return NULL;
                    311:                        direction = POLLIN;
                    312:                        continue;
                    313:                }
                    314:                ret = recv(agent->fd, buf, sizeof(buf), MSG_DONTWAIT);
                    315:                if (ret == 0)
                    316:                        errno = ECONNRESET;
                    317:                if (ret <= 0)
                    318:                        goto fail;
1.3       martijn   319:                if ((pdu = snmp_unpackage(agent, buf, ret)) == NULL) {
1.2       martijn   320:                        tries--;
                    321:                        direction = POLLOUT;
                    322:                        errno = EPROTO;
1.1       martijn   323:                        continue;
1.2       martijn   324:                }
1.1       martijn   325:                /* Validate pdu format and check request id */
                    326:                if (ber_scanf_elements(pdu, "{iSSe", &rreqid, &varbind) != 0 ||
1.2       martijn   327:                    varbind->be_encoding != BER_TYPE_SEQUENCE) {
                    328:                        errno = EPROTO;
                    329:                        direction = POLLOUT;
                    330:                        tries--;
                    331:                        continue;
                    332:                }
1.4       martijn   333:                if (rreqid != reqid && rreqid != 0) {
1.2       martijn   334:                        errno = EPROTO;
                    335:                        direction = POLLOUT;
                    336:                        tries--;
1.1       martijn   337:                        continue;
1.2       martijn   338:                }
1.1       martijn   339:                for (varbind = varbind->be_sub; varbind != NULL;
                    340:                    varbind = varbind->be_next) {
1.2       martijn   341:                        if (ber_scanf_elements(varbind, "{oS}", &oid) != 0) {
                    342:                                errno = EPROTO;
                    343:                                direction = POLLOUT;
                    344:                                tries--;
1.4       martijn   345:                                continue;
1.2       martijn   346:                        }
1.1       martijn   347:                }
                    348:
1.3       martijn   349:                free(message);
                    350:                return pdu;
                    351:        }
                    352:
                    353: fail:
                    354:        free(message);
                    355:        return NULL;
                    356: }
                    357:
                    358: static char *
                    359: snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len)
                    360: {
                    361:        struct ber ber;
1.6     ! martijn   362:        struct ber_element *message, *scopedpdu = NULL, *secparams, *encpdu;
1.4       martijn   363:        ssize_t securitysize, ret;
1.5       martijn   364:        size_t secparamsoffset;
1.4       martijn   365:        char *securityparams = NULL, *packet = NULL;
                    366:        long long msgid;
1.5       martijn   367:        void *cookie = NULL;
1.3       martijn   368:
                    369:        bzero(&ber, sizeof(ber));
                    370:        ber_set_application(&ber, smi_application);
                    371:
                    372:        if ((message = ber_add_sequence(NULL)) == NULL) {
                    373:                ber_free_elements(pdu);
                    374:                goto fail;
                    375:        }
                    376:
                    377:        switch (agent->version) {
                    378:        case SNMP_V1:
                    379:        case SNMP_V2C:
                    380:                if (ber_printf_elements(message, "dse", agent->version,
                    381:                    agent->community, pdu) == NULL) {
                    382:                        ber_free_elements(pdu);
                    383:                        goto fail;
                    384:                }
                    385:                break;
                    386:        case SNMP_V3:
1.4       martijn   387:                msgid = arc4random_uniform(2147483647);
                    388:                if ((scopedpdu = ber_add_sequence(NULL)) == NULL) {
                    389:                        ber_free_elements(pdu);
                    390:                        goto fail;
                    391:                }
                    392:                if (ber_printf_elements(scopedpdu, "xxe",
                    393:                    agent->v3->engineid, agent->v3->engineidlen,
                    394:                    agent->v3->ctxname, agent->v3->ctxnamelen, pdu) == NULL) {
                    395:                        ber_free_elements(pdu);
                    396:                        ber_free_elements(scopedpdu);
                    397:                        goto fail;
                    398:                }
                    399:                pdu = NULL;
                    400:                if ((securityparams = agent->v3->sec->genparams(agent,
1.5       martijn   401:                    &securitysize, &cookie)) == NULL) {
1.4       martijn   402:                        ber_free_elements(scopedpdu);
                    403:                        goto fail;
                    404:                }
1.6     ! martijn   405:                if (agent->v3->level & SNMP_MSGFLAG_PRIV) {
        !           406:                        if ((encpdu = agent->v3->sec->encpdu(agent, scopedpdu,
        !           407:                            cookie)) == NULL)
        !           408:                                goto fail;
        !           409:                        ber_free_elements(scopedpdu);
        !           410:                        scopedpdu = encpdu;
        !           411:                }
1.4       martijn   412:                if (ber_printf_elements(message, "d{idxd}xe",
                    413:                    agent->version, msgid, UDP_MAXPACKET, &(agent->v3->level),
                    414:                    (size_t) 1, agent->v3->sec->model, securityparams,
                    415:                    securitysize, scopedpdu) == NULL)
                    416:                        goto fail;
1.5       martijn   417:                if (ber_scanf_elements(message, "{SSe", &secparams) == -1)
                    418:                        goto fail;
                    419:                ber_set_writecallback(secparams, snmp_v3_secparamsoffset,
                    420:                    &secparamsoffset);
1.3       martijn   421:                break;
                    422:        }
                    423:
                    424:        if (ber_write_elements(&ber, message) == -1)
                    425:                goto fail;
                    426:        ret = ber_copy_writebuf(&ber, (void **)&packet);
                    427:
                    428:        *len = (size_t) ret;
                    429:        ber_free(&ber);
                    430:
1.5       martijn   431:        if (agent->version == SNMP_V3 && packet != NULL) {
                    432:                if (agent->v3->sec->finalparams(agent, packet,
                    433:                    ret, secparamsoffset, cookie) == -1) {
                    434:                        free(packet);
                    435:                        packet = NULL;
                    436:                }
                    437:        }
                    438:
1.3       martijn   439: fail:
1.5       martijn   440:        if (agent->version == SNMP_V3)
                    441:                agent->v3->sec->freecookie(cookie);
1.3       martijn   442:        ber_free_elements(message);
1.4       martijn   443:        free(securityparams);
1.3       martijn   444:        return packet;
                    445: }
                    446:
                    447: static struct ber_element *
                    448: snmp_unpackage(struct snmp_agent *agent, char *buf, size_t buflen)
                    449: {
                    450:        struct ber ber;
                    451:        enum snmp_version version;
                    452:        char *community;
                    453:        struct ber_element *pdu;
1.4       martijn   454:        long long msgid, model;
                    455:        int msgsz;
                    456:        char *msgflags, *secparams;
                    457:        size_t msgflagslen, secparamslen;
                    458:        struct ber_element *message = NULL, *payload, *scopedpdu, *ctxname;
                    459:        off_t secparamsoffset;
1.6     ! martijn   460:        char *encpdu, *engineid;
        !           461:        size_t encpdulen, engineidlen;
        !           462:        void *cookie = NULL;
1.3       martijn   463:
                    464:        bzero(&ber, sizeof(ber));
                    465:        ber_set_application(&ber, smi_application);
                    466:
                    467:        ber_set_readbuf(&ber, buf, buflen);
                    468:        if ((message = ber_read_elements(&ber, NULL)) == NULL)
                    469:                return NULL;
                    470:        ber_free(&ber);
                    471:
                    472:        if (ber_scanf_elements(message, "{de", &version, &payload) != 0)
                    473:                goto fail;
                    474:
                    475:        if (version != agent->version)
                    476:                goto fail;
                    477:
1.4       martijn   478:        switch (version) {
1.3       martijn   479:        case SNMP_V1:
                    480:        case SNMP_V2C:
                    481:                if (ber_scanf_elements(payload, "se", &community, &pdu) == -1)
                    482:                        goto fail;
                    483:                if (strcmp(community, agent->community) != 0)
                    484:                        goto fail;
                    485:                ber_unlink_elements(payload);
1.1       martijn   486:                ber_free_elements(message);
                    487:                return pdu;
1.3       martijn   488:        case SNMP_V3:
1.4       martijn   489:                if (ber_scanf_elements(payload, "{idxi}pxe", &msgid, &msgsz,
                    490:                    &msgflags, &msgflagslen, &model, &secparamsoffset,
                    491:                    &secparams, &secparamslen, &scopedpdu) == -1)
                    492:                        goto fail;
                    493:                if (msgflagslen != 1)
                    494:                        goto fail;
                    495:                if (agent->v3->sec->parseparams(agent, buf, buflen,
1.6     ! martijn   496:                    secparamsoffset, secparams, secparamslen, msgflags[0],
        !           497:                    &cookie) == -1) {
        !           498:                        cookie = NULL;
1.4       martijn   499:                        goto fail;
1.6     ! martijn   500:                }
        !           501:                if (msgflags[0] & SNMP_MSGFLAG_PRIV) {
        !           502:                        if (ber_scanf_elements(scopedpdu, "x", &encpdu,
        !           503:                            &encpdulen) == -1)
        !           504:                                goto fail;
        !           505:                        if ((scopedpdu = agent->v3->sec->decpdu(agent, encpdu,
        !           506:                            encpdulen, cookie)) == NULL)
        !           507:                                goto fail;
        !           508:                }
1.4       martijn   509:                if (ber_scanf_elements(scopedpdu, "{xeS{", &engineid,
                    510:                    &engineidlen, &ctxname) == -1)
                    511:                        goto fail;
                    512:                if (!agent->v3->engineidset) {
                    513:                        if (snmp_v3_setengineid(agent->v3, engineid,
                    514:                            engineidlen) == -1)
                    515:                                goto fail;
                    516:                }
                    517:                pdu = ber_unlink_elements(ctxname);
                    518:                /* Accept reports, so we can continue if possible */
                    519:                if (pdu->be_type != SNMP_C_REPORT) {
                    520:                        if ((msgflags[0] & SNMP_MSGFLAG_SECMASK) !=
                    521:                            (agent->v3->level & SNMP_MSGFLAG_SECMASK))
                    522:                                goto fail;
                    523:                }
                    524:
                    525:                ber_free_elements(message);
1.6     ! martijn   526:                agent->v3->sec->freecookie(cookie);
1.4       martijn   527:                return pdu;
1.1       martijn   528:        }
1.3       martijn   529:        /* NOTREACHED */
1.1       martijn   530:
                    531: fail:
1.6     ! martijn   532:        if (version == SNMP_V3)
        !           533:                agent->v3->sec->freecookie(cookie);
1.1       martijn   534:        ber_free_elements(message);
                    535:        return NULL;
1.5       martijn   536: }
                    537:
                    538: static void
                    539: snmp_v3_secparamsoffset(void *cookie, size_t offset)
                    540: {
                    541:        size_t *spoffset = cookie;
                    542:
                    543:        *spoffset = offset;
1.3       martijn   544: }
                    545:
                    546: ssize_t
                    547: ber_copy_writebuf(struct ber *ber, void **buf)
                    548: {
                    549:        char *bbuf;
                    550:        ssize_t ret;
                    551:
                    552:        *buf = NULL;
                    553:        if ((ret = ber_get_writebuf(ber, (void **)&bbuf)) == -1)
                    554:                return -1;
                    555:        if ((*buf = malloc(ret)) == NULL)
                    556:                return -1;
                    557:        memcpy(*buf, bbuf, ret);
                    558:        return  ret;
1.1       martijn   559: }