1 /*-
2 * Copyright (c) 2010,2018 The FreeBSD Foundation
3 *
4 * This software was developed by Shteryana Sotirova Shopova under
5 * sponsorship from the FreeBSD Foundation.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26 * SUCH DAMAGE.
27 *
28 * $FreeBSD$
29 */
30 #include <sys/queue.h>
31 #include <sys/types.h>
32
33 #include <errno.h>
34 #include <stdarg.h>
35 #include <stdlib.h>
36 #include <stdio.h>
37 #include <stdint.h>
38 #include <string.h>
39 #include <syslog.h>
40
41 #include "asn1.h"
42 #include "snmp.h"
43 #include "snmpmod.h"
44
45 #define SNMPTREE_TYPES
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
op_vacm_context(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)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
op_vacm_security_to_group(struct snmp_context * ctx,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)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
op_vacm_access(struct snmp_context * ctx,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)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
op_vacm_view_lock(struct snmp_context * ctx __unused,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)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
op_vacm_view(struct snmp_context * ctx,struct snmp_value * val,uint32_t sub,uint32_t iidx __unused,enum snmp_op op)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
vacm_append_userindex(struct asn_oid * oid,uint sub,const struct vacm_user * user)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
vacm_user_index_decode(const struct asn_oid * oid,uint sub,int32_t * smodel,char * uname)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 *
vacm_get_user(const struct asn_oid * oid,uint sub)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 *
vacm_get_next_user(const struct asn_oid * oid,uint sub)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
vacm_append_access_rule_index(struct asn_oid * oid,uint sub,const struct vacm_access * acl)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
vacm_access_rule_index_decode(const struct asn_oid * oid,uint sub,char * gname,char * cprefix,int32_t * smodel,int32_t * slevel)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 *
vacm_get_access_rule(const struct asn_oid * oid,uint sub)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 *
vacm_get_next_access_rule(const struct asn_oid * oid __unused,uint sub __unused)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
vacm_view_index_decode(const struct asn_oid * oid,uint sub,char * vname,struct asn_oid * view_oid)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
vacm_append_viewindex(struct asn_oid * oid,uint sub,const struct vacm_view * view)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 *
vacm_get_view(const struct asn_oid * oid,uint sub)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 *
vacm_get_next_view(const struct asn_oid * oid,uint sub)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 *
vacm_get_view_by_name(u_char * octets,u_int len)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 *
vacm_get_context(const struct asn_oid * oid,uint sub)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 *
vacm_get_next_context(const struct asn_oid * oid,uint sub)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
vacm_append_ctxindex(struct asn_oid * oid,uint sub,const struct vacm_context * ctx)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
vacm_init(struct lmodule * mod,int argc __unused,char * argv[]__unused)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
vacm_fini(void)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
vacm_start(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
vacm_dump(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 static const char vacm_comment[] =
1016 "This module implements SNMP View-based Access Control Model defined in RFC 3415.";
1017
1018 extern const struct snmp_module config;
1019 const struct snmp_module config = {
1020 .comment = vacm_comment,
1021 .init = vacm_init,
1022 .fini = vacm_fini,
1023 .start = vacm_start,
1024 .tree = vacm_ctree,
1025 .dump = vacm_dump,
1026 .tree_size = vacm_CTREE_SIZE,
1027 };
1028