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 struct asn_oid idx; 755 struct community *c; 756 asn_subid_t which = value->var.subs[sub - 1]; 757 758 switch (op) { 759 760 case SNMP_OP_GETNEXT: 761 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 762 (c = NEXT_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 763 return (SNMP_ERR_NOSUCHNAME); 764 index_append(&value->var, sub, &c->index); 765 break; 766 767 case SNMP_OP_GET: 768 if ((community != COMM_INITIALIZE && snmpd.comm_dis) || 769 (c = FIND_OBJECT_OID(&community_list, &value->var, sub)) == NULL) 770 return (SNMP_ERR_NOSUCHNAME); 771 break; 772 773 case SNMP_OP_SET: 774 if (community != COMM_INITIALIZE && snmpd.comm_dis) 775 return (SNMP_ERR_NOT_WRITEABLE); 776 idx.len = 2; 777 idx.subs[0] = 0; 778 idx.subs[1] = value->var.subs[value->var.len - 1]; 779 switch (which) { 780 case LEAF_begemotSnmpdCommunityString: 781 /* check that given string is unique */ 782 TAILQ_FOREACH(c, &community_list, link) { 783 if (!asn_compare_oid(&idx, &c->index)) 784 continue; 785 if (c->string != NULL && strcmp(c->string, 786 value->v.octetstring.octets) == 0) 787 return (SNMP_ERR_WRONG_VALUE); 788 } 789 case LEAF_begemotSnmpdCommunityPermission: 790 break; 791 default: 792 return (SNMP_ERR_NOT_WRITEABLE); 793 } 794 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 795 sub)) == NULL) { 796 /* create new community and use user sepcified index */ 797 c = comm_define_ordered(COMM_READ, "SNMP Custom Community", 798 &idx, NULL, NULL); 799 if (c == NULL) 800 return (SNMP_ERR_NO_CREATION); 801 } 802 switch (which) { 803 case LEAF_begemotSnmpdCommunityString: 804 return (string_save(value, ctx, -1, &c->string)); 805 case LEAF_begemotSnmpdCommunityPermission: 806 if (value->v.integer != COMM_READ && 807 value->v.integer != COMM_WRITE) 808 return (SNMP_ERR_WRONG_VALUE); 809 c->private = value->v.integer; 810 break; 811 default: 812 return (SNMP_ERR_NOT_WRITEABLE); 813 } 814 return (SNMP_ERR_NOERROR); 815 816 case SNMP_OP_ROLLBACK: 817 if (which == LEAF_begemotSnmpdCommunityString) { 818 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 819 sub)) == NULL) 820 string_free(ctx); 821 else 822 string_rollback(ctx, &c->string); 823 return (SNMP_ERR_NOERROR); 824 } 825 if (which == LEAF_begemotSnmpdCommunityPermission) 826 return (SNMP_ERR_NOERROR); 827 abort(); 828 829 case SNMP_OP_COMMIT: 830 if (which == LEAF_begemotSnmpdCommunityString) { 831 if ((c = FIND_OBJECT_OID(&community_list, &value->var, 832 sub)) == NULL) 833 string_free(ctx); 834 else 835 string_commit(ctx); 836 return (SNMP_ERR_NOERROR); 837 } 838 if (which == LEAF_begemotSnmpdCommunityPermission) 839 return (SNMP_ERR_NOERROR); 840 abort(); 841 842 default: 843 abort(); 844 } 845 846 switch (which) { 847 848 case LEAF_begemotSnmpdCommunityString: 849 return (string_get(value, c->string, -1)); 850 851 case LEAF_begemotSnmpdCommunityDescr: 852 return (string_get(value, c->descr, -1)); 853 854 case LEAF_begemotSnmpdCommunityPermission: 855 value->v.integer = c->private; 856 return (SNMP_ERR_NOERROR); 857 default: 858 return (SNMP_ERR_NOT_WRITEABLE); 859 } 860 abort(); 861 } 862 863 /* 864 * Module table. 865 */ 866 struct module_dep { 867 struct snmp_dependency dep; 868 u_char section[LM_SECTION_MAX + 1]; 869 u_char *path; 870 struct lmodule *m; 871 }; 872 873 static int 874 dep_modules(struct snmp_context *ctx, struct snmp_dependency *dep, 875 enum snmp_depop op) 876 { 877 struct module_dep *mdep = (struct module_dep *)(void *)dep; 878 879 switch (op) { 880 881 case SNMP_DEPOP_COMMIT: 882 if (mdep->path == NULL) { 883 /* unload - find the module */ 884 TAILQ_FOREACH(mdep->m, &lmodules, link) 885 if (strcmp(mdep->m->section, 886 mdep->section) == 0) 887 break; 888 if (mdep->m == NULL) 889 /* no such module - that's ok */ 890 return (SNMP_ERR_NOERROR); 891 892 /* handle unloading in the finalizer */ 893 return (SNMP_ERR_NOERROR); 894 } 895 /* load */ 896 if ((mdep->m = lm_load(mdep->path, mdep->section)) == NULL) { 897 /* could not load */ 898 return (SNMP_ERR_RES_UNAVAIL); 899 } 900 /* start in finalizer */ 901 return (SNMP_ERR_NOERROR); 902 903 case SNMP_DEPOP_ROLLBACK: 904 if (mdep->path == NULL) { 905 /* rollback unload - the finalizer takes care */ 906 return (SNMP_ERR_NOERROR); 907 } 908 /* rollback load */ 909 lm_unload(mdep->m); 910 return (SNMP_ERR_NOERROR); 911 912 case SNMP_DEPOP_FINISH: 913 if (mdep->path == NULL) { 914 if (mdep->m != NULL && ctx->code == SNMP_RET_OK) 915 lm_unload(mdep->m); 916 } else { 917 if (mdep->m != NULL && ctx->code == SNMP_RET_OK && 918 community != COMM_INITIALIZE) 919 lm_start(mdep->m); 920 free(mdep->path); 921 } 922 return (SNMP_ERR_NOERROR); 923 } 924 abort(); 925 } 926 927 int 928 op_modules(struct snmp_context *ctx, struct snmp_value *value, 929 u_int sub, u_int iidx, enum snmp_op op) 930 { 931 asn_subid_t which = value->var.subs[sub - 1]; 932 struct lmodule *m; 933 u_char *section, *ptr; 934 size_t seclen; 935 struct module_dep *mdep; 936 struct asn_oid idx; 937 938 switch (op) { 939 940 case SNMP_OP_GETNEXT: 941 if ((m = NEXT_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 942 return (SNMP_ERR_NOSUCHNAME); 943 index_append(&value->var, sub, &m->index); 944 break; 945 946 case SNMP_OP_GET: 947 if ((m = FIND_OBJECT_OID(&lmodules, &value->var, sub)) == NULL) 948 return (SNMP_ERR_NOSUCHNAME); 949 break; 950 951 case SNMP_OP_SET: 952 m = FIND_OBJECT_OID(&lmodules, &value->var, sub); 953 if (which != LEAF_begemotSnmpdModulePath) { 954 if (m == NULL) 955 return (SNMP_ERR_NO_CREATION); 956 return (SNMP_ERR_NOT_WRITEABLE); 957 } 958 959 /* the errors in the next few statements can only happen when 960 * m is NULL, hence the NO_CREATION error. */ 961 if (index_decode(&value->var, sub, iidx, 962 §ion, &seclen)) 963 return (SNMP_ERR_NO_CREATION); 964 965 /* check the section name */ 966 if (seclen > LM_SECTION_MAX || seclen == 0) { 967 free(section); 968 return (SNMP_ERR_NO_CREATION); 969 } 970 for (ptr = section; ptr < section + seclen; ptr++) 971 if (!isascii(*ptr) || !isalnum(*ptr)) { 972 free(section); 973 return (SNMP_ERR_NO_CREATION); 974 } 975 if (!isalpha(section[0])) { 976 free(section); 977 return (SNMP_ERR_NO_CREATION); 978 } 979 980 /* check the path */ 981 for (ptr = value->v.octetstring.octets; 982 ptr < value->v.octetstring.octets + value->v.octetstring.len; 983 ptr++) { 984 if (*ptr == '\0') { 985 free(section); 986 return (SNMP_ERR_WRONG_VALUE); 987 } 988 } 989 990 if (m == NULL) { 991 if (value->v.octetstring.len == 0) { 992 free(section); 993 return (SNMP_ERR_INCONS_VALUE); 994 } 995 } else { 996 if (value->v.octetstring.len != 0) { 997 free(section); 998 return (SNMP_ERR_INCONS_VALUE); 999 } 1000 } 1001 1002 asn_slice_oid(&idx, &value->var, sub, value->var.len); 1003 1004 /* so far, so good */ 1005 mdep = (struct module_dep *)(void *)snmp_dep_lookup(ctx, 1006 &oid_begemotSnmpdModuleTable, &idx, 1007 sizeof(*mdep), dep_modules); 1008 if (mdep == NULL) { 1009 free(section); 1010 return (SNMP_ERR_RES_UNAVAIL); 1011 } 1012 1013 if (mdep->section[0] != '\0') { 1014 /* two writes to the same entry - bad */ 1015 free(section); 1016 return (SNMP_ERR_INCONS_VALUE); 1017 } 1018 1019 strncpy(mdep->section, section, seclen); 1020 mdep->section[seclen] = '\0'; 1021 free(section); 1022 1023 if (value->v.octetstring.len == 0) 1024 mdep->path = NULL; 1025 else { 1026 if ((mdep->path = malloc(value->v.octetstring.len + 1)) == NULL) 1027 return (SNMP_ERR_RES_UNAVAIL); 1028 strncpy(mdep->path, value->v.octetstring.octets, 1029 value->v.octetstring.len); 1030 mdep->path[value->v.octetstring.len] = '\0'; 1031 } 1032 ctx->scratch->ptr1 = mdep; 1033 return (SNMP_ERR_NOERROR); 1034 1035 case SNMP_OP_ROLLBACK: 1036 case SNMP_OP_COMMIT: 1037 return (SNMP_ERR_NOERROR); 1038 1039 default: 1040 abort(); 1041 } 1042 1043 switch (which) { 1044 1045 case LEAF_begemotSnmpdModulePath: 1046 return (string_get(value, m->path, -1)); 1047 1048 case LEAF_begemotSnmpdModuleComment: 1049 return (string_get(value, m->config->comment, -1)); 1050 } 1051 abort(); 1052 } 1053 1054 int 1055 op_snmp_set(struct snmp_context *ctx __unused, struct snmp_value *value, 1056 u_int sub, u_int iidx __unused, enum snmp_op op) 1057 { 1058 switch (op) { 1059 1060 case SNMP_OP_GETNEXT: 1061 abort(); 1062 1063 case SNMP_OP_GET: 1064 switch (value->var.subs[sub - 1]) { 1065 1066 case LEAF_snmpSetSerialNo: 1067 value->v.integer = snmp_serial_no; 1068 break; 1069 1070 default: 1071 abort(); 1072 } 1073 return (SNMP_ERR_NOERROR); 1074 1075 case SNMP_OP_SET: 1076 switch (value->var.subs[sub - 1]) { 1077 1078 case LEAF_snmpSetSerialNo: 1079 if (value->v.integer != snmp_serial_no) 1080 return (SNMP_ERR_INCONS_VALUE); 1081 break; 1082 1083 default: 1084 abort(); 1085 } 1086 return (SNMP_ERR_NOERROR); 1087 1088 case SNMP_OP_ROLLBACK: 1089 return (SNMP_ERR_NOERROR); 1090 1091 case SNMP_OP_COMMIT: 1092 if (snmp_serial_no++ == 2147483647) 1093 snmp_serial_no = 0; 1094 return (SNMP_ERR_NOERROR); 1095 } 1096 abort(); 1097 } 1098 1099 /* 1100 * SNMP Engine 1101 */ 1102 int 1103 op_snmp_engine(struct snmp_context *ctx __unused, struct snmp_value *value, 1104 u_int sub, u_int iidx __unused, enum snmp_op op) 1105 { 1106 asn_subid_t which = value->var.subs[sub - 1]; 1107 1108 switch (op) { 1109 case SNMP_OP_GETNEXT: 1110 abort(); 1111 1112 case SNMP_OP_GET: 1113 break; 1114 1115 case SNMP_OP_SET: 1116 if (community != COMM_INITIALIZE) 1117 return (SNMP_ERR_NOT_WRITEABLE); 1118 switch (which) { 1119 case LEAF_snmpEngineID: 1120 if (value->v.octetstring.len > SNMP_ENGINE_ID_SIZ) 1121 return (SNMP_ERR_WRONG_VALUE); 1122 ctx->scratch->ptr1 = malloc(snmpd_engine.engine_len); 1123 if (ctx->scratch->ptr1 == NULL) 1124 return (SNMP_ERR_GENERR); 1125 memcpy(ctx->scratch->ptr1, snmpd_engine.engine_id, 1126 snmpd_engine.engine_len); 1127 ctx->scratch->int1 = snmpd_engine.engine_len; 1128 snmpd_engine.engine_len = value->v.octetstring.len; 1129 memcpy(snmpd_engine.engine_id, 1130 value->v.octetstring.octets, 1131 value->v.octetstring.len); 1132 break; 1133 1134 case LEAF_snmpEngineMaxMessageSize: 1135 ctx->scratch->int1 = snmpd_engine.max_msg_size; 1136 snmpd_engine.max_msg_size = value->v.integer; 1137 break; 1138 1139 default: 1140 return (SNMP_ERR_NOT_WRITEABLE); 1141 } 1142 return (SNMP_ERR_NOERROR); 1143 1144 case SNMP_OP_ROLLBACK: 1145 switch (which) { 1146 case LEAF_snmpEngineID: 1147 snmpd_engine.engine_len = ctx->scratch->int1; 1148 memcpy(snmpd_engine.engine_id, ctx->scratch->ptr1, 1149 snmpd_engine.engine_len); 1150 free(ctx->scratch->ptr1); 1151 break; 1152 1153 case LEAF_snmpEngineMaxMessageSize: 1154 snmpd_engine.max_msg_size = ctx->scratch->int1; 1155 break; 1156 1157 default: 1158 abort(); 1159 } 1160 return (SNMP_ERR_NOERROR); 1161 1162 case SNMP_OP_COMMIT: 1163 if (which == LEAF_snmpEngineID) { 1164 if (set_snmpd_engine() < 0) { 1165 snmpd_engine.engine_len = ctx->scratch->int1; 1166 memcpy(snmpd_engine.engine_id, 1167 ctx->scratch->ptr1, ctx->scratch->int1); 1168 } 1169 free(ctx->scratch->ptr1); 1170 } 1171 return (SNMP_ERR_NOERROR); 1172 } 1173 1174 1175 switch (which) { 1176 case LEAF_snmpEngineID: 1177 return (string_get(value, snmpd_engine.engine_id, 1178 snmpd_engine.engine_len)); 1179 case LEAF_snmpEngineBoots: 1180 value->v.integer = snmpd_engine.engine_boots; 1181 break; 1182 case LEAF_snmpEngineTime: 1183 update_snmpd_engine_time(); 1184 value->v.integer = snmpd_engine.engine_time; 1185 break; 1186 case LEAF_snmpEngineMaxMessageSize: 1187 value->v.integer = snmpd_engine.max_msg_size; 1188 break; 1189 default: 1190 return (SNMP_ERR_NOSUCHNAME); 1191 } 1192 1193 return (SNMP_ERR_NOERROR); 1194 } 1195 1196 /* 1197 * Transport table 1198 */ 1199 int 1200 op_transport_table(struct snmp_context *ctx __unused, struct snmp_value *value, 1201 u_int sub, u_int iidx, enum snmp_op op) 1202 { 1203 asn_subid_t which = value->var.subs[sub - 1]; 1204 struct transport *t; 1205 u_char *tname, *ptr; 1206 size_t tnamelen; 1207 1208 switch (op) { 1209 1210 case SNMP_OP_GETNEXT: 1211 if ((t = NEXT_OBJECT_OID(&transport_list, &value->var, sub)) 1212 == NULL) 1213 return (SNMP_ERR_NOSUCHNAME); 1214 index_append(&value->var, sub, &t->index); 1215 break; 1216 1217 case SNMP_OP_GET: 1218 if ((t = FIND_OBJECT_OID(&transport_list, &value->var, sub)) 1219 == NULL) 1220 return (SNMP_ERR_NOSUCHNAME); 1221 break; 1222 1223 case SNMP_OP_SET: 1224 t = FIND_OBJECT_OID(&transport_list, &value->var, sub); 1225 if (which != LEAF_begemotSnmpdTransportStatus) { 1226 if (t == NULL) 1227 return (SNMP_ERR_NO_CREATION); 1228 return (SNMP_ERR_NOT_WRITEABLE); 1229 } 1230 1231 /* the errors in the next few statements can only happen when 1232 * t is NULL, hence the NO_CREATION error. */ 1233 if (index_decode(&value->var, sub, iidx, 1234 &tname, &tnamelen)) 1235 return (SNMP_ERR_NO_CREATION); 1236 1237 /* check the section name */ 1238 if (tnamelen >= TRANS_NAMELEN || tnamelen == 0) { 1239 free(tname); 1240 return (SNMP_ERR_NO_CREATION); 1241 } 1242 for (ptr = tname; ptr < tname + tnamelen; ptr++) { 1243 if (!isascii(*ptr) || !isalnum(*ptr)) { 1244 free(tname); 1245 return (SNMP_ERR_NO_CREATION); 1246 } 1247 } 1248 1249 /* for now */ 1250 return (SNMP_ERR_NOT_WRITEABLE); 1251 1252 case SNMP_OP_ROLLBACK: 1253 case SNMP_OP_COMMIT: 1254 return (SNMP_ERR_NOERROR); 1255 default: 1256 abort(); 1257 } 1258 1259 switch (which) { 1260 1261 case LEAF_begemotSnmpdTransportStatus: 1262 value->v.integer = 1; 1263 break; 1264 1265 case LEAF_begemotSnmpdTransportOid: 1266 memcpy(&value->v.oid, &t->vtab->id, sizeof(t->vtab->id)); 1267 break; 1268 } 1269 return (SNMP_ERR_NOERROR); 1270 } 1271