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/queue.h> 38 #include <sys/sysctl.h> 39 #include <sys/un.h> 40 #include <sys/utsname.h> 41 #include <stdio.h> 42 #include <stdlib.h> 43 #include <stdarg.h> 44 #include <string.h> 45 #include <ctype.h> 46 #include <errno.h> 47 #include <syslog.h> 48 49 #include "snmpmod.h" 50 #include "snmpd.h" 51 #include "tree.h" 52 #include "oid.h" 53 54 static const struct asn_oid 55 oid_begemotSnmpdModuleTable = OIDX_begemotSnmpdModuleTable; 56 57 #ifdef __FreeBSD__ 58 static const struct asn_oid 59 oid_freeBSDVersion = OIDX_freeBSDVersion; 60 #endif 61 62 /* 63 * Get a string value from the KERN sysctl subtree. 64 */ 65 static char * 66 act_getkernstring(int id) 67 { 68 int mib[2]; 69 size_t len; 70 char *string; 71 72 mib[0] = CTL_KERN; 73 mib[1] = id; 74 if (sysctl(mib, 2, NULL, &len, NULL, 0) != 0) 75 return (NULL); 76 if ((string = malloc(len)) == NULL) 77 return (NULL); 78 if (sysctl(mib, 2, string, &len, NULL, 0) != 0) { 79 free(string); 80 return (NULL); 81 } 82 return (string); 83 } 84 85 /* 86 * Get an integer value from the KERN sysctl subtree. 87 */ 88 static char * 89 act_getkernint(int id) 90 { 91 int mib[2]; 92 size_t len; 93 u_long value; 94 char *string; 95 96 mib[0] = CTL_KERN; 97 mib[1] = id; 98 len = sizeof(value); 99 if (sysctl(mib, 2, &value, &len, NULL, 0) != 0) 100 return (NULL); 101 102 if ((string = malloc(20)) == NULL) 103 return (NULL); 104 sprintf(string, "%lu", value); 105 return (string); 106 } 107 108 /* 109 * Initialize global variables of the system group. 110 */ 111 int 112 init_actvals(void) 113 { 114 struct utsname uts; 115 char *hostid; 116 size_t len; 117 #ifdef __FreeBSD__ 118 char *rel, *p, *end; 119 u_long num; 120 #endif 121 122 if (uname(&uts) == -1) 123 return (-1); 124 125 if ((systemg.name = strdup(uts.nodename)) == NULL) 126 return (-1); 127 128 if ((hostid = act_getkernint(KERN_HOSTID)) == NULL) 129 return (-1); 130 131 len = strlen(uts.nodename) + 1; 132 len += strlen(hostid) + 1; 133 len += strlen(uts.sysname) + 1; 134 len += strlen(uts.release) + 1; 135 136 if ((systemg.descr = malloc(len)) == NULL) { 137 free(hostid); 138 return (-1); 139 } 140 sprintf(systemg.descr, "%s %s %s %s", uts.nodename, hostid, uts.sysname, 141 uts.release); 142 143 #ifdef __FreeBSD__ 144 /* 145 * Construct a FreeBSD oid 146 */ 147 systemg.object_id = oid_freeBSDVersion; 148 rel = uts.release; 149 while ((p = strsep(&rel, ".")) != NULL && 150 systemg.object_id.len < ASN_MAXOIDLEN) { 151 systemg.object_id.subs[systemg.object_id.len] = 0; 152 if (*p != '\0') { 153 num = strtoul(p, &end, 10); 154 if (end == p) 155 break; 156 systemg.object_id.subs[systemg.object_id.len] = num; 157 } 158 systemg.object_id.len++; 159 } 160 #endif 161 162 free(hostid); 163 164 return (0); 165 } 166 167 /* 168 * Initialize global variables of the snmpEngine group. 169 */ 170 int 171 init_snmpd_engine(void) 172 { 173 char *hostid; 174 175 snmpd_engine.engine_boots = 1; 176 snmpd_engine.engine_time = 1; 177 snmpd_engine.max_msg_size = 1500; /* XXX */ 178 179 snmpd_engine.engine_id[0] = ((OID_freeBSD & 0xff000000) >> 24) | 0x80; 180 snmpd_engine.engine_id[1] = (OID_freeBSD & 0xff0000) >> 16; 181 snmpd_engine.engine_id[2] = (OID_freeBSD & 0xff00) >> 8; 182 snmpd_engine.engine_id[3] = OID_freeBSD & 0xff; 183 snmpd_engine.engine_id[4] = 128; 184 snmpd_engine.engine_len = 5; 185 186 if ((hostid = act_getkernint(KERN_HOSTID)) == NULL) 187 return (-1); 188 189 if (strlen(hostid) > SNMP_ENGINE_ID_SIZ - snmpd_engine.engine_len) { 190 memcpy(snmpd_engine.engine_id + snmpd_engine.engine_len, 191 hostid, SNMP_ENGINE_ID_SIZ - snmpd_engine.engine_len); 192 snmpd_engine.engine_len = SNMP_ENGINE_ID_SIZ; 193 } else { 194 memcpy(snmpd_engine.engine_id + snmpd_engine.engine_len, 195 hostid, strlen(hostid)); 196 snmpd_engine.engine_len += strlen(hostid); 197 } 198 199 free(hostid); 200 201 return (0); 202 } 203 204 int 205 set_snmpd_engine(void) 206 { 207 FILE *fp; 208 uint32_t i; 209 uint8_t *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2]; 210 uint8_t myengine[2 * SNMP_ENGINE_ID_SIZ + 2]; 211 212 if (engine_file[0] == '\0') 213 return (-1); 214 215 cptr = myengine; 216 for (i = 0; i < snmpd_engine.engine_len; i++) 217 cptr += sprintf(cptr, "%.2x", snmpd_engine.engine_id[i]); 218 *cptr++ = '\n'; 219 *cptr++ = '\0'; 220 221 if ((fp = fopen(engine_file, "r+")) != NULL) { 222 if (fgets(engine, sizeof(engine) - 1, fp) == NULL || 223 fscanf(fp, "%u", &snmpd_engine.engine_boots) <= 0) { 224 fclose(fp); 225 goto save_boots; 226 } 227 228 fclose(fp); 229 if (strcmp(myengine, engine) != 0) 230 snmpd_engine.engine_boots = 1; 231 else 232 snmpd_engine.engine_boots++; 233 } else if (errno != ENOENT) 234 return (-1); 235 236 save_boots: 237 if ((fp = fopen(engine_file, "w+")) == NULL) 238 return (-1); 239 fprintf(fp, "%s%u\n", myengine, snmpd_engine.engine_boots); 240 fclose(fp); 241 242 return (0); 243 } 244 245 /************************************************************* 246 * 247 * System group 248 */ 249 int 250 op_system_group(struct snmp_context *ctx, struct snmp_value *value, 251 u_int sub, u_int iidx __unused, enum snmp_op op) 252 { 253 asn_subid_t which = value->var.subs[sub - 1]; 254 255 switch (op) { 256 257 case SNMP_OP_GETNEXT: 258 abort(); 259 260 case SNMP_OP_GET: 261 break; 262 263 case SNMP_OP_SET: 264 switch (which) { 265 266 case LEAF_sysDescr: 267 if (community != COMM_INITIALIZE) 268 return (SNMP_ERR_NOT_WRITEABLE); 269 return (string_save(value, ctx, -1, &systemg.descr)); 270 271 case LEAF_sysObjectId: 272 if (community != COMM_INITIALIZE) 273 return (SNMP_ERR_NOT_WRITEABLE); 274 return (oid_save(value, ctx, &systemg.object_id)); 275 276 case LEAF_sysContact: 277 return (string_save(value, ctx, -1, &systemg.contact)); 278 279 case LEAF_sysName: 280 return (string_save(value, ctx, -1, &systemg.name)); 281 282 case LEAF_sysLocation: 283 return (string_save(value, ctx, -1, &systemg.location)); 284 } 285 return (SNMP_ERR_NO_CREATION); 286 287 case SNMP_OP_ROLLBACK: 288 switch (which) { 289 290 case LEAF_sysDescr: 291 string_rollback(ctx, &systemg.descr); 292 return (SNMP_ERR_NOERROR); 293 case LEAF_sysObjectId: 294 oid_rollback(ctx, &systemg.object_id); 295 return (SNMP_ERR_NOERROR); 296 case LEAF_sysContact: 297 string_rollback(ctx, &systemg.contact); 298 return (SNMP_ERR_NOERROR); 299 case LEAF_sysName: 300 string_rollback(ctx, &systemg.name); 301 return (SNMP_ERR_NOERROR); 302 case LEAF_sysLocation: 303 string_rollback(ctx, &systemg.location); 304 return (SNMP_ERR_NOERROR); 305 } 306 abort(); 307 308 case SNMP_OP_COMMIT: 309 switch (which) { 310 311 case LEAF_sysDescr: 312 string_commit(ctx); 313 return (SNMP_ERR_NOERROR); 314 case LEAF_sysObjectId: 315 oid_commit(ctx); 316 return (SNMP_ERR_NOERROR); 317 case LEAF_sysContact: 318 string_commit(ctx); 319 return (SNMP_ERR_NOERROR); 320 case LEAF_sysName: 321 string_commit(ctx); 322 return (SNMP_ERR_NOERROR); 323 case LEAF_sysLocation: 324 string_commit(ctx); 325 return (SNMP_ERR_NOERROR); 326 } 327 abort(); 328 } 329 330 /* 331 * Come here for GET. 332 */ 333 switch (which) { 334 335 case LEAF_sysDescr: 336 return (string_get(value, systemg.descr, -1)); 337 case LEAF_sysObjectId: 338 return (oid_get(value, &systemg.object_id)); 339 case LEAF_sysUpTime: 340 value->v.uint32 = get_ticks() - start_tick; 341 break; 342 case LEAF_sysContact: 343 return (string_get(value, systemg.contact, -1)); 344 case LEAF_sysName: 345 return (string_get(value, systemg.name, -1)); 346 case LEAF_sysLocation: 347 return (string_get(value, systemg.location, -1)); 348 case LEAF_sysServices: 349 value->v.integer = systemg.services; 350 break; 351 case LEAF_sysORLastChange: 352 value->v.uint32 = systemg.or_last_change; 353 break; 354 } 355 return (SNMP_ERR_NOERROR); 356 } 357 358 /************************************************************* 359 * 360 * Debug group 361 */ 362 int 363 op_debug(struct snmp_context *ctx, struct snmp_value *value, u_int sub, 364 u_int iidx __unused, enum snmp_op op) 365 { 366 asn_subid_t which = value->var.subs[sub - 1]; 367 368 switch (op) { 369 370 case SNMP_OP_GETNEXT: 371 abort(); 372 373 case SNMP_OP_GET: 374 switch (which) { 375 376 case LEAF_begemotSnmpdDebugDumpPdus: 377 value->v.integer = TRUTH_MK(debug.dump_pdus); 378 break; 379 380 case LEAF_begemotSnmpdDebugSnmpTrace: 381 value->v.uint32 = snmp_trace; 382 break; 383 384 case LEAF_begemotSnmpdDebugSyslogPri: 385 value->v.integer = debug.logpri; 386 break; 387 } 388 return (SNMP_ERR_NOERROR); 389 390 case SNMP_OP_SET: 391 switch (which) { 392 393 case LEAF_begemotSnmpdDebugDumpPdus: 394 if (!TRUTH_OK(value->v.integer)) 395 return (SNMP_ERR_WRONG_VALUE); 396 ctx->scratch->int1 = debug.dump_pdus; 397 debug.dump_pdus = TRUTH_GET(value->v.integer); 398 return (SNMP_ERR_NOERROR); 399 400 case LEAF_begemotSnmpdDebugSnmpTrace: 401 ctx->scratch->int1 = snmp_trace; 402 snmp_trace = value->v.uint32; 403 return (SNMP_ERR_NOERROR); 404 405 case LEAF_begemotSnmpdDebugSyslogPri: 406 if (value->v.integer < 0 || value->v.integer > 8) 407 return (SNMP_ERR_WRONG_VALUE); 408 ctx->scratch->int1 = debug.logpri; 409 debug.logpri = (u_int)value->v.integer; 410 return (SNMP_ERR_NOERROR); 411 } 412 return (SNMP_ERR_NO_CREATION); 413 414 case SNMP_OP_ROLLBACK: 415 switch (which) { 416 417 case LEAF_begemotSnmpdDebugDumpPdus: 418 debug.dump_pdus = ctx->scratch->int1; 419 return (SNMP_ERR_NOERROR); 420 421 case LEAF_begemotSnmpdDebugSnmpTrace: 422 snmp_trace = ctx->scratch->int1; 423 return (SNMP_ERR_NOERROR); 424 425 case LEAF_begemotSnmpdDebugSyslogPri: 426 debug.logpri = ctx->scratch->int1; 427 return (SNMP_ERR_NOERROR); 428 } 429 abort(); 430 431 case SNMP_OP_COMMIT: 432 switch (which) { 433 434 case LEAF_begemotSnmpdDebugDumpPdus: 435 case LEAF_begemotSnmpdDebugSnmpTrace: 436 return (SNMP_ERR_NOERROR); 437 438 case LEAF_begemotSnmpdDebugSyslogPri: 439 if (debug.logpri == 0) 440 setlogmask(0); 441 else 442 setlogmask(LOG_UPTO(debug.logpri - 1)); 443 return (SNMP_ERR_NOERROR); 444 } 445 abort(); 446 } 447 abort(); 448 } 449 450 /************************************************************* 451 * 452 * OR Table 453 */ 454 int 455 op_or_table(struct snmp_context *ctx __unused, struct snmp_value *value, 456 u_int sub, u_int iidx __unused, enum snmp_op op) 457 { 458 struct objres *objres; 459 460 switch (op) { 461 462 case SNMP_OP_GETNEXT: 463 if ((objres = NEXT_OBJECT_INT(&objres_list, &value->var, sub)) 464 == NULL) 465 return (SNMP_ERR_NOSUCHNAME); 466 value->var.subs[sub] = objres->index; 467 value->var.len = sub + 1; 468 break; 469 470 case SNMP_OP_GET: 471 if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) 472 == NULL) 473 return (SNMP_ERR_NOSUCHNAME); 474 break; 475 476 case SNMP_OP_SET: 477 if ((objres = FIND_OBJECT_INT(&objres_list, &value->var, sub)) 478 == NULL) 479 return (SNMP_ERR_NO_CREATION); 480 return (SNMP_ERR_NOT_WRITEABLE); 481 482 case SNMP_OP_ROLLBACK: 483 case SNMP_OP_COMMIT: 484 default: 485 abort(); 486 } 487 488 /* 489 * Come here for GET, GETNEXT. 490 */ 491 switch (value->var.subs[sub - 1]) { 492 493 case LEAF_sysORID: 494 value->v.oid = objres->oid; 495 break; 496 497 case LEAF_sysORDescr: 498 return (string_get(value, objres->descr, -1)); 499 500 case LEAF_sysORUpTime: 501 value->v.uint32 = objres->uptime; 502 break; 503 } 504 return (SNMP_ERR_NOERROR); 505 } 506 507 /************************************************************* 508 * 509 * mib-2 snmp 510 */ 511 int 512 op_snmp(struct snmp_context *ctx, struct snmp_value *value, 513 u_int sub, u_int iidx __unused, enum snmp_op op) 514 { 515 switch (op) { 516 517 case SNMP_OP_GETNEXT: 518 abort(); 519 520 case SNMP_OP_GET: 521 switch (value->var.subs[sub - 1]) { 522 523 case LEAF_snmpInPkts: 524 value->v.uint32 = snmpd_stats.inPkts; 525 break; 526 527 case LEAF_snmpInBadVersions: 528 value->v.uint32 = snmpd_stats.inBadVersions; 529 break; 530 531 case LEAF_snmpInBadCommunityNames: 532 value->v.uint32 = snmpd_stats.inBadCommunityNames; 533 break; 534 535 case LEAF_snmpInBadCommunityUses: 536 value->v.uint32 = snmpd_stats.inBadCommunityUses; 537 break; 538 539 case LEAF_snmpInASNParseErrs: 540 value->v.uint32 = snmpd_stats.inASNParseErrs; 541 break; 542 543 case LEAF_snmpEnableAuthenTraps: 544 value->v.integer = TRUTH_MK(snmpd.auth_traps); 545 break; 546 547 case LEAF_snmpSilentDrops: 548 value->v.uint32 = snmpd_stats.silentDrops; 549 break; 550 551 case LEAF_snmpProxyDrops: 552 value->v.uint32 = snmpd_stats.proxyDrops; 553 break; 554 555 default: 556 return (SNMP_ERR_NOSUCHNAME); 557 558 } 559 return (SNMP_ERR_NOERROR); 560 561 case SNMP_OP_SET: 562 switch (value->var.subs[sub - 1]) { 563 case LEAF_snmpEnableAuthenTraps: 564 if (!TRUTH_OK(value->v.integer)) 565 return (SNMP_ERR_WRONG_VALUE); 566 ctx->scratch->int1 = value->v.integer; 567 snmpd.auth_traps = TRUTH_GET(value->v.integer); 568 return (SNMP_ERR_NOERROR); 569 } 570 abort(); 571 572 case SNMP_OP_ROLLBACK: 573 switch (value->var.subs[sub - 1]) { 574 case LEAF_snmpEnableAuthenTraps: 575 snmpd.auth_traps = ctx->scratch->int1; 576 return (SNMP_ERR_NOERROR); 577 } 578 abort(); 579 580 case SNMP_OP_COMMIT: 581 switch (value->var.subs[sub - 1]) { 582 case LEAF_snmpEnableAuthenTraps: 583 return (SNMP_ERR_NOERROR); 584 } 585 abort(); 586 } 587 abort(); 588 } 589 590 /************************************************************* 591 * 592 * SNMPd statistics group 593 */ 594 int 595 op_snmpd_stats(struct snmp_context *ctx __unused, struct snmp_value *value, 596 u_int sub, u_int iidx __unused, enum snmp_op op) 597 { 598 switch (op) { 599 600 case SNMP_OP_GET: 601 switch (value->var.subs[sub - 1]) { 602 603 case LEAF_begemotSnmpdStatsNoRxBufs: 604 value->v.uint32 = snmpd_stats.noRxbuf; 605 break; 606 607 case LEAF_begemotSnmpdStatsNoTxBufs: 608 value->v.uint32 = snmpd_stats.noTxbuf; 609 break; 610 611 case LEAF_begemotSnmpdStatsInTooLongPkts: 612 value->v.uint32 = snmpd_stats.inTooLong; 613 break; 614 615 case LEAF_begemotSnmpdStatsInBadPduTypes: 616 value->v.uint32 = snmpd_stats.inBadPduTypes; 617 break; 618 619 default: 620 return (SNMP_ERR_NOSUCHNAME); 621 } 622 return (SNMP_ERR_NOERROR); 623 624 case SNMP_OP_SET: 625 case SNMP_OP_ROLLBACK: 626 case SNMP_OP_COMMIT: 627 case SNMP_OP_GETNEXT: 628 abort(); 629 } 630 abort(); 631 } 632 633 /* 634 * SNMPd configuration scalars 635 */ 636 int 637 op_snmpd_config(struct snmp_context *ctx, struct snmp_value *value, 638 u_int sub, u_int iidx __unused, enum snmp_op op) 639 { 640 asn_subid_t which = value->var.subs[sub - 1]; 641 642 switch (op) { 643 644 case SNMP_OP_GETNEXT: 645 abort(); 646 647 case SNMP_OP_GET: 648 switch (which) { 649 650 case LEAF_begemotSnmpdTransmitBuffer: 651 value->v.integer = snmpd.txbuf; 652 break; 653 case LEAF_begemotSnmpdReceiveBuffer: 654 value->v.integer = snmpd.rxbuf; 655 break; 656 case LEAF_begemotSnmpdCommunityDisable: 657 value->v.integer = TRUTH_MK(snmpd.comm_dis); 658 break; 659 case LEAF_begemotSnmpdTrap1Addr: 660 return (ip_get(value, snmpd.trap1addr)); 661 case LEAF_begemotSnmpdVersionEnable: 662 value->v.uint32 = snmpd.version_enable; 663 break; 664 default: 665 return (SNMP_ERR_NOSUCHNAME); 666 } 667 return (SNMP_ERR_NOERROR); 668 669 case SNMP_OP_SET: 670 switch (which) { 671 672 case LEAF_begemotSnmpdTransmitBuffer: 673 ctx->scratch->int1 = snmpd.txbuf; 674 if (value->v.integer < 484 || 675 value->v.integer > 65535) 676 return (SNMP_ERR_WRONG_VALUE); 677 snmpd.txbuf = value->v.integer; 678 return (SNMP_ERR_NOERROR); 679 680 case LEAF_begemotSnmpdReceiveBuffer: 681 ctx->scratch->int1 = snmpd.rxbuf; 682 if (value->v.integer < 484 || 683 value->v.integer > 65535) 684 return (SNMP_ERR_WRONG_VALUE); 685 snmpd.rxbuf = value->v.integer; 686 return (SNMP_ERR_NOERROR); 687 688 case LEAF_begemotSnmpdCommunityDisable: 689 ctx->scratch->int1 = snmpd.comm_dis; 690 if (!TRUTH_OK(value->v.integer)) 691 return (SNMP_ERR_WRONG_VALUE); 692 if (TRUTH_GET(value->v.integer)) { 693 snmpd.comm_dis = 1; 694 } else { 695 if (snmpd.comm_dis) 696 return (SNMP_ERR_WRONG_VALUE); 697 } 698 return (SNMP_ERR_NOERROR); 699 700 case LEAF_begemotSnmpdTrap1Addr: 701 return (ip_save(value, ctx, snmpd.trap1addr)); 702 703 case LEAF_begemotSnmpdVersionEnable: 704 if (community != COMM_INITIALIZE) 705 return (SNMP_ERR_NOT_WRITEABLE); 706 ctx->scratch->int1 = snmpd.version_enable; 707 if (value->v.uint32 == 0 || 708 (value->v.uint32 & ~VERS_ENABLE_ALL)) 709 return (SNMP_ERR_WRONG_VALUE); 710 snmpd.version_enable = value->v.uint32; 711 return (SNMP_ERR_NOERROR); 712 } 713 abort(); 714 715 case SNMP_OP_ROLLBACK: 716 switch (which) { 717 718 case LEAF_begemotSnmpdTransmitBuffer: 719 snmpd.rxbuf = ctx->scratch->int1; 720 return (SNMP_ERR_NOERROR); 721 case LEAF_begemotSnmpdReceiveBuffer: 722 snmpd.txbuf = ctx->scratch->int1; 723 return (SNMP_ERR_NOERROR); 724 case LEAF_begemotSnmpdCommunityDisable: 725 snmpd.comm_dis = ctx->scratch->int1; 726 return (SNMP_ERR_NOERROR); 727 case LEAF_begemotSnmpdTrap1Addr: 728 ip_rollback(ctx, snmpd.trap1addr); 729 return (SNMP_ERR_NOERROR); 730 case LEAF_begemotSnmpdVersionEnable: 731 snmpd.version_enable = ctx->scratch->int1; 732 return (SNMP_ERR_NOERROR); 733 } 734 abort(); 735 736 case SNMP_OP_COMMIT: 737 switch (which) { 738 739 case LEAF_begemotSnmpdTransmitBuffer: 740 case LEAF_begemotSnmpdReceiveBuffer: 741 case LEAF_begemotSnmpdCommunityDisable: 742 return (SNMP_ERR_NOERROR); 743 case LEAF_begemotSnmpdTrap1Addr: 744 ip_commit(ctx); 745 return (SNMP_ERR_NOERROR); 746 case LEAF_begemotSnmpdVersionEnable: 747 return (SNMP_ERR_NOERROR); 748 } 749 abort(); 750 } 751 abort(); 752 } 753 754 /* 755 * The community table 756 */ 757 int 758 op_community(struct snmp_context *ctx, struct snmp_value *value, 759 u_int sub, u_int iidx __unused, enum snmp_op op) 760 { 761 asn_subid_t which = value->var.subs[sub - 1]; 762 struct community *c; 763 764 switch (op) { 765 766 case SNMP_OP_GETNEXT: 767 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 768 (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 769 return (SNMP_ERR_NOSUCHNAME); 770 index_append(&value->var, sub, &c->index); 771 break; 772 773 case SNMP_OP_GET: 774 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 775 (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 776 return (SNMP_ERR_NOSUCHNAME); 777 break; 778 779 case SNMP_OP_SET: 780 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 781 (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 782 return (SNMP_ERR_NO_CREATION); 783 if (which != LEAF_begemotSnmpdCommunityString) 784 return (SNMP_ERR_NOT_WRITEABLE); 785 return (string_save(value, ctx, -1, &c->string)); 786 787 case SNMP_OP_ROLLBACK: 788 if (which == LEAF_begemotSnmpdCommunityString) { 789 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 790 sub)) == NULL) 791 string_free(ctx); 792 else 793 string_rollback(ctx, &c->string); 794 return (SNMP_ERR_NOERROR); 795 } 796 abort(); 797 798 case SNMP_OP_COMMIT: 799 if (which == LEAF_begemotSnmpdCommunityString) { 800 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 801 sub)) == NULL) 802 string_free(ctx); 803 else 804 string_commit(ctx); 805 return (SNMP_ERR_NOERROR); 806 } 807 abort(); 808 809 default: 810 abort(); 811 } 812 813 switch (which) { 814 815 case LEAF_begemotSnmpdCommunityString: 816 return (string_get(value, c->string, -1)); 817 818 case LEAF_begemotSnmpdCommunityDescr: 819 return (string_get(value, c->descr, -1)); 820 } 821 abort(); 822 } 823 824 /* 825 * Module table. 826 */ 827 struct module_dep { 828 struct snmp_dependency dep; 829 u_char section[LM_SECTION_MAX + 1]; 830 u_char *path; 831 struct lmodule *m; 832 }; 833 834 static int 835 dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep, 836 enum snmp_depop op) 837 { 838 struct module_dep *mdep = (struct module_dep *)(void *)dep; 839 840 switch (op) { 841 842 case SNMP_DEPOP_COMMIT: 843 if (mdep->path == NULL) { 844 /* unload - find the module */ 845 TAILQ_FOREACH(mdep->m, &lmodules, link) 846 if (strcmp(mdep->m->section, 847 mdep->section) == 0) 848 break; 849 if (mdep->m == NULL) 850 /* no such module - that's ok */ 851 return (SNMP_ERR_NOERROR); 852 853 /* handle unloading in the finalizer */ 854 return (SNMP_ERR_NOERROR); 855 } 856 /* load */ 857 if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) { 858 /* could not load */ 859 return (SNMP_ERR_RES_UNAVAIL); 860 } 861 /* start in finalizer */ 862 return (SNMP_ERR_NOERROR); 863 864 case SNMP_DEPOP_ROLLBACK: 865 if (mdep->path == NULL) { 866 /* rollback unload - the finalizer takes care */ 867 return (SNMP_ERR_NOERROR); 868 } 869 /* rollback load */ 870 lm_unload(mdep->m); 871 return (SNMP_ERR_NOERROR); 872 873 case SNMP_DEPOP_FINISH: 874 if (mdep->path == NULL) { 875 if (mdep->m != NULL && ctx->code == SNMP_RET_OK) 876 lm_unload(mdep->m); 877 } else { 878 if (mdep->m != NULL && ctx->code == SNMP_RET_OK && 879 community != COMM_INITIALIZE) 880 lm_start(mdep->m); 881 free(mdep->path); 882 } 883 return (SNMP_ERR_NOERROR); 884 } 885 abort(); 886 } 887 888 int 889 op_modules(struct snmp_context *ctx, struct snmp_value *value, 890 u_int sub, u_int iidx, enum snmp_op op) 891 { 892 asn_subid_t which = value->var.subs[sub - 1]; 893 struct lmodule *m; 894 u_char *section, *ptr; 895 size_t seclen; 896 struct module_dep *mdep; 897 struct asn_oid idx; 898 899 switch (op) { 900 901 case SNMP_OP_GETNEXT: 902 if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 903 return (SNMP_ERR_NOSUCHNAME); 904 index_append(&value->var, sub, &m->index); 905 break; 906 907 case SNMP_OP_GET: 908 if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 909 return (SNMP_ERR_NOSUCHNAME); 910 break; 911 912 case SNMP_OP_SET: 913 m = FIND_OBJECT_OID(&lmodules, &value->var, sub); 914 if (which != LEAF_begemotSnmpdModulePath) { 915 if (m == NULL) 916 return (SNMP_ERR_NO_CREATION); 917 return (SNMP_ERR_NOT_WRITEABLE); 918 } 919 920 /* the errors in the next few statements can only happen when 921 * m is NULL, hence the NO_CREATION error. */ 922 if (index_decode(&value->var, sub, iidx, 923 §ion, &seclen)) 924 return (SNMP_ERR_NO_CREATION); 925 926 /* check the section name */ 927 if (seclen > LM_SECTION_MAX || seclen == 0) { 928 free(section); 929 return (SNMP_ERR_NO_CREATION); 930 } 931 for (ptr = section; ptr < section + seclen; ptr++) 932 if (!isascii(*ptr) || !isalnum(*ptr)) { 933 free(section); 934 return (SNMP_ERR_NO_CREATION); 935 } 936 if (!isalpha(section[0])) { 937 free(section); 938 return (SNMP_ERR_NO_CREATION); 939 } 940 941 /* check the path */ 942 for (ptr = value->v.octetstring.octets; 943 ptr < value->v.octetstring.octets + value->v.octetstring.len; 944 ptr++) { 945 if (*ptr == '\0') { 946 free(section); 947 return (SNMP_ERR_WRONG_VALUE); 948 } 949 } 950 951 if (m == NULL) { 952 if (value->v.octetstring.len == 0) { 953 free(section); 954 return (SNMP_ERR_INCONS_VALUE); 955 } 956 } else { 957 if (value->v.octetstring.len != 0) { 958 free(section); 959 return (SNMP_ERR_INCONS_VALUE); 960 } 961 } 962 963 asn_slice_oid(&idx, &value->var, sub, value->var.len); 964 965 /* so far, so good */ 966 mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx, 967 &oid_begemotSnmpdModuleTable, &idx, 968 sizeof(*mdep), dep_modules); 969 if (mdep == NULL) { 970 free(section); 971 return (SNMP_ERR_RES_UNAVAIL); 972 } 973 974 if (mdep->section[0] != '\0') { 975 /* two writes to the same entry - bad */ 976 free(section); 977 return (SNMP_ERR_INCONS_VALUE); 978 } 979 980 strncpy(mdep->section, section, seclen); 981 mdep->section[seclen] = '\0'; 982 free(section); 983 984 if (value->v.octetstring.len == 0) 985 mdep->path = NULL; 986 else { 987 if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL) 988 return (SNMP_ERR_RES_UNAVAIL); 989 strncpy(mdep->path, value->v.octetstring.octets, 990 value->v.octetstring.len); 991 mdep->path[value->v.octetstring.len] = '\0'; 992 } 993 ctx->scratch->ptr1 = mdep; 994 return (SNMP_ERR_NOERROR); 995 996 case SNMP_OP_ROLLBACK: 997 case SNMP_OP_COMMIT: 998 return (SNMP_ERR_NOERROR); 999 1000 default: 1001 abort(); 1002 } 1003 1004 switch (which) { 1005 1006 case LEAF_begemotSnmpdModulePath: 1007 return (string_get(value, m->path, -1)); 1008 1009 case LEAF_begemotSnmpdModuleComment: 1010 return (string_get(value, m->config->comment, -1)); 1011 } 1012 abort(); 1013 } 1014 1015 int 1016 op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value, 1017 u_int sub, u_int iidx __unused, enum snmp_op op) 1018 { 1019 switch (op) { 1020 1021 case SNMP_OP_GETNEXT: 1022 abort(); 1023 1024 case SNMP_OP_GET: 1025 switch (value->var.subs[sub - 1]) { 1026 1027 case LEAF_snmpSetSerialNo: 1028 value->v.integer = snmp_serial_no; 1029 break; 1030 1031 default: 1032 abort(); 1033 } 1034 return (SNMP_ERR_NOERROR); 1035 1036 case SNMP_OP_SET: 1037 switch (value->var.subs[sub - 1]) { 1038 1039 case LEAF_snmpSetSerialNo: 1040 if (value->v.integer != snmp_serial_no) 1041 return (SNMP_ERR_INCONS_VALUE); 1042 break; 1043 1044 default: 1045 abort(); 1046 } 1047 return (SNMP_ERR_NOERROR); 1048 1049 case SNMP_OP_ROLLBACK: 1050 return (SNMP_ERR_NOERROR); 1051 1052 case SNMP_OP_COMMIT: 1053 if (snmp_serial_no++ == 2147483647) 1054 snmp_serial_no = 0; 1055 return (SNMP_ERR_NOERROR); 1056 } 1057 abort(); 1058 } 1059 1060 /* 1061 * SNMP Engine 1062 */ 1063 int 1064 op_snmp_engine(struct snmp_context *ctx __unused, struct snmp_value *value, 1065 u_int sub, u_int iidx __unused, enum snmp_op op) 1066 { 1067 asn_subid_t which = value->var.subs[sub - 1]; 1068 1069 switch (op) { 1070 case SNMP_OP_GETNEXT: 1071 abort(); 1072 1073 case SNMP_OP_GET: 1074 break; 1075 1076 case SNMP_OP_SET: 1077 if (community != COMM_INITIALIZE) 1078 return (SNMP_ERR_NOT_WRITEABLE); 1079 switch (which) { 1080 case LEAF_snmpEngineID: 1081 if (value->v.octetstring.len > SNMP_ENGINE_ID_SIZ) 1082 return (SNMP_ERR_WRONG_VALUE); 1083 ctx->scratch->ptr1 = malloc(snmpd_engine.engine_len); 1084 if (ctx->scratch->ptr1 == NULL) 1085 return (SNMP_ERR_GENERR); 1086 memcpy(ctx->scratch->ptr1, snmpd_engine.engine_id, 1087 snmpd_engine.engine_len); 1088 ctx->scratch->int1 = snmpd_engine.engine_len; 1089 snmpd_engine.engine_len = value->v.octetstring.len; 1090 memcpy(snmpd_engine.engine_id, 1091 value->v.octetstring.octets, 1092 value->v.octetstring.len); 1093 break; 1094 1095 case LEAF_snmpEngineMaxMessageSize: 1096 ctx->scratch->int1 = snmpd_engine.max_msg_size; 1097 snmpd_engine.max_msg_size = value->v.integer; 1098 break; 1099 1100 default: 1101 return (SNMP_ERR_NOT_WRITEABLE); 1102 } 1103 return (SNMP_ERR_NOERROR); 1104 1105 case SNMP_OP_ROLLBACK: 1106 switch (which) { 1107 case LEAF_snmpEngineID: 1108 snmpd_engine.engine_len = ctx->scratch->int1; 1109 memcpy(snmpd_engine.engine_id, ctx->scratch->ptr1, 1110 snmpd_engine.engine_len); 1111 free(ctx->scratch->ptr1); 1112 break; 1113 1114 case LEAF_snmpEngineMaxMessageSize: 1115 snmpd_engine.max_msg_size = ctx->scratch->int1; 1116 break; 1117 1118 default: 1119 abort(); 1120 } 1121 return (SNMP_ERR_NOERROR); 1122 1123 case SNMP_OP_COMMIT: 1124 if (which == LEAF_snmpEngineID) { 1125 if (set_snmpd_engine() < 0) { 1126 snmpd_engine.engine_len = ctx->scratch->int1; 1127 memcpy(snmpd_engine.engine_id, 1128 ctx->scratch->ptr1, ctx->scratch->int1); 1129 } 1130 free(ctx->scratch->ptr1); 1131 } 1132 return (SNMP_ERR_NOERROR); 1133 } 1134 1135 1136 switch (which) { 1137 case LEAF_snmpEngineID: 1138 return (string_get(value, snmpd_engine.engine_id, 1139 snmpd_engine.engine_len)); 1140 case LEAF_snmpEngineBoots: 1141 value->v.integer = snmpd_engine.engine_boots; 1142 break; 1143 case LEAF_snmpEngineTime: 1144 snmpd_engine.engine_time = (get_ticks() - start_tick) / 100ULL; 1145 value->v.integer = snmpd_engine.engine_time; 1146 break; 1147 case LEAF_snmpEngineMaxMessageSize: 1148 value->v.integer = snmpd_engine.max_msg_size; 1149 break; 1150 default: 1151 return (SNMP_ERR_NOSUCHNAME); 1152 } 1153 1154 return (SNMP_ERR_NOERROR); 1155 } 1156 1157 /* 1158 * Transport table 1159 */ 1160 int 1161 op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value, 1162 u_int sub, u_int iidx, enum snmp_op op) 1163 { 1164 asn_subid_t which = value->var.subs[sub - 1]; 1165 struct transport *t; 1166 u_char *tname, *ptr; 1167 size_t tnamelen; 1168 1169 switch (op) { 1170 1171 case SNMP_OP_GETNEXT: 1172 if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub)) 1173 == NULL) 1174 return (SNMP_ERR_NOSUCHNAME); 1175 index_append(&value->var, sub, &t->index); 1176 break; 1177 1178 case SNMP_OP_GET: 1179 if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub)) 1180 == NULL) 1181 return (SNMP_ERR_NOSUCHNAME); 1182 break; 1183 1184 case SNMP_OP_SET: 1185 t = FIND_OBJECT_OID(&transport_list, &value->var, sub); 1186 if (which != LEAF_begemotSnmpdTransportStatus) { 1187 if (t == NULL) 1188 return (SNMP_ERR_NO_CREATION); 1189 return (SNMP_ERR_NOT_WRITEABLE); 1190 } 1191 1192 /* the errors in the next few statements can only happen when 1193 * t is NULL, hence the NO_CREATION error. */ 1194 if (index_decode(&value->var, sub, iidx, 1195 &tname, &tnamelen)) 1196 return (SNMP_ERR_NO_CREATION); 1197 1198 /* check the section name */ 1199 if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) { 1200 free(tname); 1201 return (SNMP_ERR_NO_CREATION); 1202 } 1203 for (ptr = tname; ptr < tname + tnamelen; ptr++) { 1204 if (!isascii(*ptr) || !isalnum(*ptr)) { 1205 free(tname); 1206 return (SNMP_ERR_NO_CREATION); 1207 } 1208 } 1209 1210 /* for now */ 1211 return (SNMP_ERR_NOT_WRITEABLE); 1212 1213 case SNMP_OP_ROLLBACK: 1214 case SNMP_OP_COMMIT: 1215 return (SNMP_ERR_NOERROR); 1216 default: 1217 abort(); 1218 } 1219 1220 switch (which) { 1221 1222 case LEAF_begemotSnmpdTransportStatus: 1223 value->v.integer = 1; 1224 break; 1225 1226 case LEAF_begemotSnmpdTransportOid: 1227 memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id)); 1228 break; 1229 } 1230 return (SNMP_ERR_NOERROR); 1231 } 1232