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