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