1 /* 2 * Copyright (c) 2001-2003 3 * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4 * All rights reserved. 5 * Copyright (c) 2004-2006 6 * Hartmut Brandt. 7 * All rights reserved. 8 * 9 * Author: Harti Brandt <harti@freebsd.org> 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions 13 * are met: 14 * 1. Redistributions of source code must retain the above copyright 15 * notice, this list of conditions and the following disclaimer. 16 * 2. Redistributions in binary form must reproduce the above copyright 17 * notice, this list of conditions and the following disclaimer in the 18 * documentation and/or other materials provided with the distribution. 19 * 20 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23 * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30 * SUCH DAMAGE. 31 * 32 * $Begemot: action.c 517 2006-10-31 08:52:04Z brandt_h $ 33 * 34 * Variable access for SNMPd 35 */ 36 #include <sys/types.h> 37 #include <sys/sysctl.h> 38 #include <sys/un.h> 39 #include <sys/utsname.h> 40 #include <stdio.h> 41 #include <stdlib.h> 42 #include <stdarg.h> 43 #include <string.h> 44 #include <ctype.h> 45 #include <syslog.h> 46 47 #include "snmpmod.h" 48 #include "snmpd.h" 49 #include "tree.h" 50 #include "oid.h" 51 52 static const struct asn_oid 53 oid_begemotSnmpdModuleTable = OIDX_begemotSnmpdModuleTable; 54 55 #ifdef __FreeBSD__ 56 static const struct asn_oid 57 oid_freeBSDVersion = OIDX_freeBSDVersion; 58 #endif 59 60 /* 61 * Get a string value from the KERN sysctl subtree. 62 */ 63 static char * 64 act_getkernstring(int id) 65 { 66 int mib[2]; 67 size_t len; 68 char *string; 69 70 mib[0] = CTL_KERN; 71 mib[1] = id; 72 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) 73 return (NULL); 74 if ((string = malloc(len)) == NULL) 75 return (NULL); 76 if (sysctl(mib, 2, string, &len, NULL, 0) != 0) { 77 free(string); 78 return (NULL); 79 } 80 return (string); 81 } 82 83 /* 84 * Get an integer value from the KERN sysctl subtree. 85 */ 86 static char * 87 act_getkernint(int id) 88 { 89 int mib[2]; 90 size_t len; 91 u_long value; 92 char *string; 93 94 mib[0] = CTL_KERN; 95 mib[1] = id; 96 len = sizeof(value); 97 if (sysctl(mib, 2, &value, &len, NULL, 0) != 0) 98 return (NULL); 99 100 if ((string = malloc(20)) == NULL) 101 return (NULL); 102 sprintf(string, "%lu", value); 103 return (string); 104 } 105 106 /* 107 * Initialize global variables of the system group. 108 */ 109 int 110 init_actvals(void) 111 { 112 struct utsname uts; 113 char *hostid; 114 size_t len; 115 #ifdef __FreeBSD__ 116 char *rel, *p, *end; 117 u_long num; 118 #endif 119 120 if (uname(&uts) == -1) 121 return (-1); 122 123 if ((systemg.name = strdup(uts.nodename)) == NULL) 124 return (-1); 125 126 if ((hostid = act_getkernint(KERN_HOSTID)) == NULL) 127 return (-1); 128 129 len = strlen(uts.nodename) + 1; 130 len += strlen(hostid) + 1; 131 len += strlen(uts.sysname) + 1; 132 len += strlen(uts.release) + 1; 133 134 if ((systemg.descr = malloc(len)) == NULL) { 135 free(hostid); 136 return (-1); 137 } 138 sprintf(systemg.descr, "%s %s %s %s", uts.nodename, hostid, uts.sysname, 139 uts.release); 140 141 #ifdef __FreeBSD__ 142 /* 143 * Construct a FreeBSD oid 144 */ 145 systemg.object_id = oid_freeBSDVersion; 146 rel = uts.release; 147 while ((p = strsep(&rel, ".")) != NULL && 148 systemg.object_id.len < ASN_MAXOIDLEN) { 149 systemg.object_id.subs[systemg.object_id.len] = 0; 150 if (*p != '\0') { 151 num = strtoul(p, &end, 10); 152 if (end == p) 153 break; 154 systemg.object_id.subs[systemg.object_id.len] = num; 155 } 156 systemg.object_id.len++; 157 } 158 #endif 159 160 free(hostid); 161 162 return (0); 163 } 164 165 166 167 /************************************************************* 168 * 169 * System group 170 */ 171 int 172 op_system_group(struct snmp_context *ctx, struct snmp_value *value, 173 u_int sub, u_int iidx __unused, enum snmp_op op) 174 { 175 asn_subid_t which = value->var.subs[sub - 1]; 176 177 switch (op) { 178 179 case SNMP_OP_GETNEXT: 180 abort(); 181 182 case SNMP_OP_GET: 183 break; 184 185 case SNMP_OP_SET: 186 switch (which) { 187 188 case LEAF_sysDescr: 189 if (community != COMM_INITIALIZE) 190 return (SNMP_ERR_NOT_WRITEABLE); 191 return (string_save(value, ctx, -1, &systemg.descr)); 192 193 case LEAF_sysObjectId: 194 if (community != COMM_INITIALIZE) 195 return (SNMP_ERR_NOT_WRITEABLE); 196 return (oid_save(value, ctx, &systemg.object_id)); 197 198 case LEAF_sysContact: 199 return (string_save(value, ctx, -1, &systemg.contact)); 200 201 case LEAF_sysName: 202 return (string_save(value, ctx, -1, &systemg.name)); 203 204 case LEAF_sysLocation: 205 return (string_save(value, ctx, -1, &systemg.location)); 206 } 207 return (SNMP_ERR_NO_CREATION); 208 209 case SNMP_OP_ROLLBACK: 210 switch (which) { 211 212 case LEAF_sysDescr: 213 string_rollback(ctx, &systemg.descr); 214 return (SNMP_ERR_NOERROR); 215 case LEAF_sysObjectId: 216 oid_rollback(ctx, &systemg.object_id); 217 return (SNMP_ERR_NOERROR); 218 case LEAF_sysContact: 219 string_rollback(ctx, &systemg.contact); 220 return (SNMP_ERR_NOERROR); 221 case LEAF_sysName: 222 string_rollback(ctx, &systemg.name); 223 return (SNMP_ERR_NOERROR); 224 case LEAF_sysLocation: 225 string_rollback(ctx, &systemg.location); 226 return (SNMP_ERR_NOERROR); 227 } 228 abort(); 229 230 case SNMP_OP_COMMIT: 231 switch (which) { 232 233 case LEAF_sysDescr: 234 string_commit(ctx); 235 return (SNMP_ERR_NOERROR); 236 case LEAF_sysObjectId: 237 oid_commit(ctx); 238 return (SNMP_ERR_NOERROR); 239 case LEAF_sysContact: 240 string_commit(ctx); 241 return (SNMP_ERR_NOERROR); 242 case LEAF_sysName: 243 string_commit(ctx); 244 return (SNMP_ERR_NOERROR); 245 case LEAF_sysLocation: 246 string_commit(ctx); 247 return (SNMP_ERR_NOERROR); 248 } 249 abort(); 250 } 251 252 /* 253 * Come here for GET. 254 */ 255 switch (which) { 256 257 case LEAF_sysDescr: 258 return (string_get(value, systemg.descr, -1)); 259 case LEAF_sysObjectId: 260 return (oid_get(value, &systemg.object_id)); 261 case LEAF_sysUpTime: 262 value->v.uint32 = get_ticks() - start_tick; 263 break; 264 case LEAF_sysContact: 265 return (string_get(value, systemg.contact, -1)); 266 case LEAF_sysName: 267 return (string_get(value, systemg.name, -1)); 268 case LEAF_sysLocation: 269 return (string_get(value, systemg.location, -1)); 270 case LEAF_sysServices: 271 value->v.integer = systemg.services; 272 break; 273 case LEAF_sysORLastChange: 274 value->v.uint32 = systemg.or_last_change; 275 break; 276 } 277 return (SNMP_ERR_NOERROR); 278 } 279 280 /************************************************************* 281 * 282 * Debug group 283 */ 284 int 285 op_debug(struct snmp_context *ctx, struct snmp_value *value, u_int sub, 286 u_int iidx __unused, enum snmp_op op) 287 { 288 asn_subid_t which = value->var.subs[sub - 1]; 289 290 switch (op) { 291 292 case SNMP_OP_GETNEXT: 293 abort(); 294 295 case SNMP_OP_GET: 296 switch (which) { 297 298 case LEAF_begemotSnmpdDebugDumpPdus: 299 value->v.integer = TRUTH_MK(debug.dump_pdus); 300 break; 301 302 case LEAF_begemotSnmpdDebugSnmpTrace: 303 value->v.uint32 = snmp_trace; 304 break; 305 306 case LEAF_begemotSnmpdDebugSyslogPri: 307 value->v.integer = debug.logpri; 308 break; 309 } 310 return (SNMP_ERR_NOERROR); 311 312 case SNMP_OP_SET: 313 switch (which) { 314 315 case LEAF_begemotSnmpdDebugDumpPdus: 316 if (!TRUTH_OK(value->v.integer)) 317 return (SNMP_ERR_WRONG_VALUE); 318 ctx->scratch->int1 = debug.dump_pdus; 319 debug.dump_pdus = TRUTH_GET(value->v.integer); 320 return (SNMP_ERR_NOERROR); 321 322 case LEAF_begemotSnmpdDebugSnmpTrace: 323 ctx->scratch->int1 = snmp_trace; 324 snmp_trace = value->v.uint32; 325 return (SNMP_ERR_NOERROR); 326 327 case LEAF_begemotSnmpdDebugSyslogPri: 328 if (value->v.integer < 0 || value->v.integer > 8) 329 return (SNMP_ERR_WRONG_VALUE); 330 ctx->scratch->int1 = debug.logpri; 331 debug.logpri = (u_int)value->v.integer; 332 return (SNMP_ERR_NOERROR); 333 } 334 return (SNMP_ERR_NO_CREATION); 335 336 case SNMP_OP_ROLLBACK: 337 switch (which) { 338 339 case LEAF_begemotSnmpdDebugDumpPdus: 340 debug.dump_pdus = ctx->scratch->int1; 341 return (SNMP_ERR_NOERROR); 342 343 case LEAF_begemotSnmpdDebugSnmpTrace: 344 snmp_trace = ctx->scratch->int1; 345 return (SNMP_ERR_NOERROR); 346 347 case LEAF_begemotSnmpdDebugSyslogPri: 348 debug.logpri = ctx->scratch->int1; 349 return (SNMP_ERR_NOERROR); 350 } 351 abort(); 352 353 case SNMP_OP_COMMIT: 354 switch (which) { 355 356 case LEAF_begemotSnmpdDebugDumpPdus: 357 case LEAF_begemotSnmpdDebugSnmpTrace: 358 return (SNMP_ERR_NOERROR); 359 360 case LEAF_begemotSnmpdDebugSyslogPri: 361 if (debug.logpri == 0) 362 setlogmask(0); 363 else 364 setlogmask(LOG_UPTO(debug.logpri - 1)); 365 return (SNMP_ERR_NOERROR); 366 } 367 abort(); 368 } 369 abort(); 370 } 371 372 /************************************************************* 373 * 374 * OR Table 375 */ 376 int 377 op_or_table(struct snmp_context *ctx __unused, struct snmp_value *value, 378 u_int sub, u_int iidx __unused, enum snmp_op op) 379 { 380 struct objres *objres; 381 382 switch (op) { 383 384 case SNMP_OP_GETNEXT: 385 if ((objres = NEXT_OBJECT_INT(&objres_list, &value->var, sub)) 386 == NULL) 387 return (SNMP_ERR_NOSUCHNAME); 388 value->var.subs[sub] = objres->index; 389 value->var.len = sub + 1; 390 break; 391 392 case SNMP_OP_GET: 393 if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) 394 == NULL) 395 return (SNMP_ERR_NOSUCHNAME); 396 break; 397 398 case SNMP_OP_SET: 399 if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) 400 == NULL) 401 return (SNMP_ERR_NO_CREATION); 402 return (SNMP_ERR_NOT_WRITEABLE); 403 404 case SNMP_OP_ROLLBACK: 405 case SNMP_OP_COMMIT: 406 default: 407 abort(); 408 } 409 410 /* 411 * Come here for GET, GETNEXT. 412 */ 413 switch (value->var.subs[sub - 1]) { 414 415 case LEAF_sysORID: 416 value->v.oid = objres->oid; 417 break; 418 419 case LEAF_sysORDescr: 420 return (string_get(value, objres->descr, -1)); 421 422 case LEAF_sysORUpTime: 423 value->v.uint32 = objres->uptime; 424 break; 425 } 426 return (SNMP_ERR_NOERROR); 427 } 428 429 /************************************************************* 430 * 431 * mib-2 snmp 432 */ 433 int 434 op_snmp(struct snmp_context *ctx, struct snmp_value *value, 435 u_int sub, u_int iidx __unused, enum snmp_op op) 436 { 437 switch (op) { 438 439 case SNMP_OP_GETNEXT: 440 abort(); 441 442 case SNMP_OP_GET: 443 switch (value->var.subs[sub - 1]) { 444 445 case LEAF_snmpInPkts: 446 value->v.uint32 = snmpd_stats.inPkts; 447 break; 448 449 case LEAF_snmpInBadVersions: 450 value->v.uint32 = snmpd_stats.inBadVersions; 451 break; 452 453 case LEAF_snmpInBadCommunityNames: 454 value->v.uint32 = snmpd_stats.inBadCommunityNames; 455 break; 456 457 case LEAF_snmpInBadCommunityUses: 458 value->v.uint32 = snmpd_stats.inBadCommunityUses; 459 break; 460 461 case LEAF_snmpInASNParseErrs: 462 value->v.uint32 = snmpd_stats.inASNParseErrs; 463 break; 464 465 case LEAF_snmpEnableAuthenTraps: 466 value->v.integer = TRUTH_MK(snmpd.auth_traps); 467 break; 468 469 case LEAF_snmpSilentDrops: 470 value->v.uint32 = snmpd_stats.silentDrops; 471 break; 472 473 case LEAF_snmpProxyDrops: 474 value->v.uint32 = snmpd_stats.proxyDrops; 475 break; 476 477 default: 478 return (SNMP_ERR_NOSUCHNAME); 479 480 } 481 return (SNMP_ERR_NOERROR); 482 483 case SNMP_OP_SET: 484 switch (value->var.subs[sub - 1]) { 485 case LEAF_snmpEnableAuthenTraps: 486 if (!TRUTH_OK(value->v.integer)) 487 return (SNMP_ERR_WRONG_VALUE); 488 ctx->scratch->int1 = value->v.integer; 489 snmpd.auth_traps = TRUTH_GET(value->v.integer); 490 return (SNMP_ERR_NOERROR); 491 } 492 abort(); 493 494 case SNMP_OP_ROLLBACK: 495 switch (value->var.subs[sub - 1]) { 496 case LEAF_snmpEnableAuthenTraps: 497 snmpd.auth_traps = ctx->scratch->int1; 498 return (SNMP_ERR_NOERROR); 499 } 500 abort(); 501 502 case SNMP_OP_COMMIT: 503 switch (value->var.subs[sub - 1]) { 504 case LEAF_snmpEnableAuthenTraps: 505 return (SNMP_ERR_NOERROR); 506 } 507 abort(); 508 } 509 abort(); 510 } 511 512 /************************************************************* 513 * 514 * SNMPd statistics group 515 */ 516 int 517 op_snmpd_stats(struct snmp_context *ctx __unused, struct snmp_value *value, 518 u_int sub, u_int iidx __unused, enum snmp_op op) 519 { 520 switch (op) { 521 522 case SNMP_OP_GET: 523 switch (value->var.subs[sub - 1]) { 524 525 case LEAF_begemotSnmpdStatsNoRxBufs: 526 value->v.uint32 = snmpd_stats.noRxbuf; 527 break; 528 529 case LEAF_begemotSnmpdStatsNoTxBufs: 530 value->v.uint32 = snmpd_stats.noTxbuf; 531 break; 532 533 case LEAF_begemotSnmpdStatsInTooLongPkts: 534 value->v.uint32 = snmpd_stats.inTooLong; 535 break; 536 537 case LEAF_begemotSnmpdStatsInBadPduTypes: 538 value->v.uint32 = snmpd_stats.inBadPduTypes; 539 break; 540 541 default: 542 return (SNMP_ERR_NOSUCHNAME); 543 } 544 return (SNMP_ERR_NOERROR); 545 546 case SNMP_OP_SET: 547 case SNMP_OP_ROLLBACK: 548 case SNMP_OP_COMMIT: 549 case SNMP_OP_GETNEXT: 550 abort(); 551 } 552 abort(); 553 } 554 555 /* 556 * SNMPd configuration scalars 557 */ 558 int 559 op_snmpd_config(struct snmp_context *ctx, struct snmp_value *value, 560 u_int sub, u_int iidx __unused, enum snmp_op op) 561 { 562 asn_subid_t which = value->var.subs[sub - 1]; 563 564 switch (op) { 565 566 case SNMP_OP_GETNEXT: 567 abort(); 568 569 case SNMP_OP_GET: 570 switch (which) { 571 572 case LEAF_begemotSnmpdTransmitBuffer: 573 value->v.integer = snmpd.txbuf; 574 break; 575 case LEAF_begemotSnmpdReceiveBuffer: 576 value->v.integer = snmpd.rxbuf; 577 break; 578 case LEAF_begemotSnmpdCommunityDisable: 579 value->v.integer = TRUTH_MK(snmpd.comm_dis); 580 break; 581 case LEAF_begemotSnmpdTrap1Addr: 582 return (ip_get(value, snmpd.trap1addr)); 583 case LEAF_begemotSnmpdVersionEnable: 584 value->v.uint32 = snmpd.version_enable; 585 break; 586 default: 587 return (SNMP_ERR_NOSUCHNAME); 588 } 589 return (SNMP_ERR_NOERROR); 590 591 case SNMP_OP_SET: 592 switch (which) { 593 594 case LEAF_begemotSnmpdTransmitBuffer: 595 ctx->scratch->int1 = snmpd.txbuf; 596 if (value->v.integer < 484 || 597 value->v.integer > 65535) 598 return (SNMP_ERR_WRONG_VALUE); 599 snmpd.txbuf = value->v.integer; 600 return (SNMP_ERR_NOERROR); 601 602 case LEAF_begemotSnmpdReceiveBuffer: 603 ctx->scratch->int1 = snmpd.rxbuf; 604 if (value->v.integer < 484 || 605 value->v.integer > 65535) 606 return (SNMP_ERR_WRONG_VALUE); 607 snmpd.rxbuf = value->v.integer; 608 return (SNMP_ERR_NOERROR); 609 610 case LEAF_begemotSnmpdCommunityDisable: 611 ctx->scratch->int1 = snmpd.comm_dis; 612 if (!TRUTH_OK(value->v.integer)) 613 return (SNMP_ERR_WRONG_VALUE); 614 if (TRUTH_GET(value->v.integer)) { 615 snmpd.comm_dis = 1; 616 } else { 617 if (snmpd.comm_dis) 618 return (SNMP_ERR_WRONG_VALUE); 619 } 620 return (SNMP_ERR_NOERROR); 621 622 case LEAF_begemotSnmpdTrap1Addr: 623 return (ip_save(value, ctx, snmpd.trap1addr)); 624 625 case LEAF_begemotSnmpdVersionEnable: 626 if (community != COMM_INITIALIZE) 627 return (SNMP_ERR_NOT_WRITEABLE); 628 ctx->scratch->int1 = snmpd.version_enable; 629 if (value->v.uint32 == 0 || 630 (value->v.uint32 & ~VERS_ENABLE_ALL)) 631 return (SNMP_ERR_WRONG_VALUE); 632 snmpd.version_enable = value->v.uint32; 633 return (SNMP_ERR_NOERROR); 634 } 635 abort(); 636 637 case SNMP_OP_ROLLBACK: 638 switch (which) { 639 640 case LEAF_begemotSnmpdTransmitBuffer: 641 snmpd.rxbuf = ctx->scratch->int1; 642 return (SNMP_ERR_NOERROR); 643 case LEAF_begemotSnmpdReceiveBuffer: 644 snmpd.txbuf = ctx->scratch->int1; 645 return (SNMP_ERR_NOERROR); 646 case LEAF_begemotSnmpdCommunityDisable: 647 snmpd.comm_dis = ctx->scratch->int1; 648 return (SNMP_ERR_NOERROR); 649 case LEAF_begemotSnmpdTrap1Addr: 650 ip_rollback(ctx, snmpd.trap1addr); 651 return (SNMP_ERR_NOERROR); 652 case LEAF_begemotSnmpdVersionEnable: 653 snmpd.version_enable = ctx->scratch->int1; 654 return (SNMP_ERR_NOERROR); 655 } 656 abort(); 657 658 case SNMP_OP_COMMIT: 659 switch (which) { 660 661 case LEAF_begemotSnmpdTransmitBuffer: 662 case LEAF_begemotSnmpdReceiveBuffer: 663 case LEAF_begemotSnmpdCommunityDisable: 664 return (SNMP_ERR_NOERROR); 665 case LEAF_begemotSnmpdTrap1Addr: 666 ip_commit(ctx); 667 return (SNMP_ERR_NOERROR); 668 case LEAF_begemotSnmpdVersionEnable: 669 return (SNMP_ERR_NOERROR); 670 } 671 abort(); 672 } 673 abort(); 674 } 675 676 /* 677 * The community table 678 */ 679 int 680 op_community(struct snmp_context *ctx, struct snmp_value *value, 681 u_int sub, u_int iidx __unused, enum snmp_op op) 682 { 683 asn_subid_t which = value->var.subs[sub - 1]; 684 struct community *c; 685 686 switch (op) { 687 688 case SNMP_OP_GETNEXT: 689 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 690 (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 691 return (SNMP_ERR_NOSUCHNAME); 692 index_append(&value->var, sub, &c->index); 693 break; 694 695 case SNMP_OP_GET: 696 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 697 (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 698 return (SNMP_ERR_NOSUCHNAME); 699 break; 700 701 case SNMP_OP_SET: 702 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 703 (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 704 return (SNMP_ERR_NO_CREATION); 705 if (which != LEAF_begemotSnmpdCommunityString) 706 return (SNMP_ERR_NOT_WRITEABLE); 707 return (string_save(value, ctx, -1, &c->string)); 708 709 case SNMP_OP_ROLLBACK: 710 if (which == LEAF_begemotSnmpdCommunityString) { 711 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 712 sub)) == NULL) 713 string_free(ctx); 714 else 715 string_rollback(ctx, &c->string); 716 return (SNMP_ERR_NOERROR); 717 } 718 abort(); 719 720 case SNMP_OP_COMMIT: 721 if (which == LEAF_begemotSnmpdCommunityString) { 722 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 723 sub)) == NULL) 724 string_free(ctx); 725 else 726 string_commit(ctx); 727 return (SNMP_ERR_NOERROR); 728 } 729 abort(); 730 731 default: 732 abort(); 733 } 734 735 switch (which) { 736 737 case LEAF_begemotSnmpdCommunityString: 738 return (string_get(value, c->string, -1)); 739 740 case LEAF_begemotSnmpdCommunityDescr: 741 return (string_get(value, c->descr, -1)); 742 } 743 abort(); 744 } 745 746 /* 747 * Module table. 748 */ 749 struct module_dep { 750 struct snmp_dependency dep; 751 u_char section[LM_SECTION_MAX + 1]; 752 u_char *path; 753 struct lmodule *m; 754 }; 755 756 static int 757 dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep, 758 enum snmp_depop op) 759 { 760 struct module_dep *mdep = (struct module_dep *)(void *)dep; 761 762 switch (op) { 763 764 case SNMP_DEPOP_COMMIT: 765 if (mdep->path == NULL) { 766 /* unload - find the module */ 767 TAILQ_FOREACH(mdep->m, &lmodules, link) 768 if (strcmp(mdep->m->section, 769 mdep->section) == 0) 770 break; 771 if (mdep->m == NULL) 772 /* no such module - that's ok */ 773 return (SNMP_ERR_NOERROR); 774 775 /* handle unloading in the finalizer */ 776 return (SNMP_ERR_NOERROR); 777 } 778 /* load */ 779 if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) { 780 /* could not load */ 781 return (SNMP_ERR_RES_UNAVAIL); 782 } 783 /* start in finalizer */ 784 return (SNMP_ERR_NOERROR); 785 786 case SNMP_DEPOP_ROLLBACK: 787 if (mdep->path == NULL) { 788 /* rollback unload - the finalizer takes care */ 789 return (SNMP_ERR_NOERROR); 790 } 791 /* rollback load */ 792 lm_unload(mdep->m); 793 return (SNMP_ERR_NOERROR); 794 795 case SNMP_DEPOP_FINISH: 796 if (mdep->path == NULL) { 797 if (mdep->m != NULL && ctx->code == SNMP_RET_OK) 798 lm_unload(mdep->m); 799 } else { 800 if (mdep->m != NULL && ctx->code == SNMP_RET_OK && 801 community != COMM_INITIALIZE) 802 lm_start(mdep->m); 803 free(mdep->path); 804 } 805 return (SNMP_ERR_NOERROR); 806 } 807 abort(); 808 } 809 810 int 811 op_modules(struct snmp_context *ctx, struct snmp_value *value, 812 u_int sub, u_int iidx, enum snmp_op op) 813 { 814 asn_subid_t which = value->var.subs[sub - 1]; 815 struct lmodule *m; 816 u_char *section, *ptr; 817 size_t seclen; 818 struct module_dep *mdep; 819 struct asn_oid idx; 820 821 switch (op) { 822 823 case SNMP_OP_GETNEXT: 824 if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 825 return (SNMP_ERR_NOSUCHNAME); 826 index_append(&value->var, sub, &m->index); 827 break; 828 829 case SNMP_OP_GET: 830 if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 831 return (SNMP_ERR_NOSUCHNAME); 832 break; 833 834 case SNMP_OP_SET: 835 m = FIND_OBJECT_OID(&lmodules, &value->var, sub); 836 if (which != LEAF_begemotSnmpdModulePath) { 837 if (m == NULL) 838 return (SNMP_ERR_NO_CREATION); 839 return (SNMP_ERR_NOT_WRITEABLE); 840 } 841 842 /* the errors in the next few statements can only happen when 843 * m is NULL, hence the NO_CREATION error. */ 844 if (index_decode(&value->var, sub, iidx, 845 §ion, &seclen)) 846 return (SNMP_ERR_NO_CREATION); 847 848 /* check the section name */ 849 if (seclen > LM_SECTION_MAX || seclen == 0) { 850 free(section); 851 return (SNMP_ERR_NO_CREATION); 852 } 853 for (ptr = section; ptr < section + seclen; ptr++) 854 if (!isascii(*ptr) || !isalnum(*ptr)) { 855 free(section); 856 return (SNMP_ERR_NO_CREATION); 857 } 858 if (!isalpha(section[0])) { 859 free(section); 860 return (SNMP_ERR_NO_CREATION); 861 } 862 863 /* check the path */ 864 for (ptr = value->v.octetstring.octets; 865 ptr < value->v.octetstring.octets + value->v.octetstring.len; 866 ptr++) { 867 if (*ptr == '\0') { 868 free(section); 869 return (SNMP_ERR_WRONG_VALUE); 870 } 871 } 872 873 if (m == NULL) { 874 if (value->v.octetstring.len == 0) { 875 free(section); 876 return (SNMP_ERR_INCONS_VALUE); 877 } 878 } else { 879 if (value->v.octetstring.len != 0) { 880 free(section); 881 return (SNMP_ERR_INCONS_VALUE); 882 } 883 } 884 885 asn_slice_oid(&idx, &value->var, sub, value->var.len); 886 887 /* so far, so good */ 888 mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx, 889 &oid_begemotSnmpdModuleTable, &idx, 890 sizeof(*mdep), dep_modules); 891 if (mdep == NULL) { 892 free(section); 893 return (SNMP_ERR_RES_UNAVAIL); 894 } 895 896 if (mdep->section[0] != '\0') { 897 /* two writes to the same entry - bad */ 898 free(section); 899 return (SNMP_ERR_INCONS_VALUE); 900 } 901 902 strncpy(mdep->section, section, seclen); 903 mdep->section[seclen] = '\0'; 904 free(section); 905 906 if (value->v.octetstring.len == 0) 907 mdep->path = NULL; 908 else { 909 if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL) 910 return (SNMP_ERR_RES_UNAVAIL); 911 strncpy(mdep->path, value->v.octetstring.octets, 912 value->v.octetstring.len); 913 mdep->path[value->v.octetstring.len] = '\0'; 914 } 915 ctx->scratch->ptr1 = mdep; 916 return (SNMP_ERR_NOERROR); 917 918 case SNMP_OP_ROLLBACK: 919 case SNMP_OP_COMMIT: 920 return (SNMP_ERR_NOERROR); 921 922 default: 923 abort(); 924 } 925 926 switch (which) { 927 928 case LEAF_begemotSnmpdModulePath: 929 return (string_get(value, m->path, -1)); 930 931 case LEAF_begemotSnmpdModuleComment: 932 return (string_get(value, m->config->comment, -1)); 933 } 934 abort(); 935 } 936 937 int 938 op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value, 939 u_int sub, u_int iidx __unused, enum snmp_op op) 940 { 941 switch (op) { 942 943 case SNMP_OP_GETNEXT: 944 abort(); 945 946 case SNMP_OP_GET: 947 switch (value->var.subs[sub - 1]) { 948 949 case LEAF_snmpSetSerialNo: 950 value->v.integer = snmp_serial_no; 951 break; 952 953 default: 954 abort(); 955 } 956 return (SNMP_ERR_NOERROR); 957 958 case SNMP_OP_SET: 959 switch (value->var.subs[sub - 1]) { 960 961 case LEAF_snmpSetSerialNo: 962 if (value->v.integer != snmp_serial_no) 963 return (SNMP_ERR_INCONS_VALUE); 964 break; 965 966 default: 967 abort(); 968 } 969 return (SNMP_ERR_NOERROR); 970 971 case SNMP_OP_ROLLBACK: 972 return (SNMP_ERR_NOERROR); 973 974 case SNMP_OP_COMMIT: 975 if (snmp_serial_no++ == 2147483647) 976 snmp_serial_no = 0; 977 return (SNMP_ERR_NOERROR); 978 } 979 abort(); 980 } 981 982 /* 983 * Transport table 984 */ 985 int 986 op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value, 987 u_int sub, u_int iidx, enum snmp_op op) 988 { 989 asn_subid_t which = value->var.subs[sub - 1]; 990 struct transport *t; 991 u_char *tname, *ptr; 992 size_t tnamelen; 993 994 switch (op) { 995 996 case SNMP_OP_GETNEXT: 997 if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub)) 998 == NULL) 999 return (SNMP_ERR_NOSUCHNAME); 1000 index_append(&value->var, sub, &t->index); 1001 break; 1002 1003 case SNMP_OP_GET: 1004 if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub)) 1005 == NULL) 1006 return (SNMP_ERR_NOSUCHNAME); 1007 break; 1008 1009 case SNMP_OP_SET: 1010 t = FIND_OBJECT_OID(&transport_list, &value->var, sub); 1011 if (which != LEAF_begemotSnmpdTransportStatus) { 1012 if (t == NULL) 1013 return (SNMP_ERR_NO_CREATION); 1014 return (SNMP_ERR_NOT_WRITEABLE); 1015 } 1016 1017 /* the errors in the next few statements can only happen when 1018 * t is NULL, hence the NO_CREATION error. */ 1019 if (index_decode(&value->var, sub, iidx, 1020 &tname, &tnamelen)) 1021 return (SNMP_ERR_NO_CREATION); 1022 1023 /* check the section name */ 1024 if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) { 1025 free(tname); 1026 return (SNMP_ERR_NO_CREATION); 1027 } 1028 for (ptr = tname; ptr < tname + tnamelen; ptr++) { 1029 if (!isascii(*ptr) || !isalnum(*ptr)) { 1030 free(tname); 1031 return (SNMP_ERR_NO_CREATION); 1032 } 1033 } 1034 1035 /* for now */ 1036 return (SNMP_ERR_NOT_WRITEABLE); 1037 1038 case SNMP_OP_ROLLBACK: 1039 case SNMP_OP_COMMIT: 1040 return (SNMP_ERR_NOERROR); 1041 default: 1042 abort(); 1043 } 1044 1045 switch (which) { 1046 1047 case LEAF_begemotSnmpdTransportStatus: 1048 value->v.integer = 1; 1049 break; 1050 1051 case LEAF_begemotSnmpdTransportOid: 1052 memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id)); 1053 break; 1054 } 1055 return (SNMP_ERR_NOERROR); 1056 } 1057