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