1 2 3 /* 4 * Copyright (c) 2007, 2008 Reyk Floeter <reyk@openbsd.org> 5 * 6 * Permission to use, copy, modify, and distribute this software for any 7 * purpose with or without fee is hereby granted, provided that the above 8 * copyright notice and this permission notice appear in all copies. 9 * 10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 17 */ 18 19 #include <sys/queue.h> 20 #include <sys/types.h> 21 #include <sys/stat.h> 22 #include <sys/socket.h> 23 #include <sys/un.h> 24 #include <sys/tree.h> 25 #include <sys/sysctl.h> 26 27 #include <net/if.h> 28 #include <net/if_dl.h> 29 #include <net/if_arp.h> 30 #include <net/if_media.h> 31 #include <net/route.h> 32 #include <netinet/in.h> 33 #include <netinet/if_ether.h> 34 #include <arpa/inet.h> 35 36 #include <stdlib.h> 37 #include <stdio.h> 38 #include <errno.h> 39 #include <event.h> 40 #include <fcntl.h> 41 #include <string.h> 42 #include <unistd.h> 43 #include <limits.h> 44 #include <pwd.h> 45 #include <vis.h> 46 47 #include "snmpd.h" 48 #include "mib.h" 49 50 #define MINIMUM(a, b) (((a) < (b)) ? (a) : (b)) 51 52 extern struct snmpd *env; 53 54 RB_HEAD(oidtree, oid); 55 RB_PROTOTYPE(oidtree, oid, o_element, smi_oid_cmp); 56 struct oidtree smi_oidtree; 57 58 RB_HEAD(keytree, oid); 59 RB_PROTOTYPE(keytree, oid, o_keyword, smi_key_cmp); 60 struct keytree smi_keytree; 61 62 u_long 63 smi_getticks(void) 64 { 65 struct timeval now, run; 66 u_long ticks; 67 68 gettimeofday(&now, NULL); 69 if (timercmp(&now, &env->sc_starttime, <=)) 70 return (0); 71 timersub(&now, &env->sc_starttime, &run); 72 ticks = run.tv_sec * 100; 73 if (run.tv_usec) 74 ticks += run.tv_usec / 10000; 75 76 return (ticks); 77 } 78 79 void 80 smi_oidlen(struct ber_oid *o) 81 { 82 size_t i; 83 84 for (i = 0; i < BER_MAX_OID_LEN && o->bo_id[i] != 0; i++) 85 ; 86 o->bo_n = i; 87 } 88 89 void 90 smi_scalar_oidlen(struct ber_oid *o) 91 { 92 smi_oidlen(o); 93 94 /* Append .0. */ 95 if (o->bo_n < BER_MAX_OID_LEN) 96 o->bo_n++; 97 } 98 99 char * 100 smi_oid2string(struct ber_oid *o, char *buf, size_t len, size_t skip) 101 { 102 char str[256]; 103 struct oid *value, key; 104 size_t i, lookup = 1; 105 106 bzero(buf, len); 107 bzero(&key, sizeof(key)); 108 bcopy(o, &key.o_id, sizeof(struct ber_oid)); 109 key.o_flags |= OID_KEY; /* do not match wildcards */ 110 111 if (env->sc_flags & SNMPD_F_NONAMES) 112 lookup = 0; 113 114 for (i = 0; i < o->bo_n; i++) { 115 key.o_oidlen = i + 1; 116 if (lookup && skip > i) 117 continue; 118 if (lookup && 119 (value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL) 120 snprintf(str, sizeof(str), "%s", value->o_name); 121 else 122 snprintf(str, sizeof(str), "%d", key.o_oid[i]); 123 strlcat(buf, str, len); 124 if (i < (o->bo_n - 1)) 125 strlcat(buf, ".", len); 126 } 127 128 return (buf); 129 } 130 131 int 132 smi_string2oid(const char *oidstr, struct ber_oid *o) 133 { 134 char *sp, *p, str[BUFSIZ]; 135 const char *errstr; 136 struct oid *oid; 137 struct ber_oid ko; 138 139 if (strlcpy(str, oidstr, sizeof(str)) >= sizeof(str)) 140 return (-1); 141 bzero(o, sizeof(*o)); 142 143 /* 144 * Parse OID strings in the common form n.n.n or n-n-n. 145 * Based on ber_string2oid with additional support for symbolic names. 146 */ 147 for (p = sp = str; p != NULL; sp = p) { 148 if ((p = strpbrk(p, ".-")) != NULL) 149 *p++ = '\0'; 150 if ((oid = smi_findkey(sp)) != NULL) { 151 bcopy(&oid->o_id, &ko, sizeof(ko)); 152 if (o->bo_n && ber_oid_cmp(o, &ko) != 2) 153 return (-1); 154 bcopy(&ko, o, sizeof(*o)); 155 errstr = NULL; 156 } else { 157 o->bo_id[o->bo_n++] = 158 strtonum(sp, 0, UINT_MAX, &errstr); 159 } 160 if (errstr || o->bo_n > BER_MAX_OID_LEN) 161 return (-1); 162 } 163 164 return (0); 165 } 166 167 void 168 smi_delete(struct oid *oid) 169 { 170 struct oid key, *value; 171 172 bzero(&key, sizeof(key)); 173 bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid)); 174 if ((value = RB_FIND(oidtree, &smi_oidtree, &key)) != NULL && 175 value == oid) 176 RB_REMOVE(oidtree, &smi_oidtree, value); 177 178 free(oid->o_data); 179 if (oid->o_flags & OID_DYNAMIC) { 180 free(oid->o_name); 181 free(oid); 182 } 183 } 184 185 int 186 smi_insert(struct oid *oid) 187 { 188 struct oid key, *value; 189 190 if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL) 191 fatalx("smi_insert: invalid MIB table"); 192 193 bzero(&key, sizeof(key)); 194 bcopy(&oid->o_id, &key.o_id, sizeof(struct ber_oid)); 195 value = RB_FIND(oidtree, &smi_oidtree, &key); 196 if (value != NULL) 197 return (-1); 198 199 RB_INSERT(oidtree, &smi_oidtree, oid); 200 return (0); 201 } 202 203 void 204 smi_mibtree(struct oid *oids) 205 { 206 struct oid *oid, *decl; 207 size_t i; 208 209 for (i = 0; oids[i].o_oid[0] != 0; i++) { 210 oid = &oids[i]; 211 smi_oidlen(&oid->o_id); 212 if (oid->o_name != NULL) { 213 if ((oid->o_flags & OID_TABLE) && oid->o_get == NULL) 214 fatalx("smi_mibtree: invalid MIB table"); 215 RB_INSERT(oidtree, &smi_oidtree, oid); 216 RB_INSERT(keytree, &smi_keytree, oid); 217 continue; 218 } 219 decl = RB_FIND(oidtree, &smi_oidtree, oid); 220 if (decl == NULL) 221 fatalx("smi_mibtree: undeclared MIB"); 222 decl->o_flags = oid->o_flags; 223 decl->o_get = oid->o_get; 224 decl->o_set = oid->o_set; 225 decl->o_table = oid->o_table; 226 decl->o_val = oid->o_val; 227 decl->o_data = oid->o_data; 228 } 229 } 230 231 int 232 smi_init(void) 233 { 234 /* Initialize the Structure of Managed Information (SMI) */ 235 RB_INIT(&smi_oidtree); 236 mib_init(); 237 return (0); 238 } 239 240 struct oid * 241 smi_find(struct oid *oid) 242 { 243 return (RB_FIND(oidtree, &smi_oidtree, oid)); 244 } 245 246 struct oid * 247 smi_findkey(char *name) 248 { 249 struct oid oid; 250 if (name == NULL) 251 return (NULL); 252 oid.o_name = name; 253 return (RB_FIND(keytree, &smi_keytree, &oid)); 254 } 255 256 struct oid * 257 smi_next(struct oid *oid) 258 { 259 return (RB_NEXT(oidtree, &smi_oidtree, oid)); 260 } 261 262 struct oid * 263 smi_foreach(struct oid *oid, u_int flags) 264 { 265 /* 266 * Traverse the tree of MIBs with the option to check 267 * for specific OID flags. 268 */ 269 if (oid == NULL) { 270 oid = RB_MIN(oidtree, &smi_oidtree); 271 if (oid == NULL) 272 return (NULL); 273 if (flags == 0 || (oid->o_flags & flags)) 274 return (oid); 275 } 276 for (;;) { 277 oid = RB_NEXT(oidtree, &smi_oidtree, oid); 278 if (oid == NULL) 279 break; 280 if (flags == 0 || (oid->o_flags & flags)) 281 return (oid); 282 } 283 284 return (oid); 285 } 286 287 #ifdef DEBUG 288 void 289 smi_debug_elements(struct ber_element *root) 290 { 291 static int indent = 0; 292 char *value; 293 int constructed; 294 295 /* calculate lengths */ 296 ber_calc_len(root); 297 298 switch (root->be_encoding) { 299 case BER_TYPE_SEQUENCE: 300 case BER_TYPE_SET: 301 constructed = root->be_encoding; 302 break; 303 default: 304 constructed = 0; 305 break; 306 } 307 308 fprintf(stderr, "%*slen %lu ", indent, "", root->be_len); 309 switch (root->be_class) { 310 case BER_CLASS_UNIVERSAL: 311 fprintf(stderr, "class: universal(%u) type: ", root->be_class); 312 switch (root->be_type) { 313 case BER_TYPE_EOC: 314 fprintf(stderr, "end-of-content"); 315 break; 316 case BER_TYPE_BOOLEAN: 317 fprintf(stderr, "boolean"); 318 break; 319 case BER_TYPE_INTEGER: 320 fprintf(stderr, "integer"); 321 break; 322 case BER_TYPE_BITSTRING: 323 fprintf(stderr, "bit-string"); 324 break; 325 case BER_TYPE_OCTETSTRING: 326 fprintf(stderr, "octet-string"); 327 break; 328 case BER_TYPE_NULL: 329 fprintf(stderr, "null"); 330 break; 331 case BER_TYPE_OBJECT: 332 fprintf(stderr, "object"); 333 break; 334 case BER_TYPE_ENUMERATED: 335 fprintf(stderr, "enumerated"); 336 break; 337 case BER_TYPE_SEQUENCE: 338 fprintf(stderr, "sequence"); 339 break; 340 case BER_TYPE_SET: 341 fprintf(stderr, "set"); 342 break; 343 } 344 break; 345 case BER_CLASS_APPLICATION: 346 fprintf(stderr, "class: application(%u) type: ", 347 root->be_class); 348 switch (root->be_type) { 349 case SNMP_T_IPADDR: 350 fprintf(stderr, "ipaddr"); 351 break; 352 case SNMP_T_COUNTER32: 353 fprintf(stderr, "counter32"); 354 break; 355 case SNMP_T_GAUGE32: 356 fprintf(stderr, "gauge32"); 357 break; 358 case SNMP_T_TIMETICKS: 359 fprintf(stderr, "timeticks"); 360 break; 361 case SNMP_T_OPAQUE: 362 fprintf(stderr, "opaque"); 363 break; 364 case SNMP_T_COUNTER64: 365 fprintf(stderr, "counter64"); 366 break; 367 } 368 break; 369 case BER_CLASS_CONTEXT: 370 fprintf(stderr, "class: context(%u) type: ", 371 root->be_class); 372 switch (root->be_type) { 373 case SNMP_C_GETREQ: 374 fprintf(stderr, "getreq"); 375 break; 376 case SNMP_C_GETNEXTREQ: 377 fprintf(stderr, "nextreq"); 378 break; 379 case SNMP_C_GETRESP: 380 fprintf(stderr, "getresp"); 381 break; 382 case SNMP_C_SETREQ: 383 fprintf(stderr, "setreq"); 384 break; 385 case SNMP_C_TRAP: 386 fprintf(stderr, "trap"); 387 break; 388 case SNMP_C_GETBULKREQ: 389 fprintf(stderr, "getbulkreq"); 390 break; 391 case SNMP_C_INFORMREQ: 392 fprintf(stderr, "informreq"); 393 break; 394 case SNMP_C_TRAPV2: 395 fprintf(stderr, "trapv2"); 396 break; 397 case SNMP_C_REPORT: 398 fprintf(stderr, "report"); 399 break; 400 } 401 break; 402 case BER_CLASS_PRIVATE: 403 fprintf(stderr, "class: private(%u) type: ", root->be_class); 404 break; 405 default: 406 fprintf(stderr, "class: <INVALID>(%u) type: ", root->be_class); 407 break; 408 } 409 fprintf(stderr, "(%lu) encoding %lu ", 410 root->be_type, root->be_encoding); 411 412 if ((value = smi_print_element(root)) == NULL) 413 goto invalid; 414 415 switch (root->be_encoding) { 416 case BER_TYPE_BOOLEAN: 417 fprintf(stderr, "%s", value); 418 break; 419 case BER_TYPE_INTEGER: 420 case BER_TYPE_ENUMERATED: 421 fprintf(stderr, "value %s", value); 422 break; 423 case BER_TYPE_BITSTRING: 424 fprintf(stderr, "hexdump %s", value); 425 break; 426 case BER_TYPE_OBJECT: 427 fprintf(stderr, "oid %s", value); 428 break; 429 case BER_TYPE_OCTETSTRING: 430 if (root->be_class == BER_CLASS_APPLICATION && 431 root->be_type == SNMP_T_IPADDR) { 432 fprintf(stderr, "addr %s", value); 433 } else { 434 fprintf(stderr, "string %s", value); 435 } 436 break; 437 case BER_TYPE_NULL: /* no payload */ 438 case BER_TYPE_EOC: 439 case BER_TYPE_SEQUENCE: 440 case BER_TYPE_SET: 441 default: 442 fprintf(stderr, "%s", value); 443 break; 444 } 445 446 invalid: 447 if (value == NULL) 448 fprintf(stderr, "<INVALID>"); 449 else 450 free(value); 451 fprintf(stderr, "\n"); 452 453 if (constructed) 454 root->be_encoding = constructed; 455 456 if (constructed && root->be_sub) { 457 indent += 2; 458 smi_debug_elements(root->be_sub); 459 indent -= 2; 460 } 461 if (root->be_next) 462 smi_debug_elements(root->be_next); 463 } 464 #endif 465 466 char * 467 smi_print_element(struct ber_element *root) 468 { 469 char *str = NULL, *buf, *p; 470 size_t len, i; 471 long long v; 472 int d; 473 struct ber_oid o; 474 char strbuf[BUFSIZ]; 475 476 switch (root->be_encoding) { 477 case BER_TYPE_BOOLEAN: 478 if (ber_get_boolean(root, &d) == -1) 479 goto fail; 480 if (asprintf(&str, "%s(%d)", d ? "true" : "false", d) == -1) 481 goto fail; 482 break; 483 case BER_TYPE_INTEGER: 484 case BER_TYPE_ENUMERATED: 485 if (ber_get_integer(root, &v) == -1) 486 goto fail; 487 if (asprintf(&str, "%lld", v) == -1) 488 goto fail; 489 break; 490 case BER_TYPE_BITSTRING: 491 if (ber_get_bitstring(root, (void *)&buf, &len) == -1) 492 goto fail; 493 if ((str = calloc(1, len * 2 + 1)) == NULL) 494 goto fail; 495 for (p = str, i = 0; i < len; i++) { 496 snprintf(p, 3, "%02x", buf[i]); 497 p += 2; 498 } 499 break; 500 case BER_TYPE_OBJECT: 501 if (ber_get_oid(root, &o) == -1) 502 goto fail; 503 if (asprintf(&str, "%s", 504 smi_oid2string(&o, strbuf, sizeof(strbuf), 0)) == -1) 505 goto fail; 506 break; 507 case BER_TYPE_OCTETSTRING: 508 if (ber_get_string(root, &buf) == -1) 509 goto fail; 510 if (root->be_class == BER_CLASS_APPLICATION && 511 root->be_type == SNMP_T_IPADDR) { 512 if (asprintf(&str, "%s", 513 inet_ntoa(*(struct in_addr *)buf)) == -1) 514 goto fail; 515 } else { 516 if ((p = reallocarray(NULL, 4, root->be_len + 1)) == NULL) 517 goto fail; 518 strvisx(p, buf, root->be_len, VIS_NL); 519 if (asprintf(&str, "\"%s\"", p) == -1) { 520 free(p); 521 goto fail; 522 } 523 free(p); 524 } 525 break; 526 case BER_TYPE_NULL: /* no payload */ 527 case BER_TYPE_EOC: 528 case BER_TYPE_SEQUENCE: 529 case BER_TYPE_SET: 530 default: 531 str = strdup(""); 532 break; 533 } 534 535 return (str); 536 537 fail: 538 free(str); 539 return (NULL); 540 } 541 542 unsigned long 543 smi_application(struct ber_element *elm) 544 { 545 if (elm->be_class != BER_CLASS_APPLICATION) 546 return (BER_TYPE_OCTETSTRING); 547 548 switch (elm->be_type) { 549 case SNMP_T_IPADDR: 550 return (BER_TYPE_OCTETSTRING); 551 case SNMP_T_COUNTER32: 552 case SNMP_T_GAUGE32: 553 case SNMP_T_TIMETICKS: 554 case SNMP_T_OPAQUE: 555 case SNMP_T_COUNTER64: 556 return (BER_TYPE_INTEGER); 557 default: 558 break; 559 } 560 return (BER_TYPE_OCTETSTRING); 561 } 562 563 int 564 smi_oid_cmp(struct oid *a, struct oid *b) 565 { 566 size_t i; 567 568 for (i = 0; i < MINIMUM(a->o_oidlen, b->o_oidlen); i++) 569 if (a->o_oid[i] != b->o_oid[i]) 570 return (a->o_oid[i] - b->o_oid[i]); 571 572 /* 573 * Return success if the matched object is a table 574 * or a MIB registered by a subagent 575 * (it will match any sub-elements) 576 */ 577 if ((b->o_flags & OID_TABLE || 578 b->o_flags & OID_REGISTERED) && 579 (a->o_flags & OID_KEY) == 0 && 580 (a->o_oidlen > b->o_oidlen)) 581 return (0); 582 583 return (a->o_oidlen - b->o_oidlen); 584 } 585 586 RB_GENERATE(oidtree, oid, o_element, smi_oid_cmp); 587 588 int 589 smi_key_cmp(struct oid *a, struct oid *b) 590 { 591 if (a->o_name == NULL || b->o_name == NULL) 592 return (-1); 593 return (strcasecmp(a->o_name, b->o_name)); 594 } 595 596 RB_GENERATE(keytree, oid, o_keyword, smi_key_cmp); 597