diff options
author | syrinx <syrinx@FreeBSD.org> | 2010-12-08 13:51:38 +0000 |
---|---|---|
committer | syrinx <syrinx@FreeBSD.org> | 2010-12-08 13:51:38 +0000 |
commit | ed79f703fb1803e10222fccd98100334741138ff (patch) | |
tree | 30b62404bfa57932ef78fb729b57635b158c2a4a /contrib/bsnmp/snmp_usm | |
parent | 6e855a313aac604a57c7b9d8561a9a4e5c2f6666 (diff) | |
download | FreeBSD-src-ed79f703fb1803e10222fccd98100334741138ff.zip FreeBSD-src-ed79f703fb1803e10222fccd98100334741138ff.tar.gz |
In bsnmpd(1) add support for SNMPv3 message processing model, including message authentication, packet encryption & view-based access control (RFC 3412, 3414, 3415).
Sponsored by: The FreeBSD Foundation
Reviewed by: philip@ (mostly)
Approved by: philip@
Diffstat (limited to 'contrib/bsnmp/snmp_usm')
-rwxr-xr-x | contrib/bsnmp/snmp_usm/snmp_usm.3 | 132 | ||||
-rwxr-xr-x | contrib/bsnmp/snmp_usm/usm_snmp.c | 614 | ||||
-rwxr-xr-x | contrib/bsnmp/snmp_usm/usm_tree.def | 109 |
3 files changed, 855 insertions, 0 deletions
diff --git a/contrib/bsnmp/snmp_usm/snmp_usm.3 b/contrib/bsnmp/snmp_usm/snmp_usm.3 new file mode 100755 index 0000000..7fd0817 --- /dev/null +++ b/contrib/bsnmp/snmp_usm/snmp_usm.3 @@ -0,0 +1,132 @@ +.\"- +.\" Copyright (C) 2010 The FreeBSD Foundation +.\" All rights reserved. +.\" +.\" This documentation was written by Shteryana Sotirova Shopova under +.\" sponsorship from the FreeBSD Foundation. +.\" +.\" Redistribution and use in source and binary forms, with or without +.\" modification, are permitted provided that the following conditions +.\" are met: +.\" 1. Redistributions of source code must retain the above copyright +.\" notice, this list of conditions and the following disclaimer. +.\" 2. Redistributions in binary form must reproduce the above copyright +.\" notice, this list of conditions and the following disclaimer in the +.\" documentation and/or other materials provided with the distribution. +.\" +.\" THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +.\" ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +.\" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +.\" ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +.\" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +.\" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +.\" OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +.\" HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +.\" LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +.\" OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +.\" SUCH DAMAGE. +.\" +.\" $FreeBSD$ +.\" +.Dd September 9, 2010 +.Dt SNMP_USM 3 +.Os +.Sh NAME +.Nm snmp_usm +.Nd "user-based security module for +.Xr bsnmpd 1 +.Sh LIBRARY +.Pq begemotSnmpdModulePath."usm" = "/usr/lib/snmp_usm.so" +.Sh DESCRIPTION +The +.Nm snmp_usm +module implements SNMPv3 User-Based Security Model MIB as defined in RFC 3414. +The module is used to manage the internal list of SNMPv3 USM active users in +.Nm bsnmpd . +The module must be loaded for +.Nm bsnmpd +to receive and process SNMPv3 USM PDUs correctly. +.Sh IMPLEMENTATION NOTES +A short description of the objects in the MIB follows. +.Bl -tag -width "XXXXXXXXX" +.It Va usmStats +The subtree contains statistics for the User-based Security Model PDU processing. +The statistics are reset each time the module is loaded. +.It Va usmUserSpinLock +An advisory lock used to coordinate several Command Generator Applications when +altering the SNMP USM users. +.It Va usmUserTable +The table contains all SNMP USM users configured in +.Nm bsnmpd. +The table contains the following objects +.Bl -tag -width ".It Va usmUserEngineID" +.It Va usmUserEngineID +An SNMP engine's administratively-unique identifier. Must be set to the same +Engine ID as +.Nm bsnmpd +so that the user will actually be allowed to communicate with the daemon. +The column is used as entry key and is not accessible for GET or SET operations. +.It Va usmUserName +The USM user name. The second entry key, again not accessible for GET or SET +operations. +.It Va usmUserSecurityName +The column has the exact same value as the +.Va usmUserName +column, however is accessible for GET operations. +.It Va usmUserCloneFrom +A GET on this column will return an empty OID. SET operations are currently not +supported. +.It Va usmUserAuthProtocol +The value of this column contains the OID corresponding to the authentication +protocol used by the USM user. The following protocols and their OIDs are known to +.Nm +module +.Bl -tag -width ".It Va NoAuthProtocol" +.It NoAuthProtocol 1.3.6.1.6.3.10.1.1.1 +.It HMACMD5AuthProtocol 1.3.6.1.6.3.10.1.1.2 +.It HMACSHAAuthProtocol 1.3.6.1.6.3.10.1.1.3 +.El +.It Va usmUserAuthKeyChange , Va usmUserOwnAuthKeyChange +These columns may be used to change the user's authentication key. +.It Va usmUserPrivProtocol +The value of this column contains the OID corresponding to the privacy +protocol used by the USM user. The following protocols and their OIDs are known to +.Nm +module +.Bl -tag -width ".It Va NoPrivProtocol" +.It NoPrivProtocol 1.3.6.1.6.3.10.1.2.1 +.It DESPrivProtoco 1.3.6.1.6.3.10.1.2.2 +.It AesCfb128Protocol 1.3.6.1.6.3.10.1.2.4 +.El +.It Va usmUserPrivKeyChange , Va usmUserOwnPrivKeyChange +These columns may be used to change the user's privacy key. +.It Va usmUserPublic +An arbitrary octet string that may be modified to confirm a SET operation on any +of the columns was successfull. +.It Va usmUserStorageType +This column always has either of two values. Entries created via +.Nm bsnmpd's +configuration file always have this column set to readOnly (5) and +it is not possible to modify those entries. Entries created by Command Generator +Applications always have this column set to volatile(2) and such entries are +lost when the module is restarted. A SET operation on this column is not +allowed. +.It Va usmUserStatus +This column is used to create new USM user entries or delete exsiting ones from +the table. +.El +.EL +.Sh FILES +.Bl -tag -width "XXXXXXXXX" +.It Pa /usr/share/snmp/defs/usm_tree.def +The description of the MIB tree implemented by +.Nm . +.El +.Sh SEE ALSO +.Xr bsnmpd 1 , +.Xr gensnmptree 1 , +.Xr snmpmod 3 +.Sh STANDARDS +IETF RFC 3414 +.Sh AUTHORS +.An Shteryana Shopova Aq syrinx@FreeBSD.org diff --git a/contrib/bsnmp/snmp_usm/usm_snmp.c b/contrib/bsnmp/snmp_usm/usm_snmp.c new file mode 100755 index 0000000..d5350bc --- /dev/null +++ b/contrib/bsnmp/snmp_usm/usm_snmp.c @@ -0,0 +1,614 @@ +/*- + * Copyright (c) 2010 The FreeBSD Foundation + * All rights reserved. + * + * This software was developed by Shteryana Sotirova Shopova under + * sponsorship from the FreeBSD Foundation. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + * + * $FreeBSD$ + */ +#include <sys/queue.h> +#include <sys/types.h> + +#include <errno.h> +#include <stdarg.h> +#include <stdlib.h> +#include <stdio.h> +#include <stdint.h> +#include <string.h> +#include <syslog.h> + +#include "asn1.h" +#include "snmp.h" +#include "snmpmod.h" + +#include "usm_tree.h" +#include "usm_oid.h" + +static struct lmodule *usm_module; +/* For the registration. */ +static const struct asn_oid oid_usm = OIDX_snmpUsmMIB; + +static const struct asn_oid oid_usmNoAuthProtocol = OIDX_usmNoAuthProtocol; +static const struct asn_oid oid_usmHMACMD5AuthProtocol = \ + OIDX_usmHMACMD5AuthProtocol; +static const struct asn_oid oid_usmHMACSHAAuthProtocol = \ + OIDX_usmHMACSHAAuthProtocol; + +static const struct asn_oid oid_usmNoPrivProtocol = OIDX_usmNoPrivProtocol; +static const struct asn_oid oid_usmDESPrivProtocol = OIDX_usmDESPrivProtocol; +static const struct asn_oid oid_usmAesCfb128Protocol = OIDX_usmAesCfb128Protocol; + +static const struct asn_oid oid_usmUserSecurityName = OIDX_usmUserSecurityName; + +/* The registration. */ +static uint reg_usm; + +static int32_t usm_lock; + +static struct usm_user * usm_get_user(const struct asn_oid *, uint); +static struct usm_user * usm_get_next_user(const struct asn_oid *, uint); +static void usm_append_userindex(struct asn_oid *, uint, + const struct usm_user *); +static int usm_user_index_decode(const struct asn_oid *, uint, uint8_t *, + uint32_t *, char *); + +int +op_usm_stats(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub __unused, uint32_t iidx __unused, enum snmp_op op) +{ + struct snmpd_usmstat *usmstats; + + if (op == SNMP_OP_SET) + return (SNMP_ERR_NOT_WRITEABLE); + + if ((usmstats = bsnmpd_get_usm_stats()) == NULL) + return (SNMP_ERR_GENERR); + + if (op == SNMP_OP_GET) { + switch (val->var.subs[sub - 1]) { + case LEAF_usmStatsUnsupportedSecLevels: + val->v.uint32 = usmstats->unsupported_seclevels; + break; + case LEAF_usmStatsNotInTimeWindows: + val->v.uint32 = usmstats->not_in_time_windows; + break; + case LEAF_usmStatsUnknownUserNames: + val->v.uint32 = usmstats->unknown_users; + break; + case LEAF_usmStatsUnknownEngineIDs: + val->v.uint32 = usmstats->unknown_engine_ids; + break; + case LEAF_usmStatsWrongDigests: + val->v.uint32 = usmstats->wrong_digests; + break; + case LEAF_usmStatsDecryptionErrors: + val->v.uint32 = usmstats->decrypt_errors; + break; + default: + return (SNMP_ERR_NOSUCHNAME); + } + return (SNMP_ERR_NOERROR); + } + abort(); +} + +int +op_usm_lock(struct snmp_context *ctx __unused, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + if (val->var.subs[sub - 1] != LEAF_usmUserSpinLock) + return (SNMP_ERR_NOSUCHNAME); + + switch (op) { + case SNMP_OP_GET: + if (++usm_lock == INT32_MAX) + usm_lock = 0; + val->v.integer = usm_lock; + break; + case SNMP_OP_GETNEXT: + abort(); + case SNMP_OP_SET: + if (val->v.integer != usm_lock) + return (SNMP_ERR_INCONS_VALUE); + break; + case SNMP_OP_ROLLBACK: + /* FALLTHROUGH */ + case SNMP_OP_COMMIT: + break; + } + + return (SNMP_ERR_NOERROR); +} + +int +op_usm_users(struct snmp_context *ctx, struct snmp_value *val, + uint32_t sub, uint32_t iidx __unused, enum snmp_op op) +{ + uint32_t elen; + struct usm_user *uuser, *clone; + char uname[SNMP_ADM_STR32_SIZ]; + uint8_t eid[SNMP_ENGINE_ID_SIZ]; + + switch (op) { + case SNMP_OP_GET: + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + break; + + case SNMP_OP_GETNEXT: + if ((uuser = usm_get_next_user(&val->var, sub)) == NULL) + return (SNMP_ERR_NOSUCHNAME); + usm_append_userindex(&val->var, sub, uuser); + break; + + case SNMP_OP_SET: + if ((uuser = usm_get_user(&val->var, sub)) == NULL && + val->var.subs[sub - 1] != LEAF_usmUserStatus && + val->var.subs[sub - 1] != LEAF_usmUserCloneFrom) + return (SNMP_ERR_NOSUCHNAME); + + if (community != COMM_INITIALIZE && + uuser->type == StorageType_readOnly) + return (SNMP_ERR_NOT_WRITEABLE); + + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserSecurityName: + return (SNMP_ERR_NOT_WRITEABLE); + + case LEAF_usmUserCloneFrom: + if (uuser != NULL || usm_user_index_decode(&val->var, + sub, eid, &elen, uname) < 0 || + !(asn_is_suboid(&oid_usmUserSecurityName, &val->v.oid))) + return (SNMP_ERR_WRONG_VALUE); + if ((clone = usm_get_user(&val->v.oid, sub)) == NULL) + return (SNMP_ERR_INCONS_VALUE); + if ((uuser = usm_new_user(eid, elen, uname)) == NULL) + return (SNMP_ERR_GENERR); + uuser->status = RowStatus_notReady; + if (community != COMM_INITIALIZE) + uuser->type = StorageType_volatile; + else + uuser->type = StorageType_readOnly; + + uuser->suser.auth_proto = clone->suser.auth_proto; + uuser->suser.priv_proto = clone->suser.priv_proto; + memcpy(uuser->suser.auth_key, clone->suser.auth_key, + sizeof(uuser->suser.auth_key)); + memcpy(uuser->suser.priv_key, clone->suser.priv_key, + sizeof(uuser->suser.priv_key)); + ctx->scratch->int1 = RowStatus_createAndWait; + break; + + case LEAF_usmUserAuthProtocol: + ctx->scratch->int1 = uuser->suser.auth_proto; + if (asn_compare_oid(&oid_usmNoAuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_NOAUTH; + else if (asn_compare_oid(&oid_usmHMACMD5AuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_HMAC_MD5; + else if (asn_compare_oid(&oid_usmHMACSHAAuthProtocol, + &val->v.oid) == 0) + uuser->suser.auth_proto = SNMP_AUTH_HMAC_SHA; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + if (val->var.subs[sub - 1] == + LEAF_usmUserOwnAuthKeyChange && + (usm_user == NULL || strcmp(uuser->suser.sec_name, + usm_user->suser.sec_name) != 0)) + return (SNMP_ERR_NO_ACCESS); + if (val->v.octetstring.len > SNMP_AUTH_KEY_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->ptr1 = malloc(SNMP_AUTH_KEY_SIZ); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, uuser->suser.auth_key, + SNMP_AUTH_KEY_SIZ); + memcpy(uuser->suser.auth_key, val->v.octetstring.octets, + val->v.octetstring.len); + break; + + case LEAF_usmUserPrivProtocol: + ctx->scratch->int1 = uuser->suser.priv_proto; + if (asn_compare_oid(&oid_usmNoPrivProtocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_NOPRIV; + else if (asn_compare_oid(&oid_usmDESPrivProtocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_DES; + else if (asn_compare_oid(&oid_usmAesCfb128Protocol, + &val->v.oid) == 0) + uuser->suser.priv_proto = SNMP_PRIV_AES; + else + return (SNMP_ERR_WRONG_VALUE); + break; + + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + if (val->var.subs[sub - 1] == + LEAF_usmUserOwnPrivKeyChange && + (usm_user == NULL || strcmp(uuser->suser.sec_name, + usm_user->suser.sec_name) != 0)) + return (SNMP_ERR_NO_ACCESS); + if (val->v.octetstring.len > SNMP_PRIV_KEY_SIZ) + return (SNMP_ERR_INCONS_VALUE); + ctx->scratch->ptr1 = malloc(SNMP_PRIV_KEY_SIZ); + if (ctx->scratch->ptr1 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr1, uuser->suser.priv_key, + SNMP_PRIV_KEY_SIZ); + memcpy(uuser->suser.priv_key, val->v.octetstring.octets, + val->v.octetstring.len); + break; + + case LEAF_usmUserPublic: + if (val->v.octetstring.len > SNMP_ADM_STR32_SIZ) + return (SNMP_ERR_INCONS_VALUE); + if (uuser->user_public_len > 0) { + ctx->scratch->ptr2 = + malloc(uuser->user_public_len); + if (ctx->scratch->ptr2 == NULL) + return (SNMP_ERR_GENERR); + memcpy(ctx->scratch->ptr2, uuser->user_public, + uuser->user_public_len); + ctx->scratch->int2 = uuser->user_public_len; + } + if (val->v.octetstring.len > 0) { + memcpy(uuser->user_public, + val->v.octetstring.octets, + val->v.octetstring.len); + uuser->user_public_len = val->v.octetstring.len; + } else { + memset(uuser->user_public, 0, + SNMP_ADM_STR32_SIZ); + uuser->user_public_len = 0; + } + break; + + case LEAF_usmUserStorageType: + return (SNMP_ERR_INCONS_VALUE); + + case LEAF_usmUserStatus: + if (uuser == NULL) { + if (val->v.integer != RowStatus_createAndWait || + usm_user_index_decode(&val->var, sub, eid, + &elen, uname) < 0) + return (SNMP_ERR_INCONS_VALUE); + uuser = usm_new_user(eid, elen, uname); + if (uuser == NULL) + return (SNMP_ERR_GENERR); + uuser->status = RowStatus_notReady; + if (community != COMM_INITIALIZE) + uuser->type = StorageType_volatile; + else + uuser->type = StorageType_readOnly; + } else if (val->v.integer != RowStatus_active && + val->v.integer != RowStatus_destroy) + return (SNMP_ERR_INCONS_VALUE); + + uuser->status = val->v.integer; + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_COMMIT: + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPublic: + if (ctx->scratch->ptr2 != NULL) + free(ctx->scratch->ptr2); + break; + case LEAF_usmUserStatus: + if (val->v.integer != RowStatus_destroy) + break; + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + usm_delete_user(uuser); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + case SNMP_OP_ROLLBACK: + if ((uuser = usm_get_user(&val->var, sub)) == NULL) + return (SNMP_ERR_GENERR); + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserAuthProtocol: + uuser->suser.auth_proto = ctx->scratch->int1; + break; + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + memcpy(uuser->suser.auth_key, ctx->scratch->ptr1, + SNMP_AUTH_KEY_SIZ); + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPrivProtocol: + uuser->suser.priv_proto = ctx->scratch->int1; + break; + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + memcpy(uuser->suser.priv_key, ctx->scratch->ptr1, + SNMP_AUTH_KEY_SIZ); + free(ctx->scratch->ptr1); + break; + case LEAF_usmUserPublic: + if (ctx->scratch->ptr2 != NULL) { + memcpy(uuser->user_public, ctx->scratch->ptr2, + ctx->scratch->int2); + uuser->user_public_len = ctx->scratch->int2; + free(ctx->scratch->ptr2); + } else { + memset(uuser->user_public, 0, + SNMP_ADM_STR32_SIZ); + uuser->user_public_len = 0; + } + break; + case LEAF_usmUserCloneFrom: + case LEAF_usmUserStatus: + if (ctx->scratch->int1 == RowStatus_createAndWait) + usm_delete_user(uuser); + break; + default: + break; + } + return (SNMP_ERR_NOERROR); + + default: + abort(); + } + + switch (val->var.subs[sub - 1]) { + case LEAF_usmUserSecurityName: + return (string_get(val, uuser->suser.sec_name, -1)); + case LEAF_usmUserCloneFrom: + memcpy(&val->v.oid, &oid_zeroDotZero, sizeof(oid_zeroDotZero)); + break; + case LEAF_usmUserAuthProtocol: + switch (uuser->suser.auth_proto) { + case SNMP_AUTH_HMAC_MD5: + memcpy(&val->v.oid, &oid_usmHMACMD5AuthProtocol, + sizeof(oid_usmHMACMD5AuthProtocol)); + break; + case SNMP_AUTH_HMAC_SHA: + memcpy(&val->v.oid, &oid_usmHMACSHAAuthProtocol, + sizeof(oid_usmHMACSHAAuthProtocol)); + break; + default: + memcpy(&val->v.oid, &oid_usmNoAuthProtocol, + sizeof(oid_usmNoAuthProtocol)); + break; + } + break; + case LEAF_usmUserAuthKeyChange: + case LEAF_usmUserOwnAuthKeyChange: + return (string_get(val, (char *)uuser->suser.auth_key, 0)); + case LEAF_usmUserPrivProtocol: + switch (uuser->suser.priv_proto) { + case SNMP_PRIV_DES: + memcpy(&val->v.oid, &oid_usmDESPrivProtocol, + sizeof(oid_usmDESPrivProtocol)); + break; + case SNMP_PRIV_AES: + memcpy(&val->v.oid, &oid_usmAesCfb128Protocol, + sizeof(oid_usmAesCfb128Protocol)); + break; + default: + memcpy(&val->v.oid, &oid_usmNoPrivProtocol, + sizeof(oid_usmNoPrivProtocol)); + break; + } + break; + case LEAF_usmUserPrivKeyChange: + case LEAF_usmUserOwnPrivKeyChange: + return (string_get(val, (char *)uuser->suser.priv_key, 0)); + case LEAF_usmUserPublic: + return (string_get(val, uuser->user_public, + uuser->user_public_len)); + case LEAF_usmUserStorageType: + val->v.integer = uuser->type; + break; + case LEAF_usmUserStatus: + val->v.integer = uuser->status; + break; + } + + return (SNMP_ERR_NOERROR); +} + +static int +usm_user_index_decode(const struct asn_oid *oid, uint sub, uint8_t *engine, + uint32_t *elen, char *uname) +{ + uint32_t i, nlen; + int uname_off; + + if (oid->subs[sub] > SNMP_ENGINE_ID_SIZ) + return (-1); + + for (i = 0; i < oid->subs[sub]; i++) + engine[i] = oid->subs[sub + i + 1]; + *elen = i; + + uname_off = sub + oid->subs[sub] + 1; + if ((nlen = oid->subs[uname_off]) >= SNMP_ADM_STR32_SIZ) + return (-1); + + for (i = 0; i < nlen; i++) + uname[i] = oid->subs[uname_off + i + 1]; + uname[nlen] = '\0'; + + return (0); +} + +static void +usm_append_userindex(struct asn_oid *oid, uint sub, + const struct usm_user *uuser) +{ + uint32_t i; + + oid->len = sub + uuser->user_engine_len + strlen(uuser->suser.sec_name); + oid->len += 2; + oid->subs[sub] = uuser->user_engine_len; + for (i = 1; i < uuser->user_engine_len + 1; i++) + oid->subs[sub + i] = uuser->user_engine_id[i - 1]; + + sub += uuser->user_engine_len + 1; + oid->subs[sub] = strlen(uuser->suser.sec_name); + for (i = 1; i <= oid->subs[sub]; i++) + oid->subs[sub + i] = uuser->suser.sec_name[i - 1]; +} + +static struct usm_user * +usm_get_user(const struct asn_oid *oid, uint sub) +{ + uint32_t enginelen; + char username[SNMP_ADM_STR32_SIZ]; + uint8_t engineid[SNMP_ENGINE_ID_SIZ]; + + if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) + return (NULL); + + return (usm_find_user(engineid, enginelen, username)); +} + +static struct usm_user * +usm_get_next_user(const struct asn_oid *oid, uint sub) +{ + uint32_t enginelen; + char username[SNMP_ADM_STR32_SIZ]; + uint8_t engineid[SNMP_ENGINE_ID_SIZ]; + struct usm_user *uuser; + + if (oid->len - sub == 0) + return (usm_first_user()); + + if (usm_user_index_decode(oid, sub, engineid, &enginelen, username) < 0) + return (NULL); + + if ((uuser = usm_find_user(engineid, enginelen, username)) != NULL) + return (usm_next_user(uuser)); + + return (NULL); +} + +/* + * USM snmp module initialization hook. + * Returns 0 on success, < 0 on error. + */ +static int +usm_init(struct lmodule * mod, int argc __unused, char *argv[] __unused) +{ + usm_module = mod; + usm_lock = random(); + bsnmpd_reset_usm_stats(); + return (0); +} + +/* + * USM snmp module finalization hook. + */ +static int +usm_fini(void) +{ + usm_flush_users(); + or_unregister(reg_usm); + + return (0); +} + +/* + * USM snmp module start operation. + */ +static void +usm_start(void) +{ + reg_usm = or_register(&oid_usm, + "The MIB module for managing SNMP User-Based Security Model.", + usm_module); +} + +static void +usm_dump(void) +{ + struct usm_user *uuser; + struct snmpd_usmstat *usmstats; + const char *const authstr[] = { + "noauth", + "md5", + "sha", + NULL + }; + const char *const privstr[] = { + "nopriv", + "des", + "aes", + NULL + }; + + if ((usmstats = bsnmpd_get_usm_stats()) != NULL) { + syslog(LOG_ERR, "UnsupportedSecLevels\t\t%u", + usmstats->unsupported_seclevels); + syslog(LOG_ERR, "NotInTimeWindows\t\t%u", + usmstats->not_in_time_windows); + syslog(LOG_ERR, "UnknownUserNames\t\t%u", + usmstats->unknown_users); + syslog(LOG_ERR, "UnknownEngineIDs\t\t%u", + usmstats->unknown_engine_ids); + syslog(LOG_ERR, "WrongDigests\t\t%u", + usmstats->wrong_digests); + syslog(LOG_ERR, "DecryptionErrors\t\t%u", + usmstats->decrypt_errors); + } + + syslog(LOG_ERR, "USM users"); + for (uuser = usm_first_user(); uuser != NULL; + (uuser = usm_next_user(uuser))) + syslog(LOG_ERR, "user %s\t\t%s, %s", uuser->suser.sec_name, + authstr[uuser->suser.auth_proto], + privstr[uuser->suser.priv_proto]); +} + +const char usm_comment[] = \ +"This module implements SNMP User-based Security Model defined in RFC 3414."; + +const struct snmp_module config = { + .comment = usm_comment, + .init = usm_init, + .fini = usm_fini, + .start = usm_start, + .tree = usm_ctree, + .dump = usm_dump, + .tree_size = usm_CTREE_SIZE, +}; diff --git a/contrib/bsnmp/snmp_usm/usm_tree.def b/contrib/bsnmp/snmp_usm/usm_tree.def new file mode 100755 index 0000000..8358d7b --- /dev/null +++ b/contrib/bsnmp/snmp_usm/usm_tree.def @@ -0,0 +1,109 @@ +#- +# Copyright (C) 2010 The FreeBSD Foundation +# All rights reserved. +# +# This software was developed by Shteryana Sotirova Shopova under +# sponsorship from the FreeBSD Foundation. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# +# $FreeBSD$ +# + +typedef StorageType ENUM ( + 1 other + 2 volatile + 3 nonVolatile + 4 permanent + 5 readOnly +) + +typedef RowStatus ENUM ( + 1 active + 2 notInService + 3 notReady + 4 createAndGo + 5 createAndWait + 6 destroy +) + +(1 internet + (6 snmpV2 + (3 snmpModules + (10 snmpFrameworkMIB + (1 snmpFrameworkAdmin + (1 snmpAuthProtocols + (1 usmNoAuthProtocol + ) + (2 usmHMACMD5AuthProtocol + ) + (3 usmHMACSHAAuthProtocol + ) + ) + (2 snmpPrivProtocols + (1 usmNoPrivProtocol + ) + (2 usmDESPrivProtocol + ) + (4 usmAesCfb128Protocol + ) + ) + ) + ) + (15 snmpUsmMIB + (1 usmMIBObjects + (1 usmStats + (1 usmStatsUnsupportedSecLevels COUNTER op_usm_stats GET) + (2 usmStatsNotInTimeWindows COUNTER op_usm_stats GET) + (3 usmStatsUnknownUserNames COUNTER op_usm_stats GET) + (4 usmStatsUnknownEngineIDs COUNTER op_usm_stats GET) + (5 usmStatsWrongDigests COUNTER op_usm_stats GET) + (6 usmStatsDecryptionErrors COUNTER op_usm_stats GET) + ) + (2 usmUser + (1 usmUserSpinLock INTEGER op_usm_lock GET SET) + (2 usmUserTable + (1 usmUserEntry : OCTETSTRING | SnmpEngineID OCTETSTRING op_usm_users + (1 usmUserEngineID OCTETSTRING | SnmpEngineID) + (2 usmUserName OCTETSTRING) + (3 usmUserSecurityName OCTETSTRING | SnmpAdminString GET) + (4 usmUserCloneFrom OID GET SET) + (5 usmUserAuthProtocol OID GET SET) + (6 usmUserAuthKeyChange OCTETSTRING | KeyChange GET SET) + (7 usmUserOwnAuthKeyChange OCTETSTRING | KeyChange GET SET) + (8 usmUserPrivProtocol OID GET SET) + (9 usmUserPrivKeyChange OCTETSTRING | KeyChange GET SET) + (10 usmUserOwnPrivKeyChange OCTETSTRING | KeyChange GET SET) + (11 usmUserPublic OCTETSTRING GET SET) + (12 usmUserStorageType StorageType GET SET) + (13 usmUserStatus RowStatus GET SET) + ) + ) + ) + ) + ) + (20 snmpUsmAesMIB + ) + ) + ) +) + |