]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - contrib/bsnmp/snmp_target/target_snmp.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.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
305         default:
306                 abort();
307         }
308
309         switch (val->var.subs[sub - 1]) {
310         case LEAF_snmpTargetAddrTDomain:
311                 return (oid_get(val, &oid_udp_domain));
312         case LEAF_snmpTargetAddrTAddress:
313                 return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ));
314         case LEAF_snmpTargetAddrTimeout:
315                 val->v.integer = addrs->timeout;
316                 break;
317         case LEAF_snmpTargetAddrRetryCount:
318                 val->v.integer = addrs->retry;
319                 break;
320         case LEAF_snmpTargetAddrTagList:
321                 return (string_get(val, addrs->taglist, -1));
322         case LEAF_snmpTargetAddrParams:
323                 return (string_get(val, addrs->paramname, -1));
324         case LEAF_snmpTargetAddrStorageType:
325                 val->v.integer = addrs->type;
326                 break;
327         case LEAF_snmpTargetAddrRowStatus:
328                 val->v.integer = addrs->status;
329                 break;
330         default:
331                 abort();
332         }
333
334         return (SNMP_ERR_NOERROR);
335 }
336
337 int
338 op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val,
339     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
340 {
341         char pname[SNMP_ADM_STR32_SIZ];
342         struct target_param *param;
343
344         switch (op) {
345         case SNMP_OP_GET:
346                 if ((param = target_get_param(&val->var, sub)) == NULL)
347                         return (SNMP_ERR_NOSUCHNAME);
348                 break;
349
350         case SNMP_OP_GETNEXT:
351                 if ((param = target_get_next_param(&val->var, sub)) == NULL)
352                         return (SNMP_ERR_NOSUCHNAME);
353                 target_append_index(&val->var, sub, param->name);
354                 break;
355
356         case SNMP_OP_SET:
357                 if ((param = target_get_param(&val->var, sub)) == NULL &&
358                     (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
359                     val->v.integer != RowStatus_createAndWait))
360                         return (SNMP_ERR_NOSUCHNAME);
361
362                 if (param != NULL) {
363                         if (community != COMM_INITIALIZE &&
364                             param->type == StorageType_readOnly)
365                                 return (SNMP_ERR_NOT_WRITEABLE);
366                         if (param->status == RowStatus_active &&
367                             val->v.integer != RowStatus_destroy)
368                                 return (SNMP_ERR_INCONS_VALUE);
369                 }
370
371                 switch (val->var.subs[sub - 1]) {
372                 case LEAF_snmpTargetParamsMPModel:
373                         if (val->v.integer != SNMP_MPM_SNMP_V1 &&
374                             val->v.integer != SNMP_MPM_SNMP_V2c &&
375                             val->v.integer != SNMP_MPM_SNMP_V3)
376                                 return (SNMP_ERR_INCONS_VALUE);
377                         ctx->scratch->int1 = param->mpmodel;
378                         param->mpmodel = val->v.integer;
379                         break;
380
381                 case LEAF_snmpTargetParamsSecurityModel:
382                         if (val->v.integer != SNMP_SECMODEL_SNMPv1 &&
383                             val->v.integer != SNMP_SECMODEL_SNMPv2c &&
384                             val->v.integer != SNMP_SECMODEL_USM)
385                                 return (SNMP_ERR_INCONS_VALUE);
386                         ctx->scratch->int1 = param->sec_model;
387                         param->sec_model = val->v.integer;
388                         break;
389
390                 case LEAF_snmpTargetParamsSecurityName:
391                         if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ)
392                                 return (SNMP_ERR_INCONS_VALUE);
393                         ctx->scratch->int1 = strlen(param->secname) + 1;
394                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
395                         if (ctx->scratch->ptr1 == NULL)
396                                 return (SNMP_ERR_GENERR);
397                         strlcpy(ctx->scratch->ptr1, param->secname,
398                             ctx->scratch->int1);
399                         memcpy(param->secname, val->v.octetstring.octets,
400                             val->v.octetstring.len);
401                         param->secname[val->v.octetstring.len] = '\0';
402                         break;
403
404                 case LEAF_snmpTargetParamsSecurityLevel:
405                         if (val->v.integer != SNMP_noAuthNoPriv &&
406                             val->v.integer != SNMP_authNoPriv &&
407                             val->v.integer != SNMP_authPriv)
408                                 return (SNMP_ERR_INCONS_VALUE);
409                         ctx->scratch->int1 = param->sec_level;
410                         param->sec_level = val->v.integer;
411                         break;
412
413                 case LEAF_snmpTargetParamsStorageType:
414                         return (SNMP_ERR_INCONS_VALUE);
415
416                 case LEAF_snmpTargetParamsRowStatus:
417                         if (param != NULL) {
418                                 if (val->v.integer != RowStatus_active &&
419                                     val->v.integer != RowStatus_destroy)
420                                         return (SNMP_ERR_INCONS_VALUE);
421                                 if (val->v.integer == RowStatus_active &&
422                                     (param->sec_model == 0 ||
423                                     param->sec_level == 0 ||
424                                     strlen(param->secname) == 0))
425                                         return (SNMP_ERR_INCONS_VALUE);
426                                 ctx->scratch->int1 = param->status;
427                                 param->status = val->v.integer;
428                                 return (SNMP_ERR_NOERROR);
429                         }
430                         if (val->v.integer != RowStatus_createAndWait ||
431                             target_decode_index(&val->var, sub, pname) < 0)
432                                 return (SNMP_ERR_INCONS_VALUE);
433                         if ((param = target_new_param(pname)) == NULL)
434                                 return (SNMP_ERR_GENERR);
435                         param->status = RowStatus_destroy;
436                         if (community != COMM_INITIALIZE)
437                                 param->type = StorageType_volatile;
438                         else
439                                 param->type = StorageType_readOnly;
440                         break;
441                 }
442                 return (SNMP_ERR_NOERROR);
443
444         case SNMP_OP_COMMIT:
445                 switch (val->var.subs[sub - 1]) {
446                 case LEAF_snmpTargetParamsSecurityName:
447                         free(ctx->scratch->ptr1);
448                         break;
449                 case LEAF_snmpTargetParamsRowStatus:
450                         if ((param = target_get_param(&val->var, sub)) == NULL)
451                                 return (SNMP_ERR_GENERR);
452                         if (val->v.integer == RowStatus_destroy)
453                                 return (target_delete_param(param));
454                         break;
455                 default:
456                         break;
457                 }
458                 return (SNMP_ERR_NOERROR);
459
460         case SNMP_OP_ROLLBACK:
461                 if ((param = target_get_param(&val->var, sub)) == NULL &&
462                     (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus ||
463                     val->v.integer != RowStatus_createAndWait))
464                         return (SNMP_ERR_GENERR);
465                 switch (val->var.subs[sub - 1]) {
466                 case LEAF_snmpTargetParamsMPModel:
467                         param->mpmodel = ctx->scratch->int1;
468                         break;
469                 case LEAF_snmpTargetParamsSecurityModel:
470                         param->sec_model = ctx->scratch->int1;
471                         break;
472                 case LEAF_snmpTargetParamsSecurityName:
473                         strlcpy(param->secname, ctx->scratch->ptr1,
474                             sizeof(param->secname));
475                         free(ctx->scratch->ptr1);
476                         break;
477                 case LEAF_snmpTargetParamsSecurityLevel:
478                         param->sec_level = ctx->scratch->int1;
479                         break;
480                 case LEAF_snmpTargetParamsRowStatus:
481                         if (ctx->scratch->int1 == RowStatus_destroy)
482                                 return (target_delete_param(param));
483                         break;
484                 default:
485                         break;
486                 }
487
488                 return (SNMP_ERR_NOERROR);
489
490         default:
491                 abort();
492         }
493
494         switch (val->var.subs[sub - 1]) {
495         case LEAF_snmpTargetParamsMPModel:
496                 val->v.integer = param->mpmodel;
497                 break;
498         case LEAF_snmpTargetParamsSecurityModel:
499                 val->v.integer = param->sec_model;
500                 break;
501         case LEAF_snmpTargetParamsSecurityName:
502                 return (string_get(val, param->secname, -1));
503         case LEAF_snmpTargetParamsSecurityLevel:
504                 val->v.integer = param->sec_level;
505                 break;
506         case LEAF_snmpTargetParamsStorageType:
507                 val->v.integer = param->type;
508                 break;
509         case LEAF_snmpTargetParamsRowStatus:
510                 val->v.integer = param->status;
511                 break;
512         default:
513                 abort();
514         }
515
516         return (SNMP_ERR_NOERROR);
517 }
518
519 int
520 op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val,
521     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
522 {
523         char nname[SNMP_ADM_STR32_SIZ];
524         struct target_notify *notify;
525
526         switch (op) {
527         case SNMP_OP_GET:
528                 if ((notify = target_get_notify(&val->var, sub)) == NULL)
529                         return (SNMP_ERR_NOSUCHNAME);
530                 break;
531
532         case SNMP_OP_GETNEXT:
533                 if ((notify = target_get_next_notify(&val->var, sub)) == NULL)
534                         return (SNMP_ERR_NOSUCHNAME);
535                 target_append_index(&val->var, sub, notify->name);
536                 break;
537
538         case SNMP_OP_SET:
539                 if ((notify = target_get_notify(&val->var, sub)) == NULL &&
540                     (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus ||
541                     val->v.integer != RowStatus_createAndGo))
542                         return (SNMP_ERR_NOSUCHNAME);
543
544                 if (notify != NULL) {
545                         if (community != COMM_INITIALIZE &&
546                             notify->type == StorageType_readOnly)
547                                 return (SNMP_ERR_NOT_WRITEABLE);
548                 }
549
550                 switch (val->var.subs[sub - 1]) {
551                 case LEAF_snmpNotifyTag:
552                         if (val->v.octetstring.len >= SNMP_TAG_SIZ)
553                                 return (SNMP_ERR_INCONS_VALUE);
554                         ctx->scratch->int1 = strlen(notify->taglist) + 1;
555                         ctx->scratch->ptr1 = malloc(ctx->scratch->int1);
556                         if (ctx->scratch->ptr1 == NULL)
557                                 return (SNMP_ERR_GENERR);
558                         strlcpy(ctx->scratch->ptr1, notify->taglist,
559                             ctx->scratch->int1);
560                         memcpy(notify->taglist, val->v.octetstring.octets,
561                             val->v.octetstring.len);
562                         notify->taglist[val->v.octetstring.len] = '\0';
563                         break;
564
565                 case LEAF_snmpNotifyType:
566                         /* FALLTHROUGH */
567                 case LEAF_snmpNotifyStorageType:
568                         return (SNMP_ERR_INCONS_VALUE);
569                 case LEAF_snmpNotifyRowStatus:
570                         if (notify != NULL) {
571                                 if (val->v.integer != RowStatus_active &&
572                                     val->v.integer != RowStatus_destroy)
573                                         return (SNMP_ERR_INCONS_VALUE);
574                                 ctx->scratch->int1 = notify->status;
575                                 notify->status = val->v.integer;
576                                 return (SNMP_ERR_NOERROR);
577                         }
578                         if (val->v.integer != RowStatus_createAndGo ||
579                             target_decode_index(&val->var, sub, nname) < 0)
580                                 return (SNMP_ERR_INCONS_VALUE);
581                         if ((notify = target_new_notify(nname)) == NULL)
582                                 return (SNMP_ERR_GENERR);
583                         notify->status = RowStatus_destroy;
584                         if (community != COMM_INITIALIZE)
585                                 notify->type = StorageType_volatile;
586                         else
587                                 notify->type = StorageType_readOnly;
588                         break;
589                 }
590                 return (SNMP_ERR_NOERROR);
591
592         case SNMP_OP_COMMIT:
593                 switch (val->var.subs[sub - 1]) {
594                 case LEAF_snmpNotifyTag:
595                         free(ctx->scratch->ptr1);
596                         break;
597                 case LEAF_snmpNotifyRowStatus:
598                         notify = target_get_notify(&val->var, sub);
599                         if (notify == NULL)
600                                 return (SNMP_ERR_GENERR);
601                         if (val->v.integer == RowStatus_destroy)
602                                 return (target_delete_notify(notify));
603                         else
604                                 notify->status = RowStatus_active;
605                         break;
606                 default:
607                         break;
608                 }
609                 return (SNMP_ERR_NOERROR);
610
611         case SNMP_OP_ROLLBACK:
612                 if ((notify = target_get_notify(&val->var, sub)) == NULL)
613                         return (SNMP_ERR_GENERR);
614
615                 switch (val->var.subs[sub - 1]) {
616                 case LEAF_snmpNotifyTag:
617                         strlcpy(notify->taglist, ctx->scratch->ptr1,
618                             ctx->scratch->int1);
619                         free(ctx->scratch->ptr1);
620                         break;
621                 case LEAF_snmpNotifyRowStatus:
622                         if (ctx->scratch->int1 == RowStatus_destroy)
623                                 return (target_delete_notify(notify));
624                         break;
625                 default:
626                         break;
627                 }
628
629         default:
630                 abort();
631         }
632
633
634         switch (val->var.subs[sub - 1]) {
635         case LEAF_snmpNotifyTag:
636                 return (string_get(val, notify->taglist, -1));
637         case LEAF_snmpNotifyType:
638                 val->v.integer = snmpNotifyType_trap;
639                 break;
640         case LEAF_snmpNotifyStorageType:
641                 val->v.integer = notify->type;
642                 break;
643         case LEAF_snmpNotifyRowStatus:
644                 val->v.integer = notify->status;
645                 break;
646         default:
647                 abort();
648         }
649
650         return (SNMP_ERR_NOERROR);
651 }
652
653 static void
654 target_append_index(struct asn_oid *oid, uint sub, const char *name)
655 {
656         uint32_t i;
657
658         oid->len = sub + strlen(name);
659         for (i = 0; i < strlen(name); i++)
660                 oid->subs[sub + i] = name[i];
661 }
662
663 static int
664 target_decode_index(const struct asn_oid *oid, uint sub, char *name)
665 {
666         uint32_t i, len;
667
668         if ((len = oid->len - sub) >= SNMP_ADM_STR32_SIZ)
669                 return (-1);
670
671         for (i = 0; i < len; i++)
672                 name[i] = oid->subs[sub + i];
673         name[i] = '\0';
674
675         return (0);
676 }
677
678 static struct target_address *
679 target_get_address(const struct asn_oid *oid, uint sub)
680 {
681         char aname[SNMP_ADM_STR32_SIZ];
682         struct target_address *addrs;
683
684         if (target_decode_index(oid, sub, aname) < 0)
685                 return (NULL);
686
687         for (addrs = target_first_address(); addrs != NULL;
688             addrs = target_next_address(addrs))
689                 if (strcmp(aname, addrs->name) == 0)
690                         return (addrs);
691
692         return (NULL);
693 }
694
695 static struct target_address *
696 target_get_next_address(const struct asn_oid * oid, uint sub)
697 {
698         char aname[SNMP_ADM_STR32_SIZ];
699         struct target_address *addrs;
700
701         if (oid->len - sub == 0)
702                 return (target_first_address());
703
704         if (target_decode_index(oid, sub, aname) < 0)
705                 return (NULL);
706
707         for (addrs = target_first_address(); addrs != NULL;
708             addrs = target_next_address(addrs))
709                 if (strcmp(aname, addrs->name) == 0)
710                         return (target_next_address(addrs));
711
712         return (NULL);
713 }
714
715 static struct target_param *
716 target_get_param(const struct asn_oid *oid, uint sub)
717 {
718         char pname[SNMP_ADM_STR32_SIZ];
719         struct target_param *param;
720
721         if (target_decode_index(oid, sub, pname) < 0)
722                 return (NULL);
723
724         for (param = target_first_param(); param != NULL;
725             param = target_next_param(param))
726                 if (strcmp(pname, param->name) == 0)
727                         return (param);
728
729         return (NULL);
730 }
731
732 static struct target_param *
733 target_get_next_param(const struct asn_oid *oid, uint sub)
734 {
735         char pname[SNMP_ADM_STR32_SIZ];
736         struct target_param *param;
737
738         if (oid->len - sub == 0)
739                 return (target_first_param());
740
741         if (target_decode_index(oid, sub, pname) < 0)
742                 return (NULL);
743
744         for (param = target_first_param(); param != NULL;
745             param = target_next_param(param))
746                 if (strcmp(pname, param->name) == 0)
747                         return (target_next_param(param));
748
749         return (NULL);
750 }
751
752 static struct target_notify *
753 target_get_notify(const struct asn_oid *oid, uint sub)
754 {
755         char nname[SNMP_ADM_STR32_SIZ];
756         struct target_notify *notify;
757
758         if (target_decode_index(oid, sub, nname) < 0)
759                 return (NULL);
760
761         for (notify = target_first_notify(); notify != NULL;
762             notify = target_next_notify(notify))
763                 if (strcmp(nname, notify->name) == 0)
764                         return (notify);
765
766         return (NULL);
767 }
768
769 static struct target_notify *
770 target_get_next_notify(const struct asn_oid *oid, uint sub)
771 {
772         char nname[SNMP_ADM_STR32_SIZ];
773         struct target_notify *notify;
774
775         if (oid->len - sub == 0)
776                 return (target_first_notify());
777
778         if (target_decode_index(oid, sub, nname) < 0)
779                 return (NULL);
780
781         for (notify = target_first_notify(); notify != NULL;
782             notify = target_next_notify(notify))
783                 if (strcmp(nname, notify->name) == 0)
784                         return (target_next_notify(notify));
785
786         return (NULL);
787 }
788
789 static int
790 target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
791 {
792         target_module = mod;
793         target_lock = random();
794
795         return (0);
796 }
797
798
799 static int
800 target_fini(void)
801 {
802         target_flush_all();
803         or_unregister(reg_target);
804         or_unregister(reg_notification);
805
806         return (0);
807 }
808
809 static void
810 target_start(void)
811 {
812         reg_target = or_register(&oid_target,
813             "The MIB module for managing SNMP Management Targets.",
814             target_module);
815         reg_notification = or_register(&oid_notification,
816             "The MIB module for configuring generation of SNMP notifications.",
817             target_module);
818 }
819
820 static void
821 target_dump(void)
822 {
823         /* XXX: dump the module stats & list of mgmt targets */
824 }
825
826 const char target_comment[] = \
827 "This module implements SNMP Management Target MIB Module defined in RFC 3413.";
828
829 const struct snmp_module config = {
830         .comment =      target_comment,
831         .init =         target_init,
832         .fini =         target_fini,
833         .start =        target_start,
834         .tree =         target_ctree,
835         .dump =         target_dump,
836         .tree_size =    target_CTREE_SIZE,
837 };