1 /* $OpenBSD: snmpc.c,v 1.33 2021/03/23 22:07:36 martijn Exp $ */ 2 3 /* 4 * Copyright (c) 2019 Martijn van Duren <martijn@openbsd.org> 5 * Copyright (c) 2013 Reyk Floeter <reyk@openbsd.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/limits.h> 21 #include <sys/types.h> 22 #include <sys/socket.h> 23 #include <sys/un.h> 24 25 #include <arpa/inet.h> 26 #include <openssl/evp.h> 27 28 #include <ber.h> 29 #include <ctype.h> 30 #include <err.h> 31 #include <errno.h> 32 #include <locale.h> 33 #include <netdb.h> 34 #include <poll.h> 35 #include <stdio.h> 36 #include <stdlib.h> 37 #include <stdint.h> 38 #include <string.h> 39 #include <time.h> 40 #include <unistd.h> 41 #include <util.h> 42 #include <wchar.h> 43 44 #include "smi.h" 45 #include "snmp.h" 46 #include "usm.h" 47 48 #define GETOPT_COMMON "A:a:c:E:e:K:k:l:n:O:r:t:u:v:X:x:Z:" 49 50 int snmpc_get(int, char *[]); 51 int snmpc_walk(int, char *[]); 52 int snmpc_set(int, char *[]); 53 int snmpc_trap(int, char *[]); 54 int snmpc_df(int, char *[]); 55 int snmpc_mibtree(int, char *[]); 56 struct snmp_agent *snmpc_connect(char *, char *); 57 int snmpc_parseagent(char *, char *); 58 int snmpc_print(struct ber_element *); 59 __dead void snmpc_printerror(enum snmp_error, struct ber_element *, int, 60 const char *); 61 char *snmpc_hex2bin(char *, size_t *); 62 ssize_t snmpc_mbswidth(char *); 63 struct ber_element *snmpc_varbindparse(int, char *[]); 64 void usage(void); 65 66 struct snmp_app { 67 const char *name; 68 const int usecommonopt; 69 const char *optstring; 70 const char *usage; 71 int (*exec)(int, char *[]); 72 }; 73 74 struct snmp_app snmp_apps[] = { 75 { "get", 1, NULL, "agent oid ...", snmpc_get }, 76 { "getnext", 1, NULL, "agent oid ...", snmpc_get }, 77 { "walk", 1, "C:", "[-C cIipt] [-C E endoid] [-C s skipoid] agent [oid]", snmpc_walk }, 78 { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get }, 79 { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] [-C s skipoid] agent [oid]", snmpc_walk }, 80 { "set", 1, NULL, "agent oid type value [oid type value] ...", snmpc_set }, 81 { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap }, 82 { "df", 1, "C:", "[-Ch] [-Cr<maxrep>] agent", snmpc_df }, 83 { "mibtree", 0, "O:", "[-O fnS] [oid ...]", snmpc_mibtree } 84 }; 85 struct snmp_app *snmp_app = NULL; 86 87 char *community = "public"; 88 struct snmp_v3 *v3; 89 char *mib = "mib_2"; 90 int retries = 5; 91 int timeout = 1; 92 enum snmp_version version = SNMP_V2C; 93 int print_equals = 1; 94 int print_varbind_only = 0; 95 int print_summary = 0; 96 int print_time = 0; 97 int print_human = 0; 98 int walk_check_increase = 1; 99 int walk_fallback_oid = 1; 100 int walk_include_oid = 0; 101 int smi_print_hint = 1; 102 int non_repeaters = 0; 103 int max_repetitions = 10; 104 struct ber_oid walk_end = {{0}, 0}; 105 struct ber_oid *walk_skip = NULL; 106 size_t walk_skip_len = 0; 107 enum smi_oid_lookup oid_lookup = smi_oidl_short; 108 enum smi_output_string output_string = smi_os_default; 109 int utf8 = 0; 110 111 int 112 main(int argc, char *argv[]) 113 { 114 const EVP_MD *md = NULL; 115 const EVP_CIPHER *cipher = NULL; 116 struct snmp_sec *sec; 117 char *user = NULL; 118 enum usm_key_level authkeylevel = USM_KEY_UNSET; 119 char *authkey = NULL; 120 size_t authkeylen = 0; 121 enum usm_key_level privkeylevel = USM_KEY_UNSET; 122 char *privkey = NULL; 123 size_t privkeylen = 0; 124 int seclevel = SNMP_MSGFLAG_REPORT; 125 char *ctxname = NULL; 126 char *ctxengineid = NULL, *secengineid = NULL; 127 size_t ctxengineidlen, secengineidlen; 128 int zflag = 0; 129 long long boots = 0, time = 0; 130 char optstr[BUFSIZ]; 131 const char *errstr; 132 char *strtolp; 133 int ch; 134 size_t i; 135 136 /* 137 * Determine if output can handle UTF-8 based on locale. 138 */ 139 setlocale(LC_CTYPE, ""); 140 utf8 = MB_CUR_MAX > 1; 141 /* 142 * SMIv2 allows for UTF-8 text at some locations. 143 * Set it explicitly so we can handle it on the input side. 144 */ 145 if (setlocale(LC_CTYPE, "en_US.UTF-8") == NULL) 146 errx(1, "setlocale(LC_CTYPE, \"en_US.UTF-8\") failed"); 147 148 if (pledge("stdio inet dns unix", NULL) == -1) 149 err(1, "pledge"); 150 151 if (argc <= 1) 152 usage(); 153 154 optstr[0] = '\0'; 155 for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) { 156 if (strcmp(snmp_apps[i].name, argv[1]) == 0) { 157 snmp_app = &snmp_apps[i]; 158 if (snmp_app->optstring != NULL) { 159 if (strlcpy(optstr, snmp_app->optstring, 160 sizeof(optstr)) > sizeof(optstr)) 161 errx(1, "strlcat"); 162 } 163 break; 164 } 165 } 166 if (snmp_app == NULL) 167 usage(); 168 169 if (snmp_app->usecommonopt) { 170 if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) > 171 sizeof(optstr)) 172 errx(1, "strlcpy"); 173 } 174 175 argc--; 176 argv++; 177 178 smi_init(); 179 180 while ((ch = getopt(argc, argv, optstr)) != -1) { 181 switch (ch) { 182 case 'A': 183 authkey = optarg; 184 authkeylen = strlen(authkey); 185 authkeylevel = USM_KEY_PASSWORD; 186 break; 187 case 'a': 188 if (strcasecmp(optarg, "MD5") == 0) 189 md = EVP_md5(); 190 else if (strcasecmp(optarg, "SHA") == 0) 191 md = EVP_sha1(); 192 else if (strcasecmp(optarg, "SHA-224") == 0) 193 md = EVP_sha224(); 194 else if (strcasecmp(optarg, "SHA-256") == 0) 195 md = EVP_sha256(); 196 else if (strcasecmp(optarg, "SHA-384") == 0) 197 md = EVP_sha384(); 198 else if (strcasecmp(optarg, "SHA-512") == 0) 199 md = EVP_sha512(); 200 else 201 errx(1, "Invalid authentication protocol " 202 "specified after -a flag: %s", optarg); 203 break; 204 case 'c': 205 community = optarg; 206 break; 207 case 'E': 208 ctxengineid = snmpc_hex2bin(optarg, 209 &ctxengineidlen); 210 if (ctxengineid == NULL) { 211 if (errno == EINVAL) 212 errx(1, "Bad engine ID value " 213 "after -3E flag."); 214 err(1, "-3E"); 215 } 216 break; 217 case 'e': 218 secengineid = snmpc_hex2bin(optarg, 219 &secengineidlen); 220 if (secengineid == NULL) { 221 if (errno == EINVAL) 222 errx(1, "Bad engine ID value " 223 "after -3e flag."); 224 err(1, "-3e"); 225 } 226 break; 227 case 'K': 228 privkey = snmpc_hex2bin(optarg, &privkeylen); 229 if (privkey == NULL) { 230 if (errno == EINVAL) 231 errx(1, "Bad key value after " 232 "-3K flag."); 233 errx(1, "-3K"); 234 } 235 privkeylevel = USM_KEY_LOCALIZED; 236 break; 237 case 'k': 238 authkey = snmpc_hex2bin(optarg, &authkeylen); 239 if (authkey == NULL) { 240 if (errno == EINVAL) 241 errx(1, "Bad key value after -k flag."); 242 err(1, "-k"); 243 } 244 authkeylevel = USM_KEY_LOCALIZED; 245 break; 246 case 'l': 247 if (strcasecmp(optarg, "noAuthNoPriv") == 0) 248 seclevel = SNMP_MSGFLAG_REPORT; 249 else if (strcasecmp(optarg, "authNoPriv") == 0) 250 seclevel = SNMP_MSGFLAG_AUTH | 251 SNMP_MSGFLAG_REPORT; 252 else if (strcasecmp(optarg, "authPriv") == 0) 253 seclevel = SNMP_MSGFLAG_AUTH | 254 SNMP_MSGFLAG_PRIV | SNMP_MSGFLAG_REPORT; 255 else 256 errx(1, "Invalid security level specified " 257 "after -l flag: %s", optarg); 258 break; 259 case 'n': 260 ctxname = optarg; 261 break; 262 case 'r': 263 if ((retries = strtonum(optarg, 0, INT_MAX, 264 &errstr)) == 0) { 265 if (errstr != NULL) 266 errx(1, "-r: %s argument", errstr); 267 } 268 break; 269 case 't': 270 if ((timeout = strtonum(optarg, 1, INT_MAX, 271 &errstr)) == 0) { 272 if (errstr != NULL) 273 errx(1, "-t: %s argument", errstr); 274 } 275 break; 276 case 'u': 277 user = optarg; 278 break; 279 case 'v': 280 if (strcmp(optarg, "1") == 0) 281 version = SNMP_V1; 282 else if (strcmp(optarg, "2c") == 0) 283 version = SNMP_V2C; 284 else if (strcmp(optarg, "3") == 0) 285 version = SNMP_V3; 286 else 287 errc(1, EINVAL, "-v"); 288 break; 289 case 'C': 290 for (i = 0; i < strlen(optarg); i++) { 291 switch (optarg[i]) { 292 case 'c': 293 if (strcmp(snmp_app->name, "walk") && 294 strcmp(snmp_app->name, "bulkwalk")) 295 usage(); 296 walk_check_increase = 0; 297 break; 298 case 'h': 299 if (strcmp(snmp_app->name, "df")) 300 usage(); 301 print_human = 1; 302 break; 303 case 'i': 304 if (strcmp(snmp_app->name, "walk") && 305 strcmp(snmp_app->name, "bulkwalk")) 306 usage(); 307 walk_include_oid = 1; 308 break; 309 case 'n': 310 if (strcmp(snmp_app->name, "bulkget") && 311 strcmp(snmp_app->name, "bulkwalk")) 312 usage(); 313 errno = 0; 314 non_repeaters = strtol(&optarg[i + 1], 315 &strtolp, 10); 316 if (non_repeaters < 0 || 317 errno == ERANGE) { 318 if (non_repeaters < 0) 319 errx(1, "%s%s", 320 "-Cn: too small ", 321 "argument"); 322 else 323 errx(1, "%s%s", 324 "-Cn: too large", 325 "argument"); 326 } else if (&optarg[i + 1] == strtolp) 327 errx(1, "-Cn invalid argument"); 328 i = strtolp - optarg - 1; 329 break; 330 case 'p': 331 if (strcmp(snmp_app->name, "walk") && 332 strcmp(snmp_app->name, "bulkwalk")) 333 usage(); 334 print_summary = 1; 335 break; 336 case 'r': 337 if (strcmp(snmp_app->name, "bulkget") && 338 strcmp(snmp_app->name, "bulkwalk") && 339 strcmp(snmp_app->name, "df")) 340 usage(); 341 errno = 0; 342 max_repetitions = strtol(&optarg[i + 1], 343 &strtolp, 10); 344 if (max_repetitions < 0 || 345 errno == ERANGE) { 346 if (max_repetitions < 0) 347 errx(1, "%s%s", 348 "-Cr: too small ", 349 "argument"); 350 else 351 errx(1, "%s%s", 352 "-Cr: too large", 353 "argument"); 354 } else if (&optarg[i + 1] == strtolp) 355 errx(1, "-Cr invalid argument"); 356 i = strtolp - optarg - 1; 357 break; 358 case 's': 359 if (strcmp(snmp_app->name, "walk") && 360 strcmp(snmp_app->name, "bulkwalk")) 361 usage(); 362 if ((walk_skip = recallocarray( 363 walk_skip, walk_skip_len, 364 walk_skip_len + 1, 365 sizeof(*walk_skip))) == NULL) 366 errx(1, "malloc"); 367 if (smi_string2oid(argv[optind], 368 &(walk_skip[walk_skip_len])) != 0) 369 errx(1, "%s: %s", 370 "Unknown Object Identifier", 371 argv[optind]); 372 walk_skip_len++; 373 optind++; 374 break; 375 case 't': 376 if (strcmp(snmp_app->name, "walk")) 377 usage(); 378 print_time = 1; 379 break; 380 case 'E': 381 if (strcmp(snmp_app->name, "walk")) 382 usage(); 383 if (smi_string2oid(argv[optind], 384 &walk_end) != 0) 385 errx(1, "%s: %s", 386 "Unknown Object Identifier", 387 argv[optind]); 388 optind++; 389 continue; 390 case 'I': 391 if (strcmp(snmp_app->name, "walk")) 392 usage(); 393 walk_fallback_oid = 0; 394 break; 395 default: 396 usage(); 397 } 398 if (optarg[i] == 'E') 399 break; 400 } 401 break; 402 case 'O': 403 for (i = 0; i < strlen(optarg); i++) { 404 if (strcmp(snmp_app->name, "mibtree") == 0 && 405 optarg[i] != 'f' && optarg[i] != 'n' && 406 optarg[i] != 'S') 407 usage(); 408 switch (optarg[i]) { 409 case 'a': 410 output_string = smi_os_ascii; 411 break; 412 case 'f': 413 oid_lookup = smi_oidl_full; 414 break; 415 case 'n': 416 oid_lookup = smi_oidl_numeric; 417 break; 418 case 'q': 419 print_equals = 0; 420 smi_print_hint = 0; 421 break; 422 case 'v': 423 print_varbind_only = 1; 424 break; 425 case 'x': 426 output_string = smi_os_hex; 427 break; 428 case 'S': 429 oid_lookup = smi_oidl_short; 430 break; 431 case 'Q': 432 smi_print_hint = 0; 433 break; 434 default: 435 usage(); 436 } 437 } 438 break; 439 case 'X': 440 privkey = optarg; 441 privkeylen = strlen(privkey); 442 privkeylevel = USM_KEY_PASSWORD; 443 break; 444 case 'x': 445 if (strcasecmp(optarg, "DES") == 0) 446 cipher = EVP_des_cbc(); 447 else if (strcasecmp(optarg, "AES") == 0) 448 cipher = EVP_aes_128_cfb128(); 449 else 450 errx(1, "Invalid privacy protocol " 451 "specified after -3x flag: %s", 452 optarg); 453 break; 454 case 'Z': 455 boots = strtoll(optarg, &strtolp, 10); 456 if (boots < 0 || strtolp == optarg || strtolp[0] != ',') 457 usage(); 458 strtolp++; 459 time = strtoll(strtolp, &strtolp, 10); 460 if (boots < 0 || strtolp == optarg) 461 usage(); 462 zflag = 1; 463 break; 464 default: 465 usage(); 466 } 467 } 468 argc -= optind; 469 argv += optind; 470 471 if (version == SNMP_V3) { 472 /* Setup USM */ 473 if (user == NULL || user[0] == '\0') 474 errx(1, "No securityName specified"); 475 if ((sec = usm_init(user, strlen(user))) == NULL) 476 err(1, "usm_init"); 477 if (seclevel & SNMP_MSGFLAG_AUTH) { 478 if (md == NULL) 479 md = EVP_md5(); 480 if (authkey == NULL) 481 errx(1, "No authKey or authPassword specified"); 482 if (usm_setauth(sec, md, authkey, authkeylen, 483 authkeylevel) == -1) 484 err(1, "Can't set authkey"); 485 } 486 if (seclevel & SNMP_MSGFLAG_PRIV) { 487 if (cipher == NULL) 488 cipher = EVP_des_cbc(); 489 if (privkey == NULL) 490 errx(1, "No privKey or privPassword specified"); 491 if (usm_setpriv(sec, cipher, privkey, privkeylen, 492 privkeylevel) == -1) 493 err(1, "Can't set authkey"); 494 } 495 if (secengineid != NULL) { 496 if (usm_setengineid(sec, secengineid, 497 secengineidlen) == -1) 498 err(1, "Can't set secengineid"); 499 } 500 if (zflag) 501 if (usm_setbootstime(sec, boots, time) == -1) 502 err(1, "Can't set boots/time"); 503 v3 = snmp_v3_init(seclevel, ctxname, ctxname == NULL ? 0 : 504 strlen(ctxname), sec); 505 if (v3 == NULL) 506 err(1, "snmp_v3_init"); 507 if (ctxengineid != NULL) { 508 if (snmp_v3_setengineid(v3, ctxengineid, 509 ctxengineidlen) == -1) 510 err(1, "Can't set ctxengineid"); 511 } 512 } 513 514 515 return snmp_app->exec(argc, argv); 516 } 517 518 int 519 snmpc_get(int argc, char *argv[]) 520 { 521 struct ber_oid *oid; 522 struct ber_element *pdu, *varbind; 523 struct snmp_agent *agent; 524 int errorstatus, errorindex; 525 int i; 526 int class; 527 unsigned type; 528 char *hint = NULL; 529 530 if (argc < 2) 531 usage(); 532 533 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 534 err(1, "%s", snmp_app->name); 535 agent->timeout = timeout; 536 agent->retries = retries; 537 538 if (pledge("stdio", NULL) == -1) 539 err(1, "pledge"); 540 argc--; 541 argv++; 542 543 oid = reallocarray(NULL, argc, sizeof(*oid)); 544 if (oid == NULL) 545 err(1, "malloc"); 546 for (i = 0; i < argc; i++) { 547 if (smi_string2oid(argv[i], &oid[i]) == -1) 548 errx(1, "%s: Unknown object identifier", argv[i]); 549 } 550 if (strcmp(snmp_app->name, "getnext") == 0) { 551 if ((pdu = snmp_getnext(agent, oid, argc)) == NULL) 552 err(1, "getnext"); 553 } else if (strcmp(snmp_app->name, "bulkget") == 0) { 554 if (version < SNMP_V2C) 555 errx(1, "Cannot send V2 PDU on V1 session"); 556 if (non_repeaters > argc) 557 errx(1, "need more objects than -Cn<num>"); 558 if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters, 559 max_repetitions)) == NULL) 560 err(1, "bulkget"); 561 } else { 562 if ((pdu = snmp_get(agent, oid, argc)) == NULL) 563 err(1, "get"); 564 } 565 566 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus, 567 &errorindex, &varbind); 568 if (errorstatus != 0) { 569 if (errorindex >= 1 && errorindex <= argc) 570 hint = argv[errorindex - 1]; 571 snmpc_printerror((enum snmp_error) errorstatus, varbind, 572 errorindex, hint); 573 } 574 575 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 576 printf("Received report:\n"); 577 for (; varbind != NULL; varbind = varbind->be_next) { 578 if (!snmpc_print(varbind)) 579 err(1, "Can't print response"); 580 } 581 ober_free_elements(pdu); 582 snmp_free_agent(agent); 583 return 0; 584 } 585 586 int 587 snmpc_walk(int argc, char *argv[]) 588 { 589 struct ber_oid oid, loid, noid; 590 struct ber_element *pdu, *varbind, *value; 591 struct timespec start, finish; 592 struct snmp_agent *agent; 593 const char *oids; 594 int n = 0, prev_cmp, skip_cmp; 595 int errorstatus, errorindex; 596 int class; 597 size_t i; 598 unsigned type; 599 600 if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C) 601 errx(1, "Cannot send V2 PDU on V1 session"); 602 if (argc < 1 || argc > 2) 603 usage(); 604 oids = argc == 1 ? mib : argv[1]; 605 606 if ((agent = snmpc_connect(argv[0], "161"))== NULL) 607 err(1, "%s", snmp_app->name); 608 agent->timeout = timeout; 609 agent->retries = retries; 610 if (pledge("stdio", NULL) == -1) 611 err(1, "pledge"); 612 613 if (smi_string2oid(oids, &oid) == -1) 614 errx(1, "%s: Unknown object identifier", oids); 615 bcopy(&oid, &noid, sizeof(noid)); 616 if (print_time) 617 clock_gettime(CLOCK_MONOTONIC, &start); 618 619 if (walk_include_oid) { 620 if ((pdu = snmp_get(agent, &oid, 1)) == NULL) 621 err(1, "%s", snmp_app->name); 622 623 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 624 &errorstatus, &errorindex, &varbind); 625 if (errorstatus != 0) 626 snmpc_printerror((enum snmp_error) errorstatus, varbind, 627 errorindex, oids); 628 629 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 630 printf("Received report:\n"); 631 if (!snmpc_print(varbind)) 632 err(1, "Can't print response"); 633 ober_free_element(pdu); 634 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 635 return 1; 636 n++; 637 } 638 while (1) { 639 for (i = 0; i < walk_skip_len; i++) { 640 skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid); 641 if (skip_cmp == 0 || skip_cmp == 2) { 642 bcopy(&(walk_skip[i]), &noid, sizeof(noid)); 643 noid.bo_id[noid.bo_n -1]++; 644 break; 645 } 646 } 647 bcopy(&noid, &loid, sizeof(loid)); 648 if (strcmp(snmp_app->name, "bulkwalk") == 0) { 649 if ((pdu = snmp_getbulk(agent, &noid, 1, 650 non_repeaters, max_repetitions)) == NULL) 651 err(1, "bulkwalk"); 652 } else { 653 if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL) 654 err(1, "walk"); 655 } 656 657 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 658 &errorstatus, &errorindex, &varbind); 659 if (errorstatus != 0) { 660 snmpc_printerror((enum snmp_error) errorstatus, varbind, 661 errorindex, NULL); 662 } 663 664 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 665 printf("Received report:\n"); 666 for (; varbind != NULL; varbind = varbind->be_next) { 667 (void) ober_scanf_elements(varbind, "{oe}", &noid, 668 &value); 669 if (value->be_class == BER_CLASS_CONTEXT && 670 value->be_type == BER_TYPE_EOC) 671 break; 672 for (i = 0; i < walk_skip_len; i++) { 673 skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid); 674 if (skip_cmp == 0 || skip_cmp == 2) 675 break; 676 } 677 if (i < walk_skip_len) 678 continue; 679 prev_cmp = ober_oid_cmp(&loid, &noid); 680 if (walk_check_increase && prev_cmp == -1) 681 errx(1, "OID not increasing"); 682 if (prev_cmp == 0 || ober_oid_cmp(&oid, &noid) != 2) 683 break; 684 if (walk_end.bo_n != 0 && 685 ober_oid_cmp(&walk_end, &noid) != -1) 686 break; 687 688 if (!snmpc_print(varbind)) 689 err(1, "Can't print response"); 690 n++; 691 } 692 ober_free_elements(pdu); 693 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 694 return 1; 695 if (varbind != NULL) 696 break; 697 } 698 if (walk_fallback_oid && n == 0) { 699 if ((pdu = snmp_get(agent, &oid, 1)) == NULL) 700 err(1, "%s", snmp_app->name); 701 702 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 703 &errorstatus, &errorindex, &varbind); 704 if (errorstatus != 0) 705 snmpc_printerror((enum snmp_error) errorstatus, varbind, 706 errorindex, oids); 707 708 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 709 printf("Received report:\n"); 710 if (!snmpc_print(varbind)) 711 err(1, "Can't print response"); 712 ober_free_element(pdu); 713 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 714 return 1; 715 n++; 716 } 717 if (print_time) 718 clock_gettime(CLOCK_MONOTONIC, &finish); 719 if (print_summary) 720 printf("Variables found: %d\n", n); 721 if (print_time) { 722 if ((finish.tv_nsec -= start.tv_nsec) < 0) { 723 finish.tv_sec -= 1; 724 finish.tv_nsec += 1000000000; 725 } 726 finish.tv_sec -= start.tv_sec; 727 fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n", 728 finish.tv_sec, finish.tv_nsec); 729 } 730 snmp_free_agent(agent); 731 return 0; 732 } 733 734 int 735 snmpc_set(int argc, char *argv[]) 736 { 737 struct snmp_agent *agent; 738 struct ber_element *pdu, *varbind; 739 int errorstatus, errorindex; 740 int class; 741 unsigned type; 742 char *hint = NULL; 743 744 if (argc < 4) 745 usage(); 746 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 747 err(1, "%s", snmp_app->name); 748 argc--; 749 argv++; 750 751 if (pledge("stdio", NULL) == -1) 752 err(1, "pledge"); 753 754 if ((pdu = snmp_set(agent, snmpc_varbindparse(argc, argv))) == NULL) 755 err(1, "set"); 756 757 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus, 758 &errorindex, &varbind); 759 if (errorstatus != 0) { 760 if (errorindex >= 1 && errorindex <= argc / 3) 761 hint = argv[(errorindex - 1) * 3]; 762 snmpc_printerror((enum snmp_error) errorstatus, varbind, 763 errorindex, hint); 764 } 765 766 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 767 printf("Received report:\n"); 768 for (; varbind != NULL; varbind = varbind->be_next) { 769 if (!snmpc_print(varbind)) 770 err(1, "Can't print response"); 771 } 772 ober_free_elements(pdu); 773 snmp_free_agent(agent); 774 return 0; 775 } 776 777 int 778 snmpc_trap(int argc, char *argv[]) 779 { 780 struct snmp_agent *agent; 781 struct timespec ts; 782 struct ber_oid trapoid; 783 const char *errstr = NULL; 784 long long lval; 785 786 if (version == SNMP_V1) 787 errx(1, "trap is not supported for snmp v1"); 788 789 if (argc < 3) 790 usage(); 791 792 if ((agent = snmpc_connect(argv[0], "162")) == NULL) 793 err(1, "%s", snmp_app->name); 794 795 if (pledge("stdio", NULL) == -1) 796 err(1, "pledge"); 797 798 if (argv[1][0] == '\0') { 799 if (clock_gettime(CLOCK_UPTIME, &ts) == -1) 800 err(1, "clock_gettime"); 801 } else { 802 lval = strtonum(argv[1], 0, UINT32_MAX, &errstr); 803 if (errstr != NULL) 804 errx(1, "Bad value notation (%s)", argv[1]); 805 ts.tv_sec = lval / 100; 806 ts.tv_nsec = (lval % 100) * 10000000; 807 } 808 if (smi_string2oid(argv[2], &trapoid) == -1) 809 errx(1, "Invalid oid: %s\n", argv[2]); 810 811 argc -= 3; 812 argv += 3; 813 814 snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv)); 815 816 return 0; 817 } 818 819 #define INCR_NEXTTAB(x) ((x + 8) & ~7) 820 #define NEXTTAB(x) (8 - (x & 7)) 821 int 822 snmpc_df(int argc, char *argv[]) 823 { 824 struct snmpc_df { 825 uint32_t index; 826 char *descr; 827 int descrwidth; 828 /* Theoretical maximum for 2 32 bit values multiplied */ 829 char size[21]; 830 char used[21]; 831 char avail[21]; 832 char proc[5]; 833 } *df = NULL; 834 struct ber_oid descroid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 3 }, 11}; 835 struct ber_oid unitsoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 4 }, 11}; 836 struct ber_oid sizeoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 5 }, 11}; 837 struct ber_oid usedoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 6 }, 11}; 838 struct ber_oid oid, *reqoid; 839 char oids[SNMP_MAX_OID_STRLEN]; 840 struct ber_element *pdu, *varbind, *elm; 841 struct snmp_agent *agent; 842 int errorstatus, errorindex; 843 int class; 844 size_t i, j, rows = 0; 845 unsigned type; 846 char *string; 847 int descrlen = 0, sizelen = 0, usedlen = 0, availlen = 0, proclen = 0; 848 int len; 849 long long units, size, used; 850 int fmtret; 851 852 if (argc != 1) 853 usage(); 854 855 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 856 err(1, "%s", snmp_app->name); 857 agent->timeout = timeout; 858 agent->retries = retries; 859 860 if (pledge("stdio", NULL) == -1) 861 err(1, "pledge"); 862 863 descrlen = sizeof("Description") - 1; 864 sizelen = sizeof("Size") - 1; 865 usedlen = sizeof("Used") - 1; 866 availlen = sizeof("Available") - 1; 867 proclen = sizeof("Used%") - 1; 868 869 bcopy(&descroid, &oid, sizeof(descroid)); 870 871 i = 0; 872 while(1) { 873 if (version < SNMP_V2C) { 874 if ((pdu = snmp_getnext(agent, &oid, 1)) == NULL) 875 err(1, "df"); 876 } else { 877 if ((pdu = snmp_getbulk(agent, &oid, 1, 0, 878 max_repetitions)) == NULL) 879 err(1, "df"); 880 } 881 882 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 883 &errorstatus, &errorindex, &varbind); 884 if (errorstatus != 0) 885 snmpc_printerror((enum snmp_error) errorstatus, varbind, 886 errorindex, NULL); 887 888 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 889 printf("Received report:\n"); 890 for (; varbind != NULL; varbind = varbind->be_next) { 891 if (!snmpc_print(varbind)) 892 err(1, "Can't print response"); 893 } 894 return 1; 895 } 896 for (; varbind != NULL; varbind = varbind->be_next) { 897 if (ober_scanf_elements(varbind, "{os", &oid, 898 &string) == -1 || 899 ober_oid_cmp(&descroid, &oid) != 2) 900 break; 901 rows++; 902 } 903 if ((df = reallocarray(df, rows, sizeof(*df))) == NULL) 904 err(1, "malloc"); 905 (void) ober_scanf_elements(pdu, "{SSS{e", &varbind); 906 for (; i < rows; varbind = varbind->be_next, i++) { 907 if (ober_scanf_elements(varbind, "{oe", &oid, 908 &elm) == -1) { 909 i--; 910 rows--; 911 continue; 912 } 913 if (ober_oid_cmp(&descroid, &oid) != 2) 914 break; 915 df[i].index = oid.bo_id[oid.bo_n - 1]; 916 if ((df[i].descr = smi_print_element(&oid, elm, 0, 917 smi_os_ascii, 0, utf8)) == NULL) { 918 smi_oid2string(&oid, oids, sizeof(oids), 919 oid_lookup); 920 warn("df: can't print oid %s", oids); 921 i--; 922 rows--; 923 continue; 924 } 925 if ((df[i].descrwidth = 926 (int) snmpc_mbswidth(df[i].descr)) == -1) 927 err(1, "df: invalid hrStorageDescr"); 928 if (df[i].descrwidth > descrlen) 929 descrlen = df[i].descrwidth; 930 } 931 ober_free_elements(pdu); 932 if (varbind != NULL) 933 break; 934 } 935 936 if (max_repetitions < 3) 937 max_repetitions = 3; 938 if ((reqoid = reallocarray(NULL, max_repetitions, sizeof(*reqoid))) == NULL) 939 err(1, "malloc"); 940 for (i = 0; i < rows;) { 941 for (j = 0; i + j < rows && j < (size_t)max_repetitions / 3; 942 j++) { 943 bcopy(&unitsoid, &(reqoid[(j * 3) + 0]), 944 sizeof(unitsoid)); 945 reqoid[(j * 3) + 0].bo_id[ 946 reqoid[(j * 3) + 0].bo_n++] = df[i + j].index; 947 bcopy(&sizeoid, &(reqoid[(j * 3) + 1]), 948 sizeof(sizeoid)); 949 reqoid[(j * 3) + 1].bo_id[ 950 reqoid[(j * 3) + 1].bo_n++] = df[i + j].index; 951 bcopy(&usedoid, &(reqoid[(j * 3) + 2]), 952 sizeof(usedoid)); 953 reqoid[(j * 3) + 2].bo_id[ 954 reqoid[(j * 3) + 2].bo_n++] = df[i + j].index; 955 } 956 if ((pdu = snmp_get(agent, reqoid, j * 3)) == NULL) 957 err(1, "df"); 958 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 959 &errorstatus, &errorindex, &varbind); 960 if (errorstatus != 0) 961 snmpc_printerror((enum snmp_error) errorstatus, varbind, 962 errorindex, NULL); 963 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 964 printf("Received report:\n"); 965 for (; varbind != NULL; varbind = varbind->be_next) { 966 if (!snmpc_print(varbind)) 967 err(1, "Can't print response"); 968 } 969 } 970 for (j = 0; varbind != NULL; i++) { 971 if (ober_scanf_elements(varbind, "{oi}{oi}{oi}", 972 &(reqoid[0]), &units, &(reqoid[1]), &size, 973 &(reqoid[2]), &used, &varbind) == -1) { 974 break; 975 } 976 varbind = varbind->be_next->be_next->be_next; 977 978 unitsoid.bo_id[unitsoid.bo_n++] = df[i].index; 979 if (ober_oid_cmp(&unitsoid, &(reqoid[0])) != 0) { 980 warnx("df: received invalid object"); 981 break; 982 } 983 unitsoid.bo_n--; 984 sizeoid.bo_id[sizeoid.bo_n++] = df[i].index; 985 if (ober_oid_cmp(&sizeoid, &(reqoid[1])) != 0) { 986 warnx("df: received invalid object"); 987 break; 988 } 989 sizeoid.bo_n--; 990 usedoid.bo_id[usedoid.bo_n++] = df[i].index; 991 if (ober_oid_cmp(&usedoid, &(reqoid[2])) != 0) { 992 warnx("df: received invalid object"); 993 break; 994 } 995 usedoid.bo_n--; 996 if (print_human) 997 fmtret = fmt_scaled((units * size), df[i].size); 998 if (!print_human || fmtret == -1) 999 snprintf(df[i].size, sizeof(df[i].size), "%lld", 1000 (units * size) / 1024); 1001 len = (int) strlen(df[i].size); 1002 if (len > sizelen) 1003 sizelen = len; 1004 if (print_human) 1005 fmtret = fmt_scaled(units * used, df[i].used); 1006 if (!print_human || fmtret == -1) 1007 snprintf(df[i].used, sizeof(df[i].used), "%lld", 1008 (units * used) / 1024); 1009 len = (int) strlen(df[i].used); 1010 if (len > usedlen) 1011 usedlen = len; 1012 if (print_human) 1013 fmtret = fmt_scaled(units * (size - used), 1014 df[i].avail); 1015 if (!print_human || fmtret == -1) 1016 snprintf(df[i].avail, sizeof(df[i].avail), 1017 "%lld", (units * (size - used)) / 1024); 1018 len = (int) strlen(df[i].avail); 1019 if (len > availlen) 1020 availlen = len; 1021 if (size == 0) 1022 strlcpy(df[i].proc, "0%", sizeof(df[i].proc)); 1023 else { 1024 snprintf(df[i].proc, sizeof(df[i].proc), 1025 "%lld%%", (used * 100) / size); 1026 } 1027 len = (int) strlen(df[i].proc); 1028 if (len > proclen) 1029 proclen = len; 1030 j++; 1031 } 1032 if (j == 0) { 1033 warnx("Failed to retrieve information for %s", 1034 df[i].descr); 1035 memmove(df + i, df + i + 1, 1036 (rows - i - 1) * sizeof(*df)); 1037 rows--; 1038 i--; 1039 } 1040 } 1041 1042 printf("%-*s%*s%*s%*s%*s\n", 1043 descrlen, "Description", 1044 NEXTTAB(descrlen) + sizelen, "Size", 1045 NEXTTAB(sizelen) + usedlen, "Used", 1046 NEXTTAB(usedlen) + availlen, "Available", 1047 NEXTTAB(availlen) + proclen, "Used%"); 1048 for (i = 0; i < rows; i++) { 1049 printf("%s%*s%*s%*s%*s%*s\n", 1050 df[i].descr, descrlen - df[i].descrwidth, "", 1051 NEXTTAB(descrlen) + sizelen, df[i].size, 1052 NEXTTAB(sizelen) + usedlen, df[i].used, 1053 NEXTTAB(usedlen) + availlen, df[i].avail, 1054 NEXTTAB(availlen) + proclen, df[i].proc); 1055 } 1056 1057 return 0; 1058 } 1059 1060 int 1061 snmpc_mibtree(int argc, char *argv[]) 1062 { 1063 struct oid *oid; 1064 struct ber_oid soid; 1065 char buf[BUFSIZ]; 1066 int i; 1067 1068 if (argc == 0) { 1069 for (oid = NULL; (oid = smi_foreach(oid)) != NULL;) { 1070 smi_oid2string(&oid->o_id, buf, sizeof(buf), 1071 oid_lookup); 1072 printf("%s\n", buf); 1073 } 1074 } else { 1075 for (i = 0; i < argc; i++) { 1076 if (smi_string2oid(argv[i], &soid) == -1) { 1077 warnx("%s: Unknown object identifier", argv[i]); 1078 continue; 1079 } 1080 smi_oid2string(&soid, buf, sizeof(buf), oid_lookup); 1081 printf("%s\n", buf); 1082 } 1083 } 1084 return 0; 1085 } 1086 1087 struct snmp_agent * 1088 snmpc_connect(char *host, char *port) 1089 { 1090 switch (version) { 1091 case SNMP_V1: 1092 case SNMP_V2C: 1093 return snmp_connect_v12(snmpc_parseagent(host, port), version, 1094 community); 1095 case SNMP_V3: 1096 return snmp_connect_v3(snmpc_parseagent(host, port), v3); 1097 } 1098 return NULL; 1099 } 1100 1101 int 1102 snmpc_print(struct ber_element *elm) 1103 { 1104 struct ber_oid oid; 1105 char oids[SNMP_MAX_OID_STRLEN]; 1106 char *value; 1107 1108 elm = elm->be_sub; 1109 if (ober_get_oid(elm, &oid) != 0) { 1110 errno = EINVAL; 1111 return 0; 1112 } 1113 1114 elm = elm->be_next; 1115 value = smi_print_element(&oid, elm, smi_print_hint, output_string, 1116 oid_lookup, utf8); 1117 if (value == NULL) 1118 return 0; 1119 1120 if (print_varbind_only) 1121 printf("%s\n", value); 1122 else if (print_equals) { 1123 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1124 printf("%s = %s\n", oids, value); 1125 } else { 1126 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1127 printf("%s %s\n", oids, value); 1128 } 1129 free(value); 1130 1131 return 1; 1132 } 1133 1134 __dead void 1135 snmpc_printerror(enum snmp_error error, struct ber_element *varbind, 1136 int index, const char *hint) 1137 { 1138 struct ber_oid hoid, vboid; 1139 char oids[SNMP_MAX_OID_STRLEN]; 1140 const char *oid = NULL; 1141 int i; 1142 1143 if (index >= 1) { 1144 /* Only print if the index is in the reply */ 1145 for (i = 1; varbind != NULL && i < index; 1146 varbind = varbind->be_next) 1147 i++; 1148 if (varbind != NULL && 1149 ober_get_oid(varbind->be_sub, &vboid) == 0) { 1150 /* If user and reply conform print user input */ 1151 if (hint != NULL && 1152 smi_string2oid(hint, &hoid) == 0 && 1153 ober_oid_cmp(&hoid, &vboid) == 0) 1154 oid = hint; 1155 else 1156 oid = smi_oid2string(&vboid, oids, 1157 sizeof(oids), oid_lookup); 1158 } 1159 } 1160 if (oid == NULL) 1161 oid = "?"; 1162 1163 switch (error) { 1164 case SNMP_ERROR_NONE: 1165 errx(1, "No error, how did I get here?"); 1166 case SNMP_ERROR_TOOBIG: 1167 errx(1, "Can't parse oid %s: Response too big", oid); 1168 case SNMP_ERROR_NOSUCHNAME: 1169 errx(1, "Can't parse oid %s: No such object", oid); 1170 case SNMP_ERROR_BADVALUE: 1171 errx(1, "Can't parse oid %s: Bad value", oid); 1172 case SNMP_ERROR_READONLY: 1173 errx(1, "Can't parse oid %s: Read only", oid); 1174 case SNMP_ERROR_GENERR: 1175 errx(1, "Can't parse oid %s: Generic error", oid); 1176 case SNMP_ERROR_NOACCESS: 1177 errx(1, "Can't parse oid %s: Access denied", oid); 1178 case SNMP_ERROR_WRONGTYPE: 1179 errx(1, "Can't parse oid %s: Wrong type", oid); 1180 case SNMP_ERROR_WRONGLENGTH: 1181 errx(1, "Can't parse oid %s: Wrong length", oid); 1182 case SNMP_ERROR_WRONGENC: 1183 errx(1, "Can't parse oid %s: Wrong encoding", oid); 1184 case SNMP_ERROR_WRONGVALUE: 1185 errx(1, "Can't parse oid %s: Wrong value", oid); 1186 case SNMP_ERROR_NOCREATION: 1187 errx(1, "Can't parse oid %s: Can't be created", oid); 1188 case SNMP_ERROR_INCONVALUE: 1189 errx(1, "Can't parse oid %s: Inconsistent value", oid); 1190 case SNMP_ERROR_RESUNAVAIL: 1191 errx(1, "Can't parse oid %s: Resource unavailable", oid); 1192 case SNMP_ERROR_COMMITFAILED: 1193 errx(1, "Can't parse oid %s: Commit failed", oid); 1194 case SNMP_ERROR_UNDOFAILED: 1195 errx(1, "Can't parse oid %s: Undo faild", oid); 1196 case SNMP_ERROR_AUTHERROR: 1197 errx(1, "Can't parse oid %s: Authorization error", oid); 1198 case SNMP_ERROR_NOTWRITABLE: 1199 errx(1, "Can't parse oid %s: Not writable", oid); 1200 case SNMP_ERROR_INCONNAME: 1201 errx(1, "Can't parse oid %s: Inconsistent name", oid); 1202 } 1203 errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error); 1204 } 1205 1206 int 1207 snmpc_parseagent(char *agent, char *defaultport) 1208 { 1209 struct addrinfo hints, *ai, *ai0 = NULL; 1210 struct sockaddr_un saddr; 1211 char *agentdup, *specifier, *hostname, *port = NULL; 1212 int error; 1213 int s; 1214 1215 if ((agentdup = specifier = strdup(agent)) == NULL) 1216 err(1, NULL); 1217 1218 bzero(&hints, sizeof(hints)); 1219 if ((hostname = strchr(specifier, ':')) != NULL) { 1220 *hostname++ = '\0'; 1221 if (strcasecmp(specifier, "udp") == 0) { 1222 hints.ai_family = AF_INET; 1223 hints.ai_socktype = SOCK_DGRAM; 1224 } else if (strcasecmp(specifier, "tcp") == 0) { 1225 hints.ai_family = AF_INET; 1226 hints.ai_socktype = SOCK_STREAM; 1227 } else if (strcasecmp(specifier, "udp6") == 0 || 1228 strcasecmp(specifier, "udpv6") == 0 || 1229 strcasecmp(specifier, "udpipv6") == 0) { 1230 hints.ai_family = AF_INET6; 1231 hints.ai_socktype = SOCK_DGRAM; 1232 } else if (strcasecmp(specifier, "tcp6") == 0 || 1233 strcasecmp(specifier, "tcpv6") == 0 || 1234 strcasecmp(specifier, "tcpipv6") == 0) { 1235 hints.ai_family = AF_INET6; 1236 hints.ai_socktype = SOCK_STREAM; 1237 } else if (strcasecmp(specifier, "unix") == 0) { 1238 hints.ai_family = AF_UNIX; 1239 hints.ai_addr = (struct sockaddr *)&saddr; 1240 hints.ai_addrlen = sizeof(saddr); 1241 saddr.sun_len = sizeof(saddr); 1242 saddr.sun_family = AF_UNIX; 1243 if (strlcpy(saddr.sun_path, hostname, 1244 sizeof(saddr.sun_path)) > sizeof(saddr.sun_path)) 1245 errx(1, "Hostname path too long"); 1246 ai = &hints; 1247 } else { 1248 *--hostname = ':'; 1249 hostname = specifier; 1250 } 1251 } else { 1252 hostname = specifier; 1253 } 1254 1255 if (hints.ai_family == AF_INET) { 1256 if ((port = strchr(hostname, ':')) != NULL) 1257 *port++ = '\0'; 1258 } else if (hints.ai_family == AF_INET6 || hints.ai_family == 0) { 1259 if (hostname[0] == '[') { 1260 hints.ai_family = AF_INET6; 1261 hostname++; 1262 if ((port = strchr(hostname, ']')) == NULL) 1263 errx(1, "invalid agent"); 1264 *port++ = '\0'; 1265 if (port[0] == ':') 1266 *port++ = '\0'; 1267 else if (port[0] == '\0') 1268 port = NULL; 1269 else 1270 errx(1, "invalid agent"); 1271 } else { 1272 if ((port = strrchr(hostname, ':')) != NULL) 1273 *port++ = '\0'; 1274 } 1275 } 1276 1277 if (hints.ai_family != AF_UNIX) { 1278 if (hints.ai_socktype == 0) 1279 hints.ai_socktype = SOCK_DGRAM; 1280 if (port == NULL) 1281 port = defaultport; 1282 error = getaddrinfo(hostname, port, &hints, &ai0); 1283 if (error) { 1284 if (error != EAI_NODATA || port == defaultport) 1285 errx(1, "%s", gai_strerror(error)); 1286 *--port = ':'; 1287 error = getaddrinfo(hostname, defaultport, &hints, 1288 &ai0); 1289 if (error) 1290 errx(1, "%s", gai_strerror(error)); 1291 } 1292 s = -1; 1293 for (ai = ai0; ai != NULL; ai = ai->ai_next) { 1294 if ((s = socket(ai->ai_family, ai->ai_socktype, 1295 ai->ai_protocol)) != -1 && 1296 connect(s, (struct sockaddr *)ai->ai_addr, 1297 ai->ai_addrlen) != -1) 1298 break; 1299 close(s); 1300 s = -1; 1301 } 1302 } else { 1303 s = socket(AF_UNIX, SOCK_STREAM, 0); 1304 if (connect(s, (struct sockaddr *)ai->ai_addr, 1305 ai->ai_addrlen) == -1) 1306 err(1, "Can't connect to %s", agent); 1307 } 1308 if (s == -1) 1309 err(1, "Can't connect to agent %s", agent); 1310 1311 1312 if (ai0 != NULL) 1313 freeaddrinfo(ai0); 1314 free(agentdup); 1315 return s; 1316 } 1317 1318 char * 1319 snmpc_hex2bin(char *hexstr, size_t *binlen) 1320 { 1321 char *decstr; 1322 1323 if (hexstr[0] == '0' && hexstr[1] == 'x') 1324 hexstr += 2; 1325 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1326 hexstr++; 1327 1328 if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL) 1329 return NULL; 1330 1331 for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) { 1332 hexstr[0] = toupper(hexstr[0]); 1333 hexstr[1] = toupper(hexstr[1]); 1334 if (hexstr[0] >= '0' && hexstr[0] <= '9') 1335 decstr[*binlen] = (hexstr[0] - '0') << 4; 1336 else if (hexstr[0] >= 'A' && hexstr[0] <= 'F') 1337 decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4; 1338 else 1339 goto fail; 1340 if (hexstr[1] >= '0' && hexstr[1] <= '9') 1341 decstr[*binlen] |= (hexstr[1] - '0'); 1342 else if (hexstr[1] >= 'A' && hexstr[1] <= 'F') 1343 decstr[*binlen] |= (hexstr[1] - 'A') + 10; 1344 else 1345 goto fail; 1346 1347 hexstr += 2; 1348 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1349 hexstr++; 1350 } 1351 1352 return decstr; 1353 fail: 1354 errno = EINVAL; 1355 free(decstr); 1356 return NULL; 1357 } 1358 1359 ssize_t 1360 snmpc_mbswidth(char *str) 1361 { 1362 wchar_t wc; 1363 size_t width = 0; 1364 size_t i; 1365 int len; 1366 1367 for (i = 0; (len = mbtowc(&wc, &(str[i]), MB_CUR_MAX)) != 0; i += len) { 1368 if (len == -1) { 1369 mbtowc(NULL, NULL, MB_CUR_MAX); 1370 return -1; 1371 } 1372 width += wcwidth(wc); 1373 } 1374 return width; 1375 } 1376 1377 struct ber_element * 1378 snmpc_varbindparse(int argc, char *argv[]) 1379 { 1380 struct ber_oid oid, oidval; 1381 struct in_addr addr4; 1382 char *addr = (char *)&addr4; 1383 char *str = NULL, *tmpstr, *endstr; 1384 const char *errstr = NULL; 1385 struct ber_element *varbind = NULL, *vblist = NULL; 1386 int i, ret; 1387 size_t strl, byte; 1388 long long lval; 1389 1390 if (argc % 3 != 0) 1391 usage(); 1392 for (i = 0; i < argc; i += 3) { 1393 if (smi_string2oid(argv[i], &oid) == -1) 1394 errx(1, "Invalid oid: %s\n", argv[i]); 1395 switch (argv[i + 1][0]) { 1396 case 'a': 1397 ret = inet_pton(AF_INET, argv[i + 2], &addr4); 1398 if (ret == -1) 1399 err(1, "inet_pton"); 1400 if (ret == 0) 1401 errx(1, "%s: Bad value notation (%s)", argv[i], 1402 argv[i + 2]); 1403 if ((varbind = ober_printf_elements(varbind, "{Oxt}", 1404 &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION, 1405 SNMP_T_IPADDR)) == NULL) 1406 err(1, "ober_printf_elements"); 1407 break; 1408 case 'b': 1409 tmpstr = argv[i + 2]; 1410 strl = 0; 1411 do { 1412 lval = strtoll(tmpstr, &endstr, 10); 1413 if (endstr[0] != ' ' && endstr[0] != '\t' && 1414 endstr[0] != ',' && endstr[0] != '\0') 1415 errx(1, "%s: Bad value notation (%s)", 1416 argv[i], argv[i + 2]); 1417 if (tmpstr == endstr) { 1418 tmpstr++; 1419 continue; 1420 } 1421 if (lval < 0) 1422 errx(1, "%s: Bad value notation (%s)", 1423 argv[i], argv[i + 2]); 1424 byte = lval / 8; 1425 if (byte >= strl) { 1426 if ((str = recallocarray(str, strl, 1427 byte + 1, 1)) == NULL) 1428 err(1, "malloc"); 1429 strl = byte + 1; 1430 } 1431 str[byte] |= 0x80 >> (lval % 8); 1432 tmpstr = endstr + 1; 1433 } while (endstr[0] != '\0'); 1434 /* 1435 * RFC3416 Section 2.5 1436 * A BITS value is encoded as an OCTET STRING 1437 */ 1438 goto pastestring; 1439 case 'c': 1440 lval = strtonum(argv[i + 2], 0, UINT32_MAX, 1441 &errstr); 1442 if (errstr != NULL) 1443 errx(1, "%s: Bad value notation (%s)", argv[i], 1444 argv[i + 2]); 1445 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1446 &oid, lval, BER_CLASS_APPLICATION, 1447 SNMP_T_COUNTER32)) == NULL) 1448 err(1, "ober_printf_elements"); 1449 break; 1450 case 'd': 1451 /* String always shrinks */ 1452 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1453 err(1, "malloc"); 1454 tmpstr = argv[i + 2]; 1455 strl = 0; 1456 do { 1457 lval = strtoll(tmpstr, &endstr, 10); 1458 if (endstr[0] != ' ' && endstr[0] != '\t' && 1459 endstr[0] != '\0') 1460 errx(1, "%s: Bad value notation (%s)", 1461 argv[i], argv[i + 2]); 1462 if (tmpstr == endstr) { 1463 tmpstr++; 1464 continue; 1465 } 1466 if (lval < 0 || lval > 0xff) 1467 errx(1, "%s: Bad value notation (%s)", 1468 argv[i], argv[i + 2]); 1469 str[strl++] = (unsigned char) lval; 1470 tmpstr = endstr + 1; 1471 } while (endstr[0] != '\0'); 1472 goto pastestring; 1473 case 'i': 1474 lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX, 1475 &errstr); 1476 if (errstr != NULL) 1477 errx(1, "%s: Bad value notation (%s)", argv[i], 1478 argv[i + 2]); 1479 if ((varbind = ober_printf_elements(varbind, "{Oi}", 1480 &oid, lval)) == NULL) 1481 err(1, "ober_printf_elements"); 1482 break; 1483 case 'n': 1484 if ((varbind = ober_printf_elements(varbind, "{O0}", 1485 &oid)) == NULL) 1486 err(1, "ober_printf_elements"); 1487 break; 1488 case 'o': 1489 if (smi_string2oid(argv[i + 2], &oidval) == -1) 1490 errx(1, "%s: Unknown Object Identifier (Sub-id " 1491 "not found: (top) -> %s)", argv[i], 1492 argv[i + 2]); 1493 if ((varbind = ober_printf_elements(varbind, "{OO}", 1494 &oid, &oidval)) == NULL) 1495 err(1, "ober_printf_elements"); 1496 break; 1497 case 's': 1498 if ((str = strdup(argv[i + 2])) == NULL) 1499 err(1, NULL); 1500 strl = strlen(argv[i + 2]); 1501 pastestring: 1502 if ((varbind = ober_printf_elements(varbind, "{Ox}", 1503 &oid, str, strl)) == NULL) 1504 err(1, "ober_printf_elements"); 1505 free(str); 1506 break; 1507 case 't': 1508 lval = strtonum(argv[i + 2], 0, UINT32_MAX, 1509 &errstr); 1510 if (errstr != NULL) 1511 errx(1, "%s: Bad value notation (%s)", argv[i], 1512 argv[i + 2]); 1513 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1514 &oid, lval, BER_CLASS_APPLICATION, 1515 SNMP_T_TIMETICKS)) == NULL) 1516 err(1, "ober_printf_elements"); 1517 break; 1518 case 'u': 1519 lval = strtonum(argv[i + 2], 0, UINT32_MAX, 1520 &errstr); 1521 if (errstr != NULL) 1522 errx(1, "%s: Bad value notation (%s)", argv[i], 1523 argv[i + 2]); 1524 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1525 &oid, lval, BER_CLASS_APPLICATION, 1526 SNMP_T_GAUGE32)) == NULL) 1527 err(1, "ober_printf_elements"); 1528 break; 1529 case 'x': 1530 /* String always shrinks */ 1531 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1532 err(1, "malloc"); 1533 tmpstr = argv[i + 2]; 1534 strl = 0; 1535 do { 1536 lval = strtoll(tmpstr, &endstr, 16); 1537 if (endstr[0] != ' ' && endstr[0] != '\t' && 1538 endstr[0] != '\0') 1539 errx(1, "%s: Bad value notation (%s)", 1540 argv[i], argv[i + 2]); 1541 if (tmpstr == endstr) { 1542 tmpstr++; 1543 continue; 1544 } 1545 if (lval < 0 || lval > 0xff) 1546 errx(1, "%s: Bad value notation (%s)", 1547 argv[i], argv[i + 2]); 1548 str[strl++] = (unsigned char) lval; 1549 tmpstr = endstr + 1; 1550 } while (endstr[0] != '\0'); 1551 goto pastestring; 1552 default: 1553 usage(); 1554 } 1555 if (vblist == NULL) 1556 vblist = varbind; 1557 } 1558 1559 return vblist; 1560 } 1561 1562 __dead void 1563 usage(void) 1564 { 1565 size_t i; 1566 1567 if (snmp_app != NULL) { 1568 fprintf(stderr, "usage: snmp %s%s%s\n", 1569 snmp_app->name, 1570 snmp_app->usecommonopt ? 1571 " [-A authpass] [-a digest] [-c community] [-e secengineid]\n" 1572 " [-E ctxengineid] [-K localpriv] [-k localauth] [-l seclevel]\n" 1573 " [-n ctxname] [-O afnqvxSQ] [-r retries] [-t timeout] [-u user]\n" 1574 " [-v version] [-X privpass] [-x cipher] [-Z boots,time]\n" 1575 " " : "", 1576 snmp_app->usage == NULL ? "" : snmp_app->usage); 1577 exit(1); 1578 } 1579 for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) { 1580 if (i == 0) 1581 fprintf(stderr, "usage: "); 1582 else 1583 fprintf(stderr, " "); 1584 fprintf(stderr, "snmp %s%s %s\n", 1585 snmp_apps[i].name, 1586 snmp_apps[i].usecommonopt ? 1587 " [options]" : "", 1588 snmp_apps[i].usage ? snmp_apps[i].usage : ""); 1589 } 1590 exit(1); 1591 } 1592