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