From f3afd27f5f54f6aed337e14213e64f2d7f142728 Mon Sep 17 00:00:00 2001 From: "Andrey V. Elsukov" Date: Fri, 19 Jan 2018 08:48:14 +0000 Subject: [PATCH] Add to bsnmpd(1) ability to specify multiple community strings with different access rights. By default there are two community strings with index 1 and 2, one for read-only access and second for read-write access: begemotSnmpdCommunityString.0.1 = $(read) begemotSnmpdCommunityString.0.2 = $(write) Now it is possible to define additional community strings using different indexes: begemotSnmpdCommunityString.0.3 = "SomeString1" begemotSnmpdCommunityPermission.0.3 = 1 begemotSnmpdCommunityString.0.4 = "SomeString2" begemotSnmpdCommunityPermission.0.4 = 2 begemotSnmpdCommunityString.0.5 = "SomeString3" begemotSnmpdCommunityString.0.6 = "SomeString4" New attribute begemotSnmpdCommunityPermission can be used to specify access rights: 1 means "read-only" access, 2 means "read-write" access. If attribute is not specified for some index this means "read-only" rights. Community strings must be unique, i.e. must not be the same for different indexes. Obtained from: Yandex LLC MFC after: 2 weeks Sponsored by: Yandex LLC Differential Revision: https://reviews.freebsd.org/D13785 --- contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt | 13 +++- contrib/bsnmp/snmpd/action.c | 58 +++++++++++++-- contrib/bsnmp/snmpd/main.c | 103 ++++++++++++++++---------- contrib/bsnmp/snmpd/snmpd.config | 1 + contrib/bsnmp/snmpd/snmpmod.h | 2 + contrib/bsnmp/snmpd/tree.def | 1 + 6 files changed, 129 insertions(+), 49 deletions(-) diff --git a/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt b/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt index d87e78e91843..0a68ed9e9ec3 100644 --- a/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt +++ b/contrib/bsnmp/snmpd/BEGEMOT-SNMPD.txt @@ -44,7 +44,7 @@ IMPORTS FROM BEGEMOT-MIB; begemotSnmpd MODULE-IDENTITY - LAST-UPDATED "200212040000Z" + LAST-UPDATED "201801190000Z" ORGANIZATION "Fraunhofer FOKUS, CATS" CONTACT-INFO " Hartmut Brandt @@ -274,7 +274,8 @@ BegemotSnmpdCommunityEntry ::= SEQUENCE { begemotSnmpdCommunityModule SectionName, begemotSnmpdCommunityIndex Unsigned32, begemotSnmpdCommunityString OCTET STRING, - begemotSnmpdCommunityDescr OCTET STRING + begemotSnmpdCommunityDescr OCTET STRING, + begemotSnmpdCommunityPermission INTEGER } begemotSnmpdCommunityModule OBJECT-TYPE @@ -310,6 +311,14 @@ begemotSnmpdCommunityDescr OBJECT-TYPE "A description what this community is good for." ::= { begemotSnmpdCommunityEntry 4 } +begemotSnmpdCommunityPermission OBJECT-TYPE + SYNTAX INTEGER (1..4294967295) + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "The numerical value of access rights granted to the community." + ::= { begemotSnmpdCommunityEntry 5 } + -- -- Module table -- diff --git a/contrib/bsnmp/snmpd/action.c b/contrib/bsnmp/snmpd/action.c index 54a5d2995eb1..c38cb0c2083f 100644 --- a/contrib/bsnmp/snmpd/action.c +++ b/contrib/bsnmp/snmpd/action.c @@ -751,8 +751,9 @@ int op_community(struct snmp_context *ctx, struct snmp_value *value, u_int sub, u_int iidx __unused, enum snmp_op op) { - asn_subid_t which = value->var.subs[sub - 1]; + struct asn_oid index; struct community *c; + asn_subid_t which = value->var.subs[sub - 1]; switch (op) { @@ -770,12 +771,47 @@ op_community(struct snmp_context *ctx, struct snmp_value *value, break; case SNMP_OP_SET: - if ((community != COMM_INITIALIZE && snmpd.comm_dis) || - (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) - return (SNMP_ERR_NO_CREATION); - if (which != LEAF_begemotSnmpdCommunityString) + if (community != COMM_INITIALIZE && snmpd.comm_dis) return (SNMP_ERR_NOT_WRITEABLE); - return (string_save(value, ctx, -1, &c->string)); + index.len = 2; + index.subs[0] = 0; + index.subs[1] = value->var.subs[value->var.len - 1]; + switch (which) { + case LEAF_begemotSnmpdCommunityString: + /* check that given string is unique */ + TAILQ_FOREACH(c, &community_list, link) { + if (!asn_compare_oid(&index, &c->index)) + continue; + if (c->string != NULL && strcmp(c->string, + value->v.octetstring.octets) == 0) + return (SNMP_ERR_WRONG_VALUE); + } + case LEAF_begemotSnmpdCommunityPermission: + break; + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + if ((c = FIND_OBJECT_OID(&community_list, &value->var, + sub)) == NULL) { + /* create new community and use user sepcified index */ + c = comm_define_ordered(COMM_READ, "SNMP Custom Community", + &index, NULL, NULL); + if (c == NULL) + return (SNMP_ERR_NO_CREATION); + } + switch (which) { + case LEAF_begemotSnmpdCommunityString: + return (string_save(value, ctx, -1, &c->string)); + case LEAF_begemotSnmpdCommunityPermission: + if (value->v.integer != COMM_READ && + value->v.integer != COMM_WRITE) + return (SNMP_ERR_WRONG_VALUE); + c->private = value->v.integer; + break; + default: + return (SNMP_ERR_NOT_WRITEABLE); + } + return (SNMP_ERR_NOERROR); case SNMP_OP_ROLLBACK: if (which == LEAF_begemotSnmpdCommunityString) { @@ -786,6 +822,8 @@ op_community(struct snmp_context *ctx, struct snmp_value *value, string_rollback(ctx, &c->string); return (SNMP_ERR_NOERROR); } + if (which == LEAF_begemotSnmpdCommunityPermission) + return (SNMP_ERR_NOERROR); abort(); case SNMP_OP_COMMIT: @@ -797,6 +835,8 @@ op_community(struct snmp_context *ctx, struct snmp_value *value, string_commit(ctx); return (SNMP_ERR_NOERROR); } + if (which == LEAF_begemotSnmpdCommunityPermission) + return (SNMP_ERR_NOERROR); abort(); default: @@ -810,6 +850,12 @@ op_community(struct snmp_context *ctx, struct snmp_value *value, case LEAF_begemotSnmpdCommunityDescr: return (string_get(value, c->descr, -1)); + + case LEAF_begemotSnmpdCommunityPermission: + value->v.integer = c->private; + return (SNMP_ERR_NOERROR); + default: + return (SNMP_ERR_NOT_WRITEABLE); } abort(); } diff --git a/contrib/bsnmp/snmpd/main.c b/contrib/bsnmp/snmpd/main.c index 70378331ee01..0f54459fe2d7 100644 --- a/contrib/bsnmp/snmpd/main.c +++ b/contrib/bsnmp/snmpd/main.c @@ -1160,8 +1160,8 @@ snmpd_input(struct port_input *pi, struct tport *tport) */ if (pdu.version < SNMP_V3 && ((pi->cred && !pi->priv && pdu.type == SNMP_PDU_SET) || - (community != COMM_WRITE && - (pdu.type == SNMP_PDU_SET || community != COMM_READ)))) { + (comm != NULL && comm->private != COMM_WRITE && + (pdu.type == SNMP_PDU_SET || comm->private != COMM_READ)))) { snmpd_stats.inBadCommunityUses++; snmp_pdu_free(&pdu); snmp_input_consume(pi); @@ -1609,8 +1609,8 @@ main(int argc, char *argv[]) /* * Get standard communities */ - (void)comm_define(1, "SNMP read", NULL, NULL); - (void)comm_define(2, "SNMP write", NULL, NULL); + comm_define(COMM_READ, "SNMP read", NULL, NULL); + comm_define(COMM_WRITE, "SNMP write", NULL, NULL); community = COMM_INITIALIZE; trap_reqid = reqid_allocate(512, NULL); @@ -2027,11 +2027,58 @@ asn_error_func(const struct asn_buf *b, const char *err, ...) /* * Create a new community */ +struct community* +comm_define_ordered(u_int priv, const char *descr, struct asn_oid *index, + struct lmodule *owner, const char *str) +{ + struct community *c, *p; + u_int ncomm; + + ncomm = index->subs[index->len - 1]; + + /* check that community doesn't already exist */ + TAILQ_FOREACH(c, &community_list, link) + if (c->value == ncomm) + return (c); + + if ((c = malloc(sizeof(struct community))) == NULL) { + syslog(LOG_ERR, "%s: %m", __func__); + return (NULL); + } + c->owner = owner; + c->value = ncomm; + c->descr = descr; + c->string = NULL; + c->private = priv; + + if (str != NULL) { + if((c->string = malloc(strlen(str)+1)) == NULL) { + free(c); + return (NULL); + } + strcpy(c->string, str); + } + /* + * Insert ordered + */ + c->index = *index; + TAILQ_FOREACH(p, &community_list, link) { + if (asn_compare_oid(&p->index, &c->index) > 0) { + TAILQ_INSERT_BEFORE(p, c, link); + break; + } + } + if (p == NULL) + TAILQ_INSERT_TAIL(&community_list, c, link); + return (c); +} + u_int comm_define(u_int priv, const char *descr, struct lmodule *owner, const char *str) { - struct community *c, *p; + struct asn_oid index, *p; + struct community *c; u_int ncomm; /* generate an identifier */ @@ -2043,44 +2090,18 @@ comm_define(u_int priv, const char *descr, struct lmodule *owner, break; } while (c != NULL); - if ((c = malloc(sizeof(struct community))) == NULL) { - syslog(LOG_ERR, "comm_define: %m"); - return (0); - } - c->owner = owner; - c->value = ncomm; - c->descr = descr; - c->string = NULL; - c->private = priv; - - if (str != NULL) { - if((c->string = malloc(strlen(str)+1)) == NULL) { - free(c); - return (0); - } - strcpy(c->string, str); - } - /* make index */ - if (c->owner == NULL) { - c->index.len = 1; - c->index.subs[0] = 0; - } else { - c->index = c->owner->index; + if (owner != NULL) + p = &owner->index; + else { + p = &index; + p->len = 1; + p->subs[0] = 0; } - c->index.subs[c->index.len++] = c->private; - - /* - * Insert ordered - */ - TAILQ_FOREACH(p, &community_list, link) { - if (asn_compare_oid(&p->index, &c->index) > 0) { - TAILQ_INSERT_BEFORE(p, c, link); - break; - } - } - if (p == NULL) - TAILQ_INSERT_TAIL(&community_list, c, link); + p->subs[p->len++] = ncomm; + c = comm_define_ordered(priv, descr, p, owner, str); + if (c == NULL) + return (0); return (c->value); } diff --git a/contrib/bsnmp/snmpd/snmpd.config b/contrib/bsnmp/snmpd/snmpd.config index 2b9355311257..f9f88410837c 100644 --- a/contrib/bsnmp/snmpd/snmpd.config +++ b/contrib/bsnmp/snmpd/snmpd.config @@ -68,6 +68,7 @@ begemotSnmpdDebugSyslogPri = 7 # begemotSnmpdCommunityString.0.1 = $(read) # begemotSnmpdCommunityString.0.2 = $(write) +# begemotSnmpdCommunityString.0.3 = "otherPublic" begemotSnmpdCommunityDisable = 1 # open standard SNMP ports diff --git a/contrib/bsnmp/snmpd/snmpmod.h b/contrib/bsnmp/snmpd/snmpmod.h index c9e609fdc60f..cc6b14e66931 100644 --- a/contrib/bsnmp/snmpd/snmpmod.h +++ b/contrib/bsnmp/snmpd/snmpmod.h @@ -334,6 +334,8 @@ extern struct systemg systemg; #define COMM_WRITE 2 u_int comm_define(u_int, const char *descr, struct lmodule *, const char *str); +struct community *comm_define_ordered(u_int priv, const char *descr, + struct asn_oid *index, struct lmodule *owner, const char *str); const char * comm_string(u_int); /* community for current packet */ diff --git a/contrib/bsnmp/snmpd/tree.def b/contrib/bsnmp/snmpd/tree.def index eb8dac246006..2b6a9b98d9a3 100644 --- a/contrib/bsnmp/snmpd/tree.def +++ b/contrib/bsnmp/snmpd/tree.def @@ -135,6 +135,7 @@ typedef RowStatus ENUM ( (2 begemotSnmpdCommunityIndex UNSIGNED32) (3 begemotSnmpdCommunityString OCTETSTRING GET SET) (4 begemotSnmpdCommunityDescr OCTETSTRING GET) + (5 begemotSnmpdCommunityPermission INTEGER GET SET) )) # # Module table