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