GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpctl/snmpctl.c Lines: 49 152 32.2 %
Date: 2017-11-07 Branches: 31 125 24.8 %

Line Branch Exec Source
1
/*	$OpenBSD: snmpctl.c,v 1.23 2017/08/10 16:03:10 rob Exp $	*/
2
3
/*
4
 * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org>
5
 * Copyright (c) 2005 Claudio Jeker <claudio@openbsd.org>
6
 * Copyright (c) 2004, 2005 Esben Norby <norby@openbsd.org>
7
 * Copyright (c) 2003 Henning Brauer <henning@openbsd.org>
8
 *
9
 * Permission to use, copy, modify, and distribute this software for any
10
 * purpose with or without fee is hereby granted, provided that the above
11
 * copyright notice and this permission notice appear in all copies.
12
 *
13
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
14
 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
15
 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
16
 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
17
 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
18
 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
19
 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20
 */
21
22
#include <sys/types.h>
23
#include <sys/socket.h>
24
#include <sys/queue.h>
25
#include <sys/un.h>
26
#include <sys/tree.h>
27
#include <sys/uio.h>
28
29
#include <netinet/in.h>
30
#include <arpa/inet.h>
31
#include <net/if.h>
32
#include <net/if_media.h>
33
#include <net/if_types.h>
34
35
#include <err.h>
36
#include <errno.h>
37
#include <stdio.h>
38
#include <stdlib.h>
39
#include <string.h>
40
#include <unistd.h>
41
#include <event.h>
42
43
#include "snmpd.h"
44
#include "snmp.h"
45
#include "parser.h"
46
#include "mib.h"
47
48
__dead void	 usage(void);
49
50
struct imsgname {
51
	int type;
52
	char *name;
53
	void (*func)(struct imsg *);
54
};
55
56
void		 show_mib(void);
57
struct imsgname *monitor_lookup(u_int8_t);
58
void		 monitor_id(struct imsg *);
59
int		 monitor(struct imsg *);
60
61
struct imsgname imsgs[] = {
62
	{ 0,				NULL,			NULL }
63
};
64
struct imsgname imsgunknown = {
65
	-1,				"<unknown>",		NULL
66
};
67
68
void snmpctl_trap(int, struct parse_result *);
69
70
struct imsgbuf	 ibuf;
71
struct snmpd	*snmpd_env;
72
struct oid	 mib_tree[] = MIB_TREE;
73
74
__dead void
75
usage(void)
76
{
77
	extern char *__progname;
78
79
	fprintf(stderr, "usage: %s [-n] [-s socket] command [arg ...]\n", __progname);
80
	exit(1);
81
}
82
83
int
84
main(int argc, char *argv[])
85
{
86
8
	struct sockaddr_un	 sun;
87
	struct parse_result	*res;
88
4
	struct imsg		 imsg;
89
	int			 ctl_sock;
90
	int			 done = 0;
91
	int			 n;
92
	int			 ch;
93
	const char		*sock = SNMPD_SOCKET;
94
95
4
	if ((snmpd_env = calloc(1, sizeof(struct snmpd))) == NULL)
96
		err(1, "calloc");
97
4
	gettimeofday(&snmpd_env->sc_starttime, NULL);
98
99
8
	while ((ch = getopt(argc, argv, "ns:")) != -1) {
100
		switch (ch) {
101
		case 'n':
102
			snmpd_env->sc_flags |= SNMPD_F_NONAMES;
103
			break;
104
		case 's':
105
			sock = optarg;
106
			break;
107
		default:
108
			usage();
109
			/* NOTREACHED */
110
		}
111
	}
112
4
	argc -= optind;
113
4
	argv += optind;
114
115
4
	smi_init();
116
117
	/* parse options */
118
4
	if ((res = parse(argc, argv)) == NULL)
119
		exit(1);
120
121

4
	switch (res->action) {
122
	case NONE:
123
		usage();
124
		break;
125
	case SHOW_MIB:
126
		if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
127
			fatal("pledge");
128
		show_mib();
129
		break;
130
	case WALK:
131
	case GET:
132
	case BULKWALK:
133
		snmpclient(res);
134
		break;
135
	default:
136
		goto connect;
137
	}
138
139
	free(snmpd_env);
140
	return (0);
141
142
 connect:
143
4
	if (pledge("stdio unix flock rpath cpath wpath", NULL) == -1)
144
		fatal("pledge");
145
146
	/* connect to snmpd control socket */
147
4
	if ((ctl_sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1)
148
		err(1, "socket");
149
150
4
	bzero(&sun, sizeof(sun));
151
4
	sun.sun_family = AF_UNIX;
152
4
	strlcpy(sun.sun_path, sock, sizeof(sun.sun_path));
153
 reconnect:
154
4
	if (connect(ctl_sock, (struct sockaddr *)&sun, sizeof(sun)) == -1) {
155
		/* Keep retrying if running in monitor mode */
156
		if (res->action == MONITOR &&
157
		    (errno == ENOENT || errno == ECONNREFUSED)) {
158
			usleep(100);
159
			goto reconnect;
160
		}
161
		err(1, "connect: %s", sock);
162
	}
163
164
4
	if (pledge("stdio flock rpath cpath wpath", NULL) == -1)
165
		fatal("pledge");
166
167
12
	imsg_init(&ibuf, ctl_sock);
168
	done = 0;
169
170
	/* process user request */
171
12
	switch (res->action) {
172
	case MONITOR:
173
		imsg_compose(&ibuf, IMSG_CTL_NOTIFY, 0, 0, -1, NULL, 0);
174
		break;
175
	case NONE:
176
	case SHOW_MIB:
177
	case WALK:
178
	case GET:
179
	case BULKWALK:
180
		break;
181
	case TRAP:
182
		/* explicitly downgrade the socket */
183
4
		imsg_compose(&ibuf, IMSG_SNMP_AGENTX, 0, 0, -1, NULL, 0);
184
4
		break;
185
	}
186
187
8
	while (ibuf.w.queued)
188

4
		if (msgbuf_write(&ibuf.w) <= 0 && errno != EAGAIN)
189
			err(1, "write error");
190
191
8
	while (!done) {
192

4
		if ((n = imsg_read(&ibuf)) == -1 && errno != EAGAIN)
193
			errx(1, "imsg_read error");
194
4
		if (n == 0)
195
			errx(1, "pipe closed");
196
197
12
		while (!done) {
198
4
			if ((n = imsg_get(&ibuf, &imsg)) == -1)
199
				errx(1, "imsg_get error");
200
4
			if (n == 0)
201
				break;
202
8
			switch (res->action) {
203
			case MONITOR:
204
				done = monitor(&imsg);
205
				break;
206
			case TRAP:
207
4
				if (imsg.hdr.type == IMSG_CTL_OK) {
208
4
					snmpctl_trap(ctl_sock, res);
209
					done = 1;
210
				} else
211
					errx(1, "snmpd refused connection");
212
4
				break;
213
			case NONE:
214
			case SHOW_MIB:
215
			case WALK:
216
			case GET:
217
			case BULKWALK:
218
				break;
219
			}
220
4
			imsg_free(&imsg);
221
		}
222
	}
223
4
	close(ctl_sock);
224
225
4
	return (0);
226
4
}
227
228
void
229
mib_init(void)
230
{
231
	/*
232
	 * MIB declarations (to register the OID names)
233
	 */
234
8
	smi_mibtree(mib_tree);
235
4
}
236
237
void
238
show_mib(void)
239
{
240
	struct oid	*oid;
241
242
	for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
243
		char	 buf[BUFSIZ];
244
		smi_oid2string(&oid->o_id, buf, sizeof(buf), 0);
245
		printf("%s\n", buf);
246
	}
247
}
248
249
struct imsgname *
250
monitor_lookup(u_int8_t type)
251
{
252
	int i;
253
254
	for (i = 0; imsgs[i].name != NULL; i++)
255
		if (imsgs[i].type == type)
256
			return (&imsgs[i]);
257
	return (&imsgunknown);
258
}
259
260
int
261
monitor(struct imsg *imsg)
262
{
263
	time_t			 now;
264
	int			 done = 0;
265
	struct imsgname		*imn;
266
267
	now = time(NULL);
268
269
	imn = monitor_lookup(imsg->hdr.type);
270
	printf("%s: imsg type %u len %u peerid %u pid %d\n", imn->name,
271
	    imsg->hdr.type, imsg->hdr.len, imsg->hdr.peerid, imsg->hdr.pid);
272
	printf("\ttimestamp: %lld, %s", (long long)now, ctime(&now));
273
	if (imn->type == -1)
274
		done = 1;
275
	if (imn->func != NULL)
276
		(*imn->func)(imsg);
277
278
	return (done);
279
}
280
281
void
282
snmpctl_trap(int ctl_sock, struct parse_result *res)
283
{
284
8
	struct snmp_oid		 oid, oid1;
285
	struct parse_varbind	*vb;
286
	struct agentx_handle	*h;
287
	struct agentx_pdu	*pdu;
288
	void			*ptr;
289
290
4
	if ((h = snmp_agentx_fdopen(ctl_sock, "snmpctl", NULL)) == NULL)
291
		err(1, "agentx socket");
292
293
4
	if (ber_string2oid(res->trapoid, (struct ber_oid *)&oid) == -1)
294
		errx(1, "bad trap oid %s", res->trapoid);
295
296
4
	if ((pdu = snmp_agentx_notify_pdu(&oid)) == NULL)
297
		errx(1, "notify start");
298
299
4
	while ((vb = TAILQ_FIRST(&res->varbinds)) != NULL) {
300
301
		if (ber_string2oid(vb->sm.snmp_oid,
302
		    (struct ber_oid *)&oid) == -1)
303
			errx(1, "bad oid %s", vb->sm.snmp_oid);
304
305
		switch (vb->sm.snmp_type) {
306
307
		/* SNMP_GAUGE32 is handled here */
308
		case SNMP_INTEGER32:
309
		case SNMP_NSAPADDR:
310
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_INTEGER,
311
			    &vb->u.d, vb->sm.snmp_len) == -1)
312
				errx(1, "varbind");
313
			break;
314
315
		case SNMP_OPAQUE:
316
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_OPAQUE,
317
			    &vb->u.d, vb->sm.snmp_len) == -1)
318
				errx(1, "varbind");
319
			break;
320
321
		case SNMP_COUNTER32:
322
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER32,
323
			    &vb->u.d, vb->sm.snmp_len) == -1)
324
				errx(1, "varbind");
325
			break;
326
327
		case SNMP_TIMETICKS:
328
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_TIME_TICKS,
329
			    &vb->u.d, vb->sm.snmp_len) == -1)
330
				errx(1, "varbind");
331
			break;
332
333
		case SNMP_UINTEGER32:
334
		case SNMP_UNSIGNED32:
335
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_INTEGER,
336
			    &vb->u.u, vb->sm.snmp_len) == -1)
337
				errx(1, "varbind");
338
			break;
339
340
		case SNMP_COUNTER64:
341
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_COUNTER64,
342
			    &vb->u.l, vb->sm.snmp_len) == -1)
343
				errx(1, "varbind");
344
			break;
345
346
		case SNMP_IPADDR:
347
			if (vb->sm.snmp_len == sizeof(struct in6_addr))
348
				ptr = &vb->u.in6;
349
			else
350
				ptr = &vb->u.in4;
351
352
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_OPAQUE,
353
			    ptr, vb->sm.snmp_len) == -1)
354
				errx(1, "varbind");
355
			break;
356
357
		case SNMP_OBJECT:
358
			if (ber_string2oid(vb->u.str,
359
			    (struct ber_oid *)&oid1) == -1)
360
				errx(1, "invalid OID %s", vb->u.str);
361
362
			if (snmp_agentx_varbind(pdu, &oid,
363
			    AGENTX_OBJECT_IDENTIFIER, &oid1,
364
			    sizeof(oid1)) == -1)
365
				errx(1, "varbind");
366
			break;
367
368
		case SNMP_BITSTRING:
369
		case SNMP_OCTETSTRING:
370
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_OCTET_STRING,
371
			    vb->u.str, vb->sm.snmp_len) == -1)
372
				errx(1, "varbind");
373
			break;
374
375
		case SNMP_NULL:
376
			/* no data beyond the OID itself */
377
			if (snmp_agentx_varbind(pdu, &oid, AGENTX_NULL,
378
			    NULL, 0) == -1)
379
				errx(1, "varbind");
380
			break;
381
		}
382
383
		TAILQ_REMOVE(&res->varbinds, vb, vb_entry);
384
		free(vb);
385
	}
386
387
4
	if ((pdu = snmp_agentx_request(h, pdu)) == NULL)
388
		err(1, "request: %i", h->error);
389
4
	if (snmp_agentx_response(h, pdu) == -1)
390
		errx(1, "response: %i", h->error);
391
4
	snmp_agentx_pdu_free(pdu);
392
4
	if (snmp_agentx_close(h, AGENTX_CLOSE_SHUTDOWN) == -1)
393
		err(1, "close");
394
4
}