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