1 /*-
2 * Copyright (c) 2005-2006 The FreeBSD Project
3 * All rights reserved.
4 *
5 * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6 *
7 * Redistribution of this software and documentation and use in source and
8 * binary forms, with or without modification, are permitted provided that
9 * the following conditions are met:
10 *
11 * 1. Redistributions of source code or documentation must retain the above
12 * copyright notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 *
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 * SUCH DAMAGE.
28 *
29 * Helper functions for snmp client tools
30 *
31 * $FreeBSD: stable/9/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c 301690 2016-06-08 19:31:12Z ngie $
32 */
33
34 #include <sys/param.h>
35 #include <sys/queue.h>
36 #include <sys/uio.h>
37
38 #include <assert.h>
39 #include <ctype.h>
40 #include <err.h>
41 #include <errno.h>
42 #include <fcntl.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <string.h>
46 #include <syslog.h>
47 #include <unistd.h>
48
49 #include <bsnmp/asn1.h>
50 #include <bsnmp/snmp.h>
51 #include <bsnmp/snmpclient.h>
52 #include "bsnmptc.h"
53 #include "bsnmptools.h"
54
55 /* Internal varibale to turn on library debugging for testing and to
56 * find bugs. It is not exported via the header file.
57 * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
58 int _bsnmptools_debug = 0;
59
60 /* Default files to import mapping from if none explicitly provided. */
61 #define bsnmpd_defs "/usr/share/snmp/defs/tree.def"
62 #define mibII_defs "/usr/share/snmp/defs/mibII_tree.def"
63
64 /*
65 * The .iso.org.dod oid that has to be prepended to every OID when requesting
66 * a value.
67 */
68 const struct asn_oid IsoOrgDod_OID = {
69 3, { 1, 3, 6 }
70 };
71
72
73 #define SNMP_ERR_UNKNOWN 0
74
75 /*
76 * An array of error strings corresponding to error definitions from libbsnmp.
77 */
78 static const struct {
79 const char *str;
80 int32_t error;
81 } error_strings[] = {
82 { "Unknown", SNMP_ERR_UNKNOWN },
83 { "Too big ", SNMP_ERR_TOOBIG },
84 { "No such Name", SNMP_ERR_NOSUCHNAME },
85 { "Bad Value", SNMP_ERR_BADVALUE },
86 { "Readonly", SNMP_ERR_READONLY },
87 { "General error", SNMP_ERR_GENERR },
88 { "No access", SNMP_ERR_NO_ACCESS },
89 { "Wrong type", SNMP_ERR_WRONG_TYPE },
90 { "Wrong lenght", SNMP_ERR_WRONG_LENGTH },
91 { "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
92 { "Wrong value", SNMP_ERR_WRONG_VALUE },
93 { "No creation", SNMP_ERR_NO_CREATION },
94 { "Inconsistent value", SNMP_ERR_INCONS_VALUE },
95 { "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
96 { "Commit failed", SNMP_ERR_COMMIT_FAILED },
97 { "Undo failed", SNMP_ERR_UNDO_FAILED },
98 { "Authorization error", SNMP_ERR_AUTH_ERR },
99 { "Not writable", SNMP_ERR_NOT_WRITEABLE },
100 { "Inconsistent name", SNMP_ERR_INCONS_NAME },
101 { NULL, 0 }
102 };
103
104 /* This one and any following are exceptions. */
105 #define SNMP_SYNTAX_UNKNOWN SNMP_SYNTAX_NOSUCHOBJECT
106
107 static const struct {
108 const char *str;
109 enum snmp_syntax stx;
110 } syntax_strings[] = {
111 { "Null", SNMP_SYNTAX_NULL },
112 { "Integer", SNMP_SYNTAX_INTEGER },
113 { "OctetString", SNMP_SYNTAX_OCTETSTRING },
114 { "OID", SNMP_SYNTAX_OID },
115 { "IpAddress", SNMP_SYNTAX_IPADDRESS },
116 { "Counter32", SNMP_SYNTAX_COUNTER },
117 { "Gauge", SNMP_SYNTAX_GAUGE },
118 { "TimeTicks", SNMP_SYNTAX_TIMETICKS },
119 { "Counter64", SNMP_SYNTAX_COUNTER64 },
120 { "Unknown", SNMP_SYNTAX_UNKNOWN },
121 };
122
123 int
snmptool_init(struct snmp_toolinfo * snmptoolctx)124 snmptool_init(struct snmp_toolinfo *snmptoolctx)
125 {
126 char *str;
127 size_t slen;
128
129 memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
130 snmptoolctx->objects = 0;
131 snmptoolctx->mappings = NULL;
132 snmptoolctx->flags = SNMP_PDU_GET; /* XXX */
133 SLIST_INIT(&snmptoolctx->filelist);
134 snmp_client_init(&snmp_client);
135
136 if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
137 warnx("Error adding file %s to list", bsnmpd_defs);
138
139 if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
140 warnx("Error adding file %s to list", mibII_defs);
141
142 /* Read the environment */
143 if ((str = getenv("SNMPAUTH")) != NULL) {
144 slen = strlen(str);
145 if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
146 snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
147 else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
148 snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
149 else if (slen != 0)
150 warnx("Bad authentication type - %s in SNMPAUTH", str);
151 }
152
153 if ((str = getenv("SNMPPRIV")) != NULL) {
154 slen = strlen(str);
155 if (slen == strlen("des") && strcasecmp(str, "des") == 0)
156 snmp_client.user.priv_proto = SNMP_PRIV_DES;
157 else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
158 snmp_client.user.priv_proto = SNMP_PRIV_AES;
159 else if (slen != 0)
160 warnx("Bad privacy type - %s in SNMPPRIV", str);
161 }
162
163 if ((str = getenv("SNMPUSER")) != NULL) {
164 if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
165 warnx("Username too long - %s in SNMPUSER", str);
166 return (-1);
167 }
168 if (slen > 0) {
169 strlcpy(snmp_client.user.sec_name, str,
170 sizeof(snmp_client.user.sec_name));
171 snmp_client.version = SNMP_V3;
172 }
173 }
174
175 if ((str = getenv("SNMPPASSWD")) != NULL) {
176 if ((slen = strlen(str)) > MAXSTR)
177 slen = MAXSTR - 1;
178 if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
179 warnx("malloc() failed - %s", strerror(errno));
180 return (-1);
181 }
182 if (slen > 0)
183 strlcpy(snmptoolctx->passwd, str, slen + 1);
184 }
185
186 return (0);
187 }
188
189 #define OBJECT_IDX_LIST(o) o->info->table_idx->index_list
190
191 /*
192 * Walk through the file list and import string<->oid mappings from each file.
193 */
194 int32_t
snmp_import_all(struct snmp_toolinfo * snmptoolctx)195 snmp_import_all(struct snmp_toolinfo *snmptoolctx)
196 {
197 int32_t fc;
198 struct fname *tmp;
199
200 if (snmptoolctx == NULL)
201 return (-1);
202
203 if (ISSET_NUMERIC(snmptoolctx))
204 return (0);
205
206 if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
207 return (-1);
208
209 fc = 0;
210 if (SLIST_EMPTY(&snmptoolctx->filelist)) {
211 warnx("No files to read OID <-> string conversions from");
212 return (-1);
213 } else {
214 SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
215 if (tmp->done)
216 continue;
217 if (snmp_import_file(snmptoolctx, tmp) < 0) {
218 fc = -1;
219 break;
220 }
221 fc++;
222 }
223 }
224
225 snmp_mapping_dump(snmptoolctx);
226 return (fc);
227 }
228
229 /*
230 * Add a filename to the file list - the initail idea of keeping a list with all
231 * files to read OIDs from was that an application might want to have loaded in
232 * memory the OIDs from a single file only and when done with them read the OIDs
233 * from another file. This is not used yet but might be a good idea at some
234 * point. Size argument is number of bytes in string including trailing '\0',
235 * not string lenght.
236 */
237 int32_t
add_filename(struct snmp_toolinfo * snmptoolctx,const char * filename,const struct asn_oid * cut,int32_t done)238 add_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
239 const struct asn_oid *cut, int32_t done)
240 {
241 char *fstring;
242 struct fname *entry;
243
244 if (snmptoolctx == NULL)
245 return (-1);
246
247 /* Make sure file was not in list. */
248 SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
249 if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
250 return (0);
251 }
252
253 if ((fstring = strdup(filename)) == NULL) {
254 warnx("strdup() failed - %s", strerror(errno));
255 return (-1);
256 }
257
258 if ((entry = calloc(1, sizeof(struct fname))) == NULL) {
259 warnx("calloc() failed - %s", strerror(errno));
260 free(fstring);
261 return (-1);
262 }
263
264 if (cut != NULL)
265 asn_append_oid(&(entry->cut), cut);
266 entry->name = fstring;
267 entry->done = done;
268 SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
269
270 return (1);
271 }
272
273 void
free_filelist(struct snmp_toolinfo * snmptoolctx)274 free_filelist(struct snmp_toolinfo *snmptoolctx)
275 {
276 struct fname *f;
277
278 if (snmptoolctx == NULL)
279 return; /* XXX error handling */
280
281 while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
282 SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
283 if (f->name)
284 free(f->name);
285 free(f);
286 }
287 }
288
289 static char
isvalid_fchar(char c,int pos)290 isvalid_fchar(char c, int pos)
291 {
292 if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
293 (pos != 0 && isdigit(c))){
294 return (c);
295 }
296
297 if (c == '\0')
298 return (0);
299
300 if (!isascii(c) || !isprint(c))
301 warnx("Unexpected character %#2x", (u_int) c);
302 else
303 warnx("Illegal character '%c'", c);
304
305 return (-1);
306 }
307
308 /*
309 * Re-implement getsubopt from scratch, because the second argument is broken
310 * and will not compile with WARNS=5.
311 * Copied from src/contrib/bsnmp/snmpd/main.c.
312 */
313 static int
getsubopt1(char ** arg,const char * const * options,char ** valp,char ** optp)314 getsubopt1(char **arg, const char *const *options, char **valp, char **optp)
315 {
316 static const char *const delim = ",\t ";
317 u_int i;
318 char *ptr;
319
320 *optp = NULL;
321
322 /* Skip leading junk. */
323 for (ptr = *arg; *ptr != '\0'; ptr++)
324 if (strchr(delim, *ptr) == NULL)
325 break;
326 if (*ptr == '\0') {
327 *arg = ptr;
328 return (-1);
329 }
330 *optp = ptr;
331
332 /* Find the end of the option. */
333 while (*++ptr != '\0')
334 if (strchr(delim, *ptr) != NULL || *ptr == '=')
335 break;
336
337 if (*ptr != '\0') {
338 if (*ptr == '=') {
339 *ptr++ = '\0';
340 *valp = ptr;
341 while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
342 ptr++;
343 if (*ptr != '\0')
344 *ptr++ = '\0';
345 } else
346 *ptr++ = '\0';
347 }
348
349 *arg = ptr;
350
351 for (i = 0; *options != NULL; options++, i++)
352 if (strcmp(*optp, *options) == 0)
353 return (i);
354 return (-1);
355 }
356
357 static int32_t
parse_path(char * value)358 parse_path(char *value)
359 {
360 int32_t i, len;
361
362 if (value == NULL)
363 return (-1);
364
365 for (len = 0; len < MAXPATHLEN; len++) {
366 i = isvalid_fchar(*(value + len), len) ;
367
368 if (i == 0)
369 break;
370 else if (i < 0)
371 return (-1);
372 }
373
374 if (len >= MAXPATHLEN || value[len] != '\0') {
375 warnx("Bad pathname - '%s'", value);
376 return (-1);
377 }
378
379 return (len);
380 }
381
382 static int32_t
parse_flist(struct snmp_toolinfo * snmptoolctx,char * value,char * path,const struct asn_oid * cut)383 parse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
384 const struct asn_oid *cut)
385 {
386 int32_t namelen;
387 char filename[MAXPATHLEN + 1];
388
389 if (value == NULL)
390 return (-1);
391
392 do {
393 memset(filename, 0, MAXPATHLEN + 1);
394
395 if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
396 strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
397 namelen = strlen(SNMP_DEFS_DIR);
398 } else if (path != NULL){
399 strlcpy(filename, path, MAXPATHLEN + 1);
400 namelen = strlen(path);
401 } else
402 namelen = 0;
403
404 for ( ; namelen < MAXPATHLEN; value++) {
405 if (isvalid_fchar(*value, namelen) > 0) {
406 filename[namelen++] = *value;
407 continue;
408 }
409
410 if (*value == ',' )
411 value++;
412 else if (*value == '\0')
413 ;
414 else {
415 if (!isascii(*value) || !isprint(*value))
416 warnx("Unexpected character %#2x in"
417 " filename", (u_int) *value);
418 else
419 warnx("Illegal character '%c' in"
420 " filename", *value);
421 return (-1);
422 }
423
424 filename[namelen]='\0';
425 break;
426 }
427
428 if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
429 warnx("Filename %s too long", filename);
430 return (-1);
431 }
432
433 if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
434 warnx("Error adding file %s to list", filename);
435 return (-1);
436 }
437 } while (*value != '\0');
438
439 return(1);
440 }
441
442 static int32_t
parse_ascii(char * ascii,uint8_t * binstr,size_t binlen)443 parse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
444 {
445 char dptr[3];
446 size_t count;
447 int32_t alen, i, saved_errno;
448 uint32_t val;
449
450 /* Filter 0x at the beggining */
451 if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
452 i = 2;
453 else
454 i = 0;
455
456 saved_errno = errno;
457 errno = 0;
458 for (count = 0; i < alen; i += 2) {
459 /* XXX: consider strlen(ascii) % 2 != 0 */
460 dptr[0] = ascii[i];
461 dptr[1] = ascii[i + 1];
462 dptr[2] = '\0';
463 if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
464 errno = saved_errno;
465 return (-1);
466 }
467 binstr[count] = (uint8_t) val;
468 if (++count >= binlen) {
469 warnx("Key %s too long - truncating to %zu octest",
470 ascii, binlen);
471 break;
472 }
473 }
474
475 return (count);
476 }
477
478 /*
479 * Functions to parse common input options for client tools and fill in the
480 * snmp_client structure.
481 */
482 int32_t
parse_authentication(struct snmp_toolinfo * snmptoolctx __unused,char * opt_arg)483 parse_authentication(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
484 {
485 int32_t count, subopt;
486 char *val, *option;
487 const char *const subopts[] = {
488 "proto",
489 "key",
490 NULL
491 };
492
493 assert(opt_arg != NULL);
494 count = 1;
495 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
496 switch (subopt) {
497 case 0:
498 if (val == NULL) {
499 warnx("Suboption 'proto' requires an argument");
500 return (-1);
501 }
502 if (strlen(val) != 3) {
503 warnx("Unknown auth protocol - %s", val);
504 return (-1);
505 }
506 if (strncasecmp("md5", val, strlen("md5")) == 0)
507 snmp_client.user.auth_proto =
508 SNMP_AUTH_HMAC_MD5;
509 else if (strncasecmp("sha", val, strlen("sha")) == 0)
510 snmp_client.user.auth_proto =
511 SNMP_AUTH_HMAC_SHA;
512 else {
513 warnx("Unknown auth protocol - %s", val);
514 return (-1);
515 }
516 break;
517 case 1:
518 if (val == NULL) {
519 warnx("Suboption 'key' requires an argument");
520 return (-1);
521 }
522 if (parse_ascii(val, snmp_client.user.auth_key,
523 SNMP_AUTH_KEY_SIZ) < 0) {
524 warnx("Bad authentication key- %s", val);
525 return (-1);
526 }
527 break;
528 default:
529 warnx("Unknown suboption - '%s'", suboptarg);
530 return (-1);
531 }
532 count += 1;
533 }
534 return (2/* count */);
535 }
536
537 int32_t
parse_privacy(struct snmp_toolinfo * snmptoolctx __unused,char * opt_arg)538 parse_privacy(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
539 {
540 int32_t count, subopt;
541 char *val, *option;
542 const char *const subopts[] = {
543 "proto",
544 "key",
545 NULL
546 };
547
548 assert(opt_arg != NULL);
549 count = 1;
550 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
551 switch (subopt) {
552 case 0:
553 if (val == NULL) {
554 warnx("Suboption 'proto' requires an argument");
555 return (-1);
556 }
557 if (strlen(val) != 3) {
558 warnx("Unknown privacy protocol - %s", val);
559 return (-1);
560 }
561 if (strncasecmp("aes", val, strlen("aes")) == 0)
562 snmp_client.user.priv_proto = SNMP_PRIV_AES;
563 else if (strncasecmp("des", val, strlen("des")) == 0)
564 snmp_client.user.priv_proto = SNMP_PRIV_DES;
565 else {
566 warnx("Unknown privacy protocol - %s", val);
567 return (-1);
568 }
569 break;
570 case 1:
571 if (val == NULL) {
572 warnx("Suboption 'key' requires an argument");
573 return (-1);
574 }
575 if (parse_ascii(val, snmp_client.user.priv_key,
576 SNMP_PRIV_KEY_SIZ) < 0) {
577 warnx("Bad privacy key- %s", val);
578 return (-1);
579 }
580 break;
581 default:
582 warnx("Unknown suboption - '%s'", suboptarg);
583 return (-1);
584 }
585 count += 1;
586 }
587 return (2/* count */);
588 }
589
590 int32_t
parse_context(struct snmp_toolinfo * snmptoolctx __unused,char * opt_arg)591 parse_context(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
592 {
593 int32_t count, subopt;
594 char *val, *option;
595 const char *const subopts[] = {
596 "context",
597 "context-engine",
598 NULL
599 };
600
601 assert(opt_arg != NULL);
602 count = 1;
603 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
604 switch (subopt) {
605 case 0:
606 if (val == NULL) {
607 warnx("Suboption 'context' - no argument");
608 return (-1);
609 }
610 strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
611 break;
612 case 1:
613 if (val == NULL) {
614 warnx("Suboption 'context-engine' - no argument");
615 return (-1);
616 }
617 if ((int32_t)(snmp_client.clen = parse_ascii(val,
618 snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) == -1) {
619 warnx("Bad EngineID - %s", val);
620 return (-1);
621 }
622 break;
623 default:
624 warnx("Unknown suboption - '%s'", suboptarg);
625 return (-1);
626 }
627 count += 1;
628 }
629 return (2/* count */);
630 }
631
632 int32_t
parse_user_security(struct snmp_toolinfo * snmptoolctx __unused,char * opt_arg)633 parse_user_security(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
634 {
635 int32_t count, subopt, saved_errno;
636 char *val, *option;
637 const char *const subopts[] = {
638 "engine",
639 "engine-boots",
640 "engine-time",
641 "name",
642 NULL
643 };
644
645 assert(opt_arg != NULL);
646 count = 1;
647 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
648 switch (subopt) {
649 case 0:
650 if (val == NULL) {
651 warnx("Suboption 'engine' - no argument");
652 return (-1);
653 }
654 snmp_client.engine.engine_len = parse_ascii(val,
655 snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
656 if ((int32_t)snmp_client.engine.engine_len == -1) {
657 warnx("Bad EngineID - %s", val);
658 return (-1);
659 }
660 break;
661 case 1:
662 if (val == NULL) {
663 warnx("Suboption 'engine-boots' - no argument");
664 return (-1);
665 }
666 saved_errno = errno;
667 errno = 0;
668 snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
669 if (errno != 0) {
670 warnx("Bad 'engine-boots' value %s - %s", val,
671 strerror(errno));
672 errno = saved_errno;
673 return (-1);
674 }
675 errno = saved_errno;
676 break;
677 case 2:
678 if (val == NULL) {
679 warnx("Suboption 'engine-time' - no argument");
680 return (-1);
681 }
682 saved_errno = errno;
683 errno = 0;
684 snmp_client.engine.engine_time = strtoul(val, NULL, 10);
685 if (errno != 0) {
686 warnx("Bad 'engine-time' value %s - %s", val,
687 strerror(errno));
688 errno = saved_errno;
689 return (-1);
690 }
691 errno = saved_errno;
692 break;
693 case 3:
694 strlcpy(snmp_client.user.sec_name, val,
695 SNMP_ADM_STR32_SIZ);
696 break;
697 default:
698 warnx("Unknown suboption - '%s'", suboptarg);
699 return (-1);
700 }
701 count += 1;
702 }
703 return (2/* count */);
704 }
705
706 int32_t
parse_file(struct snmp_toolinfo * snmptoolctx,char * opt_arg)707 parse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
708 {
709 assert(opt_arg != NULL);
710
711 if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
712 return (-1);
713
714 return (2);
715 }
716
717 int32_t
parse_include(struct snmp_toolinfo * snmptoolctx,char * opt_arg)718 parse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
719 {
720 char path[MAXPATHLEN + 1];
721 int32_t cut_dflt, len, subopt;
722 struct asn_oid cut;
723 char *val, *option;
724 const char *const subopts[] = {
725 "cut",
726 "path",
727 "file",
728 NULL
729 };
730
731 #define INC_CUT 0
732 #define INC_PATH 1
733 #define INC_LIST 2
734
735 assert(opt_arg != NULL);
736
737 /* if (opt == 'i')
738 free_filelist(snmptoolctx, ); */
739 /*
740 * This function should be called only after getopt(3) - otherwise if
741 * no previous validation of opt_arg strlen() may not return what is
742 * expected.
743 */
744
745 path[0] = '\0';
746 memset(&cut, 0, sizeof(struct asn_oid));
747 cut_dflt = -1;
748
749 while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
750 switch (subopt) {
751 case INC_CUT:
752 if (val == NULL) {
753 warnx("Suboption 'cut' requires an argument");
754 return (-1);
755 } else {
756 if (snmp_parse_numoid(val, &cut) < 0)
757 return (-1);
758 }
759 cut_dflt = 1;
760 break;
761
762 case INC_PATH:
763 if ((len = parse_path(val)) < 0)
764 return (-1);
765 strlcpy(path, val, len + 1);
766 break;
767
768 case INC_LIST:
769 if (val == NULL)
770 return (-1);
771 if (cut_dflt == -1)
772 len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
773 else
774 len = parse_flist(snmptoolctx, val, path, &cut);
775 if (len < 0)
776 return (-1);
777 break;
778
779 default:
780 warnx("Unknown suboption - '%s'", suboptarg);
781 return (-1);
782 }
783 }
784
785 /* XXX: Fix me - returning two is wrong here */
786 return (2);
787 }
788
789 int32_t
parse_server(char * opt_arg)790 parse_server(char *opt_arg)
791 {
792 assert(opt_arg != NULL);
793
794 if (snmp_parse_server(&snmp_client, opt_arg) < 0)
795 return (-1);
796
797 if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
798 if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL + 1)))
799 == NULL) {
800 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
801 return (-1);
802 }
803 strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
804 }
805
806 return (2);
807 }
808
809 int32_t
parse_timeout(char * opt_arg)810 parse_timeout(char *opt_arg)
811 {
812 int32_t v, saved_errno;
813
814 assert(opt_arg != NULL);
815
816 saved_errno = errno;
817 errno = 0;
818
819 v = strtol(opt_arg, NULL, 10);
820 if (errno != 0) {
821 warnx( "Error parsing timeout value - %s", strerror(errno));
822 errno = saved_errno;
823 return (-1);
824 }
825
826 snmp_client.timeout.tv_sec = v;
827 errno = saved_errno;
828 return (2);
829 }
830
831 int32_t
parse_retry(char * opt_arg)832 parse_retry(char *opt_arg)
833 {
834 uint32_t v;
835 int32_t saved_errno;
836
837 assert(opt_arg != NULL);
838
839 saved_errno = errno;
840 errno = 0;
841
842 v = strtoul(opt_arg, NULL, 10);
843 if (errno != 0) {
844 warnx("Error parsing retries count - %s", strerror(errno));
845 errno = saved_errno;
846 return (-1);
847 }
848
849 snmp_client.retries = v;
850 errno = saved_errno;
851 return (2);
852 }
853
854 int32_t
parse_version(char * opt_arg)855 parse_version(char *opt_arg)
856 {
857 uint32_t v;
858 int32_t saved_errno;
859
860 assert(opt_arg != NULL);
861
862 saved_errno = errno;
863 errno = 0;
864
865 v = strtoul(opt_arg, NULL, 10);
866 if (errno != 0) {
867 warnx("Error parsing version - %s", strerror(errno));
868 errno = saved_errno;
869 return (-1);
870 }
871
872 switch (v) {
873 case 1:
874 snmp_client.version = SNMP_V1;
875 break;
876 case 2:
877 snmp_client.version = SNMP_V2c;
878 break;
879 case 3:
880 snmp_client.version = SNMP_V3;
881 break;
882 default:
883 warnx("Unsupported SNMP version - %u", v);
884 errno = saved_errno;
885 return (-1);
886 }
887
888 errno = saved_errno;
889 return (2);
890 }
891
892 int32_t
parse_local_path(char * opt_arg)893 parse_local_path(char *opt_arg)
894 {
895 assert(opt_arg != NULL);
896
897 if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
898 warnx("Filename too long - %s", opt_arg);
899 return (-1);
900 }
901
902 strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
903 return (2);
904 }
905
906 int32_t
parse_buflen(char * opt_arg)907 parse_buflen(char *opt_arg)
908 {
909 uint32_t size;
910 int32_t saved_errno;
911
912 assert(opt_arg != NULL);
913
914 saved_errno = errno;
915 errno = 0;
916
917 size = strtoul(opt_arg, NULL, 10);
918 if (errno != 0) {
919 warnx("Error parsing buffer size - %s", strerror(errno));
920 errno = saved_errno;
921 return (-1);
922 }
923
924 if (size > MAX_BUFF_SIZE) {
925 warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
926 errno = saved_errno;
927 return (-1);
928 }
929
930 snmp_client.txbuflen = snmp_client.rxbuflen = size;
931 errno = saved_errno;
932 return (2);
933 }
934
935 int32_t
parse_debug(void)936 parse_debug(void)
937 {
938 snmp_client.dump_pdus = 1;
939 return (1);
940 }
941
942 int32_t
parse_discovery(struct snmp_toolinfo * snmptoolctx)943 parse_discovery(struct snmp_toolinfo *snmptoolctx)
944 {
945 SET_EDISCOVER(snmptoolctx);
946 snmp_client.version = SNMP_V3;
947 return (1);
948 }
949
950 int32_t
parse_local_key(struct snmp_toolinfo * snmptoolctx)951 parse_local_key(struct snmp_toolinfo *snmptoolctx)
952 {
953 SET_LOCALKEY(snmptoolctx);
954 snmp_client.version = SNMP_V3;
955 return (1);
956 }
957
958 int32_t
parse_num_oids(struct snmp_toolinfo * snmptoolctx)959 parse_num_oids(struct snmp_toolinfo *snmptoolctx)
960 {
961 SET_NUMERIC(snmptoolctx);
962 return (1);
963 }
964
965 int32_t
parse_output(struct snmp_toolinfo * snmptoolctx,char * opt_arg)966 parse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
967 {
968 assert(opt_arg != NULL);
969
970 if (strlen(opt_arg) > strlen("verbose")) {
971 warnx( "Invalid output option - %s",opt_arg);
972 return (-1);
973 }
974
975 if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
976 SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
977 else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
978 SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
979 else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
980 SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
981 else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
982 SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
983 else {
984 warnx( "Invalid output option - %s", opt_arg);
985 return (-1);
986 }
987
988 return (2);
989 }
990
991 int32_t
parse_errors(struct snmp_toolinfo * snmptoolctx)992 parse_errors(struct snmp_toolinfo *snmptoolctx)
993 {
994 SET_RETRY(snmptoolctx);
995 return (1);
996 }
997
998 int32_t
parse_skip_access(struct snmp_toolinfo * snmptoolctx)999 parse_skip_access(struct snmp_toolinfo *snmptoolctx)
1000 {
1001 SET_ERRIGNORE(snmptoolctx);
1002 return (1);
1003 }
1004
1005 char *
snmp_parse_suboid(char * str,struct asn_oid * oid)1006 snmp_parse_suboid(char *str, struct asn_oid *oid)
1007 {
1008 char *endptr;
1009 asn_subid_t suboid;
1010
1011 if (*str == '.')
1012 str++;
1013
1014 if (*str < '0' || *str > '9')
1015 return (str);
1016
1017 do {
1018 suboid = strtoul(str, &endptr, 10);
1019 if ((asn_subid_t) suboid > ASN_MAXID) {
1020 warnx("Suboid %u > ASN_MAXID", suboid);
1021 return (NULL);
1022 }
1023 if (snmp_suboid_append(oid, suboid) < 0)
1024 return (NULL);
1025 str = endptr + 1;
1026 } while (*endptr == '.');
1027
1028 return (endptr);
1029 }
1030
1031 static char *
snmp_int2asn_oid(char * str,struct asn_oid * oid)1032 snmp_int2asn_oid(char *str, struct asn_oid *oid)
1033 {
1034 char *endptr;
1035 int32_t v, saved_errno;
1036
1037 saved_errno = errno;
1038 errno = 0;
1039
1040 v = strtol(str, &endptr, 10);
1041 if (errno != 0) {
1042 warnx("Integer value %s not supported - %s", str,
1043 strerror(errno));
1044 errno = saved_errno;
1045 return (NULL);
1046 }
1047 errno = saved_errno;
1048
1049 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1050 return (NULL);
1051
1052 return (endptr);
1053 }
1054
1055 /* It is a bit weird to have a table indexed by OID but still... */
1056 static char *
snmp_oid2asn_oid(struct snmp_toolinfo * snmptoolctx,char * str,struct asn_oid * oid)1057 snmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
1058 struct asn_oid *oid)
1059 {
1060 int32_t i;
1061 char string[MAXSTR + 1], *endptr;
1062 struct snmp_object obj;
1063
1064 for (i = 0; i < MAXSTR; i++)
1065 if (isalpha (*(str + i)) == 0)
1066 break;
1067
1068 endptr = str + i;
1069 memset(&obj, 0, sizeof(struct snmp_object));
1070 if (i == 0) {
1071 if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
1072 return (NULL);
1073 if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
1074 return (NULL);
1075 } else {
1076 strlcpy(string, str, i + 1);
1077 if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
1078 warnx("Unknown string - %s", string);
1079 return (NULL);
1080 }
1081 }
1082
1083 asn_append_oid(oid, &(obj.val.var));
1084 return (endptr);
1085 }
1086
1087 static char *
snmp_ip2asn_oid(char * str,struct asn_oid * oid)1088 snmp_ip2asn_oid(char *str, struct asn_oid *oid)
1089 {
1090 uint32_t v;
1091 int32_t i;
1092 char *endptr, *ptr;
1093
1094 ptr = str;
1095 for (i = 0; i < 4; i++) {
1096 v = strtoul(ptr, &endptr, 10);
1097 if (v > 0xff)
1098 return (NULL);
1099 if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
1100 return (NULL);
1101 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1102 return (NULL);
1103 ptr = endptr + 1;
1104 }
1105
1106 return (endptr);
1107 }
1108
1109 /* 32-bit counter, gauge, timeticks. */
1110 static char *
snmp_uint2asn_oid(char * str,struct asn_oid * oid)1111 snmp_uint2asn_oid(char *str, struct asn_oid *oid)
1112 {
1113 char *endptr;
1114 uint32_t v;
1115 int32_t saved_errno;
1116
1117 saved_errno = errno;
1118 errno = 0;
1119
1120 v = strtoul(str, &endptr, 10);
1121 if (errno != 0) {
1122 warnx("Integer value %s not supported - %s\n", str,
1123 strerror(errno));
1124 errno = saved_errno;
1125 return (NULL);
1126 }
1127 errno = saved_errno;
1128 if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1129 return (NULL);
1130
1131 return (endptr);
1132 }
1133
1134 static char *
snmp_cnt64_2asn_oid(char * str,struct asn_oid * oid)1135 snmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
1136 {
1137 char *endptr;
1138 uint64_t v;
1139 int32_t saved_errno;
1140
1141 saved_errno = errno;
1142 errno = 0;
1143
1144 v = strtoull(str, &endptr, 10);
1145
1146 if (errno != 0) {
1147 warnx("Integer value %s not supported - %s", str,
1148 strerror(errno));
1149 errno = saved_errno;
1150 return (NULL);
1151 }
1152 errno = saved_errno;
1153 if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
1154 return (NULL);
1155
1156 if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
1157 return (NULL);
1158
1159 return (endptr);
1160 }
1161
1162 enum snmp_syntax
parse_syntax(char * str)1163 parse_syntax(char *str)
1164 {
1165 int32_t i;
1166
1167 for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
1168 if (strncmp(syntax_strings[i].str, str,
1169 strlen(syntax_strings[i].str)) == 0)
1170 return (syntax_strings[i].stx);
1171 }
1172
1173 return (SNMP_SYNTAX_NULL);
1174 }
1175
1176 static char *
snmp_parse_subindex(struct snmp_toolinfo * snmptoolctx,char * str,struct index * idx,struct snmp_object * object)1177 snmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
1178 struct index *idx, struct snmp_object *object)
1179 {
1180 char *ptr;
1181 int32_t i;
1182 enum snmp_syntax stx;
1183 char syntax[MAX_CMD_SYNTAX_LEN];
1184
1185 ptr = str;
1186 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
1187 for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
1188 if (*(ptr + i) == ':')
1189 break;
1190 }
1191
1192 if (i >= MAX_CMD_SYNTAX_LEN) {
1193 warnx("Unknown syntax in OID - %s", str);
1194 return (NULL);
1195 }
1196 /* Expect a syntax string here. */
1197 if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
1198 warnx("Invalid syntax - %s",syntax);
1199 return (NULL);
1200 }
1201
1202 if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
1203 warnx("Syntax mismatch - %d expected, %d given",
1204 idx->syntax, stx);
1205 return (NULL);
1206 }
1207 /*
1208 * That is where the suboid started + the syntax length + one
1209 * character for ':'.
1210 */
1211 ptr = str + i + 1;
1212 } else
1213 stx = idx->syntax;
1214
1215 switch (stx) {
1216 case SNMP_SYNTAX_INTEGER:
1217 return (snmp_int2asn_oid(ptr, &(object->val.var)));
1218 case SNMP_SYNTAX_OID:
1219 return (snmp_oid2asn_oid(snmptoolctx, ptr,
1220 &(object->val.var)));
1221 case SNMP_SYNTAX_IPADDRESS:
1222 return (snmp_ip2asn_oid(ptr, &(object->val.var)));
1223 case SNMP_SYNTAX_COUNTER:
1224 /* FALLTHROUGH */
1225 case SNMP_SYNTAX_GAUGE:
1226 /* FALLTHROUGH */
1227 case SNMP_SYNTAX_TIMETICKS:
1228 return (snmp_uint2asn_oid(ptr, &(object->val.var)));
1229 case SNMP_SYNTAX_COUNTER64:
1230 return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
1231 case SNMP_SYNTAX_OCTETSTRING:
1232 return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
1233 default:
1234 /* NOTREACHED */
1235 break;
1236 }
1237
1238 return (NULL);
1239 }
1240
1241 char *
snmp_parse_index(struct snmp_toolinfo * snmptoolctx,char * str,struct snmp_object * object)1242 snmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
1243 struct snmp_object *object)
1244 {
1245 char *ptr;
1246 struct index *temp;
1247
1248 if (object->info->table_idx == NULL)
1249 return (NULL);
1250
1251 ptr = NULL;
1252 STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
1253 if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
1254 == NULL)
1255 return (NULL);
1256
1257 if (*ptr != ',' && *ptr != ']')
1258 return (NULL);
1259 str = ptr + 1;
1260 }
1261
1262 if (ptr == NULL || *ptr != ']') {
1263 warnx("Mismatching index - %s", str);
1264 return (NULL);
1265 }
1266
1267 return (ptr + 1);
1268 }
1269
1270 /*
1271 * Fill in the struct asn_oid member of snmp_value with suboids from input.
1272 * If an error occurs - print message on stderr and return (-1).
1273 * If all is ok - return the length of the oid.
1274 */
1275 int32_t
snmp_parse_numoid(char * argv,struct asn_oid * var)1276 snmp_parse_numoid(char *argv, struct asn_oid *var)
1277 {
1278 char *endptr, *str;
1279 asn_subid_t suboid;
1280
1281 str = argv;
1282
1283 if (*str == '.')
1284 str++;
1285
1286 do {
1287 if (var->len == ASN_MAXOIDLEN) {
1288 warnx("Oid too long - %u", var->len);
1289 return (-1);
1290 }
1291
1292 suboid = strtoul(str, &endptr, 10);
1293 if (suboid > ASN_MAXID) {
1294 warnx("Oid too long - %u", var->len);
1295 return (-1);
1296 }
1297
1298 var->subs[var->len++] = suboid;
1299 str = endptr + 1;
1300 } while ( *endptr == '.');
1301
1302 if (*endptr != '\0') {
1303 warnx("Invalid oid string - %s", argv);
1304 return (-1);
1305 }
1306
1307 return (var->len);
1308 }
1309
1310 /* Append a length 1 suboid to an asn_oid structure. */
1311 int32_t
snmp_suboid_append(struct asn_oid * var,asn_subid_t suboid)1312 snmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
1313 {
1314 if (var == NULL)
1315 return (-1);
1316
1317 if (var->len >= ASN_MAXOIDLEN) {
1318 warnx("Oid too long - %u", var->len);
1319 return (-1);
1320 }
1321
1322 var->subs[var->len++] = suboid;
1323
1324 return (1);
1325 }
1326
1327 /* Pop the last suboid from an asn_oid structure. */
1328 int32_t
snmp_suboid_pop(struct asn_oid * var)1329 snmp_suboid_pop(struct asn_oid *var)
1330 {
1331 asn_subid_t suboid;
1332
1333 if (var == NULL)
1334 return (-1);
1335
1336 if (var->len < 1)
1337 return (-1);
1338
1339 suboid = var->subs[--(var->len)];
1340 var->subs[var->len] = 0;
1341
1342 return (suboid);
1343 }
1344
1345 /*
1346 * Parse the command-line provided string into an OID - alocate memory for a new
1347 * snmp object, fill in its fields and insert it in the object list. A
1348 * (snmp_verify_inoid_f) function must be provided to validate the input string.
1349 */
1350 int32_t
snmp_object_add(struct snmp_toolinfo * snmptoolctx,snmp_verify_inoid_f func,char * string)1351 snmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
1352 char *string)
1353 {
1354 struct snmp_object *obj;
1355
1356 if (snmptoolctx == NULL)
1357 return (-1);
1358
1359 /* XXX-BZ does that chack make sense? */
1360 if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
1361 warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
1362 return (-1);
1363 }
1364
1365 if ((obj = calloc(1, sizeof(struct snmp_object))) == NULL) {
1366 syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
1367 return (-1);
1368 }
1369
1370 if (func(snmptoolctx, obj, string) < 0) {
1371 warnx("Invalid OID - %s", string);
1372 free(obj);
1373 return (-1);
1374 }
1375
1376 snmptoolctx->objects++;
1377 SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
1378
1379 return (1);
1380 }
1381
1382 /* Given an OID, find it in the object list and remove it. */
1383 int32_t
snmp_object_remove(struct snmp_toolinfo * snmptoolctx,struct asn_oid * oid)1384 snmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1385 {
1386 struct snmp_object *temp;
1387
1388 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
1389 warnx("Object list already empty");
1390 return (-1);
1391 }
1392
1393
1394 SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
1395 if (asn_compare_oid(&(temp->val.var), oid) == 0)
1396 break;
1397
1398 if (temp == NULL) {
1399 warnx("No such object in list");
1400 return (-1);
1401 }
1402
1403 SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
1404 if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1405 temp->val.v.octetstring.octets != NULL)
1406 free(temp->val.v.octetstring.octets);
1407 free(temp);
1408
1409 return (1);
1410 }
1411
1412 static void
snmp_object_freeall(struct snmp_toolinfo * snmptoolctx)1413 snmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
1414 {
1415 struct snmp_object *o;
1416
1417 while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
1418 SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
1419
1420 if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1421 o->val.v.octetstring.octets != NULL)
1422 free(o->val.v.octetstring.octets);
1423 free(o);
1424 }
1425 }
1426
1427 /* Do all possible memory release before exit. */
1428 void
snmp_tool_freeall(struct snmp_toolinfo * snmptoolctx)1429 snmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
1430 {
1431 if (snmp_client.chost != NULL) {
1432 free(snmp_client.chost);
1433 snmp_client.chost = NULL;
1434 }
1435
1436 if (snmp_client.cport != NULL) {
1437 free(snmp_client.cport);
1438 snmp_client.cport = NULL;
1439 }
1440
1441 snmp_mapping_free(snmptoolctx);
1442 free_filelist(snmptoolctx);
1443 snmp_object_freeall(snmptoolctx);
1444
1445 if (snmptoolctx->passwd != NULL) {
1446 free(snmptoolctx->passwd);
1447 snmptoolctx->passwd = NULL;
1448 }
1449 }
1450
1451 /*
1452 * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
1453 * function should check whether the variable is consistent in this PDU
1454 * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
1455 * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
1456 * function actually adds the variable to the PDU and must not be NULL.
1457 */
1458 int32_t
snmp_pdu_add_bindings(struct snmp_toolinfo * snmptoolctx,snmp_verify_vbind_f vfunc,snmp_add_vbind_f afunc,struct snmp_pdu * pdu,int32_t maxcount)1459 snmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
1460 snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
1461 struct snmp_pdu *pdu, int32_t maxcount)
1462 {
1463 int32_t nbindings, abind;
1464 struct snmp_object *obj;
1465
1466 if (pdu == NULL || afunc == NULL)
1467 return (-1);
1468
1469 /* Return 0 in case of no more work todo. */
1470 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
1471 return (0);
1472
1473 if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
1474 warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
1475 return (-1);
1476 }
1477
1478 nbindings = 0;
1479 SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
1480 if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
1481 nbindings = -1;
1482 break;
1483 }
1484 if ((abind = afunc(pdu, obj)) < 0) {
1485 nbindings = -1;
1486 break;
1487 }
1488
1489 if (abind > 0) {
1490 /* Do not put more varbindings than requested. */
1491 if (++nbindings >= maxcount)
1492 break;
1493 }
1494 }
1495
1496 return (nbindings);
1497 }
1498
1499 /*
1500 * Locate an object in the object list and set a corresponding error status.
1501 */
1502 int32_t
snmp_object_seterror(struct snmp_toolinfo * snmptoolctx,struct snmp_value * err_value,int32_t error_status)1503 snmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
1504 struct snmp_value *err_value, int32_t error_status)
1505 {
1506 struct snmp_object *obj;
1507
1508 if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
1509 return (-1);
1510
1511 SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
1512 if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
1513 obj->error = error_status;
1514 return (1);
1515 }
1516
1517 return (0);
1518 }
1519
1520 /*
1521 * Check a PDU received in responce to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
1522 * but don't compare syntaxes - when sending a request PDU they must be null.
1523 * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
1524 * checks and some other checks skiped.
1525 */
1526 int32_t
snmp_parse_get_resp(struct snmp_pdu * resp,struct snmp_pdu * req)1527 snmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1528 {
1529 uint32_t i;
1530
1531 for (i = 0; i < req->nbindings; i++) {
1532 if (asn_compare_oid(&req->bindings[i].var,
1533 &resp->bindings[i].var) != 0) {
1534 warnx("Bad OID in response");
1535 return (-1);
1536 }
1537
1538 if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
1539 == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
1540 SNMP_SYNTAX_NOSUCHINSTANCE))
1541 return (0);
1542 }
1543
1544 return (1);
1545 }
1546
1547 int32_t
snmp_parse_getbulk_resp(struct snmp_pdu * resp,struct snmp_pdu * req)1548 snmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1549 {
1550 int32_t N, R, M, r;
1551
1552 if (req->error_status > (int32_t) resp->nbindings) {
1553 warnx("Bad number of bindings in response");
1554 return (-1);
1555 }
1556
1557 for (N = 0; N < req->error_status; N++) {
1558 if (asn_is_suboid(&req->bindings[N].var,
1559 &resp->bindings[N].var) == 0)
1560 return (0);
1561 if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
1562 return (0);
1563 }
1564
1565 for (R = N , r = N; R < (int32_t) req->nbindings; R++) {
1566 for (M = 0; M < req->error_index && (r + M) <
1567 (int32_t) resp->nbindings; M++) {
1568 if (asn_is_suboid(&req->bindings[R].var,
1569 &resp->bindings[r + M].var) == 0)
1570 return (0);
1571
1572 if (resp->bindings[r + M].syntax ==
1573 SNMP_SYNTAX_ENDOFMIBVIEW) {
1574 M++;
1575 break;
1576 }
1577 }
1578 r += M;
1579 }
1580
1581 return (0);
1582 }
1583
1584 int32_t
snmp_parse_getnext_resp(struct snmp_pdu * resp,struct snmp_pdu * req)1585 snmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1586 {
1587 uint32_t i;
1588
1589 for (i = 0; i < req->nbindings; i++) {
1590 if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
1591 == 0)
1592 return (0);
1593
1594 if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
1595 SNMP_SYNTAX_ENDOFMIBVIEW)
1596 return (0);
1597 }
1598
1599 return (1);
1600 }
1601
1602 /*
1603 * Should be called to check a responce to get/getnext/getbulk.
1604 */
1605 int32_t
snmp_parse_resp(struct snmp_pdu * resp,struct snmp_pdu * req)1606 snmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1607 {
1608 if (resp == NULL || req == NULL)
1609 return (-2);
1610
1611 if (resp->version != req->version) {
1612 warnx("Response has wrong version");
1613 return (-1);
1614 }
1615
1616 if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
1617 warnx("Error - No Such Name");
1618 return (0);
1619 }
1620
1621 if (resp->error_status != SNMP_ERR_NOERROR) {
1622 warnx("Error %d in responce", resp->error_status);
1623 return (-1);
1624 }
1625
1626 if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
1627 warnx("Bad number of bindings in response");
1628 return (-1);
1629 }
1630
1631 switch (req->type) {
1632 case SNMP_PDU_GET:
1633 return (snmp_parse_get_resp(resp,req));
1634 case SNMP_PDU_GETBULK:
1635 return (snmp_parse_getbulk_resp(resp,req));
1636 case SNMP_PDU_GETNEXT:
1637 return (snmp_parse_getnext_resp(resp,req));
1638 default:
1639 /* NOTREACHED */
1640 break;
1641 }
1642
1643 return (-2);
1644 }
1645
1646 static void
snmp_output_octetstring(struct snmp_toolinfo * snmptoolctx,enum snmp_tc tc,uint32_t len,uint8_t * octets)1647 snmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1648 uint32_t len, uint8_t *octets)
1649 {
1650 char *buf;
1651
1652 if (len == 0 || octets == NULL)
1653 return;
1654
1655 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1656 fprintf(stdout, "%s : ",
1657 syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
1658
1659 if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
1660 fprintf(stdout, "%s", buf);
1661 free(buf);
1662 }
1663 }
1664
1665 static void
snmp_output_octetindex(struct snmp_toolinfo * snmptoolctx,enum snmp_tc tc,struct asn_oid * oid)1666 snmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1667 struct asn_oid *oid)
1668 {
1669 uint32_t i;
1670 uint8_t *s;
1671
1672 if ((s = malloc(oid->subs[0] + 1)) == NULL)
1673 syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
1674 else {
1675 for (i = 0; i < oid->subs[0]; i++)
1676 s[i] = (u_char) (oid->subs[i + 1]);
1677
1678 snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
1679 free(s);
1680 }
1681 }
1682
1683 /*
1684 * Check and output syntax type and value.
1685 */
1686 static void
snmp_output_oid_value(struct snmp_toolinfo * snmptoolctx,struct asn_oid * oid)1687 snmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1688 {
1689 char oid_string[ASN_OIDSTRLEN];
1690 struct snmp_object obj;
1691
1692 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1693 fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
1694
1695 if(!ISSET_NUMERIC(snmptoolctx)) {
1696 memset(&obj, 0, sizeof(struct snmp_object));
1697 asn_append_oid(&(obj.val.var), oid);
1698
1699 if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
1700 fprintf(stdout, "%s" , obj.info->string);
1701 else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
1702 fprintf(stdout, "%s" , obj.info->string);
1703 else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
1704 fprintf(stdout, "%s" , obj.info->string);
1705 else {
1706 (void) asn_oid2str_r(oid, oid_string);
1707 fprintf(stdout, "%s", oid_string);
1708 }
1709 } else {
1710 (void) asn_oid2str_r(oid, oid_string);
1711 fprintf(stdout, "%s", oid_string);
1712 }
1713 }
1714
1715 static void
snmp_output_int(struct snmp_toolinfo * snmptoolctx,struct enum_pairs * enums,int32_t int_val)1716 snmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
1717 int32_t int_val)
1718 {
1719 char *string;
1720
1721 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1722 fprintf(stdout, "%s : ",
1723 syntax_strings[SNMP_SYNTAX_INTEGER].str);
1724
1725 if (enums != NULL && (string = enum_string_lookup(enums, int_val))
1726 != NULL)
1727 fprintf(stdout, "%s", string);
1728 else
1729 fprintf(stdout, "%d", int_val);
1730 }
1731
1732 static void
snmp_output_ipaddress(struct snmp_toolinfo * snmptoolctx,uint8_t * ip)1733 snmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
1734 {
1735 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1736 fprintf(stdout, "%s : ",
1737 syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
1738
1739 fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1740 }
1741
1742 static void
snmp_output_counter(struct snmp_toolinfo * snmptoolctx,uint32_t counter)1743 snmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
1744 {
1745 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1746 fprintf(stdout, "%s : ",
1747 syntax_strings[SNMP_SYNTAX_COUNTER].str);
1748
1749 fprintf(stdout, "%u", counter);
1750 }
1751
1752 static void
snmp_output_gauge(struct snmp_toolinfo * snmptoolctx,uint32_t gauge)1753 snmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
1754 {
1755 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1756 fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
1757
1758 fprintf(stdout, "%u", gauge);
1759 }
1760
1761 static void
snmp_output_ticks(struct snmp_toolinfo * snmptoolctx,uint32_t ticks)1762 snmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
1763 {
1764 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1765 fprintf(stdout, "%s : ",
1766 syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
1767
1768 fprintf(stdout, "%u", ticks);
1769 }
1770
1771 static void
snmp_output_counter64(struct snmp_toolinfo * snmptoolctx,uint64_t counter64)1772 snmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
1773 {
1774 if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1775 fprintf(stdout, "%s : ",
1776 syntax_strings[SNMP_SYNTAX_COUNTER64].str);
1777
1778 fprintf(stdout,"%ju", counter64);
1779 }
1780
1781 int32_t
snmp_output_numval(struct snmp_toolinfo * snmptoolctx,struct snmp_value * val,struct snmp_oid2str * entry)1782 snmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
1783 struct snmp_oid2str *entry)
1784 {
1785 if (val == NULL)
1786 return (-1);
1787
1788 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1789 fprintf(stdout, " = ");
1790
1791 switch (val->syntax) {
1792 case SNMP_SYNTAX_INTEGER:
1793 if (entry != NULL)
1794 snmp_output_int(snmptoolctx, entry->snmp_enum,
1795 val->v.integer);
1796 else
1797 snmp_output_int(snmptoolctx, NULL, val->v.integer);
1798 break;
1799
1800 case SNMP_SYNTAX_OCTETSTRING:
1801 if (entry != NULL)
1802 snmp_output_octetstring(snmptoolctx, entry->tc,
1803 val->v.octetstring.len, val->v.octetstring.octets);
1804 else
1805 snmp_output_octetstring(snmptoolctx, SNMP_STRING,
1806 val->v.octetstring.len, val->v.octetstring.octets);
1807 break;
1808
1809 case SNMP_SYNTAX_OID:
1810 snmp_output_oid_value(snmptoolctx, &(val->v.oid));
1811 break;
1812
1813 case SNMP_SYNTAX_IPADDRESS:
1814 snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
1815 break;
1816
1817 case SNMP_SYNTAX_COUNTER:
1818 snmp_output_counter(snmptoolctx, val->v.uint32);
1819 break;
1820
1821 case SNMP_SYNTAX_GAUGE:
1822 snmp_output_gauge(snmptoolctx, val->v.uint32);
1823 break;
1824
1825 case SNMP_SYNTAX_TIMETICKS:
1826 snmp_output_ticks(snmptoolctx, val->v.uint32);
1827 break;
1828
1829 case SNMP_SYNTAX_COUNTER64:
1830 snmp_output_counter64(snmptoolctx, val->v.counter64);
1831 break;
1832
1833 case SNMP_SYNTAX_NOSUCHOBJECT:
1834 fprintf(stdout, "No Such Object\n");
1835 return (val->syntax);
1836
1837 case SNMP_SYNTAX_NOSUCHINSTANCE:
1838 fprintf(stdout, "No Such Instance\n");
1839 return (val->syntax);
1840
1841 case SNMP_SYNTAX_ENDOFMIBVIEW:
1842 fprintf(stdout, "End of Mib View\n");
1843 return (val->syntax);
1844
1845 case SNMP_SYNTAX_NULL:
1846 /* NOTREACHED */
1847 fprintf(stdout, "agent returned NULL Syntax\n");
1848 return (val->syntax);
1849
1850 default:
1851 /* NOTREACHED - If here - then all went completely wrong. */
1852 fprintf(stdout, "agent returned unknown syntax\n");
1853 return (-1);
1854 }
1855
1856 fprintf(stdout, "\n");
1857
1858 return (0);
1859 }
1860
1861 static int32_t
snmp_fill_object(struct snmp_toolinfo * snmptoolctx,struct snmp_object * obj,struct snmp_value * val)1862 snmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
1863 struct snmp_value *val)
1864 {
1865 int32_t rc;
1866 asn_subid_t suboid;
1867
1868 if (obj == NULL || val == NULL)
1869 return (-1);
1870
1871 if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
1872 return (-1);
1873
1874 memset(obj, 0, sizeof(struct snmp_object));
1875 asn_append_oid(&(obj->val.var), &(val->var));
1876 obj->val.syntax = val->syntax;
1877
1878 if (obj->val.syntax > 0)
1879 rc = snmp_lookup_leafstring(snmptoolctx, obj);
1880 else
1881 rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
1882
1883 (void) snmp_suboid_append(&(val->var), suboid);
1884 (void) snmp_suboid_append(&(obj->val.var), suboid);
1885
1886 return (rc);
1887 }
1888
1889 static int32_t
snmp_output_index(struct snmp_toolinfo * snmptoolctx,struct index * stx,struct asn_oid * oid)1890 snmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
1891 struct asn_oid *oid)
1892 {
1893 uint8_t ip[4];
1894 uint32_t bytes = 1;
1895 uint64_t cnt64;
1896 struct asn_oid temp, out;
1897
1898 if (oid->len < bytes)
1899 return (-1);
1900
1901 memset(&temp, 0, sizeof(struct asn_oid));
1902 asn_append_oid(&temp, oid);
1903
1904 switch (stx->syntax) {
1905 case SNMP_SYNTAX_INTEGER:
1906 snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
1907 break;
1908
1909 case SNMP_SYNTAX_OCTETSTRING:
1910 if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
1911 ASN_MAXOCTETSTRING))
1912 return (-1);
1913 snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
1914 bytes += temp.subs[0];
1915 break;
1916
1917 case SNMP_SYNTAX_OID:
1918 if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
1919 ASN_MAXOIDLEN))
1920 return (-1);
1921
1922 bytes += temp.subs[0];
1923 memset(&out, 0, sizeof(struct asn_oid));
1924 asn_slice_oid(&out, &temp, 1, bytes);
1925 snmp_output_oid_value(snmptoolctx, &out);
1926 break;
1927
1928 case SNMP_SYNTAX_IPADDRESS:
1929 if (temp.len < 4)
1930 return (-1);
1931 for (bytes = 0; bytes < 4; bytes++)
1932 ip[bytes] = temp.subs[bytes];
1933
1934 snmp_output_ipaddress(snmptoolctx, ip);
1935 bytes = 4;
1936 break;
1937
1938 case SNMP_SYNTAX_COUNTER:
1939 snmp_output_counter(snmptoolctx, temp.subs[0]);
1940 break;
1941
1942 case SNMP_SYNTAX_GAUGE:
1943 snmp_output_gauge(snmptoolctx, temp.subs[0]);
1944 break;
1945
1946 case SNMP_SYNTAX_TIMETICKS:
1947 snmp_output_ticks(snmptoolctx, temp.subs[0]);
1948 break;
1949
1950 case SNMP_SYNTAX_COUNTER64:
1951 if (oid->len < 2)
1952 return (-1);
1953 bytes = 2;
1954 memcpy(&cnt64, temp.subs, bytes);
1955 snmp_output_counter64(snmptoolctx, cnt64);
1956 break;
1957
1958 default:
1959 return (-1);
1960 }
1961
1962 return (bytes);
1963 }
1964
1965 static int32_t
snmp_output_object(struct snmp_toolinfo * snmptoolctx,struct snmp_object * o)1966 snmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
1967 {
1968 int32_t i, first, len;
1969 struct asn_oid oid;
1970 struct index *temp;
1971
1972 if (ISSET_NUMERIC(snmptoolctx))
1973 return (-1);
1974
1975 if (o->info->table_idx == NULL) {
1976 fprintf(stdout,"%s.%d", o->info->string,
1977 o->val.var.subs[o->val.var.len - 1]);
1978 return (1);
1979 }
1980
1981 fprintf(stdout,"%s[", o->info->string);
1982 memset(&oid, 0, sizeof(struct asn_oid));
1983
1984 len = 1;
1985 asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
1986 o->val.var.len);
1987
1988 first = 1;
1989 STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
1990 if(first)
1991 first = 0;
1992 else
1993 fprintf(stdout, ", ");
1994 if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
1995 break;
1996 len += i;
1997 memset(&oid, 0, sizeof(struct asn_oid));
1998 asn_slice_oid(&oid, &(o->val.var),
1999 (o->info->table_idx->var.len + len), o->val.var.len + 1);
2000 }
2001
2002 fprintf(stdout,"]");
2003 return (1);
2004 }
2005
2006 void
snmp_output_err_resp(struct snmp_toolinfo * snmptoolctx,struct snmp_pdu * pdu)2007 snmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
2008 {
2009 char buf[ASN_OIDSTRLEN];
2010 struct snmp_object object;
2011
2012 if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
2013 fprintf(stdout,"Invalid error index in PDU\n");
2014 return;
2015 }
2016
2017 fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
2018 snmp_client.cport);
2019
2020 if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object,
2021 &(pdu->bindings[pdu->error_index - 1])) > 0))
2022 snmp_output_object(snmptoolctx, &object);
2023 else {
2024 asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
2025 fprintf(stdout,"%s", buf);
2026 }
2027
2028 fprintf(stdout," caused error - ");
2029 if ((pdu->error_status > 0) && (pdu->error_status <=
2030 SNMP_ERR_INCONS_NAME))
2031 fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
2032 else
2033 fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
2034 }
2035
2036 int32_t
snmp_output_resp(struct snmp_toolinfo * snmptoolctx,struct snmp_pdu * pdu)2037 snmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
2038 {
2039 int32_t error;
2040 char p[ASN_OIDSTRLEN];
2041 uint32_t i;
2042 struct snmp_object object;
2043
2044 for (i = 0, error = 0; i < pdu->nbindings; i++) {
2045 if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
2046 if (!ISSET_NUMERIC(snmptoolctx) &&
2047 (snmp_fill_object(snmptoolctx, &object,
2048 &(pdu->bindings[i])) > 0))
2049 snmp_output_object(snmptoolctx, &object);
2050 else {
2051 asn_oid2str_r(&(pdu->bindings[i].var), p);
2052 fprintf(stdout, "%s", p);
2053 }
2054 }
2055 error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info);
2056 }
2057
2058 return (error);
2059 }
2060
2061 void
snmp_output_engine(void)2062 snmp_output_engine(void)
2063 {
2064 uint32_t i;
2065 char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
2066
2067 cptr = engine;
2068 for (i = 0; i < snmp_client.engine.engine_len; i++)
2069 cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
2070 *cptr++ = '\0';
2071
2072 fprintf(stdout, "Engine ID 0x%s\n", engine);
2073 fprintf(stdout, "Boots : %u\t\tTime : %d\n",
2074 snmp_client.engine.engine_boots,
2075 snmp_client.engine.engine_time);
2076 }
2077
2078 void
snmp_output_keys(void)2079 snmp_output_keys(void)
2080 {
2081 uint32_t i, keylen = 0;
2082 char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
2083
2084 fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
2085 if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
2086 fprintf(stdout, "MD5 : 0x");
2087 keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
2088 } else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
2089 fprintf(stdout, "SHA : 0x");
2090 keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
2091 }
2092 if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
2093 cptr = extkey;
2094 for (i = 0; i < keylen; i++)
2095 cptr += sprintf(cptr, "%.2x",
2096 snmp_client.user.auth_key[i]);
2097 *cptr++ = '\0';
2098 fprintf(stdout, "%s\n", extkey);
2099 }
2100
2101 if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
2102 fprintf(stdout, "DES : 0x");
2103 keylen = SNMP_PRIV_DES_KEY_SIZ;
2104 } else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
2105 fprintf(stdout, "AES : 0x");
2106 keylen = SNMP_PRIV_AES_KEY_SIZ;
2107 }
2108 if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
2109 cptr = extkey;
2110 for (i = 0; i < keylen; i++)
2111 cptr += sprintf(cptr, "%.2x",
2112 snmp_client.user.priv_key[i]);
2113 *cptr++ = '\0';
2114 fprintf(stdout, "%s\n", extkey);
2115 }
2116 }
2117