summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--usr.sbin/snmpd/parse.y252
-rw-r--r--usr.sbin/snmpd/snmpd.c45
-rw-r--r--usr.sbin/snmpd/snmpd.conf.569
-rw-r--r--usr.sbin/snmpd/snmpd.h9
-rw-r--r--usr.sbin/snmpd/snmpe.c5
-rw-r--r--usr.sbin/snmpd/util.c43
6 files changed, 369 insertions, 54 deletions
diff --git a/usr.sbin/snmpd/parse.y b/usr.sbin/snmpd/parse.y
index b5bd627f714..de88a26c70e 100644
--- a/usr.sbin/snmpd/parse.y
+++ b/usr.sbin/snmpd/parse.y
@@ -1,4 +1,4 @@
-/* $OpenBSD: parse.y,v 1.64 2021/06/20 19:55:48 martijn Exp $ */
+/* $OpenBSD: parse.y,v 1.65 2021/08/09 18:14:53 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -35,6 +35,8 @@
#include <arpa/inet.h>
#include <arpa/nameser.h>
+#include <openssl/sha.h>
+
#include <ctype.h>
#include <unistd.h>
#include <err.h>
@@ -95,6 +97,10 @@ struct snmpd *conf = NULL;
static int errors = 0;
static struct usmuser *user = NULL;
+static uint8_t engineid[SNMPD_MAXENGINEIDLEN];
+static int32_t enginepen;
+static size_t engineidlen;
+
int host(const char *, const char *, int,
struct sockaddr_storage *, int);
int listen_add(struct sockaddr_storage *, int, int);
@@ -120,13 +126,14 @@ typedef struct {
%}
%token INCLUDE
-%token LISTEN ON READ WRITE NOTIFY SNMPV1 SNMPV2 SNMPV3
+%token LISTEN ON READ WRITE NOTIFY SNMPV1 SNMPV2 SNMPV3
+%token ENGINEID PEN OPENBSD IP4 IP6 MAC TEXT OCTETS AGENTID HOSTHASH
%token SYSTEM CONTACT DESCR LOCATION NAME OBJECTID SERVICES RTFILTER
%token READONLY READWRITE OCTETSTRING INTEGER COMMUNITY TRAP RECEIVER
%token SECLEVEL NONE AUTH ENC USER AUTHKEY ENCKEY ERROR
%token HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER PORT
%token <v.string> STRING
-%token <v.number> NUMBER
+%token <v.number> NUMBER
%type <v.string> hostcmn
%type <v.string> srcaddr port
%type <v.number> optwrite yesno seclevel listenopt listenopts
@@ -196,6 +203,14 @@ yesno : STRING {
;
main : LISTEN ON listenproto
+ | engineid_local {
+ if (conf->sc_engineid_len != 0) {
+ yyerror("Redefinition of engineid");
+ YYERROR;
+ }
+ memcpy(conf->sc_engineid, engineid, engineidlen);
+ conf->sc_engineid_len = engineidlen;
+ }
| READONLY COMMUNITY STRING {
if (strlcpy(conf->sc_rdcommunity, $3,
sizeof(conf->sc_rdcommunity)) >=
@@ -381,6 +396,210 @@ port : /* empty */ {
}
;
+enginefmt : IP4 STRING {
+ struct in_addr addr;
+
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_IPv4;
+ if (inet_pton(AF_INET, $2, &addr) != 1) {
+ yyerror("Invalid ipv4 address: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ memcpy(engineid + engineidlen, &addr,
+ sizeof(engineid) - engineidlen);
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ engineidlen += sizeof(addr);
+ free($2);
+ }
+ | IP6 STRING {
+ struct in6_addr addr;
+
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_IPv6;
+ if (inet_pton(AF_INET6, $2, &addr) != 1) {
+ yyerror("Invalid ipv6 address: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ memcpy(engineid + engineidlen, &addr,
+ sizeof(engineid) - engineidlen);
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ engineidlen += sizeof(addr);
+ free($2);
+ }
+ | MAC STRING {
+ size_t i;
+
+ if (strlen($2) != 5 * 3 + 2) {
+ yyerror("Invalid mac address: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_MAC;
+ for (i = 0; i < 6; i++) {
+ if (fromhexstr(engineid + engineidlen + i,
+ $2 + (i * 3), 2) == NULL ||
+ $2[i * 3 + 2] != (i < 5 ? ':' : '\0')) {
+ yyerror("Invalid mac address: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ }
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ engineidlen += 6;
+ free($2);
+ }
+ | TEXT STRING {
+ size_t i, fmtstart;
+
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_TEXT;
+ for (i = 0, fmtstart = engineidlen;
+ i < sizeof(engineid) - engineidlen && $2[i] != '\0';
+ i++) {
+ if (!isprint($2[i])) {
+ yyerror("invalid text character");
+ free($2);
+ YYERROR;
+ }
+ engineid[fmtstart + i] = $2[i];
+ engineidlen++;
+ }
+ if (i == 0 || $2[i] != '\0') {
+ yyerror("Invalid text length: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ free($2);
+ }
+ | OCTETS STRING {
+ if (strlen($2) / 2 > sizeof(engineid) - 1) {
+ yyerror("Invalid octets length: %s", $2);
+ free($2);
+ YYERROR;
+ }
+
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_OCT;
+ if (fromhexstr(engineid + engineidlen, $2,
+ strlen($2)) == NULL) {
+ yyerror("Invalid octets: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ engineidlen += strlen($2) / 2;
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ free($2);
+ }
+ | AGENTID STRING {
+ if (strlen($2) / 2 != 8) {
+ yyerror("Invalid agentid length: %s", $2);
+ free($2);
+ YYERROR;
+ }
+
+ if (fromhexstr(engineid + engineidlen, $2,
+ strlen($2)) == NULL) {
+ yyerror("Invalid agentid: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ engineidlen += 8;
+ engineid[0] |= SNMP_ENGINEID_OLD;
+ free($2);
+ }
+ | HOSTHASH STRING {
+ if (enginepen != PEN_OPENBSD) {
+ yyerror("hosthash only allowed for pen "
+ "openbsd");
+ YYERROR;
+ }
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_HH;
+ memcpy(engineid + engineidlen,
+ SHA256($2, strlen($2), NULL),
+ sizeof(engineid) - engineidlen);
+ engineidlen = sizeof(engineid);
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ free($2);
+ }
+ | NUMBER STRING {
+ if (enginepen == PEN_OPENBSD) {
+ yyerror("%lld is only allowed when pen is not "
+ "openbsd", $1);
+ YYERROR;
+ }
+
+ if ($1 < 128 || $1 > 255) {
+ yyerror("Invalid format number: %lld\n", $1);
+ YYERROR;
+ }
+ if (strlen($2) / 2 > sizeof(engineid) - 1) {
+ yyerror("Invalid octets length: %s", $2);
+ free($2);
+ YYERROR;
+ }
+
+ engineid[engineidlen++] = (uint8_t)$1;
+ if (fromhexstr(engineid + engineidlen, $2,
+ strlen($2)) == NULL) {
+ yyerror("Invalid octets: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ engineidlen += strlen($2) / 2;
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ free($2);
+ }
+ ;
+
+enginefmt_local : enginefmt
+ | HOSTHASH {
+ char hostname[HOST_NAME_MAX + 1];
+
+ if (enginepen != PEN_OPENBSD) {
+ yyerror("hosthash only allowed for pen "
+ "openbsd");
+ YYERROR;
+ }
+
+ if (gethostname(hostname, sizeof(hostname)) == -1) {
+ yyerror("gethostname: %s", strerror(errno));
+ YYERROR;
+ }
+
+ engineid[engineidlen++] = SNMP_ENGINEID_FMT_HH;
+ memcpy(engineid + engineidlen,
+ SHA256(hostname, strlen(hostname), NULL),
+ sizeof(engineid) - engineidlen);
+ engineidlen = sizeof(engineid);
+ engineid[0] |= SNMP_ENGINEID_NEW;
+ }
+ ;
+
+pen : /* empty */ {
+ enginepen = PEN_OPENBSD;
+ }
+ | PEN NUMBER {
+ if ($2 > INT32_MAX) {
+ yyerror("pen number too large");
+ YYERROR;
+ }
+ if ($2 <= 0) {
+ yyerror("pen number too small");
+ YYERROR;
+ }
+ enginepen = $2;
+ }
+ | PEN OPENBSD {
+ enginepen = PEN_OPENBSD;
+ }
+ ;
+
+engineid_local : ENGINEID pen {
+ uint32_t npen = htonl(enginepen);
+
+ memcpy(engineid, &npen, sizeof(enginepen));
+ engineidlen = sizeof(enginepen);
+ } enginefmt_local
+
system : SYSTEM sysmib
;
@@ -707,6 +926,7 @@ lookup(char *s)
{
/* this has to be sorted always */
static const struct keywords keywords[] = {
+ { "agentid", AGENTID },
{ "auth", AUTH },
{ "authkey", AUTHKEY },
{ "community", COMMUNITY },
@@ -715,18 +935,26 @@ lookup(char *s)
{ "description", DESCR },
{ "enc", ENC },
{ "enckey", ENCKEY },
+ { "engineid", ENGINEID },
{ "filter-pf-addresses", PFADDRFILTER },
{ "filter-routes", RTFILTER },
{ "handle", HANDLE },
+ { "hosthash", HOSTHASH },
{ "include", INCLUDE },
{ "integer", INTEGER },
+ { "ipv4", IP4 },
+ { "ipv6", IP6 },
{ "listen", LISTEN },
{ "location", LOCATION },
+ { "mac", MAC },
{ "name", NAME },
{ "none", NONE },
{ "notify", NOTIFY },
+ { "octets", OCTETS },
{ "oid", OBJECTID },
{ "on", ON },
+ { "openbsd", OPENBSD },
+ { "pen", PEN },
{ "port", PORT },
{ "read", READ },
{ "read-only", READONLY },
@@ -741,6 +969,7 @@ lookup(char *s)
{ "string", OCTETSTRING },
{ "system", SYSTEM },
{ "tcp", TCP },
+ { "text", TEXT },
{ "trap", TRAP },
{ "udp", UDP },
{ "user", USER },
@@ -1109,7 +1338,9 @@ parse_config(const char *filename, u_int flags)
struct trap_address *tr;
const struct usmuser *up;
const char *errstr;
+ char hostname[HOST_NAME_MAX + 1];
int found;
+ uint32_t npen = htonl(PEN_OPENBSD);
if ((conf = calloc(1, sizeof(*conf))) == NULL) {
log_warn("%s", __func__);
@@ -1135,6 +1366,21 @@ parse_config(const char *filename, u_int flags)
endservent();
+ /* Must be identical to enginefmt_local:HOSTHASH */
+ if (conf->sc_engineid_len == 0) {
+ if (gethostname(hostname, sizeof(hostname)) == -1)
+ fatal("gethostname");
+ memcpy(conf->sc_engineid, &npen, sizeof(npen));
+ conf->sc_engineid_len += sizeof(npen);
+ conf->sc_engineid[conf->sc_engineid_len++] |=
+ SNMP_ENGINEID_FMT_HH;
+ memcpy(conf->sc_engineid + conf->sc_engineid_len,
+ SHA256(hostname, strlen(hostname), NULL),
+ sizeof(conf->sc_engineid) - conf->sc_engineid_len);
+ conf->sc_engineid_len = sizeof(conf->sc_engineid);
+ conf->sc_engineid[0] |= SNMP_ENGINEID_NEW;
+ }
+
/* Setup default listen addresses */
if (TAILQ_EMPTY(&conf->sc_addresses)) {
if (host("0.0.0.0", SNMP_PORT, SOCK_DGRAM, &ss, 1) != 1)
diff --git a/usr.sbin/snmpd/snmpd.c b/usr.sbin/snmpd/snmpd.c
index f8cafb6263d..750ffd7205e 100644
--- a/usr.sbin/snmpd/snmpd.c
+++ b/usr.sbin/snmpd/snmpd.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.c,v 1.44 2021/01/27 07:21:54 deraadt Exp $ */
+/* $OpenBSD: snmpd.c,v 1.45 2021/08/09 18:14:53 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -45,7 +45,6 @@ __dead void usage(void);
void snmpd_shutdown(struct snmpd *);
void snmpd_sig_handler(int, short, void *);
int snmpd_dispatch_snmpe(int, struct privsep_proc *, struct imsg *);
-void snmpd_generate_engineid(struct snmpd *);
int check_child(pid_t, const char *);
struct snmpd *snmpd_env;
@@ -228,7 +227,6 @@ main(int argc, char *argv[])
env->sc_engine_boots = 0;
pf_init();
- snmpd_generate_engineid(env);
proc_init(ps, procs, nitems(procs), debug, argc0, argv0, proc_id);
if (!debug && daemon(0, 0) == -1)
@@ -318,29 +316,6 @@ snmpd_socket_af(struct sockaddr_storage *ss, int type)
SOCK_STREAM | SOCK_NONBLOCK : SOCK_DGRAM) | SOCK_CLOEXEC, 0);
}
-void
-snmpd_generate_engineid(struct snmpd *env)
-{
- u_int32_t oid_enterprise, rnd, tim;
-
- /* RFC 3411 */
- memset(env->sc_engineid, 0, sizeof(env->sc_engineid));
- oid_enterprise = htonl(OIDVAL_openBSD_eid);
- memcpy(env->sc_engineid, &oid_enterprise, sizeof(oid_enterprise));
- env->sc_engineid[0] |= SNMP_ENGINEID_NEW;
- env->sc_engineid_len = sizeof(oid_enterprise);
-
- /* XXX alternatively configure engine id via snmpd.conf */
- env->sc_engineid[(env->sc_engineid_len)++] = SNMP_ENGINEID_FMT_EID;
- rnd = arc4random();
- memcpy(&env->sc_engineid[env->sc_engineid_len], &rnd, sizeof(rnd));
- env->sc_engineid_len += sizeof(rnd);
-
- tim = htonl(env->sc_starttime.tv_sec);
- memcpy(&env->sc_engineid[env->sc_engineid_len], &tim, sizeof(tim));
- env->sc_engineid_len += sizeof(tim);
-}
-
u_long
snmpd_engine_time(void)
{
@@ -358,21 +333,3 @@ snmpd_engine_time(void)
gettimeofday(&now, NULL);
return now.tv_sec;
}
-
-char *
-tohexstr(u_int8_t *bstr, int len)
-{
-#define MAXHEXSTRLEN 256
- static char hstr[2 * MAXHEXSTRLEN + 1];
- static const char hex[] = "0123456789abcdef";
- int i;
-
- if (len > MAXHEXSTRLEN)
- len = MAXHEXSTRLEN; /* truncate */
- for (i = 0; i < len; i++) {
- hstr[i + i] = hex[bstr[i] >> 4];
- hstr[i + i + 1] = hex[bstr[i] & 0x0f];
- }
- hstr[i + i] = '\0';
- return hstr;
-}
diff --git a/usr.sbin/snmpd/snmpd.conf.5 b/usr.sbin/snmpd/snmpd.conf.5
index 640afe51a83..62fb978ed4d 100644
--- a/usr.sbin/snmpd/snmpd.conf.5
+++ b/usr.sbin/snmpd/snmpd.conf.5
@@ -1,4 +1,4 @@
-.\" $OpenBSD: snmpd.conf.5,v 1.52 2021/08/08 13:41:26 sthen Exp $
+.\" $OpenBSD: snmpd.conf.5,v 1.53 2021/08/09 18:14:53 martijn Exp $
.\"
.\" Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: August 8 2021 $
+.Dd $Mdocdate: August 9 2021 $
.Dt SNMPD.CONF 5
.Os
.Sh NAME
@@ -146,6 +146,71 @@ Having
set requires at least one
.Ic trap handle
statement.
+.It Ic engineid Oo Ic pen Ar enterprise Oc Ar format
+Set the snmp engineid, used for instance identification and key
+generation for the
+.Ic user
+.Ar auth
+and
+.Ar key .
+.Ar enterprise
+specifies the private enterprise number of the instance and can be either an
+integer or
+.Ic openbsd
+.Pq default .
+.Pp
+.Ar format
+can be one of the following:
+.Bl -tag -widt Ds
+.It Ic ipv4 Ar address
+The engineID's format identifier is set to 1 and the ipv4
+.Ar address
+is used in the format.
+.It Ic ipv6 Ar address
+The engineID's format identifier is set to 2 and the ipv6
+.Ar address
+is used in the format.
+.It Ic mac Ar address
+The engineID's format identifier is set to 3 and the mac
+.Ar address
+is used in the format.
+.It Ic text Ar text
+The engineID's format identifier is set to 4 and the ASCII
+.Ar text
+is used in the format.
+.It Ic octets Ar octetstring
+The engineID's format identifier is set to 5 and the
+.Ar octetstring
+in hexadecimal is used in the format.
+.It Ic hosthash Op Ar hostname
+The engineID's format identifier is set to 129 and the first 27 bytes of the
+sha256 hash of the
+.Ar hostname
+are used in the format.
+This option is only valid for
+.Ar enterprise
+.Ic openbsd .
+If used for the local engineID, then
+.Ar hostname
+defaults to the value of
+.Xr hostname 1 .
+This format is the default.
+.It Ar number Ar octetstring
+The engineID's format identifier is set to
+.Ar number
+and the
+.Ar octetstring
+in hexadecimal is used in the format.
+This format is only available if
+.Ar enterprise
+is not
+.Ic openbsd .
+.It Ic agentid Ar octetstring
+RFC1910 legacy format.
+.Ar octetstring
+must be 8 bytes
+.Pq or 16 characters in hexadecimal format .
+.El
.It Ic read-only community Ar string
Specify the name of the read-only community.
There is no default value.
diff --git a/usr.sbin/snmpd/snmpd.h b/usr.sbin/snmpd/snmpd.h
index fbd9ce58f07..d5f3b75d688 100644
--- a/usr.sbin/snmpd/snmpd.h
+++ b/usr.sbin/snmpd/snmpd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpd.h,v 1.98 2021/08/08 13:41:26 sthen Exp $ */
+/* $OpenBSD: snmpd.h,v 1.99 2021/08/09 18:14:53 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -77,7 +77,9 @@
#define SNMP_ENGINEID_FMT_MAC 3
#define SNMP_ENGINEID_FMT_TEXT 4
#define SNMP_ENGINEID_FMT_OCT 5
-#define SNMP_ENGINEID_FMT_EID 128
+#define SNMP_ENGINEID_FMT_HH 129
+
+#define PEN_OPENBSD 30155
enum imsg_type {
IMSG_NONE,
@@ -733,7 +735,6 @@ void timer_init(void);
/* snmpd.c */
int snmpd_socket_af(struct sockaddr_storage *, int);
u_long snmpd_engine_time(void);
-char *tohexstr(u_int8_t *, int);
/* usm.c */
void usm_generate_keys(void);
@@ -796,5 +797,7 @@ ssize_t recvfromto(int, void *, size_t, int, struct sockaddr *,
socklen_t *, struct sockaddr *, socklen_t *);
const char *log_in6addr(const struct in6_addr *);
const char *print_host(struct sockaddr_storage *, char *, size_t);
+char *tohexstr(u_int8_t *, int);
+uint8_t *fromhexstr(uint8_t *, const char *, size_t);
#endif /* SNMPD_H */
diff --git a/usr.sbin/snmpd/snmpe.c b/usr.sbin/snmpd/snmpe.c
index 5fcb9171381..093cb26ba55 100644
--- a/usr.sbin/snmpd/snmpe.c
+++ b/usr.sbin/snmpd/snmpe.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: snmpe.c,v 1.73 2021/08/01 11:36:48 martijn Exp $ */
+/* $OpenBSD: snmpe.c,v 1.74 2021/08/09 18:14:53 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
@@ -121,6 +121,9 @@ snmpe_init(struct privsep *ps, struct privsep_proc *p, void *arg)
fatal("unveil");
if (unveil(NULL, NULL) == -1)
fatal("unveil");
+
+ log_info("snmpe %s: ready",
+ tohexstr(env->sc_engineid, env->sc_engineid_len));
}
void
diff --git a/usr.sbin/snmpd/util.c b/usr.sbin/snmpd/util.c
index fb8bdf20d29..e0a798fbcd7 100644
--- a/usr.sbin/snmpd/util.c
+++ b/usr.sbin/snmpd/util.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: util.c,v 1.11 2021/01/28 20:45:14 martijn Exp $ */
+/* $OpenBSD: util.c,v 1.12 2021/08/09 18:14:53 martijn Exp $ */
/*
* Copyright (c) 2014 Bret Stephen Lambert <blambert@openbsd.org>
*
@@ -22,7 +22,9 @@
#include <net/if.h>
#include <ber.h>
+#include <ctype.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <event.h>
@@ -187,3 +189,42 @@ print_host(struct sockaddr_storage *ss, char *buf, size_t len)
}
return (buf);
}
+
+char *
+tohexstr(uint8_t *bstr, int len)
+{
+#define MAXHEXSTRLEN 256
+ static char hstr[2 * MAXHEXSTRLEN + 1];
+ static const char hex[] = "0123456789abcdef";
+ int i;
+
+ if (len > MAXHEXSTRLEN)
+ len = MAXHEXSTRLEN; /* truncate */
+ for (i = 0; i < len; i++) {
+ hstr[i + i] = hex[bstr[i] >> 4];
+ hstr[i + i + 1] = hex[bstr[i] & 0x0f];
+ }
+ hstr[i + i] = '\0';
+ return hstr;
+}
+
+uint8_t *
+fromhexstr(uint8_t *bstr, const char *hstr, size_t len)
+{
+ size_t i;
+ char hex[3];
+
+ if (len % 2 != 0)
+ return NULL;
+
+ hex[2] = '\0';
+ for (i = 0; i < len; i += 2) {
+ if (!isxdigit(hstr[i]) || !isxdigit(hstr[i + 1]))
+ return NULL;
+ hex[0] = hstr[i];
+ hex[1] = hstr[i + 1];
+ bstr[i / 2] = strtol(hex, NULL, 16);
+ }
+
+ return bstr;
+}