GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/smi.c Lines: 44 171 25.7 %
Date: 2017-11-07 Branches: 102 506 20.2 %

Line Branch Exec Source
1
2
3
/*
4
 * Copyright (c) 2007, 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
#include <sys/sysctl.h>
26
27
#include <net/if.h>
28
#include <net/if_dl.h>
29
#include <net/if_arp.h>
30
#include <net/if_media.h>
31
#include <net/route.h>
32
#include <netinet/in.h>
33
#include <netinet/if_ether.h>
34
#include <arpa/inet.h>
35
36
#include <stdlib.h>
37
#include <stdio.h>
38
#include <errno.h>
39
#include <event.h>
40
#include <fcntl.h>
41
#include <string.h>
42
#include <unistd.h>
43
#include <limits.h>
44
#include <pwd.h>
45
#include <vis.h>
46
47
#include "snmpd.h"
48
#include "mib.h"
49
50
#define MINIMUM(a, b)	(((a) < (b)) ? (a) : (b))
51
52
RB_HEAD(oidtree, oid);
53
RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp);
54
struct oidtree smi_oidtree;
55
56
RB_HEAD(keytree, oid);
57
RB_PROTOTYPE(keytree, oid, o_keyword, smi_key_cmp);
58
struct keytree smi_keytree;
59
60
u_long
61
smi_getticks(void)
62
{
63
	struct timeval	 now, run;
64
	u_long		 ticks;
65
66
	gettimeofday(&now, NULL);
67
	if (timercmp(&now, &snmpd_env->sc_starttime, <=))
68
		return (0);
69
	timersub(&now, &snmpd_env->sc_starttime, &run);
70
	ticks = run.tv_sec * 100;
71
	if (run.tv_usec)
72
		ticks += run.tv_usec / 10000;
73
74
	return (ticks);
75
}
76
77
void
78
smi_oidlen(struct ber_oid *o)
79
{
80
	size_t	 i;
81
82

522680
	for (i = 0; i < BER_MAX_OID_LEN && o->bo_id[i] != 0; i++)
83
		;
84
15608
	o->bo_n = i;
85
15608
}
86
87
void
88
smi_scalar_oidlen(struct ber_oid *o)
89
{
90
	smi_oidlen(o);
91
92
	/* Append .0. */
93
	if (o->bo_n < BER_MAX_OID_LEN)
94
		o->bo_n++;
95
}
96
97
char *
98
smi_oid2string(struct ber_oid *o, char *buf, size_t len, size_t skip)
99
{
100
	char		 str[256];
101
	struct oid	*value, key;
102
	size_t		 i, lookup = 1;
103
104
	bzero(buf, len);
105
	bzero(&key, sizeof(key));
106
	bcopy(o, &key.o_id, sizeof(struct ber_oid));
107
	key.o_flags |= OID_KEY;		/* do not match wildcards */
108
109
	if (snmpd_env->sc_flags & SNMPD_F_NONAMES)
110
		lookup = 0;
111
112
	for (i = 0; i < o->bo_n; i++) {
113
		key.o_oidlen = i + 1;
114
		if (lookup && skip > i)
115
			continue;
116
		if (lookup &&
117
		    (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL)
118
			snprintf(str, sizeof(str), "%s", value->o_name);
119
		else
120
			snprintf(str, sizeof(str), "%d", key.o_oid[i]);
121
		strlcat(buf, str, len);
122
		if (i < (o->bo_n - 1))
123
			strlcat(buf, ".", len);
124
	}
125
126
	return (buf);
127
}
128
129
int
130
smi_string2oid(const char *oidstr, struct ber_oid *o)
131
{
132
	char			*sp, *p, str[BUFSIZ];
133
	const char		*errstr;
134
	struct oid		*oid;
135
	struct ber_oid		 ko;
136
137
	if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str))
138
		return (-1);
139
	bzero(o, sizeof(*o));
140
141
	/*
142
	 * Parse OID strings in the common form n.n.n or n-n-n.
143
	 * Based on ber_string2oid with additional support for symbolic names.
144
	 */
145
	for (p = sp = str; p != NULL; sp = p) {
146
		if ((p = strpbrk(p, ".-")) != NULL)
147
			*p++ = '\0';
148
		if ((oid = smi_findkey(sp)) != NULL) {
149
			bcopy(&oid->o_id, &ko, sizeof(ko));
150
			if (o->bo_n && ber_oid_cmp(o, &ko) != 2)
151
				return (-1);
152
			bcopy(&ko, o, sizeof(*o));
153
			errstr = NULL;
154
		} else {
155
			o->bo_id[o->bo_n++] =
156
			    strtonum(sp, 0, UINT_MAX, &errstr);
157
		}
158
		if (errstr || o->bo_n > BER_MAX_OID_LEN)
159
			return (-1);
160
	}
161
162
	return (0);
163
}
164
165
void
166
smi_delete(struct oid *oid)
167
{
168
	struct oid	 key, *value;
169
170
	bzero(&key, sizeof(key));
171
	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
172
	if ((value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL &&
173
	    value == oid)
174
		RB_REMOVE(oidtree, &smi_oidtree, value);
175
176
	free(oid->o_data);
177
	if (oid->o_flags & OID_DYNAMIC) {
178
		free(oid->o_name);
179
		free(oid);
180
	}
181
}
182
183
int
184
smi_insert(struct oid *oid)
185
{
186
16
	struct oid		 key, *value;
187
188

8
	if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
189
		fatalx("smi_insert: invalid MIB table");
190
191
8
	bzero(&key, sizeof(key));
192
8
	bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid));
193
8
	value = RB_FIND(oidtree, &smi_oidtree, &key);
194
8
	if (value != NULL)
195
		return (-1);
196
197
8
	RB_INSERT(oidtree, &smi_oidtree, oid);
198
8
	return (0);
199
8
}
200
201
void
202
smi_mibtree(struct oid *oids)
203
{
204
	struct oid	*oid, *decl;
205
	size_t		 i;
206
207
31680
	for (i = 0; oids[i].o_oid[0] != 0; i++) {
208
		oid = &oids[i];
209
15600
		smi_oidlen(&oid->o_id);
210
15600
		if (oid->o_name != NULL) {
211

9424
			if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL)
212
				fatalx("smi_mibtree: invalid MIB table");
213
9424
			RB_INSERT(oidtree, &smi_oidtree, oid);
214
9424
			RB_INSERT(keytree, &smi_keytree, oid);
215
9424
			continue;
216
		}
217
6176
		decl = RB_FIND(oidtree, &smi_oidtree, oid);
218
6176
		if (decl == NULL)
219
			fatalx("smi_mibtree: undeclared MIB");
220
6176
		decl->o_flags = oid->o_flags;
221
6176
		decl->o_get = oid->o_get;
222
6176
		decl->o_set = oid->o_set;
223
6176
		decl->o_table = oid->o_table;
224
6176
		decl->o_val = oid->o_val;
225
6176
		decl->o_data = oid->o_data;
226
6176
	}
227
160
}
228
229
int
230
smi_init(void)
231
{
232
	/* Initialize the Structure of Managed Information (SMI) */
233
32
	RB_INIT(&smi_oidtree);
234
16
	mib_init();
235
16
	return (0);
236
}
237
238
struct oid *
239
smi_find(struct oid *oid)
240
{
241
	return (RB_FIND(oidtree, &smi_oidtree, oid));
242
}
243
244
struct oid *
245
smi_findkey(char *name)
246
{
247
	struct oid	oid;
248
	if (name == NULL)
249
		return (NULL);
250
	oid.o_name = name;
251
	return (RB_FIND(keytree, &smi_keytree, &oid));
252
}
253
254
struct oid *
255
smi_next(struct oid *oid)
256
{
257
	return (RB_NEXT(oidtree, &smi_oidtree, oid));
258
}
259
260
struct oid *
261
smi_foreach(struct oid *oid, u_int flags)
262
{
263
	/*
264
	 * Traverse the tree of MIBs with the option to check
265
	 * for specific OID flags.
266
	 */
267
	if (oid == NULL) {
268
		oid = RB_MIN(oidtree, &smi_oidtree);
269
		if (oid == NULL)
270
			return (NULL);
271
		if (flags == 0 || (oid->o_flags & flags))
272
			return (oid);
273
	}
274
	for (;;) {
275
		oid = RB_NEXT(oidtree, &smi_oidtree, oid);
276
		if (oid == NULL)
277
			break;
278
		if (flags == 0 || (oid->o_flags & flags))
279
			return (oid);
280
	}
281
282
	return (oid);
283
}
284
285
#ifdef DEBUG
286
void
287
smi_debug_elements(struct ber_element *root)
288
{
289
	static int	 indent = 0;
290
	char		*value;
291
	int		 constructed;
292
293
	/* calculate lengths */
294
	ber_calc_len(root);
295
296
	switch (root->be_encoding) {
297
	case BER_TYPE_SEQUENCE:
298
	case BER_TYPE_SET:
299
		constructed = root->be_encoding;
300
		break;
301
	default:
302
		constructed = 0;
303
		break;
304
	}
305
306
	fprintf(stderr, "%*slen %lu ", indent, "", root->be_len);
307
	switch (root->be_class) {
308
	case BER_CLASS_UNIVERSAL:
309
		fprintf(stderr, "class: universal(%u) type: ", root->be_class);
310
		switch (root->be_type) {
311
		case BER_TYPE_EOC:
312
			fprintf(stderr, "end-of-content");
313
			break;
314
		case BER_TYPE_BOOLEAN:
315
			fprintf(stderr, "boolean");
316
			break;
317
		case BER_TYPE_INTEGER:
318
			fprintf(stderr, "integer");
319
			break;
320
		case BER_TYPE_BITSTRING:
321
			fprintf(stderr, "bit-string");
322
			break;
323
		case BER_TYPE_OCTETSTRING:
324
			fprintf(stderr, "octet-string");
325
			break;
326
		case BER_TYPE_NULL:
327
			fprintf(stderr, "null");
328
			break;
329
		case BER_TYPE_OBJECT:
330
			fprintf(stderr, "object");
331
			break;
332
		case BER_TYPE_ENUMERATED:
333
			fprintf(stderr, "enumerated");
334
			break;
335
		case BER_TYPE_SEQUENCE:
336
			fprintf(stderr, "sequence");
337
			break;
338
		case BER_TYPE_SET:
339
			fprintf(stderr, "set");
340
			break;
341
		}
342
		break;
343
	case BER_CLASS_APPLICATION:
344
		fprintf(stderr, "class: application(%u) type: ",
345
		    root->be_class);
346
		switch (root->be_type) {
347
		case SNMP_T_IPADDR:
348
			fprintf(stderr, "ipaddr");
349
			break;
350
		case SNMP_T_COUNTER32:
351
			fprintf(stderr, "counter32");
352
			break;
353
		case SNMP_T_GAUGE32:
354
			fprintf(stderr, "gauge32");
355
			break;
356
		case SNMP_T_TIMETICKS:
357
			fprintf(stderr, "timeticks");
358
			break;
359
		case SNMP_T_OPAQUE:
360
			fprintf(stderr, "opaque");
361
			break;
362
		case SNMP_T_COUNTER64:
363
			fprintf(stderr, "counter64");
364
			break;
365
		}
366
		break;
367
	case BER_CLASS_CONTEXT:
368
		fprintf(stderr, "class: context(%u) type: ",
369
		    root->be_class);
370
		switch (root->be_type) {
371
		case SNMP_C_GETREQ:
372
			fprintf(stderr, "getreq");
373
			break;
374
		case SNMP_C_GETNEXTREQ:
375
			fprintf(stderr, "nextreq");
376
			break;
377
		case SNMP_C_GETRESP:
378
			fprintf(stderr, "getresp");
379
			break;
380
		case SNMP_C_SETREQ:
381
			fprintf(stderr, "setreq");
382
			break;
383
		case SNMP_C_TRAP:
384
			fprintf(stderr, "trap");
385
			break;
386
		case SNMP_C_GETBULKREQ:
387
			fprintf(stderr, "getbulkreq");
388
			break;
389
		case SNMP_C_INFORMREQ:
390
			fprintf(stderr, "informreq");
391
			break;
392
		case SNMP_C_TRAPV2:
393
			fprintf(stderr, "trapv2");
394
			break;
395
		case SNMP_C_REPORT:
396
			fprintf(stderr, "report");
397
			break;
398
		}
399
		break;
400
	case BER_CLASS_PRIVATE:
401
		fprintf(stderr, "class: private(%u) type: ", root->be_class);
402
		break;
403
	default:
404
		fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class);
405
		break;
406
	}
407
	fprintf(stderr, "(%lu) encoding %lu ",
408
	    root->be_type, root->be_encoding);
409
410
	if ((value = smi_print_element(root)) == NULL)
411
		goto invalid;
412
413
	switch (root->be_encoding) {
414
	case BER_TYPE_BOOLEAN:
415
		fprintf(stderr, "%s", value);
416
		break;
417
	case BER_TYPE_INTEGER:
418
	case BER_TYPE_ENUMERATED:
419
		fprintf(stderr, "value %s", value);
420
		break;
421
	case BER_TYPE_BITSTRING:
422
		fprintf(stderr, "hexdump %s", value);
423
		break;
424
	case BER_TYPE_OBJECT:
425
		fprintf(stderr, "oid %s", value);
426
		break;
427
	case BER_TYPE_OCTETSTRING:
428
		if (root->be_class == BER_CLASS_APPLICATION &&
429
		    root->be_type == SNMP_T_IPADDR) {
430
			fprintf(stderr, "addr %s", value);
431
		} else {
432
			fprintf(stderr, "string %s", value);
433
		}
434
		break;
435
	case BER_TYPE_NULL:	/* no payload */
436
	case BER_TYPE_EOC:
437
	case BER_TYPE_SEQUENCE:
438
	case BER_TYPE_SET:
439
	default:
440
		fprintf(stderr, "%s", value);
441
		break;
442
	}
443
444
 invalid:
445
	if (value == NULL)
446
		fprintf(stderr, "<INVALID>");
447
	else
448
		free(value);
449
	fprintf(stderr, "\n");
450
451
	if (constructed)
452
		root->be_encoding = constructed;
453
454
	if (constructed && root->be_sub) {
455
		indent += 2;
456
		smi_debug_elements(root->be_sub);
457
		indent -= 2;
458
	}
459
	if (root->be_next)
460
		smi_debug_elements(root->be_next);
461
}
462
#endif
463
464
char *
465
smi_print_element(struct ber_element *root)
466
{
467
	char		*str = NULL, *buf, *p;
468
	size_t		 len, i;
469
	long long	 v;
470
	int		 d;
471
	struct ber_oid	 o;
472
	char		 strbuf[BUFSIZ];
473
474
	switch (root->be_encoding) {
475
	case BER_TYPE_BOOLEAN:
476
		if (ber_get_boolean(root, &d) == -1)
477
			goto fail;
478
		if (asprintf(&str, "%s(%d)", d ? "true" : "false", d) == -1)
479
			goto fail;
480
		break;
481
	case BER_TYPE_INTEGER:
482
	case BER_TYPE_ENUMERATED:
483
		if (ber_get_integer(root, &v) == -1)
484
			goto fail;
485
		if (asprintf(&str, "%lld", v) == -1)
486
			goto fail;
487
		break;
488
	case BER_TYPE_BITSTRING:
489
		if (ber_get_bitstring(root, (void *)&buf, &len) == -1)
490
			goto fail;
491
		if ((str = calloc(1, len * 2 + 1)) == NULL)
492
			goto fail;
493
		for (p = str, i = 0; i < len; i++) {
494
			snprintf(p, 3, "%02x", buf[i]);
495
			p += 2;
496
		}
497
		break;
498
	case BER_TYPE_OBJECT:
499
		if (ber_get_oid(root, &o) == -1)
500
			goto fail;
501
		if (asprintf(&str, "%s",
502
		    smi_oid2string(&o, strbuf, sizeof(strbuf), 0)) == -1)
503
			goto fail;
504
		break;
505
	case BER_TYPE_OCTETSTRING:
506
		if (ber_get_string(root, &buf) == -1)
507
			goto fail;
508
		if (root->be_class == BER_CLASS_APPLICATION &&
509
		    root->be_type == SNMP_T_IPADDR) {
510
			if (asprintf(&str, "%s",
511
			    inet_ntoa(*(struct in_addr *)buf)) == -1)
512
				goto fail;
513
		} else {
514
			if ((p = reallocarray(NULL, 4, root->be_len + 1)) == NULL)
515
				goto fail;
516
			strvisx(p, buf, root->be_len, VIS_NL);
517
			if (asprintf(&str, "\"%s\"", p) == -1) {
518
				free(p);
519
				goto fail;
520
			}
521
			free(p);
522
		}
523
		break;
524
	case BER_TYPE_NULL:	/* no payload */
525
	case BER_TYPE_EOC:
526
	case BER_TYPE_SEQUENCE:
527
	case BER_TYPE_SET:
528
	default:
529
		str = strdup("");
530
		break;
531
	}
532
533
	return (str);
534
535
 fail:
536
	free(str);
537
	return (NULL);
538
}
539
540
unsigned long
541
smi_application(struct ber_element *elm)
542
{
543
	if (elm->be_class != BER_CLASS_APPLICATION)
544
		return (BER_TYPE_OCTETSTRING);
545
546
	switch (elm->be_type) {
547
	case SNMP_T_IPADDR:
548
		return (BER_TYPE_OCTETSTRING);
549
	case SNMP_T_COUNTER32:
550
	case SNMP_T_GAUGE32:
551
	case SNMP_T_TIMETICKS:
552
	case SNMP_T_OPAQUE:
553
	case SNMP_T_COUNTER64:
554
		return (BER_TYPE_INTEGER);
555
	default:
556
		break;
557
	}
558
	return (BER_TYPE_OCTETSTRING);
559
}
560
561
int
562
smi_oid_cmp(struct oid *a, struct oid *b)
563
{
564
	size_t	 i;
565
566
2861120
	for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++)
567
1329576
		if (a->o_oid[i] != b->o_oid[i])
568
151424
			return (a->o_oid[i] - b->o_oid[i]);
569
570
	/*
571
	 * Return success if the matched object is a table
572
	 * or a MIB registered by a subagent
573
	 * (it will match any sub-elements)
574
	 */
575

16848
	if ((b->o_flags & OID_TABLE ||
576
16848
	    b->o_flags & OID_REGISTERED) &&
577
	    (a->o_flags & OID_KEY) == 0 &&
578
	    (a->o_oidlen > b->o_oidlen))
579
		return (0);
580
581
16848
	return (a->o_oidlen - b->o_oidlen);
582
168272
}
583
584













































913884
RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp);
585
586
int
587
smi_key_cmp(struct oid *a, struct oid *b)
588
{
589

261456
	if (a->o_name == NULL || b->o_name == NULL)
590
		return (-1);
591
87152
	return (strcasecmp(a->o_name, b->o_name));
592
87152
}
593
594













































507760
RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp);