]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - contrib/bsnmp/snmp_target/target_snmp.c
Add two missing eventhandler.h headers
[FreeBSD/FreeBSD.git] / contrib / bsnmp / snmp_target / target_snmp.c
1 /*-
2  * Copyright (c) 2010,2018 The FreeBSD Foundation
3  * All rights reserved.
4  *
5  * This software was developed by Shteryana Sotirova Shopova under
6  * sponsorship from the FreeBSD Foundation.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  * $FreeBSD$
30  */
31 #include <sys/queue.h>
32 #include <sys/types.h>
33
34 #include <errno.h>
35 #include <stdarg.h>
36 #include <stdlib.h>
37 #include <stdio.h>
38 #include <stdint.h>
39 #include <string.h>
40 #include <syslog.h>
41
42 #include "asn1.h"
43 #include "snmp.h"
44 #include "snmpmod.h"
45
46 #define SNMPTREE_TYPES
47 #include "target_tree.h"
48 #include "target_oid.h"
49
50 static struct lmodule *target_module;
51 /* For the registration. */
52 static const struct asn_oid oid_target = OIDX_snmpTargetMIB;
53 static const struct asn_oid oid_notification = OIDX_snmpNotificationMIB;
54
55 static uint reg_target;
56 static uint reg_notification;
57
58 static int32_t target_lock;
59
60 static const struct asn_oid oid_udp_domain = OIDX_snmpUDPDomain;
61
62 /*
63  * Internal datastructures and forward declarations.
64  */
65 static void             target_append_index(struct asn_oid *, uint,
66     const char *);
67 static int              target_decode_index(const struct asn_oid *, uint,
68     char *);
69 static struct target_address *target_get_address(const struct asn_oid *,
70     uint);
71 static struct target_address *target_get_next_address(const struct asn_oid *,
72     uint);
73 static struct target_param *target_get_param(const struct asn_oid *,
74     uint);
75 static struct target_param *target_get_next_param(const struct asn_oid *,
76     uint);
77 static struct target_notify *target_get_notify(const struct asn_oid *,
78     uint);
79 static struct target_notify *target_get_next_notify(const struct asn_oid *,
80     uint);
81
82 int
83 op_snmp_target(struct snmp_context *ctx __unused, struct snmp_value *val,
84     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
85 {
86         struct snmpd_target_stats *ctx_stats;
87
88         if (val->var.subs[sub - 1] == LEAF_snmpTargetSpinLock) {
89                 switch (op) {
90                 case SNMP_OP_GET:
91                         if (++target_lock == INT32_MAX)
92                                 target_lock = 0;
93                         val->v.integer = target_lock;
94                         break;
95                 case SNMP_OP_GETNEXT:
96                         abort();
97                 case SNMP_OP_SET:
98                         if (val->v.integer != target_lock)
99                                 return (SNMP_ERR_INCONS_VALUE);
100                         break;
101                 case SNMP_OP_ROLLBACK:
102                         /* FALLTHROUGH */
103                 case SNMP_OP_COMMIT:
104                         break;
105                 }
106                 return (SNMP_ERR_NOERROR);
107         } else if (op == SNMP_OP_SET)
108                 return (SNMP_ERR_NOT_WRITEABLE);
109
110         if ((ctx_stats = bsnmpd_get_target_stats()) == NULL)
111                 return (SNMP_ERR_GENERR);
112
113         if (op == SNMP_OP_GET) {
114                 switch (val->var.subs[sub - 1]) {
115                 case LEAF_snmpUnavailableContexts:
116                         val->v.uint32 = ctx_stats->unavail_contexts;
117                         break;
118                 case LEAF_snmpUnknownContexts:
119                         val->v.uint32 = ctx_stats->unknown_contexts;
120                         break;
121                 default:
122                         return (SNMP_ERR_NOSUCHNAME);
123                 }
124                 return (SNMP_ERR_NOERROR);
125         }
126         abort();
127 }
128
129 int
130 op_snmp_target_addrs(struct snmp_context *ctx __unused, struct snmp_value *val,
131     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
132 {
133         char aname[SNMP_ADM_STR32_SIZ];
134         struct target_address *addrs;
135
136         switch (op) {
137         case SNMP_OP_GET:
138                 if ((addrs = target_get_address(&val->var, sub)) == NULL)
139                         return (SNMP_ERR_NOSUCHNAME);
140                 break;
141
142         case SNMP_OP_GETNEXT:
143                 if ((addrs = target_get_next_address(&val->var, sub)) == NULL)
144                         return (SNMP_ERR_NOSUCHNAME);
145                 target_append_index(&val->var, sub, addrs->name);
146                 break;
147
148         case SNMP_OP_SET:
149                 if ((addrs = target_get_address(&val->var, sub)) == NULL &&
150                     (val->var.subs[sub - 1] != LEAF_snmpTargetAddrRowStatus ||
151                     val->v.integer != RowStatus_createAndWait))
152                         return (SNMP_ERR_NOSUCHNAME);
153
154                 if (addrs != NULL) {
155                         if (community != COMM_INITIALIZE &&
156                             addrs->type == StorageType_readOnly)
157                                 return (SNMP_ERR_NOT_WRITEABLE);
158                         if (addrs->status == RowStatus_active &&
159                             val->v.integer != RowStatus_destroy)
160                                 return (SNMP_ERR_INCONS_VALUE);
161                 }
162
163                 switch (val->var.subs[sub - 1]) {
164                 case LEAF_snmpTargetAddrTDomain:
165                         return (SNMP_ERR_INCONS_VALUE);
166                 case LEAF_snmpTargetAddrTAddress:
167                         if (val->v.octetstring.len != SNMP_UDP_ADDR_SIZ)
168                                 return (SNMP_ERR_INCONS_VALUE);
169                         ctx->scratch->ptr1 = malloc(SNMP_UDP_ADDR_SIZ);
170                         if (ctx->scratch->ptr1 == NULL)
171                                 return (SNMP_ERR_GENERR);
172                         memcpy(ctx->scratch->ptr1, addrs->address,
173                             SNMP_UDP_ADDR_SIZ);
174                         memcpy(addrs->address, val->v.octetstring.octets,
175                             SNMP_UDP_ADDR_SIZ);
176                         break;
177
178                 case LEAF_snmpTargetAddrTagList:
179                         if (val->v.octetstring.len >= SNMP_TAG_SIZ)
180                                 return (SNMP_ERR_INCONS_VALUE);
181                         ctx->scratch->int1 = strlen(addrs->taglist) + 1;
182                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
183                         if (ctx->scratch->ptr1 == NULL)
184                                 return (SNMP_ERR_GENERR);
185                         strlcpy(ctx->scratch->ptr1, addrs->taglist,
186                             ctx->scratch->int1);
187                         memcpy(addrs->taglist, val->v.octetstring.octets,
188                             val->v.octetstring.len);
189                         addrs->taglist[val->v.octetstring.len] = '\0';
190                         break;
191
192                 case LEAF_snmpTargetAddrParams:
193                         if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
194                                 return (SNMP_ERR_INCONS_VALUE);
195                         ctx->scratch->int1 = strlen(addrs->paramname) + 1;
196                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
197                         if (ctx->scratch->ptr1 == NULL)
198                                 return (SNMP_ERR_GENERR);
199                         strlcpy(ctx->scratch->ptr1, addrs->paramname,
200                             ctx->scratch->int1);
201                         memcpy(addrs->paramname, val->v.octetstring.octets,
202                             val->v.octetstring.len);
203                         addrs->paramname[val->v.octetstring.len] = '\0';
204                         break;
205
206                 case LEAF_snmpTargetAddrRetryCount:
207                         ctx->scratch->int1 = addrs->retry;
208                         addrs->retry = val->v.integer;
209                         break;
210
211                 case LEAF_snmpTargetAddrTimeout:
212                         ctx->scratch->int1 = addrs->timeout;
213                         addrs->timeout = val->v.integer / 10;
214                         break;
215
216                 case LEAF_snmpTargetAddrStorageType:
217                         return (SNMP_ERR_INCONS_VALUE);
218
219                 case LEAF_snmpTargetAddrRowStatus:
220                         if (addrs != NULL) {
221                                 if (val->v.integer != RowStatus_active &&
222                                     val->v.integer != RowStatus_destroy)
223                                         return (SNMP_ERR_INCONS_VALUE);
224                                 if (val->v.integer == RowStatus_active &&
225                                     (addrs->address[0] == 0 ||
226                                     strlen(addrs->taglist) == 0 ||
227                                     strlen(addrs->paramname) == 0))
228                                         return (SNMP_ERR_INCONS_VALUE);
229                                 ctx->scratch->int1 = addrs->status;
230                                 addrs->status = val->v.integer;
231                                 return (SNMP_ERR_NOERROR);
232                         }
233                         if (val->v.integer != RowStatus_createAndWait ||
234                             target_decode_index(&val->var, sub, aname) < 0)
235                                 return (SNMP_ERR_INCONS_VALUE);
236                         if ((addrs = target_new_address(aname)) == NULL)
237                                 return (SNMP_ERR_GENERR);
238                         addrs->status = RowStatus_destroy;
239                         if (community != COMM_INITIALIZE)
240                                 addrs->type = StorageType_volatile;
241                         else
242                                 addrs->type = StorageType_readOnly;
243                         break;
244                 }
245                 return (SNMP_ERR_NOERROR);
246
247         case SNMP_OP_COMMIT:
248                 switch (val->var.subs[sub - 1]) {
249                 case LEAF_snmpTargetAddrTAddress:
250                 case LEAF_snmpTargetAddrTagList:
251                 case LEAF_snmpTargetAddrParams:
252                         free(ctx->scratch->ptr1);
253                         break;
254                 case LEAF_snmpTargetAddrRowStatus:
255                         if ((addrs = target_get_address(&val->var, sub)) == NULL)
256                                 return (SNMP_ERR_GENERR);
257                         if (val->v.integer == RowStatus_destroy)
258                                 return (target_delete_address(addrs));
259                         else if (val->v.integer == RowStatus_active)
260                                 return (target_activate_address(addrs));
261                         break;
262                 default:
263                         break;
264                 }
265                 return (SNMP_ERR_NOERROR);
266
267         case SNMP_OP_ROLLBACK:
268                 if ((addrs = target_get_address(&val->var, sub)) == NULL)
269                         return (SNMP_ERR_GENERR);
270
271                 switch (val->var.subs[sub - 1]) {
272                 case LEAF_snmpTargetAddrTAddress:
273                         memcpy(addrs->address, ctx->scratch->ptr1,
274                             SNMP_UDP_ADDR_SIZ);
275                         free(ctx->scratch->ptr1);
276                         break;
277
278                 case LEAF_snmpTargetAddrTagList:
279                         strlcpy(addrs->taglist, ctx->scratch->ptr1,
280                             ctx->scratch->int1);
281                         free(ctx->scratch->ptr1);
282                         break;
283
284                 case LEAF_snmpTargetAddrParams:
285                         strlcpy(addrs->paramname, ctx->scratch->ptr1,
286                             ctx->scratch->int1);
287                         free(ctx->scratch->ptr1);
288                         break;
289
290                 case LEAF_snmpTargetAddrRetryCount:
291                         addrs->retry = ctx->scratch->int1;
292                         break;
293
294                 case LEAF_snmpTargetAddrTimeout:
295                         addrs->timeout = ctx->scratch->int1;
296                         break;
297
298                 case LEAF_snmpTargetAddrRowStatus:
299                         if (ctx->scratch->int1 == RowStatus_destroy)
300                                 return (target_delete_address(addrs));
301                         break;
302                 default:
303                         break;
304                 }
305                 return (SNMP_ERR_NOERROR);
306
307         default:
308                 abort();
309         }
310
311         switch (val->var.subs[sub - 1]) {
312         case LEAF_snmpTargetAddrTDomain:
313                 return (oid_get(val, &oid_udp_domain));
314         case LEAF_snmpTargetAddrTAddress:
315                 return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ));
316         case LEAF_snmpTargetAddrTimeout:
317                 val->v.integer = addrs->timeout;
318                 break;
319         case LEAF_snmpTargetAddrRetryCount:
320                 val->v.integer = addrs->retry;
321                 break;
322         case LEAF_snmpTargetAddrTagList:
323                 return (string_get(val, addrs->taglist, -1));
324         case LEAF_snmpTargetAddrParams:
325                 return (string_get(val, addrs->paramname, -1));
326         case LEAF_snmpTargetAddrStorageType:
327                 val->v.integer = addrs->type;
328                 break;
329         case LEAF_snmpTargetAddrRowStatus:
330                 val->v.integer = addrs->status;
331                 break;
332         default:
333                 abort();
334         }
335
336         return (SNMP_ERR_NOERROR);
337 }
338
339 int
340 op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val,
341     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
342 {
343         char pname[SNMP_ADM_STR32_SIZ];
344         struct target_param *param;
345
346         switch (op) {
347         case SNMP_OP_GET:
348                 if ((param = target_get_param(&val->var, sub)) == NULL)
349                         return (SNMP_ERR_NOSUCHNAME);
350                 break;
351
352         case SNMP_OP_GETNEXT:
353                 if ((param = target_get_next_param(&val->var, sub)) == NULL)
354                         return (SNMP_ERR_NOSUCHNAME);
355                 target_append_index(&val->var, sub, param->name);
356                 break;
357
358         case SNMP_OP_SET:
359                 if ((param = target_get_param(&val->var, sub)) == NULL &&
360                     (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
361                     val->v.integer != RowStatus_createAndWait))
362                         return (SNMP_ERR_NOSUCHNAME);
363
364                 if (param != NULL) {
365                         if (community != COMM_INITIALIZE &&
366                             param->type == StorageType_readOnly)
367                                 return (SNMP_ERR_NOT_WRITEABLE);
368                         if (param->status == RowStatus_active &&
369                             val->v.integer != RowStatus_destroy)
370                                 return (SNMP_ERR_INCONS_VALUE);
371                 }
372
373                 switch (val->var.subs[sub - 1]) {
374                 case LEAF_snmpTargetParamsMPModel:
375                         if (val->v.integer != SNMP_MPM_SNMP_V1 &&
376                             val->v.integer != SNMP_MPM_SNMP_V2c &&
377                             val->v.integer != SNMP_MPM_SNMP_V3)
378                                 return (SNMP_ERR_INCONS_VALUE);
379                         ctx->scratch->int1 = param->mpmodel;
380                         param->mpmodel = val->v.integer;
381                         break;
382
383                 case LEAF_snmpTargetParamsSecurityModel:
384                         if (val->v.integer != SNMP_SECMODEL_SNMPv1 &&
385                             val->v.integer != SNMP_SECMODEL_SNMPv2c &&
386                             val->v.integer != SNMP_SECMODEL_USM)
387                                 return (SNMP_ERR_INCONS_VALUE);
388                         ctx->scratch->int1 = param->sec_model;
389                         param->sec_model = val->v.integer;
390                         break;
391
392                 case LEAF_snmpTargetParamsSecurityName:
393                         if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
394                                 return (SNMP_ERR_INCONS_VALUE);
395                         ctx->scratch->int1 = strlen(param->secname) + 1;
396                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
397                         if (ctx->scratch->ptr1 == NULL)
398                                 return (SNMP_ERR_GENERR);
399                         strlcpy(ctx->scratch->ptr1, param->secname,
400                             ctx->scratch->int1);
401                         memcpy(param->secname, val->v.octetstring.octets,
402                             val->v.octetstring.len);
403                         param->secname[val->v.octetstring.len] = '\0';
404                         break;
405
406                 case LEAF_snmpTargetParamsSecurityLevel:
407                         if (val->v.integer != SNMP_noAuthNoPriv &&
408                             val->v.integer != SNMP_authNoPriv &&
409                             val->v.integer != SNMP_authPriv)
410                                 return (SNMP_ERR_INCONS_VALUE);
411                         ctx->scratch->int1 = param->sec_level;
412                         param->sec_level = val->v.integer;
413                         break;
414
415                 case LEAF_snmpTargetParamsStorageType:
416                         return (SNMP_ERR_INCONS_VALUE);
417
418                 case LEAF_snmpTargetParamsRowStatus:
419                         if (param != NULL) {
420                                 if (val->v.integer != RowStatus_active &&
421                                     val->v.integer != RowStatus_destroy)
422                                         return (SNMP_ERR_INCONS_VALUE);
423                                 if (val->v.integer == RowStatus_active &&
424                                     (param->sec_model == 0 ||
425                                     param->sec_level == 0 ||
426                                     strlen(param->secname) == 0))
427                                         return (SNMP_ERR_INCONS_VALUE);
428                                 ctx->scratch->int1 = param->status;
429                                 param->status = val->v.integer;
430                                 return (SNMP_ERR_NOERROR);
431                         }
432                         if (val->v.integer != RowStatus_createAndWait ||
433                             target_decode_index(&val->var, sub, pname) < 0)
434                                 return (SNMP_ERR_INCONS_VALUE);
435                         if ((param = target_new_param(pname)) == NULL)
436                                 return (SNMP_ERR_GENERR);
437                         param->status = RowStatus_destroy;
438                         if (community != COMM_INITIALIZE)
439                                 param->type = StorageType_volatile;
440                         else
441                                 param->type = StorageType_readOnly;
442                         break;
443                 }
444                 return (SNMP_ERR_NOERROR);
445
446         case SNMP_OP_COMMIT:
447                 switch (val->var.subs[sub - 1]) {
448                 case LEAF_snmpTargetParamsSecurityName:
449                         free(ctx->scratch->ptr1);
450                         break;
451                 case LEAF_snmpTargetParamsRowStatus:
452                         if ((param = target_get_param(&val->var, sub)) == NULL)
453                                 return (SNMP_ERR_GENERR);
454                         if (val->v.integer == RowStatus_destroy)
455                                 return (target_delete_param(param));
456                         break;
457                 default:
458                         break;
459                 }
460                 return (SNMP_ERR_NOERROR);
461
462         case SNMP_OP_ROLLBACK:
463                 if ((param = target_get_param(&val->var, sub)) == NULL &&
464                     (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
465                     val->v.integer != RowStatus_createAndWait))
466                         return (SNMP_ERR_GENERR);
467                 switch (val->var.subs[sub - 1]) {
468                 case LEAF_snmpTargetParamsMPModel:
469                         param->mpmodel = ctx->scratch->int1;
470                         break;
471                 case LEAF_snmpTargetParamsSecurityModel:
472                         param->sec_model = ctx->scratch->int1;
473                         break;
474                 case LEAF_snmpTargetParamsSecurityName:
475                         strlcpy(param->secname, ctx->scratch->ptr1,
476                             sizeof(param->secname));
477                         free(ctx->scratch->ptr1);
478                         break;
479                 case LEAF_snmpTargetParamsSecurityLevel:
480                         param->sec_level = ctx->scratch->int1;
481                         break;
482                 case LEAF_snmpTargetParamsRowStatus:
483                         if (ctx->scratch->int1 == RowStatus_destroy)
484                                 return (target_delete_param(param));
485                         break;
486                 default:
487                         break;
488                 }
489
490                 return (SNMP_ERR_NOERROR);
491
492         default:
493                 abort();
494         }
495
496         switch (val->var.subs[sub - 1]) {
497         case LEAF_snmpTargetParamsMPModel:
498                 val->v.integer = param->mpmodel;
499                 break;
500         case LEAF_snmpTargetParamsSecurityModel:
501                 val->v.integer = param->sec_model;
502                 break;
503         case LEAF_snmpTargetParamsSecurityName:
504                 return (string_get(val, param->secname, -1));
505         case LEAF_snmpTargetParamsSecurityLevel:
506                 val->v.integer = param->sec_level;
507                 break;
508         case LEAF_snmpTargetParamsStorageType:
509                 val->v.integer = param->type;
510                 break;
511         case LEAF_snmpTargetParamsRowStatus:
512                 val->v.integer = param->status;
513                 break;
514         default:
515                 abort();
516         }
517
518         return (SNMP_ERR_NOERROR);
519 }
520
521 int
522 op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val,
523     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
524 {
525         char nname[SNMP_ADM_STR32_SIZ];
526         struct target_notify *notify;
527
528         switch (op) {
529         case SNMP_OP_GET:
530                 if ((notify = target_get_notify(&val->var, sub)) == NULL)
531                         return (SNMP_ERR_NOSUCHNAME);
532                 break;
533
534         case SNMP_OP_GETNEXT:
535                 if ((notify = target_get_next_notify(&val->var, sub)) == NULL)
536                         return (SNMP_ERR_NOSUCHNAME);
537                 target_append_index(&val->var, sub, notify->name);
538                 break;
539
540         case SNMP_OP_SET:
541                 if ((notify = target_get_notify(&val->var, sub)) == NULL &&
542                     (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus ||
543                     val->v.integer != RowStatus_createAndGo))
544                         return (SNMP_ERR_NOSUCHNAME);
545
546                 if (notify != NULL) {
547                         if (community != COMM_INITIALIZE &&
548                             notify->type == StorageType_readOnly)
549                                 return (SNMP_ERR_NOT_WRITEABLE);
550                 }
551
552                 switch (val->var.subs[sub - 1]) {
553                 case LEAF_snmpNotifyTag:
554                         if (val->v.octetstring.len >= SNMP_TAG_SIZ)
555                                 return (SNMP_ERR_INCONS_VALUE);
556                         ctx->scratch->int1 = strlen(notify->taglist) + 1;
557                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
558                         if (ctx->scratch->ptr1 == NULL)
559                                 return (SNMP_ERR_GENERR);
560                         strlcpy(ctx->scratch->ptr1, notify->taglist,
561                             ctx->scratch->int1);
562                         memcpy(notify->taglist, val->v.octetstring.octets,
563                             val->v.octetstring.len);
564                         notify->taglist[val->v.octetstring.len] = '\0';
565                         break;
566
567                 case LEAF_snmpNotifyType:
568                         /* FALLTHROUGH */
569                 case LEAF_snmpNotifyStorageType:
570                         return (SNMP_ERR_INCONS_VALUE);
571                 case LEAF_snmpNotifyRowStatus:
572                         if (notify != NULL) {
573                                 if (val->v.integer != RowStatus_active &&
574                                     val->v.integer != RowStatus_destroy)
575                                         return (SNMP_ERR_INCONS_VALUE);
576                                 ctx->scratch->int1 = notify->status;
577                                 notify->status = val->v.integer;
578                                 return (SNMP_ERR_NOERROR);
579                         }
580                         if (val->v.integer != RowStatus_createAndGo ||
581                             target_decode_index(&val->var, sub, nname) < 0)
582                                 return (SNMP_ERR_INCONS_VALUE);
583                         if ((notify = target_new_notify(nname)) == NULL)
584                                 return (SNMP_ERR_GENERR);
585                         notify->status = RowStatus_destroy;
586                         if (community != COMM_INITIALIZE)
587                                 notify->type = StorageType_volatile;
588                         else
589                                 notify->type = StorageType_readOnly;
590                         break;
591                 }
592                 return (SNMP_ERR_NOERROR);
593
594         case SNMP_OP_COMMIT:
595                 switch (val->var.subs[sub - 1]) {
596                 case LEAF_snmpNotifyTag:
597                         free(ctx->scratch->ptr1);
598                         break;
599                 case LEAF_snmpNotifyRowStatus:
600                         notify = target_get_notify(&val->var, sub);
601                         if (notify == NULL)
602                                 return (SNMP_ERR_GENERR);
603                         if (val->v.integer == RowStatus_destroy)
604                                 return (target_delete_notify(notify));
605                         else
606                                 notify->status = RowStatus_active;
607                         break;
608                 default:
609                         break;
610                 }
611                 return (SNMP_ERR_NOERROR);
612
613         case SNMP_OP_ROLLBACK:
614                 if ((notify = target_get_notify(&val->var, sub)) == NULL)
615                         return (SNMP_ERR_GENERR);
616
617                 switch (val->var.subs[sub - 1]) {
618                 case LEAF_snmpNotifyTag:
619                         strlcpy(notify->taglist, ctx->scratch->ptr1,
620                             ctx->scratch->int1);
621                         free(ctx->scratch->ptr1);
622                         break;
623                 case LEAF_snmpNotifyRowStatus:
624                         if (ctx->scratch->int1 == RowStatus_destroy)
625                                 return (target_delete_notify(notify));
626                         break;
627                 default:
628                         break;
629                 }
630                 return (SNMP_ERR_NOERROR);
631
632         default:
633                 abort();
634         }
635
636
637         switch (val->var.subs[sub - 1]) {
638         case LEAF_snmpNotifyTag:
639                 return (string_get(val, notify->taglist, -1));
640         case LEAF_snmpNotifyType:
641                 val->v.integer = snmpNotifyType_trap;
642                 break;
643         case LEAF_snmpNotifyStorageType:
644                 val->v.integer = notify->type;
645                 break;
646         case LEAF_snmpNotifyRowStatus:
647                 val->v.integer = notify->status;
648                 break;
649         default:
650                 abort();
651         }
652
653         return (SNMP_ERR_NOERROR);
654 }
655
656 static void
657 target_append_index(struct asn_oid *oid, uint sub, const char *name)
658 {
659         uint32_t i;
660
661         oid->len = sub + strlen(name);
662         for (i = 0; i < strlen(name); i++)
663                 oid->subs[sub + i] = name[i];
664 }
665
666 static int
667 target_decode_index(const struct asn_oid *oid, uint sub, char *name)
668 {
669         uint32_t i;
670
671         if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >=
672             SNMP_ADM_STR32_SIZ)
673                 return (-1);
674
675         for (i = 0; i < oid->subs[sub]; i++)
676                 name[i] = oid->subs[sub + i + 1];
677         name[i] = '\0';
678
679         return (0);
680 }
681
682 static struct target_address *
683 target_get_address(const struct asn_oid *oid, uint sub)
684 {
685         char aname[SNMP_ADM_STR32_SIZ];
686         struct target_address *addrs;
687
688         if (target_decode_index(oid, sub, aname) < 0)
689                 return (NULL);
690
691         for (addrs = target_first_address(); addrs != NULL;
692             addrs = target_next_address(addrs))
693                 if (strcmp(aname, addrs->name) == 0)
694                         return (addrs);
695
696         return (NULL);
697 }
698
699 static struct target_address *
700 target_get_next_address(const struct asn_oid * oid, uint sub)
701 {
702         char aname[SNMP_ADM_STR32_SIZ];
703         struct target_address *addrs;
704
705         if (oid->len - sub == 0)
706                 return (target_first_address());
707
708         if (target_decode_index(oid, sub, aname) < 0)
709                 return (NULL);
710
711         for (addrs = target_first_address(); addrs != NULL;
712             addrs = target_next_address(addrs))
713                 if (strcmp(aname, addrs->name) == 0)
714                         return (target_next_address(addrs));
715
716         return (NULL);
717 }
718
719 static struct target_param *
720 target_get_param(const struct asn_oid *oid, uint sub)
721 {
722         char pname[SNMP_ADM_STR32_SIZ];
723         struct target_param *param;
724
725         if (target_decode_index(oid, sub, pname) < 0)
726                 return (NULL);
727
728         for (param = target_first_param(); param != NULL;
729             param = target_next_param(param))
730                 if (strcmp(pname, param->name) == 0)
731                         return (param);
732
733         return (NULL);
734 }
735
736 static struct target_param *
737 target_get_next_param(const struct asn_oid *oid, uint sub)
738 {
739         char pname[SNMP_ADM_STR32_SIZ];
740         struct target_param *param;
741
742         if (oid->len - sub == 0)
743                 return (target_first_param());
744
745         if (target_decode_index(oid, sub, pname) < 0)
746                 return (NULL);
747
748         for (param = target_first_param(); param != NULL;
749             param = target_next_param(param))
750                 if (strcmp(pname, param->name) == 0)
751                         return (target_next_param(param));
752
753         return (NULL);
754 }
755
756 static struct target_notify *
757 target_get_notify(const struct asn_oid *oid, uint sub)
758 {
759         char nname[SNMP_ADM_STR32_SIZ];
760         struct target_notify *notify;
761
762         if (target_decode_index(oid, sub, nname) < 0)
763                 return (NULL);
764
765         for (notify = target_first_notify(); notify != NULL;
766             notify = target_next_notify(notify))
767                 if (strcmp(nname, notify->name) == 0)
768                         return (notify);
769
770         return (NULL);
771 }
772
773 static struct target_notify *
774 target_get_next_notify(const struct asn_oid *oid, uint sub)
775 {
776         char nname[SNMP_ADM_STR32_SIZ];
777         struct target_notify *notify;
778
779         if (oid->len - sub == 0)
780                 return (target_first_notify());
781
782         if (target_decode_index(oid, sub, nname) < 0)
783                 return (NULL);
784
785         for (notify = target_first_notify(); notify != NULL;
786             notify = target_next_notify(notify))
787                 if (strcmp(nname, notify->name) == 0)
788                         return (target_next_notify(notify));
789
790         return (NULL);
791 }
792
793 static int
794 target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
795 {
796         target_module = mod;
797         target_lock = random();
798
799         return (0);
800 }
801
802
803 static int
804 target_fini(void)
805 {
806         target_flush_all();
807         or_unregister(reg_target);
808         or_unregister(reg_notification);
809
810         return (0);
811 }
812
813 static void
814 target_start(void)
815 {
816         reg_target = or_register(&oid_target,
817             "The MIB module for managing SNMP Management Targets.",
818             target_module);
819         reg_notification = or_register(&oid_notification,
820             "The MIB module for configuring generation of SNMP notifications.",
821             target_module);
822 }
823
824 static void
825 target_dump(void)
826 {
827         /* XXX: dump the module stats & list of mgmt targets */
828 }
829
830 static const char target_comment[] = \
831 "This module implements SNMP Management Target MIB Module defined in RFC 3413.";
832
833 extern const struct snmp_module config;
834 const struct snmp_module config = {
835         .comment =      target_comment,
836         .init =         target_init,
837         .fini =         target_fini,
838         .start =        target_start,
839         .tree =         target_ctree,
840         .dump =         target_dump,
841         .tree_size =    target_CTREE_SIZE,
842 };