]> CyberLeo.Net >> Repos - FreeBSD/releng/10.3.git/blob - contrib/bsnmp/snmpd/action.c
- Copy stable/10@296371 to releng/10.3 in preparation for 10.3-RC1
[FreeBSD/releng/10.3.git] / contrib / bsnmp / snmpd / action.c
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 *
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
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
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
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
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
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
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
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
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
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
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
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
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                     &section, &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
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
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
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 }