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

Annotation of src/usr.bin/snmp/usm.c, Revision 1.1

1.1     ! martijn     1: /*     $OpenBSD: usm.c,v 1.16 2019/06/11 05:36:32 martijn Exp $        */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org>
        !             5:  *
        !             6:  * Permission to use, copy, modify, and distribute this software for any
        !             7:  * purpose with or without fee is hereby granted, provided that the above
        !             8:  * copyright notice and this permission notice appear in all copies.
        !             9:  *
        !            10:  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
        !            11:  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
        !            12:  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
        !            13:  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
        !            14:  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
        !            15:  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
        !            16:  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
        !            17:  */
        !            18:
        !            19: #include <sys/time.h>
        !            20:
        !            21: #include <openssl/evp.h>
        !            22: #include <openssl/hmac.h>
        !            23:
        !            24: #include <ber.h>
        !            25: #include <errno.h>
        !            26: #include <string.h>
        !            27: #include <time.h>
        !            28:
        !            29: #include "smi.h"
        !            30: #include "snmp.h"
        !            31: #include "usm.h"
        !            32:
        !            33: #define USM_MAX_DIGESTLEN 48
        !            34: #define USM_MAX_TIMEWINDOW 150
        !            35: #define USM_SALTOFFSET 8
        !            36:
        !            37: struct usm_sec {
        !            38:        struct snmp_sec snmp;
        !            39:        char *user;
        !            40:        size_t userlen;
        !            41:        int engineidset;
        !            42:        char *engineid;
        !            43:        size_t engineidlen;
        !            44:        int bootsset;
        !            45:        uint32_t boots;
        !            46:        int timeset;
        !            47:        uint32_t time;
        !            48:        struct timespec timecheck;
        !            49: };
        !            50:
        !            51: static int usm_doinit(struct snmp_agent *);
        !            52: static char *usm_genparams(struct snmp_agent *, size_t *);
        !            53: static int usm_parseparams(struct snmp_agent *, char *, size_t, off_t, char *,
        !            54:     size_t, uint8_t);
        !            55: static void usm_free(void *);
        !            56:
        !            57: struct snmp_sec *
        !            58: usm_init(const char *user, size_t userlen)
        !            59: {
        !            60:        struct snmp_sec *sec;
        !            61:        struct usm_sec *usm;
        !            62:
        !            63:        if (user == NULL || user[0] == '\0') {
        !            64:                errno = EINVAL;
        !            65:                return NULL;
        !            66:        }
        !            67:
        !            68:        if ((sec = malloc(sizeof(*sec))) == NULL)
        !            69:                return NULL;
        !            70:
        !            71:        if ((usm = calloc(1, sizeof(struct usm_sec))) == NULL) {
        !            72:                free(sec);
        !            73:                return NULL;
        !            74:        }
        !            75:        if ((usm->user = malloc(userlen)) == NULL) {
        !            76:                free(sec);
        !            77:                free(usm);
        !            78:                return NULL;
        !            79:        }
        !            80:        memcpy(usm->user, user, userlen);
        !            81:        usm->userlen = userlen;
        !            82:
        !            83:        sec->model = SNMP_SEC_USM;
        !            84:        sec->init = usm_doinit;
        !            85:        sec->genparams = usm_genparams;
        !            86:        sec->parseparams = usm_parseparams;
        !            87:        sec->free = usm_free;
        !            88:        sec->data = usm;
        !            89:        return sec;
        !            90: }
        !            91:
        !            92: static int
        !            93: usm_doinit(struct snmp_agent *agent)
        !            94: {
        !            95:        struct ber_element *ber;
        !            96:        struct usm_sec *usm = agent->v3->sec->data;
        !            97:        int level;
        !            98:        size_t userlen;
        !            99:
        !           100:        if (usm->engineidset && usm->bootsset && usm->timeset)
        !           101:                return 0;
        !           102:
        !           103:        level = agent->v3->level;
        !           104:        agent->v3->level = SNMP_MSGFLAG_REPORT;
        !           105:        userlen = usm->userlen;
        !           106:        usm->userlen = 0;
        !           107:
        !           108:        if ((ber = snmp_get(agent, NULL, 0)) == NULL) {
        !           109:                agent->v3->level = level;
        !           110:                usm->userlen = userlen;
        !           111:                return -1;
        !           112:        }
        !           113:        ber_free_element(ber);
        !           114:
        !           115:        agent->v3->level = level;
        !           116:        usm->userlen = userlen;
        !           117:
        !           118:        return 0;
        !           119: }
        !           120:
        !           121: static char *
        !           122: usm_genparams(struct snmp_agent *agent, size_t *len)
        !           123: {
        !           124:        struct ber ber;
        !           125:        struct ber_element *params;
        !           126:        struct usm_sec *usm = agent->v3->sec->data;
        !           127:        char *secparams = NULL;
        !           128:        ssize_t berlen = 0;
        !           129:        struct timespec now, timediff;
        !           130:        uint32_t boots, time;
        !           131:
        !           132:        if (usm->timeset) {
        !           133:                if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
        !           134:                        return NULL;
        !           135:                timespecsub(&now, &(usm->timecheck), &timediff);
        !           136:                time = usm->time + timediff.tv_sec;
        !           137:        } else
        !           138:                time = 0;
        !           139:        boots = usm->boots;
        !           140:
        !           141:        if ((params = ber_printf_elements(NULL, "{xddxxx}", usm->engineid,
        !           142:            usm->engineidlen, boots, time, usm->user, usm->userlen, NULL,
        !           143:            (size_t) 0, NULL, (size_t) 0)) == NULL)
        !           144:                return NULL;
        !           145:
        !           146:        bzero(&ber, sizeof(ber));
        !           147:        ber_set_application(&ber, smi_application);
        !           148:        if (ber_write_elements(&ber, params) != -1)
        !           149:            berlen = ber_copy_writebuf(&ber, (void **)&secparams);
        !           150:
        !           151:        *len = berlen;
        !           152:        ber_free_element(params);
        !           153:        ber_free(&ber);
        !           154:        return secparams;
        !           155: }
        !           156:
        !           157: static int
        !           158: usm_parseparams(struct snmp_agent *agent, char *packet, size_t packetlen,
        !           159:     off_t secparamsoffset, char *buf, size_t buflen, uint8_t level)
        !           160: {
        !           161:        struct usm_sec *usm = agent->v3->sec->data;
        !           162:        struct ber ber;
        !           163:        struct ber_element *secparams;
        !           164:        char *engineid, *user;
        !           165:        size_t engineidlen, userlen;
        !           166:        struct timespec now, timediff;
        !           167:        uint32_t boots, time;
        !           168:
        !           169:        bzero(&ber, sizeof(ber));
        !           170:
        !           171:        ber_set_application(&ber, smi_application);
        !           172:        ber_set_readbuf(&ber, buf, buflen);
        !           173:        if ((secparams = ber_read_elements(&ber, NULL)) == NULL)
        !           174:                return -1;
        !           175:        ber_free(&ber);
        !           176:
        !           177:        if (ber_scanf_elements(secparams, "{xddxSS}", &engineid, &engineidlen,
        !           178:            &boots, &time, &user, &userlen) == -1)
        !           179:                goto fail;
        !           180:
        !           181:        if (!usm->engineidset) {
        !           182:                if (usm_setengineid(agent->v3->sec, engineid,
        !           183:                    engineidlen) == -1)
        !           184:                        goto fail;
        !           185:        } else {
        !           186:                if (usm->engineidlen != engineidlen)
        !           187:                        goto fail;
        !           188:                if (memcmp(usm->engineid, engineid, engineidlen) != 0)
        !           189:                        goto fail;
        !           190:        }
        !           191:
        !           192:        if (!usm->bootsset) {
        !           193:                usm->boots = boots;
        !           194:                usm->bootsset = 1;
        !           195:        } else {
        !           196:                if (boots < usm->boots)
        !           197:                        goto fail;
        !           198:                if (boots > usm->boots) {
        !           199:                        usm->bootsset = 0;
        !           200:                        usm->timeset = 0;
        !           201:                        usm_doinit(agent);
        !           202:                        goto fail;
        !           203:                }
        !           204:        }
        !           205:
        !           206:        if (!usm->timeset) {
        !           207:                usm->time = time;
        !           208:                if (clock_gettime(CLOCK_MONOTONIC, &usm->timecheck) == -1)
        !           209:                        goto fail;
        !           210:                usm->timeset = 1;
        !           211:        } else {
        !           212:                if (clock_gettime(CLOCK_MONOTONIC, &now) == -1)
        !           213:                        goto fail;
        !           214:                timespecsub(&now, &(usm->timecheck), &timediff);
        !           215:                if (time < usm->time + timediff.tv_sec - USM_MAX_TIMEWINDOW ||
        !           216:                    time > usm->time + timediff.tv_sec + USM_MAX_TIMEWINDOW) {
        !           217:                        usm->bootsset = 0;
        !           218:                        usm->timeset = 0;
        !           219:                        usm_doinit(agent);
        !           220:                        goto fail;
        !           221:                }
        !           222:        }
        !           223:
        !           224:        if (userlen != usm->userlen ||
        !           225:            memcmp(user, usm->user, userlen) != 0)
        !           226:                goto fail;
        !           227:
        !           228:        ber_free_element(secparams);
        !           229:        return 0;
        !           230:
        !           231: fail:
        !           232:        ber_free_element(secparams);
        !           233:        return -1;
        !           234: }
        !           235:
        !           236: static void
        !           237: usm_free(void *data)
        !           238: {
        !           239:        struct usm_sec *usm = data;
        !           240:
        !           241:        free(usm->user);
        !           242:        free(usm->engineid);
        !           243:        free(usm);
        !           244: }
        !           245:
        !           246: int
        !           247: usm_setengineid(struct snmp_sec *sec, char *engineid, size_t engineidlen)
        !           248: {
        !           249:        struct usm_sec *usm = sec->data;
        !           250:
        !           251:        if (usm->engineid != NULL)
        !           252:                free(usm->engineid);
        !           253:        if ((usm->engineid = malloc(engineidlen)) == NULL)
        !           254:                return -1;
        !           255:        memcpy(usm->engineid, engineid, engineidlen);
        !           256:        usm->engineidlen = engineidlen;
        !           257:        usm->engineidset = 1;
        !           258:
        !           259:        return 0;
        !           260: }
        !           261:
        !           262: int
        !           263: usm_setbootstime(struct snmp_sec *sec, uint32_t boots, uint32_t time)
        !           264: {
        !           265:        struct usm_sec *usm = sec->data;
        !           266:
        !           267:        if (clock_gettime(CLOCK_MONOTONIC, &(usm->timecheck)) == -1)
        !           268:                return -1;
        !           269:
        !           270:        usm->boots = boots;
        !           271:        usm->bootsset = 1;
        !           272:        usm->time = time;
        !           273:        usm->timeset = 1;
        !           274:        return 0;
        !           275: }