]> CyberLeo.Net >> Repos - FreeBSD/releng/10.0.git/blob - contrib/bsnmp/snmp_vacm/vacm_snmp.c
- Copy stable/10 (r259064) to releng/10.0 as part of the
[FreeBSD/releng/10.0.git] / contrib / bsnmp / snmp_vacm / vacm_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 "vacm_tree.h"
47 #include "vacm_oid.h"
48
49 static struct lmodule *vacm_module;
50 /* For the registration. */
51 static const struct asn_oid oid_vacm = OIDX_snmpVacmMIB;
52
53 static uint reg_vacm;
54
55 static int32_t vacm_lock;
56
57 /*
58  * Internal datastructures and forward declarations.
59  */
60 static void             vacm_append_userindex(struct asn_oid *,
61     uint, const struct vacm_user *);
62 static int              vacm_user_index_decode(const struct asn_oid *,
63     uint, int32_t *, char *);
64 static struct vacm_user *vacm_get_user(const struct asn_oid *,
65     uint);
66 static struct vacm_user *vacm_get_next_user(const struct asn_oid *,
67     uint);
68 static void             vacm_append_access_rule_index(struct asn_oid *,
69     uint, const struct vacm_access *);
70 static int              vacm_access_rule_index_decode(const struct asn_oid *,
71     uint, char *, char *, int32_t *, int32_t *);
72 static struct vacm_access *     vacm_get_access_rule(const struct asn_oid *,
73     uint);
74 static struct vacm_access *     vacm_get_next_access_rule(const struct asn_oid *,
75     uint);
76 static int              vacm_view_index_decode(const struct asn_oid *, uint,
77     char *, struct asn_oid *);
78 static void             vacm_append_viewindex(struct asn_oid *, uint,
79     const struct vacm_view *);
80 static struct vacm_view *vacm_get_view(const struct asn_oid *, uint);
81 static struct vacm_view *vacm_get_next_view(const struct asn_oid *, uint);
82 static struct vacm_view *vacm_get_view_by_name(u_char *, u_int);
83 static struct vacm_context      *vacm_get_context(const struct asn_oid *, uint);
84 static struct vacm_context      *vacm_get_next_context(const struct asn_oid *,
85     uint);
86 static void                     vacm_append_ctxindex(struct asn_oid *, uint,
87     const struct vacm_context *);
88
89 int
90 op_vacm_context(struct snmp_context *ctx __unused, struct snmp_value *val,
91     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
92 {
93         char cname[SNMP_ADM_STR32_SIZ];
94         size_t cnamelen;
95         struct vacm_context *vacm_ctx;
96
97         if (val->var.subs[sub - 1] != LEAF_vacmContextName)
98                 abort();
99
100         switch (op) {
101         case SNMP_OP_GET:
102                 if ((vacm_ctx = vacm_get_context(&val->var, sub)) == NULL)
103                         return (SNMP_ERR_NOSUCHNAME);
104                 break;
105
106         case SNMP_OP_GETNEXT:
107                 if ((vacm_ctx = vacm_get_next_context(&val->var, sub)) == NULL)
108                         return (SNMP_ERR_NOSUCHNAME);
109                 vacm_append_ctxindex(&val->var, sub, vacm_ctx);
110                 break;
111
112         case SNMP_OP_SET:
113                 if ((vacm_ctx = vacm_get_context(&val->var, sub)) != NULL)
114                         return (SNMP_ERR_WRONG_VALUE);
115                 if (community != COMM_INITIALIZE)
116                         return (SNMP_ERR_NOT_WRITEABLE);
117                 if (val->var.subs[sub] >= SNMP_ADM_STR32_SIZ)
118                         return (SNMP_ERR_WRONG_VALUE);
119                 if (index_decode(&val->var, sub, iidx, &cname, &cnamelen))
120                         return (SNMP_ERR_GENERR);
121                 cname[cnamelen] = '\0';
122                 if ((vacm_ctx = vacm_add_context(cname, reg_vacm)) == NULL)
123                         return (SNMP_ERR_GENERR);
124                 return (SNMP_ERR_NOERROR);
125
126         case SNMP_OP_COMMIT:
127                 /* FALLTHROUGH*/
128         case SNMP_OP_ROLLBACK:
129                 return (SNMP_ERR_NOERROR);
130         default:
131                 abort();
132         }
133
134         return (string_get(val, vacm_ctx->ctxname, -1));
135 }
136
137 int
138 op_vacm_security_to_group(struct snmp_context *ctx, struct snmp_value *val,
139     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
140 {
141         int32_t smodel;
142         char uname[SNMP_ADM_STR32_SIZ];
143         struct vacm_user *user;
144
145         switch (op) {
146         case SNMP_OP_GET:
147                 if ((user = vacm_get_user(&val->var, sub)) == NULL)
148                         return (SNMP_ERR_NOSUCHNAME);
149                 break;
150
151         case SNMP_OP_GETNEXT:
152                 if ((user = vacm_get_next_user(&val->var, sub)) == NULL)
153                         return (SNMP_ERR_NOSUCHNAME);
154                 vacm_append_userindex(&val->var, sub, user);
155                 break;
156
157         case SNMP_OP_SET:
158                 if ((user = vacm_get_user(&val->var, sub)) == NULL &&
159                     val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
160                         return (SNMP_ERR_NOSUCHNAME);
161
162                 if (user != NULL) {
163                         if (community != COMM_INITIALIZE &&
164                             user->type == StorageType_readOnly)
165                                 return (SNMP_ERR_NOT_WRITEABLE);
166                         if (user->status == RowStatus_active &&
167                             val->v.integer != RowStatus_destroy)
168                                 return (SNMP_ERR_INCONS_VALUE);
169                 }
170
171                 switch (val->var.subs[sub - 1]) {
172                 case LEAF_vacmGroupName:
173                         ctx->scratch->ptr1 = user->group->groupname;
174                         ctx->scratch->int1 = strlen(user->group->groupname);
175                         return (vacm_user_set_group(user,
176                             val->v.octetstring.octets,val->v.octetstring.len));
177
178                 case LEAF_vacmSecurityToGroupStorageType:
179                         return (SNMP_ERR_INCONS_VALUE);
180
181                 case LEAF_vacmSecurityToGroupStatus:
182                         if (user == NULL) {
183                                 if (val->v.integer != RowStatus_createAndGo ||
184                                     vacm_user_index_decode(&val->var, sub,
185                                     &smodel, uname) < 0)
186                                         return (SNMP_ERR_INCONS_VALUE);
187                                 user = vacm_new_user(smodel, uname);
188                                 if (user == NULL)
189                                         return (SNMP_ERR_GENERR);
190                                 user->status = RowStatus_destroy;
191                                 if (community != COMM_INITIALIZE)
192                                         user->type = StorageType_volatile;
193                                 else
194                                         user->type = StorageType_readOnly;
195                         } else if (val->v.integer != RowStatus_active &&
196                             val->v.integer != RowStatus_destroy)
197                                 return (SNMP_ERR_INCONS_VALUE);
198                         ctx->scratch->int1 = user->status;
199                         user->status = val->v.integer;
200                         break;
201                 }
202                 return (SNMP_ERR_NOERROR);
203
204         case SNMP_OP_COMMIT:
205                 if (val->var.subs[sub - 1] != LEAF_vacmSecurityToGroupStatus)
206                         return (SNMP_ERR_NOERROR);
207                 if ((user = vacm_get_user(&val->var, sub)) == NULL)
208                         return (SNMP_ERR_GENERR);
209                 switch (val->v.integer) {
210                 case  RowStatus_destroy:
211                         return (vacm_delete_user(user));
212
213                 case RowStatus_createAndGo:
214                         user->status = RowStatus_active;
215                         break;
216
217                 default:
218                         break;
219                 }
220                 return (SNMP_ERR_NOERROR);
221
222         case SNMP_OP_ROLLBACK:
223                 if ((user = vacm_get_user(&val->var, sub)) == NULL)
224                         return (SNMP_ERR_GENERR);
225                 switch (val->var.subs[sub - 1]) {
226                 case LEAF_vacmGroupName:
227                         return (vacm_user_set_group(user, ctx->scratch->ptr1,
228                             ctx->scratch->int1));
229
230                 case LEAF_vacmSecurityToGroupStatus:
231                         if (ctx->scratch->int1 == RowStatus_destroy)
232                                 return (vacm_delete_user(user));
233                         user->status = ctx->scratch->int1;
234                         break;
235
236                 default:
237                         break;
238                 }
239                 return (SNMP_ERR_NOERROR);
240
241         default:
242                 abort();
243         }
244
245         switch (val->var.subs[sub - 1]) {
246         case LEAF_vacmGroupName:
247                 return (string_get(val, user->group->groupname, -1));
248         case LEAF_vacmSecurityToGroupStorageType:
249                 val->v.integer = user->type;
250                 break;
251         case LEAF_vacmSecurityToGroupStatus:
252                 val->v.integer = user->status;
253                 break;
254         default:
255                 abort();
256         }
257
258         return (SNMP_ERR_NOERROR);
259 }
260
261 int
262 op_vacm_access(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
263     uint32_t iidx __unused, enum snmp_op op)
264 {
265         int32_t smodel, slevel;
266         char gname[SNMP_ADM_STR32_SIZ], cprefix[SNMP_ADM_STR32_SIZ];
267         struct vacm_access *acl;
268
269         switch (op) {
270         case SNMP_OP_GET:
271                 if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
272                         return (SNMP_ERR_NOSUCHNAME);
273                 break;
274
275         case SNMP_OP_GETNEXT:
276                 if ((acl = vacm_get_next_access_rule(&val->var, sub)) == NULL)
277                         return (SNMP_ERR_NOSUCHNAME);
278                 vacm_append_access_rule_index(&val->var, sub, acl);
279                 break;
280
281         case SNMP_OP_SET:
282                 if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL &&
283                     val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
284                                 return (SNMP_ERR_NOSUCHNAME);
285                 if (acl != NULL && community != COMM_INITIALIZE &&
286                     acl->type == StorageType_readOnly)
287                         return (SNMP_ERR_NOT_WRITEABLE);
288
289                 switch (val->var.subs[sub - 1]) {
290                 case LEAF_vacmAccessContextMatch:
291                         ctx->scratch->int1 = acl->ctx_match;
292                         if (val->v.integer == vacmAccessContextMatch_exact)
293                                 acl->ctx_match = 1;
294                         else if (val->v.integer == vacmAccessContextMatch_prefix)
295                                 acl->ctx_match = 0;
296                         else
297                                 return (SNMP_ERR_WRONG_VALUE);
298                         break;
299
300                 case LEAF_vacmAccessReadViewName:
301                         ctx->scratch->ptr1 = acl->read_view;
302                         acl->read_view = vacm_get_view_by_name(val->v.octetstring.octets, val->v.octetstring.len);
303                         if (acl->read_view == NULL) {
304                                 acl->read_view = ctx->scratch->ptr1;
305                                 return (SNMP_ERR_INCONS_VALUE);
306                         }
307                         return (SNMP_ERR_NOERROR);
308
309                 case LEAF_vacmAccessWriteViewName:
310                         ctx->scratch->ptr1 = acl->write_view;
311                         if ((acl->write_view =
312                             vacm_get_view_by_name(val->v.octetstring.octets,
313                             val->v.octetstring.len)) == NULL) {
314                                 acl->write_view = ctx->scratch->ptr1;
315                                 return (SNMP_ERR_INCONS_VALUE);
316                         }
317                         break;
318
319                 case LEAF_vacmAccessNotifyViewName:
320                         ctx->scratch->ptr1 = acl->notify_view;
321                         if ((acl->notify_view =
322                             vacm_get_view_by_name(val->v.octetstring.octets,
323                             val->v.octetstring.len)) == NULL) {
324                                 acl->notify_view = ctx->scratch->ptr1;
325                                 return (SNMP_ERR_INCONS_VALUE);
326                         }
327                         break;
328
329                 case LEAF_vacmAccessStorageType:
330                         return (SNMP_ERR_INCONS_VALUE);
331
332                 case LEAF_vacmAccessStatus:
333                         if (acl == NULL) {
334                                 if (val->v.integer != RowStatus_createAndGo ||
335                                     vacm_access_rule_index_decode(&val->var,
336                                     sub, gname, cprefix, &smodel, &slevel) < 0)
337                                         return (SNMP_ERR_INCONS_VALUE);
338                                 if ((acl = vacm_new_access_rule(gname, cprefix,
339                                     smodel, slevel)) == NULL)
340                                         return (SNMP_ERR_GENERR);
341                                 acl->status = RowStatus_destroy;
342                                 if (community != COMM_INITIALIZE)
343                                         acl->type = StorageType_volatile;
344                                 else
345                                         acl->type = StorageType_readOnly;
346                         } else if (val->v.integer != RowStatus_active &&
347                             val->v.integer != RowStatus_destroy)
348                                 return (SNMP_ERR_INCONS_VALUE);
349                         ctx->scratch->int1 = acl->status;
350                         acl->status = val->v.integer;
351                         break;
352                 }
353                 return (SNMP_ERR_NOERROR);
354
355         case SNMP_OP_COMMIT:
356                 if (val->var.subs[sub - 1] != LEAF_vacmAccessStatus)
357                         return (SNMP_ERR_NOERROR);
358                 if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
359                         return (SNMP_ERR_GENERR);
360                 if (val->v.integer == RowStatus_destroy)
361                         return (vacm_delete_access_rule(acl));
362                 else
363                         acl->status = RowStatus_active;
364                 return (SNMP_ERR_NOERROR);
365
366         case SNMP_OP_ROLLBACK:
367                 if ((acl = vacm_get_access_rule(&val->var, sub)) == NULL)
368                         return (SNMP_ERR_GENERR);
369                 switch (val->var.subs[sub - 1]) {
370                 case LEAF_vacmAccessContextMatch:
371                         acl->ctx_match = ctx->scratch->int1;
372                         break;
373                 case LEAF_vacmAccessReadViewName:
374                         acl->read_view = ctx->scratch->ptr1;
375                         break;
376                 case LEAF_vacmAccessWriteViewName:
377                         acl->write_view = ctx->scratch->ptr1;
378                         break;
379                 case LEAF_vacmAccessNotifyViewName:
380                         acl->notify_view = ctx->scratch->ptr1;
381                         break;
382                 case LEAF_vacmAccessStatus:
383                         if (ctx->scratch->int1 == RowStatus_destroy)
384                                 return (vacm_delete_access_rule(acl));
385                 default:
386                         break;
387                 }
388                 return (SNMP_ERR_NOERROR);
389
390         default:
391                 abort();
392         }
393
394         switch (val->var.subs[sub - 1]) {
395         case LEAF_vacmAccessContextMatch:
396                 return (string_get(val, acl->ctx_prefix, -1));
397         case LEAF_vacmAccessReadViewName:
398                 if (acl->read_view != NULL)
399                         return (string_get(val, acl->read_view->viewname, -1));
400                 else
401                         return (string_get(val, NULL, 0));
402         case LEAF_vacmAccessWriteViewName:
403                 if (acl->write_view != NULL)
404                         return (string_get(val, acl->write_view->viewname, -1));
405                 else
406                         return (string_get(val, NULL, 0));
407         case LEAF_vacmAccessNotifyViewName:
408                 if (acl->notify_view != NULL)
409                         return (string_get(val, acl->notify_view->viewname, -1));
410                 else
411                         return (string_get(val, NULL, 0));
412         case LEAF_vacmAccessStorageType:
413                 val->v.integer = acl->type;
414                 break;
415         case LEAF_vacmAccessStatus:
416                 val->v.integer = acl->status;
417                 break;
418         default:
419                 abort();
420         }
421
422         return (SNMP_ERR_NOERROR);
423 }
424
425 int
426 op_vacm_view_lock(struct snmp_context *ctx __unused, struct snmp_value *val,
427     uint32_t sub, uint32_t iidx __unused, enum snmp_op op)
428 {
429         if (val->var.subs[sub - 1] != LEAF_vacmViewSpinLock)
430                 return (SNMP_ERR_NOSUCHNAME);
431
432         switch (op) {
433         case SNMP_OP_GET:
434                 if (++vacm_lock == INT32_MAX)
435                         vacm_lock = 0;
436                 val->v.integer = vacm_lock;
437                 break;
438
439         case SNMP_OP_GETNEXT:
440                 abort();
441
442         case SNMP_OP_SET:
443                 if (val->v.integer != vacm_lock)
444                         return (SNMP_ERR_INCONS_VALUE);
445                 break;
446
447         case SNMP_OP_ROLLBACK:
448                 /* FALLTHROUGH */
449         case SNMP_OP_COMMIT:
450                 break;
451         }
452
453         return (SNMP_ERR_NOERROR);
454 }
455
456 int
457 op_vacm_view(struct snmp_context *ctx, struct snmp_value *val, uint32_t sub,
458     uint32_t iidx __unused, enum snmp_op op)
459 {
460         char vname[SNMP_ADM_STR32_SIZ];
461         struct asn_oid oid;
462         struct vacm_view *view;
463
464         switch (op) {
465         case SNMP_OP_GET:
466                 if ((view = vacm_get_view(&val->var, sub)) == NULL)
467                         return (SNMP_ERR_NOSUCHNAME);
468                 break;
469
470         case SNMP_OP_GETNEXT:
471                 if ((view = vacm_get_next_view(&val->var, sub)) == NULL)
472                         return (SNMP_ERR_NOSUCHNAME);
473                 vacm_append_viewindex(&val->var, sub, view);
474                 break;
475
476         case SNMP_OP_SET:
477                 if ((view = vacm_get_view(&val->var, sub)) == NULL &&
478                     val->var.subs[sub - 1] != LEAF_vacmViewTreeFamilyStatus)
479                                 return (SNMP_ERR_NOSUCHNAME);
480
481                 if (view != NULL) {
482                         if (community != COMM_INITIALIZE &&
483                             view->type == StorageType_readOnly)
484                                 return (SNMP_ERR_NOT_WRITEABLE);
485                         if (view->status == RowStatus_active &&
486                             val->v.integer != RowStatus_destroy)
487                                 return (SNMP_ERR_INCONS_VALUE);
488                 }
489
490                 switch (val->var.subs[sub - 1]) {
491                 case LEAF_vacmViewTreeFamilyMask:
492                         if (val->v.octetstring.len > sizeof(view->mask))
493                         ctx->scratch->ptr1 = malloc(sizeof(view->mask));
494                         if (ctx->scratch->ptr1 == NULL)
495                                 return (SNMP_ERR_GENERR);
496                         memset(ctx->scratch->ptr1, 0, sizeof(view->mask));
497                         memcpy(ctx->scratch->ptr1, view->mask,
498                             sizeof(view->mask));
499                         memset(view->mask, 0, sizeof(view->mask));
500                         memcpy(view->mask, val->v.octetstring.octets,
501                             val->v.octetstring.len);
502                         break;
503
504                 case LEAF_vacmViewTreeFamilyType:
505                         ctx->scratch->int1 = view->exclude;
506                         if (val->v.integer == vacmViewTreeFamilyType_included)
507                                 view->exclude = 0;
508                         else if (val->v.integer == vacmViewTreeFamilyType_excluded)
509                                 view->exclude = 1;
510                         else
511                                 return (SNMP_ERR_WRONG_VALUE);
512                         break;
513
514                 case LEAF_vacmViewTreeFamilyStorageType:
515                         return (SNMP_ERR_INCONS_VALUE);
516
517                 case LEAF_vacmViewTreeFamilyStatus:
518                         if (view == NULL) {
519                                 if (val->v.integer != RowStatus_createAndGo ||
520                                     vacm_view_index_decode(&val->var, sub, vname,
521                                     &oid) < 0)
522                                         return (SNMP_ERR_INCONS_VALUE);
523                                 if ((view = vacm_new_view(vname, &oid)) == NULL)
524                                         return (SNMP_ERR_GENERR);
525                                 view->status = RowStatus_destroy;
526                                 if (community != COMM_INITIALIZE)
527                                         view->type = StorageType_volatile;
528                                 else
529                                         view->type = StorageType_readOnly;
530                         } else if (val->v.integer != RowStatus_active &&
531                             val->v.integer != RowStatus_destroy)
532                                 return (SNMP_ERR_INCONS_VALUE);
533                         ctx->scratch->int1 = view->status;
534                         view->status = val->v.integer;
535                         break;
536                 }
537                 return (SNMP_ERR_NOERROR);
538
539         case SNMP_OP_COMMIT:
540                 switch (val->var.subs[sub - 1]) {
541                 case LEAF_vacmViewTreeFamilyMask:
542                         free(ctx->scratch->ptr1);
543                         break;
544                 case LEAF_vacmViewTreeFamilyStatus:
545                         if ((view = vacm_get_view(&val->var, sub)) == NULL)
546                                 return (SNMP_ERR_GENERR);
547                         switch (val->v.integer) {
548                         case  RowStatus_destroy:
549                                 return (vacm_delete_view(view));
550
551                         case RowStatus_createAndGo:
552                                 view->status = RowStatus_active;
553                                 break;
554
555                         default:
556                                 /* NOTREACHED*/
557                                 return (SNMP_ERR_GENERR);
558                         }
559                 default:
560                         break;
561                 }
562                 return (SNMP_ERR_NOERROR);
563
564         case SNMP_OP_ROLLBACK:
565                 if ((view = vacm_get_view(&val->var, sub)) == NULL)
566                         return (SNMP_ERR_GENERR);
567                 switch (val->var.subs[sub - 1]) {
568                 case LEAF_vacmViewTreeFamilyMask:
569                         memcpy(view->mask, ctx->scratch->ptr1,
570                             sizeof(view->mask));
571                         free(ctx->scratch->ptr1);
572                         break;
573                 case LEAF_vacmViewTreeFamilyType:
574                         view->exclude = ctx->scratch->int1;
575                         break;
576                 case LEAF_vacmViewTreeFamilyStatus:
577                         if (ctx->scratch->int1 == RowStatus_destroy)
578                                 return (vacm_delete_view(view));
579                         break;
580                 default:
581                         break;  
582                 }
583                 return (SNMP_ERR_NOERROR);
584
585         default:
586                 abort();
587         }
588
589         switch (val->var.subs[sub - 1]) {
590         case LEAF_vacmViewTreeFamilyMask:
591                 return (string_get(val, view->mask, sizeof(view->mask)));
592         case LEAF_vacmViewTreeFamilyType:
593                 if (view->exclude)
594                         val->v.integer = vacmViewTreeFamilyType_excluded;
595                 else
596                         val->v.integer = vacmViewTreeFamilyType_included;
597                 break;
598         case LEAF_vacmViewTreeFamilyStorageType:
599                 val->v.integer = view->type;
600                 break;
601         case LEAF_vacmViewTreeFamilyStatus:
602                 val->v.integer = view->status;
603                 break;
604         default:
605                 abort();
606         }
607
608         return (SNMP_ERR_NOERROR);
609 }
610
611 static void
612 vacm_append_userindex(struct asn_oid *oid, uint sub,
613     const struct vacm_user *user)
614 {
615         uint32_t i;
616
617         oid->len = sub + strlen(user->secname) + 2;
618         oid->subs[sub++] = user->sec_model;
619         oid->subs[sub] = strlen(user->secname);
620         for (i = 1; i <= strlen(user->secname); i++)
621                 oid->subs[sub + i] = user->secname[i - 1];
622 }
623
624 static int
625 vacm_user_index_decode(const struct asn_oid *oid, uint sub,
626     int32_t *smodel, char *uname)
627 {
628         uint32_t i;
629
630         *smodel = oid->subs[sub++];
631
632         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
633                 return (-1);
634
635         for (i = 0; i < oid->subs[sub]; i++)
636                 uname[i] = oid->subs[sub + i + 1];
637         uname[i] = '\0';
638
639         return (0);
640 }
641
642 static struct vacm_user *
643 vacm_get_user(const struct asn_oid *oid, uint sub)
644 {
645         int32_t smodel;
646         char uname[SNMP_ADM_STR32_SIZ];
647         struct vacm_user *user;
648
649         if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
650                 return (NULL);
651
652         for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
653                 if (strcmp(uname, user->secname) == 0 &&
654                     user->sec_model == smodel)
655                         return (user);
656
657         return (NULL);
658 }
659
660 static struct vacm_user *
661 vacm_get_next_user(const struct asn_oid *oid, uint sub)
662 {
663         int32_t smodel;
664         char uname[SNMP_ADM_STR32_SIZ];
665         struct vacm_user *user;
666
667         if (oid->len - sub == 0)
668                 return (vacm_first_user());
669
670         if (vacm_user_index_decode(oid, sub, &smodel, uname) < 0)
671                 return (NULL);
672
673         for (user = vacm_first_user(); user != NULL; user = vacm_next_user(user))
674                 if (strcmp(uname, user->secname) == 0 &&
675                     user->sec_model == smodel)
676                         return (vacm_next_user(user));
677
678         return (NULL);
679 }
680
681 static void
682 vacm_append_access_rule_index(struct asn_oid *oid, uint sub,
683     const struct vacm_access *acl)
684 {
685         uint32_t i;
686   
687         oid->len = sub + strlen(acl->group->groupname) +
688             strlen(acl->ctx_prefix) + 4;
689
690         oid->subs[sub] = strlen(acl->group->groupname);
691         for (i = 1; i <= strlen(acl->group->groupname); i++)
692                 oid->subs[sub + i] = acl->group->groupname[i - 1];
693         sub += strlen(acl->group->groupname) + 1;
694
695         oid->subs[sub] = strlen(acl->ctx_prefix);
696         for (i = 1; i <= strlen(acl->ctx_prefix); i++)
697                 oid->subs[sub + i] = acl->ctx_prefix[i - 1];
698         sub += strlen(acl->ctx_prefix) + 1;
699         oid->subs[sub++] = acl->sec_model;
700         oid->subs[sub] = acl->sec_level;
701 }
702
703 static int
704 vacm_access_rule_index_decode(const struct asn_oid *oid, uint sub, char *gname,
705     char *cprefix, int32_t *smodel, int32_t *slevel)
706 {
707         uint32_t i;
708
709         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
710                 return (-1);
711
712         for (i = 0; i < oid->subs[sub]; i++)
713                 gname[i] = oid->subs[sub + i + 1];
714         gname[i] = '\0';
715         sub += strlen(gname) + 1;
716
717         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
718                 return (-1);
719
720         for (i = 0; i < oid->subs[sub]; i++)
721                 cprefix[i] = oid->subs[sub + i + 1];
722         cprefix[i] = '\0';
723         sub += strlen(cprefix) + 1;
724
725         *smodel = oid->subs[sub++];
726         *slevel = oid->subs[sub];
727
728         return (0);
729 }
730
731 struct vacm_access *
732 vacm_get_access_rule(const struct asn_oid *oid, uint sub)
733 {
734         int32_t smodel, slevel;
735         char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
736         struct vacm_access *acl;
737
738         if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
739             &slevel) < 0)
740                 return (NULL);
741
742         for (acl = vacm_first_access_rule(); acl != NULL;
743             acl = vacm_next_access_rule(acl))
744                 if (strcmp(gname, acl->group->groupname) == 0 &&
745                     strcmp(prefix, acl->ctx_prefix) == 0 &&
746                     smodel == acl->sec_model && slevel == acl->sec_level)
747                         return (acl);
748
749         return (NULL);
750 }
751
752 struct vacm_access *
753 vacm_get_next_access_rule(const struct asn_oid *oid __unused, uint sub __unused)
754 {
755         int32_t smodel, slevel;
756         char gname[SNMP_ADM_STR32_SIZ], prefix[SNMP_ADM_STR32_SIZ];
757         struct vacm_access *acl;
758
759         if (oid->len - sub == 0)
760                 return (vacm_first_access_rule());
761
762         if (vacm_access_rule_index_decode(oid, sub, gname, prefix, &smodel,
763             &slevel) < 0)
764                 return (NULL);
765
766         for (acl = vacm_first_access_rule(); acl != NULL;
767             acl = vacm_next_access_rule(acl))
768                 if (strcmp(gname, acl->group->groupname) == 0 &&
769                     strcmp(prefix, acl->ctx_prefix) == 0 &&
770                     smodel == acl->sec_model && slevel == acl->sec_model)
771                         return (vacm_next_access_rule(acl));
772
773         return (NULL);
774 }
775
776 static int
777 vacm_view_index_decode(const struct asn_oid *oid, uint sub, char *vname,
778    struct asn_oid *view_oid)
779 {       
780         uint32_t i;
781         int viod_off;
782
783         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
784                 return (-1);
785
786         for (i = 0; i < oid->subs[sub]; i++)
787                 vname[i] = oid->subs[sub + i + 1];
788         vname[i] = '\0';
789
790         viod_off = sub + oid->subs[sub] + 1;
791         if ((view_oid->len = oid->subs[viod_off]) > ASN_MAXOIDLEN)
792                 return (-1);
793
794         memcpy(&view_oid->subs[0], &oid->subs[viod_off + 1],
795             view_oid->len * sizeof(view_oid->subs[0]));
796
797         return (0);
798 }
799
800 static void
801 vacm_append_viewindex(struct asn_oid *oid, uint sub, const struct vacm_view *view)
802 {
803         uint32_t i;
804
805         oid->len = sub + strlen(view->viewname) + 1;
806         oid->subs[sub] = strlen(view->viewname);
807         for (i = 1; i <= strlen(view->viewname); i++)
808                 oid->subs[sub + i] = view->viewname[i - 1];
809
810         sub += strlen(view->viewname) + 1;
811         oid->subs[sub] = view->subtree.len;
812         oid->len++;
813         asn_append_oid(oid, &view->subtree);
814 }
815
816 struct vacm_view *
817 vacm_get_view(const struct asn_oid *oid, uint sub)
818 {
819         char vname[SNMP_ADM_STR32_SIZ];
820         struct asn_oid subtree;
821         struct vacm_view *view;
822
823         if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
824                 return (NULL);
825
826         for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
827                 if (strcmp(vname, view->viewname) == 0 &&
828                     asn_compare_oid(&subtree, &view->subtree)== 0)
829                         return (view);
830
831         return (NULL);
832 }
833
834 struct vacm_view *
835 vacm_get_next_view(const struct asn_oid *oid, uint sub)
836 {
837         char vname[SNMP_ADM_STR32_SIZ];
838         struct asn_oid subtree;
839         struct vacm_view *view;
840
841         if (oid->len - sub == 0)
842                 return (vacm_first_view());
843
844         if (vacm_view_index_decode(oid, sub, vname, &subtree) < 0)
845                 return (NULL);
846
847         for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
848                 if (strcmp(vname, view->viewname) == 0 &&
849                     asn_compare_oid(&subtree, &view->subtree)== 0)
850                         return (vacm_next_view(view));
851
852         return (NULL);
853 }
854
855 static struct vacm_view *
856 vacm_get_view_by_name(u_char *octets, u_int len)
857 {
858         struct vacm_view *view;
859
860         for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
861                 if (strlen(view->viewname) == len &&
862                     memcmp(octets, view->viewname, len) == 0)
863                         return (view);
864
865         return (NULL);
866 }
867
868 static struct vacm_context *
869 vacm_get_context(const struct asn_oid *oid, uint sub)
870 {
871         char cname[SNMP_ADM_STR32_SIZ];
872         size_t cnamelen;
873         u_int index_count;
874         struct vacm_context *vacm_ctx;
875
876         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
877                 return (NULL);
878
879         index_count = 0;
880         index_count = SNMP_INDEX(index_count, 1);
881         if (index_decode(oid, sub, index_count, &cname, &cnamelen))
882                 return (NULL);
883
884         for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
885             vacm_ctx = vacm_next_context(vacm_ctx))
886                 if (strcmp(cname, vacm_ctx->ctxname) == 0)
887                         return (vacm_ctx);
888
889         return (NULL);
890 }
891
892 static struct vacm_context *
893 vacm_get_next_context(const struct asn_oid *oid, uint sub)
894 {
895         char cname[SNMP_ADM_STR32_SIZ];
896         size_t cnamelen;
897         u_int index_count;
898         struct vacm_context *vacm_ctx;
899
900         if (oid->len - sub == 0)
901                 return (vacm_first_context());
902
903         if (oid->subs[sub] >= SNMP_ADM_STR32_SIZ)
904                 return (NULL);
905
906         index_count = 0;
907         index_count = SNMP_INDEX(index_count, 1);
908         if (index_decode(oid, sub, index_count, &cname, &cnamelen))
909                 return (NULL);
910
911         for (vacm_ctx = vacm_first_context(); vacm_ctx != NULL;
912             vacm_ctx = vacm_next_context(vacm_ctx))
913                 if (strcmp(cname, vacm_ctx->ctxname) == 0)
914                         return (vacm_next_context(vacm_ctx));
915
916         return (NULL);
917 }
918
919 static void
920 vacm_append_ctxindex(struct asn_oid *oid, uint sub,
921     const struct vacm_context *ctx)
922 {
923         uint32_t i;
924
925         oid->len = sub + strlen(ctx->ctxname) + 1;
926         oid->subs[sub] = strlen(ctx->ctxname);
927         for (i = 1; i <= strlen(ctx->ctxname); i++)
928                 oid->subs[sub + i] = ctx->ctxname[i - 1];
929 }
930
931 /*
932  * VACM snmp module initialization hook.
933  * Returns 0 on success, < 0 on error.
934  */
935 static int
936 vacm_init(struct lmodule *mod, int argc __unused, char *argv[] __unused)
937 {
938         vacm_module = mod;
939         vacm_lock = random();
940         vacm_groups_init();
941
942         /* XXX: TODO - initialize structures */
943         return (0);
944 }
945
946 /*
947  * VACM snmp module finalization hook.
948  */
949 static int
950 vacm_fini(void)
951 {
952         /* XXX: TODO - cleanup */
953         vacm_flush_contexts(reg_vacm);
954         or_unregister(reg_vacm);
955
956         return (0);
957 }
958
959 /*
960  * VACM snmp module start operation.
961  */
962 static void
963 vacm_start(void)
964 {
965         static char dflt_ctx[] = "";
966
967         reg_vacm = or_register(&oid_vacm,
968             "The MIB module for managing SNMP View-based Access Control Model.",
969             vacm_module);
970
971         (void)vacm_add_context(dflt_ctx, reg_vacm);
972 }
973
974 static void
975 vacm_dump(void)
976 {
977         struct vacm_context *vacmctx;
978         struct vacm_user *vuser;
979         struct vacm_access *vacl;
980         struct vacm_view *view;
981         static char oidbuf[ASN_OIDSTRLEN];
982
983         syslog(LOG_ERR, "\n");
984         syslog(LOG_ERR, "Context list:");
985         for (vacmctx = vacm_first_context(); vacmctx != NULL;
986             vacmctx = vacm_next_context(vacmctx))
987                 syslog(LOG_ERR, "Context \"%s\", module id %d",
988                     vacmctx->ctxname, vacmctx->regid);
989
990         syslog(LOG_ERR, "VACM users:");
991         for (vuser = vacm_first_user(); vuser != NULL;
992             vuser = vacm_next_user(vuser))
993                 syslog(LOG_ERR, "Uname %s, Group %s, model %d", vuser->secname,
994                     vuser->group!= NULL?vuser->group->groupname:"Unknown",
995                     vuser->sec_model);
996
997         syslog(LOG_ERR, "VACM Access rules:");
998         for (vacl = vacm_first_access_rule(); vacl != NULL;
999             vacl = vacm_next_access_rule(vacl))
1000                 syslog(LOG_ERR, "Group %s, CtxPrefix %s, Model %d, Level %d, "
1001                     "RV %s, WR %s, NV %s", vacl->group!=NULL?
1002                     vacl->group->groupname:"Unknown", vacl->ctx_prefix,
1003                     vacl->sec_model, vacl->sec_level, vacl->read_view!=NULL?
1004                     vacl->read_view->viewname:"None", vacl->write_view!=NULL?
1005                     vacl->write_view->viewname:"None", vacl->notify_view!=NULL?
1006                     vacl->notify_view->viewname:"None");
1007
1008         syslog(LOG_ERR, "VACM Views:");
1009         for (view = vacm_first_view(); view != NULL; view = vacm_next_view(view))
1010                 syslog(LOG_ERR, "View %s, Tree %s - %s", view->viewname,
1011                     asn_oid2str_r(&view->subtree, oidbuf), view->exclude?
1012                     "excluded":"included");
1013 }
1014
1015 const char vacm_comment[] = \
1016 "This module implements SNMP View-based Access Control Model defined in RFC 3415.";
1017
1018 const struct snmp_module config = {
1019         .comment =      vacm_comment,
1020         .init =         vacm_init,
1021         .fini =         vacm_fini,
1022         .start =        vacm_start,
1023         .tree =         vacm_ctree,
1024         .dump =         vacm_dump,
1025         .tree_size =    vacm_CTREE_SIZE,
1026 };