1 /* $OpenBSD: snmpc.c,v 1.30 2020/09/14 15:12:27 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 while (strtolp[0] == ' ' && strtolp[0] == '\t') 460 strtolp++; 461 time = strtoll(strtolp, &strtolp, 10); 462 if (boots < 0 || strtolp == optarg) 463 usage(); 464 zflag = 1; 465 break; 466 default: 467 usage(); 468 } 469 } 470 argc -= optind; 471 argv += optind; 472 473 if (version == SNMP_V3) { 474 /* Setup USM */ 475 if (user == NULL || user[0] == '\0') 476 errx(1, "No securityName specified"); 477 if ((sec = usm_init(user, strlen(user))) == NULL) 478 err(1, "usm_init"); 479 if (seclevel & SNMP_MSGFLAG_AUTH) { 480 if (md == NULL) 481 md = EVP_md5(); 482 if (authkey == NULL) 483 errx(1, "No authKey or authPassword specified"); 484 if (usm_setauth(sec, md, authkey, authkeylen, 485 authkeylevel) == -1) 486 err(1, "Can't set authkey"); 487 } 488 if (seclevel & SNMP_MSGFLAG_PRIV) { 489 if (cipher == NULL) 490 cipher = EVP_des_cbc(); 491 if (privkey == NULL) 492 errx(1, "No privKey or privPassword specified"); 493 if (usm_setpriv(sec, cipher, privkey, privkeylen, 494 privkeylevel) == -1) 495 err(1, "Can't set authkey"); 496 } 497 if (secengineid != NULL) { 498 if (usm_setengineid(sec, secengineid, 499 secengineidlen) == -1) 500 err(1, "Can't set secengineid"); 501 } 502 if (zflag) 503 if (usm_setbootstime(sec, boots, time) == -1) 504 err(1, "Can't set boots/time"); 505 v3 = snmp_v3_init(seclevel, ctxname, ctxname == NULL ? 0 : 506 strlen(ctxname), sec); 507 if (v3 == NULL) 508 err(1, "snmp_v3_init"); 509 if (ctxengineid != NULL) { 510 if (snmp_v3_setengineid(v3, ctxengineid, 511 ctxengineidlen) == -1) 512 err(1, "Can't set ctxengineid"); 513 } 514 } 515 516 517 return snmp_app->exec(argc, argv); 518 } 519 520 int 521 snmpc_get(int argc, char *argv[]) 522 { 523 struct ber_oid *oid; 524 struct ber_element *pdu, *varbind; 525 struct snmp_agent *agent; 526 int errorstatus, errorindex; 527 int i; 528 int class; 529 unsigned type; 530 char *hint = NULL; 531 532 if (argc < 2) 533 usage(); 534 535 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 536 err(1, "%s", snmp_app->name); 537 agent->timeout = timeout; 538 agent->retries = retries; 539 540 if (pledge("stdio", NULL) == -1) 541 err(1, "pledge"); 542 argc--; 543 argv++; 544 545 oid = reallocarray(NULL, argc, sizeof(*oid)); 546 if (oid == NULL) 547 err(1, "malloc"); 548 for (i = 0; i < argc; i++) { 549 if (smi_string2oid(argv[i], &oid[i]) == -1) 550 errx(1, "%s: Unknown object identifier", argv[i]); 551 } 552 if (strcmp(snmp_app->name, "getnext") == 0) { 553 if ((pdu = snmp_getnext(agent, oid, argc)) == NULL) 554 err(1, "getnext"); 555 } else if (strcmp(snmp_app->name, "bulkget") == 0) { 556 if (version < SNMP_V2C) 557 errx(1, "Cannot send V2 PDU on V1 session"); 558 if (non_repeaters > argc) 559 errx(1, "need more objects than -Cn<num>"); 560 if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters, 561 max_repetitions)) == NULL) 562 err(1, "bulkget"); 563 } else { 564 if ((pdu = snmp_get(agent, oid, argc)) == NULL) 565 err(1, "get"); 566 } 567 568 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus, 569 &errorindex, &varbind); 570 if (errorstatus != 0) { 571 if (errorindex >= 1 && errorindex <= argc) 572 hint = argv[errorindex - 1]; 573 snmpc_printerror((enum snmp_error) errorstatus, varbind, 574 errorindex, hint); 575 } 576 577 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 578 printf("Received report:\n"); 579 for (; varbind != NULL; varbind = varbind->be_next) { 580 if (!snmpc_print(varbind)) 581 err(1, "Can't print response"); 582 } 583 ober_free_elements(pdu); 584 snmp_free_agent(agent); 585 return 0; 586 } 587 588 int 589 snmpc_walk(int argc, char *argv[]) 590 { 591 struct ber_oid oid, loid, noid; 592 struct ber_element *pdu, *varbind, *value; 593 struct timespec start, finish; 594 struct snmp_agent *agent; 595 const char *oids; 596 int n = 0, prev_cmp, skip_cmp; 597 int errorstatus, errorindex; 598 int class; 599 size_t i; 600 unsigned type; 601 602 if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C) 603 errx(1, "Cannot send V2 PDU on V1 session"); 604 if (argc < 1 || argc > 2) 605 usage(); 606 oids = argc == 1 ? mib : argv[1]; 607 608 if ((agent = snmpc_connect(argv[0], "161"))== NULL) 609 err(1, "%s", snmp_app->name); 610 agent->timeout = timeout; 611 agent->retries = retries; 612 if (pledge("stdio", NULL) == -1) 613 err(1, "pledge"); 614 615 if (smi_string2oid(oids, &oid) == -1) 616 errx(1, "%s: Unknown object identifier", oids); 617 bcopy(&oid, &noid, sizeof(noid)); 618 if (print_time) 619 clock_gettime(CLOCK_MONOTONIC, &start); 620 621 if (walk_include_oid) { 622 if ((pdu = snmp_get(agent, &oid, 1)) == NULL) 623 err(1, "%s", snmp_app->name); 624 625 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 626 &errorstatus, &errorindex, &varbind); 627 if (errorstatus != 0) 628 snmpc_printerror((enum snmp_error) errorstatus, varbind, 629 errorindex, oids); 630 631 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 632 printf("Received report:\n"); 633 if (!snmpc_print(varbind)) 634 err(1, "Can't print response"); 635 ober_free_element(pdu); 636 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 637 return 1; 638 n++; 639 } 640 while (1) { 641 for (i = 0; i < walk_skip_len; i++) { 642 skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid); 643 if (skip_cmp == 0 || skip_cmp == 2) { 644 bcopy(&(walk_skip[i]), &noid, sizeof(noid)); 645 noid.bo_id[noid.bo_n -1]++; 646 break; 647 } 648 } 649 bcopy(&noid, &loid, sizeof(loid)); 650 if (strcmp(snmp_app->name, "bulkwalk") == 0) { 651 if ((pdu = snmp_getbulk(agent, &noid, 1, 652 non_repeaters, max_repetitions)) == NULL) 653 err(1, "bulkwalk"); 654 } else { 655 if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL) 656 err(1, "walk"); 657 } 658 659 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 660 &errorstatus, &errorindex, &varbind); 661 if (errorstatus != 0) { 662 snmpc_printerror((enum snmp_error) errorstatus, varbind, 663 errorindex, NULL); 664 } 665 666 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 667 printf("Received report:\n"); 668 for (; varbind != NULL; varbind = varbind->be_next) { 669 (void) ober_scanf_elements(varbind, "{oe}", &noid, 670 &value); 671 if (value->be_class == BER_CLASS_CONTEXT && 672 value->be_type == BER_TYPE_EOC) 673 break; 674 for (i = 0; i < walk_skip_len; i++) { 675 skip_cmp = ober_oid_cmp(&(walk_skip[i]), &noid); 676 if (skip_cmp == 0 || skip_cmp == 2) 677 break; 678 } 679 if (i < walk_skip_len) 680 continue; 681 prev_cmp = ober_oid_cmp(&loid, &noid); 682 if (walk_check_increase && prev_cmp == -1) 683 errx(1, "OID not increasing"); 684 if (prev_cmp == 0 || ober_oid_cmp(&oid, &noid) != 2) 685 break; 686 if (walk_end.bo_n != 0 && 687 ober_oid_cmp(&walk_end, &noid) != -1) 688 break; 689 690 if (!snmpc_print(varbind)) 691 err(1, "Can't print response"); 692 n++; 693 } 694 ober_free_elements(pdu); 695 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 696 return 1; 697 if (varbind != NULL) 698 break; 699 } 700 if (walk_fallback_oid && n == 0) { 701 if ((pdu = snmp_get(agent, &oid, 1)) == NULL) 702 err(1, "%s", snmp_app->name); 703 704 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 705 &errorstatus, &errorindex, &varbind); 706 if (errorstatus != 0) 707 snmpc_printerror((enum snmp_error) errorstatus, varbind, 708 errorindex, oids); 709 710 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 711 printf("Received report:\n"); 712 if (!snmpc_print(varbind)) 713 err(1, "Can't print response"); 714 ober_free_element(pdu); 715 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 716 return 1; 717 n++; 718 } 719 if (print_time) 720 clock_gettime(CLOCK_MONOTONIC, &finish); 721 if (print_summary) 722 printf("Variables found: %d\n", n); 723 if (print_time) { 724 if ((finish.tv_nsec -= start.tv_nsec) < 0) { 725 finish.tv_sec -= 1; 726 finish.tv_nsec += 1000000000; 727 } 728 finish.tv_sec -= start.tv_sec; 729 fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n", 730 finish.tv_sec, finish.tv_nsec); 731 } 732 snmp_free_agent(agent); 733 return 0; 734 } 735 736 int 737 snmpc_set(int argc, char *argv[]) 738 { 739 struct snmp_agent *agent; 740 struct ber_element *pdu, *varbind; 741 int errorstatus, errorindex; 742 int class; 743 unsigned type; 744 char *hint = NULL; 745 746 if (argc < 4) 747 usage(); 748 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 749 err(1, "%s", snmp_app->name); 750 argc--; 751 argv++; 752 753 if (pledge("stdio", NULL) == -1) 754 err(1, "pledge"); 755 756 if ((pdu = snmp_set(agent, snmpc_varbindparse(argc, argv))) == NULL) 757 err(1, "set"); 758 759 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, &errorstatus, 760 &errorindex, &varbind); 761 if (errorstatus != 0) { 762 if (errorindex >= 1 && errorindex <= argc / 3) 763 hint = argv[(errorindex - 1) * 3]; 764 snmpc_printerror((enum snmp_error) errorstatus, varbind, 765 errorindex, hint); 766 } 767 768 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) 769 printf("Received report:\n"); 770 for (; varbind != NULL; varbind = varbind->be_next) { 771 if (!snmpc_print(varbind)) 772 err(1, "Can't print response"); 773 } 774 ober_free_elements(pdu); 775 snmp_free_agent(agent); 776 return 0; 777 } 778 779 int 780 snmpc_trap(int argc, char *argv[]) 781 { 782 struct snmp_agent *agent; 783 struct timespec ts; 784 struct ber_oid trapoid; 785 const char *errstr = NULL; 786 long long lval; 787 788 if (version == SNMP_V1) 789 errx(1, "trap is not supported for snmp v1"); 790 791 if ((agent = snmpc_connect(argv[0], "162")) == NULL) 792 err(1, "%s", snmp_app->name); 793 794 if (pledge("stdio", NULL) == -1) 795 err(1, "pledge"); 796 797 if (argv[1][0] == '\0') { 798 if (clock_gettime(CLOCK_UPTIME, &ts) == -1) 799 err(1, "clock_gettime"); 800 } else { 801 lval = strtonum(argv[1], 0, LLONG_MAX, &errstr); 802 if (errstr != NULL) 803 errx(1, "Bad value notation (%s)", argv[1]); 804 ts.tv_sec = lval / 100; 805 ts.tv_nsec = (lval % 100) * 10000000; 806 } 807 if (smi_string2oid(argv[2], &trapoid) == -1) 808 errx(1, "Invalid oid: %s\n", argv[2]); 809 810 argc -= 3; 811 argv += 3; 812 813 snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv)); 814 815 return 0; 816 } 817 818 #define INCR_NEXTTAB(x) ((x + 8) & ~7) 819 #define NEXTTAB(x) (8 - (x & 7)) 820 int 821 snmpc_df(int argc, char *argv[]) 822 { 823 struct snmpc_df { 824 uint32_t index; 825 char *descr; 826 int descrwidth; 827 /* Theoretical maximum for 2 32 bit values multiplied */ 828 char size[21]; 829 char used[21]; 830 char avail[21]; 831 char proc[5]; 832 } *df = NULL; 833 struct ber_oid descroid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 3 }, 11}; 834 struct ber_oid unitsoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 4 }, 11}; 835 struct ber_oid sizeoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 5 }, 11}; 836 struct ber_oid usedoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 6 }, 11}; 837 struct ber_oid oid, *reqoid; 838 char oids[SNMP_MAX_OID_STRLEN]; 839 struct ber_element *pdu, *varbind, *elm; 840 struct snmp_agent *agent; 841 int errorstatus, errorindex; 842 int class; 843 size_t i, j, rows = 0; 844 unsigned type; 845 char *string; 846 int descrlen = 0, sizelen = 0, usedlen = 0, availlen = 0, proclen = 0; 847 int len; 848 long long units, size, used; 849 int fmtret; 850 851 if (argc != 1) 852 usage(); 853 854 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 855 err(1, "%s", snmp_app->name); 856 agent->timeout = timeout; 857 agent->retries = retries; 858 859 if (pledge("stdio", NULL) == -1) 860 err(1, "pledge"); 861 862 descrlen = sizeof("Description") - 1; 863 sizelen = sizeof("Size") - 1; 864 usedlen = sizeof("Used") - 1; 865 availlen = sizeof("Available") - 1; 866 proclen = sizeof("Used%") - 1; 867 868 bcopy(&descroid, &oid, sizeof(descroid)); 869 870 i = 0; 871 while(1) { 872 if (version < SNMP_V2C) { 873 if ((pdu = snmp_getnext(agent, &oid, 1)) == NULL) 874 err(1, "df"); 875 } else { 876 if ((pdu = snmp_getbulk(agent, &oid, 1, 0, 877 max_repetitions)) == NULL) 878 err(1, "df"); 879 } 880 881 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 882 &errorstatus, &errorindex, &varbind); 883 if (errorstatus != 0) 884 snmpc_printerror((enum snmp_error) errorstatus, varbind, 885 errorindex, NULL); 886 887 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 888 printf("Received report:\n"); 889 for (; varbind != NULL; varbind = varbind->be_next) { 890 if (!snmpc_print(varbind)) 891 err(1, "Can't print response"); 892 } 893 return 1; 894 } 895 for (; varbind != NULL; varbind = varbind->be_next) { 896 if (ober_scanf_elements(varbind, "{os", &oid, 897 &string) == -1 || 898 ober_oid_cmp(&descroid, &oid) != 2) 899 break; 900 rows++; 901 } 902 if ((df = reallocarray(df, rows, sizeof(*df))) == NULL) 903 err(1, "malloc"); 904 (void) ober_scanf_elements(pdu, "{SSS{e", &varbind); 905 for (; i < rows; varbind = varbind->be_next, i++) { 906 if (ober_scanf_elements(varbind, "{oe", &oid, 907 &elm) == -1) { 908 i--; 909 rows--; 910 continue; 911 } 912 if (ober_oid_cmp(&descroid, &oid) != 2) 913 break; 914 df[i].index = oid.bo_id[oid.bo_n - 1]; 915 if ((df[i].descr = smi_print_element(&oid, elm, 0, 916 smi_os_ascii, 0, utf8)) == NULL) { 917 smi_oid2string(&oid, oids, sizeof(oids), 918 oid_lookup); 919 warn("df: can't print oid %s", oids); 920 i--; 921 rows--; 922 continue; 923 } 924 if ((df[i].descrwidth = 925 (int) snmpc_mbswidth(df[i].descr)) == -1) 926 err(1, "df: invalid hrStorageDescr"); 927 if (df[i].descrwidth > descrlen) 928 descrlen = df[i].descrwidth; 929 } 930 ober_free_elements(pdu); 931 if (varbind != NULL) 932 break; 933 } 934 935 if (max_repetitions < 3) 936 max_repetitions = 3; 937 if ((reqoid = reallocarray(NULL, max_repetitions, sizeof(*reqoid))) == NULL) 938 err(1, "malloc"); 939 for (i = 0; i < rows;) { 940 for (j = 0; i + j < rows && j < (size_t)max_repetitions / 3; 941 j++) { 942 bcopy(&unitsoid, &(reqoid[(j * 3) + 0]), 943 sizeof(unitsoid)); 944 reqoid[(j * 3) + 0].bo_id[ 945 reqoid[(j * 3) + 0].bo_n++] = df[i + j].index; 946 bcopy(&sizeoid, &(reqoid[(j * 3) + 1]), 947 sizeof(sizeoid)); 948 reqoid[(j * 3) + 1].bo_id[ 949 reqoid[(j * 3) + 1].bo_n++] = df[i + j].index; 950 bcopy(&usedoid, &(reqoid[(j * 3) + 2]), 951 sizeof(usedoid)); 952 reqoid[(j * 3) + 2].bo_id[ 953 reqoid[(j * 3) + 2].bo_n++] = df[i + j].index; 954 } 955 if ((pdu = snmp_get(agent, reqoid, j * 3)) == NULL) 956 err(1, "df"); 957 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 958 &errorstatus, &errorindex, &varbind); 959 if (errorstatus != 0) 960 snmpc_printerror((enum snmp_error) errorstatus, varbind, 961 errorindex, NULL); 962 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 963 printf("Received report:\n"); 964 for (; varbind != NULL; varbind = varbind->be_next) { 965 if (!snmpc_print(varbind)) 966 err(1, "Can't print response"); 967 } 968 } 969 for (j = 0; varbind != NULL; i++) { 970 if (ober_scanf_elements(varbind, "{oi}{oi}{oi}", 971 &(reqoid[0]), &units, &(reqoid[1]), &size, 972 &(reqoid[2]), &used, &varbind) == -1) { 973 break; 974 } 975 varbind = varbind->be_next->be_next->be_next; 976 977 unitsoid.bo_id[unitsoid.bo_n++] = df[i].index; 978 if (ober_oid_cmp(&unitsoid, &(reqoid[0])) != 0) { 979 warnx("df: received invalid object"); 980 break; 981 } 982 unitsoid.bo_n--; 983 sizeoid.bo_id[sizeoid.bo_n++] = df[i].index; 984 if (ober_oid_cmp(&sizeoid, &(reqoid[1])) != 0) { 985 warnx("df: received invalid object"); 986 break; 987 } 988 sizeoid.bo_n--; 989 usedoid.bo_id[usedoid.bo_n++] = df[i].index; 990 if (ober_oid_cmp(&usedoid, &(reqoid[2])) != 0) { 991 warnx("df: received invalid object"); 992 break; 993 } 994 usedoid.bo_n--; 995 if (print_human) 996 fmtret = fmt_scaled((units * size), df[i].size); 997 if (!print_human || fmtret == -1) 998 snprintf(df[i].size, sizeof(df[i].size), "%lld", 999 (units * size) / 1024); 1000 len = (int) strlen(df[i].size); 1001 if (len > sizelen) 1002 sizelen = len; 1003 if (print_human) 1004 fmtret = fmt_scaled(units * used, df[i].used); 1005 if (!print_human || fmtret == -1) 1006 snprintf(df[i].used, sizeof(df[i].used), "%lld", 1007 (units * used) / 1024); 1008 len = (int) strlen(df[i].used); 1009 if (len > usedlen) 1010 usedlen = len; 1011 if (print_human) 1012 fmtret = fmt_scaled(units * (size - used), 1013 df[i].avail); 1014 if (!print_human || fmtret == -1) 1015 snprintf(df[i].avail, sizeof(df[i].avail), 1016 "%lld", (units * (size - used)) / 1024); 1017 len = (int) strlen(df[i].avail); 1018 if (len > availlen) 1019 availlen = len; 1020 if (size == 0) 1021 strlcpy(df[i].proc, "0%", sizeof(df[i].proc)); 1022 else { 1023 snprintf(df[i].proc, sizeof(df[i].proc), 1024 "%lld%%", (used * 100) / size); 1025 } 1026 len = (int) strlen(df[i].proc); 1027 if (len > proclen) 1028 proclen = len; 1029 j++; 1030 } 1031 if (j == 0) { 1032 warnx("Failed to retrieve information for %s", 1033 df[i].descr); 1034 memmove(df + i, df + i + 1, 1035 (rows - i - 1) * sizeof(*df)); 1036 rows--; 1037 i--; 1038 } 1039 } 1040 1041 printf("%-*s%*s%*s%*s%*s\n", 1042 descrlen, "Description", 1043 NEXTTAB(descrlen) + sizelen, "Size", 1044 NEXTTAB(sizelen) + usedlen, "Used", 1045 NEXTTAB(usedlen) + availlen, "Available", 1046 NEXTTAB(availlen) + proclen, "Used%"); 1047 for (i = 0; i < rows; i++) { 1048 printf("%s%*s%*s%*s%*s%*s\n", 1049 df[i].descr, descrlen - df[i].descrwidth, "", 1050 NEXTTAB(descrlen) + sizelen, df[i].size, 1051 NEXTTAB(sizelen) + usedlen, df[i].used, 1052 NEXTTAB(usedlen) + availlen, df[i].avail, 1053 NEXTTAB(availlen) + proclen, df[i].proc); 1054 } 1055 1056 return 0; 1057 } 1058 1059 int 1060 snmpc_mibtree(int argc, char *argv[]) 1061 { 1062 struct oid *oid; 1063 struct ber_oid soid; 1064 char buf[BUFSIZ]; 1065 int i; 1066 1067 if (argc == 0) { 1068 for (oid = NULL; (oid = smi_foreach(oid)) != NULL;) { 1069 smi_oid2string(&oid->o_id, buf, sizeof(buf), 1070 oid_lookup); 1071 printf("%s\n", buf); 1072 } 1073 } else { 1074 for (i = 0; i < argc; i++) { 1075 if (smi_string2oid(argv[i], &soid) == -1) { 1076 warnx("%s: Unknown object identifier", argv[i]); 1077 continue; 1078 } 1079 smi_oid2string(&soid, buf, sizeof(buf), oid_lookup); 1080 printf("%s\n", buf); 1081 } 1082 } 1083 return 0; 1084 } 1085 1086 struct snmp_agent * 1087 snmpc_connect(char *host, char *port) 1088 { 1089 switch (version) { 1090 case SNMP_V1: 1091 case SNMP_V2C: 1092 return snmp_connect_v12(snmpc_parseagent(host, port), version, 1093 community); 1094 case SNMP_V3: 1095 return snmp_connect_v3(snmpc_parseagent(host, port), v3); 1096 } 1097 return NULL; 1098 } 1099 1100 int 1101 snmpc_print(struct ber_element *elm) 1102 { 1103 struct ber_oid oid; 1104 char oids[SNMP_MAX_OID_STRLEN]; 1105 char *value; 1106 1107 elm = elm->be_sub; 1108 if (ober_get_oid(elm, &oid) != 0) { 1109 errno = EINVAL; 1110 return 0; 1111 } 1112 1113 elm = elm->be_next; 1114 value = smi_print_element(&oid, elm, smi_print_hint, output_string, 1115 oid_lookup, utf8); 1116 if (value == NULL) 1117 return 0; 1118 1119 if (print_varbind_only) 1120 printf("%s\n", value); 1121 else if (print_equals) { 1122 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1123 printf("%s = %s\n", oids, value); 1124 } else { 1125 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1126 printf("%s %s\n", oids, value); 1127 } 1128 free(value); 1129 1130 return 1; 1131 } 1132 1133 __dead void 1134 snmpc_printerror(enum snmp_error error, struct ber_element *varbind, 1135 int index, const char *hint) 1136 { 1137 struct ber_oid hoid, vboid; 1138 char oids[SNMP_MAX_OID_STRLEN]; 1139 const char *oid = NULL; 1140 int i; 1141 1142 if (index >= 1) { 1143 /* Only print if the index is in the reply */ 1144 for (i = 1; varbind != NULL && i < index; 1145 varbind = varbind->be_next) 1146 i++; 1147 if (varbind != NULL && 1148 ober_get_oid(varbind->be_sub, &vboid) == 0) { 1149 /* If user and reply conform print user input */ 1150 if (hint != NULL && 1151 smi_string2oid(hint, &hoid) == 0 && 1152 ober_oid_cmp(&hoid, &vboid) == 0) 1153 oid = hint; 1154 else 1155 oid = smi_oid2string(&vboid, oids, 1156 sizeof(oids), oid_lookup); 1157 } 1158 } 1159 if (oid == NULL) 1160 oid = "?"; 1161 1162 switch (error) { 1163 case SNMP_ERROR_NONE: 1164 errx(1, "No error, how did I get here?"); 1165 case SNMP_ERROR_TOOBIG: 1166 errx(1, "Can't parse oid %s: Response too big", oid); 1167 case SNMP_ERROR_NOSUCHNAME: 1168 errx(1, "Can't parse oid %s: No such object", oid); 1169 case SNMP_ERROR_BADVALUE: 1170 errx(1, "Can't parse oid %s: Bad value", oid); 1171 case SNMP_ERROR_READONLY: 1172 errx(1, "Can't parse oid %s: Read only", oid); 1173 case SNMP_ERROR_GENERR: 1174 errx(1, "Can't parse oid %s: Generic error", oid); 1175 case SNMP_ERROR_NOACCESS: 1176 errx(1, "Can't parse oid %s: Access denied", oid); 1177 case SNMP_ERROR_WRONGTYPE: 1178 errx(1, "Can't parse oid %s: Wrong type", oid); 1179 case SNMP_ERROR_WRONGLENGTH: 1180 errx(1, "Can't parse oid %s: Wrong length", oid); 1181 case SNMP_ERROR_WRONGENC: 1182 errx(1, "Can't parse oid %s: Wrong encoding", oid); 1183 case SNMP_ERROR_WRONGVALUE: 1184 errx(1, "Can't parse oid %s: Wrong value", oid); 1185 case SNMP_ERROR_NOCREATION: 1186 errx(1, "Can't parse oid %s: Can't be created", oid); 1187 case SNMP_ERROR_INCONVALUE: 1188 errx(1, "Can't parse oid %s: Inconsistent value", oid); 1189 case SNMP_ERROR_RESUNAVAIL: 1190 errx(1, "Can't parse oid %s: Resource unavailable", oid); 1191 case SNMP_ERROR_COMMITFAILED: 1192 errx(1, "Can't parse oid %s: Commit failed", oid); 1193 case SNMP_ERROR_UNDOFAILED: 1194 errx(1, "Can't parse oid %s: Undo faild", oid); 1195 case SNMP_ERROR_AUTHERROR: 1196 errx(1, "Can't parse oid %s: Authorization error", oid); 1197 case SNMP_ERROR_NOTWRITABLE: 1198 errx(1, "Can't parse oid %s: Not writable", oid); 1199 case SNMP_ERROR_INCONNAME: 1200 errx(1, "Can't parse oid %s: Inconsistent name", oid); 1201 } 1202 errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error); 1203 } 1204 1205 int 1206 snmpc_parseagent(char *agent, char *defaultport) 1207 { 1208 struct addrinfo hints, *ai, *ai0 = NULL; 1209 struct sockaddr_un saddr; 1210 char *agentdup, *specifier, *hostname, *port = NULL; 1211 int error; 1212 int s; 1213 1214 if ((agentdup = specifier = strdup(agent)) == NULL) 1215 err(1, NULL); 1216 1217 bzero(&hints, sizeof(hints)); 1218 if ((hostname = strchr(specifier, ':')) != NULL) { 1219 *hostname++ = '\0'; 1220 if (strcasecmp(specifier, "udp") == 0) { 1221 hints.ai_family = AF_INET; 1222 hints.ai_socktype = SOCK_DGRAM; 1223 } else if (strcasecmp(specifier, "tcp") == 0) { 1224 hints.ai_family = AF_INET; 1225 hints.ai_socktype = SOCK_STREAM; 1226 } else if (strcasecmp(specifier, "udp6") == 0 || 1227 strcasecmp(specifier, "udpv6") == 0 || 1228 strcasecmp(specifier, "udpipv6") == 0) { 1229 hints.ai_family = AF_INET6; 1230 hints.ai_socktype = SOCK_DGRAM; 1231 } else if (strcasecmp(specifier, "tcp6") == 0 || 1232 strcasecmp(specifier, "tcpv6") == 0 || 1233 strcasecmp(specifier, "tcpipv6") == 0) { 1234 hints.ai_family = AF_INET6; 1235 hints.ai_socktype = SOCK_STREAM; 1236 } else if (strcasecmp(specifier, "unix") == 0) { 1237 hints.ai_family = AF_UNIX; 1238 hints.ai_addr = (struct sockaddr *)&saddr; 1239 hints.ai_addrlen = sizeof(saddr); 1240 saddr.sun_len = sizeof(saddr); 1241 saddr.sun_family = AF_UNIX; 1242 if (strlcpy(saddr.sun_path, hostname, 1243 sizeof(saddr.sun_path)) > sizeof(saddr.sun_path)) 1244 errx(1, "Hostname path too long"); 1245 ai = &hints; 1246 } else { 1247 *--hostname = ':'; 1248 hostname = specifier; 1249 } 1250 } else { 1251 hostname = specifier; 1252 } 1253 1254 if (hints.ai_family == AF_INET) { 1255 if ((port = strchr(hostname, ':')) != NULL) 1256 *port++ = '\0'; 1257 } else if (hints.ai_family == AF_INET6 || hints.ai_family == 0) { 1258 if (hostname[0] == '[') { 1259 hints.ai_family = AF_INET6; 1260 hostname++; 1261 if ((port = strchr(hostname, ']')) == NULL) 1262 errx(1, "invalid agent"); 1263 *port++ = '\0'; 1264 if (port[0] == ':') 1265 *port++ = '\0'; 1266 else if (port[0] == '\0') 1267 port = NULL; 1268 else 1269 errx(1, "invalid agent"); 1270 } else { 1271 if ((port = strrchr(hostname, ':')) != NULL) 1272 *port++ = '\0'; 1273 } 1274 } 1275 1276 if (hints.ai_family != AF_UNIX) { 1277 if (hints.ai_socktype == 0) 1278 hints.ai_socktype = SOCK_DGRAM; 1279 if (port == NULL) 1280 port = defaultport; 1281 error = getaddrinfo(hostname, port, &hints, &ai0); 1282 if (error) { 1283 if (error != EAI_NODATA || port == defaultport) 1284 errx(1, "%s", gai_strerror(error)); 1285 *--port = ':'; 1286 error = getaddrinfo(hostname, defaultport, &hints, 1287 &ai0); 1288 if (error) 1289 errx(1, "%s", gai_strerror(error)); 1290 } 1291 s = -1; 1292 for (ai = ai0; ai != NULL; ai = ai->ai_next) { 1293 if ((s = socket(ai->ai_family, ai->ai_socktype, 1294 ai->ai_protocol)) != -1 && 1295 connect(s, (struct sockaddr *)ai->ai_addr, 1296 ai->ai_addrlen) != -1) 1297 break; 1298 close(s); 1299 s = -1; 1300 } 1301 } else { 1302 s = socket(AF_UNIX, SOCK_STREAM, 0); 1303 if (connect(s, (struct sockaddr *)ai->ai_addr, 1304 ai->ai_addrlen) == -1) 1305 err(1, "Can't connect to %s", agent); 1306 } 1307 if (s == -1) 1308 err(1, "Can't connect to agent %s", agent); 1309 1310 1311 if (ai0 != NULL) 1312 freeaddrinfo(ai0); 1313 free(agentdup); 1314 return s; 1315 } 1316 1317 char * 1318 snmpc_hex2bin(char *hexstr, size_t *binlen) 1319 { 1320 char *decstr; 1321 1322 if (hexstr[0] == '0' && hexstr[1] == 'x') 1323 hexstr += 2; 1324 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1325 hexstr++; 1326 1327 if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL) 1328 return NULL; 1329 1330 for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) { 1331 hexstr[0] = toupper(hexstr[0]); 1332 hexstr[1] = toupper(hexstr[1]); 1333 if (hexstr[0] >= '0' && hexstr[0] <= '9') 1334 decstr[*binlen] = (hexstr[0] - '0') << 4; 1335 else if (hexstr[0] >= 'A' && hexstr[0] <= 'F') 1336 decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4; 1337 else 1338 goto fail; 1339 if (hexstr[1] >= '0' && hexstr[1] <= '9') 1340 decstr[*binlen] |= (hexstr[1] - '0'); 1341 else if (hexstr[1] >= 'A' && hexstr[1] <= 'F') 1342 decstr[*binlen] |= (hexstr[1] - 'A') + 10; 1343 else 1344 goto fail; 1345 1346 hexstr += 2; 1347 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1348 hexstr++; 1349 } 1350 1351 return decstr; 1352 fail: 1353 errno = EINVAL; 1354 free(decstr); 1355 return NULL; 1356 } 1357 1358 ssize_t 1359 snmpc_mbswidth(char *str) 1360 { 1361 wchar_t wc; 1362 size_t width = 0; 1363 size_t i; 1364 int len; 1365 1366 for (i = 0; (len = mbtowc(&wc, &(str[i]), MB_CUR_MAX)) != 0; i += len) { 1367 if (len == -1) { 1368 mbtowc(NULL, NULL, MB_CUR_MAX); 1369 return -1; 1370 } 1371 width += wcwidth(wc); 1372 } 1373 return width; 1374 } 1375 1376 struct ber_element * 1377 snmpc_varbindparse(int argc, char *argv[]) 1378 { 1379 struct ber_oid oid, oidval; 1380 struct in_addr addr4; 1381 char *addr = (char *)&addr4; 1382 char *str = NULL, *tmpstr, *endstr; 1383 const char *errstr = NULL; 1384 struct ber_element *varbind = NULL, *vblist = NULL; 1385 int i, ret; 1386 size_t strl, byte; 1387 long long lval; 1388 1389 if (argc % 3 != 0) 1390 usage(); 1391 for (i = 0; i < argc; i += 3) { 1392 if (smi_string2oid(argv[i], &oid) == -1) 1393 errx(1, "Invalid oid: %s\n", argv[i]); 1394 switch (argv[i + 1][0]) { 1395 case 'a': 1396 ret = inet_pton(AF_INET, argv[i + 2], &addr4); 1397 if (ret == -1) 1398 err(1, "inet_pton"); 1399 if (ret == 0) 1400 errx(1, "%s: Bad value notation (%s)", argv[i], 1401 argv[i + 2]); 1402 if ((varbind = ober_printf_elements(varbind, "{Oxt}", 1403 &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION, 1404 SNMP_T_IPADDR)) == NULL) 1405 err(1, "ober_printf_elements"); 1406 break; 1407 case 'b': 1408 tmpstr = argv[i + 2]; 1409 strl = 0; 1410 do { 1411 lval = strtoll(tmpstr, &endstr, 10); 1412 if (endstr[0] != ' ' && endstr[0] != '\t' && 1413 endstr[0] != ',' && endstr[0] != '\0') 1414 errx(1, "%s: Bad value notation (%s)", 1415 argv[i], argv[i + 2]); 1416 if (tmpstr == endstr) { 1417 tmpstr++; 1418 continue; 1419 } 1420 if (lval < 0) 1421 errx(1, "%s: Bad value notation (%s)", 1422 argv[i], argv[i + 2]); 1423 byte = lval / 8; 1424 if (byte >= strl) { 1425 if ((str = recallocarray(str, strl, 1426 byte + 1, 1)) == NULL) 1427 err(1, "malloc"); 1428 strl = byte + 1; 1429 } 1430 str[byte] |= 0x80 >> (lval % 8); 1431 tmpstr = endstr + 1; 1432 } while (endstr[0] != '\0'); 1433 /* 1434 * RFC3416 Section 2.5 1435 * A BITS value is encoded as an OCTET STRING 1436 */ 1437 goto pastestring; 1438 case 'c': 1439 lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX, 1440 &errstr); 1441 if (errstr != NULL) 1442 errx(1, "%s: Bad value notation (%s)", argv[i], 1443 argv[i + 2]); 1444 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1445 &oid, lval, BER_CLASS_APPLICATION, 1446 SNMP_T_COUNTER32)) == NULL) 1447 err(1, "ober_printf_elements"); 1448 break; 1449 case 'd': 1450 /* String always shrinks */ 1451 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1452 err(1, "malloc"); 1453 tmpstr = argv[i + 2]; 1454 strl = 0; 1455 do { 1456 lval = strtoll(tmpstr, &endstr, 10); 1457 if (endstr[0] != ' ' && endstr[0] != '\t' && 1458 endstr[0] != '\0') 1459 errx(1, "%s: Bad value notation (%s)", 1460 argv[i], argv[i + 2]); 1461 if (tmpstr == endstr) { 1462 tmpstr++; 1463 continue; 1464 } 1465 if (lval < 0 || lval > 0xff) 1466 errx(1, "%s: Bad value notation (%s)", 1467 argv[i], argv[i + 2]); 1468 str[strl++] = (unsigned char) lval; 1469 tmpstr = endstr + 1; 1470 } while (endstr[0] != '\0'); 1471 goto pastestring; 1472 case 'u': 1473 case 'i': 1474 lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_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], LLONG_MIN, LLONG_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 'x': 1519 /* String always shrinks */ 1520 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1521 err(1, "malloc"); 1522 tmpstr = argv[i + 2]; 1523 strl = 0; 1524 do { 1525 lval = strtoll(tmpstr, &endstr, 16); 1526 if (endstr[0] != ' ' && endstr[0] != '\t' && 1527 endstr[0] != '\0') 1528 errx(1, "%s: Bad value notation (%s)", 1529 argv[i], argv[i + 2]); 1530 if (tmpstr == endstr) { 1531 tmpstr++; 1532 continue; 1533 } 1534 if (lval < 0 || lval > 0xff) 1535 errx(1, "%s: Bad value notation (%s)", 1536 argv[i], argv[i + 2]); 1537 str[strl++] = (unsigned char) lval; 1538 tmpstr = endstr + 1; 1539 } while (endstr[0] != '\0'); 1540 goto pastestring; 1541 default: 1542 usage(); 1543 } 1544 if (vblist == NULL) 1545 vblist = varbind; 1546 } 1547 1548 return vblist; 1549 } 1550 1551 __dead void 1552 usage(void) 1553 { 1554 size_t i; 1555 1556 if (snmp_app != NULL) { 1557 fprintf(stderr, "usage: snmp %s%s%s\n", 1558 snmp_app->name, 1559 snmp_app->usecommonopt ? 1560 " [-A authpass] [-a digest] [-c community] [-e secengineid]\n" 1561 " [-E ctxengineid] [-K localpriv] [-k localauth] [-l seclevel]\n" 1562 " [-n ctxname] [-O afnqvxSQ] [-r retries] [-t timeout] [-u user]\n" 1563 " [-v version] [-X privpass] [-x cipher] [-Z boots,time]\n" 1564 " " : "", 1565 snmp_app->usage == NULL ? "" : snmp_app->usage); 1566 exit(1); 1567 } 1568 for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) { 1569 if (i == 0) 1570 fprintf(stderr, "usage: "); 1571 else 1572 fprintf(stderr, " "); 1573 fprintf(stderr, "snmp %s%s %s\n", 1574 snmp_apps[i].name, 1575 snmp_apps[i].usecommonopt ? 1576 " [options]" : "", 1577 snmp_apps[i].usage ? snmp_apps[i].usage : ""); 1578 } 1579 exit(1); 1580 } 1581