xref: /freebsd/contrib/bsnmp/snmpd/action.c (revision 6af83ee0d2941d18880b6aaa2b4facd1d30c6106)
1 /*
2  * Copyright (c) 2001-2003
3  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4  *	All rights reserved.
5  *
6  * Author: Harti Brandt <harti@freebsd.org>
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $Begemot: bsnmp/snmpd/action.c,v 1.58 2004/08/06 08:47:09 brandt Exp $
30  *
31  * Variable access for SNMPd
32  */
33 #include <sys/types.h>
34 #include <sys/sysctl.h>
35 #include <sys/un.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38 #include <stdarg.h>
39 #include <string.h>
40 #include <ctype.h>
41 #include <syslog.h>
42 
43 #include "snmpmod.h"
44 #include "snmpd.h"
45 #include "tree.h"
46 #include "oid.h"
47 
48 static const struct asn_oid
49 	oid_begemotSnmpdModuleTable = OIDX_begemotSnmpdModuleTable;
50 
51 /*
52  * Get a string value from the KERN sysctl subtree.
53  */
54 static char *
55 act_getkernstring(int id)
56 {
57 	int mib[2];
58 	size_t len;
59 	char *string;
60 
61 	mib[0] = CTL_KERN;
62 	mib[1] = id;
63 	if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0)
64 		return (NULL);
65 	if ((string = malloc(len)) == NULL)
66 		return (NULL);
67 	if (sysctl(mib, 2, string, &len, NULL, 0) != 0) {
68 		free(string);
69 		return (NULL);
70 	}
71 	return (string);
72 }
73 
74 /*
75  * Get an integer value from the KERN sysctl subtree.
76  */
77 static char *
78 act_getkernint(int id)
79 {
80 	int mib[2];
81 	size_t len;
82 	u_long value;
83 	char *string;
84 
85 	mib[0] = CTL_KERN;
86 	mib[1] = id;
87 	len = sizeof(value);
88 	if (sysctl(mib, 2, &value, &len, NULL, 0) != 0)
89 		return (NULL);
90 
91 	if ((string = malloc(20)) == NULL)
92 		return (NULL);
93 	sprintf(string, "%lu", value);
94 	return (string);
95 }
96 
97 /*
98  * Initialize global variables of the system group.
99  */
100 int
101 init_actvals(void)
102 {
103 	char *v[4];
104 	u_int i;
105 	size_t len;
106 
107 	if ((systemg.name = act_getkernstring(KERN_HOSTNAME)) == NULL)
108 		return (-1);
109 
110 	for (i = 0; i < 4; i++)
111 		v[1] = NULL;
112 
113 	if ((v[0] = act_getkernstring(KERN_HOSTNAME)) == NULL)
114 		goto err;
115 	if ((v[1] = act_getkernint(KERN_HOSTID)) == NULL)
116 		goto err;
117 	if ((v[2] = act_getkernstring(KERN_OSTYPE)) == NULL)
118 		goto err;
119 	if ((v[3] = act_getkernstring(KERN_OSRELEASE)) == NULL)
120 		goto err;
121 
122 	for (i = 0, len = 0; i < 4; i++)
123 		len += strlen(v[i]) + 1;
124 
125 	if ((systemg.descr = malloc(len)) == NULL)
126 		goto err;
127 	sprintf(systemg.descr, "%s %s %s %s", v[0], v[1], v[2], v[3]);
128 
129 	return (0);
130 
131   err:
132 	for (i = 0; i < 4; i++)
133 		if (v[i] != NULL)
134 			free(v[i]);
135 	return (-1);
136 }
137 
138 
139 
140 /*************************************************************
141  *
142  * System group
143  */
144 int
145 op_system_group(struct snmp_context *ctx, struct snmp_value *value,
146     u_int sub, u_int iidx __unused, enum snmp_op op)
147 {
148 	asn_subid_t which = value->var.subs[sub - 1];
149 
150 	switch (op) {
151 
152 	  case SNMP_OP_GETNEXT:
153 		abort();
154 
155 	  case SNMP_OP_GET:
156 		break;
157 
158 	  case SNMP_OP_SET:
159 		switch (which) {
160 
161 		  case LEAF_sysDescr:
162 			if (community != COMM_INITIALIZE)
163 				return (SNMP_ERR_NOT_WRITEABLE);
164 			return (string_save(value, ctx, -1, &systemg.descr));
165 
166 		  case LEAF_sysObjectId:
167 			if (community != COMM_INITIALIZE)
168 				return (SNMP_ERR_NOT_WRITEABLE);
169 			return (oid_save(value, ctx, &systemg.object_id));
170 
171 		  case LEAF_sysContact:
172 			return (string_save(value, ctx, -1, &systemg.contact));
173 
174 		  case LEAF_sysName:
175 			return (string_save(value, ctx, -1, &systemg.name));
176 
177 		  case LEAF_sysLocation:
178 			return (string_save(value, ctx, -1, &systemg.location));
179 		}
180 		return (SNMP_ERR_NO_CREATION);
181 
182 	  case SNMP_OP_ROLLBACK:
183 		switch (which) {
184 
185 		  case LEAF_sysDescr:
186 			string_rollback(ctx, &systemg.descr);
187 			return (SNMP_ERR_NOERROR);
188 		  case LEAF_sysObjectId:
189 			oid_rollback(ctx, &systemg.object_id);
190 			return (SNMP_ERR_NOERROR);
191 		  case LEAF_sysContact:
192 			string_rollback(ctx, &systemg.contact);
193 			return (SNMP_ERR_NOERROR);
194 		  case LEAF_sysName:
195 			string_rollback(ctx, &systemg.name);
196 			return (SNMP_ERR_NOERROR);
197 		  case LEAF_sysLocation:
198 			string_rollback(ctx, &systemg.location);
199 			return (SNMP_ERR_NOERROR);
200 		}
201 		abort();
202 
203 	  case SNMP_OP_COMMIT:
204 		switch (which) {
205 
206 		  case LEAF_sysDescr:
207 			string_commit(ctx);
208 			return (SNMP_ERR_NOERROR);
209 		  case LEAF_sysObjectId:
210 			oid_commit(ctx);
211 			return (SNMP_ERR_NOERROR);
212 		  case LEAF_sysContact:
213 			string_commit(ctx);
214 			return (SNMP_ERR_NOERROR);
215 		  case LEAF_sysName:
216 			string_commit(ctx);
217 			return (SNMP_ERR_NOERROR);
218 		  case LEAF_sysLocation:
219 			string_commit(ctx);
220 			return (SNMP_ERR_NOERROR);
221 		}
222 		abort();
223 	}
224 
225 	/*
226 	 * Come here for GET.
227 	 */
228 	switch (which) {
229 
230 	  case LEAF_sysDescr:
231 		return (string_get(value, systemg.descr, -1));
232 	  case LEAF_sysObjectId:
233 		return (oid_get(value, &systemg.object_id));
234 	  case LEAF_sysUpTime:
235 		value->v.uint32 = get_ticks() - start_tick;
236 		break;
237 	  case LEAF_sysContact:
238 		return (string_get(value, systemg.contact, -1));
239 	  case LEAF_sysName:
240 		return (string_get(value, systemg.name, -1));
241 	  case LEAF_sysLocation:
242 		return (string_get(value, systemg.location, -1));
243 	  case LEAF_sysServices:
244 		value->v.integer = systemg.services;
245 		break;
246 	  case LEAF_sysORLastChange:
247 		value->v.uint32 = systemg.or_last_change;
248 		break;
249 	}
250 	return (SNMP_ERR_NOERROR);
251 }
252 
253 /*************************************************************
254  *
255  * Debug group
256  */
257 int
258 op_debug(struct snmp_context *ctx, struct snmp_value *value, u_int sub,
259     u_int iidx __unused, enum snmp_op op)
260 {
261 	asn_subid_t which = value->var.subs[sub - 1];
262 
263 	switch (op) {
264 
265 	  case SNMP_OP_GETNEXT:
266 		abort();
267 
268 	  case SNMP_OP_GET:
269 		switch (which) {
270 
271 		  case LEAF_begemotSnmpdDebugDumpPdus:
272 			value->v.integer = TRUTH_MK(debug.dump_pdus);
273 			break;
274 
275 		  case LEAF_begemotSnmpdDebugSnmpTrace:
276 			value->v.uint32 = snmp_trace;
277 			break;
278 
279 		  case LEAF_begemotSnmpdDebugSyslogPri:
280 			value->v.integer = debug.logpri;
281 			break;
282 		}
283 		return (SNMP_ERR_NOERROR);
284 
285 	  case SNMP_OP_SET:
286 		switch (which) {
287 
288 		  case LEAF_begemotSnmpdDebugDumpPdus:
289 			if (!TRUTH_OK(value->v.integer))
290 				return (SNMP_ERR_WRONG_VALUE);
291 			ctx->scratch->int1 = debug.dump_pdus;
292 			debug.dump_pdus = TRUTH_GET(value->v.integer);
293 			return (SNMP_ERR_NOERROR);
294 
295 		  case LEAF_begemotSnmpdDebugSnmpTrace:
296 			ctx->scratch->int1 = snmp_trace;
297 			snmp_trace = value->v.uint32;
298 			return (SNMP_ERR_NOERROR);
299 
300 		  case LEAF_begemotSnmpdDebugSyslogPri:
301 			if (value->v.integer < 0 || value->v.integer > 8)
302 				return (SNMP_ERR_WRONG_VALUE);
303 			ctx->scratch->int1 = debug.logpri;
304 			debug.logpri = (u_int)value->v.integer;
305 			return (SNMP_ERR_NOERROR);
306 		}
307 		return (SNMP_ERR_NO_CREATION);
308 
309 	  case SNMP_OP_ROLLBACK:
310 		switch (which) {
311 
312 		  case LEAF_begemotSnmpdDebugDumpPdus:
313 			debug.dump_pdus = ctx->scratch->int1;
314 			return (SNMP_ERR_NOERROR);
315 
316 		  case LEAF_begemotSnmpdDebugSnmpTrace:
317 			snmp_trace = ctx->scratch->int1;
318 			return (SNMP_ERR_NOERROR);
319 
320 		  case LEAF_begemotSnmpdDebugSyslogPri:
321 			debug.logpri = ctx->scratch->int1;
322 			return (SNMP_ERR_NOERROR);
323 		}
324 		abort();
325 
326 	  case SNMP_OP_COMMIT:
327 		switch (which) {
328 
329 		  case LEAF_begemotSnmpdDebugDumpPdus:
330 		  case LEAF_begemotSnmpdDebugSnmpTrace:
331 			return (SNMP_ERR_NOERROR);
332 
333 		  case LEAF_begemotSnmpdDebugSyslogPri:
334 			if (debug.logpri == 0)
335 				setlogmask(0);
336 			else
337 				setlogmask(LOG_UPTO(debug.logpri - 1));
338 			return (SNMP_ERR_NOERROR);
339 		}
340 		abort();
341 	}
342 	abort();
343 }
344 
345 /*************************************************************
346  *
347  * OR Table
348  */
349 int
350 op_or_table(struct snmp_context *ctx __unused, struct snmp_value *value,
351     u_int sub, u_int iidx __unused, enum snmp_op op)
352 {
353 	struct objres *objres;
354 
355 	switch (op) {
356 
357 	  case SNMP_OP_GETNEXT:
358 		if ((objres = NEXT_OBJECT_INT(&objres_list, &value->var, sub))
359 		    == NULL)
360 			return (SNMP_ERR_NOSUCHNAME);
361 		value->var.subs[sub] = objres->index;
362 		value->var.len = sub + 1;
363 		break;
364 
365 	  case SNMP_OP_GET:
366 		if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub))
367 		    == NULL)
368 			return (SNMP_ERR_NOSUCHNAME);
369 		break;
370 
371 	  case SNMP_OP_SET:
372 		if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub))
373 		    == NULL)
374 			return (SNMP_ERR_NO_CREATION);
375 		return (SNMP_ERR_NOT_WRITEABLE);
376 
377 	  case SNMP_OP_ROLLBACK:
378 	  case SNMP_OP_COMMIT:
379 	  default:
380 		abort();
381 	}
382 
383 	/*
384 	 * Come here for GET, GETNEXT.
385 	 */
386 	switch (value->var.subs[sub - 1]) {
387 
388 	  case LEAF_sysORID:
389 		value->v.oid = objres->oid;
390 		break;
391 
392 	  case LEAF_sysORDescr:
393 		return (string_get(value, objres->descr, -1));
394 
395 	  case LEAF_sysORUpTime:
396 		value->v.uint32 = objres->uptime;
397 		break;
398 	}
399 	return (SNMP_ERR_NOERROR);
400 }
401 
402 /*************************************************************
403  *
404  * mib-2 snmp
405  */
406 int
407 op_snmp(struct snmp_context *ctx, struct snmp_value *value,
408     u_int sub, u_int iidx __unused, enum snmp_op op)
409 {
410 	switch (op) {
411 
412 	  case SNMP_OP_GETNEXT:
413 		abort();
414 
415 	  case SNMP_OP_GET:
416 		switch (value->var.subs[sub - 1]) {
417 
418 		  case LEAF_snmpInPkts:
419 			value->v.uint32 = snmpd_stats.inPkts;
420 			break;
421 
422 		  case LEAF_snmpInBadVersions:
423 			value->v.uint32 = snmpd_stats.inBadVersions;
424 			break;
425 
426 		  case LEAF_snmpInBadCommunityNames:
427 			value->v.uint32 = snmpd_stats.inBadCommunityNames;
428 			break;
429 
430 		  case LEAF_snmpInBadCommunityUses:
431 			value->v.uint32 = snmpd_stats.inBadCommunityUses;
432 			break;
433 
434 		  case LEAF_snmpInASNParseErrs:
435 			value->v.uint32 = snmpd_stats.inASNParseErrs;
436 			break;
437 
438 		  case LEAF_snmpEnableAuthenTraps:
439 			value->v.integer = TRUTH_MK(snmpd.auth_traps);
440 			break;
441 
442 		  case LEAF_snmpSilentDrops:
443 			value->v.uint32 = snmpd_stats.silentDrops;
444 			break;
445 
446 		  case LEAF_snmpProxyDrops:
447 			value->v.uint32 = snmpd_stats.proxyDrops;
448 			break;
449 
450 		  default:
451 			return (SNMP_ERR_NOSUCHNAME);
452 
453 		}
454 		return (SNMP_ERR_NOERROR);
455 
456 	  case SNMP_OP_SET:
457 		switch (value->var.subs[sub - 1]) {
458 		  case LEAF_snmpEnableAuthenTraps:
459 			if (!TRUTH_OK(value->v.integer))
460 				return (SNMP_ERR_WRONG_VALUE);
461 			ctx->scratch->int1 = value->v.integer;
462 			snmpd.auth_traps = TRUTH_GET(value->v.integer);
463 			return (SNMP_ERR_NOERROR);
464 		}
465 		abort();
466 
467 	  case SNMP_OP_ROLLBACK:
468 		switch (value->var.subs[sub - 1]) {
469 		  case LEAF_snmpEnableAuthenTraps:
470 			snmpd.auth_traps = ctx->scratch->int1;
471 			return (SNMP_ERR_NOERROR);
472 		}
473 		abort();
474 
475 	  case SNMP_OP_COMMIT:
476 		switch (value->var.subs[sub - 1]) {
477 		  case LEAF_snmpEnableAuthenTraps:
478 			return (SNMP_ERR_NOERROR);
479 		}
480 		abort();
481 	}
482 	abort();
483 }
484 
485 /*************************************************************
486  *
487  * SNMPd statistics group
488  */
489 int
490 op_snmpd_stats(struct snmp_context *ctx __unused, struct snmp_value *value,
491     u_int sub, u_int iidx __unused, enum snmp_op op)
492 {
493 	switch (op) {
494 
495 	  case SNMP_OP_GET:
496 		switch (value->var.subs[sub - 1]) {
497 
498 		  case LEAF_begemotSnmpdStatsNoRxBufs:
499 			value->v.uint32 = snmpd_stats.noRxbuf;
500 			break;
501 
502 		  case LEAF_begemotSnmpdStatsNoTxBufs:
503 			value->v.uint32 = snmpd_stats.noTxbuf;
504 			break;
505 
506 		  case LEAF_begemotSnmpdStatsInTooLongPkts:
507 			value->v.uint32 = snmpd_stats.inTooLong;
508 			break;
509 
510 		  case LEAF_begemotSnmpdStatsInBadPduTypes:
511 			value->v.uint32 = snmpd_stats.inBadPduTypes;
512 			break;
513 
514 		  default:
515 			return (SNMP_ERR_NOSUCHNAME);
516 		}
517 		return (SNMP_ERR_NOERROR);
518 
519 	  case SNMP_OP_SET:
520 	  case SNMP_OP_ROLLBACK:
521 	  case SNMP_OP_COMMIT:
522 	  case SNMP_OP_GETNEXT:
523 		abort();
524 	}
525 	abort();
526 }
527 
528 /*
529  * SNMPd configuration scalars
530  */
531 int
532 op_snmpd_config(struct snmp_context *ctx, struct snmp_value *value,
533     u_int sub, u_int iidx __unused, enum snmp_op op)
534 {
535 	asn_subid_t which = value->var.subs[sub - 1];
536 
537 	switch (op) {
538 
539 	  case SNMP_OP_GETNEXT:
540 		abort();
541 
542 	  case SNMP_OP_GET:
543 		switch (which) {
544 
545 		  case LEAF_begemotSnmpdTransmitBuffer:
546 			value->v.integer = snmpd.txbuf;
547 			break;
548 		  case LEAF_begemotSnmpdReceiveBuffer:
549 			value->v.integer = snmpd.rxbuf;
550 			break;
551 		  case LEAF_begemotSnmpdCommunityDisable:
552 			value->v.integer = TRUTH_MK(snmpd.comm_dis);
553 			break;
554 		  case LEAF_begemotSnmpdTrap1Addr:
555 			return (ip_get(value, snmpd.trap1addr));
556 		  case LEAF_begemotSnmpdVersionEnable:
557 			value->v.uint32 = snmpd.version_enable;
558 			break;
559 		  default:
560 			return (SNMP_ERR_NOSUCHNAME);
561 		}
562 		return (SNMP_ERR_NOERROR);
563 
564 	  case SNMP_OP_SET:
565 		switch (which) {
566 
567 		  case LEAF_begemotSnmpdTransmitBuffer:
568 			ctx->scratch->int1 = snmpd.txbuf;
569 			if (value->v.integer < 484 ||
570 			    value->v.integer > 65535)
571 				return (SNMP_ERR_WRONG_VALUE);
572 			snmpd.txbuf = value->v.integer;
573 			return (SNMP_ERR_NOERROR);
574 
575 		  case LEAF_begemotSnmpdReceiveBuffer:
576 			ctx->scratch->int1 = snmpd.rxbuf;
577 			if (value->v.integer < 484 ||
578 			    value->v.integer > 65535)
579 				return (SNMP_ERR_WRONG_VALUE);
580 			snmpd.rxbuf = value->v.integer;
581 			return (SNMP_ERR_NOERROR);
582 
583 		  case LEAF_begemotSnmpdCommunityDisable:
584 			ctx->scratch->int1 = snmpd.comm_dis;
585 			if (!TRUTH_OK(value->v.integer))
586 				return (SNMP_ERR_WRONG_VALUE);
587 			if (TRUTH_GET(value->v.integer)) {
588 				snmpd.comm_dis = 1;
589 			} else {
590 				if (snmpd.comm_dis)
591 					return (SNMP_ERR_WRONG_VALUE);
592 			}
593 			return (SNMP_ERR_NOERROR);
594 
595 		  case LEAF_begemotSnmpdTrap1Addr:
596 			return (ip_save(value, ctx, snmpd.trap1addr));
597 
598 		  case LEAF_begemotSnmpdVersionEnable:
599 			if (community != COMM_INITIALIZE)
600 				return (SNMP_ERR_NOT_WRITEABLE);
601 			ctx->scratch->int1 = snmpd.version_enable;
602 			if (value->v.uint32 == 0 ||
603 			    (value->v.uint32 & ~VERS_ENABLE_ALL))
604 				return (SNMP_ERR_WRONG_VALUE);
605 			snmpd.version_enable = value->v.uint32;
606 			return (SNMP_ERR_NOERROR);
607 		}
608 		abort();
609 
610 	  case SNMP_OP_ROLLBACK:
611 		switch (which) {
612 
613 		  case LEAF_begemotSnmpdTransmitBuffer:
614 			snmpd.rxbuf = ctx->scratch->int1;
615 			return (SNMP_ERR_NOERROR);
616 		  case LEAF_begemotSnmpdReceiveBuffer:
617 			snmpd.txbuf = ctx->scratch->int1;
618 			return (SNMP_ERR_NOERROR);
619 		  case LEAF_begemotSnmpdCommunityDisable:
620 			snmpd.comm_dis = ctx->scratch->int1;
621 			return (SNMP_ERR_NOERROR);
622 		  case LEAF_begemotSnmpdTrap1Addr:
623 			ip_rollback(ctx, snmpd.trap1addr);
624 			return (SNMP_ERR_NOERROR);
625 		  case LEAF_begemotSnmpdVersionEnable:
626 			snmpd.version_enable = ctx->scratch->int1;
627 			return (SNMP_ERR_NOERROR);
628 		}
629 		abort();
630 
631 	  case SNMP_OP_COMMIT:
632 		switch (which) {
633 
634 		  case LEAF_begemotSnmpdTransmitBuffer:
635 		  case LEAF_begemotSnmpdReceiveBuffer:
636 		  case LEAF_begemotSnmpdCommunityDisable:
637 			return (SNMP_ERR_NOERROR);
638 		  case LEAF_begemotSnmpdTrap1Addr:
639 			ip_commit(ctx);
640 			return (SNMP_ERR_NOERROR);
641 		  case LEAF_begemotSnmpdVersionEnable:
642 			return (SNMP_ERR_NOERROR);
643 		}
644 		abort();
645 	}
646 	abort();
647 }
648 
649 /*
650  * The community table
651  */
652 int
653 op_community(struct snmp_context *ctx, struct snmp_value *value,
654     u_int sub, u_int iidx __unused, enum snmp_op op)
655 {
656 	asn_subid_t which = value->var.subs[sub - 1];
657 	struct community *c;
658 
659 	switch (op) {
660 
661 	  case SNMP_OP_GETNEXT:
662 		if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
663 		    (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
664 			return (SNMP_ERR_NOSUCHNAME);
665 		index_append(&value->var, sub, &c->index);
666 		break;
667 
668 	  case SNMP_OP_GET:
669 		if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
670 		    (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
671 			return (SNMP_ERR_NOSUCHNAME);
672 		break;
673 
674 	  case SNMP_OP_SET:
675 		if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
676 		    (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
677 			return (SNMP_ERR_NO_CREATION);
678 		if (which != LEAF_begemotSnmpdCommunityString)
679 			return (SNMP_ERR_NOT_WRITEABLE);
680 		return (string_save(value, ctx, -1, &c->string));
681 
682 	  case SNMP_OP_ROLLBACK:
683 		if (which == LEAF_begemotSnmpdCommunityString) {
684 			if ((c = FIND_OBJECT_OID(&community_list, &value->var,
685 			    sub)) == NULL)
686 				string_free(ctx);
687 			else
688 				string_rollback(ctx, &c->string);
689 			return (SNMP_ERR_NOERROR);
690 		}
691 		abort();
692 
693 	  case SNMP_OP_COMMIT:
694 		if (which == LEAF_begemotSnmpdCommunityString) {
695 			if ((c = FIND_OBJECT_OID(&community_list, &value->var,
696 			    sub)) == NULL)
697 				string_free(ctx);
698 			else
699 				string_commit(ctx);
700 			return (SNMP_ERR_NOERROR);
701 		}
702 		abort();
703 
704 	  default:
705 		abort();
706 	}
707 
708 	switch (which) {
709 
710 	  case LEAF_begemotSnmpdCommunityString:
711 		return (string_get(value, c->string, -1));
712 
713 	  case LEAF_begemotSnmpdCommunityDescr:
714 		return (string_get(value, c->descr, -1));
715 	}
716 	abort();
717 }
718 
719 /*
720  * Module table.
721  */
722 struct module_dep {
723 	struct snmp_dependency dep;
724 	u_char	section[LM_SECTION_MAX + 1];
725 	u_char	*path;
726 	struct lmodule *m;
727 };
728 
729 static int
730 dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep,
731     enum snmp_depop op)
732 {
733 	struct module_dep *mdep = (struct module_dep *)(void *)dep;
734 
735 	switch (op) {
736 
737 	  case SNMP_DEPOP_COMMIT:
738 		if (mdep->path == NULL) {
739 			/* unload - find the module */
740 			TAILQ_FOREACH(mdep->m, &lmodules, link)
741 				if (strcmp(mdep->m->section,
742 				    mdep->section) == 0)
743 					break;
744 			if (mdep->m == NULL)
745 				/* no such module - that's ok */
746 				return (SNMP_ERR_NOERROR);
747 
748 			/* handle unloading in the finalizer */
749 			return (SNMP_ERR_NOERROR);
750 		}
751 		/* load */
752 		if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) {
753 			/* could not load */
754 			return (SNMP_ERR_RES_UNAVAIL);
755 		}
756 		/* start in finalizer */
757 		return (SNMP_ERR_NOERROR);
758 
759 	  case SNMP_DEPOP_ROLLBACK:
760 		if (mdep->path == NULL) {
761 			/* rollback unload - the finalizer takes care */
762 			return (SNMP_ERR_NOERROR);
763 		}
764 		/* rollback load */
765 		lm_unload(mdep->m);
766 		return (SNMP_ERR_NOERROR);
767 
768 	  case SNMP_DEPOP_FINISH:
769 		if (mdep->path == NULL) {
770 			if (mdep->m != NULL && ctx->code == SNMP_RET_OK)
771 				lm_unload(mdep->m);
772 		} else {
773 			if (mdep->m != NULL && ctx->code == SNMP_RET_OK &&
774 			    community != COMM_INITIALIZE)
775 				lm_start(mdep->m);
776 			free(mdep->path);
777 		}
778 		return (SNMP_ERR_NOERROR);
779 	}
780 	abort();
781 }
782 
783 int
784 op_modules(struct snmp_context *ctx, struct snmp_value *value,
785     u_int sub, u_int iidx, enum snmp_op op)
786 {
787 	asn_subid_t which = value->var.subs[sub - 1];
788 	struct lmodule *m;
789 	u_char *section, *ptr;
790 	size_t seclen;
791 	struct module_dep *mdep;
792 	struct asn_oid idx;
793 
794 	switch (op) {
795 
796 	  case SNMP_OP_GETNEXT:
797 		if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
798 			return (SNMP_ERR_NOSUCHNAME);
799 		index_append(&value->var, sub, &m->index);
800 		break;
801 
802 	  case SNMP_OP_GET:
803 		if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
804 			return (SNMP_ERR_NOSUCHNAME);
805 		break;
806 
807 	  case SNMP_OP_SET:
808 		m = FIND_OBJECT_OID(&lmodules, &value->var, sub);
809 		if (which != LEAF_begemotSnmpdModulePath) {
810 			if (m == NULL)
811 				return (SNMP_ERR_NO_CREATION);
812 			return (SNMP_ERR_NOT_WRITEABLE);
813 		}
814 
815 		/* the errors in the next few statements can only happen when
816 		 * m is NULL, hence the NO_CREATION error. */
817 		if (index_decode(&value->var, sub, iidx,
818 		    &section, &seclen))
819 			return (SNMP_ERR_NO_CREATION);
820 
821 		/* check the section name */
822 		if (seclen > LM_SECTION_MAX || seclen == 0) {
823 			free(section);
824 			return (SNMP_ERR_NO_CREATION);
825 		}
826 		for (ptr = section; ptr < section + seclen; ptr++)
827 			if (!isascii(*ptr) || !isalnum(*ptr)) {
828 				free(section);
829 				return (SNMP_ERR_NO_CREATION);
830 			}
831 		if (!isalpha(section[0])) {
832 			free(section);
833 			return (SNMP_ERR_NO_CREATION);
834 		}
835 
836 		/* check the path */
837 		for (ptr = value->v.octetstring.octets;
838 		     ptr < value->v.octetstring.octets + value->v.octetstring.len;
839 		     ptr++) {
840 			if (*ptr == '\0') {
841 				free(section);
842 				return (SNMP_ERR_WRONG_VALUE);
843 			}
844 		}
845 
846 		if (m == NULL) {
847 			if (value->v.octetstring.len == 0) {
848 				free(section);
849 				return (SNMP_ERR_INCONS_VALUE);
850 			}
851 		} else {
852 			if (value->v.octetstring.len != 0) {
853 				free(section);
854 				return (SNMP_ERR_INCONS_VALUE);
855 			}
856 		}
857 
858 		asn_slice_oid(&idx, &value->var, sub, value->var.len);
859 
860 		/* so far, so good */
861 		mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx,
862 		    &oid_begemotSnmpdModuleTable, &idx,
863 		    sizeof(*mdep), dep_modules);
864 		if (mdep == NULL) {
865 			free(section);
866 			return (SNMP_ERR_RES_UNAVAIL);
867 		}
868 
869 		if (mdep->section[0] != '\0') {
870 			/* two writes to the same entry - bad */
871 			free(section);
872 			return (SNMP_ERR_INCONS_VALUE);
873 		}
874 
875 		strncpy(mdep->section, section, seclen);
876 		mdep->section[seclen] = '\0';
877 		free(section);
878 
879 		if (value->v.octetstring.len == 0)
880 			mdep->path = NULL;
881 		else {
882 			if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL)
883 				return (SNMP_ERR_RES_UNAVAIL);
884 			strncpy(mdep->path, value->v.octetstring.octets,
885 			    value->v.octetstring.len);
886 			mdep->path[value->v.octetstring.len] = '\0';
887 		}
888 		ctx->scratch->ptr1 = mdep;
889 		return (SNMP_ERR_NOERROR);
890 
891 	  case SNMP_OP_ROLLBACK:
892 	  case SNMP_OP_COMMIT:
893 		return (SNMP_ERR_NOERROR);
894 
895 	  default:
896 		abort();
897 	}
898 
899 	switch (which) {
900 
901 	  case LEAF_begemotSnmpdModulePath:
902 		return (string_get(value, m->path, -1));
903 
904 	  case LEAF_begemotSnmpdModuleComment:
905 		return (string_get(value, m->config->comment, -1));
906 	}
907 	abort();
908 }
909 
910 int
911 op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value,
912     u_int sub, u_int iidx __unused, enum snmp_op op)
913 {
914 	switch (op) {
915 
916 	  case SNMP_OP_GETNEXT:
917 		abort();
918 
919 	  case SNMP_OP_GET:
920 		switch (value->var.subs[sub - 1]) {
921 
922 		  case LEAF_snmpSetSerialNo:
923 			value->v.integer = snmp_serial_no;
924 			break;
925 
926 		  default:
927 			abort();
928 		}
929 		return (SNMP_ERR_NOERROR);
930 
931 	  case SNMP_OP_SET:
932 		switch (value->var.subs[sub - 1]) {
933 
934 		  case LEAF_snmpSetSerialNo:
935 			if (value->v.integer != snmp_serial_no)
936 				return (SNMP_ERR_INCONS_VALUE);
937 			break;
938 
939 		  default:
940 			abort();
941 		}
942 		return (SNMP_ERR_NOERROR);
943 
944 	  case SNMP_OP_ROLLBACK:
945 		return (SNMP_ERR_NOERROR);
946 
947 	  case SNMP_OP_COMMIT:
948 		if (snmp_serial_no++ == 2147483647)
949 			snmp_serial_no = 0;
950 		return (SNMP_ERR_NOERROR);
951 	}
952 	abort();
953 }
954 
955 /*
956  * Transport table
957  */
958 int
959 op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value,
960     u_int sub, u_int iidx, enum snmp_op op)
961 {
962 	asn_subid_t which = value->var.subs[sub - 1];
963 	struct transport *t;
964 	u_char *tname, *ptr;
965 	size_t tnamelen;
966 
967 	switch (op) {
968 
969 	  case SNMP_OP_GETNEXT:
970 		if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub))
971 		    == NULL)
972 			return (SNMP_ERR_NOSUCHNAME);
973 		index_append(&value->var, sub, &t->index);
974 		break;
975 
976 	  case SNMP_OP_GET:
977 		if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub))
978 		    == NULL)
979 			return (SNMP_ERR_NOSUCHNAME);
980 		break;
981 
982 	  case SNMP_OP_SET:
983 		t = FIND_OBJECT_OID(&transport_list, &value->var, sub);
984 		if (which != LEAF_begemotSnmpdTransportStatus) {
985 			if (t == NULL)
986 				return (SNMP_ERR_NO_CREATION);
987 			return (SNMP_ERR_NOT_WRITEABLE);
988 		}
989 
990 		/* the errors in the next few statements can only happen when
991 		 * t is NULL, hence the NO_CREATION error. */
992 		if (index_decode(&value->var, sub, iidx,
993 		    &tname, &tnamelen))
994 			return (SNMP_ERR_NO_CREATION);
995 
996 		/* check the section name */
997 		if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) {
998 			free(tname);
999 			return (SNMP_ERR_NO_CREATION);
1000 		}
1001 		for (ptr = tname; ptr < tname + tnamelen; ptr++) {
1002 			if (!isascii(*ptr) || !isalnum(*ptr)) {
1003 				free(tname);
1004 				return (SNMP_ERR_NO_CREATION);
1005 			}
1006 		}
1007 
1008 		/* for now */
1009 		return (SNMP_ERR_NOT_WRITEABLE);
1010 
1011 	  case SNMP_OP_ROLLBACK:
1012 	  case SNMP_OP_COMMIT:
1013 		return (SNMP_ERR_NOERROR);
1014 	  default:
1015 		abort();
1016 	}
1017 
1018 	switch (which) {
1019 
1020 	    case LEAF_begemotSnmpdTransportStatus:
1021 		value->v.integer = 1;
1022 		break;
1023 
1024 	    case LEAF_begemotSnmpdTransportOid:
1025 		memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id));
1026 		break;
1027 	}
1028 	return (SNMP_ERR_NOERROR);
1029 }
1030