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

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