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