-/* $OpenBSD: parse.y,v 1.67 2021/08/10 16:14:00 martijn Exp $ */
+/* $OpenBSD: parse.y,v 1.68 2021/09/02 05:41:02 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
%token HANDLE DEFAULT SRCADDR TCP UDP PFADDRFILTER PORT
%token <v.string> STRING
%token <v.number> NUMBER
-%type <v.string> hostcmn
+%type <v.string> usmuser community optcommunity
%type <v.number> listenproto listenflag listenflags
%type <v.string> srcaddr port
%type <v.number> optwrite yesno seclevel
-%type <v.data> objtype cmd
+%type <v.data> objtype cmd hostauth hostauthv3 usmauthopts usmauthopt
%type <v.oid> oid hostoid trapoid
%type <v.auth> auth
%type <v.enc> enc
free($3);
}
| TRAP RECEIVER host
- | TRAP HANDLE hostcmn trapoid cmd {
- struct trapcmd *cmd = $5.data;
+ | TRAP HANDLE trapoid cmd {
+ struct trapcmd *cmd = $4.data;
- cmd->cmd_oid = $4;
+ cmd->cmd_oid = $3;
if (trapcmd_add(cmd) != 0) {
- free($4);
+ free($3);
free(cmd);
yyerror("duplicate oid");
YYERROR;
| PFADDRFILTER yesno {
conf->sc_pfaddrfilter = $2;
}
- | SECLEVEL seclevel {
- conf->sc_min_seclevel = $2;
+ | seclevel {
+ conf->sc_min_seclevel = $1;
}
| USER STRING {
const char *errstr;
| OBJECTID oid { $$ = $2; }
;
-hostcmn : /* empty */ { $$ = NULL; }
- | COMMUNITY STRING { $$ = $2; }
+usmuser : USER STRING {
+ if (strlen($2) > SNMPD_MAXUSERNAMELEN) {
+ yyerror("User name too long: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+community : COMMUNITY STRING {
+ if (strlen($2) > SNMPD_MAXCOMMUNITYLEN) {
+ yyerror("Community too long: %s", $2);
+ free($2);
+ YYERROR;
+ }
+ $$ = $2;
+ }
+ ;
+
+optcommunity : /* empty */ { $$ = NULL; }
+ | community { $$ = $1; }
+ ;
+
+usmauthopt : usmuser {
+ $$.data = $1;
+ $$.value = -1;
+ }
+ | seclevel {
+ $$.data = 0;
+ $$.value = $1;
+ }
+ ;
+
+usmauthopts : /* empty */ {
+ $$.data = NULL;
+ $$.value = -1;
+ }
+ | usmauthopts usmauthopt {
+ if ($2.data != NULL) {
+ if ($$.data != NULL) {
+ yyerror("user redefined");
+ free($2.data);
+ YYERROR;
+ }
+ $$.data = $2.data;
+ } else {
+ if ($$.value != -1) {
+ yyerror("seclevel redefined");
+ YYERROR;
+ }
+ $$.value = $2.value;
+ }
+ }
+ ;
+
+hostauthv3 : usmauthopts {
+ if ($1.data == NULL) {
+ yyerror("user missing");
+ YYERROR;
+ }
+ $$.data = $1.data;
+ $$.value = $1.value;
+ }
+ ;
+
+hostauth : hostauthv3 {
+ $$.type = SNMP_V3;
+ $$.data = $1.data;
+ $$.value = $1.value;
+ }
+ | SNMPV2 optcommunity {
+ $$.type = SNMP_V2;
+ $$.data = $2;
+ }
+ | SNMPV3 hostauthv3 {
+ $$.type = SNMP_V3;
+ $$.data = $2.data;
+ $$.value = $2.value;
+ }
;
srcaddr : /* empty */ { $$ = NULL; }
| SRCADDR STRING { $$ = $2; }
;
-hostdef : STRING hostoid hostcmn srcaddr {
+hostdef : STRING hostoid hostauth srcaddr {
struct sockaddr_storage ss;
struct trap_address *tr;
yyerror("invalid host: %s", $1);
free($1);
free($2);
- free($3);
+ free($3.data);
free($4);
free(tr);
YYERROR;
}
free($1);
- memcpy(&(tr->ss), &ss, sizeof(ss));
+ memcpy(&(tr->ta_ss), &ss, sizeof(ss));
if ($4 != NULL) {
if (host($1, "0", SOCK_DGRAM, &ss, 1) <= 0) {
yyerror("invalid host: %s", $1);
free($2);
- free($3);
+ free($3.data);
free($4);
free(tr);
YYERROR;
}
free($4);
- memcpy(&(tr->ss_local), &ss, sizeof(ss));
+ memcpy(&(tr->ta_sslocal), &ss, sizeof(ss));
+ }
+ tr->ta_oid = $2;
+ tr->ta_version = $3.type;
+ if ($3.type == ADDRESS_FLAG_SNMPV2) {
+ (void)strlcpy(tr->ta_community, $3.data,
+ sizeof(tr->ta_community));
+ free($3.data);
+ } else {
+ tr->ta_usmusername = $3.data;
+ tr->ta_seclevel = $3.value;
}
- tr->sa_oid = $2;
- tr->sa_community = $3;
TAILQ_INSERT_TAIL(&(conf->sc_trapreceivers), tr, entry);
}
;
| ','
;
-seclevel : NONE { $$ = 0; }
- | AUTH { $$ = SNMP_MSGFLAG_AUTH; }
- | ENC { $$ = SNMP_MSGFLAG_AUTH | SNMP_MSGFLAG_PRIV; }
+seclevel : SECLEVEL NONE { $$ = 0; }
+ | SECLEVEL AUTH { $$ = SNMP_MSGFLAG_AUTH; }
+ | SECLEVEL ENC { $$ = SNMP_MSGFLAG_AUTH | SNMP_MSGFLAG_PRIV; }
;
userspecs : /* empty */
return (NULL);
}
- if (conf->sc_trcommunity[0] == '\0') {
- TAILQ_FOREACH(tr, &conf->sc_trapreceivers, entry) {
- if (tr->sa_community == NULL) {
- log_warnx("trap receiver: missing community");
+ TAILQ_FOREACH(tr, &conf->sc_trapreceivers, entry) {
+ if (tr->ta_version == SNMP_V2 &&
+ tr->ta_community[0] == '\0' &&
+ conf->sc_trcommunity[0] == '\0') {
+ log_warnx("trap receiver: missing community");
+ free(conf);
+ return (NULL);
+ }
+ if (tr->ta_version == SNMP_V3) {
+ tr->ta_usmuser = usm_finduser(tr->ta_usmusername);
+ if (tr->ta_usmuser == NULL) {
+ log_warnx("trap receiver: user not defined: %s",
+ tr->ta_usmusername);
free(conf);
return (NULL);
}
-.\" $OpenBSD: snmpd.conf.5,v 1.57 2021/08/11 18:35:02 sthen Exp $
+.\" $OpenBSD: snmpd.conf.5,v 1.58 2021/09/02 05:41:02 martijn Exp $
.\"
.\" Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
.\"
.\" 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 11 2021 $
+.Dd $Mdocdate: September 2 2021 $
.Dt SNMPD.CONF 5
.Os
.Sh NAME
flag set.
Traps over SNMPv3 are currently unsupported.
.It Xo
-.Ic trap receiver Ar string
+.Ic trap receiver Ar address
.Op Ic oid Ar oid-string
+.Ic snmpv2c
.Op Ic community Ar string
.Op Ic source-address Ar address
.Xc
-Specify the address or FQDN of a remote trap receiver for outgoing traps
+Specify the
+.Ar address
+or FQDN of a remote trap receiver for outgoing traps
sent by
.Xr snmpd 8 .
This option may be specified multiple times.
-The daemon will send outgoing traps using the revised SNMPv2 format and the
-configured trap community.
+The daemon will send outgoing traps in
+.Ic snmpv2c
+format.
The default community is specified by the global
.Ic trap community
option.
The IPv4 or IPv6 source address of the traps can be enforced using
+.It Xo
+.Ic trap receiver Ar address
+.Op Ic oid Ar oid-string
+.Op Ic snmpv3
+.Ic user Ar name Oo Ic seclevel Ar level Oc
+.Op Ic source-address Ar address
+.Xc
+Specify the
+.Ar address
+or FQDN of a remote trap receiver for outgoing traps
+sent by
+.Xr snmpd 8 .
+This option may be specified multiple times.
+The daemon will send outgoing traps in
+.Ic snmpv3
+format.
+.Ic user
+must point to an existing global
+.Ic user .
+If
+.Ic seclevel
+is not defined it defaults to the global
+.Ic seclevel
+option.
+The IPv4 or IPv6 source address of the traps can be enforced using
.Ic source-address .
.El
.Sh USER CONFIGURATION
-/* $OpenBSD: snmpd.h,v 1.99 2021/08/09 18:14:53 martijn Exp $ */
+/* $OpenBSD: snmpd.h,v 1.100 2021/09/02 05:41:02 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
(ADDRESS_FLAG_SNMPV1 | ADDRESS_FLAG_SNMPV2 | ADDRESS_FLAG_SNMPV3)
struct trap_address {
- struct sockaddr_storage ss;
- struct sockaddr_storage ss_local;
- char *sa_community;
- struct ber_oid *sa_oid;
+ struct sockaddr_storage ta_ss;
+ struct sockaddr_storage ta_sslocal;
+ int ta_version;
+ union {
+ char ta_community[SNMPD_MAXCOMMUNITYLEN];
+ struct {
+ char *ta_usmusername;
+ struct usmuser *ta_usmuser;
+ int ta_seclevel;
+ };
+ };
+ struct ber_oid *ta_oid;
TAILQ_ENTRY(trap_address) entry;
};
void snmpe(struct privsep *, struct privsep_proc *);
void snmpe_shutdown(void);
void snmpe_dispatchmsg(struct snmp_message *);
+void snmpe_response(struct snmp_message *);
int snmp_messagecmp(struct snmp_message *, struct snmp_message *);
RB_PROTOTYPE(snmp_messages, snmp_message, sm_entry, snmp_messagecmp)
-/* $OpenBSD: snmpe.c,v 1.74 2021/08/09 18:14:53 martijn Exp $ */
+/* $OpenBSD: snmpe.c,v 1.75 2021/09/02 05:41:02 martijn Exp $ */
/*
* Copyright (c) 2007, 2008, 2012 Reyk Floeter <reyk@openbsd.org>
int snmpe_parse(struct snmp_message *);
void snmpe_tryparse(int, struct snmp_message *);
int snmpe_parsevarbinds(struct snmp_message *);
-void snmpe_response(struct snmp_message *);
void snmpe_sig_handler(int sig, short, void *);
int snmpe_bind(struct address *);
void snmpe_recvmsg(int fd, short, void *);
struct address *h;
kr_init();
- trap_init();
timer_init();
usm_generate_keys();
log_info("snmpe %s: ready",
tohexstr(env->sc_engineid, env->sc_engineid_len));
+ trap_init();
}
void
-/* $OpenBSD: trap.c,v 1.36 2020/09/06 15:51:28 martijn Exp $ */
+/* $OpenBSD: trap.c,v 1.37 2021/09/02 05:41:02 martijn Exp $ */
/*
* Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
int
trap_send(struct ber_oid *oid, struct ber_element *elm)
{
- int ret = 0, s;
struct trap_address *tr;
- struct ber_element *root, *b, *c, *trap;
- struct ber ber;
- char *cmn;
- ssize_t len;
- u_int8_t *ptr;
+ struct ber_element *vblist, *trap;
struct ber_oid uptime = OID(MIB_sysUpTime);
struct ber_oid trapoid = OID(MIB_snmpTrapOID);
char ostr[SNMP_MAX_OID_STRLEN];
struct oid oa, ob;
+ struct snmp_message *msg;
if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers))
return (0);
/* Add mandatory varbind elements */
trap = ober_add_sequence(NULL);
- c = ober_printf_elements(trap, "{Odt}{OO}",
+ vblist = ober_printf_elements(trap, "{Odt}{OO}",
&uptime, smi_getticks(),
BER_CLASS_APPLICATION, SNMP_T_TIMETICKS,
&trapoid, oid);
if (elm != NULL)
- ober_link_elements(c, elm);
-
- bzero(&ber, sizeof(ber));
+ ober_link_elements(vblist, elm);
TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) {
- if (tr->sa_oid != NULL && tr->sa_oid->bo_n) {
+ if (tr->ta_oid != NULL && tr->ta_oid->bo_n) {
/* The trap receiver may want only a specified MIB */
- bcopy(&tr->sa_oid->bo_id, &ob.o_oid,
+ bcopy(&tr->ta_oid->bo_id, &ob.o_oid,
sizeof(ob.o_oid));
- ob.o_oidlen = tr->sa_oid->bo_n;
+ ob.o_oidlen = tr->ta_oid->bo_n;
if (smi_oid_cmp(&oa, &ob) != 0)
continue;
}
- if ((s = snmpd_socket_af(&tr->ss, SOCK_DGRAM)) == -1) {
- ret = -1;
- goto done;
+ if ((msg = calloc(1, sizeof(*msg))) == NULL)
+ fatal("malloc");
+ msg->sm_sock = snmpd_socket_af(&tr->ta_ss, SOCK_DGRAM);
+ if (msg->sm_sock == -1) {
+ log_warn("socket");
+ free(msg);
+ continue;
}
- if (tr->ss_local.ss_family != 0) {
- if (bind(s, (struct sockaddr *)&(tr->ss_local),
- tr->ss_local.ss_len) == -1) {
- ret = -1;
- goto done;
- }
+ memcpy(&(msg->sm_ss), &(tr->ta_ss), sizeof(msg->sm_ss));
+ msg->sm_slen = tr->ta_ss.ss_len;
+ if (tr->ta_sslocal.ss_family != 0) {
+ memcpy(&(msg->sm_local_ss), &(tr->ta_sslocal),
+ sizeof(msg->sm_local_ss));
+ msg->sm_local_slen = tr->ta_sslocal.ss_len;
}
-
- cmn = tr->sa_community != NULL ?
- tr->sa_community : snmpd_env->sc_trcommunity;
-
- /* SNMP header */
- root = ober_add_sequence(NULL);
- b = ober_printf_elements(root, "ds{tddd",
- SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2,
- arc4random(), 0, 0);
- ober_link_elements(b, trap);
-
-#ifdef DEBUG
- smi_debug_elements(root);
-#endif
- len = ober_write_elements(&ber, root);
- if (ober_get_writebuf(&ber, (void *)&ptr) > 0 &&
- sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss,
- tr->ss.ss_len) != -1) {
- snmpd_env->sc_stats.snmp_outpkts++;
- ret++;
+ msg->sm_version = tr->ta_version;
+ msg->sm_pdutype = SNMP_C_TRAPV2;
+ ober_set_application(&msg->sm_ber, smi_application);
+ msg->sm_request = arc4random();
+ if ((msg->sm_varbindresp = ober_dup(trap->be_sub)) == NULL)
+ fatal("malloc");
+
+ switch (msg->sm_version) {
+ case SNMP_V2:
+ (void)strlcpy(msg->sm_community, tr->ta_community,
+ sizeof(msg->sm_community));
+ break;
+ case SNMP_V3:
+ msg->sm_msgid = msg->sm_request & INT32_MAX;
+ msg->sm_max_msg_size = READ_BUF_SIZE;
+ msg->sm_flags = tr->ta_seclevel != -1 ?
+ tr->ta_seclevel : snmpd_env->sc_min_seclevel;
+ msg->sm_secmodel = SNMP_SEC_USM;
+ msg->sm_engine_time = snmpd_engine_time();
+ msg->sm_engine_boots = snmpd_env->sc_engine_boots;
+ memcpy(msg->sm_ctxengineid, snmpd_env->sc_engineid,
+ snmpd_env->sc_engineid_len);
+ msg->sm_ctxengineid_len =
+ snmpd_env->sc_engineid_len;
+ (void)strlcpy(msg->sm_username, tr->ta_usmusername,
+ sizeof(msg->sm_username));
+ msg->sm_user = tr->ta_usmuser;
+ arc4random_buf(msg->sm_salt, sizeof(msg->sm_salt));
+ break;
}
- close(s);
- ober_unlink_elements(b);
- ober_free_elements(root);
+ snmpe_response(msg);
}
-
- done:
ober_free_elements(trap);
- ober_free(&ber);
- return (ret);
+ return 0;
}