]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/bsnmp/snmpd/action.c
MFC r368207,368607:
[FreeBSD/stable/10.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         asn_subid_t which = value->var.subs[sub - 1];
755         struct community *c;
756
757         switch (op) {
758
759           case SNMP_OP_GETNEXT:
760                 if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
761                     (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
762                         return (SNMP_ERR_NOSUCHNAME);
763                 index_append(&value->var, sub, &c->index);
764                 break;
765
766           case SNMP_OP_GET:
767                 if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
768                     (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
769                         return (SNMP_ERR_NOSUCHNAME);
770                 break;
771
772           case SNMP_OP_SET:
773                 if ((community != COMM_INITIALIZE && snmpd.comm_dis) ||
774                     (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL)
775                         return (SNMP_ERR_NO_CREATION);
776                 if (which != LEAF_begemotSnmpdCommunityString)
777                         return (SNMP_ERR_NOT_WRITEABLE);
778                 return (string_save(value, ctx, -1, &c->string));
779
780           case SNMP_OP_ROLLBACK:
781                 if (which == LEAF_begemotSnmpdCommunityString) {
782                         if ((c = FIND_OBJECT_OID(&community_list, &value->var,
783                             sub)) == NULL)
784                                 string_free(ctx);
785                         else
786                                 string_rollback(ctx, &c->string);
787                         return (SNMP_ERR_NOERROR);
788                 }
789                 abort();
790
791           case SNMP_OP_COMMIT:
792                 if (which == LEAF_begemotSnmpdCommunityString) {
793                         if ((c = FIND_OBJECT_OID(&community_list, &value->var,
794                             sub)) == NULL)
795                                 string_free(ctx);
796                         else
797                                 string_commit(ctx);
798                         return (SNMP_ERR_NOERROR);
799                 }
800                 abort();
801
802           default:
803                 abort();
804         }
805
806         switch (which) {
807
808           case LEAF_begemotSnmpdCommunityString:
809                 return (string_get(value, c->string, -1));
810
811           case LEAF_begemotSnmpdCommunityDescr:
812                 return (string_get(value, c->descr, -1));
813         }
814         abort();
815 }
816
817 /*
818  * Module table.
819  */
820 struct module_dep {
821         struct snmp_dependency dep;
822         u_char  section[LM_SECTION_MAX + 1];
823         u_char  *path;
824         struct lmodule *m;
825 };
826
827 static int
828 dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep,
829     enum snmp_depop op)
830 {
831         struct module_dep *mdep = (struct module_dep *)(void *)dep;
832
833         switch (op) {
834
835           case SNMP_DEPOP_COMMIT:
836                 if (mdep->path == NULL) {
837                         /* unload - find the module */
838                         TAILQ_FOREACH(mdep->m, &lmodules, link)
839                                 if (strcmp(mdep->m->section,
840                                     mdep->section) == 0)
841                                         break;
842                         if (mdep->m == NULL)
843                                 /* no such module - that's ok */
844                                 return (SNMP_ERR_NOERROR);
845
846                         /* handle unloading in the finalizer */
847                         return (SNMP_ERR_NOERROR);
848                 }
849                 /* load */
850                 if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) {
851                         /* could not load */
852                         return (SNMP_ERR_RES_UNAVAIL);
853                 }
854                 /* start in finalizer */
855                 return (SNMP_ERR_NOERROR);
856
857           case SNMP_DEPOP_ROLLBACK:
858                 if (mdep->path == NULL) {
859                         /* rollback unload - the finalizer takes care */
860                         return (SNMP_ERR_NOERROR);
861                 }
862                 /* rollback load */
863                 lm_unload(mdep->m);
864                 return (SNMP_ERR_NOERROR);
865
866           case SNMP_DEPOP_FINISH:
867                 if (mdep->path == NULL) {
868                         if (mdep->m != NULL && ctx->code == SNMP_RET_OK)
869                                 lm_unload(mdep->m);
870                 } else {
871                         if (mdep->m != NULL && ctx->code == SNMP_RET_OK &&
872                             community != COMM_INITIALIZE)
873                                 lm_start(mdep->m);
874                         free(mdep->path);
875                 }
876                 return (SNMP_ERR_NOERROR);
877         }
878         abort();
879 }
880
881 int
882 op_modules(struct snmp_context *ctx, struct snmp_value *value,
883     u_int sub, u_int iidx, enum snmp_op op)
884 {
885         asn_subid_t which = value->var.subs[sub - 1];
886         struct lmodule *m;
887         u_char *section, *ptr;
888         size_t seclen;
889         struct module_dep *mdep;
890         struct asn_oid idx;
891
892         switch (op) {
893
894           case SNMP_OP_GETNEXT:
895                 if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
896                         return (SNMP_ERR_NOSUCHNAME);
897                 index_append(&value->var, sub, &m->index);
898                 break;
899
900           case SNMP_OP_GET:
901                 if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL)
902                         return (SNMP_ERR_NOSUCHNAME);
903                 break;
904
905           case SNMP_OP_SET:
906                 m = FIND_OBJECT_OID(&lmodules, &value->var, sub);
907                 if (which != LEAF_begemotSnmpdModulePath) {
908                         if (m == NULL)
909                                 return (SNMP_ERR_NO_CREATION);
910                         return (SNMP_ERR_NOT_WRITEABLE);
911                 }
912
913                 /* the errors in the next few statements can only happen when
914                  * m is NULL, hence the NO_CREATION error. */
915                 if (index_decode(&value->var, sub, iidx,
916                     &section, &seclen))
917                         return (SNMP_ERR_NO_CREATION);
918
919                 /* check the section name */
920                 if (seclen > LM_SECTION_MAX || seclen == 0) {
921                         free(section);
922                         return (SNMP_ERR_NO_CREATION);
923                 }
924                 for (ptr = section; ptr < section + seclen; ptr++)
925                         if (!isascii(*ptr) || !isalnum(*ptr)) {
926                                 free(section);
927                                 return (SNMP_ERR_NO_CREATION);
928                         }
929                 if (!isalpha(section[0])) {
930                         free(section);
931                         return (SNMP_ERR_NO_CREATION);
932                 }
933
934                 /* check the path */
935                 for (ptr = value->v.octetstring.octets;
936                      ptr < value->v.octetstring.octets + value->v.octetstring.len;
937                      ptr++) {
938                         if (*ptr == '\0') {
939                                 free(section);
940                                 return (SNMP_ERR_WRONG_VALUE);
941                         }
942                 }
943
944                 if (m == NULL) {
945                         if (value->v.octetstring.len == 0) {
946                                 free(section);
947                                 return (SNMP_ERR_INCONS_VALUE);
948                         }
949                 } else {
950                         if (value->v.octetstring.len != 0) {
951                                 free(section);
952                                 return (SNMP_ERR_INCONS_VALUE);
953                         }
954                 }
955
956                 asn_slice_oid(&idx, &value->var, sub, value->var.len);
957
958                 /* so far, so good */
959                 mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx,
960                     &oid_begemotSnmpdModuleTable, &idx,
961                     sizeof(*mdep), dep_modules);
962                 if (mdep == NULL) {
963                         free(section);
964                         return (SNMP_ERR_RES_UNAVAIL);
965                 }
966
967                 if (mdep->section[0] != '\0') {
968                         /* two writes to the same entry - bad */
969                         free(section);
970                         return (SNMP_ERR_INCONS_VALUE);
971                 }
972
973                 strncpy(mdep->section, section, seclen);
974                 mdep->section[seclen] = '\0';
975                 free(section);
976
977                 if (value->v.octetstring.len == 0)
978                         mdep->path = NULL;
979                 else {
980                         if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL)
981                                 return (SNMP_ERR_RES_UNAVAIL);
982                         strncpy(mdep->path, value->v.octetstring.octets,
983                             value->v.octetstring.len);
984                         mdep->path[value->v.octetstring.len] = '\0';
985                 }
986                 ctx->scratch->ptr1 = mdep;
987                 return (SNMP_ERR_NOERROR);
988
989           case SNMP_OP_ROLLBACK:
990           case SNMP_OP_COMMIT:
991                 return (SNMP_ERR_NOERROR);
992
993           default:
994                 abort();
995         }
996
997         switch (which) {
998
999           case LEAF_begemotSnmpdModulePath:
1000                 return (string_get(value, m->path, -1));
1001
1002           case LEAF_begemotSnmpdModuleComment:
1003                 return (string_get(value, m->config->comment, -1));
1004         }
1005         abort();
1006 }
1007
1008 int
1009 op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value,
1010     u_int sub, u_int iidx __unused, enum snmp_op op)
1011 {
1012         switch (op) {
1013
1014           case SNMP_OP_GETNEXT:
1015                 abort();
1016
1017           case SNMP_OP_GET:
1018                 switch (value->var.subs[sub - 1]) {
1019
1020                   case LEAF_snmpSetSerialNo:
1021                         value->v.integer = snmp_serial_no;
1022                         break;
1023
1024                   default:
1025                         abort();
1026                 }
1027                 return (SNMP_ERR_NOERROR);
1028
1029           case SNMP_OP_SET:
1030                 switch (value->var.subs[sub - 1]) {
1031
1032                   case LEAF_snmpSetSerialNo:
1033                         if (value->v.integer != snmp_serial_no)
1034                                 return (SNMP_ERR_INCONS_VALUE);
1035                         break;
1036
1037                   default:
1038                         abort();
1039                 }
1040                 return (SNMP_ERR_NOERROR);
1041
1042           case SNMP_OP_ROLLBACK:
1043                 return (SNMP_ERR_NOERROR);
1044
1045           case SNMP_OP_COMMIT:
1046                 if (snmp_serial_no++ == 2147483647)
1047                         snmp_serial_no = 0;
1048                 return (SNMP_ERR_NOERROR);
1049         }
1050         abort();
1051 }
1052
1053 /*
1054  * SNMP Engine
1055  */
1056 int
1057 op_snmp_engine(struct snmp_context *ctx __unused, struct snmp_value *value,
1058     u_int sub, u_int iidx __unused, enum snmp_op op)
1059 {
1060         asn_subid_t which = value->var.subs[sub - 1];
1061
1062         switch (op) {
1063         case SNMP_OP_GETNEXT:
1064                 abort();
1065
1066         case SNMP_OP_GET:
1067                 break;
1068
1069         case SNMP_OP_SET:
1070                 if (community != COMM_INITIALIZE)
1071                         return (SNMP_ERR_NOT_WRITEABLE);
1072                 switch (which) {
1073                 case LEAF_snmpEngineID:
1074                         if (value->v.octetstring.len > SNMP_ENGINE_ID_SIZ)
1075                                 return (SNMP_ERR_WRONG_VALUE);
1076                         ctx->scratch->ptr1 = malloc(snmpd_engine.engine_len);
1077                         if (ctx->scratch->ptr1 == NULL)
1078                                 return (SNMP_ERR_GENERR);
1079                         memcpy(ctx->scratch->ptr1, snmpd_engine.engine_id,
1080                             snmpd_engine.engine_len);
1081                         ctx->scratch->int1 = snmpd_engine.engine_len;
1082                         snmpd_engine.engine_len = value->v.octetstring.len;
1083                         memcpy(snmpd_engine.engine_id,
1084                             value->v.octetstring.octets,
1085                             value->v.octetstring.len);
1086                         break;
1087
1088                 case LEAF_snmpEngineMaxMessageSize:
1089                         ctx->scratch->int1 = snmpd_engine.max_msg_size;
1090                         snmpd_engine.max_msg_size = value->v.integer;
1091                         break;
1092
1093                 default:
1094                         return (SNMP_ERR_NOT_WRITEABLE);
1095                 }
1096                 return (SNMP_ERR_NOERROR);
1097
1098         case SNMP_OP_ROLLBACK:
1099                 switch (which) {
1100                 case LEAF_snmpEngineID:
1101                         snmpd_engine.engine_len = ctx->scratch->int1;
1102                         memcpy(snmpd_engine.engine_id, ctx->scratch->ptr1,
1103                             snmpd_engine.engine_len);
1104                         free(ctx->scratch->ptr1);
1105                         break;
1106
1107                 case LEAF_snmpEngineMaxMessageSize:
1108                         snmpd_engine.max_msg_size = ctx->scratch->int1;
1109                         break;
1110
1111                 default:
1112                         abort();
1113                 }
1114                 return (SNMP_ERR_NOERROR);
1115
1116         case SNMP_OP_COMMIT:
1117                 if (which == LEAF_snmpEngineID) {
1118                         if (set_snmpd_engine() < 0) {
1119                                 snmpd_engine.engine_len = ctx->scratch->int1;
1120                                 memcpy(snmpd_engine.engine_id,
1121                                     ctx->scratch->ptr1, ctx->scratch->int1);
1122                         }
1123                         free(ctx->scratch->ptr1);
1124                 }
1125                 return (SNMP_ERR_NOERROR);
1126         }
1127
1128
1129         switch (which) {
1130         case LEAF_snmpEngineID:
1131                 return (string_get(value, snmpd_engine.engine_id,
1132                     snmpd_engine.engine_len));
1133         case LEAF_snmpEngineBoots:
1134                 value->v.integer = snmpd_engine.engine_boots;
1135                 break;
1136         case LEAF_snmpEngineTime:
1137                 update_snmpd_engine_time();
1138                 value->v.integer = snmpd_engine.engine_time;
1139                 break;
1140         case LEAF_snmpEngineMaxMessageSize:
1141                 value->v.integer = snmpd_engine.max_msg_size;
1142                 break;
1143         default:
1144                 return (SNMP_ERR_NOSUCHNAME);
1145         }
1146
1147         return (SNMP_ERR_NOERROR);
1148 }
1149
1150 /*
1151  * Transport table
1152  */
1153 int
1154 op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value,
1155     u_int sub, u_int iidx, enum snmp_op op)
1156 {
1157         asn_subid_t which = value->var.subs[sub - 1];
1158         struct transport *t;
1159         u_char *tname, *ptr;
1160         size_t tnamelen;
1161
1162         switch (op) {
1163
1164           case SNMP_OP_GETNEXT:
1165                 if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub))
1166                     == NULL)
1167                         return (SNMP_ERR_NOSUCHNAME);
1168                 index_append(&value->var, sub, &t->index);
1169                 break;
1170
1171           case SNMP_OP_GET:
1172                 if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub))
1173                     == NULL)
1174                         return (SNMP_ERR_NOSUCHNAME);
1175                 break;
1176
1177           case SNMP_OP_SET:
1178                 t = FIND_OBJECT_OID(&transport_list, &value->var, sub);
1179                 if (which != LEAF_begemotSnmpdTransportStatus) {
1180                         if (t == NULL)
1181                                 return (SNMP_ERR_NO_CREATION);
1182                         return (SNMP_ERR_NOT_WRITEABLE);
1183                 }
1184
1185                 /* the errors in the next few statements can only happen when
1186                  * t is NULL, hence the NO_CREATION error. */
1187                 if (index_decode(&value->var, sub, iidx,
1188                     &tname, &tnamelen))
1189                         return (SNMP_ERR_NO_CREATION);
1190
1191                 /* check the section name */
1192                 if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) {
1193                         free(tname);
1194                         return (SNMP_ERR_NO_CREATION);
1195                 }
1196                 for (ptr = tname; ptr < tname + tnamelen; ptr++) {
1197                         if (!isascii(*ptr) || !isalnum(*ptr)) {
1198                                 free(tname);
1199                                 return (SNMP_ERR_NO_CREATION);
1200                         }
1201                 }
1202
1203                 /* for now */
1204                 return (SNMP_ERR_NOT_WRITEABLE);
1205
1206           case SNMP_OP_ROLLBACK:
1207           case SNMP_OP_COMMIT:
1208                 return (SNMP_ERR_NOERROR);
1209           default:
1210                 abort();
1211         }
1212
1213         switch (which) {
1214
1215             case LEAF_begemotSnmpdTransportStatus:
1216                 value->v.integer = 1;
1217                 break;
1218
1219             case LEAF_begemotSnmpdTransportOid:
1220                 memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id));
1221                 break;
1222         }
1223         return (SNMP_ERR_NOERROR);
1224 }