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