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