Annotation of src/usr.bin/snmp/snmpc.c, Revision 1.3
1.3 ! deraadt 1: /* $OpenBSD: snmpc.c,v 1.2 2019/08/11 14:41:20 deraadt 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>
26:
27: #include <ber.h>
28: #include <err.h>
29: #include <errno.h>
30: #include <netdb.h>
31: #include <poll.h>
32: #include <stdio.h>
33: #include <stdlib.h>
34: #include <stdint.h>
35: #include <string.h>
36: #include <time.h>
37: #include <unistd.h>
38:
39: #include "smi.h"
40: #include "snmp.h"
41:
42: #define GETOPT_COMMON "c:r:t:v:O:"
43:
44: int snmpc_get(int, char *[]);
45: int snmpc_walk(int, char *[]);
46: int snmpc_trap(int, char *[]);
47: int snmpc_mibtree(int, char *[]);
48: int snmpc_parseagent(char *, char *);
49: int snmpc_print(struct ber_element *);
50: __dead void snmpc_printerror(enum snmp_error, char *);
51: void usage(void);
52:
53: struct snmp_app {
54: const char *name;
55: const int usecommonopt;
56: const char *optstring;
57: const char *usage;
1.2 deraadt 58: int (*exec)(int, char *[]);
1.1 martijn 59: };
60:
61: struct snmp_app snmp_apps[] = {
1.2 deraadt 62: { "get", 1, NULL, "agent oid ...", snmpc_get },
63: { "getnext", 1, NULL, "agent oid ...", snmpc_get },
64: { "walk", 1, "C:", "[-C cIipt] [-C E OID] agent [oid]", snmpc_walk },
65: { "bulkget", 1, "C:", "[-C n<nonrep>r<maxrep>] agent oid ...", snmpc_get },
66: { "bulkwalk", 1, "C:", "[-C cipn<nonrep>r<maxrep>] agent [oid]", snmpc_walk },
67: { "trap", 1, NULL, "agent uptime oid [oid type value] ...", snmpc_trap },
68: { "mibtree", 0, "O:", "[-O fnS]", snmpc_mibtree }
1.1 martijn 69: };
70: struct snmp_app *snmp_app = NULL;
71:
72: char *community = "public";
73: char *mib = "mib_2";
74: int retries = 5;
75: int timeout = 1;
76: int version = SNMP_V2C;
77: int print_equals = 1;
78: int print_varbind_only = 0;
79: int print_summary = 0;
80: int print_time = 0;
81: int walk_check_increase = 1;
82: int walk_fallback_oid = 1;
83: int walk_include_oid = 0;
84: int smi_print_hint = 1;
85: int non_repeaters = 0;
86: int max_repetitions = 10;
87: struct ber_oid walk_end = {{0}, 0};
88: enum smi_oid_lookup oid_lookup = smi_oidl_short;
89: enum smi_output_string output_string = smi_os_default;
90:
91: int
92: main(int argc, char *argv[])
93: {
94: char optstr[BUFSIZ];
95: const char *errstr;
96: char *strtolp;
97: int ch;
98: size_t i;
99:
100: if (pledge("stdio inet dns", NULL) == -1)
101: err(1, "pledge");
1.2 deraadt 102:
1.1 martijn 103: if (argc <= 1)
104: usage();
105:
106: for (i = 0; i < sizeof(snmp_apps)/sizeof(*snmp_apps); i++) {
107: if (strcmp(snmp_apps[i].name, argv[1]) == 0) {
108: snmp_app = &snmp_apps[i];
109: if (snmp_app->optstring != NULL) {
110: if (strlcpy(optstr, snmp_app->optstring,
111: sizeof(optstr)) > sizeof(optstr))
112: errx(1, "strlcat");
113: }
114: break;
115: }
116: }
117: if (snmp_app == NULL)
118: usage();
119:
120: if (snmp_app->usecommonopt) {
121: if (strlcat(optstr, GETOPT_COMMON, sizeof(optstr)) >
122: sizeof(optstr))
123: errx(1, "strlcpy");
124: }
125:
126: argc--;
127: argv++;
128:
129: smi_init();
130:
131: while ((ch = getopt(argc, argv, optstr)) != -1) {
132: switch (ch) {
133: case 'c':
134: community = optarg;
135: break;
136: case 'r':
137: if ((retries = strtonum(optarg, 0, INT_MAX,
138: &errstr)) == 0) {
139: if (errstr != NULL)
140: errx(1, "-r: %s argument", errstr);
141: }
142: break;
143: case 't':
144: if ((timeout = strtonum(optarg, 1, INT_MAX,
145: &errstr)) == 0) {
146: if (errstr != NULL)
147: errx(1, "-t: %s argument", errstr);
148: }
149: break;
150: case 'v':
151: if (strcmp(optarg, "1") == 0)
152: version = SNMP_V1;
153: else if (strcmp(optarg, "2c") == 0)
154: version = SNMP_V2C;
155: else
156: errc(1, EINVAL, "-v");
157: break;
158: case 'C':
159: for (i = 0; i < strlen(optarg); i++) {
160: switch (optarg[i]) {
161: case 'c':
162: if (strcmp(snmp_app->name, "walk") &&
163: strcmp(snmp_app->name, "bulkwalk"))
164: usage();
165: walk_check_increase = 0;
166: break;
167: case 'i':
168: if (strcmp(snmp_app->name, "walk") &&
169: strcmp(snmp_app->name, "bulkwalk"))
170: usage();
171: walk_include_oid = 1;
172: break;
173: case 'n':
174: if (strcmp(snmp_app->name, "bulkget") &&
175: strcmp(snmp_app->name, "bulkwalk"))
176: usage();
177: errno = 0;
178: non_repeaters = strtol(&optarg[i + 1],
179: &strtolp, 10);
180: if (non_repeaters < 0 ||
181: errno == ERANGE) {
182: if (non_repeaters < 0)
183: errx(1, "%s%s",
184: "-Cn: too small ",
185: "argument");
186: else
187: errx(1, "%s%s",
188: "-Cn: too large",
189: "argument");
190: } else if (&optarg[i + 1] == strtolp)
191: errx(1, "-Cn invalid argument");
192: i = strtolp - optarg - 1;
193: break;
194: case 'p':
195: if (strcmp(snmp_app->name, "walk") &&
196: strcmp(snmp_app->name, "bulkwalk"))
197: usage();
198: print_summary = 1;
199: break;
200: case 'r':
201: if (strcmp(snmp_app->name, "bulkget") &&
202: strcmp(snmp_app->name, "bulkwalk"))
203: usage();
204: errno = 0;
205: max_repetitions = strtol(&optarg[i + 1],
206: &strtolp, 10);
207: if (max_repetitions < 0 ||
208: errno == ERANGE) {
209: if (max_repetitions < 0)
210: errx(1, "%s%s",
211: "-Cr: too small ",
212: "argument");
213: else
214: errx(1, "%s%s",
215: "-Cr: too large",
216: "argument");
217: } else if (&optarg[i + 1] == strtolp)
218: errx(1, "-Cr invalid argument");
219: i = strtolp - optarg - 1;
220: break;
221: case 't':
222: if (strcmp(snmp_app->name, "walk"))
223: usage();
224: print_time = 1;
225: break;
226: case 'E':
227: if (strcmp(snmp_app->name, "walk"))
228: usage();
229: if (smi_string2oid(argv[optind],
230: &walk_end) != 0)
231: errx(1, "%s: %s",
232: "Unknown Object Identifier",
233: argv[optind]);
234: optind++;
235: continue;
236: case 'I':
237: if (strcmp(snmp_app->name, "walk"))
238: usage();
239: walk_fallback_oid = 0;
240: break;
241: default:
242: usage();
243: }
244: if (optarg[i] == 'E')
245: break;
246: }
247: break;
248: case 'O':
249: for (i = 0; i < strlen(optarg); i++) {
250: if (strcmp(snmp_app->name, "mibtree") == 0 &&
251: optarg[i] != 'f' && optarg[i] != 'n' &&
252: optarg[i] != 'S')
253: usage();
254: switch (optarg[i]) {
255: case 'a':
256: output_string = smi_os_ascii;
257: break;
258: case 'f':
259: oid_lookup = smi_oidl_full;
260: break;
261: case 'n':
262: oid_lookup = smi_oidl_numeric;
263: break;
264: case 'q':
265: print_equals = 0;
266: smi_print_hint = 0;
267: break;
268: case 'v':
1.2 deraadt 269: print_varbind_only = 1;
1.1 martijn 270: break;
271: case 'x':
272: output_string = smi_os_hex;
273: break;
274: case 'S':
275: oid_lookup = smi_oidl_short;
276: break;
277: case 'Q':
278: smi_print_hint = 0;
279: break;
280: default:
281: usage();
282: }
283: }
284: break;
285: default:
286: usage();
287: }
288: }
289: argc -= optind;
290: argv += optind;
291:
292: return snmp_app->exec(argc, argv);
293: }
294:
295: int
296: snmpc_get(int argc, char *argv[])
297: {
298: struct ber_oid *oid;
299: struct ber_element *pdu, *varbind;
300: struct snmp_agent *agent;
301: int errorstatus, errorindex;
302: int i;
303:
304: if (argc < 2)
305: usage();
306:
307: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version,
308: community);
309: if (agent == NULL)
310: err(1, "%s", snmp_app->name);
311: agent->timeout = timeout;
312: agent->retries = retries;
313:
314: if (pledge("stdio", NULL) == -1)
315: err(1, "pledge");
316: argc--;
317: argv++;
318:
319: oid = reallocarray(NULL, argc, sizeof(*oid));
1.3 ! deraadt 320: if (oid == NULL)
! 321: err(1, "malloc");
1.1 martijn 322: for (i = 0; i < argc; i++) {
323: if (smi_string2oid(argv[i], &oid[i]) == -1)
324: errx(1, "%s: Unknown object identifier", argv[0]);
325: }
326: if (strcmp(snmp_app->name, "getnext") == 0) {
327: if ((pdu = snmp_getnext(agent, oid, argc)) == NULL)
328: err(1, "getnext");
329: } else if (strcmp(snmp_app->name, "bulkget") == 0) {
330: if (version < SNMP_V2C)
331: errx(1, "Cannot send V2 PDU on V1 session");
332: if (non_repeaters > argc)
333: errx(1, "need more objects than -Cn<num>");
334: if ((pdu = snmp_getbulk(agent, oid, argc, non_repeaters,
335: max_repetitions)) == NULL)
336: err(1, "bulkget");
337: } else {
338: if ((pdu = snmp_get(agent, oid, argc)) == NULL)
339: err(1, "get");
340: }
341:
342: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus, &errorindex,
343: &varbind);
344: if (errorstatus != 0)
345: snmpc_printerror((enum snmp_error) errorstatus,
346: argv[errorindex]);
347:
348: for (; varbind != NULL; varbind = varbind->be_next) {
349: if (!snmpc_print(varbind))
350: err(1, "Can't print response");
351: }
352: ber_free_elements(pdu);
353: snmp_free_agent(agent);
354: return 0;
355: }
356:
357: int
358: snmpc_walk(int argc, char *argv[])
359: {
360: struct ber_oid oid, loid, noid;
361: struct ber_element *pdu, *varbind, *value;
362: struct timespec start, finish;
363: struct snmp_agent *agent;
364: const char *oids;
365: char oidstr[SNMP_MAX_OID_STRLEN];
366: int n = 0, prev_cmp;
367: int errorstatus, errorindex;
368:
369: if (strcmp(snmp_app->name, "bulkwalk") == 0 && version < SNMP_V2C)
370: errx(1, "Cannot send V2 PDU on V1 session");
371: if (argc < 1 || argc > 2)
372: usage();
373: oids = argc == 1 ? mib : argv[1];
374:
375: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "161"), version, community);
376: if (agent == NULL)
377: err(1, "%s", snmp_app->name);
378: agent->timeout = timeout;
379: agent->retries = retries;
380: if (pledge("stdio", NULL) == -1)
381: err(1, "pledge");
382:
383: if (smi_string2oid(oids, &oid) == -1)
384: errx(1, "%s: Unknown object identifier", oids);
385: bcopy(&oid, &noid, sizeof(noid));
386: if (print_time)
387: clock_gettime(CLOCK_MONOTONIC, &start);
388:
389: if (walk_include_oid) {
390: if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
391: err(1, "%s", snmp_app->name);
392:
393: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
394: &errorindex, &varbind);
395: if (errorstatus != 0)
396: snmpc_printerror((enum snmp_error) errorstatus,
397: argv[errorindex]);
398:
399: if (!snmpc_print(varbind))
400: err(1, "Can't print response");
401: ber_free_element(pdu);
402: n++;
403: }
404: while (1) {
405: bcopy(&noid, &loid, sizeof(loid));
406: if (strcmp(snmp_app->name, "bulkwalk") == 0) {
407: if ((pdu = snmp_getbulk(agent, &noid, 1,
408: non_repeaters, max_repetitions)) == NULL)
409: err(1, "bulkwalk");
410: } else {
411: if ((pdu = snmp_getnext(agent, &noid, 1)) == NULL)
412: err(1, "walk");
413: }
414:
415: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
416: &errorindex, &varbind);
417: if (errorstatus != 0) {
418: smi_oid2string(&noid, oidstr, sizeof(oidstr),
419: oid_lookup);
420: snmpc_printerror((enum snmp_error) errorstatus, oidstr);
421: }
422:
1.2 deraadt 423: for (; varbind != NULL; varbind = varbind->be_next) {
1.1 martijn 424: (void) ber_scanf_elements(varbind, "{oe}", &noid,
425: &value);
426: if (value->be_class == BER_CLASS_CONTEXT &&
427: value->be_type == BER_TYPE_EOC)
428: break;
429: prev_cmp = ber_oid_cmp(&loid, &noid);
430: if (walk_check_increase && prev_cmp == -1)
431: errx(1, "OID not increasing");
432: if (prev_cmp == 0 || ber_oid_cmp(&oid, &noid) != 2)
433: break;
434: if (walk_end.bo_n != 0 &&
435: ber_oid_cmp(&walk_end, &noid) != -1)
436: break;
437:
438: if (!snmpc_print(varbind))
439: err(1, "Can't print response");
440: n++;
441: }
442: ber_free_elements(pdu);
443: if (varbind != NULL)
444: break;
445: }
446: if (walk_fallback_oid && n == 0) {
447: if ((pdu = snmp_get(agent, &oid, 1)) == NULL)
448: err(1, "%s", snmp_app->name);
449:
450: (void) ber_scanf_elements(pdu, "{Sdd{e", &errorstatus,
451: &errorindex, &varbind);
452: if (errorstatus != 0)
453: snmpc_printerror((enum snmp_error) errorstatus,
454: argv[errorindex]);
455:
456: if (!snmpc_print(varbind))
457: err(1, "Can't print response");
458: ber_free_element(pdu);
459: n++;
460: }
461: if (print_time)
462: clock_gettime(CLOCK_MONOTONIC, &finish);
463: if (print_summary)
464: printf("Variables found: %d\n", n);
465: if (print_time) {
466: if ((finish.tv_nsec -= start.tv_nsec) < 0) {
467: finish.tv_sec -= 1;
468: finish.tv_nsec += 1000000000;
469: }
470: finish.tv_sec -= start.tv_sec;
471: fprintf(stderr, "Total traversal time: %lld.%09ld seconds\n",
472: finish.tv_sec, finish.tv_nsec);
473: }
474: snmp_free_agent(agent);
475: return 0;
476: }
477:
478: int
479: snmpc_trap(int argc, char *argv[])
480: {
481: struct snmp_agent *agent;
482: struct timespec ts;
483: struct ber_oid trapoid, oid, oidval;
484: struct in_addr addr4;
485: char *addr = (char *)&addr4;
486: char *str = NULL, *tmpstr, *endstr;
487: const char *errstr = NULL;
488: struct ber_element *varbind = NULL, *pdu = NULL;
489: long long lval;
490: int i, ret;
491: size_t strl, byte;
492:
493: if (argc < 3 || argc % 3 != 0)
494: usage();
495: if (version == SNMP_V1)
496: errx(1, "trap is not supported for snmp v1");
497:
498: agent = snmp_connect_v12(snmpc_parseagent(argv[0], "162"),
499: version, community);
500: if (agent == NULL)
501: err(1, "%s", snmp_app->name);
502:
503: if (pledge("stdio", NULL) == -1)
504: err(1, "pledge");
505:
506: if (argv[1][0] == '\0') {
507: if (clock_gettime(CLOCK_UPTIME, &ts) == -1)
508: err(1, "clock_gettime");
509: } else {
510: lval = strtonum(argv[1], 0, LLONG_MAX, &errstr);
511: if (errstr != NULL)
512: errx(1, "Bad value notation (%s)", argv[1]);
513: ts.tv_sec = lval / 100;
514: ts.tv_nsec = (lval % 100) * 10000000;
515: }
516: if (smi_string2oid(argv[2], &trapoid) == -1)
517: errx(1, "Invalid oid: %s\n", argv[2]);
518:
519: argc -= 3;
520: argv += 3;
521: for (i = 0; i < argc; i += 3) {
522: if (smi_string2oid(argv[i], &oid) == -1)
523: errx(1, "Invalid oid: %s\n", argv[i]);
524: switch (argv[i + 1][0]) {
525: case 'a':
526: ret = inet_pton(AF_INET, argv[i + 2], &addr4);
527: if (ret == -1)
528: err(1, "inet_pton");
529: if (ret == 0)
530: errx(1, "%s: Bad value notation (%s)", argv[i],
531: argv[i + 2]);
532: if ((varbind = ber_printf_elements(varbind, "{Oxt}",
533: &oid, addr, sizeof(addr4), BER_CLASS_APPLICATION,
534: SNMP_T_IPADDR)) == NULL)
535: err(1, "ber_printf_elements");
536: break;
537: case 'b':
538: tmpstr = argv[i + 2];
539: strl = 0;
540: do {
541: lval = strtoll(tmpstr, &endstr, 10);
542: if (endstr[0] != ' ' && endstr[0] != '\t' &&
543: endstr[0] != ',' && endstr[0] != '\0')
544: errx(1, "%s: Bad value notation (%s)",
545: argv[i], argv[i + 2]);
546: if (tmpstr == endstr) {
547: tmpstr++;
548: continue;
549: }
550: if (lval < 0)
551: errx(1, "%s: Bad value notation (%s)",
552: argv[i], argv[i + 2]);
553: byte = lval / 8;
554: if (byte >= strl) {
555: if ((str = recallocarray(str, strl,
556: byte + 1, 1)) == NULL)
557: err(1, NULL);
558: strl = byte + 1;
559: }
560: str[byte] |= 0x80 >> (lval % 8);
561: tmpstr = endstr + 1;
562: } while (endstr[0] != '\0');
563: /*
564: * RFC3416 Section 2.5
565: * A BITS value is encoded as an OCTET STRING
566: */
567: goto pastestring;
568: case 'c':
569: lval = strtonum(argv[i + 2], INT32_MIN, INT32_MAX,
570: &errstr);
571: if (errstr != NULL)
572: errx(1, "%s: Bad value notation (%s)", argv[i],
573: argv[i + 2]);
574: if ((varbind = ber_printf_elements(varbind, "{Oit}",
575: &oid, lval, BER_CLASS_APPLICATION,
576: SNMP_T_COUNTER32)) == NULL)
577: err(1, "ber_printf_elements");
578: break;
579: case 'd':
580: /* String always shrinks */
581: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
582: err(1, NULL);
583: tmpstr = argv[i + 2];
584: strl = 0;
585: do {
586: lval = strtoll(tmpstr, &endstr, 10);
587: if (endstr[0] != ' ' && endstr[0] != '\t' &&
588: endstr[0] != '\0')
589: errx(1, "%s: Bad value notation (%s)",
590: argv[i], argv[i + 2]);
591: if (tmpstr == endstr) {
592: tmpstr++;
593: continue;
594: }
595: if (lval < 0 || lval > 0xff)
596: errx(1, "%s: Bad value notation (%s)",
597: argv[i], argv[i + 2]);
598: str[strl++] = (unsigned char) lval;
599: tmpstr = endstr + 1;
600: } while (endstr[0] != '\0');
601: goto pastestring;
602: case 'u':
603: case 'i':
604: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
605: &errstr);
606: if (errstr != NULL)
607: errx(1, "%s: Bad value notation (%s)", argv[i],
608: argv[i + 2]);
609: if ((varbind = ber_printf_elements(varbind, "{Oi}",
610: &oid, lval)) == NULL)
611: err(1, "ber_printf_elements");
612: break;
613: case 'n':
614: if ((varbind = ber_printf_elements(varbind, "{O0}",
615: &oid)) == NULL)
616: err(1, "ber_printf_elements");
617: break;
618: case 'o':
619: if (smi_string2oid(argv[i + 2], &oidval) == -1)
620: errx(1, "%s: Unknown Object Identifier (Sub-id "
621: "not found: (top) -> %s)", argv[i],
622: argv[i + 2]);
623: if ((varbind = ber_printf_elements(varbind, "{OO}",
624: &oid, &oidval)) == NULL)
625: err(1, "ber_printf_elements");
626: break;
627: case 's':
628: if ((str = strdup(argv[i + 2])) == NULL)
629: err(1, NULL);
630: strl = strlen(argv[i + 2]);
631: pastestring:
632: if ((varbind = ber_printf_elements(varbind, "{Ox}",
633: &oid, str, strl)) == NULL)
634: err(1, "ber_printf_elements");
635: free(str);
636: break;
637: case 't':
638: lval = strtonum(argv[i + 2], LLONG_MIN, LLONG_MAX,
639: &errstr);
640: if (errstr != NULL)
641: errx(1, "%s: Bad value notation (%s)", argv[i],
642: argv[i + 2]);
643: if ((varbind = ber_printf_elements(varbind, "{Oit}",
644: &oid, lval, BER_CLASS_APPLICATION,
645: SNMP_T_TIMETICKS)) == NULL)
646: err(1, "ber_printf_elements");
647: break;
648: case 'x':
649: /* String always shrinks */
650: if ((str = malloc(strlen(argv[i + 2]))) == NULL)
651: err(1, NULL);
652: tmpstr = argv[i + 2];
653: strl = 0;
654: do {
655: lval = strtoll(tmpstr, &endstr, 16);
656: if (endstr[0] != ' ' && endstr[0] != '\t' &&
657: endstr[0] != '\0')
658: errx(1, "%s: Bad value notation (%s)",
659: argv[i], argv[i + 2]);
660: if (tmpstr == endstr) {
661: tmpstr++;
662: continue;
663: }
664: if (lval < 0 || lval > 0xff)
665: errx(1, "%s: Bad value notation (%s)",
666: argv[i], argv[i + 2]);
667: str[strl++] = (unsigned char) lval;
668: tmpstr = endstr + 1;
669: } while (endstr[0] != '\0');
670: goto pastestring;
671: default:
672: usage();
673: }
674: if (pdu == NULL)
675: pdu = varbind;
676: }
677:
678: snmp_trap(agent, &ts, &trapoid, pdu);
679:
680: return 0;
681: }
682:
683: int
684: snmpc_mibtree(int argc, char *argv[])
685: {
686: struct oid *oid;
687: char buf[BUFSIZ];
688:
689: for (oid = NULL; (oid = smi_foreach(oid, 0)) != NULL;) {
690: smi_oid2string(&oid->o_id, buf, sizeof(buf), oid_lookup);
691: printf("%s\n", buf);
692: }
693: return 0;
694: }
695:
696: int
697: snmpc_print(struct ber_element *elm)
698: {
699: struct ber_oid oid;
700: char oids[SNMP_MAX_OID_STRLEN];
701: char *value;
702:
703: elm = elm->be_sub;
704: if (ber_get_oid(elm, &oid) != 0) {
705: errno = EINVAL;
706: return 0;
707: }
708:
709: elm = elm->be_next;
710: value = smi_print_element(elm, smi_print_hint, output_string, oid_lookup);
711: if (value == NULL)
712: return 0;
713:
714: if (print_varbind_only)
715: printf("%s\n", value);
716: else if (print_equals) {
717: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
718: printf("%s = %s\n", oids, value);
719: } else {
720: smi_oid2string(&oid, oids, sizeof(oids), oid_lookup);
721: printf("%s %s\n", oids, value);
722: }
723: free(value);
1.2 deraadt 724:
1.1 martijn 725: return 1;
726: }
727:
728: __dead void
729: snmpc_printerror(enum snmp_error error, char *oid)
730: {
1.2 deraadt 731: switch (error) {
1.1 martijn 732: case SNMP_ERROR_NONE:
733: errx(1, "No error, how did I get here?");
734: case SNMP_ERROR_TOOBIG:
735: errx(1, "Can't parse oid %s: Response too big", oid);
736: case SNMP_ERROR_NOSUCHNAME:
737: errx(1, "Can't parse oid %s: No such object", oid);
738: case SNMP_ERROR_BADVALUE:
739: errx(1, "Can't parse oid %s: Bad value", oid);
740: case SNMP_ERROR_READONLY:
741: errx(1, "Can't parse oid %s: Read only", oid);
742: case SNMP_ERROR_GENERR:
743: errx(1, "Can't parse oid %s: Generic error", oid);
744: case SNMP_ERROR_NOACCESS:
745: errx(1, "Can't parse oid %s: Access denied", oid);
746: case SNMP_ERROR_WRONGTYPE:
747: errx(1, "Can't parse oid %s: Wrong type", oid);
748: case SNMP_ERROR_WRONGLENGTH:
749: errx(1, "Can't parse oid %s: Wrong length", oid);
750: case SNMP_ERROR_WRONGENC:
751: errx(1, "Can't parse oid %s: Wrong encoding", oid);
752: case SNMP_ERROR_WRONGVALUE:
753: errx(1, "Can't parse oid %s: Wrong value", oid);
754: case SNMP_ERROR_NOCREATION:
755: errx(1, "Can't parse oid %s: Can't be created", oid);
756: case SNMP_ERROR_INCONVALUE:
757: errx(1, "Can't parse oid %s: Inconsistent value", oid);
758: case SNMP_ERROR_RESUNAVAIL:
759: errx(1, "Can't parse oid %s: Resource unavailable", oid);
760: case SNMP_ERROR_COMMITFAILED:
761: errx(1, "Can't parse oid %s: Commit failed", oid);
762: case SNMP_ERROR_UNDOFAILED:
763: errx(1, "Can't parse oid %s: Undo faild", oid);
764: case SNMP_ERROR_AUTHERROR:
765: errx(1, "Can't parse oid %s: Authorization error", oid);
766: case SNMP_ERROR_NOTWRITABLE:
767: errx(1, "Can't parse oid %s: Not writable", oid);
768: case SNMP_ERROR_INCONNAME:
769: errx(1, "Can't parse oid %s: Inconsistent name", oid);
770: }
771: errx(1, "Can't parse oid %s: Unknown error (%d)", oid, error);
772: }
773:
774: int
775: snmpc_parseagent(char *agent, char *defaultport)
776: {
777: struct addrinfo hints, *ai, *ai0 = NULL;
778: struct sockaddr_un saddr;
779: char *agentdup, *specifier, *hostname, *port = NULL;
780: int error;
781: int s;
782:
783: if ((agentdup = specifier = strdup(agent)) == NULL)
784: err(1, NULL);
785:
786: bzero(&hints, sizeof(hints));
787: if ((hostname = strchr(specifier, ':')) != NULL) {
788: *hostname++ = '\0';
789: if (strcasecmp(specifier, "udp") == 0) {
790: hints.ai_family = AF_INET;
791: hints.ai_socktype = SOCK_DGRAM;
792: } else if (strcasecmp(specifier, "tcp") == 0) {
793: hints.ai_family = AF_INET;
794: hints.ai_socktype = SOCK_STREAM;
795: } else if (strcasecmp(specifier, "udp6") == 0 ||
796: strcasecmp(specifier, "udpv6") == 0 ||
797: strcasecmp(specifier, "udpipv6") == 0) {
798: hints.ai_family = AF_INET6;
799: hints.ai_socktype = SOCK_DGRAM;
800: } else if (strcasecmp(specifier, "tcp6") == 0 ||
801: strcasecmp(specifier, "tcpv6") == 0 ||
802: strcasecmp(specifier, "tcpipv6") == 0) {
803: hints.ai_family = AF_INET6;
804: hints.ai_socktype = SOCK_STREAM;
805: } else if (strcasecmp(specifier, "unix") == 0) {
806: hints.ai_family = AF_UNIX;
807: hints.ai_socktype = SOCK_STREAM;
808: hints.ai_addr = (struct sockaddr *)&saddr;
809: hints.ai_addrlen = sizeof(saddr);
810: saddr.sun_len = sizeof(saddr);
811: saddr.sun_family = AF_UNIX;
812: if (strlcpy(saddr.sun_path, hostname,
813: sizeof(saddr.sun_path)) > sizeof(saddr.sun_path))
814: errx(1, "Hostname path too long");
815: ai = &hints;
816: } else {
817: port = hostname;
818: hostname = specifier;
819: specifier = NULL;
820: hints.ai_family = AF_INET;
821: hints.ai_socktype = SOCK_DGRAM;
822: }
823: if (port == NULL) {
824: if (hints.ai_family == AF_INET) {
825: if ((port = strchr(hostname, ':')) != NULL)
826: *port++ = '\0';
827: } else if (hints.ai_family == AF_INET6) {
828: if (hostname[0] == '[') {
829: hostname++;
830: if ((port = strchr(hostname, ']')) == NULL)
831: errx(1, "invalid agent");
832: *port++ = '\0';
833: if (port[0] == ':')
834: *port++ = '\0';
835: else
836: port = NULL;
837: } else {
838: if ((port = strrchr(hostname, ':')) == NULL)
839: errx(1, "invalid agent");
840: *port++ = '\0';
841: }
842: }
843: }
844: } else {
845: hostname = specifier;
846: hints.ai_family = AF_INET;
847: hints.ai_socktype = SOCK_DGRAM;
848: }
849:
850: if (hints.ai_family != AF_UNIX) {
851: if (port == NULL)
852: port = defaultport;
853: error = getaddrinfo(hostname, port, &hints, &ai0);
854: if (error)
855: errx(1, "%s", gai_strerror(error));
856: s = -1;
857: for (ai = ai0; ai != NULL; ai = ai->ai_next) {
858: if ((s = socket(ai->ai_family, ai->ai_socktype,
859: ai->ai_protocol)) == -1)
860: continue;
861: break;
862: }
863: } else
864: s = socket(hints.ai_family, hints.ai_socktype,
865: hints.ai_protocol);
866: if (s == -1)
867: err(1, "socket");
868:
869: if (connect(s, (struct sockaddr *)ai->ai_addr, ai->ai_addrlen) == -1)
870: err(1, "Can't connect to %s", agent);
871:
872: if (ai0 != NULL)
873: freeaddrinfo(ai0);
874: free(agentdup);
875: return s;
876: }
877:
878: __dead void
879: usage(void)
880: {
881: size_t i;
882:
883: extern char *__progname;
884:
885: if (snmp_app != NULL) {
886: fprintf(stderr, "usage: %s %s%s%s%s\n",
887: __progname, snmp_app->name,
888: snmp_app->usecommonopt ?
889: " [-c community] [-r retries] [-t timeout] "
890: "[-v protocol version] [-O afnqvxSQ]" : "",
891: snmp_app->usage == NULL ? "" : " ",
892: snmp_app->usage == NULL ? "" : snmp_app->usage);
893: exit(1);
894: }
895: fprintf(stderr, "usage: \n");
896: for (i = 0; i < (sizeof(snmp_apps)/sizeof(*snmp_apps)); i++) {
897: fprintf(stderr, "%*s %s%s%s%s\n",
898: (int) (sizeof("usage:") + strlen(__progname)),
899: __progname, snmp_apps[i].name,
900: snmp_apps[i].usecommonopt ?
901: " [-c community] [-r retries] [-t timeout] "
902: "[-v protocol version] [-O afnqvxSQ]" : "",
903: snmp_apps[i].usage == NULL ? "" : " ",
904: snmp_apps[i].usage == NULL ? "" : snmp_apps[i].usage);
905: }
906: exit(1);
907: }