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