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 "target_tree.h" 47 #include "target_oid.h" 48 49 static struct lmodule *target_module; 50 /* For the registration. */ 51 static const struct asn_oid oid_target = OIDX_snmpTargetMIB; 52 static const struct asn_oid oid_notification = OIDX_snmpNotificationMIB; 53 54 static uint reg_target; 55 static uint reg_notification; 56 57 static int32_t target_lock; 58 59 static const struct asn_oid oid_udp_domain = OIDX_snmpUDPDomain; 60 61 /* 62 * Internal datastructures and forward declarations. 63 */ 64 static void target_append_index(struct asn_oid *, uint, 65 const char *); 66 static int target_decode_index(const struct asn_oid *, uint, 67 char *); 68 static struct target_address *target_get_address(const struct asn_oid *, 69 uint); 70 static struct target_address *target_get_next_address(const struct asn_oid *, 71 uint); 72 static struct target_param *target_get_param(const struct asn_oid *, 73 uint); 74 static struct target_param *target_get_next_param(const struct asn_oid *, 75 uint); 76 static struct target_notify *target_get_notify(const struct asn_oid *, 77 uint); 78 static struct target_notify *target_get_next_notify(const struct asn_oid *, 79 uint); 80 81 int 82 op_snmp_target(struct snmp_context *ctx __unused, struct snmp_value *val, 83 uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 84 { 85 struct snmpd_target_stats *ctx_stats; 86 87 if (val->var.subs[sub - 1] == LEAF_snmpTargetSpinLock) { 88 switch (op) { 89 case SNMP_OP_GET: 90 if (++target_lock == INT32_MAX) 91 target_lock = 0; 92 val->v.integer = target_lock; 93 break; 94 case SNMP_OP_GETNEXT: 95 abort(); 96 case SNMP_OP_SET: 97 if (val->v.integer != target_lock) 98 return (SNMP_ERR_INCONS_VALUE); 99 break; 100 case SNMP_OP_ROLLBACK: 101 /* FALLTHROUGH */ 102 case SNMP_OP_COMMIT: 103 break; 104 } 105 return (SNMP_ERR_NOERROR); 106 } else if (op == SNMP_OP_SET) 107 return (SNMP_ERR_NOT_WRITEABLE); 108 109 if ((ctx_stats = bsnmpd_get_target_stats()) == NULL) 110 return (SNMP_ERR_GENERR); 111 112 if (op == SNMP_OP_GET) { 113 switch (val->var.subs[sub - 1]) { 114 case LEAF_snmpUnavailableContexts: 115 val->v.uint32 = ctx_stats->unavail_contexts; 116 break; 117 case LEAF_snmpUnknownContexts: 118 val->v.uint32 = ctx_stats->unknown_contexts; 119 break; 120 default: 121 return (SNMP_ERR_NOSUCHNAME); 122 } 123 return (SNMP_ERR_NOERROR); 124 } 125 abort(); 126 } 127 128 int 129 op_snmp_target_addrs(struct snmp_context *ctx __unused, struct snmp_value *val, 130 uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 131 { 132 char aname[SNMP_ADM_STR32_SIZ]; 133 struct target_address *addrs; 134 135 switch (op) { 136 case SNMP_OP_GET: 137 if ((addrs = target_get_address(&val->var, sub)) == NULL) 138 return (SNMP_ERR_NOSUCHNAME); 139 break; 140 141 case SNMP_OP_GETNEXT: 142 if ((addrs = target_get_next_address(&val->var, sub)) == NULL) 143 return (SNMP_ERR_NOSUCHNAME); 144 target_append_index(&val->var, sub, addrs->name); 145 break; 146 147 case SNMP_OP_SET: 148 if ((addrs = target_get_address(&val->var, sub)) == NULL && 149 (val->var.subs[sub - 1] != LEAF_snmpTargetAddrRowStatus || 150 val->v.integer != RowStatus_createAndWait)) 151 return (SNMP_ERR_NOSUCHNAME); 152 153 if (addrs != NULL) { 154 if (community != COMM_INITIALIZE && 155 addrs->type == StorageType_readOnly) 156 return (SNMP_ERR_NOT_WRITEABLE); 157 if (addrs->status == RowStatus_active && 158 val->v.integer != RowStatus_destroy) 159 return (SNMP_ERR_INCONS_VALUE); 160 } 161 162 switch (val->var.subs[sub - 1]) { 163 case LEAF_snmpTargetAddrTDomain: 164 return (SNMP_ERR_INCONS_VALUE); 165 case LEAF_snmpTargetAddrTAddress: 166 if (val->v.octetstring.len != SNMP_UDP_ADDR_SIZ) 167 return (SNMP_ERR_INCONS_VALUE); 168 ctx->scratch->ptr1 = malloc(SNMP_UDP_ADDR_SIZ); 169 if (ctx->scratch->ptr1 == NULL) 170 return (SNMP_ERR_GENERR); 171 memcpy(ctx->scratch->ptr1, addrs->address, 172 SNMP_UDP_ADDR_SIZ); 173 memcpy(addrs->address, val->v.octetstring.octets, 174 SNMP_UDP_ADDR_SIZ); 175 break; 176 177 case LEAF_snmpTargetAddrTagList: 178 if (val->v.octetstring.len >= SNMP_TAG_SIZ) 179 return (SNMP_ERR_INCONS_VALUE); 180 ctx->scratch->int1 = strlen(addrs->taglist) + 1; 181 ctx->scratch->ptr1 = malloc(ctx->scratch->int1); 182 if (ctx->scratch->ptr1 == NULL) 183 return (SNMP_ERR_GENERR); 184 strlcpy(ctx->scratch->ptr1, addrs->taglist, 185 ctx->scratch->int1); 186 memcpy(addrs->taglist, val->v.octetstring.octets, 187 val->v.octetstring.len); 188 addrs->taglist[val->v.octetstring.len] = '\0'; 189 break; 190 191 case LEAF_snmpTargetAddrParams: 192 if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ) 193 return (SNMP_ERR_INCONS_VALUE); 194 ctx->scratch->int1 = strlen(addrs->paramname) + 1; 195 ctx->scratch->ptr1 = malloc(ctx->scratch->int1); 196 if (ctx->scratch->ptr1 == NULL) 197 return (SNMP_ERR_GENERR); 198 strlcpy(ctx->scratch->ptr1, addrs->paramname, 199 ctx->scratch->int1); 200 memcpy(addrs->paramname, val->v.octetstring.octets, 201 val->v.octetstring.len); 202 addrs->paramname[val->v.octetstring.len] = '\0'; 203 break; 204 205 case LEAF_snmpTargetAddrRetryCount: 206 ctx->scratch->int1 = addrs->retry; 207 addrs->retry = val->v.integer; 208 break; 209 210 case LEAF_snmpTargetAddrTimeout: 211 ctx->scratch->int1 = addrs->timeout; 212 addrs->timeout = val->v.integer / 10; 213 break; 214 215 case LEAF_snmpTargetAddrStorageType: 216 return (SNMP_ERR_INCONS_VALUE); 217 218 case LEAF_snmpTargetAddrRowStatus: 219 if (addrs != NULL) { 220 if (val->v.integer != RowStatus_active && 221 val->v.integer != RowStatus_destroy) 222 return (SNMP_ERR_INCONS_VALUE); 223 if (val->v.integer == RowStatus_active && 224 (addrs->address[0] == 0 || 225 strlen(addrs->taglist) == 0 || 226 strlen(addrs->paramname) == 0)) 227 return (SNMP_ERR_INCONS_VALUE); 228 ctx->scratch->int1 = addrs->status; 229 addrs->status = val->v.integer; 230 return (SNMP_ERR_NOERROR); 231 } 232 if (val->v.integer != RowStatus_createAndWait || 233 target_decode_index(&val->var, sub, aname) < 0) 234 return (SNMP_ERR_INCONS_VALUE); 235 if ((addrs = target_new_address(aname)) == NULL) 236 return (SNMP_ERR_GENERR); 237 addrs->status = RowStatus_destroy; 238 if (community != COMM_INITIALIZE) 239 addrs->type = StorageType_volatile; 240 else 241 addrs->type = StorageType_readOnly; 242 break; 243 } 244 return (SNMP_ERR_NOERROR); 245 246 case SNMP_OP_COMMIT: 247 switch (val->var.subs[sub - 1]) { 248 case LEAF_snmpTargetAddrTAddress: 249 case LEAF_snmpTargetAddrTagList: 250 case LEAF_snmpTargetAddrParams: 251 free(ctx->scratch->ptr1); 252 break; 253 case LEAF_snmpTargetAddrRowStatus: 254 if ((addrs = target_get_address(&val->var, sub)) == NULL) 255 return (SNMP_ERR_GENERR); 256 if (val->v.integer == RowStatus_destroy) 257 return (target_delete_address(addrs)); 258 else if (val->v.integer == RowStatus_active) 259 return (target_activate_address(addrs)); 260 break; 261 default: 262 break; 263 } 264 return (SNMP_ERR_NOERROR); 265 266 case SNMP_OP_ROLLBACK: 267 if ((addrs = target_get_address(&val->var, sub)) == NULL) 268 return (SNMP_ERR_GENERR); 269 270 switch (val->var.subs[sub - 1]) { 271 case LEAF_snmpTargetAddrTAddress: 272 memcpy(addrs->address, ctx->scratch->ptr1, 273 SNMP_UDP_ADDR_SIZ); 274 free(ctx->scratch->ptr1); 275 break; 276 277 case LEAF_snmpTargetAddrTagList: 278 strlcpy(addrs->taglist, ctx->scratch->ptr1, 279 ctx->scratch->int1); 280 free(ctx->scratch->ptr1); 281 break; 282 283 case LEAF_snmpTargetAddrParams: 284 strlcpy(addrs->paramname, ctx->scratch->ptr1, 285 ctx->scratch->int1); 286 free(ctx->scratch->ptr1); 287 break; 288 289 case LEAF_snmpTargetAddrRetryCount: 290 addrs->retry = ctx->scratch->int1; 291 break; 292 293 case LEAF_snmpTargetAddrTimeout: 294 addrs->timeout = ctx->scratch->int1; 295 break; 296 297 case LEAF_snmpTargetAddrRowStatus: 298 if (ctx->scratch->int1 == RowStatus_destroy) 299 return (target_delete_address(addrs)); 300 break; 301 default: 302 break; 303 } 304 return (SNMP_ERR_NOERROR); 305 306 default: 307 abort(); 308 } 309 310 switch (val->var.subs[sub - 1]) { 311 case LEAF_snmpTargetAddrTDomain: 312 return (oid_get(val, &oid_udp_domain)); 313 case LEAF_snmpTargetAddrTAddress: 314 return (string_get(val, addrs->address, SNMP_UDP_ADDR_SIZ)); 315 case LEAF_snmpTargetAddrTimeout: 316 val->v.integer = addrs->timeout; 317 break; 318 case LEAF_snmpTargetAddrRetryCount: 319 val->v.integer = addrs->retry; 320 break; 321 case LEAF_snmpTargetAddrTagList: 322 return (string_get(val, addrs->taglist, -1)); 323 case LEAF_snmpTargetAddrParams: 324 return (string_get(val, addrs->paramname, -1)); 325 case LEAF_snmpTargetAddrStorageType: 326 val->v.integer = addrs->type; 327 break; 328 case LEAF_snmpTargetAddrRowStatus: 329 val->v.integer = addrs->status; 330 break; 331 default: 332 abort(); 333 } 334 335 return (SNMP_ERR_NOERROR); 336 } 337 338 int 339 op_snmp_target_params(struct snmp_context *ctx __unused, struct snmp_value *val, 340 uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 341 { 342 char pname[SNMP_ADM_STR32_SIZ]; 343 struct target_param *param; 344 345 switch (op) { 346 case SNMP_OP_GET: 347 if ((param = target_get_param(&val->var, sub)) == NULL) 348 return (SNMP_ERR_NOSUCHNAME); 349 break; 350 351 case SNMP_OP_GETNEXT: 352 if ((param = target_get_next_param(&val->var, sub)) == NULL) 353 return (SNMP_ERR_NOSUCHNAME); 354 target_append_index(&val->var, sub, param->name); 355 break; 356 357 case SNMP_OP_SET: 358 if ((param = target_get_param(&val->var, sub)) == NULL && 359 (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus || 360 val->v.integer != RowStatus_createAndWait)) 361 return (SNMP_ERR_NOSUCHNAME); 362 363 if (param != NULL) { 364 if (community != COMM_INITIALIZE && 365 param->type == StorageType_readOnly) 366 return (SNMP_ERR_NOT_WRITEABLE); 367 if (param->status == RowStatus_active && 368 val->v.integer != RowStatus_destroy) 369 return (SNMP_ERR_INCONS_VALUE); 370 } 371 372 switch (val->var.subs[sub - 1]) { 373 case LEAF_snmpTargetParamsMPModel: 374 if (val->v.integer != SNMP_MPM_SNMP_V1 && 375 val->v.integer != SNMP_MPM_SNMP_V2c && 376 val->v.integer != SNMP_MPM_SNMP_V3) 377 return (SNMP_ERR_INCONS_VALUE); 378 ctx->scratch->int1 = param->mpmodel; 379 param->mpmodel = val->v.integer; 380 break; 381 382 case LEAF_snmpTargetParamsSecurityModel: 383 if (val->v.integer != SNMP_SECMODEL_SNMPv1 && 384 val->v.integer != SNMP_SECMODEL_SNMPv2c && 385 val->v.integer != SNMP_SECMODEL_USM) 386 return (SNMP_ERR_INCONS_VALUE); 387 ctx->scratch->int1 = param->sec_model; 388 param->sec_model = val->v.integer; 389 break; 390 391 case LEAF_snmpTargetParamsSecurityName: 392 if (val->v.octetstring.len >= SNMP_ADM_STR32_SIZ) 393 return (SNMP_ERR_INCONS_VALUE); 394 ctx->scratch->int1 = strlen(param->secname) + 1; 395 ctx->scratch->ptr1 = malloc(ctx->scratch->int1); 396 if (ctx->scratch->ptr1 == NULL) 397 return (SNMP_ERR_GENERR); 398 strlcpy(ctx->scratch->ptr1, param->secname, 399 ctx->scratch->int1); 400 memcpy(param->secname, val->v.octetstring.octets, 401 val->v.octetstring.len); 402 param->secname[val->v.octetstring.len] = '\0'; 403 break; 404 405 case LEAF_snmpTargetParamsSecurityLevel: 406 if (val->v.integer != SNMP_noAuthNoPriv && 407 val->v.integer != SNMP_authNoPriv && 408 val->v.integer != SNMP_authPriv) 409 return (SNMP_ERR_INCONS_VALUE); 410 ctx->scratch->int1 = param->sec_level; 411 param->sec_level = val->v.integer; 412 break; 413 414 case LEAF_snmpTargetParamsStorageType: 415 return (SNMP_ERR_INCONS_VALUE); 416 417 case LEAF_snmpTargetParamsRowStatus: 418 if (param != NULL) { 419 if (val->v.integer != RowStatus_active && 420 val->v.integer != RowStatus_destroy) 421 return (SNMP_ERR_INCONS_VALUE); 422 if (val->v.integer == RowStatus_active && 423 (param->sec_model == 0 || 424 param->sec_level == 0 || 425 strlen(param->secname) == 0)) 426 return (SNMP_ERR_INCONS_VALUE); 427 ctx->scratch->int1 = param->status; 428 param->status = val->v.integer; 429 return (SNMP_ERR_NOERROR); 430 } 431 if (val->v.integer != RowStatus_createAndWait || 432 target_decode_index(&val->var, sub, pname) < 0) 433 return (SNMP_ERR_INCONS_VALUE); 434 if ((param = target_new_param(pname)) == NULL) 435 return (SNMP_ERR_GENERR); 436 param->status = RowStatus_destroy; 437 if (community != COMM_INITIALIZE) 438 param->type = StorageType_volatile; 439 else 440 param->type = StorageType_readOnly; 441 break; 442 } 443 return (SNMP_ERR_NOERROR); 444 445 case SNMP_OP_COMMIT: 446 switch (val->var.subs[sub - 1]) { 447 case LEAF_snmpTargetParamsSecurityName: 448 free(ctx->scratch->ptr1); 449 break; 450 case LEAF_snmpTargetParamsRowStatus: 451 if ((param = target_get_param(&val->var, sub)) == NULL) 452 return (SNMP_ERR_GENERR); 453 if (val->v.integer == RowStatus_destroy) 454 return (target_delete_param(param)); 455 break; 456 default: 457 break; 458 } 459 return (SNMP_ERR_NOERROR); 460 461 case SNMP_OP_ROLLBACK: 462 if ((param = target_get_param(&val->var, sub)) == NULL && 463 (val->var.subs[sub - 1] != LEAF_snmpTargetParamsRowStatus || 464 val->v.integer != RowStatus_createAndWait)) 465 return (SNMP_ERR_GENERR); 466 switch (val->var.subs[sub - 1]) { 467 case LEAF_snmpTargetParamsMPModel: 468 param->mpmodel = ctx->scratch->int1; 469 break; 470 case LEAF_snmpTargetParamsSecurityModel: 471 param->sec_model = ctx->scratch->int1; 472 break; 473 case LEAF_snmpTargetParamsSecurityName: 474 strlcpy(param->secname, ctx->scratch->ptr1, 475 sizeof(param->secname)); 476 free(ctx->scratch->ptr1); 477 break; 478 case LEAF_snmpTargetParamsSecurityLevel: 479 param->sec_level = ctx->scratch->int1; 480 break; 481 case LEAF_snmpTargetParamsRowStatus: 482 if (ctx->scratch->int1 == RowStatus_destroy) 483 return (target_delete_param(param)); 484 break; 485 default: 486 break; 487 } 488 489 return (SNMP_ERR_NOERROR); 490 491 default: 492 abort(); 493 } 494 495 switch (val->var.subs[sub - 1]) { 496 case LEAF_snmpTargetParamsMPModel: 497 val->v.integer = param->mpmodel; 498 break; 499 case LEAF_snmpTargetParamsSecurityModel: 500 val->v.integer = param->sec_model; 501 break; 502 case LEAF_snmpTargetParamsSecurityName: 503 return (string_get(val, param->secname, -1)); 504 case LEAF_snmpTargetParamsSecurityLevel: 505 val->v.integer = param->sec_level; 506 break; 507 case LEAF_snmpTargetParamsStorageType: 508 val->v.integer = param->type; 509 break; 510 case LEAF_snmpTargetParamsRowStatus: 511 val->v.integer = param->status; 512 break; 513 default: 514 abort(); 515 } 516 517 return (SNMP_ERR_NOERROR); 518 } 519 520 int 521 op_snmp_notify(struct snmp_context *ctx __unused, struct snmp_value *val, 522 uint32_t sub, uint32_t iidx __unused, enum snmp_op op) 523 { 524 char nname[SNMP_ADM_STR32_SIZ]; 525 struct target_notify *notify; 526 527 switch (op) { 528 case SNMP_OP_GET: 529 if ((notify = target_get_notify(&val->var, sub)) == NULL) 530 return (SNMP_ERR_NOSUCHNAME); 531 break; 532 533 case SNMP_OP_GETNEXT: 534 if ((notify = target_get_next_notify(&val->var, sub)) == NULL) 535 return (SNMP_ERR_NOSUCHNAME); 536 target_append_index(&val->var, sub, notify->name); 537 break; 538 539 case SNMP_OP_SET: 540 if ((notify = target_get_notify(&val->var, sub)) == NULL && 541 (val->var.subs[sub - 1] != LEAF_snmpNotifyRowStatus || 542 val->v.integer != RowStatus_createAndGo)) 543 return (SNMP_ERR_NOSUCHNAME); 544 545 if (notify != NULL) { 546 if (community != COMM_INITIALIZE && 547 notify->type == StorageType_readOnly) 548 return (SNMP_ERR_NOT_WRITEABLE); 549 } 550 551 switch (val->var.subs[sub - 1]) { 552 case LEAF_snmpNotifyTag: 553 if (val->v.octetstring.len >= SNMP_TAG_SIZ) 554 return (SNMP_ERR_INCONS_VALUE); 555 ctx->scratch->int1 = strlen(notify->taglist) + 1; 556 ctx->scratch->ptr1 = malloc(ctx->scratch->int1); 557 if (ctx->scratch->ptr1 == NULL) 558 return (SNMP_ERR_GENERR); 559 strlcpy(ctx->scratch->ptr1, notify->taglist, 560 ctx->scratch->int1); 561 memcpy(notify->taglist, val->v.octetstring.octets, 562 val->v.octetstring.len); 563 notify->taglist[val->v.octetstring.len] = '\0'; 564 break; 565 566 case LEAF_snmpNotifyType: 567 /* FALLTHROUGH */ 568 case LEAF_snmpNotifyStorageType: 569 return (SNMP_ERR_INCONS_VALUE); 570 case LEAF_snmpNotifyRowStatus: 571 if (notify != NULL) { 572 if (val->v.integer != RowStatus_active && 573 val->v.integer != RowStatus_destroy) 574 return (SNMP_ERR_INCONS_VALUE); 575 ctx->scratch->int1 = notify->status; 576 notify->status = val->v.integer; 577 return (SNMP_ERR_NOERROR); 578 } 579 if (val->v.integer != RowStatus_createAndGo || 580 target_decode_index(&val->var, sub, nname) < 0) 581 return (SNMP_ERR_INCONS_VALUE); 582 if ((notify = target_new_notify(nname)) == NULL) 583 return (SNMP_ERR_GENERR); 584 notify->status = RowStatus_destroy; 585 if (community != COMM_INITIALIZE) 586 notify->type = StorageType_volatile; 587 else 588 notify->type = StorageType_readOnly; 589 break; 590 } 591 return (SNMP_ERR_NOERROR); 592 593 case SNMP_OP_COMMIT: 594 switch (val->var.subs[sub - 1]) { 595 case LEAF_snmpNotifyTag: 596 free(ctx->scratch->ptr1); 597 break; 598 case LEAF_snmpNotifyRowStatus: 599 notify = target_get_notify(&val->var, sub); 600 if (notify == NULL) 601 return (SNMP_ERR_GENERR); 602 if (val->v.integer == RowStatus_destroy) 603 return (target_delete_notify(notify)); 604 else 605 notify->status = RowStatus_active; 606 break; 607 default: 608 break; 609 } 610 return (SNMP_ERR_NOERROR); 611 612 case SNMP_OP_ROLLBACK: 613 if ((notify = target_get_notify(&val->var, sub)) == NULL) 614 return (SNMP_ERR_GENERR); 615 616 switch (val->var.subs[sub - 1]) { 617 case LEAF_snmpNotifyTag: 618 strlcpy(notify->taglist, ctx->scratch->ptr1, 619 ctx->scratch->int1); 620 free(ctx->scratch->ptr1); 621 break; 622 case LEAF_snmpNotifyRowStatus: 623 if (ctx->scratch->int1 == RowStatus_destroy) 624 return (target_delete_notify(notify)); 625 break; 626 default: 627 break; 628 } 629 return (SNMP_ERR_NOERROR); 630 631 default: 632 abort(); 633 } 634 635 636 switch (val->var.subs[sub - 1]) { 637 case LEAF_snmpNotifyTag: 638 return (string_get(val, notify->taglist, -1)); 639 case LEAF_snmpNotifyType: 640 val->v.integer = snmpNotifyType_trap; 641 break; 642 case LEAF_snmpNotifyStorageType: 643 val->v.integer = notify->type; 644 break; 645 case LEAF_snmpNotifyRowStatus: 646 val->v.integer = notify->status; 647 break; 648 default: 649 abort(); 650 } 651 652 return (SNMP_ERR_NOERROR); 653 } 654 655 static void 656 target_append_index(struct asn_oid *oid, uint sub, const char *name) 657 { 658 uint32_t i; 659 660 oid->len = sub + strlen(name); 661 for (i = 0; i < strlen(name); i++) 662 oid->subs[sub + i] = name[i]; 663 } 664 665 static int 666 target_decode_index(const struct asn_oid *oid, uint sub, char *name) 667 { 668 uint32_t i; 669 670 if (oid->len - sub != oid->subs[sub] + 1 || oid->subs[sub] >= 671 SNMP_ADM_STR32_SIZ) 672 return (-1); 673 674 for (i = 0; i < oid->subs[sub]; i++) 675 name[i] = oid->subs[sub + i + 1]; 676 name[i] = '\0'; 677 678 return (0); 679 } 680 681 static struct target_address * 682 target_get_address(const struct asn_oid *oid, uint sub) 683 { 684 char aname[SNMP_ADM_STR32_SIZ]; 685 struct target_address *addrs; 686 687 if (target_decode_index(oid, sub, aname) < 0) 688 return (NULL); 689 690 for (addrs = target_first_address(); addrs != NULL; 691 addrs = target_next_address(addrs)) 692 if (strcmp(aname, addrs->name) == 0) 693 return (addrs); 694 695 return (NULL); 696 } 697 698 static struct target_address * 699 target_get_next_address(const struct asn_oid * oid, uint sub) 700 { 701 char aname[SNMP_ADM_STR32_SIZ]; 702 struct target_address *addrs; 703 704 if (oid->len - sub == 0) 705 return (target_first_address()); 706 707 if (target_decode_index(oid, sub, aname) < 0) 708 return (NULL); 709 710 for (addrs = target_first_address(); addrs != NULL; 711 addrs = target_next_address(addrs)) 712 if (strcmp(aname, addrs->name) == 0) 713 return (target_next_address(addrs)); 714 715 return (NULL); 716 } 717 718 static struct target_param * 719 target_get_param(const struct asn_oid *oid, uint sub) 720 { 721 char pname[SNMP_ADM_STR32_SIZ]; 722 struct target_param *param; 723 724 if (target_decode_index(oid, sub, pname) < 0) 725 return (NULL); 726 727 for (param = target_first_param(); param != NULL; 728 param = target_next_param(param)) 729 if (strcmp(pname, param->name) == 0) 730 return (param); 731 732 return (NULL); 733 } 734 735 static struct target_param * 736 target_get_next_param(const struct asn_oid *oid, uint sub) 737 { 738 char pname[SNMP_ADM_STR32_SIZ]; 739 struct target_param *param; 740 741 if (oid->len - sub == 0) 742 return (target_first_param()); 743 744 if (target_decode_index(oid, sub, pname) < 0) 745 return (NULL); 746 747 for (param = target_first_param(); param != NULL; 748 param = target_next_param(param)) 749 if (strcmp(pname, param->name) == 0) 750 return (target_next_param(param)); 751 752 return (NULL); 753 } 754 755 static struct target_notify * 756 target_get_notify(const struct asn_oid *oid, uint sub) 757 { 758 char nname[SNMP_ADM_STR32_SIZ]; 759 struct target_notify *notify; 760 761 if (target_decode_index(oid, sub, nname) < 0) 762 return (NULL); 763 764 for (notify = target_first_notify(); notify != NULL; 765 notify = target_next_notify(notify)) 766 if (strcmp(nname, notify->name) == 0) 767 return (notify); 768 769 return (NULL); 770 } 771 772 static struct target_notify * 773 target_get_next_notify(const struct asn_oid *oid, uint sub) 774 { 775 char nname[SNMP_ADM_STR32_SIZ]; 776 struct target_notify *notify; 777 778 if (oid->len - sub == 0) 779 return (target_first_notify()); 780 781 if (target_decode_index(oid, sub, nname) < 0) 782 return (NULL); 783 784 for (notify = target_first_notify(); notify != NULL; 785 notify = target_next_notify(notify)) 786 if (strcmp(nname, notify->name) == 0) 787 return (target_next_notify(notify)); 788 789 return (NULL); 790 } 791 792 static int 793 target_init(struct lmodule *mod, int argc __unused, char *argv[] __unused) 794 { 795 target_module = mod; 796 target_lock = random(); 797 798 return (0); 799 } 800 801 802 static int 803 target_fini(void) 804 { 805 target_flush_all(); 806 or_unregister(reg_target); 807 or_unregister(reg_notification); 808 809 return (0); 810 } 811 812 static void 813 target_start(void) 814 { 815 reg_target = or_register(&oid_target, 816 "The MIB module for managing SNMP Management Targets.", 817 target_module); 818 reg_notification = or_register(&oid_notification, 819 "The MIB module for configuring generation of SNMP notifications.", 820 target_module); 821 } 822 823 static void 824 target_dump(void) 825 { 826 /* XXX: dump the module stats & list of mgmt targets */ 827 } 828 829 static const char target_comment[] = \ 830 "This module implements SNMP Management Target MIB Module defined in RFC 3413."; 831 832 extern const struct snmp_module config; 833 const struct snmp_module config = { 834 .comment = target_comment, 835 .init = target_init, 836 .fini = target_fini, 837 .start = target_start, 838 .tree = target_ctree, 839 .dump = target_dump, 840 .tree_size = target_CTREE_SIZE, 841 }; 842