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