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 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 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