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