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