xref: /openbsd-src/usr.sbin/snmpd/trap.c (revision 17240de173a8a1a47a0778dd703c3d79b26065fe)
1 /*	$OpenBSD: trap.c,v 1.43 2024/02/06 15:36:11 martijn Exp $	*/
2 
3 /*
4  * Copyright (c) 2008 Reyk Floeter <reyk@openbsd.org>
5  *
6  * Permission to use, copy, modify, and distribute this software for any
7  * purpose with or without fee is hereby granted, provided that the above
8  * copyright notice and this permission notice appear in all copies.
9  *
10  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17  */
18 
19 #include <sys/queue.h>
20 #include <sys/socket.h>
21 
22 #include <ber.h>
23 #include <stdint.h>
24 #include <stdlib.h>
25 #include <string.h>
26 
27 #include "log.h"
28 #include "mib.h"
29 #include "smi.h"
30 #include "snmp.h"
31 #include "snmpd.h"
32 
33 void
trap_init(void)34 trap_init(void)
35 {
36 	/*
37 	 * Send a coldStart to notify that the daemon has been
38 	 * started and re-initialized.
39 	 */
40 	trap_send(&OID(MIB_coldStart), NULL);
41 }
42 
43 int
trap_send(struct ber_oid * oid,struct ber_element * elm)44 trap_send(struct ber_oid *oid, struct ber_element *elm)
45 {
46 	struct trap_address	*tr;
47 	struct ber_element	*vblist, *trap;
48 	struct			 ber_oid uptime = OID(MIB_sysUpTime, 0);
49 	struct			 ber_oid trapoid = OID(MIB_snmpTrapOID, 0);
50 	char			 ostr[SNMP_MAX_OID_STRLEN];
51 	struct snmp_message	*msg;
52 	int			 r;
53 
54 	if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers))
55 		return (0);
56 
57 	mib_oid2string(oid, ostr, sizeof(ostr), snmpd_env->sc_oidfmt);
58 	log_debug("trap_send: oid %s", ostr);
59 
60 	/* Add mandatory varbind elements */
61 	trap = ober_add_sequence(NULL);
62 	vblist = ober_printf_elements(trap, "{Odt}{OO}",
63 	    &uptime, smi_getticks(),
64 	    BER_CLASS_APPLICATION, SNMP_T_TIMETICKS,
65 	    &trapoid, oid);
66 	if (elm != NULL)
67 		ober_link_elements(vblist, elm);
68 
69 	TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) {
70 		if (tr->ta_oid.bo_n) {
71 			/* The trap receiver may want only a specified MIB */
72 			r = ober_oid_cmp(oid, &tr->ta_oid);
73 			if (r != 0 && r != 2)
74 				continue;
75 		}
76 
77 		if ((msg = calloc(1, sizeof(*msg))) == NULL)
78 			fatal("malloc");
79 		msg->sm_sock = snmpd_socket_af(&tr->ta_ss, SOCK_DGRAM);
80 		if (msg->sm_sock == -1) {
81 			log_warn("socket");
82 			free(msg);
83 			continue;
84 		}
85 		memcpy(&(msg->sm_ss), &(tr->ta_ss), sizeof(msg->sm_ss));
86 		msg->sm_slen = tr->ta_ss.ss_len;
87 		if (tr->ta_sslocal.ss_family != 0) {
88 			memcpy(&(msg->sm_local_ss), &(tr->ta_sslocal),
89 			    sizeof(msg->sm_local_ss));
90 			msg->sm_local_slen = tr->ta_sslocal.ss_len;
91 		}
92 		msg->sm_version = tr->ta_version;
93 		msg->sm_pdutype = SNMP_C_TRAPV2;
94 		ober_set_application(&msg->sm_ber, smi_application);
95 		msg->sm_request = arc4random();
96 		if ((msg->sm_varbindresp = ober_dup(trap->be_sub)) == NULL)
97 			fatal("malloc");
98 
99 		switch (msg->sm_version) {
100 		case SNMP_V2:
101 			(void)strlcpy(msg->sm_community, tr->ta_community,
102 			    sizeof(msg->sm_community));
103 			break;
104 		case SNMP_V3:
105 			msg->sm_msgid = msg->sm_request & INT32_MAX;
106 			msg->sm_max_msg_size = READ_BUF_SIZE;
107 			msg->sm_flags = tr->ta_seclevel != -1 ?
108 			    tr->ta_seclevel : snmpd_env->sc_min_seclevel;
109 			msg->sm_secmodel = SNMP_SEC_USM;
110 			msg->sm_engine_time = snmpd_engine_time();
111 			msg->sm_engine_boots = snmpd_env->sc_engine_boots;
112 			memcpy(msg->sm_ctxengineid, snmpd_env->sc_engineid,
113 			    snmpd_env->sc_engineid_len);
114 			msg->sm_ctxengineid_len =
115 			    snmpd_env->sc_engineid_len;
116 			(void)strlcpy(msg->sm_username, tr->ta_usmusername,
117 			    sizeof(msg->sm_username));
118 			msg->sm_user = tr->ta_usmuser;
119 			arc4random_buf(msg->sm_salt, sizeof(msg->sm_salt));
120 			break;
121 		}
122 
123 		snmpe_response(msg);
124 	}
125 	ober_free_elements(trap);
126 
127 	return 0;
128 }
129