[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.7

1.7     ! martijn     1: /*     $OpenBSD: snmp.c,v 1.6 2019/09/18 09:54:36 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;
1.7     ! martijn   250: }
        !           251:
        !           252: struct ber_element *
        !           253: snmp_set(struct snmp_agent *agent, struct ber_element *vblist)
        !           254: {
        !           255:        struct ber_element *pdu;
        !           256:
        !           257:        if ((pdu = ber_add_sequence(NULL)) == NULL)
        !           258:                return NULL;
        !           259:        if (ber_printf_elements(pdu, "tddd{e", BER_CLASS_CONTEXT,
        !           260:            SNMP_C_SETREQ, arc4random() & 0x7fffffff, 0, 0, vblist) == NULL) {
        !           261:                ber_free_elements(pdu);
        !           262:                return NULL;
        !           263:        }
        !           264:
        !           265:        return snmp_resolve(agent, pdu, 1);
1.1       martijn   266: }
                    267:
                    268: static struct ber_element *
                    269: snmp_resolve(struct snmp_agent *agent, struct ber_element *pdu, int reply)
                    270: {
1.3       martijn   271:        struct ber_element *varbind;
1.1       martijn   272:        struct ber_oid oid;
                    273:        struct timespec start, now;
                    274:        struct pollfd pfd;
1.3       martijn   275:        char *message;
1.1       martijn   276:        ssize_t len;
                    277:        long long reqid, rreqid;
                    278:        short direction;
                    279:        int to, nfds, ret;
                    280:        int tries;
                    281:        char buf[READ_BUF_SIZE];
                    282:
                    283:        if (ber_scanf_elements(pdu, "{i", &reqid) != 0) {
                    284:                errno = EINVAL;
                    285:                ber_free_elements(pdu);
                    286:                return NULL;
                    287:        }
                    288:
1.3       martijn   289:        if ((message = snmp_package(agent, pdu, &len)) == NULL)
1.1       martijn   290:                return NULL;
                    291:
                    292:        clock_gettime(CLOCK_MONOTONIC, &start);
                    293:        memcpy(&now, &start, sizeof(now));
                    294:        direction = POLLOUT;
                    295:        tries = agent->retries + 1;
                    296:        while (tries) {
                    297:                pfd.fd = agent->fd;
                    298:                pfd.events = direction;
                    299:                if (agent->timeout > 0) {
                    300:                        to = (agent->timeout - (now.tv_sec - start.tv_sec)) * 1000;
                    301:                        to -= (now.tv_nsec - start.tv_nsec) / 1000000;
                    302:                } else
                    303:                        to = INFTIM;
                    304:                nfds = poll(&pfd, 1, to);
                    305:                if (nfds == 0) {
                    306:                        errno = ETIMEDOUT;
                    307:                        direction = POLLOUT;
                    308:                        tries--;
                    309:                        continue;
                    310:                }
                    311:                if (nfds == -1) {
                    312:                        if (errno == EINTR)
                    313:                                continue;
                    314:                        else
                    315:                                goto fail;
                    316:                }
                    317:                if (direction == POLLOUT) {
1.3       martijn   318:                        ret = send(agent->fd, message, len, MSG_DONTWAIT);
1.1       martijn   319:                        if (ret == -1)
                    320:                                goto fail;
                    321:                        if (ret < len) {
                    322:                                errno = EBADMSG;
                    323:                                goto fail;
                    324:                        }
                    325:                        if (!reply)
                    326:                                return NULL;
                    327:                        direction = POLLIN;
                    328:                        continue;
                    329:                }
                    330:                ret = recv(agent->fd, buf, sizeof(buf), MSG_DONTWAIT);
                    331:                if (ret == 0)
                    332:                        errno = ECONNRESET;
                    333:                if (ret <= 0)
                    334:                        goto fail;
1.3       martijn   335:                if ((pdu = snmp_unpackage(agent, buf, ret)) == NULL) {
1.2       martijn   336:                        tries--;
                    337:                        direction = POLLOUT;
                    338:                        errno = EPROTO;
1.1       martijn   339:                        continue;
1.2       martijn   340:                }
1.1       martijn   341:                /* Validate pdu format and check request id */
                    342:                if (ber_scanf_elements(pdu, "{iSSe", &rreqid, &varbind) != 0 ||
1.2       martijn   343:                    varbind->be_encoding != BER_TYPE_SEQUENCE) {
                    344:                        errno = EPROTO;
                    345:                        direction = POLLOUT;
                    346:                        tries--;
                    347:                        continue;
                    348:                }
1.4       martijn   349:                if (rreqid != reqid && rreqid != 0) {
1.2       martijn   350:                        errno = EPROTO;
                    351:                        direction = POLLOUT;
                    352:                        tries--;
1.1       martijn   353:                        continue;
1.2       martijn   354:                }
1.1       martijn   355:                for (varbind = varbind->be_sub; varbind != NULL;
                    356:                    varbind = varbind->be_next) {
1.2       martijn   357:                        if (ber_scanf_elements(varbind, "{oS}", &oid) != 0) {
                    358:                                errno = EPROTO;
                    359:                                direction = POLLOUT;
                    360:                                tries--;
1.4       martijn   361:                                continue;
1.2       martijn   362:                        }
1.1       martijn   363:                }
                    364:
1.3       martijn   365:                free(message);
                    366:                return pdu;
                    367:        }
                    368:
                    369: fail:
                    370:        free(message);
                    371:        return NULL;
                    372: }
                    373:
                    374: static char *
                    375: snmp_package(struct snmp_agent *agent, struct ber_element *pdu, size_t *len)
                    376: {
                    377:        struct ber ber;
1.6       martijn   378:        struct ber_element *message, *scopedpdu = NULL, *secparams, *encpdu;
1.4       martijn   379:        ssize_t securitysize, ret;
1.5       martijn   380:        size_t secparamsoffset;
1.4       martijn   381:        char *securityparams = NULL, *packet = NULL;
                    382:        long long msgid;
1.5       martijn   383:        void *cookie = NULL;
1.3       martijn   384:
                    385:        bzero(&ber, sizeof(ber));
                    386:        ber_set_application(&ber, smi_application);
                    387:
                    388:        if ((message = ber_add_sequence(NULL)) == NULL) {
                    389:                ber_free_elements(pdu);
                    390:                goto fail;
                    391:        }
                    392:
                    393:        switch (agent->version) {
                    394:        case SNMP_V1:
                    395:        case SNMP_V2C:
                    396:                if (ber_printf_elements(message, "dse", agent->version,
                    397:                    agent->community, pdu) == NULL) {
                    398:                        ber_free_elements(pdu);
                    399:                        goto fail;
                    400:                }
                    401:                break;
                    402:        case SNMP_V3:
1.4       martijn   403:                msgid = arc4random_uniform(2147483647);
                    404:                if ((scopedpdu = ber_add_sequence(NULL)) == NULL) {
                    405:                        ber_free_elements(pdu);
                    406:                        goto fail;
                    407:                }
                    408:                if (ber_printf_elements(scopedpdu, "xxe",
                    409:                    agent->v3->engineid, agent->v3->engineidlen,
                    410:                    agent->v3->ctxname, agent->v3->ctxnamelen, pdu) == NULL) {
                    411:                        ber_free_elements(pdu);
                    412:                        ber_free_elements(scopedpdu);
                    413:                        goto fail;
                    414:                }
                    415:                pdu = NULL;
                    416:                if ((securityparams = agent->v3->sec->genparams(agent,
1.5       martijn   417:                    &securitysize, &cookie)) == NULL) {
1.4       martijn   418:                        ber_free_elements(scopedpdu);
                    419:                        goto fail;
                    420:                }
1.6       martijn   421:                if (agent->v3->level & SNMP_MSGFLAG_PRIV) {
                    422:                        if ((encpdu = agent->v3->sec->encpdu(agent, scopedpdu,
                    423:                            cookie)) == NULL)
                    424:                                goto fail;
                    425:                        ber_free_elements(scopedpdu);
                    426:                        scopedpdu = encpdu;
                    427:                }
1.4       martijn   428:                if (ber_printf_elements(message, "d{idxd}xe",
                    429:                    agent->version, msgid, UDP_MAXPACKET, &(agent->v3->level),
                    430:                    (size_t) 1, agent->v3->sec->model, securityparams,
                    431:                    securitysize, scopedpdu) == NULL)
                    432:                        goto fail;
1.5       martijn   433:                if (ber_scanf_elements(message, "{SSe", &secparams) == -1)
                    434:                        goto fail;
                    435:                ber_set_writecallback(secparams, snmp_v3_secparamsoffset,
                    436:                    &secparamsoffset);
1.3       martijn   437:                break;
                    438:        }
                    439:
                    440:        if (ber_write_elements(&ber, message) == -1)
                    441:                goto fail;
                    442:        ret = ber_copy_writebuf(&ber, (void **)&packet);
                    443:
                    444:        *len = (size_t) ret;
                    445:        ber_free(&ber);
                    446:
1.5       martijn   447:        if (agent->version == SNMP_V3 && packet != NULL) {
                    448:                if (agent->v3->sec->finalparams(agent, packet,
                    449:                    ret, secparamsoffset, cookie) == -1) {
                    450:                        free(packet);
                    451:                        packet = NULL;
                    452:                }
                    453:        }
                    454:
1.3       martijn   455: fail:
1.5       martijn   456:        if (agent->version == SNMP_V3)
                    457:                agent->v3->sec->freecookie(cookie);
1.3       martijn   458:        ber_free_elements(message);
1.4       martijn   459:        free(securityparams);
1.3       martijn   460:        return packet;
                    461: }
                    462:
                    463: static struct ber_element *
                    464: snmp_unpackage(struct snmp_agent *agent, char *buf, size_t buflen)
                    465: {
                    466:        struct ber ber;
                    467:        enum snmp_version version;
                    468:        char *community;
                    469:        struct ber_element *pdu;
1.4       martijn   470:        long long msgid, model;
                    471:        int msgsz;
                    472:        char *msgflags, *secparams;
                    473:        size_t msgflagslen, secparamslen;
                    474:        struct ber_element *message = NULL, *payload, *scopedpdu, *ctxname;
                    475:        off_t secparamsoffset;
1.6       martijn   476:        char *encpdu, *engineid;
                    477:        size_t encpdulen, engineidlen;
                    478:        void *cookie = NULL;
1.3       martijn   479:
                    480:        bzero(&ber, sizeof(ber));
                    481:        ber_set_application(&ber, smi_application);
                    482:
                    483:        ber_set_readbuf(&ber, buf, buflen);
                    484:        if ((message = ber_read_elements(&ber, NULL)) == NULL)
                    485:                return NULL;
                    486:        ber_free(&ber);
                    487:
                    488:        if (ber_scanf_elements(message, "{de", &version, &payload) != 0)
                    489:                goto fail;
                    490:
                    491:        if (version != agent->version)
                    492:                goto fail;
                    493:
1.4       martijn   494:        switch (version) {
1.3       martijn   495:        case SNMP_V1:
                    496:        case SNMP_V2C:
                    497:                if (ber_scanf_elements(payload, "se", &community, &pdu) == -1)
                    498:                        goto fail;
                    499:                if (strcmp(community, agent->community) != 0)
                    500:                        goto fail;
                    501:                ber_unlink_elements(payload);
1.1       martijn   502:                ber_free_elements(message);
                    503:                return pdu;
1.3       martijn   504:        case SNMP_V3:
1.4       martijn   505:                if (ber_scanf_elements(payload, "{idxi}pxe", &msgid, &msgsz,
                    506:                    &msgflags, &msgflagslen, &model, &secparamsoffset,
                    507:                    &secparams, &secparamslen, &scopedpdu) == -1)
                    508:                        goto fail;
                    509:                if (msgflagslen != 1)
                    510:                        goto fail;
                    511:                if (agent->v3->sec->parseparams(agent, buf, buflen,
1.6       martijn   512:                    secparamsoffset, secparams, secparamslen, msgflags[0],
                    513:                    &cookie) == -1) {
                    514:                        cookie = NULL;
1.4       martijn   515:                        goto fail;
1.6       martijn   516:                }
                    517:                if (msgflags[0] & SNMP_MSGFLAG_PRIV) {
                    518:                        if (ber_scanf_elements(scopedpdu, "x", &encpdu,
                    519:                            &encpdulen) == -1)
                    520:                                goto fail;
                    521:                        if ((scopedpdu = agent->v3->sec->decpdu(agent, encpdu,
                    522:                            encpdulen, cookie)) == NULL)
                    523:                                goto fail;
                    524:                }
1.4       martijn   525:                if (ber_scanf_elements(scopedpdu, "{xeS{", &engineid,
                    526:                    &engineidlen, &ctxname) == -1)
                    527:                        goto fail;
                    528:                if (!agent->v3->engineidset) {
                    529:                        if (snmp_v3_setengineid(agent->v3, engineid,
                    530:                            engineidlen) == -1)
                    531:                                goto fail;
                    532:                }
                    533:                pdu = ber_unlink_elements(ctxname);
                    534:                /* Accept reports, so we can continue if possible */
                    535:                if (pdu->be_type != SNMP_C_REPORT) {
                    536:                        if ((msgflags[0] & SNMP_MSGFLAG_SECMASK) !=
                    537:                            (agent->v3->level & SNMP_MSGFLAG_SECMASK))
                    538:                                goto fail;
                    539:                }
                    540:
                    541:                ber_free_elements(message);
1.6       martijn   542:                agent->v3->sec->freecookie(cookie);
1.4       martijn   543:                return pdu;
1.1       martijn   544:        }
1.3       martijn   545:        /* NOTREACHED */
1.1       martijn   546:
                    547: fail:
1.6       martijn   548:        if (version == SNMP_V3)
                    549:                agent->v3->sec->freecookie(cookie);
1.1       martijn   550:        ber_free_elements(message);
                    551:        return NULL;
1.5       martijn   552: }
                    553:
                    554: static void
                    555: snmp_v3_secparamsoffset(void *cookie, size_t offset)
                    556: {
                    557:        size_t *spoffset = cookie;
                    558:
                    559:        *spoffset = offset;
1.3       martijn   560: }
                    561:
                    562: ssize_t
                    563: ber_copy_writebuf(struct ber *ber, void **buf)
                    564: {
                    565:        char *bbuf;
                    566:        ssize_t ret;
                    567:
                    568:        *buf = NULL;
                    569:        if ((ret = ber_get_writebuf(ber, (void **)&bbuf)) == -1)
                    570:                return -1;
                    571:        if ((*buf = malloc(ret)) == NULL)
                    572:                return -1;
                    573:        memcpy(*buf, bbuf, ret);
                    574:        return  ret;
1.1       martijn   575: }