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