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

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