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