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