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