GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/trap.c Lines: 0 101 0.0 %
Date: 2017-11-07 Branches: 0 54 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: trap.c,v 1.29 2017/04/21 13:46:15 jca 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/types.h>
21
#include <sys/stat.h>
22
#include <sys/socket.h>
23
#include <sys/un.h>
24
#include <sys/tree.h>
25
26
#include <net/if.h>
27
#include <netinet/in.h>
28
#include <arpa/inet.h>
29
30
#include <stdlib.h>
31
#include <stdio.h>
32
#include <errno.h>
33
#include <event.h>
34
#include <fcntl.h>
35
#include <string.h>
36
#include <unistd.h>
37
#include <pwd.h>
38
39
#include "snmpd.h"
40
#include "mib.h"
41
42
void
43
trap_init(void)
44
{
45
	struct ber_oid	 trapoid = OID(MIB_coldStart);
46
47
	/*
48
	 * Send a coldStart to notify that the daemon has been
49
	 * started and re-initialized.
50
	 */
51
	trap_send(&trapoid, NULL);
52
}
53
54
int
55
trap_agentx(struct agentx_handle *h, struct agentx_pdu *pdu, int *idx,
56
    char **varcpy, int *vcpylen)
57
{
58
	struct agentx_varbind_hdr	 vbhdr;
59
	u_int32_t			 d;
60
	struct ber_oid			 o, oid;
61
	struct ber_oid			 uptime = OID(MIB_sysUpTime);
62
	struct ber_oid			 trapoid = OID(MIB_snmpTrapOID);
63
	struct ber_element		*varbind, *iter;
64
	int				 x = 0, state = 0;
65
	int				 ret = AGENTX_ERR_NONE;
66
	int				 seensysuptime, seentrapoid;
67
	size_t				 len = 0;
68
	pid_t				 pid = -1;
69
	char				*v = NULL;
70
71
	*varcpy = NULL;
72
	varbind = NULL;
73
	iter = NULL;
74
	seensysuptime = seentrapoid = 0;
75
76
	if (pdu->hdr->flags & AGENTX_NON_DEFAULT_CONTEXT) {
77
		ret = AGENTX_ERR_UNSUPPORTED_CONTEXT;
78
		goto done;
79
	}
80
81
	if ((v = malloc(pdu->hdr->length)) == NULL ||
82
	    snmp_agentx_copy_raw(pdu, v, pdu->hdr->length) == -1) {
83
		ret = AGENTX_ERR_PROCESSING_ERROR;
84
		goto done;
85
	}
86
87
	while (pdu->datalen > sizeof(struct agentx_hdr)) {
88
		x++;
89
90
		if (snmp_agentx_read_vbhdr(pdu, &vbhdr) == -1) {
91
			ret = AGENTX_ERR_PARSE_ERROR;
92
			goto done;
93
		}
94
95
		if (state < 2) {
96
			if (snmp_agentx_read_oid(pdu, (struct snmp_oid *)&oid) == -1) {
97
				ret = AGENTX_ERR_PARSE_ERROR;
98
				goto done;
99
			}
100
			if (state == 0 && ber_oid_cmp(&oid, &uptime) == 0) {
101
				if (snmp_agentx_read_int(pdu, &d) == -1) {
102
					ret = AGENTX_ERR_PARSE_ERROR;
103
					goto done;
104
				}
105
				state = 1;
106
				continue;
107
			} else if (ber_oid_cmp(&oid, &trapoid) == 0) {
108
				if (snmp_agentx_read_oid(pdu,
109
				    (struct snmp_oid *)&o) == -1) {
110
					ret = AGENTX_ERR_PARSE_ERROR;
111
					goto done;
112
				}
113
				state = 2;
114
				continue;
115
			} else {
116
				ret = AGENTX_ERR_PROCESSING_ERROR;
117
				goto done;
118
			}
119
		}
120
121
		ret = varbind_convert(pdu, &vbhdr, &varbind, &iter);
122
		if (ret != AGENTX_ERR_NONE)
123
			goto done;
124
	}
125
126
	if (varbind != NULL)
127
		len = ber_calc_len(varbind);
128
	log_debug("trap_agentx: from pid %u len %zd elements %d",
129
	    pid, len, x);
130
131
	trap_send(&o, varbind);
132
133
	*varcpy = v;
134
	*vcpylen = pdu->hdr->length;
135
136
	return (AGENTX_ERR_NONE);
137
 done:
138
	if (varbind != NULL)
139
		ber_free_elements(varbind);
140
	free(v);
141
	*idx = x;
142
	return (ret);
143
}
144
145
int
146
trap_send(struct ber_oid *oid, struct ber_element *elm)
147
{
148
	int			 ret = 0, s;
149
	struct address		*tr;
150
	struct ber_element	*root, *b, *c, *trap;
151
	struct ber		 ber;
152
	char			*cmn;
153
	ssize_t			 len;
154
	u_int8_t		*ptr;
155
	struct			 ber_oid uptime = OID(MIB_sysUpTime);
156
	struct			 ber_oid trapoid = OID(MIB_snmpTrapOID);
157
	char			 ostr[SNMP_MAX_OID_STRLEN];
158
	struct oid		 oa, ob;
159
160
	if (TAILQ_EMPTY(&snmpd_env->sc_trapreceivers))
161
		return (0);
162
163
	smi_scalar_oidlen(&uptime);
164
	smi_scalar_oidlen(&trapoid);
165
	smi_scalar_oidlen(oid);
166
167
	smi_oid2string(oid, ostr, sizeof(ostr), 0);
168
	log_debug("trap_send: oid %s", ostr);
169
170
	/* Setup OIDs to compare against the trap receiver MIB */
171
	bzero(&oa, sizeof(oa));
172
	bcopy(oid->bo_id, &oa.o_oid, sizeof(oa.o_oid));
173
	oa.o_oidlen = oid->bo_n;
174
	bzero(&ob, sizeof(ob));
175
	ob.o_flags = OID_TABLE;
176
177
	/* Add mandatory varbind elements */
178
	trap = ber_add_sequence(NULL);
179
	c = ber_printf_elements(trap, "{Odt}{OO}",
180
	    &uptime, smi_getticks(),
181
	    BER_CLASS_APPLICATION, SNMP_T_TIMETICKS,
182
	    &trapoid, oid);
183
	if (elm != NULL)
184
		ber_link_elements(c, elm);
185
186
	bzero(&ber, sizeof(ber));
187
	ber.fd = -1;
188
189
	TAILQ_FOREACH(tr, &snmpd_env->sc_trapreceivers, entry) {
190
		if (tr->sa_oid != NULL && tr->sa_oid->bo_n) {
191
			/* The trap receiver may want only a specified MIB */
192
			bcopy(&tr->sa_oid->bo_id, &ob.o_oid,
193
			    sizeof(ob.o_oid));
194
			ob.o_oidlen = tr->sa_oid->bo_n;
195
			if (smi_oid_cmp(&oa, &ob) != 0)
196
				continue;
197
		}
198
199
		if ((s = snmpd_socket_af(&tr->ss, htons(tr->port))) == -1) {
200
			ret = -1;
201
			goto done;
202
		}
203
		if (tr->sa_srcaddr != NULL) {
204
			if (bind(s, (struct sockaddr *)&tr->sa_srcaddr->ss,
205
			    tr->sa_srcaddr->ss.ss_len) == -1) {
206
				ret = -1;
207
				goto done;
208
			}
209
		}
210
211
		cmn = tr->sa_community != NULL ?
212
		    tr->sa_community : snmpd_env->sc_trcommunity;
213
214
		/* SNMP header */
215
		root = ber_add_sequence(NULL);
216
		b = ber_printf_elements(root, "ds{tddd",
217
		    SNMP_V2, cmn, BER_CLASS_CONTEXT, SNMP_C_TRAPV2,
218
		    arc4random(), 0, 0);
219
		ber_link_elements(b, trap);
220
221
#ifdef DEBUG
222
		smi_debug_elements(root);
223
#endif
224
		len = ber_write_elements(&ber, root);
225
		if (ber_get_writebuf(&ber, (void *)&ptr) > 0 &&
226
		    sendto(s, ptr, len, 0, (struct sockaddr *)&tr->ss,
227
		    tr->ss.ss_len) != -1) {
228
			snmpd_env->sc_stats.snmp_outpkts++;
229
			ret++;
230
		}
231
232
		close(s);
233
		ber_unlink_elements(b);
234
		ber_free_elements(root);
235
	}
236
237
 done:
238
	ber_free_elements(trap);
239
	ber_free(&ber);
240
241
	return (ret);
242
}