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