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