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