GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.sbin/snmpd/mps.c Lines: 0 205 0.0 %
Date: 2017-11-13 Branches: 0 133 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: mps.c,v 1.24 2016/10/28 08:01:53 rzalamena Exp $	*/
2
3
/*
4
 * Copyright (c) 2007, 2008, 2012 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 <pwd.h>
44
45
#include "snmpd.h"
46
#include "mib.h"
47
48
struct ber_oid *
49
	 mps_table(struct oid *, struct ber_oid *, struct ber_oid *);
50
51
extern void control_event_add(struct ctl_conn *, int, int, struct timeval *); /* XXX */
52
53
int
54
mps_getstr(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
55
{
56
	char			*s = oid->o_data;
57
58
	if (s == NULL)
59
		return (-1);
60
	*elm = ber_add_string(*elm, s);
61
	return (0);
62
}
63
64
int
65
mps_setstr(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
66
{
67
	struct ber_element	*ber = *elm;
68
	char			*s, *v;
69
70
	if ((oid->o_flags & OID_WR) == 0)
71
		return (-1);
72
73
	if (ber->be_class != BER_CLASS_UNIVERSAL ||
74
	    ber->be_type != BER_TYPE_OCTETSTRING)
75
		return (-1);
76
	if (ber_get_string(ber, &s) == -1)
77
		return (-1);
78
	if ((v = (void *)strdup(s)) == NULL)
79
		return (-1);
80
	free(oid->o_data);
81
	oid->o_data = v;
82
	oid->o_val = strlen(v);
83
84
	return (0);
85
}
86
87
int
88
mps_getint(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
89
{
90
	*elm = ber_add_integer(*elm, oid->o_val);
91
	return (0);
92
}
93
94
int
95
mps_setint(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
96
{
97
	long long	 i;
98
99
	if (ber_get_integer(*elm, &i) == -1)
100
		return (-1);
101
	oid->o_val = i;
102
103
	return (0);
104
}
105
106
int
107
mps_getts(struct oid *oid, struct ber_oid *o, struct ber_element **elm)
108
{
109
	*elm = ber_add_integer(*elm, oid->o_val);
110
	ber_set_header(*elm, BER_CLASS_APPLICATION, SNMP_T_TIMETICKS);
111
	return (0);
112
}
113
114
int
115
mps_getreq(struct snmp_message *msg, struct ber_element *root,
116
    struct ber_oid *o, u_int sm_version)
117
{
118
	struct ber_element	*elm = root;
119
	struct oid		 key, *value;
120
	unsigned long		 error_type = 0;	/* noSuchObject */
121
122
	if (o->bo_n > BER_MAX_OID_LEN)
123
		return (-1);
124
	bzero(&key, sizeof(key));
125
	bcopy(o, &key.o_id, sizeof(struct ber_oid));
126
	smi_oidlen(&key.o_id);	/* Strip off any trailing .0. */
127
	value = smi_find(&key);
128
	if (value == NULL)
129
		goto fail;
130
131
	if (OID_NOTSET(value))
132
		goto fail;
133
134
	if (value->o_flags & OID_REGISTERED) {
135
		struct agentx_pdu	*pdu;
136
137
		if ((pdu = snmp_agentx_get_pdu((struct snmp_oid *)o, 1)) == NULL)
138
			return (-1);
139
		pdu->cookie = msg;
140
		if (snmp_agentx_send(value->o_session->handle, pdu) == -1)
141
			return (-1);
142
143
		control_event_add(value->o_session,
144
		    value->o_session->handle->fd, EV_WRITE, NULL);
145
		return (1);
146
	}
147
148
	if (value->o_get == NULL)
149
		goto fail;
150
151
	if (value->o_oidlen == o->bo_n) {
152
		/* No instance identifier specified. */
153
		error_type = 1;	/* noSuchInstance */
154
		goto fail;
155
	}
156
157
	if ((value->o_flags & OID_TABLE) == 0)
158
		elm = ber_add_oid(elm, o);
159
	if (value->o_get(value, o, &elm) != 0)
160
		goto fail;
161
162
	return (0);
163
164
fail:
165
	if (sm_version == 0)
166
		return (-1);
167
168
	/* Set SNMPv2 extended error response. */
169
	elm = ber_add_oid(elm, o);
170
	elm = ber_add_null(elm);
171
	ber_set_header(elm, BER_CLASS_CONTEXT, error_type);
172
	return (0);
173
}
174
175
int
176
mps_setreq(struct snmp_message *msg, struct ber_element *ber,
177
    struct ber_oid *o)
178
{
179
	struct oid		 key, *value;
180
181
	smi_oidlen(o);
182
	if (o->bo_n > BER_MAX_OID_LEN)
183
		return (-1);
184
	bzero(&key, sizeof(key));
185
	bcopy(o, &key.o_id, sizeof(struct ber_oid));
186
	value = smi_find(&key);
187
	if (value == NULL)
188
		return (-1);
189
	if ((value->o_flags & OID_WR) == 0 ||
190
	    value->o_set == NULL)
191
		return (-1);
192
	return (value->o_set(value, o, &ber));
193
}
194
195
int
196
mps_getnextreq(struct snmp_message *msg, struct ber_element *root,
197
    struct ber_oid *o)
198
{
199
	struct oid		*next = NULL;
200
	struct ber_element	*ber = root;
201
	struct oid		 key, *value;
202
	int			 ret;
203
	struct ber_oid		 no;
204
	unsigned long		 error_type = 0; 	/* noSuchObject */
205
206
	if (o->bo_n > BER_MAX_OID_LEN)
207
		return (-1);
208
	bzero(&key, sizeof(key));
209
	bcopy(o, &key.o_id, sizeof(struct ber_oid));
210
	smi_oidlen(&key.o_id);	/* Strip off any trailing .0. */
211
	value = smi_find(&key);
212
	if (value == NULL)
213
		goto fail;
214
215
	if (value->o_flags & OID_REGISTERED) {
216
		struct agentx_pdu	*pdu;
217
218
		if ((pdu = snmp_agentx_getnext_pdu((struct snmp_oid *)o, 1)) == NULL)
219
			return (-1);
220
		pdu->cookie = msg;
221
		if (snmp_agentx_send(value->o_session->handle, pdu) == -1)
222
			return (-1);
223
224
		control_event_add(value->o_session,
225
		    value->o_session->handle->fd, EV_WRITE, NULL);
226
		return (1);
227
	}
228
229
	if (value->o_flags & OID_TABLE) {
230
		/* Get the next table row for this column */
231
		if (mps_table(value, o, &no) != NULL) {
232
			bcopy(&no, o, sizeof(*o));
233
			ret = value->o_get(value, o, &ber);
234
		} else
235
			ret = 1;
236
		switch (ret) {
237
		case 0:
238
			return (0);
239
		case -1:
240
			goto fail;
241
		case 1:	/* end-of-rows */
242
			break;
243
		}
244
	} else if (o->bo_n == value->o_oidlen && value->o_get != NULL) {
245
		next = value;
246
		goto appendzero;
247
	}
248
249
 getnext:
250
	for (next = value; next != NULL;) {
251
		next = smi_next(next);
252
		if (next == NULL)
253
			break;
254
		if (!OID_NOTSET(next) && next->o_get != NULL)
255
			break;
256
	}
257
	if (next == NULL || next->o_get == NULL)
258
		goto fail;
259
260
	if (next->o_flags & OID_TABLE) {
261
		/* Get the next table row for this column */
262
		if (mps_table(next, o, &no) == NULL) {
263
			value = next;
264
			goto getnext;
265
		}
266
		bcopy(&no, o, sizeof(*o));
267
		if ((ret = next->o_get(next, o, &ber)) != 0) {
268
			if (ret == 1) {
269
				value = next;
270
				goto getnext;
271
			}
272
			goto fail;
273
		}
274
	} else {
275
		bcopy(&next->o_id, o, sizeof(*o));
276
 appendzero:
277
		/* No instance identifier specified. Append .0. */
278
		if (o->bo_n + 1 > BER_MAX_OID_LEN)
279
			goto fail;
280
		ber = ber_add_noid(ber, o, ++o->bo_n);
281
		if ((ret = next->o_get(next, o, &ber)) != 0)
282
			goto fail;
283
	}
284
285
	return (0);
286
287
fail:
288
	if (msg->sm_version == 0)
289
		return (-1);
290
291
	/* Set SNMPv2 extended error response. */
292
	ber = ber_add_oid(ber, o);
293
	ber = ber_add_null(ber);
294
	ber_set_header(ber, BER_CLASS_CONTEXT, error_type);
295
	return (0);
296
}
297
298
int
299
mps_getbulkreq(struct snmp_message *msg, struct ber_element **root,
300
    struct ber_element **end, struct ber_oid *o, int max)
301
{
302
	struct ber_element *c, *d, *e;
303
	size_t len;
304
	int j, ret;
305
306
	j = max;
307
	c = *root;
308
	*end = NULL;
309
310
	for (d = NULL, len = 0; j > 0; j--) {
311
		e = ber_add_sequence(NULL);
312
		if (c == NULL)
313
			c = e;
314
		ret = mps_getnextreq(msg, e, o);
315
		if (ret == 1) {
316
			*root = c;
317
			return (1);
318
		}
319
		if (ret == -1) {
320
			ber_free_elements(e);
321
			if (d == NULL)
322
				return (-1);
323
			break;
324
		}
325
		len += ber_calc_len(e);
326
		if (len > SNMPD_MAXVARBINDLEN) {
327
			ber_free_elements(e);
328
			break;
329
		}
330
		if (d != NULL)
331
			ber_link_elements(d, e);
332
		d = e;
333
		*end = d;
334
	}
335
336
	*root = c;
337
	return (0);
338
}
339
340
int
341
mps_set(struct ber_oid *o, void *p, long long len)
342
{
343
	struct oid		 key, *value;
344
345
	smi_oidlen(o);
346
	if (o->bo_n > BER_MAX_OID_LEN)
347
		return (-1);
348
	bzero(&key, sizeof(key));
349
	bcopy(o, &key.o_id, sizeof(struct ber_oid));
350
	value = smi_find(&key);
351
	if (value == NULL)
352
		return (-1);
353
	free(value->o_data);
354
	value->o_data = p;
355
	value->o_val = len;
356
357
	return (0);
358
}
359
360
struct ber_oid *
361
mps_table(struct oid *oid, struct ber_oid *o, struct ber_oid *no)
362
{
363
	u_int32_t		 col, idx = 1, id, subid;
364
	struct oid		 a, b;
365
366
	/*
367
	 * This function is being used to iterate through elements
368
	 * in a SMI "table". It is called by the mps_getnext() handler.
369
	 * For example, if the input is sysORIndex, it will return
370
	 * sysORIndex.1. If the input is sysORIndex.2, it will return
371
	 * sysORIndex.3 etc.. The MIB code has to verify the index,
372
	 * see mib_sysor() as an example.
373
	 */
374
375
	if (oid->o_table != NULL)
376
		return (oid->o_table(oid, o, no));
377
378
	bcopy(&oid->o_id, no, sizeof(*no));
379
	id = oid->o_oidlen - 1;
380
	subid = oid->o_oidlen;
381
382
	if (o->bo_n >= oid->o_oidlen) {
383
		/*
384
		 * Compare the requested and the matched OID to see
385
		 * if we have to iterate to the next element.
386
		 */
387
		bzero(&a, sizeof(a));
388
		bcopy(o, &a.o_id, sizeof(struct ber_oid));
389
		bzero(&b, sizeof(b));
390
		bcopy(&oid->o_id, &b.o_id, sizeof(struct ber_oid));
391
		b.o_oidlen--;
392
		b.o_flags |= OID_TABLE;
393
		if (smi_oid_cmp(&a, &b) == 0) {
394
			col = oid->o_oid[id];
395
			if (col > o->bo_id[id])
396
				idx = 1;
397
			else
398
				idx = o->bo_id[subid] + 1;
399
			o->bo_id[subid] = idx;
400
			o->bo_id[id] = col;
401
			bcopy(o, no, sizeof(*no));
402
		}
403
	}
404
405
	/* The root element ends with a 0, iterate to the first element */
406
	if (!no->bo_id[subid])
407
		no->bo_id[subid]++;
408
409
	smi_oidlen(no);
410
411
	return (no);
412
}
413
414
void
415
mps_encodeinaddr(struct ber_oid *o, struct in_addr *addr, int offset)
416
{
417
	u_int32_t	 a, i;
418
419
	o->bo_n = offset;
420
	if (addr != NULL) {
421
		a = htole32(addr->s_addr);
422
		o->bo_id[o->bo_n++] = a & 0xff;
423
		o->bo_id[o->bo_n++] = (a >> 8) & 0xff;
424
		o->bo_id[o->bo_n++] = (a >> 16) & 0xff;
425
		o->bo_id[o->bo_n++] = (a >> 24) & 0xff;
426
	} else {
427
		/* Create an invalid "last address" marker (5 bytes) */
428
		for (i = 0; i < 5; i++)
429
			o->bo_id[o->bo_n++] = 0xff;
430
	}
431
}
432
433
int
434
mps_decodeinaddr(struct ber_oid *o, struct in_addr *addr, int offset)
435
{
436
	u_int32_t	 a;
437
438
	a = ((o->bo_id[offset] & 0xff)) |
439
	    ((o->bo_id[offset + 1] & 0xff) << 8) |
440
	    ((o->bo_id[offset + 2] & 0xff) << 16) |
441
	    ((o->bo_id[offset + 3] & 0xff) << 24);
442
	addr->s_addr = letoh32(a);
443
444
	/* Detect invalid address */
445
	if ((o->bo_n - offset) > 4)
446
		return (-1);
447
448
	return (0);
449
}