1 /* $OpenBSD: snmpc.c,v 1.31 2020/12/02 15:45:51 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 (argc < 3) 792 usage(); 793 794 if ((agent = snmpc_connect(argv[0], "162")) == NULL) 795 err(1, "%s", snmp_app->name); 796 797 if (pledge("stdio", NULL) == -1) 798 err(1, "pledge"); 799 800 if (argv[1][0] == '\0') { 801 if (clock_gettime(CLOCK_UPTIME, &ts) == -1) 802 err(1, "clock_gettime"); 803 } else { 804 lval = strtonum(argv[1], 0, LLONG_MAX, &errstr); 805 if (errstr != NULL) 806 errx(1, "Bad value notation (%s)", argv[1]); 807 ts.tv_sec = lval / 100; 808 ts.tv_nsec = (lval % 100) * 10000000; 809 } 810 if (smi_string2oid(argv[2], &trapoid) == -1) 811 errx(1, "Invalid oid: %s\n", argv[2]); 812 813 argc -= 3; 814 argv += 3; 815 816 snmp_trap(agent, &ts, &trapoid, snmpc_varbindparse(argc, argv)); 817 818 return 0; 819 } 820 821 #define INCR_NEXTTAB(x) ((x + 8) & ~7) 822 #define NEXTTAB(x) (8 - (x & 7)) 823 int 824 snmpc_df(int argc, char *argv[]) 825 { 826 struct snmpc_df { 827 uint32_t index; 828 char *descr; 829 int descrwidth; 830 /* Theoretical maximum for 2 32 bit values multiplied */ 831 char size[21]; 832 char used[21]; 833 char avail[21]; 834 char proc[5]; 835 } *df = NULL; 836 struct ber_oid descroid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 3 }, 11}; 837 struct ber_oid unitsoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 4 }, 11}; 838 struct ber_oid sizeoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 5 }, 11}; 839 struct ber_oid usedoid = {{ 1, 3, 6, 1, 2, 1, 25, 2, 3, 1, 6 }, 11}; 840 struct ber_oid oid, *reqoid; 841 char oids[SNMP_MAX_OID_STRLEN]; 842 struct ber_element *pdu, *varbind, *elm; 843 struct snmp_agent *agent; 844 int errorstatus, errorindex; 845 int class; 846 size_t i, j, rows = 0; 847 unsigned type; 848 char *string; 849 int descrlen = 0, sizelen = 0, usedlen = 0, availlen = 0, proclen = 0; 850 int len; 851 long long units, size, used; 852 int fmtret; 853 854 if (argc != 1) 855 usage(); 856 857 if ((agent = snmpc_connect(argv[0], "161")) == NULL) 858 err(1, "%s", snmp_app->name); 859 agent->timeout = timeout; 860 agent->retries = retries; 861 862 if (pledge("stdio", NULL) == -1) 863 err(1, "pledge"); 864 865 descrlen = sizeof("Description") - 1; 866 sizelen = sizeof("Size") - 1; 867 usedlen = sizeof("Used") - 1; 868 availlen = sizeof("Available") - 1; 869 proclen = sizeof("Used%") - 1; 870 871 bcopy(&descroid, &oid, sizeof(descroid)); 872 873 i = 0; 874 while(1) { 875 if (version < SNMP_V2C) { 876 if ((pdu = snmp_getnext(agent, &oid, 1)) == NULL) 877 err(1, "df"); 878 } else { 879 if ((pdu = snmp_getbulk(agent, &oid, 1, 0, 880 max_repetitions)) == NULL) 881 err(1, "df"); 882 } 883 884 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 885 &errorstatus, &errorindex, &varbind); 886 if (errorstatus != 0) 887 snmpc_printerror((enum snmp_error) errorstatus, varbind, 888 errorindex, NULL); 889 890 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 891 printf("Received report:\n"); 892 for (; varbind != NULL; varbind = varbind->be_next) { 893 if (!snmpc_print(varbind)) 894 err(1, "Can't print response"); 895 } 896 return 1; 897 } 898 for (; varbind != NULL; varbind = varbind->be_next) { 899 if (ober_scanf_elements(varbind, "{os", &oid, 900 &string) == -1 || 901 ober_oid_cmp(&descroid, &oid) != 2) 902 break; 903 rows++; 904 } 905 if ((df = reallocarray(df, rows, sizeof(*df))) == NULL) 906 err(1, "malloc"); 907 (void) ober_scanf_elements(pdu, "{SSS{e", &varbind); 908 for (; i < rows; varbind = varbind->be_next, i++) { 909 if (ober_scanf_elements(varbind, "{oe", &oid, 910 &elm) == -1) { 911 i--; 912 rows--; 913 continue; 914 } 915 if (ober_oid_cmp(&descroid, &oid) != 2) 916 break; 917 df[i].index = oid.bo_id[oid.bo_n - 1]; 918 if ((df[i].descr = smi_print_element(&oid, elm, 0, 919 smi_os_ascii, 0, utf8)) == NULL) { 920 smi_oid2string(&oid, oids, sizeof(oids), 921 oid_lookup); 922 warn("df: can't print oid %s", oids); 923 i--; 924 rows--; 925 continue; 926 } 927 if ((df[i].descrwidth = 928 (int) snmpc_mbswidth(df[i].descr)) == -1) 929 err(1, "df: invalid hrStorageDescr"); 930 if (df[i].descrwidth > descrlen) 931 descrlen = df[i].descrwidth; 932 } 933 ober_free_elements(pdu); 934 if (varbind != NULL) 935 break; 936 } 937 938 if (max_repetitions < 3) 939 max_repetitions = 3; 940 if ((reqoid = reallocarray(NULL, max_repetitions, sizeof(*reqoid))) == NULL) 941 err(1, "malloc"); 942 for (i = 0; i < rows;) { 943 for (j = 0; i + j < rows && j < (size_t)max_repetitions / 3; 944 j++) { 945 bcopy(&unitsoid, &(reqoid[(j * 3) + 0]), 946 sizeof(unitsoid)); 947 reqoid[(j * 3) + 0].bo_id[ 948 reqoid[(j * 3) + 0].bo_n++] = df[i + j].index; 949 bcopy(&sizeoid, &(reqoid[(j * 3) + 1]), 950 sizeof(sizeoid)); 951 reqoid[(j * 3) + 1].bo_id[ 952 reqoid[(j * 3) + 1].bo_n++] = df[i + j].index; 953 bcopy(&usedoid, &(reqoid[(j * 3) + 2]), 954 sizeof(usedoid)); 955 reqoid[(j * 3) + 2].bo_id[ 956 reqoid[(j * 3) + 2].bo_n++] = df[i + j].index; 957 } 958 if ((pdu = snmp_get(agent, reqoid, j * 3)) == NULL) 959 err(1, "df"); 960 (void) ober_scanf_elements(pdu, "t{Sdd{e", &class, &type, 961 &errorstatus, &errorindex, &varbind); 962 if (errorstatus != 0) 963 snmpc_printerror((enum snmp_error) errorstatus, varbind, 964 errorindex, NULL); 965 if (class == BER_CLASS_CONTEXT && type == SNMP_C_REPORT) { 966 printf("Received report:\n"); 967 for (; varbind != NULL; varbind = varbind->be_next) { 968 if (!snmpc_print(varbind)) 969 err(1, "Can't print response"); 970 } 971 } 972 for (j = 0; varbind != NULL; i++) { 973 if (ober_scanf_elements(varbind, "{oi}{oi}{oi}", 974 &(reqoid[0]), &units, &(reqoid[1]), &size, 975 &(reqoid[2]), &used, &varbind) == -1) { 976 break; 977 } 978 varbind = varbind->be_next->be_next->be_next; 979 980 unitsoid.bo_id[unitsoid.bo_n++] = df[i].index; 981 if (ober_oid_cmp(&unitsoid, &(reqoid[0])) != 0) { 982 warnx("df: received invalid object"); 983 break; 984 } 985 unitsoid.bo_n--; 986 sizeoid.bo_id[sizeoid.bo_n++] = df[i].index; 987 if (ober_oid_cmp(&sizeoid, &(reqoid[1])) != 0) { 988 warnx("df: received invalid object"); 989 break; 990 } 991 sizeoid.bo_n--; 992 usedoid.bo_id[usedoid.bo_n++] = df[i].index; 993 if (ober_oid_cmp(&usedoid, &(reqoid[2])) != 0) { 994 warnx("df: received invalid object"); 995 break; 996 } 997 usedoid.bo_n--; 998 if (print_human) 999 fmtret = fmt_scaled((units * size), df[i].size); 1000 if (!print_human || fmtret == -1) 1001 snprintf(df[i].size, sizeof(df[i].size), "%lld", 1002 (units * size) / 1024); 1003 len = (int) strlen(df[i].size); 1004 if (len > sizelen) 1005 sizelen = len; 1006 if (print_human) 1007 fmtret = fmt_scaled(units * used, df[i].used); 1008 if (!print_human || fmtret == -1) 1009 snprintf(df[i].used, sizeof(df[i].used), "%lld", 1010 (units * used) / 1024); 1011 len = (int) strlen(df[i].used); 1012 if (len > usedlen) 1013 usedlen = len; 1014 if (print_human) 1015 fmtret = fmt_scaled(units * (size - used), 1016 df[i].avail); 1017 if (!print_human || fmtret == -1) 1018 snprintf(df[i].avail, sizeof(df[i].avail), 1019 "%lld", (units * (size - used)) / 1024); 1020 len = (int) strlen(df[i].avail); 1021 if (len > availlen) 1022 availlen = len; 1023 if (size == 0) 1024 strlcpy(df[i].proc, "0%", sizeof(df[i].proc)); 1025 else { 1026 snprintf(df[i].proc, sizeof(df[i].proc), 1027 "%lld%%", (used * 100) / size); 1028 } 1029 len = (int) strlen(df[i].proc); 1030 if (len > proclen) 1031 proclen = len; 1032 j++; 1033 } 1034 if (j == 0) { 1035 warnx("Failed to retrieve information for %s", 1036 df[i].descr); 1037 memmove(df + i, df + i + 1, 1038 (rows - i - 1) * sizeof(*df)); 1039 rows--; 1040 i--; 1041 } 1042 } 1043 1044 printf("%-*s%*s%*s%*s%*s\n", 1045 descrlen, "Description", 1046 NEXTTAB(descrlen) + sizelen, "Size", 1047 NEXTTAB(sizelen) + usedlen, "Used", 1048 NEXTTAB(usedlen) + availlen, "Available", 1049 NEXTTAB(availlen) + proclen, "Used%"); 1050 for (i = 0; i < rows; i++) { 1051 printf("%s%*s%*s%*s%*s%*s\n", 1052 df[i].descr, descrlen - df[i].descrwidth, "", 1053 NEXTTAB(descrlen) + sizelen, df[i].size, 1054 NEXTTAB(sizelen) + usedlen, df[i].used, 1055 NEXTTAB(usedlen) + availlen, df[i].avail, 1056 NEXTTAB(availlen) + proclen, df[i].proc); 1057 } 1058 1059 return 0; 1060 } 1061 1062 int 1063 snmpc_mibtree(int argc, char *argv[]) 1064 { 1065 struct oid *oid; 1066 struct ber_oid soid; 1067 char buf[BUFSIZ]; 1068 int i; 1069 1070 if (argc == 0) { 1071 for (oid = NULL; (oid = smi_foreach(oid)) != NULL;) { 1072 smi_oid2string(&oid->o_id, buf, sizeof(buf), 1073 oid_lookup); 1074 printf("%s\n", buf); 1075 } 1076 } else { 1077 for (i = 0; i < argc; i++) { 1078 if (smi_string2oid(argv[i], &soid) == -1) { 1079 warnx("%s: Unknown object identifier", argv[i]); 1080 continue; 1081 } 1082 smi_oid2string(&soid, buf, sizeof(buf), oid_lookup); 1083 printf("%s\n", buf); 1084 } 1085 } 1086 return 0; 1087 } 1088 1089 struct snmp_agent * 1090 snmpc_connect(char *host, char *port) 1091 { 1092 switch (version) { 1093 case SNMP_V1: 1094 case SNMP_V2C: 1095 return snmp_connect_v12(snmpc_parseagent(host, port), version, 1096 community); 1097 case SNMP_V3: 1098 return snmp_connect_v3(snmpc_parseagent(host, port), v3); 1099 } 1100 return NULL; 1101 } 1102 1103 int 1104 snmpc_print(struct ber_element *elm) 1105 { 1106 struct ber_oid oid; 1107 char oids[SNMP_MAX_OID_STRLEN]; 1108 char *value; 1109 1110 elm = elm->be_sub; 1111 if (ober_get_oid(elm, &oid) != 0) { 1112 errno = EINVAL; 1113 return 0; 1114 } 1115 1116 elm = elm->be_next; 1117 value = smi_print_element(&oid, elm, smi_print_hint, output_string, 1118 oid_lookup, utf8); 1119 if (value == NULL) 1120 return 0; 1121 1122 if (print_varbind_only) 1123 printf("%s\n", value); 1124 else if (print_equals) { 1125 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1126 printf("%s = %s\n", oids, value); 1127 } else { 1128 smi_oid2string(&oid, oids, sizeof(oids), oid_lookup); 1129 printf("%s %s\n", oids, value); 1130 } 1131 free(value); 1132 1133 return 1; 1134 } 1135 1136 __dead void 1137 snmpc_printerror(enum snmp_error error, struct ber_element *varbind, 1138 int index, const char *hint) 1139 { 1140 struct ber_oid hoid, vboid; 1141 char oids[SNMP_MAX_OID_STRLEN]; 1142 const char *oid = NULL; 1143 int i; 1144 1145 if (index >= 1) { 1146 /* Only print if the index is in the reply */ 1147 for (i = 1; varbind != NULL && i < index; 1148 varbind = varbind->be_next) 1149 i++; 1150 if (varbind != NULL && 1151 ober_get_oid(varbind->be_sub, &vboid) == 0) { 1152 /* If user and reply conform print user input */ 1153 if (hint != NULL && 1154 smi_string2oid(hint, &hoid) == 0 && 1155 ober_oid_cmp(&hoid, &vboid) == 0) 1156 oid = hint; 1157 else 1158 oid = smi_oid2string(&vboid, oids, 1159 sizeof(oids), oid_lookup); 1160 } 1161 } 1162 if (oid == NULL) 1163 oid = "?"; 1164 1165 switch (error) { 1166 case SNMP_ERROR_NONE: 1167 errx(1, "No error, how did I get here?"); 1168 case SNMP_ERROR_TOOBIG: 1169 errx(1, "Can't parse oid %s: Response too big", oid); 1170 case SNMP_ERROR_NOSUCHNAME: 1171 errx(1, "Can't parse oid %s: No such object", oid); 1172 case SNMP_ERROR_BADVALUE: 1173 errx(1, "Can't parse oid %s: Bad value", oid); 1174 case SNMP_ERROR_READONLY: 1175 errx(1, "Can't parse oid %s: Read only", oid); 1176 case SNMP_ERROR_GENERR: 1177 errx(1, "Can't parse oid %s: Generic error", oid); 1178 case SNMP_ERROR_NOACCESS: 1179 errx(1, "Can't parse oid %s: Access denied", oid); 1180 case SNMP_ERROR_WRONGTYPE: 1181 errx(1, "Can't parse oid %s: Wrong type", oid); 1182 case SNMP_ERROR_WRONGLENGTH: 1183 errx(1, "Can't parse oid %s: Wrong length", oid); 1184 case SNMP_ERROR_WRONGENC: 1185 errx(1, "Can't parse oid %s: Wrong encoding", oid); 1186 case SNMP_ERROR_WRONGVALUE: 1187 errx(1, "Can't parse oid %s: Wrong value", oid); 1188 case SNMP_ERROR_NOCREATION: 1189 errx(1, "Can't parse oid %s: Can't be created", oid); 1190 case SNMP_ERROR_INCONVALUE: 1191 errx(1, "Can't parse oid %s: Inconsistent value", oid); 1192 case SNMP_ERROR_RESUNAVAIL: 1193 errx(1, "Can't parse oid %s: Resource unavailable", oid); 1194 case SNMP_ERROR_COMMITFAILED: 1195 errx(1, "Can't parse oid %s: Commit failed", oid); 1196 case SNMP_ERROR_UNDOFAILED: 1197 errx(1, "Can't parse oid %s: Undo faild", oid); 1198 case SNMP_ERROR_AUTHERROR: 1199 errx(1, "Can't parse oid %s: Authorization error", oid); 1200 case SNMP_ERROR_NOTWRITABLE: 1201 errx(1, "Can't parse oid %s: Not writable", oid); 1202 case SNMP_ERROR_INCONNAME: 1203 errx(1, "Can't parse oid %s: Inconsistent name", oid); 1204 } 1205 errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error); 1206 } 1207 1208 int 1209 snmpc_parseagent(char *agent, char *defaultport) 1210 { 1211 struct addrinfo hints, *ai, *ai0 = NULL; 1212 struct sockaddr_un saddr; 1213 char *agentdup, *specifier, *hostname, *port = NULL; 1214 int error; 1215 int s; 1216 1217 if ((agentdup = specifier = strdup(agent)) == NULL) 1218 err(1, NULL); 1219 1220 bzero(&hints, sizeof(hints)); 1221 if ((hostname = strchr(specifier, ':')) != NULL) { 1222 *hostname++ = '\0'; 1223 if (strcasecmp(specifier, "udp") == 0) { 1224 hints.ai_family = AF_INET; 1225 hints.ai_socktype = SOCK_DGRAM; 1226 } else if (strcasecmp(specifier, "tcp") == 0) { 1227 hints.ai_family = AF_INET; 1228 hints.ai_socktype = SOCK_STREAM; 1229 } else if (strcasecmp(specifier, "udp6") == 0 || 1230 strcasecmp(specifier, "udpv6") == 0 || 1231 strcasecmp(specifier, "udpipv6") == 0) { 1232 hints.ai_family = AF_INET6; 1233 hints.ai_socktype = SOCK_DGRAM; 1234 } else if (strcasecmp(specifier, "tcp6") == 0 || 1235 strcasecmp(specifier, "tcpv6") == 0 || 1236 strcasecmp(specifier, "tcpipv6") == 0) { 1237 hints.ai_family = AF_INET6; 1238 hints.ai_socktype = SOCK_STREAM; 1239 } else if (strcasecmp(specifier, "unix") == 0) { 1240 hints.ai_family = AF_UNIX; 1241 hints.ai_addr = (struct sockaddr *)&saddr; 1242 hints.ai_addrlen = sizeof(saddr); 1243 saddr.sun_len = sizeof(saddr); 1244 saddr.sun_family = AF_UNIX; 1245 if (strlcpy(saddr.sun_path, hostname, 1246 sizeof(saddr.sun_path)) > sizeof(saddr.sun_path)) 1247 errx(1, "Hostname path too long"); 1248 ai = &hints; 1249 } else { 1250 *--hostname = ':'; 1251 hostname = specifier; 1252 } 1253 } else { 1254 hostname = specifier; 1255 } 1256 1257 if (hints.ai_family == AF_INET) { 1258 if ((port = strchr(hostname, ':')) != NULL) 1259 *port++ = '\0'; 1260 } else if (hints.ai_family == AF_INET6 || hints.ai_family == 0) { 1261 if (hostname[0] == '[') { 1262 hints.ai_family = AF_INET6; 1263 hostname++; 1264 if ((port = strchr(hostname, ']')) == NULL) 1265 errx(1, "invalid agent"); 1266 *port++ = '\0'; 1267 if (port[0] == ':') 1268 *port++ = '\0'; 1269 else if (port[0] == '\0') 1270 port = NULL; 1271 else 1272 errx(1, "invalid agent"); 1273 } else { 1274 if ((port = strrchr(hostname, ':')) != NULL) 1275 *port++ = '\0'; 1276 } 1277 } 1278 1279 if (hints.ai_family != AF_UNIX) { 1280 if (hints.ai_socktype == 0) 1281 hints.ai_socktype = SOCK_DGRAM; 1282 if (port == NULL) 1283 port = defaultport; 1284 error = getaddrinfo(hostname, port, &hints, &ai0); 1285 if (error) { 1286 if (error != EAI_NODATA || port == defaultport) 1287 errx(1, "%s", gai_strerror(error)); 1288 *--port = ':'; 1289 error = getaddrinfo(hostname, defaultport, &hints, 1290 &ai0); 1291 if (error) 1292 errx(1, "%s", gai_strerror(error)); 1293 } 1294 s = -1; 1295 for (ai = ai0; ai != NULL; ai = ai->ai_next) { 1296 if ((s = socket(ai->ai_family, ai->ai_socktype, 1297 ai->ai_protocol)) != -1 && 1298 connect(s, (struct sockaddr *)ai->ai_addr, 1299 ai->ai_addrlen) != -1) 1300 break; 1301 close(s); 1302 s = -1; 1303 } 1304 } else { 1305 s = socket(AF_UNIX, SOCK_STREAM, 0); 1306 if (connect(s, (struct sockaddr *)ai->ai_addr, 1307 ai->ai_addrlen) == -1) 1308 err(1, "Can't connect to %s", agent); 1309 } 1310 if (s == -1) 1311 err(1, "Can't connect to agent %s", agent); 1312 1313 1314 if (ai0 != NULL) 1315 freeaddrinfo(ai0); 1316 free(agentdup); 1317 return s; 1318 } 1319 1320 char * 1321 snmpc_hex2bin(char *hexstr, size_t *binlen) 1322 { 1323 char *decstr; 1324 1325 if (hexstr[0] == '0' && hexstr[1] == 'x') 1326 hexstr += 2; 1327 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1328 hexstr++; 1329 1330 if ((decstr = malloc((strlen(hexstr) / 2) + 1)) == NULL) 1331 return NULL; 1332 1333 for (*binlen = 0; hexstr[0] != '\0'; (*binlen)++) { 1334 hexstr[0] = toupper(hexstr[0]); 1335 hexstr[1] = toupper(hexstr[1]); 1336 if (hexstr[0] >= '0' && hexstr[0] <= '9') 1337 decstr[*binlen] = (hexstr[0] - '0') << 4; 1338 else if (hexstr[0] >= 'A' && hexstr[0] <= 'F') 1339 decstr[*binlen] = ((hexstr[0] - 'A') + 10) << 4; 1340 else 1341 goto fail; 1342 if (hexstr[1] >= '0' && hexstr[1] <= '9') 1343 decstr[*binlen] |= (hexstr[1] - '0'); 1344 else if (hexstr[1] >= 'A' && hexstr[1] <= 'F') 1345 decstr[*binlen] |= (hexstr[1] - 'A') + 10; 1346 else 1347 goto fail; 1348 1349 hexstr += 2; 1350 while (hexstr[0] == ' ' || hexstr[0] == '\t') 1351 hexstr++; 1352 } 1353 1354 return decstr; 1355 fail: 1356 errno = EINVAL; 1357 free(decstr); 1358 return NULL; 1359 } 1360 1361 ssize_t 1362 snmpc_mbswidth(char *str) 1363 { 1364 wchar_t wc; 1365 size_t width = 0; 1366 size_t i; 1367 int len; 1368 1369 for (i = 0; (len = mbtowc(&wc, &(str[i]), MB_CUR_MAX)) != 0; i += len) { 1370 if (len == -1) { 1371 mbtowc(NULL, NULL, MB_CUR_MAX); 1372 return -1; 1373 } 1374 width += wcwidth(wc); 1375 } 1376 return width; 1377 } 1378 1379 struct ber_element * 1380 snmpc_varbindparse(int argc, char *argv[]) 1381 { 1382 struct ber_oid oid, oidval; 1383 struct in_addr addr4; 1384 char *addr = (char *)&addr4; 1385 char *str = NULL, *tmpstr, *endstr; 1386 const char *errstr = NULL; 1387 struct ber_element *varbind = NULL, *vblist = NULL; 1388 int i, ret; 1389 size_t strl, byte; 1390 long long lval; 1391 1392 if (argc % 3 != 0) 1393 usage(); 1394 for (i = 0; i < argc; i += 3) { 1395 if (smi_string2oid(argv[i], &oid) == -1) 1396 errx(1, "Invalid oid: %s\n", argv[i]); 1397 switch (argv[i + 1][0]) { 1398 case 'a': 1399 ret = inet_pton(AF_INET, argv[i + 2], &addr4); 1400 if (ret == -1) 1401 err(1, "inet_pton"); 1402 if (ret == 0) 1403 errx(1, "%s: Bad value notation (%s)", argv[i], 1404 argv[i + 2]); 1405 if ((varbind = ober_printf_elements(varbind, "{Oxt}", 1406 &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION, 1407 SNMP_T_IPADDR)) == NULL) 1408 err(1, "ober_printf_elements"); 1409 break; 1410 case 'b': 1411 tmpstr = argv[i + 2]; 1412 strl = 0; 1413 do { 1414 lval = strtoll(tmpstr, &endstr, 10); 1415 if (endstr[0] != ' ' && endstr[0] != '\t' && 1416 endstr[0] != ',' && endstr[0] != '\0') 1417 errx(1, "%s: Bad value notation (%s)", 1418 argv[i], argv[i + 2]); 1419 if (tmpstr == endstr) { 1420 tmpstr++; 1421 continue; 1422 } 1423 if (lval < 0) 1424 errx(1, "%s: Bad value notation (%s)", 1425 argv[i], argv[i + 2]); 1426 byte = lval / 8; 1427 if (byte >= strl) { 1428 if ((str = recallocarray(str, strl, 1429 byte + 1, 1)) == NULL) 1430 err(1, "malloc"); 1431 strl = byte + 1; 1432 } 1433 str[byte] |= 0x80 >> (lval % 8); 1434 tmpstr = endstr + 1; 1435 } while (endstr[0] != '\0'); 1436 /* 1437 * RFC3416 Section 2.5 1438 * A BITS value is encoded as an OCTET STRING 1439 */ 1440 goto pastestring; 1441 case 'c': 1442 lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX, 1443 &errstr); 1444 if (errstr != NULL) 1445 errx(1, "%s: Bad value notation (%s)", argv[i], 1446 argv[i + 2]); 1447 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1448 &oid, lval, BER_CLASS_APPLICATION, 1449 SNMP_T_COUNTER32)) == NULL) 1450 err(1, "ober_printf_elements"); 1451 break; 1452 case 'd': 1453 /* String always shrinks */ 1454 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1455 err(1, "malloc"); 1456 tmpstr = argv[i + 2]; 1457 strl = 0; 1458 do { 1459 lval = strtoll(tmpstr, &endstr, 10); 1460 if (endstr[0] != ' ' && endstr[0] != '\t' && 1461 endstr[0] != '\0') 1462 errx(1, "%s: Bad value notation (%s)", 1463 argv[i], argv[i + 2]); 1464 if (tmpstr == endstr) { 1465 tmpstr++; 1466 continue; 1467 } 1468 if (lval < 0 || lval > 0xff) 1469 errx(1, "%s: Bad value notation (%s)", 1470 argv[i], argv[i + 2]); 1471 str[strl++] = (unsigned char) lval; 1472 tmpstr = endstr + 1; 1473 } while (endstr[0] != '\0'); 1474 goto pastestring; 1475 case 'u': 1476 case 'i': 1477 lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX, 1478 &errstr); 1479 if (errstr != NULL) 1480 errx(1, "%s: Bad value notation (%s)", argv[i], 1481 argv[i + 2]); 1482 if ((varbind = ober_printf_elements(varbind, "{Oi}", 1483 &oid, lval)) == NULL) 1484 err(1, "ober_printf_elements"); 1485 break; 1486 case 'n': 1487 if ((varbind = ober_printf_elements(varbind, "{O0}", 1488 &oid)) == NULL) 1489 err(1, "ober_printf_elements"); 1490 break; 1491 case 'o': 1492 if (smi_string2oid(argv[i + 2], &oidval) == -1) 1493 errx(1, "%s: Unknown Object Identifier (Sub-id " 1494 "not found: (top) -> %s)", argv[i], 1495 argv[i + 2]); 1496 if ((varbind = ober_printf_elements(varbind, "{OO}", 1497 &oid, &oidval)) == NULL) 1498 err(1, "ober_printf_elements"); 1499 break; 1500 case 's': 1501 if ((str = strdup(argv[i + 2])) == NULL) 1502 err(1, NULL); 1503 strl = strlen(argv[i + 2]); 1504 pastestring: 1505 if ((varbind = ober_printf_elements(varbind, "{Ox}", 1506 &oid, str, strl)) == NULL) 1507 err(1, "ober_printf_elements"); 1508 free(str); 1509 break; 1510 case 't': 1511 lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX, 1512 &errstr); 1513 if (errstr != NULL) 1514 errx(1, "%s: Bad value notation (%s)", argv[i], 1515 argv[i + 2]); 1516 if ((varbind = ober_printf_elements(varbind, "{Oit}", 1517 &oid, lval, BER_CLASS_APPLICATION, 1518 SNMP_T_TIMETICKS)) == NULL) 1519 err(1, "ober_printf_elements"); 1520 break; 1521 case 'x': 1522 /* String always shrinks */ 1523 if ((str = malloc(strlen(argv[i + 2]))) == NULL) 1524 err(1, "malloc"); 1525 tmpstr = argv[i + 2]; 1526 strl = 0; 1527 do { 1528 lval = strtoll(tmpstr, &endstr, 16); 1529 if (endstr[0] != ' ' && endstr[0] != '\t' && 1530 endstr[0] != '\0') 1531 errx(1, "%s: Bad value notation (%s)", 1532 argv[i], argv[i + 2]); 1533 if (tmpstr == endstr) { 1534 tmpstr++; 1535 continue; 1536 } 1537 if (lval < 0 || lval > 0xff) 1538 errx(1, "%s: Bad value notation (%s)", 1539 argv[i], argv[i + 2]); 1540 str[strl++] = (unsigned char) lval; 1541 tmpstr = endstr + 1; 1542 } while (endstr[0] != '\0'); 1543 goto pastestring; 1544 default: 1545 usage(); 1546 } 1547 if (vblist == NULL) 1548 vblist = varbind; 1549 } 1550 1551 return vblist; 1552 } 1553 1554 __dead void 1555 usage(void) 1556 { 1557 size_t i; 1558 1559 if (snmp_app != NULL) { 1560 fprintf(stderr, "usage: snmp %s%s%s\n", 1561 snmp_app->name, 1562 snmp_app->usecommonopt ? 1563 " [-A authpass] [-a digest] [-c community] [-e secengineid]\n" 1564 " [-E ctxengineid] [-K localpriv] [-k localauth] [-l seclevel]\n" 1565 " [-n ctxname] [-O afnqvxSQ] [-r retries] [-t timeout] [-u user]\n" 1566 " [-v version] [-X privpass] [-x cipher] [-Z boots,time]\n" 1567 " " : "", 1568 snmp_app->usage == NULL ? "" : snmp_app->usage); 1569 exit(1); 1570 } 1571 for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) { 1572 if (i == 0) 1573 fprintf(stderr, "usage: "); 1574 else 1575 fprintf(stderr, " "); 1576 fprintf(stderr, "snmp %s%s %s\n", 1577 snmp_apps[i].name, 1578 snmp_apps[i].usecommonopt ? 1579 " [options]" : "", 1580 snmp_apps[i].usage ? snmp_apps[i].usage : ""); 1581 } 1582 exit(1); 1583 } 1584