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