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