1216294Ssyrinx/*- 2216294Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation 3216294Ssyrinx * All rights reserved. 4216294Ssyrinx * 5216294Ssyrinx * This software was developed by Shteryana Sotirova Shopova under 6216294Ssyrinx * sponsorship from the FreeBSD Foundation. 7216294Ssyrinx * 8216294Ssyrinx * Redistribution and use in source and binary forms, with or without 9216294Ssyrinx * modification, are permitted provided that the following conditions 10216294Ssyrinx * are met: 11216294Ssyrinx * 1. Redistributions of source code must retain the above copyright 12216294Ssyrinx * notice, this list of conditions and the following disclaimer. 13216294Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright 14216294Ssyrinx * notice, this list of conditions and the following disclaimer in the 15216294Ssyrinx * documentation and/or other materials provided with the distribution. 16216294Ssyrinx * 17216294Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 18216294Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 19216294Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 20216294Ssyrinx * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 21216294Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 22216294Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23216294Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24216294Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25216294Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26216294Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27216294Ssyrinx * SUCH DAMAGE. 28216294Ssyrinx * 29216294Ssyrinx * $FreeBSD$ 30216294Ssyrinx */ 31216294Ssyrinx#include <sys/queue.h> 32216294Ssyrinx#include <sys/types.h> 33216294Ssyrinx 34216294Ssyrinx#include <errno.h> 35216294Ssyrinx#include <stdarg.h> 36216294Ssyrinx#include <stdlib.h> 37216294Ssyrinx#include <stdio.h> 38216294Ssyrinx#include <stdint.h> 39216294Ssyrinx#include <string.h> 40216294Ssyrinx#include <syslog.h> 41216294Ssyrinx 42216294Ssyrinx#include "asn1.h" 43216294Ssyrinx#include "snmp.h" 44216294Ssyrinx#include "snmpmod.h" 45216294Ssyrinx 46216294Ssyrinx#include "usm_tree.h" 47216294Ssyrinx#include "usm_oid.h" 48216294Ssyrinx 49216294Ssyrinxstatic struct lmodule *usm_module; 50216294Ssyrinx/* For the registration. */ 51216294Ssyrinxstatic const struct asn_oid oid_usm = OIDX_snmpUsmMIB; 52216294Ssyrinx 53216294Ssyrinxstatic const struct asn_oid oid_usmNoAuthProtocol = OIDX_usmNoAuthProtocol; 54216294Ssyrinxstatic const struct asn_oid oid_usmHMACMD5AuthProtocol = \ 55216294Ssyrinx OIDX_usmHMACMD5AuthProtocol; 56216294Ssyrinxstatic const struct asn_oid oid_usmHMACSHAAuthProtocol = \ 57216294Ssyrinx OIDX_usmHMACSHAAuthProtocol; 58216294Ssyrinx 59216294Ssyrinxstatic const struct asn_oid oid_usmNoPrivProtocol = OIDX_usmNoPrivProtocol; 60216294Ssyrinxstatic const struct asn_oid oid_usmDESPrivProtocol = OIDX_usmDESPrivProtocol; 61216294Ssyrinxstatic const struct asn_oid oid_usmAesCfb128Protocol = OIDX_usmAesCfb128Protocol; 62216294Ssyrinx 63216294Ssyrinxstatic const struct asn_oid oid_usmUserSecurityName = OIDX_usmUserSecurityName; 64216294Ssyrinx 65216294Ssyrinx/* The registration. */ 66216294Ssyrinxstatic uint reg_usm; 67216294Ssyrinx 68216294Ssyrinxstatic int32_t usm_lock; 69216294Ssyrinx 70216294Ssyrinxstatic struct usm_user * usm_get_user(const struct asn_oid *, uint); 71216294Ssyrinxstatic struct usm_user * usm_get_next_user(const struct asn_oid *, uint); 72216294Ssyrinxstatic void usm_append_userindex(struct asn_oid *, uint, 73216294Ssyrinx const struct usm_user *); 74216294Ssyrinxstatic int usm_user_index_decode(const struct asn_oid *, uint, uint8_t *, 75216294Ssyrinx uint32_t *, char *); 76216294Ssyrinx 77216294Ssyrinxint 78216294Ssyrinxop_usm_stats(struct snmp_context *ctx __unused, struct snmp_value *val, 79216294Ssyrinx uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op) 80216294Ssyrinx{ 81216294Ssyrinx struct snmpd_usmstat *usmstats; 82216294Ssyrinx 83216294Ssyrinx if (op == SNMP_OP_SET) 84216294Ssyrinx return (SNMP_ERR_NOT_WRITEABLE); 85216294Ssyrinx 86216294Ssyrinx if ((usmstats = bsnmpd_get_usm_stats()) == NULL) 87216294Ssyrinx return (SNMP_ERR_GENERR); 88216294Ssyrinx 89216294Ssyrinx if (op == SNMP_OP_GET) { 90216294Ssyrinx switch (val->var.subs[sub - 1]) { 91216294Ssyrinx case LEAF_usmStatsUnsupportedSecLevels: 92216294Ssyrinx val->v.uint32 = usmstats->unsupported_seclevels; 93216294Ssyrinx break; 94216294Ssyrinx case LEAF_usmStatsNotInTimeWindows: 95216294Ssyrinx val->v.uint32 = usmstats->not_in_time_windows; 96216294Ssyrinx break; 97216294Ssyrinx case LEAF_usmStatsUnknownUserNames: 98216294Ssyrinx val->v.uint32 = usmstats->unknown_users; 99216294Ssyrinx break; 100216294Ssyrinx case LEAF_usmStatsUnknownEngineIDs: 101216294Ssyrinx val->v.uint32 = usmstats->unknown_engine_ids; 102216294Ssyrinx break; 103216294Ssyrinx case LEAF_usmStatsWrongDigests: 104216294Ssyrinx val->v.uint32 = usmstats->wrong_digests; 105216294Ssyrinx break; 106216294Ssyrinx case LEAF_usmStatsDecryptionErrors: 107216294Ssyrinx val->v.uint32 = usmstats->decrypt_errors; 108216294Ssyrinx break; 109216294Ssyrinx default: 110216294Ssyrinx return (SNMP_ERR_NOSUCHNAME); 111216294Ssyrinx } 112216294Ssyrinx return (SNMP_ERR_NOERROR); 113216294Ssyrinx } 114216294Ssyrinx abort(); 115216294Ssyrinx} 116216294Ssyrinx 117216294Ssyrinxint 118216294Ssyrinxop_usm_lock(struct snmp_context *ctx __unused, struct snmp_value *val, 119216294Ssyrinx uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 120216294Ssyrinx{ 121216294Ssyrinx if (val->var.subs[sub - 1] != LEAF_usmUserSpinLock) 122216294Ssyrinx return (SNMP_ERR_NOSUCHNAME); 123216294Ssyrinx 124216294Ssyrinx switch (op) { 125216294Ssyrinx case SNMP_OP_GET: 126216294Ssyrinx if (++usm_lock == INT32_MAX) 127216294Ssyrinx usm_lock = 0; 128216294Ssyrinx val->v.integer = usm_lock; 129216294Ssyrinx break; 130216294Ssyrinx case SNMP_OP_GETNEXT: 131216294Ssyrinx abort(); 132216294Ssyrinx case SNMP_OP_SET: 133216294Ssyrinx if (val->v.integer != usm_lock) 134216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 135216294Ssyrinx break; 136216294Ssyrinx case SNMP_OP_ROLLBACK: 137216294Ssyrinx /* FALLTHROUGH */ 138216294Ssyrinx case SNMP_OP_COMMIT: 139216294Ssyrinx break; 140216294Ssyrinx } 141216294Ssyrinx 142216294Ssyrinx return (SNMP_ERR_NOERROR); 143216294Ssyrinx} 144216294Ssyrinx 145216294Ssyrinxint 146216294Ssyrinxop_usm_users(struct snmp_context *ctx, struct snmp_value *val, 147216294Ssyrinx uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 148216294Ssyrinx{ 149216294Ssyrinx uint32_t elen; 150216294Ssyrinx struct usm_user *uuser, *clone; 151216294Ssyrinx char uname[SNMP_ADM_STR32_SIZ]; 152216294Ssyrinx uint8_t eid[SNMP_ENGINE_ID_SIZ]; 153216294Ssyrinx 154216294Ssyrinx switch (op) { 155216294Ssyrinx case SNMP_OP_GET: 156216294Ssyrinx if ((uuser = usm_get_user(&val->var, sub)) == NULL) 157216294Ssyrinx return (SNMP_ERR_NOSUCHNAME); 158216294Ssyrinx break; 159216294Ssyrinx 160216294Ssyrinx case SNMP_OP_GETNEXT: 161216294Ssyrinx if ((uuser = usm_get_next_user(&val->var, sub)) == NULL) 162216294Ssyrinx return (SNMP_ERR_NOSUCHNAME); 163216294Ssyrinx usm_append_userindex(&val->var, sub, uuser); 164216294Ssyrinx break; 165216294Ssyrinx 166216294Ssyrinx case SNMP_OP_SET: 167216294Ssyrinx if ((uuser = usm_get_user(&val->var, sub)) == NULL && 168216294Ssyrinx val->var.subs[sub - 1] != LEAF_usmUserStatus && 169216294Ssyrinx val->var.subs[sub - 1] != LEAF_usmUserCloneFrom) 170216294Ssyrinx return (SNMP_ERR_NOSUCHNAME); 171216294Ssyrinx 172216294Ssyrinx if (community != COMM_INITIALIZE && 173216294Ssyrinx uuser->type == StorageType_readOnly) 174216294Ssyrinx return (SNMP_ERR_NOT_WRITEABLE); 175216294Ssyrinx 176216294Ssyrinx switch (val->var.subs[sub - 1]) { 177216294Ssyrinx case LEAF_usmUserSecurityName: 178216294Ssyrinx return (SNMP_ERR_NOT_WRITEABLE); 179216294Ssyrinx 180216294Ssyrinx case LEAF_usmUserCloneFrom: 181216294Ssyrinx if (uuser != NULL || usm_user_index_decode(&val->var, 182216294Ssyrinx sub, eid, &elen, uname) < 0 || 183216294Ssyrinx !(asn_is_suboid(&oid_usmUserSecurityName, &val->v.oid))) 184216294Ssyrinx return (SNMP_ERR_WRONG_VALUE); 185216294Ssyrinx if ((clone = usm_get_user(&val->v.oid, sub)) == NULL) 186216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 187216294Ssyrinx if ((uuser = usm_new_user(eid, elen, uname)) == NULL) 188216294Ssyrinx return (SNMP_ERR_GENERR); 189216294Ssyrinx uuser->status = RowStatus_notReady; 190216294Ssyrinx if (community != COMM_INITIALIZE) 191216294Ssyrinx uuser->type = StorageType_volatile; 192216294Ssyrinx else 193216294Ssyrinx uuser->type = StorageType_readOnly; 194216294Ssyrinx 195216294Ssyrinx uuser->suser.auth_proto = clone->suser.auth_proto; 196216294Ssyrinx uuser->suser.priv_proto = clone->suser.priv_proto; 197216294Ssyrinx memcpy(uuser->suser.auth_key, clone->suser.auth_key, 198216294Ssyrinx sizeof(uuser->suser.auth_key)); 199216294Ssyrinx memcpy(uuser->suser.priv_key, clone->suser.priv_key, 200216294Ssyrinx sizeof(uuser->suser.priv_key)); 201216294Ssyrinx ctx->scratch->int1 = RowStatus_createAndWait; 202216294Ssyrinx break; 203216294Ssyrinx 204216294Ssyrinx case LEAF_usmUserAuthProtocol: 205216294Ssyrinx ctx->scratch->int1 = uuser->suser.auth_proto; 206216294Ssyrinx if (asn_compare_oid(&oid_usmNoAuthProtocol, 207216294Ssyrinx &val->v.oid) == 0) 208216294Ssyrinx uuser->suser.auth_proto = SNMP_AUTH_NOAUTH; 209216294Ssyrinx else if (asn_compare_oid(&oid_usmHMACMD5AuthProtocol, 210216294Ssyrinx &val->v.oid) == 0) 211216294Ssyrinx uuser->suser.auth_proto = SNMP_AUTH_HMAC_MD5; 212216294Ssyrinx else if (asn_compare_oid(&oid_usmHMACSHAAuthProtocol, 213216294Ssyrinx &val->v.oid) == 0) 214216294Ssyrinx uuser->suser.auth_proto = SNMP_AUTH_HMAC_SHA; 215216294Ssyrinx else 216216294Ssyrinx return (SNMP_ERR_WRONG_VALUE); 217216294Ssyrinx break; 218216294Ssyrinx 219216294Ssyrinx case LEAF_usmUserAuthKeyChange: 220216294Ssyrinx case LEAF_usmUserOwnAuthKeyChange: 221216294Ssyrinx if (val->var.subs[sub - 1] == 222216294Ssyrinx LEAF_usmUserOwnAuthKeyChange && 223216294Ssyrinx (usm_user == NULL || strcmp(uuser->suser.sec_name, 224216294Ssyrinx usm_user->suser.sec_name) != 0)) 225216294Ssyrinx return (SNMP_ERR_NO_ACCESS); 226216294Ssyrinx if (val->v.octetstring.len > SNMP_AUTH_KEY_SIZ) 227216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 228216294Ssyrinx ctx->scratch->ptr1 = malloc(SNMP_AUTH_KEY_SIZ); 229216294Ssyrinx if (ctx->scratch->ptr1 == NULL) 230216294Ssyrinx return (SNMP_ERR_GENERR); 231216294Ssyrinx memcpy(ctx->scratch->ptr1, uuser->suser.auth_key, 232216294Ssyrinx SNMP_AUTH_KEY_SIZ); 233216294Ssyrinx memcpy(uuser->suser.auth_key, val->v.octetstring.octets, 234216294Ssyrinx val->v.octetstring.len); 235216294Ssyrinx break; 236216294Ssyrinx 237216294Ssyrinx case LEAF_usmUserPrivProtocol: 238216294Ssyrinx ctx->scratch->int1 = uuser->suser.priv_proto; 239216294Ssyrinx if (asn_compare_oid(&oid_usmNoPrivProtocol, 240216294Ssyrinx &val->v.oid) == 0) 241216294Ssyrinx uuser->suser.priv_proto = SNMP_PRIV_NOPRIV; 242216294Ssyrinx else if (asn_compare_oid(&oid_usmDESPrivProtocol, 243216294Ssyrinx &val->v.oid) == 0) 244216294Ssyrinx uuser->suser.priv_proto = SNMP_PRIV_DES; 245216294Ssyrinx else if (asn_compare_oid(&oid_usmAesCfb128Protocol, 246216294Ssyrinx &val->v.oid) == 0) 247216294Ssyrinx uuser->suser.priv_proto = SNMP_PRIV_AES; 248216294Ssyrinx else 249216294Ssyrinx return (SNMP_ERR_WRONG_VALUE); 250216294Ssyrinx break; 251216294Ssyrinx 252216294Ssyrinx case LEAF_usmUserPrivKeyChange: 253216294Ssyrinx case LEAF_usmUserOwnPrivKeyChange: 254216294Ssyrinx if (val->var.subs[sub - 1] == 255216294Ssyrinx LEAF_usmUserOwnPrivKeyChange && 256216294Ssyrinx (usm_user == NULL || strcmp(uuser->suser.sec_name, 257216294Ssyrinx usm_user->suser.sec_name) != 0)) 258216294Ssyrinx return (SNMP_ERR_NO_ACCESS); 259216294Ssyrinx if (val->v.octetstring.len > SNMP_PRIV_KEY_SIZ) 260216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 261216294Ssyrinx ctx->scratch->ptr1 = malloc(SNMP_PRIV_KEY_SIZ); 262216294Ssyrinx if (ctx->scratch->ptr1 == NULL) 263216294Ssyrinx return (SNMP_ERR_GENERR); 264216294Ssyrinx memcpy(ctx->scratch->ptr1, uuser->suser.priv_key, 265216294Ssyrinx SNMP_PRIV_KEY_SIZ); 266216294Ssyrinx memcpy(uuser->suser.priv_key, val->v.octetstring.octets, 267216294Ssyrinx val->v.octetstring.len); 268216294Ssyrinx break; 269216294Ssyrinx 270216294Ssyrinx case LEAF_usmUserPublic: 271216294Ssyrinx if (val->v.octetstring.len > SNMP_ADM_STR32_SIZ) 272216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 273216294Ssyrinx if (uuser->user_public_len > 0) { 274216294Ssyrinx ctx->scratch->ptr2 = 275216294Ssyrinx malloc(uuser->user_public_len); 276216294Ssyrinx if (ctx->scratch->ptr2 == NULL) 277216294Ssyrinx return (SNMP_ERR_GENERR); 278216294Ssyrinx memcpy(ctx->scratch->ptr2, uuser->user_public, 279216294Ssyrinx uuser->user_public_len); 280216294Ssyrinx ctx->scratch->int2 = uuser->user_public_len; 281216294Ssyrinx } 282216294Ssyrinx if (val->v.octetstring.len > 0) { 283216294Ssyrinx memcpy(uuser->user_public, 284216294Ssyrinx val->v.octetstring.octets, 285216294Ssyrinx val->v.octetstring.len); 286216294Ssyrinx uuser->user_public_len = val->v.octetstring.len; 287216294Ssyrinx } else { 288216294Ssyrinx memset(uuser->user_public, 0, 289216294Ssyrinx SNMP_ADM_STR32_SIZ); 290216294Ssyrinx uuser->user_public_len = 0; 291216294Ssyrinx } 292216294Ssyrinx break; 293216294Ssyrinx 294216294Ssyrinx case LEAF_usmUserStorageType: 295216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 296216294Ssyrinx 297216294Ssyrinx case LEAF_usmUserStatus: 298216294Ssyrinx if (uuser == NULL) { 299216294Ssyrinx if (val->v.integer != RowStatus_createAndWait || 300216294Ssyrinx usm_user_index_decode(&val->var, sub, eid, 301216294Ssyrinx &elen, uname) < 0) 302216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 303216294Ssyrinx uuser = usm_new_user(eid, elen, uname); 304216294Ssyrinx if (uuser == NULL) 305216294Ssyrinx return (SNMP_ERR_GENERR); 306216294Ssyrinx uuser->status = RowStatus_notReady; 307216294Ssyrinx if (community != COMM_INITIALIZE) 308216294Ssyrinx uuser->type = StorageType_volatile; 309216294Ssyrinx else 310216294Ssyrinx uuser->type = StorageType_readOnly; 311216294Ssyrinx } else if (val->v.integer != RowStatus_active && 312216294Ssyrinx val->v.integer != RowStatus_destroy) 313216294Ssyrinx return (SNMP_ERR_INCONS_VALUE); 314216294Ssyrinx 315216294Ssyrinx uuser->status = val->v.integer; 316216294Ssyrinx break; 317216294Ssyrinx } 318216294Ssyrinx return (SNMP_ERR_NOERROR); 319216294Ssyrinx 320216294Ssyrinx case SNMP_OP_COMMIT: 321216294Ssyrinx switch (val->var.subs[sub - 1]) { 322216294Ssyrinx case LEAF_usmUserAuthKeyChange: 323216294Ssyrinx case LEAF_usmUserOwnAuthKeyChange: 324216294Ssyrinx case LEAF_usmUserPrivKeyChange: 325216294Ssyrinx case LEAF_usmUserOwnPrivKeyChange: 326216294Ssyrinx free(ctx->scratch->ptr1); 327216294Ssyrinx break; 328216294Ssyrinx case LEAF_usmUserPublic: 329216294Ssyrinx if (ctx->scratch->ptr2 != NULL) 330216294Ssyrinx free(ctx->scratch->ptr2); 331216294Ssyrinx break; 332216294Ssyrinx case LEAF_usmUserStatus: 333216294Ssyrinx if (val->v.integer != RowStatus_destroy) 334216294Ssyrinx break; 335216294Ssyrinx if ((uuser = usm_get_user(&val->var, sub)) == NULL) 336216294Ssyrinx return (SNMP_ERR_GENERR); 337216294Ssyrinx usm_delete_user(uuser); 338216294Ssyrinx break; 339216294Ssyrinx default: 340216294Ssyrinx break; 341216294Ssyrinx } 342216294Ssyrinx return (SNMP_ERR_NOERROR); 343216294Ssyrinx 344216294Ssyrinx case SNMP_OP_ROLLBACK: 345216294Ssyrinx if ((uuser = usm_get_user(&val->var, sub)) == NULL) 346216294Ssyrinx return (SNMP_ERR_GENERR); 347216294Ssyrinx switch (val->var.subs[sub - 1]) { 348216294Ssyrinx case LEAF_usmUserAuthProtocol: 349216294Ssyrinx uuser->suser.auth_proto = ctx->scratch->int1; 350216294Ssyrinx break; 351216294Ssyrinx case LEAF_usmUserAuthKeyChange: 352216294Ssyrinx case LEAF_usmUserOwnAuthKeyChange: 353216294Ssyrinx memcpy(uuser->suser.auth_key, ctx->scratch->ptr1, 354216294Ssyrinx SNMP_AUTH_KEY_SIZ); 355216294Ssyrinx free(ctx->scratch->ptr1); 356216294Ssyrinx break; 357216294Ssyrinx case LEAF_usmUserPrivProtocol: 358216294Ssyrinx uuser->suser.priv_proto = ctx->scratch->int1; 359216294Ssyrinx break; 360216294Ssyrinx case LEAF_usmUserPrivKeyChange: 361216294Ssyrinx case LEAF_usmUserOwnPrivKeyChange: 362216294Ssyrinx memcpy(uuser->suser.priv_key, ctx->scratch->ptr1, 363216294Ssyrinx SNMP_AUTH_KEY_SIZ); 364216294Ssyrinx free(ctx->scratch->ptr1); 365216294Ssyrinx break; 366216294Ssyrinx case LEAF_usmUserPublic: 367216294Ssyrinx if (ctx->scratch->ptr2 != NULL) { 368216294Ssyrinx memcpy(uuser->user_public, ctx->scratch->ptr2, 369216294Ssyrinx ctx->scratch->int2); 370216294Ssyrinx uuser->user_public_len = ctx->scratch->int2; 371216294Ssyrinx free(ctx->scratch->ptr2); 372216294Ssyrinx } else { 373216294Ssyrinx memset(uuser->user_public, 0, 374216294Ssyrinx SNMP_ADM_STR32_SIZ); 375216294Ssyrinx uuser->user_public_len = 0; 376216294Ssyrinx } 377216294Ssyrinx break; 378216294Ssyrinx case LEAF_usmUserCloneFrom: 379216294Ssyrinx case LEAF_usmUserStatus: 380216294Ssyrinx if (ctx->scratch->int1 == RowStatus_createAndWait) 381216294Ssyrinx usm_delete_user(uuser); 382216294Ssyrinx break; 383216294Ssyrinx default: 384216294Ssyrinx break; 385216294Ssyrinx } 386216294Ssyrinx return (SNMP_ERR_NOERROR); 387216294Ssyrinx 388216294Ssyrinx default: 389216294Ssyrinx abort(); 390216294Ssyrinx } 391216294Ssyrinx 392216294Ssyrinx switch (val->var.subs[sub - 1]) { 393216294Ssyrinx case LEAF_usmUserSecurityName: 394216294Ssyrinx return (string_get(val, uuser->suser.sec_name, -1)); 395216294Ssyrinx case LEAF_usmUserCloneFrom: 396216294Ssyrinx memcpy(&val->v.oid, &oid_zeroDotZero, sizeof(oid_zeroDotZero)); 397216294Ssyrinx break; 398216294Ssyrinx case LEAF_usmUserAuthProtocol: 399216294Ssyrinx switch (uuser->suser.auth_proto) { 400216294Ssyrinx case SNMP_AUTH_HMAC_MD5: 401216294Ssyrinx memcpy(&val->v.oid, &oid_usmHMACMD5AuthProtocol, 402216294Ssyrinx sizeof(oid_usmHMACMD5AuthProtocol)); 403216294Ssyrinx break; 404216294Ssyrinx case SNMP_AUTH_HMAC_SHA: 405216294Ssyrinx memcpy(&val->v.oid, &oid_usmHMACSHAAuthProtocol, 406216294Ssyrinx sizeof(oid_usmHMACSHAAuthProtocol)); 407216294Ssyrinx break; 408216294Ssyrinx default: 409216294Ssyrinx memcpy(&val->v.oid, &oid_usmNoAuthProtocol, 410216294Ssyrinx sizeof(oid_usmNoAuthProtocol)); 411216294Ssyrinx break; 412216294Ssyrinx } 413216294Ssyrinx break; 414216294Ssyrinx case LEAF_usmUserAuthKeyChange: 415216294Ssyrinx case LEAF_usmUserOwnAuthKeyChange: 416216294Ssyrinx return (string_get(val, (char *)uuser->suser.auth_key, 0)); 417216294Ssyrinx case LEAF_usmUserPrivProtocol: 418216294Ssyrinx switch (uuser->suser.priv_proto) { 419216294Ssyrinx case SNMP_PRIV_DES: 420216294Ssyrinx memcpy(&val->v.oid, &oid_usmDESPrivProtocol, 421216294Ssyrinx sizeof(oid_usmDESPrivProtocol)); 422216294Ssyrinx break; 423216294Ssyrinx case SNMP_PRIV_AES: 424216294Ssyrinx memcpy(&val->v.oid, &oid_usmAesCfb128Protocol, 425216294Ssyrinx sizeof(oid_usmAesCfb128Protocol)); 426216294Ssyrinx break; 427216294Ssyrinx default: 428216294Ssyrinx memcpy(&val->v.oid, &oid_usmNoPrivProtocol, 429216294Ssyrinx sizeof(oid_usmNoPrivProtocol)); 430216294Ssyrinx break; 431216294Ssyrinx } 432216294Ssyrinx break; 433216294Ssyrinx case LEAF_usmUserPrivKeyChange: 434216294Ssyrinx case LEAF_usmUserOwnPrivKeyChange: 435216294Ssyrinx return (string_get(val, (char *)uuser->suser.priv_key, 0)); 436216294Ssyrinx case LEAF_usmUserPublic: 437216294Ssyrinx return (string_get(val, uuser->user_public, 438216294Ssyrinx uuser->user_public_len)); 439216294Ssyrinx case LEAF_usmUserStorageType: 440216294Ssyrinx val->v.integer = uuser->type; 441216294Ssyrinx break; 442216294Ssyrinx case LEAF_usmUserStatus: 443216294Ssyrinx val->v.integer = uuser->status; 444216294Ssyrinx break; 445216294Ssyrinx } 446216294Ssyrinx 447216294Ssyrinx return (SNMP_ERR_NOERROR); 448216294Ssyrinx} 449216294Ssyrinx 450216294Ssyrinxstatic int 451216294Ssyrinxusm_user_index_decode(const struct asn_oid *oid, uint sub, uint8_t *engine, 452216294Ssyrinx uint32_t *elen, char *uname) 453216294Ssyrinx{ 454216294Ssyrinx uint32_t i, nlen; 455216294Ssyrinx int uname_off; 456216294Ssyrinx 457216294Ssyrinx if (oid->subs[sub] > SNMP_ENGINE_ID_SIZ) 458216294Ssyrinx return (-1); 459216294Ssyrinx 460216294Ssyrinx for (i = 0; i < oid->subs[sub]; i++) 461216294Ssyrinx engine[i] = oid->subs[sub + i + 1]; 462216294Ssyrinx *elen = i; 463216294Ssyrinx 464216294Ssyrinx uname_off = sub + oid->subs[sub] + 1; 465216294Ssyrinx if ((nlen = oid->subs[uname_off]) >= SNMP_ADM_STR32_SIZ) 466216294Ssyrinx return (-1); 467216294Ssyrinx 468216294Ssyrinx for (i = 0; i < nlen; i++) 469216294Ssyrinx uname[i] = oid->subs[uname_off + i + 1]; 470216294Ssyrinx uname[nlen] = '\0'; 471216294Ssyrinx 472216294Ssyrinx return (0); 473216294Ssyrinx} 474216294Ssyrinx 475216294Ssyrinxstatic void 476216294Ssyrinxusm_append_userindex(struct asn_oid *oid, uint sub, 477216294Ssyrinx const struct usm_user *uuser) 478216294Ssyrinx{ 479216294Ssyrinx uint32_t i; 480216294Ssyrinx 481216294Ssyrinx oid->len = sub + uuser->user_engine_len + strlen(uuser->suser.sec_name); 482216294Ssyrinx oid->len += 2; 483216294Ssyrinx oid->subs[sub] = uuser->user_engine_len; 484216294Ssyrinx for (i = 1; i < uuser->user_engine_len + 1; i++) 485216294Ssyrinx oid->subs[sub + i] = uuser->user_engine_id[i - 1]; 486216294Ssyrinx 487216294Ssyrinx sub += uuser->user_engine_len + 1; 488216294Ssyrinx oid->subs[sub] = strlen(uuser->suser.sec_name); 489216294Ssyrinx for (i = 1; i <= oid->subs[sub]; i++) 490216294Ssyrinx oid->subs[sub + i] = uuser->suser.sec_name[i - 1]; 491216294Ssyrinx} 492216294Ssyrinx 493216294Ssyrinxstatic struct usm_user * 494216294Ssyrinxusm_get_user(const struct asn_oid *oid, uint sub) 495216294Ssyrinx{ 496216294Ssyrinx uint32_t enginelen; 497216294Ssyrinx char username[SNMP_ADM_STR32_SIZ]; 498216294Ssyrinx uint8_t engineid[SNMP_ENGINE_ID_SIZ]; 499216294Ssyrinx 500216294Ssyrinx if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) 501216294Ssyrinx return (NULL); 502216294Ssyrinx 503216294Ssyrinx return (usm_find_user(engineid, enginelen, username)); 504216294Ssyrinx} 505216294Ssyrinx 506216294Ssyrinxstatic struct usm_user * 507216294Ssyrinxusm_get_next_user(const struct asn_oid *oid, uint sub) 508216294Ssyrinx{ 509216294Ssyrinx uint32_t enginelen; 510216294Ssyrinx char username[SNMP_ADM_STR32_SIZ]; 511216294Ssyrinx uint8_t engineid[SNMP_ENGINE_ID_SIZ]; 512216294Ssyrinx struct usm_user *uuser; 513216294Ssyrinx 514216294Ssyrinx if (oid->len - sub == 0) 515216294Ssyrinx return (usm_first_user()); 516216294Ssyrinx 517216294Ssyrinx if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) 518216294Ssyrinx return (NULL); 519216294Ssyrinx 520216294Ssyrinx if ((uuser = usm_find_user(engineid, enginelen, username)) != NULL) 521216294Ssyrinx return (usm_next_user(uuser)); 522216294Ssyrinx 523216294Ssyrinx return (NULL); 524216294Ssyrinx} 525216294Ssyrinx 526216294Ssyrinx/* 527216294Ssyrinx * USM snmp module initialization hook. 528216294Ssyrinx * Returns 0 on success, < 0 on error. 529216294Ssyrinx */ 530216294Ssyrinxstatic int 531216294Ssyrinxusm_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) 532216294Ssyrinx{ 533216294Ssyrinx usm_module = mod; 534216294Ssyrinx usm_lock = random(); 535216294Ssyrinx bsnmpd_reset_usm_stats(); 536216294Ssyrinx return (0); 537216294Ssyrinx} 538216294Ssyrinx 539216294Ssyrinx/* 540216294Ssyrinx * USM snmp module finalization hook. 541216294Ssyrinx */ 542216294Ssyrinxstatic int 543216294Ssyrinxusm_fini(void) 544216294Ssyrinx{ 545216294Ssyrinx usm_flush_users(); 546216294Ssyrinx or_unregister(reg_usm); 547216294Ssyrinx 548216294Ssyrinx return (0); 549216294Ssyrinx} 550216294Ssyrinx 551216294Ssyrinx/* 552216294Ssyrinx * USM snmp module start operation. 553216294Ssyrinx */ 554216294Ssyrinxstatic void 555216294Ssyrinxusm_start(void) 556216294Ssyrinx{ 557216294Ssyrinx reg_usm = or_register(&oid_usm, 558216294Ssyrinx "The MIB module for managing SNMP User-Based Security Model.", 559216294Ssyrinx usm_module); 560216294Ssyrinx} 561216294Ssyrinx 562216294Ssyrinxstatic void 563216294Ssyrinxusm_dump(void) 564216294Ssyrinx{ 565216294Ssyrinx struct usm_user *uuser; 566216294Ssyrinx struct snmpd_usmstat *usmstats; 567216294Ssyrinx const char *const authstr[] = { 568216294Ssyrinx "noauth", 569216294Ssyrinx "md5", 570216294Ssyrinx "sha", 571216294Ssyrinx NULL 572216294Ssyrinx }; 573216294Ssyrinx const char *const privstr[] = { 574216294Ssyrinx "nopriv", 575216294Ssyrinx "des", 576216294Ssyrinx "aes", 577216294Ssyrinx NULL 578216294Ssyrinx }; 579216294Ssyrinx 580216294Ssyrinx if ((usmstats = bsnmpd_get_usm_stats()) != NULL) { 581216294Ssyrinx syslog(LOG_ERR, "UnsupportedSecLevels\t\t%u", 582216294Ssyrinx usmstats->unsupported_seclevels); 583216294Ssyrinx syslog(LOG_ERR, "NotInTimeWindows\t\t%u", 584216294Ssyrinx usmstats->not_in_time_windows); 585216294Ssyrinx syslog(LOG_ERR, "UnknownUserNames\t\t%u", 586216294Ssyrinx usmstats->unknown_users); 587216294Ssyrinx syslog(LOG_ERR, "UnknownEngineIDs\t\t%u", 588216294Ssyrinx usmstats->unknown_engine_ids); 589216294Ssyrinx syslog(LOG_ERR, "WrongDigests\t\t%u", 590216294Ssyrinx usmstats->wrong_digests); 591216294Ssyrinx syslog(LOG_ERR, "DecryptionErrors\t\t%u", 592216294Ssyrinx usmstats->decrypt_errors); 593216294Ssyrinx } 594216294Ssyrinx 595216294Ssyrinx syslog(LOG_ERR, "USM users"); 596216294Ssyrinx for (uuser = usm_first_user(); uuser != NULL; 597216294Ssyrinx (uuser = usm_next_user(uuser))) 598216294Ssyrinx syslog(LOG_ERR, "user %s\t\t%s, %s", uuser->suser.sec_name, 599216294Ssyrinx authstr[uuser->suser.auth_proto], 600216294Ssyrinx privstr[uuser->suser.priv_proto]); 601216294Ssyrinx} 602216294Ssyrinx 603216294Ssyrinxconst char usm_comment[] = \ 604216294Ssyrinx"This module implements SNMP User-based Security Model defined in RFC 3414."; 605216294Ssyrinx 606216294Ssyrinxconst struct snmp_module config = { 607216294Ssyrinx .comment = usm_comment, 608216294Ssyrinx .init = usm_init, 609216294Ssyrinx .fini = usm_fini, 610216294Ssyrinx .start = usm_start, 611216294Ssyrinx .tree = usm_ctree, 612216294Ssyrinx .dump = usm_dump, 613216294Ssyrinx .tree_size = usm_CTREE_SIZE, 614216294Ssyrinx}; 615