bsnmptools.c revision 245952
1178825Sdfr/*-
2178825Sdfr * Copyright (c) 2005-2006 The FreeBSD Project
3178825Sdfr * All rights reserved.
4178825Sdfr *
5178825Sdfr * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6178825Sdfr *
7178825Sdfr * Redistribution of this software and documentation and use in source and
8178825Sdfr * binary forms, with or without modification, are permitted provided that
9178825Sdfr * the following conditions are met:
10178825Sdfr *
11233294Sstas * 1. Redistributions of source code or documentation must retain the above
12178825Sdfr *    copyright notice, this list of conditions and the following disclaimer.
13178825Sdfr * 2. Redistributions in binary form must reproduce the above copyright
14178825Sdfr *    notice, this list of conditions and the following disclaimer in the
15178825Sdfr *    documentation and/or other materials provided with the distribution.
16178825Sdfr *
17178825Sdfr * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18178825Sdfr * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19178825Sdfr * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20178825Sdfr * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21178825Sdfr * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22178825Sdfr * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23178825Sdfr * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24178825Sdfr * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25178825Sdfr * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26178825Sdfr * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27178825Sdfr * SUCH DAMAGE.
28178825Sdfr *
29178825Sdfr * Helper functions for snmp client tools
30178825Sdfr *
31178825Sdfr * $FreeBSD: head/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c 245952 2013-01-26 22:08:21Z pfg $
32178825Sdfr */
33233294Sstas
34178825Sdfr#include <sys/param.h>
35178825Sdfr#include <sys/queue.h>
36178825Sdfr#include <sys/uio.h>
37178825Sdfr
38178825Sdfr#include <assert.h>
39178825Sdfr#include <ctype.h>
40178825Sdfr#include <err.h>
41178825Sdfr#include <errno.h>
42178825Sdfr#include <fcntl.h>
43178825Sdfr#include <stdio.h>
44178825Sdfr#include <stdlib.h>
45178825Sdfr#include <string.h>
46178825Sdfr#include <syslog.h>
47178825Sdfr#include <unistd.h>
48178825Sdfr
49178825Sdfr#include <bsnmp/asn1.h>
50178825Sdfr#include <bsnmp/snmp.h>
51178825Sdfr#include <bsnmp/snmpclient.h>
52178825Sdfr#include "bsnmptc.h"
53178825Sdfr#include "bsnmptools.h"
54178825Sdfr
55178825Sdfr/* Internal varibale to turn on library debugging for testing and to
56178825Sdfr * find bugs. It is not exported via the header file.
57178825Sdfr * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
58178825Sdfrint _bsnmptools_debug = 0;
59178825Sdfr
60178825Sdfr/* Default files to import mapping from if none explicitly provided. */
61178825Sdfr#define	bsnmpd_defs		"/usr/share/snmp/defs/tree.def"
62178825Sdfr#define	mibII_defs		"/usr/share/snmp/defs/mibII_tree.def"
63178825Sdfr
64178825Sdfr/*
65178825Sdfr * The .iso.org.dod oid that has to be prepended to every OID when requesting
66178825Sdfr * a value.
67178825Sdfr */
68178825Sdfrconst struct asn_oid IsoOrgDod_OID = {
69178825Sdfr	3, { 1, 3, 6 }
70178825Sdfr};
71178825Sdfr
72178825Sdfr
73178825Sdfr#define	SNMP_ERR_UNKNOWN	0
74178825Sdfr
75178825Sdfr/*
76178825Sdfr * An array of error strings corresponding to error definitions from libbsnmp.
77178825Sdfr */
78178825Sdfrstatic const struct {
79178825Sdfr	const char *str;
80178825Sdfr	int32_t error;
81178825Sdfr} error_strings[] = {
82178825Sdfr	{ "Unknown", SNMP_ERR_UNKNOWN },
83178825Sdfr	{ "Too big ", SNMP_ERR_TOOBIG },
84178825Sdfr	{ "No such Name", SNMP_ERR_NOSUCHNAME },
85178825Sdfr	{ "Bad Value", SNMP_ERR_BADVALUE },
86178825Sdfr	{ "Readonly", SNMP_ERR_READONLY },
87178825Sdfr	{ "General error", SNMP_ERR_GENERR },
88178825Sdfr	{ "No access", SNMP_ERR_NO_ACCESS },
89178825Sdfr	{ "Wrong type", SNMP_ERR_WRONG_TYPE },
90178825Sdfr	{ "Wrong length", SNMP_ERR_WRONG_LENGTH },
91178825Sdfr	{ "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
92178825Sdfr	{ "Wrong value", SNMP_ERR_WRONG_VALUE },
93178825Sdfr	{ "No creation", SNMP_ERR_NO_CREATION },
94178825Sdfr	{ "Inconsistent value", SNMP_ERR_INCONS_VALUE },
95178825Sdfr	{ "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
96233294Sstas	{ "Commit failed", SNMP_ERR_COMMIT_FAILED },
97233294Sstas	{ "Undo failed", SNMP_ERR_UNDO_FAILED },
98178825Sdfr	{ "Authorization error", SNMP_ERR_AUTH_ERR },
99178825Sdfr	{ "Not writable", SNMP_ERR_NOT_WRITEABLE },
100178825Sdfr	{ "Inconsistent name", SNMP_ERR_INCONS_NAME },
101233294Sstas	{ NULL, 0 }
102178825Sdfr};
103178825Sdfr
104178825Sdfr/* This one and any following are exceptions. */
105178825Sdfr#define	SNMP_SYNTAX_UNKNOWN	SNMP_SYNTAX_NOSUCHOBJECT
106178825Sdfr
107178825Sdfrstatic const struct {
108178825Sdfr	const char *str;
109178825Sdfr	enum snmp_syntax stx;
110178825Sdfr} syntax_strings[] = {
111178825Sdfr	{ "Null", SNMP_SYNTAX_NULL },
112178825Sdfr	{ "Integer", SNMP_SYNTAX_INTEGER },
113178825Sdfr	{ "OctetString", SNMP_SYNTAX_OCTETSTRING },
114178825Sdfr	{ "OID", SNMP_SYNTAX_OID },
115178825Sdfr	{ "IpAddress", SNMP_SYNTAX_IPADDRESS },
116178825Sdfr	{ "Counter32", SNMP_SYNTAX_COUNTER },
117178825Sdfr	{ "Gauge", SNMP_SYNTAX_GAUGE },
118178825Sdfr	{ "TimeTicks", SNMP_SYNTAX_TIMETICKS },
119178825Sdfr	{ "Counter64", SNMP_SYNTAX_COUNTER64 },
120178825Sdfr	{ "Unknown", SNMP_SYNTAX_UNKNOWN },
121178825Sdfr};
122178825Sdfr
123178825Sdfrint
124178825Sdfrsnmptool_init(struct snmp_toolinfo *snmptoolctx)
125178825Sdfr{
126178825Sdfr	char *str;
127178825Sdfr	size_t slen;
128178825Sdfr
129178825Sdfr	memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
130178825Sdfr	snmptoolctx->objects = 0;
131178825Sdfr	snmptoolctx->mappings = NULL;
132178825Sdfr	snmptoolctx->flags = SNMP_PDU_GET;	/* XXX */
133178825Sdfr	SLIST_INIT(&snmptoolctx->filelist);
134178825Sdfr	snmp_client_init(&snmp_client);
135178825Sdfr	SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS);
136178825Sdfr
137178825Sdfr	if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
138178825Sdfr		warnx("Error adding file %s to list", bsnmpd_defs);
139178825Sdfr
140178825Sdfr	if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
141178825Sdfr		warnx("Error adding file %s to list", mibII_defs);
142178825Sdfr
143178825Sdfr	/* Read the environment */
144178825Sdfr	if ((str = getenv("SNMPAUTH")) != NULL) {
145178825Sdfr		slen = strlen(str);
146178825Sdfr		if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
147178825Sdfr			snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
148178825Sdfr		else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
149178825Sdfr			snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
150178825Sdfr		else if (slen != 0)
151178825Sdfr			warnx("Bad authentication type - %s in SNMPAUTH", str);
152178825Sdfr	}
153178825Sdfr
154178825Sdfr	if ((str = getenv("SNMPPRIV")) != NULL) {
155233294Sstas		slen = strlen(str);
156233294Sstas		if (slen == strlen("des") && strcasecmp(str, "des") == 0)
157233294Sstas			snmp_client.user.priv_proto = SNMP_PRIV_DES;
158233294Sstas		else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
159178825Sdfr			snmp_client.user.priv_proto = SNMP_PRIV_AES;
160233294Sstas		else if (slen != 0)
161233294Sstas			warnx("Bad privacy type - %s in SNMPPRIV", str);
162178825Sdfr	}
163178825Sdfr
164178825Sdfr	if ((str = getenv("SNMPUSER")) != NULL) {
165178825Sdfr		if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
166178825Sdfr			warnx("Username too long - %s in SNMPUSER", str);
167178825Sdfr			return (-1);
168178825Sdfr		}
169178825Sdfr		if (slen > 0) {
170178825Sdfr			strlcpy(snmp_client.user.sec_name, str,
171178825Sdfr			    sizeof(snmp_client.user.sec_name));
172178825Sdfr			snmp_client.version = SNMP_V3;
173178825Sdfr		}
174178825Sdfr	}
175178825Sdfr
176178825Sdfr	if ((str = getenv("SNMPPASSWD")) != NULL) {
177178825Sdfr		if ((slen = strlen(str)) > MAXSTR)
178178825Sdfr			slen = MAXSTR - 1;
179178825Sdfr		if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
180178825Sdfr			warnx("malloc() failed - %s", strerror(errno));
181178825Sdfr			return (-1);
182178825Sdfr		}
183178825Sdfr		if (slen > 0)
184178825Sdfr			strlcpy(snmptoolctx->passwd, str, slen + 1);
185178825Sdfr	}
186178825Sdfr
187178825Sdfr	return (0);
188178825Sdfr}
189178825Sdfr
190178825Sdfr#define	OBJECT_IDX_LIST(o)	o->info->table_idx->index_list
191178825Sdfr
192178825Sdfr/*
193178825Sdfr * Walk through the file list and import string<->oid mappings from each file.
194178825Sdfr */
195178825Sdfrint32_t
196178825Sdfrsnmp_import_all(struct snmp_toolinfo *snmptoolctx)
197178825Sdfr{
198178825Sdfr	int32_t fc;
199178825Sdfr	struct fname *tmp;
200178825Sdfr
201178825Sdfr	if (snmptoolctx == NULL)
202178825Sdfr		return (-1);
203233294Sstas
204178825Sdfr	if (ISSET_NUMERIC(snmptoolctx))
205178825Sdfr		return (0);
206178825Sdfr
207178825Sdfr	if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
208178825Sdfr		return (-1);
209178825Sdfr
210178825Sdfr	fc = 0;
211178825Sdfr	if (SLIST_EMPTY(&snmptoolctx->filelist)) {
212178825Sdfr		warnx("No files to read OID <-> string conversions from");
213178825Sdfr		return (-1);
214178825Sdfr	} else {
215178825Sdfr		SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
216178825Sdfr			if (tmp->done)
217178825Sdfr				continue;
218178825Sdfr			if (snmp_import_file(snmptoolctx, tmp) < 0) {
219178825Sdfr				fc = -1;
220178825Sdfr				break;
221178825Sdfr			}
222178825Sdfr			fc++;
223178825Sdfr		}
224178825Sdfr	}
225178825Sdfr
226178825Sdfr	snmp_mapping_dump(snmptoolctx);
227178825Sdfr	return (fc);
228178825Sdfr}
229178825Sdfr
230178825Sdfr/*
231178825Sdfr * Add a filename to the file list - the initial idea of keeping a list with all
232178825Sdfr * files to read OIDs from was that an application might want to have loaded in
233178825Sdfr * memory the OIDs from a single file only and when done with them read the OIDs
234178825Sdfr * from another file. This is not used yet but might be a good idea at some
235178825Sdfr * point. Size argument is number of bytes in string including trailing '\0',
236178825Sdfr * not string length.
237178825Sdfr */
238178825Sdfrint32_t
239178825Sdfradd_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
240178825Sdfr    const struct asn_oid *cut, int32_t done)
241178825Sdfr{
242178825Sdfr	char *fstring;
243178825Sdfr	struct fname *entry;
244178825Sdfr
245178825Sdfr	if (snmptoolctx == NULL)
246178825Sdfr		return (-1);
247178825Sdfr
248178825Sdfr	/* Make sure file was not in list. */
249178825Sdfr	SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
250178825Sdfr		if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
251178825Sdfr			return (0);
252178825Sdfr	}
253178825Sdfr
254178825Sdfr	if ((fstring = malloc(strlen(filename) + 1)) == NULL) {
255178825Sdfr		warnx("malloc() failed - %s", strerror(errno));
256178825Sdfr		return (-1);
257178825Sdfr	}
258178825Sdfr
259178825Sdfr	if ((entry = malloc(sizeof(struct fname))) == NULL) {
260178825Sdfr		warnx("malloc() failed - %s", strerror(errno));
261178825Sdfr		free(fstring);
262178825Sdfr		return (-1);
263178825Sdfr	}
264178825Sdfr
265178825Sdfr	memset(entry, 0, sizeof(struct fname));
266178825Sdfr
267178825Sdfr	if (cut != NULL)
268178825Sdfr		asn_append_oid(&(entry->cut), cut);
269178825Sdfr	strlcpy(fstring, filename, strlen(filename) + 1);
270178825Sdfr	entry->name = fstring;
271178825Sdfr	entry->done = done;
272178825Sdfr	SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
273233294Sstas
274233294Sstas	return (1);
275178825Sdfr}
276178825Sdfr
277178825Sdfrvoid
278178825Sdfrfree_filelist(struct snmp_toolinfo *snmptoolctx)
279178825Sdfr{
280178825Sdfr	struct fname *f;
281178825Sdfr
282178825Sdfr	if (snmptoolctx == NULL)
283178825Sdfr		return; /* XXX error handling */
284178825Sdfr
285178825Sdfr	while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
286178825Sdfr		SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
287178825Sdfr		if (f->name)
288178825Sdfr			free(f->name);
289178825Sdfr		free(f);
290178825Sdfr	}
291178825Sdfr}
292178825Sdfr
293178825Sdfrstatic char
294178825Sdfrisvalid_fchar(char c, int pos)
295178825Sdfr{
296178825Sdfr	if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
297178825Sdfr	    (pos != 0 && isdigit(c))){
298178825Sdfr		return (c);
299178825Sdfr	}
300178825Sdfr
301178825Sdfr	if (c == '\0')
302233294Sstas		return (0);
303178825Sdfr
304178825Sdfr	if (!isascii(c) || !isprint(c))
305178825Sdfr		warnx("Unexpected character %#2x", (u_int) c);
306178825Sdfr	else
307178825Sdfr		warnx("Illegal character '%c'", c);
308178825Sdfr
309178825Sdfr	return (-1);
310178825Sdfr}
311178825Sdfr
312178825Sdfr/*
313178825Sdfr * Re-implement getsubopt from scratch, because the second argument is broken
314178825Sdfr * and will not compile with WARNS=5.
315178825Sdfr * Copied from src/contrib/bsnmp/snmpd/main.c.
316178825Sdfr */
317178825Sdfrstatic int
318178825Sdfrgetsubopt1(char **arg, const char *const *options, char **valp, char **optp)
319178825Sdfr{
320178825Sdfr	static const char *const delim = ",\t ";
321178825Sdfr	u_int i;
322178825Sdfr	char *ptr;
323178825Sdfr
324178825Sdfr	*optp = NULL;
325178825Sdfr
326178825Sdfr	/* Skip leading junk. */
327178825Sdfr	for (ptr = *arg; *ptr != '\0'; ptr++)
328178825Sdfr		if (strchr(delim, *ptr) == NULL)
329178825Sdfr			break;
330178825Sdfr	if (*ptr == '\0') {
331178825Sdfr		*arg = ptr;
332178825Sdfr		return (-1);
333178825Sdfr	}
334178825Sdfr	*optp = ptr;
335178825Sdfr
336178825Sdfr	/* Find the end of the option. */
337178825Sdfr	while (*++ptr != '\0')
338178825Sdfr		if (strchr(delim, *ptr) != NULL || *ptr == '=')
339178825Sdfr			break;
340178825Sdfr
341178825Sdfr	if (*ptr != '\0') {
342178825Sdfr		if (*ptr == '=') {
343178825Sdfr			*ptr++ = '\0';
344178825Sdfr			*valp = ptr;
345178825Sdfr			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
346178825Sdfr				ptr++;
347178825Sdfr			if (*ptr != '\0')
348178825Sdfr				*ptr++ = '\0';
349178825Sdfr		} else
350178825Sdfr			*ptr++ = '\0';
351178825Sdfr	}
352178825Sdfr
353178825Sdfr	*arg = ptr;
354178825Sdfr
355178825Sdfr	for (i = 0; *options != NULL; options++, i++)
356178825Sdfr		if (strcmp(*optp, *options) == 0)
357178825Sdfr			return (i);
358178825Sdfr	return (-1);
359178825Sdfr}
360178825Sdfr
361178825Sdfrstatic int32_t
362178825Sdfrparse_path(char *value)
363178825Sdfr{
364178825Sdfr	int32_t i, len;
365178825Sdfr
366178825Sdfr	if (value == NULL)
367178825Sdfr		return (-1);
368178825Sdfr
369178825Sdfr	for (len = 0; len < MAXPATHLEN; len++) {
370178825Sdfr		i = isvalid_fchar(*(value + len), len) ;
371178825Sdfr
372178825Sdfr		if (i == 0)
373178825Sdfr			break;
374178825Sdfr		else if (i < 0)
375178825Sdfr			return (-1);
376178825Sdfr	}
377178825Sdfr
378178825Sdfr	if (len >= MAXPATHLEN || value[len] != '\0') {
379178825Sdfr		warnx("Bad pathname - '%s'", value);
380178825Sdfr		return (-1);
381178825Sdfr	}
382178825Sdfr
383178825Sdfr	return (len);
384178825Sdfr}
385178825Sdfr
386178825Sdfrstatic int32_t
387178825Sdfrparse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
388178825Sdfr    const struct asn_oid *cut)
389178825Sdfr{
390178825Sdfr	int32_t namelen;
391178825Sdfr	char filename[MAXPATHLEN + 1];
392178825Sdfr
393178825Sdfr	if (value == NULL)
394178825Sdfr		return (-1);
395178825Sdfr
396178825Sdfr	do {
397178825Sdfr		memset(filename, 0, MAXPATHLEN + 1);
398178825Sdfr
399178825Sdfr		if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
400178825Sdfr			strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
401178825Sdfr			namelen = strlen(SNMP_DEFS_DIR);
402178825Sdfr		} else if (path != NULL){
403178825Sdfr			strlcpy(filename, path, MAXPATHLEN + 1);
404178825Sdfr			namelen = strlen(path);
405178825Sdfr		} else
406178825Sdfr			namelen = 0;
407178825Sdfr
408178825Sdfr		for ( ; namelen < MAXPATHLEN; value++) {
409178825Sdfr			if (isvalid_fchar(*value, namelen) > 0) {
410178825Sdfr				filename[namelen++] = *value;
411178825Sdfr				continue;
412178825Sdfr			}
413178825Sdfr
414178825Sdfr			if (*value == ',' )
415178825Sdfr				value++;
416178825Sdfr			else if (*value == '\0')
417178825Sdfr				;
418178825Sdfr			else {
419178825Sdfr				if (!isascii(*value) || !isprint(*value))
420178825Sdfr					warnx("Unexpected character %#2x in"
421178825Sdfr					    " filename", (u_int) *value);
422178825Sdfr				else
423178825Sdfr					warnx("Illegal character '%c' in"
424178825Sdfr					    " filename", *value);
425178825Sdfr				return (-1);
426178825Sdfr			}
427178825Sdfr
428178825Sdfr			filename[namelen]='\0';
429178825Sdfr			break;
430178825Sdfr		}
431178825Sdfr
432178825Sdfr		if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
433178825Sdfr			warnx("Filename %s too long", filename);
434178825Sdfr			return (-1);
435178825Sdfr		}
436178825Sdfr
437178825Sdfr		if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
438178825Sdfr			warnx("Error adding file %s to list", filename);
439178825Sdfr			return (-1);
440178825Sdfr		}
441178825Sdfr	} while (*value != '\0');
442178825Sdfr
443178825Sdfr	return(1);
444178825Sdfr}
445178825Sdfr
446178825Sdfrstatic int32_t
447178825Sdfrparse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
448178825Sdfr{
449178825Sdfr	int32_t alen, count, saved_errno, i;
450178825Sdfr	uint32_t val;
451178825Sdfr	char dptr[3];
452178825Sdfr
453178825Sdfr	/* Filter 0x at the beginning */
454178825Sdfr	if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
455178825Sdfr		i = 2;
456178825Sdfr	else
457178825Sdfr		i = 0;
458178825Sdfr
459178825Sdfr	saved_errno = errno;
460178825Sdfr	errno = 0;
461178825Sdfr	for (count = 0; i < alen; i += 2) {
462178825Sdfr		/* XXX: consider strlen(ascii) % 2 != 0 */
463178825Sdfr		dptr[0] = ascii[i];
464178825Sdfr		dptr[1] = ascii[i + 1];
465178825Sdfr		dptr[2] = '\0';
466178825Sdfr		if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
467178825Sdfr			errno = saved_errno;
468178825Sdfr			return (-1);
469178825Sdfr		}
470178825Sdfr		binstr[count] = (uint8_t) val;
471178825Sdfr		if (++count >= binlen) {
472178825Sdfr			warnx("Key %s too long - truncating to %zu octets",
473178825Sdfr			    ascii, binlen);
474178825Sdfr			break;
475178825Sdfr		}
476178825Sdfr	}
477178825Sdfr
478178825Sdfr	return (count);
479178825Sdfr}
480178825Sdfr
481178825Sdfr/*
482178825Sdfr * Functions to parse common input options for client tools and fill in the
483178825Sdfr * snmp_client structure.
484178825Sdfr */
485178825Sdfrint32_t
486178825Sdfrparse_authentication(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
487178825Sdfr{
488178825Sdfr	int32_t count, subopt;
489178825Sdfr	char *val, *option;
490178825Sdfr	const char *const subopts[] = {
491178825Sdfr		"proto",
492178825Sdfr		"key",
493178825Sdfr		NULL
494178825Sdfr	};
495178825Sdfr
496178825Sdfr	assert(opt_arg != NULL);
497178825Sdfr	count = 1;
498178825Sdfr	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
499178825Sdfr		switch (subopt) {
500178825Sdfr		case 0:
501178825Sdfr			if (val == NULL) {
502178825Sdfr				warnx("Suboption 'proto' requires an argument");
503178825Sdfr				return (-1);
504178825Sdfr			}
505178825Sdfr			if (strlen(val) != 3) {
506178825Sdfr				warnx("Unknown auth protocol - %s", val);
507178825Sdfr				return (-1);
508178825Sdfr			}
509178825Sdfr			if (strncasecmp("md5", val, strlen("md5")) == 0)
510178825Sdfr				snmp_client.user.auth_proto =
511178825Sdfr				    SNMP_AUTH_HMAC_MD5;
512178825Sdfr			else if (strncasecmp("sha", val, strlen("sha")) == 0)
513178825Sdfr				snmp_client.user.auth_proto =
514178825Sdfr				    SNMP_AUTH_HMAC_SHA;
515178825Sdfr			else {
516178825Sdfr				warnx("Unknown auth protocol - %s", val);
517178825Sdfr				return (-1);
518178825Sdfr			}
519178825Sdfr			break;
520178825Sdfr		case 1:
521178825Sdfr			if (val == NULL) {
522178825Sdfr				warnx("Suboption 'key' requires an argument");
523178825Sdfr				return (-1);
524178825Sdfr			}
525178825Sdfr			if (parse_ascii(val, snmp_client.user.auth_key,
526178825Sdfr			    SNMP_AUTH_KEY_SIZ) < 0) {
527178825Sdfr				warnx("Bad authentication key- %s", val);
528178825Sdfr				return (-1);
529178825Sdfr			}
530178825Sdfr			break;
531178825Sdfr		default:
532178825Sdfr			warnx("Unknown suboption - '%s'", suboptarg);
533178825Sdfr			return (-1);
534178825Sdfr		}
535178825Sdfr		count += 1;
536178825Sdfr	}
537178825Sdfr	return (2/* count */);
538178825Sdfr}
539178825Sdfr
540178825Sdfrint32_t
541178825Sdfrparse_privacy(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
542178825Sdfr{
543178825Sdfr	int32_t count, subopt;
544178825Sdfr	char *val, *option;
545178825Sdfr	const char *const subopts[] = {
546178825Sdfr		"proto",
547178825Sdfr		"key",
548178825Sdfr		NULL
549178825Sdfr	};
550178825Sdfr
551178825Sdfr	assert(opt_arg != NULL);
552178825Sdfr	count = 1;
553178825Sdfr	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
554178825Sdfr		switch (subopt) {
555178825Sdfr		case 0:
556178825Sdfr			if (val == NULL) {
557178825Sdfr				warnx("Suboption 'proto' requires an argument");
558178825Sdfr				return (-1);
559178825Sdfr			}
560178825Sdfr			if (strlen(val) != 3) {
561178825Sdfr				warnx("Unknown privacy protocol - %s", val);
562178825Sdfr				return (-1);
563178825Sdfr			}
564178825Sdfr			if (strncasecmp("aes", val, strlen("aes")) == 0)
565178825Sdfr				snmp_client.user.priv_proto = SNMP_PRIV_AES;
566178825Sdfr			else if (strncasecmp("des", val, strlen("des")) == 0)
567178825Sdfr				snmp_client.user.priv_proto = SNMP_PRIV_DES;
568178825Sdfr			else {
569178825Sdfr				warnx("Unknown privacy protocol - %s", val);
570178825Sdfr				return (-1);
571178825Sdfr			}
572178825Sdfr			break;
573178825Sdfr		case 1:
574178825Sdfr			if (val == NULL) {
575178825Sdfr				warnx("Suboption 'key' requires an argument");
576178825Sdfr				return (-1);
577178825Sdfr			}
578178825Sdfr			if (parse_ascii(val, snmp_client.user.priv_key,
579178825Sdfr			    SNMP_PRIV_KEY_SIZ) < 0) {
580178825Sdfr				warnx("Bad privacy key- %s", val);
581178825Sdfr				return (-1);
582178825Sdfr			}
583178825Sdfr			break;
584178825Sdfr		default:
585178825Sdfr			warnx("Unknown suboption - '%s'", suboptarg);
586178825Sdfr			return (-1);
587178825Sdfr		}
588178825Sdfr		count += 1;
589178825Sdfr	}
590178825Sdfr	return (2/* count */);
591178825Sdfr}
592178825Sdfr
593178825Sdfrint32_t
594178825Sdfrparse_context(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
595178825Sdfr{
596178825Sdfr	int32_t count, subopt;
597178825Sdfr	char *val, *option;
598178825Sdfr	const char *const subopts[] = {
599178825Sdfr		"context",
600178825Sdfr		"context-engine",
601178825Sdfr		NULL
602178825Sdfr	};
603178825Sdfr
604178825Sdfr	assert(opt_arg != NULL);
605178825Sdfr	count = 1;
606178825Sdfr	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
607178825Sdfr		switch (subopt) {
608178825Sdfr		case 0:
609178825Sdfr			if (val == NULL) {
610178825Sdfr				warnx("Suboption 'context' - no argument");
611178825Sdfr				return (-1);
612178825Sdfr			}
613178825Sdfr			strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
614178825Sdfr			break;
615178825Sdfr		case 1:
616178825Sdfr			if (val == NULL) {
617178825Sdfr				warnx("Suboption 'context-engine' - no argument");
618178825Sdfr				return (-1);
619178825Sdfr			}
620178825Sdfr			if ((snmp_client.clen = parse_ascii(val,
621178825Sdfr			    snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) < 0) {
622178825Sdfr				warnx("Bad EngineID - %s", val);
623178825Sdfr				return (-1);
624178825Sdfr			}
625178825Sdfr			break;
626178825Sdfr		default:
627178825Sdfr			warnx("Unknown suboption - '%s'", suboptarg);
628178825Sdfr			return (-1);
629178825Sdfr		}
630178825Sdfr		count += 1;
631178825Sdfr	}
632178825Sdfr	return (2/* count */);
633178825Sdfr}
634178825Sdfr
635178825Sdfrint32_t
636178825Sdfrparse_user_security(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
637178825Sdfr{
638178825Sdfr	int32_t count, subopt, saved_errno;
639178825Sdfr	char *val, *option;
640178825Sdfr	const char *const subopts[] = {
641178825Sdfr		"engine",
642178825Sdfr		"engine-boots",
643178825Sdfr		"engine-time",
644178825Sdfr		"name",
645178825Sdfr		NULL
646178825Sdfr	};
647178825Sdfr
648178825Sdfr	assert(opt_arg != NULL);
649178825Sdfr	count = 1;
650178825Sdfr	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
651178825Sdfr		switch (subopt) {
652178825Sdfr		case 0:
653178825Sdfr			if (val == NULL) {
654178825Sdfr				warnx("Suboption 'engine' - no argument");
655178825Sdfr				return (-1);
656178825Sdfr			}
657178825Sdfr			snmp_client.engine.engine_len = parse_ascii(val,
658178825Sdfr			    snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
659178825Sdfr			if (snmp_client.engine.engine_len < 0) {
660178825Sdfr				warnx("Bad EngineID - %s", val);
661178825Sdfr				return (-1);
662178825Sdfr			}
663178825Sdfr			break;
664178825Sdfr		case 1:
665178825Sdfr			if (val == NULL) {
666178825Sdfr				warnx("Suboption 'engine-boots' - no argument");
667178825Sdfr				return (-1);
668178825Sdfr			}
669178825Sdfr			saved_errno = errno;
670178825Sdfr			errno = 0;
671178825Sdfr			snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
672178825Sdfr			if (errno != 0) {
673178825Sdfr				warnx("Bad 'engine-boots' value %s - %s", val,
674178825Sdfr				    strerror(errno));
675178825Sdfr				errno = saved_errno;
676178825Sdfr				return (-1);
677178825Sdfr			}
678178825Sdfr			errno = saved_errno;
679178825Sdfr			break;
680178825Sdfr		case 2:
681178825Sdfr			if (val == NULL) {
682178825Sdfr				warnx("Suboption 'engine-time' - no argument");
683178825Sdfr				return (-1);
684178825Sdfr			}
685178825Sdfr			saved_errno = errno;
686178825Sdfr			errno = 0;
687178825Sdfr			snmp_client.engine.engine_time = strtoul(val, NULL, 10);
688178825Sdfr			if (errno != 0) {
689178825Sdfr				warnx("Bad 'engine-time' value %s - %s", val,
690178825Sdfr				    strerror(errno));
691178825Sdfr				errno = saved_errno;
692178825Sdfr				return (-1);
693178825Sdfr			}
694178825Sdfr			errno = saved_errno;
695178825Sdfr			break;
696178825Sdfr		case 3:
697178825Sdfr			strlcpy(snmp_client.user.sec_name, val,
698178825Sdfr			    SNMP_ADM_STR32_SIZ);
699178825Sdfr			break;
700178825Sdfr		default:
701178825Sdfr			warnx("Unknown suboption - '%s'", suboptarg);
702178825Sdfr			return (-1);
703178825Sdfr		}
704178825Sdfr		count += 1;
705178825Sdfr	}
706178825Sdfr	return (2/* count */);
707178825Sdfr}
708178825Sdfr
709178825Sdfrint32_t
710178825Sdfrparse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
711178825Sdfr{
712178825Sdfr	assert(opt_arg != NULL);
713178825Sdfr
714178825Sdfr	if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
715178825Sdfr		return (-1);
716178825Sdfr
717178825Sdfr	return (2);
718178825Sdfr}
719178825Sdfr
720178825Sdfrint32_t
721178825Sdfrparse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
722178825Sdfr{
723178825Sdfr	char path[MAXPATHLEN + 1];
724178825Sdfr	int32_t cut_dflt, len, subopt;
725178825Sdfr	struct asn_oid cut;
726178825Sdfr	char *val, *option;
727178825Sdfr	const char *const subopts[] = {
728178825Sdfr		"cut",
729178825Sdfr		"path",
730178825Sdfr		"file",
731178825Sdfr		NULL
732178825Sdfr	};
733178825Sdfr
734178825Sdfr#define	INC_CUT		0
735178825Sdfr#define	INC_PATH	1
736178825Sdfr#define	INC_LIST	2
737178825Sdfr
738178825Sdfr	assert(opt_arg != NULL);
739178825Sdfr
740178825Sdfr	/* if (opt == 'i')
741178825Sdfr		free_filelist(snmptoolctx, ); */
742178825Sdfr	/*
743178825Sdfr	 * This function should be called only after getopt(3) - otherwise if
744178825Sdfr	 * no previous validation of opt_arg strlen() may not return what is
745178825Sdfr	 * expected.
746178825Sdfr	 */
747178825Sdfr
748178825Sdfr	path[0] = '\0';
749178825Sdfr	memset(&cut, 0, sizeof(struct asn_oid));
750178825Sdfr	cut_dflt = -1;
751178825Sdfr
752178825Sdfr	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
753178825Sdfr		switch (subopt) {
754178825Sdfr		    case INC_CUT:
755178825Sdfr			if (val == NULL) {
756178825Sdfr				warnx("Suboption 'cut' requires an argument");
757178825Sdfr				return (-1);
758178825Sdfr			} else {
759178825Sdfr				if (snmp_parse_numoid(val, &cut) < 0)
760178825Sdfr					return (-1);
761178825Sdfr			}
762178825Sdfr			cut_dflt = 1;
763178825Sdfr			break;
764178825Sdfr
765178825Sdfr		    case INC_PATH:
766178825Sdfr			if ((len = parse_path(val)) < 0)
767178825Sdfr				return (-1);
768178825Sdfr			strlcpy(path, val, len + 1);
769178825Sdfr			break;
770178825Sdfr
771178825Sdfr		    case INC_LIST:
772178825Sdfr			if (val == NULL)
773178825Sdfr				return (-1);
774178825Sdfr			if (cut_dflt == -1)
775178825Sdfr				len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
776178825Sdfr			else
777178825Sdfr				len = parse_flist(snmptoolctx, val, path, &cut);
778178825Sdfr			if (len < 0)
779178825Sdfr				return (-1);
780178825Sdfr			break;
781178825Sdfr
782178825Sdfr		    default:
783178825Sdfr			warnx("Unknown suboption - '%s'", suboptarg);
784178825Sdfr			return (-1);
785178825Sdfr		}
786178825Sdfr	}
787178825Sdfr
788178825Sdfr	/* XXX: Fix me - returning two is wrong here */
789178825Sdfr	return (2);
790178825Sdfr}
791178825Sdfr
792178825Sdfrint32_t
793233294Sstasparse_server(char *opt_arg)
794233294Sstas{
795233294Sstas	assert(opt_arg != NULL);
796178825Sdfr
797233294Sstas	if (snmp_parse_server(&snmp_client, opt_arg) < 0)
798233294Sstas		return (-1);
799233294Sstas
800178825Sdfr	if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
801233294Sstas		if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL + 1)))
802233294Sstas		    == NULL) {
803178825Sdfr			syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
804233294Sstas			return (-1);
805233294Sstas		}
806233294Sstas		strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
807178825Sdfr	}
808233294Sstas
809233294Sstas	return (2);
810233294Sstas}
811178825Sdfr
812233294Sstasint32_t
813233294Sstasparse_timeout(char *opt_arg)
814233294Sstas{
815233294Sstas	int32_t v, saved_errno;
816233294Sstas
817233294Sstas	assert(opt_arg != NULL);
818233294Sstas
819233294Sstas	saved_errno = errno;
820233294Sstas	errno = 0;
821233294Sstas
822233294Sstas	v = strtol(opt_arg, NULL, 10);
823178825Sdfr	if (errno != 0) {
824178825Sdfr		warnx( "Error parsing timeout value - %s", strerror(errno));
825233294Sstas		errno = saved_errno;
826178825Sdfr		return (-1);
827178825Sdfr	}
828178825Sdfr
829178825Sdfr	snmp_client.timeout.tv_sec = v;
830178825Sdfr	errno = saved_errno;
831178825Sdfr	return (2);
832178825Sdfr}
833178825Sdfr
834178825Sdfrint32_t
835178825Sdfrparse_retry(char *opt_arg)
836178825Sdfr{
837178825Sdfr	uint32_t v;
838178825Sdfr	int32_t saved_errno;
839233294Sstas
840178825Sdfr	assert(opt_arg != NULL);
841178825Sdfr
842178825Sdfr	saved_errno = errno;
843178825Sdfr	errno = 0;
844178825Sdfr
845178825Sdfr	v = strtoul(opt_arg, NULL, 10);
846178825Sdfr	if (errno != 0) {
847178825Sdfr		warnx("Error parsing retries count - %s", strerror(errno));
848178825Sdfr		errno = saved_errno;
849178825Sdfr		return (-1);
850233294Sstas	}
851178825Sdfr
852178825Sdfr	snmp_client.retries = v;
853178825Sdfr	errno = saved_errno;
854178825Sdfr	return (2);
855178825Sdfr}
856178825Sdfr
857178825Sdfrint32_t
858178825Sdfrparse_version(char *opt_arg)
859178825Sdfr{
860178825Sdfr	uint32_t v;
861178825Sdfr	int32_t saved_errno;
862178825Sdfr
863178825Sdfr	assert(opt_arg != NULL);
864178825Sdfr
865178825Sdfr	saved_errno = errno;
866178825Sdfr	errno = 0;
867178825Sdfr
868233294Sstas	v = strtoul(opt_arg, NULL, 10);
869233294Sstas	if (errno != 0) {
870233294Sstas		warnx("Error parsing version - %s", strerror(errno));
871233294Sstas		errno = saved_errno;
872233294Sstas		return (-1);
873233294Sstas	}
874233294Sstas
875233294Sstas	switch (v) {
876233294Sstas		case 1:
877233294Sstas			snmp_client.version = SNMP_V1;
878233294Sstas			break;
879233294Sstas		case 2:
880233294Sstas			snmp_client.version = SNMP_V2c;
881233294Sstas			break;
882233294Sstas		case 3:
883233294Sstas			snmp_client.version = SNMP_V3;
884233294Sstas			break;
885233294Sstas		default:
886233294Sstas			warnx("Unsupported SNMP version - %u", v);
887233294Sstas			errno = saved_errno;
888233294Sstas			return (-1);
889233294Sstas	}
890233294Sstas
891233294Sstas	errno = saved_errno;
892233294Sstas	return (2);
893233294Sstas}
894233294Sstas
895233294Sstasint32_t
896233294Sstasparse_local_path(char *opt_arg)
897178825Sdfr{
898178825Sdfr	assert(opt_arg != NULL);
899178825Sdfr
900178825Sdfr	if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
901178825Sdfr		warnx("Filename too long - %s", opt_arg);
902178825Sdfr		return (-1);
903178825Sdfr	}
904178825Sdfr
905178825Sdfr	strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
906178825Sdfr	return (2);
907178825Sdfr}
908178825Sdfr
909178825Sdfrint32_t
910178825Sdfrparse_buflen(char *opt_arg)
911178825Sdfr{
912178825Sdfr	uint32_t size;
913178825Sdfr	int32_t saved_errno;
914178825Sdfr
915178825Sdfr	assert(opt_arg != NULL);
916178825Sdfr
917178825Sdfr	saved_errno = errno;
918178825Sdfr	errno = 0;
919178825Sdfr
920178825Sdfr	size = strtoul(opt_arg, NULL, 10);
921178825Sdfr	if (errno != 0) {
922178825Sdfr		warnx("Error parsing buffer size - %s", strerror(errno));
923178825Sdfr		errno = saved_errno;
924178825Sdfr		return (-1);
925178825Sdfr	}
926178825Sdfr
927178825Sdfr	if (size > MAX_BUFF_SIZE) {
928178825Sdfr		warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
929178825Sdfr		errno = saved_errno;
930178825Sdfr		return (-1);
931178825Sdfr	}
932178825Sdfr
933178825Sdfr	snmp_client.txbuflen = snmp_client.rxbuflen = size;
934178825Sdfr	errno = saved_errno;
935178825Sdfr	return (2);
936178825Sdfr}
937178825Sdfr
938178825Sdfrint32_t
939233294Sstasparse_debug(void)
940178825Sdfr{
941178825Sdfr	snmp_client.dump_pdus = 1;
942178825Sdfr	return (1);
943178825Sdfr}
944178825Sdfr
945178825Sdfrint32_t
946178825Sdfrparse_discovery(struct snmp_toolinfo *snmptoolctx)
947178825Sdfr{
948178825Sdfr	SET_EDISCOVER(snmptoolctx);
949178825Sdfr	snmp_client.version = SNMP_V3;
950233294Sstas	return (1);
951178825Sdfr}
952178825Sdfr
953178825Sdfrint32_t
954178825Sdfrparse_local_key(struct snmp_toolinfo *snmptoolctx)
955178825Sdfr{
956178825Sdfr	SET_LOCALKEY(snmptoolctx);
957178825Sdfr	snmp_client.version = SNMP_V3;
958178825Sdfr	return (1);
959178825Sdfr}
960178825Sdfr
961178825Sdfrint32_t
962178825Sdfrparse_num_oids(struct snmp_toolinfo *snmptoolctx)
963178825Sdfr{
964178825Sdfr	SET_NUMERIC(snmptoolctx);
965178825Sdfr	return (1);
966178825Sdfr}
967178825Sdfr
968178825Sdfrint32_t
969178825Sdfrparse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
970178825Sdfr{
971178825Sdfr	assert(opt_arg != NULL);
972178825Sdfr
973178825Sdfr	if (strlen(opt_arg) > strlen("verbose")) {
974178825Sdfr		warnx( "Invalid output option - %s",opt_arg);
975178825Sdfr		return (-1);
976178825Sdfr	}
977178825Sdfr
978178825Sdfr	if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
979178825Sdfr		SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
980178825Sdfr	else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
981178825Sdfr		SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
982178825Sdfr	else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
983178825Sdfr		SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
984178825Sdfr	else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
985178825Sdfr		SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
986178825Sdfr	else {
987178825Sdfr		warnx( "Invalid output option - %s", opt_arg);
988178825Sdfr		return (-1);
989178825Sdfr	}
990178825Sdfr
991178825Sdfr	return (2);
992178825Sdfr}
993178825Sdfr
994178825Sdfrint32_t
995178825Sdfrparse_errors(struct snmp_toolinfo *snmptoolctx)
996178825Sdfr{
997178825Sdfr	SET_RETRY(snmptoolctx);
998178825Sdfr	return (1);
999178825Sdfr}
1000178825Sdfr
1001178825Sdfrint32_t
1002178825Sdfrparse_skip_access(struct snmp_toolinfo *snmptoolctx)
1003178825Sdfr{
1004178825Sdfr	SET_ERRIGNORE(snmptoolctx);
1005178825Sdfr	return (1);
1006178825Sdfr}
1007178825Sdfr
1008178825Sdfrchar *
1009178825Sdfrsnmp_parse_suboid(char *str, struct asn_oid *oid)
1010178825Sdfr{
1011178825Sdfr	char *endptr;
1012178825Sdfr	asn_subid_t suboid;
1013178825Sdfr
1014178825Sdfr	if (*str == '.')
1015178825Sdfr		str++;
1016178825Sdfr
1017178825Sdfr	if (*str < '0' || *str > '9')
1018178825Sdfr		return (str);
1019178825Sdfr
1020178825Sdfr	do {
1021178825Sdfr		suboid = strtoul(str, &endptr, 10);
1022178825Sdfr		if ((asn_subid_t) suboid > ASN_MAXID) {
1023178825Sdfr			warnx("Suboid %u > ASN_MAXID", suboid);
1024178825Sdfr			return (NULL);
1025178825Sdfr		}
1026178825Sdfr		if (snmp_suboid_append(oid, suboid) < 0)
1027178825Sdfr			return (NULL);
1028178825Sdfr		str = endptr + 1;
1029178825Sdfr	} while (*endptr == '.');
1030178825Sdfr
1031178825Sdfr	return (endptr);
1032178825Sdfr}
1033178825Sdfr
1034233294Sstasstatic char *
1035178825Sdfrsnmp_int2asn_oid(char *str, struct asn_oid *oid)
1036178825Sdfr{
1037178825Sdfr	char *endptr;
1038178825Sdfr	int32_t v, saved_errno;
1039178825Sdfr
1040178825Sdfr	saved_errno = errno;
1041178825Sdfr	errno = 0;
1042178825Sdfr
1043178825Sdfr	v = strtol(str, &endptr, 10);
1044178825Sdfr	if (errno != 0) {
1045178825Sdfr		warnx("Integer value %s not supported - %s", str,
1046178825Sdfr		    strerror(errno));
1047178825Sdfr		errno = saved_errno;
1048178825Sdfr		return (NULL);
1049178825Sdfr	}
1050178825Sdfr	errno = saved_errno;
1051178825Sdfr
1052178825Sdfr	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1053178825Sdfr		return (NULL);
1054178825Sdfr
1055178825Sdfr	return (endptr);
1056178825Sdfr}
1057178825Sdfr
1058178825Sdfr/* It is a bit weird to have a table indexed by OID but still... */
1059178825Sdfrstatic char *
1060178825Sdfrsnmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
1061178825Sdfr    struct asn_oid *oid)
1062178825Sdfr{
1063178825Sdfr	int32_t i;
1064178825Sdfr	char string[MAXSTR], *endptr;
1065178825Sdfr	struct snmp_object obj;
1066178825Sdfr
1067178825Sdfr	for (i = 0; i < MAXSTR; i++)
1068178825Sdfr		if (isalpha (*(str + i)) == 0)
1069178825Sdfr			break;
1070178825Sdfr
1071178825Sdfr	endptr = str + i;
1072178825Sdfr	memset(&obj, 0, sizeof(struct snmp_object));
1073178825Sdfr	if (i == 0) {
1074178825Sdfr		if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
1075178825Sdfr			return (NULL);
1076178825Sdfr		if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
1077178825Sdfr			return (NULL);
1078178825Sdfr	} else {
1079178825Sdfr		strlcpy(string, str, i + 1);
1080178825Sdfr		string[i] = '\0';
1081178825Sdfr		if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
1082178825Sdfr			warnx("Unknown string - %s",string);
1083178825Sdfr			return (NULL);
1084178825Sdfr		}
1085178825Sdfr		free(string);
1086178825Sdfr	}
1087178825Sdfr
1088178825Sdfr	asn_append_oid(oid, &(obj.val.var));
1089178825Sdfr	return (endptr);
1090178825Sdfr}
1091178825Sdfr
1092178825Sdfrstatic char *
1093178825Sdfrsnmp_ip2asn_oid(char *str, struct asn_oid *oid)
1094178825Sdfr{
1095178825Sdfr	uint32_t v;
1096178825Sdfr	int32_t i;
1097178825Sdfr	char *endptr, *ptr;
1098178825Sdfr
1099178825Sdfr	ptr = str;
1100178825Sdfr	for (i = 0; i < 4; i++) {
1101178825Sdfr		v = strtoul(ptr, &endptr, 10);
1102178825Sdfr		if (v > 0xff)
1103178825Sdfr			return (NULL);
1104178825Sdfr		if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
1105178825Sdfr			return (NULL);
1106178825Sdfr		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1107178825Sdfr			return (NULL);
1108178825Sdfr		ptr = endptr + 1;
1109178825Sdfr	}
1110178825Sdfr
1111178825Sdfr	return (endptr);
1112178825Sdfr}
1113178825Sdfr
1114178825Sdfr/* 32-bit counter, gauge, timeticks. */
1115178825Sdfrstatic char *
1116178825Sdfrsnmp_uint2asn_oid(char *str, struct asn_oid *oid)
1117178825Sdfr{
1118178825Sdfr	char *endptr;
1119178825Sdfr	uint32_t v;
1120178825Sdfr	int32_t saved_errno;
1121178825Sdfr
1122178825Sdfr	saved_errno = errno;
1123178825Sdfr	errno = 0;
1124178825Sdfr
1125178825Sdfr	v = strtoul(str, &endptr, 10);
1126178825Sdfr	if (errno != 0) {
1127178825Sdfr		warnx("Integer value %s not supported - %s\n", str,
1128178825Sdfr		    strerror(errno));
1129178825Sdfr		errno = saved_errno;
1130178825Sdfr		return (NULL);
1131178825Sdfr	}
1132178825Sdfr	errno = saved_errno;
1133178825Sdfr	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1134178825Sdfr		return (NULL);
1135178825Sdfr
1136178825Sdfr	return (endptr);
1137178825Sdfr}
1138178825Sdfr
1139178825Sdfrstatic char *
1140178825Sdfrsnmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
1141178825Sdfr{
1142178825Sdfr	char *endptr;
1143178825Sdfr	uint64_t v;
1144178825Sdfr	int32_t saved_errno;
1145178825Sdfr
1146178825Sdfr	saved_errno = errno;
1147178825Sdfr	errno = 0;
1148178825Sdfr
1149178825Sdfr	v = strtoull(str, &endptr, 10);
1150178825Sdfr
1151178825Sdfr	if (errno != 0) {
1152178825Sdfr		warnx("Integer value %s not supported - %s", str,
1153178825Sdfr		    strerror(errno));
1154178825Sdfr		errno = saved_errno;
1155178825Sdfr		return (NULL);
1156178825Sdfr	}
1157178825Sdfr	errno = saved_errno;
1158178825Sdfr	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
1159178825Sdfr		return (NULL);
1160178825Sdfr
1161178825Sdfr	if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
1162178825Sdfr		return (NULL);
1163178825Sdfr
1164178825Sdfr	return (endptr);
1165178825Sdfr}
1166178825Sdfr
1167178825Sdfrenum snmp_syntax
1168178825Sdfrparse_syntax(char *str)
1169178825Sdfr{
1170178825Sdfr	int32_t i;
1171178825Sdfr
1172178825Sdfr	for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
1173178825Sdfr		if (strncmp(syntax_strings[i].str, str,
1174178825Sdfr		    strlen(syntax_strings[i].str)) == 0)
1175178825Sdfr			return (syntax_strings[i].stx);
1176178825Sdfr	}
1177178825Sdfr
1178178825Sdfr	return (SNMP_SYNTAX_NULL);
1179178825Sdfr}
1180178825Sdfr
1181178825Sdfrstatic char *
1182178825Sdfrsnmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
1183178825Sdfr    struct index *idx, struct snmp_object *object)
1184178825Sdfr{
1185178825Sdfr	char *ptr;
1186178825Sdfr	int32_t i;
1187178825Sdfr	enum snmp_syntax stx;
1188178825Sdfr	char syntax[MAX_CMD_SYNTAX_LEN];
1189178825Sdfr
1190178825Sdfr	ptr = str;
1191178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
1192178825Sdfr		for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
1193178825Sdfr			if (*(ptr + i) == ':')
1194178825Sdfr				break;
1195178825Sdfr		}
1196178825Sdfr
1197178825Sdfr		if (i >= MAX_CMD_SYNTAX_LEN) {
1198178825Sdfr			warnx("Unknown syntax in OID - %s", str);
1199178825Sdfr			return (NULL);
1200178825Sdfr		}
1201178825Sdfr		/* Expect a syntax string here. */
1202178825Sdfr		if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
1203178825Sdfr			warnx("Invalid  syntax - %s",syntax);
1204178825Sdfr			return (NULL);
1205178825Sdfr		}
1206178825Sdfr
1207178825Sdfr		if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
1208178825Sdfr			warnx("Syntax mismatch - %d expected, %d given",
1209178825Sdfr			    idx->syntax, stx);
1210178825Sdfr			return (NULL);
1211178825Sdfr		}
1212178825Sdfr		/*
1213178825Sdfr		 * That is where the suboid started + the syntax length + one
1214178825Sdfr		 * character for ':'.
1215178825Sdfr		 */
1216178825Sdfr		ptr = str + i + 1;
1217178825Sdfr	} else
1218178825Sdfr		stx = idx->syntax;
1219178825Sdfr
1220178825Sdfr	switch (stx) {
1221178825Sdfr		case SNMP_SYNTAX_INTEGER:
1222178825Sdfr			return (snmp_int2asn_oid(ptr, &(object->val.var)));
1223178825Sdfr		case SNMP_SYNTAX_OID:
1224178825Sdfr			return (snmp_oid2asn_oid(snmptoolctx, ptr,
1225178825Sdfr			    &(object->val.var)));
1226178825Sdfr		case SNMP_SYNTAX_IPADDRESS:
1227178825Sdfr			return (snmp_ip2asn_oid(ptr, &(object->val.var)));
1228178825Sdfr		case SNMP_SYNTAX_COUNTER:
1229178825Sdfr			/* FALLTHROUGH */
1230178825Sdfr		case SNMP_SYNTAX_GAUGE:
1231178825Sdfr			/* FALLTHROUGH */
1232178825Sdfr		case SNMP_SYNTAX_TIMETICKS:
1233178825Sdfr			return (snmp_uint2asn_oid(ptr, &(object->val.var)));
1234178825Sdfr		case SNMP_SYNTAX_COUNTER64:
1235178825Sdfr			return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
1236178825Sdfr		case SNMP_SYNTAX_OCTETSTRING:
1237178825Sdfr			return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
1238178825Sdfr		default:
1239178825Sdfr			/* NOTREACHED */
1240178825Sdfr			break;
1241178825Sdfr	}
1242178825Sdfr
1243178825Sdfr	return (NULL);
1244178825Sdfr}
1245178825Sdfr
1246178825Sdfrchar *
1247178825Sdfrsnmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
1248178825Sdfr    struct snmp_object *object)
1249178825Sdfr{
1250178825Sdfr	char *ptr;
1251178825Sdfr	struct index *temp;
1252178825Sdfr
1253178825Sdfr	if (object->info->table_idx == NULL)
1254178825Sdfr		return (NULL);
1255178825Sdfr
1256178825Sdfr	ptr = NULL;
1257178825Sdfr	STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
1258178825Sdfr		if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
1259178825Sdfr		    == NULL)
1260178825Sdfr			return (NULL);
1261178825Sdfr
1262178825Sdfr		if (*ptr != ',' && *ptr != ']')
1263178825Sdfr			return (NULL);
1264178825Sdfr		str = ptr + 1;
1265178825Sdfr	}
1266178825Sdfr
1267178825Sdfr	if (ptr == NULL || *ptr != ']') {
1268178825Sdfr		warnx("Mismatching index - %s", str);
1269178825Sdfr		return (NULL);
1270178825Sdfr	}
1271178825Sdfr
1272178825Sdfr	return (ptr + 1);
1273178825Sdfr}
1274178825Sdfr
1275178825Sdfr/*
1276178825Sdfr * Fill in the struct asn_oid member of snmp_value with suboids from input.
1277178825Sdfr * If an error occurs - print message on stderr and return (-1).
1278178825Sdfr * If all is ok - return the length of the oid.
1279178825Sdfr */
1280178825Sdfrint32_t
1281178825Sdfrsnmp_parse_numoid(char *argv, struct asn_oid *var)
1282178825Sdfr{
1283178825Sdfr	char *endptr, *str;
1284178825Sdfr	asn_subid_t suboid;
1285178825Sdfr
1286178825Sdfr	str = argv;
1287178825Sdfr
1288178825Sdfr	if (*str == '.')
1289178825Sdfr		str++;
1290178825Sdfr
1291178825Sdfr	do {
1292178825Sdfr		if (var->len == ASN_MAXOIDLEN) {
1293178825Sdfr			warnx("Oid too long - %u", var->len);
1294178825Sdfr			return (-1);
1295178825Sdfr		}
1296178825Sdfr
1297178825Sdfr		suboid = strtoul(str, &endptr, 10);
1298178825Sdfr		if (suboid > ASN_MAXID) {
1299178825Sdfr			warnx("Oid too long - %u", var->len);
1300178825Sdfr			return (-1);
1301178825Sdfr		}
1302178825Sdfr
1303178825Sdfr		var->subs[var->len++] = suboid;
1304178825Sdfr		str = endptr + 1;
1305178825Sdfr	} while ( *endptr == '.');
1306178825Sdfr
1307178825Sdfr	if (*endptr != '\0') {
1308178825Sdfr		warnx("Invalid oid string - %s", argv);
1309178825Sdfr		return (-1);
1310178825Sdfr	}
1311178825Sdfr
1312178825Sdfr	return (var->len);
1313178825Sdfr}
1314178825Sdfr
1315178825Sdfr/* Append a length 1 suboid to an asn_oid structure. */
1316178825Sdfrint32_t
1317178825Sdfrsnmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
1318178825Sdfr{
1319178825Sdfr	if (var == NULL)
1320178825Sdfr		return (-1);
1321178825Sdfr
1322178825Sdfr	if (var->len >= ASN_MAXOIDLEN) {
1323178825Sdfr		warnx("Oid too long - %u", var->len);
1324178825Sdfr		return (-1);
1325178825Sdfr	}
1326178825Sdfr
1327178825Sdfr	var->subs[var->len++] = suboid;
1328178825Sdfr
1329178825Sdfr	return (1);
1330178825Sdfr}
1331178825Sdfr
1332178825Sdfr/* Pop the last suboid from an asn_oid structure. */
1333178825Sdfrint32_t
1334178825Sdfrsnmp_suboid_pop(struct asn_oid *var)
1335178825Sdfr{
1336178825Sdfr	asn_subid_t suboid;
1337178825Sdfr
1338178825Sdfr	if (var == NULL)
1339178825Sdfr		return (-1);
1340178825Sdfr
1341178825Sdfr	if (var->len < 1)
1342178825Sdfr		return (-1);
1343178825Sdfr
1344178825Sdfr	suboid = var->subs[--(var->len)];
1345178825Sdfr	var->subs[var->len] = 0;
1346178825Sdfr
1347178825Sdfr	return (suboid);
1348178825Sdfr}
1349178825Sdfr
1350178825Sdfr/*
1351178825Sdfr * Parse the command-line provided string into an OID - alocate memory for a new
1352178825Sdfr * snmp object, fill in its fields and insert it in the object list. A
1353178825Sdfr * (snmp_verify_inoid_f) function must be provided to validate the input string.
1354178825Sdfr */
1355178825Sdfrint32_t
1356178825Sdfrsnmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
1357178825Sdfr    char *string)
1358178825Sdfr{
1359178825Sdfr	struct snmp_object *obj;
1360178825Sdfr
1361178825Sdfr	if (snmptoolctx == NULL)
1362178825Sdfr		return (-1);
1363178825Sdfr
1364178825Sdfr	/* XXX-BZ does that chack make sense? */
1365178825Sdfr	if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
1366178825Sdfr		warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
1367178825Sdfr		return (-1);
1368178825Sdfr	}
1369178825Sdfr
1370178825Sdfr	if ((obj = malloc(sizeof(struct snmp_object))) == NULL) {
1371178825Sdfr		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
1372178825Sdfr		return (-1);
1373178825Sdfr	}
1374178825Sdfr
1375178825Sdfr	memset(obj, 0, sizeof(struct snmp_object));
1376178825Sdfr	if (func(snmptoolctx, obj, string) < 0) {
1377178825Sdfr		warnx("Invalid OID - %s", string);
1378178825Sdfr		free(obj);
1379178825Sdfr		return (-1);
1380178825Sdfr	}
1381178825Sdfr
1382178825Sdfr	snmptoolctx->objects++;
1383178825Sdfr	SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
1384178825Sdfr
1385178825Sdfr	return (1);
1386178825Sdfr}
1387178825Sdfr
1388178825Sdfr/* Given an OID, find it in the object list and remove it. */
1389178825Sdfrint32_t
1390178825Sdfrsnmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1391178825Sdfr{
1392178825Sdfr	struct snmp_object *temp;
1393178825Sdfr
1394178825Sdfr	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
1395178825Sdfr		warnx("Object list already empty");
1396178825Sdfr		return (-1);
1397178825Sdfr	}
1398178825Sdfr
1399178825Sdfr
1400178825Sdfr	SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
1401178825Sdfr		if (asn_compare_oid(&(temp->val.var), oid) == 0)
1402178825Sdfr			break;
1403178825Sdfr
1404178825Sdfr	if (temp == NULL) {
1405178825Sdfr		warnx("No such object in list");
1406178825Sdfr		return (-1);
1407178825Sdfr	}
1408178825Sdfr
1409178825Sdfr	SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
1410178825Sdfr	if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1411178825Sdfr	    temp->val.v.octetstring.octets != NULL)
1412178825Sdfr		free(temp->val.v.octetstring.octets);
1413178825Sdfr	free(temp);
1414178825Sdfr
1415178825Sdfr	return (1);
1416178825Sdfr}
1417178825Sdfr
1418178825Sdfrstatic void
1419178825Sdfrsnmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
1420178825Sdfr{
1421178825Sdfr	struct snmp_object *o;
1422178825Sdfr
1423178825Sdfr	while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
1424178825Sdfr		SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
1425178825Sdfr
1426178825Sdfr		if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1427178825Sdfr		    o->val.v.octetstring.octets != NULL)
1428178825Sdfr			free(o->val.v.octetstring.octets);
1429178825Sdfr		free(o);
1430178825Sdfr	}
1431178825Sdfr}
1432178825Sdfr
1433178825Sdfr/* Do all possible memory release before exit. */
1434178825Sdfrvoid
1435178825Sdfrsnmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
1436178825Sdfr{
1437178825Sdfr	if (snmp_client.chost != NULL) {
1438178825Sdfr		free(snmp_client.chost);
1439178825Sdfr		snmp_client.chost = NULL;
1440178825Sdfr	}
1441178825Sdfr
1442178825Sdfr	if (snmp_client.cport != NULL) {
1443178825Sdfr		free(snmp_client.cport);
1444178825Sdfr		snmp_client.cport = NULL;
1445178825Sdfr	}
1446178825Sdfr
1447178825Sdfr	snmp_mapping_free(snmptoolctx);
1448178825Sdfr	free_filelist(snmptoolctx);
1449178825Sdfr	snmp_object_freeall(snmptoolctx);
1450178825Sdfr
1451178825Sdfr	if (snmptoolctx->passwd != NULL) {
1452178825Sdfr		free(snmptoolctx->passwd);
1453178825Sdfr		snmptoolctx->passwd = NULL;
1454178825Sdfr	}
1455178825Sdfr}
1456178825Sdfr
1457178825Sdfr/*
1458178825Sdfr * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
1459178825Sdfr * function should check whether the variable is consistent in this PDU
1460178825Sdfr * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
1461178825Sdfr * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
1462178825Sdfr * function actually adds the variable to the PDU and must not be NULL.
1463178825Sdfr */
1464178825Sdfrint32_t
1465178825Sdfrsnmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
1466178825Sdfr    snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
1467178825Sdfr    struct snmp_pdu *pdu, int32_t maxcount)
1468178825Sdfr{
1469178825Sdfr	int32_t nbindings, abind;
1470178825Sdfr	struct snmp_object *obj;
1471178825Sdfr
1472178825Sdfr	if (pdu == NULL || afunc == NULL)
1473178825Sdfr		return (-1);
1474178825Sdfr
1475178825Sdfr	/* Return 0 in case of no more work todo. */
1476178825Sdfr	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
1477178825Sdfr		return (0);
1478178825Sdfr
1479178825Sdfr	if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
1480178825Sdfr		warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
1481178825Sdfr		return (-1);
1482178825Sdfr	}
1483178825Sdfr
1484178825Sdfr	nbindings = 0;
1485178825Sdfr	SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
1486178825Sdfr		if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
1487178825Sdfr			nbindings = -1;
1488178825Sdfr			break;
1489178825Sdfr		}
1490178825Sdfr		if ((abind = afunc(pdu, obj)) < 0) {
1491178825Sdfr			nbindings = -1;
1492178825Sdfr			break;
1493178825Sdfr		}
1494178825Sdfr
1495178825Sdfr		if (abind > 0) {
1496178825Sdfr			/* Do not put more varbindings than requested. */
1497178825Sdfr			if (++nbindings >= maxcount)
1498178825Sdfr				break;
1499178825Sdfr		}
1500178825Sdfr	}
1501178825Sdfr
1502178825Sdfr	return (nbindings);
1503178825Sdfr}
1504178825Sdfr
1505178825Sdfr/*
1506178825Sdfr * Locate an object in the object list and set a corresponding error status.
1507178825Sdfr */
1508178825Sdfrint32_t
1509178825Sdfrsnmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
1510178825Sdfr    struct snmp_value *err_value, int32_t error_status)
1511178825Sdfr{
1512178825Sdfr	struct snmp_object *obj;
1513178825Sdfr
1514178825Sdfr	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
1515178825Sdfr		return (-1);
1516178825Sdfr
1517178825Sdfr	SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
1518178825Sdfr		if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
1519178825Sdfr			obj->error = error_status;
1520178825Sdfr			return (1);
1521178825Sdfr		}
1522178825Sdfr
1523178825Sdfr	return (0);
1524178825Sdfr}
1525178825Sdfr
1526178825Sdfr/*
1527178825Sdfr * Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
1528178825Sdfr * but don't compare syntaxes - when sending a request PDU they must be null.
1529178825Sdfr * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
1530178825Sdfr * checks and some other checks skipped.
1531178825Sdfr */
1532178825Sdfrint32_t
1533178825Sdfrsnmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1534178825Sdfr{
1535178825Sdfr	uint32_t i;
1536178825Sdfr
1537178825Sdfr	for (i = 0; i < req->nbindings; i++) {
1538178825Sdfr		if (asn_compare_oid(&req->bindings[i].var,
1539178825Sdfr		    &resp->bindings[i].var) != 0) {
1540233294Sstas			warnx("Bad OID in response");
1541178825Sdfr			return (-1);
1542178825Sdfr		}
1543178825Sdfr
1544178825Sdfr		if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
1545178825Sdfr		    == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
1546178825Sdfr		    SNMP_SYNTAX_NOSUCHINSTANCE))
1547178825Sdfr			return (0);
1548178825Sdfr	}
1549178825Sdfr
1550178825Sdfr	return (1);
1551178825Sdfr}
1552178825Sdfr
1553178825Sdfrint32_t
1554178825Sdfrsnmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1555178825Sdfr{
1556178825Sdfr	int32_t N, R, M, r;
1557178825Sdfr
1558178825Sdfr	if (req->error_status > (int32_t) resp->nbindings) {
1559178825Sdfr		warnx("Bad number of bindings in response");
1560178825Sdfr		return (-1);
1561178825Sdfr	}
1562178825Sdfr
1563233294Sstas	for (N = 0; N < req->error_status; N++) {
1564178825Sdfr		if (asn_is_suboid(&req->bindings[N].var,
1565178825Sdfr		    &resp->bindings[N].var) == 0)
1566178825Sdfr			return (0);
1567178825Sdfr		if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
1568178825Sdfr			return (0);
1569178825Sdfr	}
1570178825Sdfr
1571178825Sdfr	for (R = N , r = N; R  < (int32_t) req->nbindings; R++) {
1572178825Sdfr		for (M = 0; M < req->error_index && (r + M) <
1573178825Sdfr		    (int32_t) resp->nbindings; M++) {
1574178825Sdfr			if (asn_is_suboid(&req->bindings[R].var,
1575178825Sdfr			    &resp->bindings[r + M].var) == 0)
1576178825Sdfr				return (0);
1577178825Sdfr
1578178825Sdfr			if (resp->bindings[r + M].syntax ==
1579178825Sdfr			    SNMP_SYNTAX_ENDOFMIBVIEW) {
1580178825Sdfr				M++;
1581178825Sdfr				break;
1582178825Sdfr			}
1583178825Sdfr		}
1584178825Sdfr		r += M;
1585178825Sdfr	}
1586178825Sdfr
1587178825Sdfr	return (0);
1588178825Sdfr}
1589178825Sdfr
1590233294Sstasint32_t
1591178825Sdfrsnmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1592178825Sdfr{
1593178825Sdfr	uint32_t i;
1594178825Sdfr
1595178825Sdfr	for (i = 0; i < req->nbindings; i++) {
1596178825Sdfr		if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
1597178825Sdfr		    == 0)
1598178825Sdfr			return (0);
1599178825Sdfr
1600178825Sdfr		if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
1601178825Sdfr		    SNMP_SYNTAX_ENDOFMIBVIEW)
1602178825Sdfr			return (0);
1603178825Sdfr	}
1604178825Sdfr
1605178825Sdfr	return (1);
1606178825Sdfr}
1607233294Sstas
1608178825Sdfr/*
1609178825Sdfr * Should be called to check a response to get/getnext/getbulk.
1610178825Sdfr */
1611178825Sdfrint32_t
1612178825Sdfrsnmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1613178825Sdfr{
1614233294Sstas	if (resp == NULL || req == NULL)
1615178825Sdfr		return (-2);
1616178825Sdfr
1617178825Sdfr	if (resp->version != req->version) {
1618178825Sdfr		warnx("Response has wrong version");
1619178825Sdfr		return (-1);
1620178825Sdfr	}
1621178825Sdfr
1622233294Sstas	if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
1623178825Sdfr		warnx("Error - No Such Name");
1624178825Sdfr		return (0);
1625178825Sdfr	}
1626178825Sdfr
1627178825Sdfr	if (resp->error_status != SNMP_ERR_NOERROR) {
1628178825Sdfr		warnx("Error %d in response", resp->error_status);
1629178825Sdfr		return (-1);
1630178825Sdfr	}
1631178825Sdfr
1632178825Sdfr	if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
1633178825Sdfr		warnx("Bad number of bindings in response");
1634178825Sdfr		return (-1);
1635178825Sdfr	}
1636178825Sdfr
1637178825Sdfr	switch (req->type) {
1638178825Sdfr		case SNMP_PDU_GET:
1639178825Sdfr			return (snmp_parse_get_resp(resp,req));
1640178825Sdfr		case SNMP_PDU_GETBULK:
1641178825Sdfr			return (snmp_parse_getbulk_resp(resp,req));
1642178825Sdfr		case SNMP_PDU_GETNEXT:
1643178825Sdfr			return (snmp_parse_getnext_resp(resp,req));
1644178825Sdfr		default:
1645178825Sdfr			/* NOTREACHED */
1646178825Sdfr			break;
1647178825Sdfr	}
1648178825Sdfr
1649233294Sstas	return (-2);
1650178825Sdfr}
1651178825Sdfr
1652178825Sdfrstatic void
1653178825Sdfrsnmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1654178825Sdfr    uint32_t len, uint8_t *octets)
1655178825Sdfr{
1656178825Sdfr	char *buf;
1657178825Sdfr
1658233294Sstas	if (len == 0 || octets == NULL)
1659233294Sstas		return;
1660178825Sdfr
1661178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1662178825Sdfr		fprintf(stdout, "%s : ",
1663178825Sdfr		    syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
1664178825Sdfr
1665178825Sdfr	if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
1666178825Sdfr		fprintf(stdout, "%s", buf);
1667178825Sdfr		free(buf);
1668178825Sdfr	}
1669178825Sdfr}
1670178825Sdfr
1671178825Sdfrstatic void
1672178825Sdfrsnmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1673178825Sdfr    struct asn_oid *oid)
1674178825Sdfr{
1675178825Sdfr	uint32_t i;
1676178825Sdfr	uint8_t *s;
1677178825Sdfr
1678178825Sdfr	if ((s = malloc(oid->subs[0] + 1)) == NULL)
1679178825Sdfr		syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
1680178825Sdfr	else {
1681178825Sdfr		for (i = 0; i < oid->subs[0]; i++)
1682178825Sdfr			s[i] = (u_char) (oid->subs[i + 1]);
1683178825Sdfr
1684178825Sdfr		snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
1685178825Sdfr		free(s);
1686178825Sdfr	}
1687178825Sdfr}
1688178825Sdfr
1689178825Sdfr/*
1690178825Sdfr * Check and output syntax type and value.
1691178825Sdfr */
1692178825Sdfrstatic void
1693178825Sdfrsnmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1694178825Sdfr{
1695178825Sdfr	char oid_string[ASN_OIDSTRLEN];
1696233294Sstas	struct snmp_object obj;
1697178825Sdfr
1698178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1699178825Sdfr		fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
1700178825Sdfr
1701178825Sdfr	if(!ISSET_NUMERIC(snmptoolctx)) {
1702178825Sdfr		memset(&obj, 0, sizeof(struct snmp_object));
1703233294Sstas		asn_append_oid(&(obj.val.var), oid);
1704178825Sdfr
1705178825Sdfr		if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
1706178825Sdfr			fprintf(stdout, "%s" , obj.info->string);
1707178825Sdfr		else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
1708178825Sdfr			fprintf(stdout, "%s" , obj.info->string);
1709178825Sdfr		else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
1710178825Sdfr			fprintf(stdout, "%s" , obj.info->string);
1711178825Sdfr		else {
1712178825Sdfr			(void) asn_oid2str_r(oid, oid_string);
1713178825Sdfr			fprintf(stdout, "%s", oid_string);
1714178825Sdfr		}
1715178825Sdfr	} else {
1716178825Sdfr		(void) asn_oid2str_r(oid, oid_string);
1717178825Sdfr		fprintf(stdout, "%s", oid_string);
1718178825Sdfr	}
1719178825Sdfr}
1720178825Sdfr
1721178825Sdfrstatic void
1722178825Sdfrsnmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
1723178825Sdfr    int32_t int_val)
1724178825Sdfr{
1725178825Sdfr	char *string;
1726178825Sdfr
1727178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1728178825Sdfr		fprintf(stdout, "%s : ",
1729178825Sdfr		    syntax_strings[SNMP_SYNTAX_INTEGER].str);
1730178825Sdfr
1731178825Sdfr	if (enums != NULL && (string = enum_string_lookup(enums, int_val))
1732178825Sdfr	    != NULL)
1733178825Sdfr		fprintf(stdout, "%s", string);
1734178825Sdfr	else
1735178825Sdfr		fprintf(stdout, "%d", int_val);
1736178825Sdfr}
1737178825Sdfr
1738178825Sdfrstatic void
1739178825Sdfrsnmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
1740178825Sdfr{
1741178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1742178825Sdfr		fprintf(stdout, "%s : ",
1743178825Sdfr		    syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
1744178825Sdfr
1745178825Sdfr	fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1746178825Sdfr}
1747178825Sdfr
1748178825Sdfrstatic void
1749178825Sdfrsnmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
1750178825Sdfr{
1751178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1752178825Sdfr		fprintf(stdout, "%s : ",
1753178825Sdfr		    syntax_strings[SNMP_SYNTAX_COUNTER].str);
1754178825Sdfr
1755178825Sdfr	fprintf(stdout, "%u", counter);
1756178825Sdfr}
1757178825Sdfr
1758178825Sdfrstatic void
1759178825Sdfrsnmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
1760178825Sdfr{
1761178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1762178825Sdfr		fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
1763178825Sdfr
1764178825Sdfr	fprintf(stdout, "%u", gauge);
1765178825Sdfr}
1766178825Sdfr
1767178825Sdfrstatic void
1768178825Sdfrsnmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
1769178825Sdfr{
1770178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1771178825Sdfr		fprintf(stdout, "%s : ",
1772178825Sdfr		    syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
1773178825Sdfr
1774178825Sdfr	fprintf(stdout, "%u", ticks);
1775178825Sdfr}
1776178825Sdfr
1777178825Sdfrstatic void
1778178825Sdfrsnmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
1779178825Sdfr{
1780178825Sdfr	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1781178825Sdfr		fprintf(stdout, "%s : ",
1782178825Sdfr		    syntax_strings[SNMP_SYNTAX_COUNTER64].str);
1783178825Sdfr
1784178825Sdfr	fprintf(stdout,"%ju", counter64);
1785178825Sdfr}
1786178825Sdfr
1787178825Sdfrint32_t
1788178825Sdfrsnmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
1789178825Sdfr    struct snmp_oid2str *entry)
1790178825Sdfr{
1791178825Sdfr	if (val == NULL)
1792178825Sdfr		return (-1);
1793178825Sdfr
1794178825Sdfr	if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1795178825Sdfr		fprintf(stdout, " = ");
1796178825Sdfr
1797178825Sdfr	switch (val->syntax) {
1798178825Sdfr	    case SNMP_SYNTAX_INTEGER:
1799178825Sdfr		if (entry != NULL)
1800178825Sdfr			snmp_output_int(snmptoolctx, entry->snmp_enum,
1801178825Sdfr			    val->v.integer);
1802178825Sdfr		else
1803178825Sdfr			snmp_output_int(snmptoolctx, NULL, val->v.integer);
1804178825Sdfr		break;
1805178825Sdfr
1806178825Sdfr	    case SNMP_SYNTAX_OCTETSTRING:
1807178825Sdfr		if (entry != NULL)
1808178825Sdfr			snmp_output_octetstring(snmptoolctx, entry->tc,
1809178825Sdfr			    val->v.octetstring.len, val->v.octetstring.octets);
1810178825Sdfr		else
1811178825Sdfr			snmp_output_octetstring(snmptoolctx, SNMP_STRING,
1812178825Sdfr			    val->v.octetstring.len, val->v.octetstring.octets);
1813178825Sdfr		break;
1814178825Sdfr
1815178825Sdfr	    case SNMP_SYNTAX_OID:
1816178825Sdfr		snmp_output_oid_value(snmptoolctx, &(val->v.oid));
1817178825Sdfr		break;
1818178825Sdfr
1819178825Sdfr	    case SNMP_SYNTAX_IPADDRESS:
1820178825Sdfr		snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
1821178825Sdfr		break;
1822178825Sdfr
1823178825Sdfr	    case SNMP_SYNTAX_COUNTER:
1824178825Sdfr		snmp_output_counter(snmptoolctx, val->v.uint32);
1825178825Sdfr		break;
1826178825Sdfr
1827178825Sdfr	    case SNMP_SYNTAX_GAUGE:
1828178825Sdfr		snmp_output_gauge(snmptoolctx, val->v.uint32);
1829178825Sdfr		break;
1830178825Sdfr
1831178825Sdfr	    case SNMP_SYNTAX_TIMETICKS:
1832178825Sdfr		snmp_output_ticks(snmptoolctx, val->v.uint32);
1833178825Sdfr		break;
1834178825Sdfr
1835178825Sdfr	    case SNMP_SYNTAX_COUNTER64:
1836178825Sdfr		snmp_output_counter64(snmptoolctx, val->v.counter64);
1837178825Sdfr		break;
1838178825Sdfr
1839178825Sdfr	    case SNMP_SYNTAX_NOSUCHOBJECT:
1840178825Sdfr		fprintf(stdout, "No Such Object\n");
1841178825Sdfr		return (val->syntax);
1842178825Sdfr
1843178825Sdfr	    case SNMP_SYNTAX_NOSUCHINSTANCE:
1844178825Sdfr		fprintf(stdout, "No Such Instance\n");
1845178825Sdfr		return (val->syntax);
1846178825Sdfr
1847178825Sdfr	    case SNMP_SYNTAX_ENDOFMIBVIEW:
1848178825Sdfr		fprintf(stdout, "End of Mib View\n");
1849178825Sdfr		return (val->syntax);
1850178825Sdfr
1851178825Sdfr	    case SNMP_SYNTAX_NULL:
1852178825Sdfr		/* NOTREACHED */
1853178825Sdfr		fprintf(stdout, "agent returned NULL Syntax\n");
1854178825Sdfr		return (val->syntax);
1855178825Sdfr
1856178825Sdfr	    default:
1857178825Sdfr		/* NOTREACHED - If here - then all went completely wrong. */
1858178825Sdfr		fprintf(stdout, "agent returned unknown syntax\n");
1859178825Sdfr		return (-1);
1860178825Sdfr	}
1861178825Sdfr
1862178825Sdfr	fprintf(stdout, "\n");
1863178825Sdfr
1864178825Sdfr	return (0);
1865178825Sdfr}
1866178825Sdfr
1867178825Sdfrstatic int32_t
1868178825Sdfrsnmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
1869178825Sdfr    struct snmp_value *val)
1870178825Sdfr{
1871178825Sdfr	int32_t rc;
1872178825Sdfr	asn_subid_t suboid;
1873178825Sdfr
1874178825Sdfr	if (obj == NULL || val == NULL)
1875178825Sdfr		return (-1);
1876178825Sdfr
1877178825Sdfr	if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
1878178825Sdfr		return (-1);
1879178825Sdfr
1880178825Sdfr	memset(obj, 0, sizeof(struct snmp_object));
1881178825Sdfr	asn_append_oid(&(obj->val.var), &(val->var));
1882178825Sdfr	obj->val.syntax = val->syntax;
1883178825Sdfr
1884178825Sdfr	if (obj->val.syntax > 0)
1885178825Sdfr		rc = snmp_lookup_leafstring(snmptoolctx, obj);
1886178825Sdfr	else
1887178825Sdfr		rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
1888178825Sdfr
1889233294Sstas	(void) snmp_suboid_append(&(val->var), suboid);
1890178825Sdfr	(void) snmp_suboid_append(&(obj->val.var), suboid);
1891178825Sdfr
1892178825Sdfr	return (rc);
1893178825Sdfr}
1894178825Sdfr
1895178825Sdfrstatic int32_t
1896178825Sdfrsnmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
1897178825Sdfr    struct asn_oid *oid)
1898178825Sdfr{
1899178825Sdfr	uint8_t ip[4];
1900178825Sdfr	uint32_t bytes = 1;
1901178825Sdfr	uint64_t cnt64;
1902178825Sdfr	struct asn_oid temp, out;
1903233294Sstas
1904178825Sdfr	if (oid->len < bytes)
1905178825Sdfr		return (-1);
1906178825Sdfr
1907178825Sdfr	memset(&temp, 0, sizeof(struct asn_oid));
1908178825Sdfr	asn_append_oid(&temp, oid);
1909178825Sdfr
1910178825Sdfr	switch (stx->syntax) {
1911178825Sdfr	    case SNMP_SYNTAX_INTEGER:
1912178825Sdfr		snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
1913178825Sdfr		break;
1914178825Sdfr
1915178825Sdfr	    case SNMP_SYNTAX_OCTETSTRING:
1916178825Sdfr		if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
1917178825Sdfr		    ASN_MAXOCTETSTRING))
1918178825Sdfr			return (-1);
1919178825Sdfr		snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
1920178825Sdfr		bytes += temp.subs[0];
1921178825Sdfr		break;
1922178825Sdfr
1923178825Sdfr	    case SNMP_SYNTAX_OID:
1924178825Sdfr		if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
1925178825Sdfr		    ASN_MAXOIDLEN))
1926178825Sdfr			return (-1);
1927178825Sdfr
1928178825Sdfr		bytes += temp.subs[0];
1929178825Sdfr		memset(&out, 0, sizeof(struct asn_oid));
1930178825Sdfr		asn_slice_oid(&out, &temp, 1, bytes);
1931178825Sdfr		snmp_output_oid_value(snmptoolctx, &out);
1932178825Sdfr		break;
1933178825Sdfr
1934178825Sdfr	    case SNMP_SYNTAX_IPADDRESS:
1935178825Sdfr		if (temp.len < 4)
1936178825Sdfr			return (-1);
1937178825Sdfr		for (bytes = 0; bytes < 4; bytes++)
1938178825Sdfr			ip[bytes] = temp.subs[bytes];
1939178825Sdfr
1940178825Sdfr		snmp_output_ipaddress(snmptoolctx, ip);
1941178825Sdfr		bytes = 4;
1942178825Sdfr		break;
1943178825Sdfr
1944178825Sdfr	    case SNMP_SYNTAX_COUNTER:
1945178825Sdfr		snmp_output_counter(snmptoolctx, temp.subs[0]);
1946178825Sdfr		break;
1947178825Sdfr
1948178825Sdfr	    case SNMP_SYNTAX_GAUGE:
1949178825Sdfr		snmp_output_gauge(snmptoolctx, temp.subs[0]);
1950178825Sdfr		break;
1951178825Sdfr
1952178825Sdfr	    case SNMP_SYNTAX_TIMETICKS:
1953178825Sdfr		snmp_output_ticks(snmptoolctx, temp.subs[0]);
1954178825Sdfr		break;
1955178825Sdfr
1956178825Sdfr	    case SNMP_SYNTAX_COUNTER64:
1957178825Sdfr		if (oid->len < 2)
1958233294Sstas			return (-1);
1959233294Sstas		bytes = 2;
1960233294Sstas		memcpy(&cnt64, temp.subs, bytes);
1961233294Sstas		snmp_output_counter64(snmptoolctx, cnt64);
1962233294Sstas		break;
1963233294Sstas
1964233294Sstas	    default:
1965233294Sstas		return (-1);
1966178825Sdfr	}
1967178825Sdfr
1968178825Sdfr	return (bytes);
1969178825Sdfr}
1970178825Sdfr
1971178825Sdfrstatic int32_t
1972178825Sdfrsnmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
1973178825Sdfr{
1974178825Sdfr	int32_t i, first, len;
1975178825Sdfr	struct asn_oid oid;
1976178825Sdfr	struct index *temp;
1977178825Sdfr
1978178825Sdfr	if (ISSET_NUMERIC(snmptoolctx))
1979178825Sdfr		return (-1);
1980178825Sdfr
1981178825Sdfr	if (o->info->table_idx == NULL) {
1982178825Sdfr		fprintf(stdout,"%s.%d", o->info->string,
1983178825Sdfr		    o->val.var.subs[o->val.var.len - 1]);
1984178825Sdfr		return (1);
1985178825Sdfr	}
1986178825Sdfr
1987178825Sdfr	fprintf(stdout,"%s[", o->info->string);
1988178825Sdfr	memset(&oid, 0, sizeof(struct asn_oid));
1989178825Sdfr
1990178825Sdfr	len = 1;
1991178825Sdfr	asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
1992178825Sdfr	    o->val.var.len);
1993178825Sdfr
1994178825Sdfr	first = 1;
1995178825Sdfr	STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
1996178825Sdfr		if(first)
1997178825Sdfr			first = 0;
1998178825Sdfr		else
1999178825Sdfr			fprintf(stdout, ", ");
2000178825Sdfr		if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
2001178825Sdfr			break;
2002178825Sdfr		len += i;
2003178825Sdfr		memset(&oid, 0, sizeof(struct asn_oid));
2004178825Sdfr		asn_slice_oid(&oid, &(o->val.var),
2005178825Sdfr		    (o->info->table_idx->var.len + len), o->val.var.len + 1);
2006178825Sdfr	}
2007178825Sdfr
2008178825Sdfr	fprintf(stdout,"]");
2009178825Sdfr	return (1);
2010178825Sdfr}
2011178825Sdfr
2012178825Sdfrvoid
2013178825Sdfrsnmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
2014178825Sdfr{
2015178825Sdfr	char buf[ASN_OIDSTRLEN];
2016178825Sdfr	struct snmp_object object;
2017178825Sdfr
2018178825Sdfr	if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
2019178825Sdfr		fprintf(stdout,"Invalid error index in PDU\n");
2020178825Sdfr		return;
2021178825Sdfr	}
2022178825Sdfr
2023178825Sdfr	fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
2024178825Sdfr	    snmp_client.cport);
2025178825Sdfr
2026178825Sdfr	if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, &object,
2027178825Sdfr	    &(pdu->bindings[pdu->error_index - 1])) > 0))
2028178825Sdfr		snmp_output_object(snmptoolctx, &object);
2029178825Sdfr	else {
2030178825Sdfr		asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
2031178825Sdfr		fprintf(stdout,"%s", buf);
2032178825Sdfr	}
2033178825Sdfr
2034178825Sdfr	fprintf(stdout," caused error - ");
2035178825Sdfr	if ((pdu->error_status > 0) && (pdu->error_status <=
2036178825Sdfr	    SNMP_ERR_INCONS_NAME))
2037178825Sdfr		fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
2038178825Sdfr	else
2039178825Sdfr		fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
2040178825Sdfr}
2041178825Sdfr
2042178825Sdfrint32_t
2043178825Sdfrsnmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
2044233294Sstas    struct asn_oid *root)
2045178825Sdfr{
2046178825Sdfr	int32_t error;
2047178825Sdfr	char p[ASN_OIDSTRLEN];
2048178825Sdfr	uint32_t i;
2049178825Sdfr	struct snmp_object object;
2050178825Sdfr
2051178825Sdfr	i = error = 0;
2052178825Sdfr	while (i < pdu->nbindings) {
2053178825Sdfr		if (root != NULL && !(asn_is_suboid(root,
2054178825Sdfr		    &(pdu->bindings[i].var))))
2055178825Sdfr			break;
2056178825Sdfr
2057178825Sdfr		if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
2058178825Sdfr			if (!ISSET_NUMERIC(snmptoolctx) &&
2059178825Sdfr			    (snmp_fill_object(snmptoolctx, &object,
2060178825Sdfr			    &(pdu->bindings[i])) > 0))
2061178825Sdfr				snmp_output_object(snmptoolctx, &object);
2062178825Sdfr			else {
2063178825Sdfr				asn_oid2str_r(&(pdu->bindings[i].var), p);
2064178825Sdfr				fprintf(stdout, "%s", p);
2065178825Sdfr			}
2066178825Sdfr		}
2067178825Sdfr		error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]), object.info);
2068178825Sdfr		i++;
2069178825Sdfr	}
2070178825Sdfr
2071178825Sdfr	if (error)
2072178825Sdfr		return (-1);
2073178825Sdfr
2074178825Sdfr	return (i);
2075178825Sdfr}
2076178825Sdfr
2077178825Sdfrvoid
2078178825Sdfrsnmp_output_engine(void)
2079178825Sdfr{
2080178825Sdfr	uint32_t i;
2081178825Sdfr	char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
2082178825Sdfr
2083178825Sdfr	cptr = engine;
2084178825Sdfr	for (i = 0; i < snmp_client.engine.engine_len; i++)
2085178825Sdfr		cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
2086178825Sdfr	*cptr++ = '\0';
2087178825Sdfr
2088178825Sdfr	fprintf(stdout, "Engine ID 0x%s\n", engine);
2089178825Sdfr	fprintf(stdout, "Boots : %u\t\tTime : %d\n",
2090178825Sdfr	    snmp_client.engine.engine_boots,
2091178825Sdfr	    snmp_client.engine.engine_time);
2092178825Sdfr}
2093233294Sstas
2094178825Sdfrvoid
2095178825Sdfrsnmp_output_keys(void)
2096178825Sdfr{
2097178825Sdfr	uint32_t i, keylen = 0;
2098178825Sdfr	char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
2099178825Sdfr
2100178825Sdfr	fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
2101178825Sdfr	if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
2102178825Sdfr		fprintf(stdout, "MD5 : 0x");
2103178825Sdfr		keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
2104178825Sdfr	} else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
2105178825Sdfr		fprintf(stdout, "SHA : 0x");
2106178825Sdfr		keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
2107178825Sdfr	}
2108178825Sdfr	if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
2109178825Sdfr		cptr = extkey;
2110178825Sdfr		for (i = 0; i < keylen; i++)
2111178825Sdfr			cptr += sprintf(cptr, "%.2x",
2112178825Sdfr			    snmp_client.user.auth_key[i]);
2113178825Sdfr		*cptr++ = '\0';
2114178825Sdfr		fprintf(stdout, "%s\n", extkey);
2115178825Sdfr	}
2116178825Sdfr
2117178825Sdfr	if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
2118178825Sdfr		fprintf(stdout, "DES : 0x");
2119178825Sdfr		keylen = SNMP_PRIV_DES_KEY_SIZ;
2120178825Sdfr	} else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
2121178825Sdfr		fprintf(stdout, "AES : 0x");
2122178825Sdfr		keylen = SNMP_PRIV_AES_KEY_SIZ;
2123178825Sdfr	}
2124178825Sdfr	if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
2125178825Sdfr		cptr = extkey;
2126178825Sdfr		for (i = 0; i < keylen; i++)
2127178825Sdfr			cptr += sprintf(cptr, "%.2x",
2128178825Sdfr			    snmp_client.user.priv_key[i]);
2129178825Sdfr		*cptr++ = '\0';
2130178825Sdfr		fprintf(stdout, "%s\n", extkey);
2131178825Sdfr	}
2132178825Sdfr}
2133178825Sdfr