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