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