1216295Ssyrinx/*-
2216295Ssyrinx * Copyright (c) 2005-2006 The FreeBSD Project
3216295Ssyrinx * All rights reserved.
4216295Ssyrinx *
5216295Ssyrinx * Author: Shteryana Shopova <syrinx@FreeBSD.org>
6216295Ssyrinx *
7216295Ssyrinx * Redistribution of this software and documentation and use in source and
8216295Ssyrinx * binary forms, with or without modification, are permitted provided that
9216295Ssyrinx * the following conditions are met:
10216295Ssyrinx *
11216295Ssyrinx * 1. Redistributions of source code or documentation must retain the above
12216295Ssyrinx *    copyright notice, this list of conditions and the following disclaimer.
13216295Ssyrinx * 2. Redistributions in binary form must reproduce the above copyright
14216295Ssyrinx *    notice, this list of conditions and the following disclaimer in the
15216295Ssyrinx *    documentation and/or other materials provided with the distribution.
16216295Ssyrinx *
17216295Ssyrinx * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18216295Ssyrinx * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19216295Ssyrinx * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20216295Ssyrinx * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21216295Ssyrinx * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22216295Ssyrinx * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23216295Ssyrinx * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24216295Ssyrinx * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25216295Ssyrinx * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26216295Ssyrinx * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27216295Ssyrinx * SUCH DAMAGE.
28216295Ssyrinx *
29216295Ssyrinx * Helper functions for snmp client tools
30216295Ssyrinx *
31216295Ssyrinx * $FreeBSD: stable/10/usr.sbin/bsnmpd/tools/libbsnmptools/bsnmptools.c 311595 2017-01-07 08:46:16Z ngie $
32216295Ssyrinx */
33216295Ssyrinx
34310903Sngie#include <sys/param.h>
35216295Ssyrinx#include <sys/queue.h>
36216295Ssyrinx#include <sys/uio.h>
37216295Ssyrinx
38216295Ssyrinx#include <assert.h>
39216295Ssyrinx#include <ctype.h>
40216295Ssyrinx#include <err.h>
41216295Ssyrinx#include <errno.h>
42216295Ssyrinx#include <fcntl.h>
43216295Ssyrinx#include <stdio.h>
44216295Ssyrinx#include <stdlib.h>
45216295Ssyrinx#include <string.h>
46216295Ssyrinx#include <syslog.h>
47216295Ssyrinx#include <unistd.h>
48216295Ssyrinx
49216295Ssyrinx#include <bsnmp/asn1.h>
50216295Ssyrinx#include <bsnmp/snmp.h>
51216295Ssyrinx#include <bsnmp/snmpclient.h>
52216295Ssyrinx#include "bsnmptc.h"
53216295Ssyrinx#include "bsnmptools.h"
54216295Ssyrinx
55216295Ssyrinx/* Internal varibale to turn on library debugging for testing and to
56216295Ssyrinx * find bugs. It is not exported via the header file.
57216295Ssyrinx * XXX should we cover it by some #ifdef BSNMPTOOLS_DEBUG? */
58216295Ssyrinxint _bsnmptools_debug = 0;
59216295Ssyrinx
60216295Ssyrinx/* Default files to import mapping from if none explicitly provided. */
61216295Ssyrinx#define	bsnmpd_defs		"/usr/share/snmp/defs/tree.def"
62216295Ssyrinx#define	mibII_defs		"/usr/share/snmp/defs/mibII_tree.def"
63216295Ssyrinx
64216295Ssyrinx/*
65216295Ssyrinx * The .iso.org.dod oid that has to be prepended to every OID when requesting
66216295Ssyrinx * a value.
67216295Ssyrinx */
68216295Ssyrinxconst struct asn_oid IsoOrgDod_OID = {
69216295Ssyrinx	3, { 1, 3, 6 }
70216295Ssyrinx};
71216295Ssyrinx
72216295Ssyrinx
73216295Ssyrinx#define	SNMP_ERR_UNKNOWN	0
74216295Ssyrinx
75216295Ssyrinx/*
76216295Ssyrinx * An array of error strings corresponding to error definitions from libbsnmp.
77216295Ssyrinx */
78216295Ssyrinxstatic const struct {
79216295Ssyrinx	const char *str;
80216295Ssyrinx	int32_t error;
81216295Ssyrinx} error_strings[] = {
82216295Ssyrinx	{ "Unknown", SNMP_ERR_UNKNOWN },
83216295Ssyrinx	{ "Too big ", SNMP_ERR_TOOBIG },
84216295Ssyrinx	{ "No such Name", SNMP_ERR_NOSUCHNAME },
85216295Ssyrinx	{ "Bad Value", SNMP_ERR_BADVALUE },
86216295Ssyrinx	{ "Readonly", SNMP_ERR_READONLY },
87216295Ssyrinx	{ "General error", SNMP_ERR_GENERR },
88216295Ssyrinx	{ "No access", SNMP_ERR_NO_ACCESS },
89216295Ssyrinx	{ "Wrong type", SNMP_ERR_WRONG_TYPE },
90228990Suqs	{ "Wrong length", SNMP_ERR_WRONG_LENGTH },
91216295Ssyrinx	{ "Wrong encoding", SNMP_ERR_WRONG_ENCODING },
92216295Ssyrinx	{ "Wrong value", SNMP_ERR_WRONG_VALUE },
93216295Ssyrinx	{ "No creation", SNMP_ERR_NO_CREATION },
94216295Ssyrinx	{ "Inconsistent value", SNMP_ERR_INCONS_VALUE },
95216295Ssyrinx	{ "Resource unavailable", SNMP_ERR_RES_UNAVAIL },
96216295Ssyrinx	{ "Commit failed", SNMP_ERR_COMMIT_FAILED },
97216295Ssyrinx	{ "Undo failed", SNMP_ERR_UNDO_FAILED },
98216295Ssyrinx	{ "Authorization error", SNMP_ERR_AUTH_ERR },
99216295Ssyrinx	{ "Not writable", SNMP_ERR_NOT_WRITEABLE },
100216295Ssyrinx	{ "Inconsistent name", SNMP_ERR_INCONS_NAME },
101216295Ssyrinx	{ NULL, 0 }
102216295Ssyrinx};
103216295Ssyrinx
104216295Ssyrinx/* This one and any following are exceptions. */
105216295Ssyrinx#define	SNMP_SYNTAX_UNKNOWN	SNMP_SYNTAX_NOSUCHOBJECT
106216295Ssyrinx
107216295Ssyrinxstatic const struct {
108216295Ssyrinx	const char *str;
109216295Ssyrinx	enum snmp_syntax stx;
110216295Ssyrinx} syntax_strings[] = {
111216295Ssyrinx	{ "Null", SNMP_SYNTAX_NULL },
112216295Ssyrinx	{ "Integer", SNMP_SYNTAX_INTEGER },
113216295Ssyrinx	{ "OctetString", SNMP_SYNTAX_OCTETSTRING },
114216295Ssyrinx	{ "OID", SNMP_SYNTAX_OID },
115216295Ssyrinx	{ "IpAddress", SNMP_SYNTAX_IPADDRESS },
116216295Ssyrinx	{ "Counter32", SNMP_SYNTAX_COUNTER },
117216295Ssyrinx	{ "Gauge", SNMP_SYNTAX_GAUGE },
118216295Ssyrinx	{ "TimeTicks", SNMP_SYNTAX_TIMETICKS },
119216295Ssyrinx	{ "Counter64", SNMP_SYNTAX_COUNTER64 },
120310903Sngie	{ "Unknown", SNMP_SYNTAX_UNKNOWN },
121216295Ssyrinx};
122216295Ssyrinx
123216295Ssyrinxint
124216295Ssyrinxsnmptool_init(struct snmp_toolinfo *snmptoolctx)
125216295Ssyrinx{
126216295Ssyrinx	char *str;
127216295Ssyrinx	size_t slen;
128216295Ssyrinx
129216295Ssyrinx	memset(snmptoolctx, 0, sizeof(struct snmp_toolinfo));
130216295Ssyrinx	snmptoolctx->objects = 0;
131216295Ssyrinx	snmptoolctx->mappings = NULL;
132216295Ssyrinx	snmptoolctx->flags = SNMP_PDU_GET;	/* XXX */
133216295Ssyrinx	SLIST_INIT(&snmptoolctx->filelist);
134216295Ssyrinx	snmp_client_init(&snmp_client);
135229933Ssyrinx	SET_MAXREP(snmptoolctx, SNMP_MAX_REPETITIONS);
136216295Ssyrinx
137216295Ssyrinx	if (add_filename(snmptoolctx, bsnmpd_defs, &IsoOrgDod_OID, 0) < 0)
138216295Ssyrinx		warnx("Error adding file %s to list", bsnmpd_defs);
139216295Ssyrinx
140216295Ssyrinx	if (add_filename(snmptoolctx, mibII_defs, &IsoOrgDod_OID, 0) < 0)
141216295Ssyrinx		warnx("Error adding file %s to list", mibII_defs);
142216295Ssyrinx
143216295Ssyrinx	/* Read the environment */
144216295Ssyrinx	if ((str = getenv("SNMPAUTH")) != NULL) {
145216295Ssyrinx		slen = strlen(str);
146216295Ssyrinx		if (slen == strlen("md5") && strcasecmp(str, "md5") == 0)
147216295Ssyrinx			snmp_client.user.auth_proto = SNMP_AUTH_HMAC_MD5;
148216295Ssyrinx		else if (slen == strlen("sha")&& strcasecmp(str, "sha") == 0)
149216295Ssyrinx			snmp_client.user.auth_proto = SNMP_AUTH_HMAC_SHA;
150216295Ssyrinx		else if (slen != 0)
151216295Ssyrinx			warnx("Bad authentication type - %s in SNMPAUTH", str);
152216295Ssyrinx	}
153216295Ssyrinx
154216295Ssyrinx	if ((str = getenv("SNMPPRIV")) != NULL) {
155216295Ssyrinx		slen = strlen(str);
156216295Ssyrinx		if (slen == strlen("des") && strcasecmp(str, "des") == 0)
157216295Ssyrinx			snmp_client.user.priv_proto = SNMP_PRIV_DES;
158216295Ssyrinx		else if (slen == strlen("aes")&& strcasecmp(str, "aes") == 0)
159216295Ssyrinx			snmp_client.user.priv_proto = SNMP_PRIV_AES;
160216295Ssyrinx		else if (slen != 0)
161216295Ssyrinx			warnx("Bad privacy type - %s in SNMPPRIV", str);
162216295Ssyrinx	}
163216295Ssyrinx
164216295Ssyrinx	if ((str = getenv("SNMPUSER")) != NULL) {
165216295Ssyrinx		if ((slen = strlen(str)) > sizeof(snmp_client.user.sec_name)) {
166216295Ssyrinx			warnx("Username too long - %s in SNMPUSER", str);
167216295Ssyrinx			return (-1);
168216295Ssyrinx		}
169216295Ssyrinx		if (slen > 0) {
170216295Ssyrinx			strlcpy(snmp_client.user.sec_name, str,
171216295Ssyrinx			    sizeof(snmp_client.user.sec_name));
172216295Ssyrinx			snmp_client.version = SNMP_V3;
173216295Ssyrinx		}
174216295Ssyrinx	}
175216295Ssyrinx
176216295Ssyrinx	if ((str = getenv("SNMPPASSWD")) != NULL) {
177216295Ssyrinx		if ((slen = strlen(str)) > MAXSTR)
178216295Ssyrinx			slen = MAXSTR - 1;
179216295Ssyrinx		if ((snmptoolctx->passwd = malloc(slen + 1)) == NULL) {
180311595Sngie			warn("malloc() failed");
181216295Ssyrinx			return (-1);
182216295Ssyrinx		}
183216295Ssyrinx		if (slen > 0)
184216295Ssyrinx			strlcpy(snmptoolctx->passwd, str, slen + 1);
185216295Ssyrinx	}
186216295Ssyrinx
187216295Ssyrinx	return (0);
188216295Ssyrinx}
189216295Ssyrinx
190216295Ssyrinx#define	OBJECT_IDX_LIST(o)	o->info->table_idx->index_list
191216295Ssyrinx
192310903Sngie/*
193216295Ssyrinx * Walk through the file list and import string<->oid mappings from each file.
194216295Ssyrinx */
195216295Ssyrinxint32_t
196216295Ssyrinxsnmp_import_all(struct snmp_toolinfo *snmptoolctx)
197216295Ssyrinx{
198216295Ssyrinx	int32_t fc;
199216295Ssyrinx	struct fname *tmp;
200216295Ssyrinx
201216295Ssyrinx	if (snmptoolctx == NULL)
202216295Ssyrinx		return (-1);
203216295Ssyrinx
204216295Ssyrinx	if (ISSET_NUMERIC(snmptoolctx))
205216295Ssyrinx		return (0);
206216295Ssyrinx
207216295Ssyrinx	if ((snmptoolctx->mappings = snmp_mapping_init()) == NULL)
208216295Ssyrinx		return (-1);
209216295Ssyrinx
210216295Ssyrinx	fc = 0;
211216295Ssyrinx	if (SLIST_EMPTY(&snmptoolctx->filelist)) {
212216295Ssyrinx		warnx("No files to read OID <-> string conversions from");
213216295Ssyrinx		return (-1);
214216295Ssyrinx	} else {
215216295Ssyrinx		SLIST_FOREACH(tmp, &snmptoolctx->filelist, link) {
216216295Ssyrinx			if (tmp->done)
217216295Ssyrinx				continue;
218216295Ssyrinx			if (snmp_import_file(snmptoolctx, tmp) < 0) {
219216295Ssyrinx				fc = -1;
220216295Ssyrinx				break;
221216295Ssyrinx			}
222216295Ssyrinx			fc++;
223216295Ssyrinx		}
224216295Ssyrinx	}
225216295Ssyrinx
226216295Ssyrinx	snmp_mapping_dump(snmptoolctx);
227216295Ssyrinx	return (fc);
228216295Ssyrinx}
229216295Ssyrinx
230216295Ssyrinx/*
231228990Suqs * Add a filename to the file list - the initial idea of keeping a list with all
232216295Ssyrinx * files to read OIDs from was that an application might want to have loaded in
233216295Ssyrinx * memory the OIDs from a single file only and when done with them read the OIDs
234216295Ssyrinx * from another file. This is not used yet but might be a good idea at some
235216295Ssyrinx * point. Size argument is number of bytes in string including trailing '\0',
236228990Suqs * not string length.
237216295Ssyrinx */
238216295Ssyrinxint32_t
239216295Ssyrinxadd_filename(struct snmp_toolinfo *snmptoolctx, const char *filename,
240216295Ssyrinx    const struct asn_oid *cut, int32_t done)
241216295Ssyrinx{
242216295Ssyrinx	char *fstring;
243216295Ssyrinx	struct fname *entry;
244216295Ssyrinx
245216295Ssyrinx	if (snmptoolctx == NULL)
246216295Ssyrinx		return (-1);
247216295Ssyrinx
248216295Ssyrinx	/* Make sure file was not in list. */
249216295Ssyrinx	SLIST_FOREACH(entry, &snmptoolctx->filelist, link) {
250216295Ssyrinx		if (strncmp(entry->name, filename, strlen(entry->name)) == 0)
251216295Ssyrinx			return (0);
252216295Ssyrinx	}
253216295Ssyrinx
254300559Sngie	if ((fstring = strdup(filename)) == NULL) {
255311595Sngie		warn("strdup() failed");
256216295Ssyrinx		return (-1);
257216295Ssyrinx	}
258216295Ssyrinx
259300471Sngie	if ((entry = calloc(1, sizeof(struct fname))) == NULL) {
260311595Sngie		warn("calloc() failed");
261216295Ssyrinx		free(fstring);
262216295Ssyrinx		return (-1);
263216295Ssyrinx	}
264216295Ssyrinx
265216295Ssyrinx	if (cut != NULL)
266216295Ssyrinx		asn_append_oid(&(entry->cut), cut);
267216295Ssyrinx	entry->name = fstring;
268216295Ssyrinx	entry->done = done;
269216295Ssyrinx	SLIST_INSERT_HEAD(&snmptoolctx->filelist, entry, link);
270216295Ssyrinx
271216295Ssyrinx	return (1);
272216295Ssyrinx}
273216295Ssyrinx
274216295Ssyrinxvoid
275216295Ssyrinxfree_filelist(struct snmp_toolinfo *snmptoolctx)
276216295Ssyrinx{
277216295Ssyrinx	struct fname *f;
278216295Ssyrinx
279216295Ssyrinx	if (snmptoolctx == NULL)
280216295Ssyrinx		return; /* XXX error handling */
281216295Ssyrinx
282216295Ssyrinx	while ((f = SLIST_FIRST(&snmptoolctx->filelist)) != NULL) {
283216295Ssyrinx		SLIST_REMOVE_HEAD(&snmptoolctx->filelist, link);
284216295Ssyrinx		if (f->name)
285216295Ssyrinx			free(f->name);
286216295Ssyrinx		free(f);
287216295Ssyrinx	}
288216295Ssyrinx}
289216295Ssyrinx
290310903Sngiestatic char
291216295Ssyrinxisvalid_fchar(char c, int pos)
292216295Ssyrinx{
293216295Ssyrinx	if (isalpha(c)|| c == '/'|| c == '_' || c == '.' || c == '~' ||
294216295Ssyrinx	    (pos != 0 && isdigit(c))){
295216295Ssyrinx		return (c);
296216295Ssyrinx	}
297216295Ssyrinx
298216295Ssyrinx	if (c == '\0')
299216295Ssyrinx		return (0);
300216295Ssyrinx
301216295Ssyrinx	if (!isascii(c) || !isprint(c))
302216295Ssyrinx		warnx("Unexpected character %#2x", (u_int) c);
303216295Ssyrinx	else
304216295Ssyrinx		warnx("Illegal character '%c'", c);
305216295Ssyrinx
306216295Ssyrinx	return (-1);
307216295Ssyrinx}
308216295Ssyrinx
309216295Ssyrinx/*
310216295Ssyrinx * Re-implement getsubopt from scratch, because the second argument is broken
311216295Ssyrinx * and will not compile with WARNS=5.
312216295Ssyrinx * Copied from src/contrib/bsnmp/snmpd/main.c.
313216295Ssyrinx */
314216295Ssyrinxstatic int
315216295Ssyrinxgetsubopt1(char **arg, const char *const *options, char **valp, char **optp)
316216295Ssyrinx{
317216295Ssyrinx	static const char *const delim = ",\t ";
318216295Ssyrinx	u_int i;
319216295Ssyrinx	char *ptr;
320216295Ssyrinx
321216295Ssyrinx	*optp = NULL;
322216295Ssyrinx
323216295Ssyrinx	/* Skip leading junk. */
324216295Ssyrinx	for (ptr = *arg; *ptr != '\0'; ptr++)
325216295Ssyrinx		if (strchr(delim, *ptr) == NULL)
326216295Ssyrinx			break;
327216295Ssyrinx	if (*ptr == '\0') {
328216295Ssyrinx		*arg = ptr;
329216295Ssyrinx		return (-1);
330216295Ssyrinx	}
331216295Ssyrinx	*optp = ptr;
332216295Ssyrinx
333216295Ssyrinx	/* Find the end of the option. */
334216295Ssyrinx	while (*++ptr != '\0')
335216295Ssyrinx		if (strchr(delim, *ptr) != NULL || *ptr == '=')
336216295Ssyrinx			break;
337216295Ssyrinx
338216295Ssyrinx	if (*ptr != '\0') {
339216295Ssyrinx		if (*ptr == '=') {
340216295Ssyrinx			*ptr++ = '\0';
341216295Ssyrinx			*valp = ptr;
342216295Ssyrinx			while (*ptr != '\0' && strchr(delim, *ptr) == NULL)
343216295Ssyrinx				ptr++;
344216295Ssyrinx			if (*ptr != '\0')
345216295Ssyrinx				*ptr++ = '\0';
346216295Ssyrinx		} else
347216295Ssyrinx			*ptr++ = '\0';
348216295Ssyrinx	}
349216295Ssyrinx
350216295Ssyrinx	*arg = ptr;
351216295Ssyrinx
352216295Ssyrinx	for (i = 0; *options != NULL; options++, i++)
353216295Ssyrinx		if (strcmp(*optp, *options) == 0)
354216295Ssyrinx			return (i);
355216295Ssyrinx	return (-1);
356216295Ssyrinx}
357216295Ssyrinx
358216295Ssyrinxstatic int32_t
359216295Ssyrinxparse_path(char *value)
360216295Ssyrinx{
361216295Ssyrinx	int32_t i, len;
362216295Ssyrinx
363216295Ssyrinx	if (value == NULL)
364216295Ssyrinx		return (-1);
365216295Ssyrinx
366216295Ssyrinx	for (len = 0; len < MAXPATHLEN; len++) {
367216295Ssyrinx		i = isvalid_fchar(*(value + len), len) ;
368216295Ssyrinx
369216295Ssyrinx		if (i == 0)
370216295Ssyrinx			break;
371216295Ssyrinx		else if (i < 0)
372216295Ssyrinx			return (-1);
373216295Ssyrinx	}
374216295Ssyrinx
375216295Ssyrinx	if (len >= MAXPATHLEN || value[len] != '\0') {
376216295Ssyrinx		warnx("Bad pathname - '%s'", value);
377216295Ssyrinx		return (-1);
378216295Ssyrinx	}
379216295Ssyrinx
380216295Ssyrinx	return (len);
381216295Ssyrinx}
382216295Ssyrinx
383216295Ssyrinxstatic int32_t
384216295Ssyrinxparse_flist(struct snmp_toolinfo *snmptoolctx, char *value, char *path,
385216295Ssyrinx    const struct asn_oid *cut)
386216295Ssyrinx{
387216295Ssyrinx	int32_t namelen;
388216295Ssyrinx	char filename[MAXPATHLEN + 1];
389216295Ssyrinx
390216295Ssyrinx	if (value == NULL)
391216295Ssyrinx		return (-1);
392216295Ssyrinx
393216295Ssyrinx	do {
394216295Ssyrinx		memset(filename, 0, MAXPATHLEN + 1);
395216295Ssyrinx
396216295Ssyrinx		if (isalpha(*value) && (path == NULL || path[0] == '\0')) {
397216295Ssyrinx			strlcpy(filename, SNMP_DEFS_DIR, MAXPATHLEN + 1);
398216295Ssyrinx			namelen = strlen(SNMP_DEFS_DIR);
399216295Ssyrinx		} else if (path != NULL){
400216295Ssyrinx			strlcpy(filename, path, MAXPATHLEN + 1);
401216295Ssyrinx			namelen = strlen(path);
402216295Ssyrinx		} else
403216295Ssyrinx			namelen = 0;
404216295Ssyrinx
405216295Ssyrinx		for ( ; namelen < MAXPATHLEN; value++) {
406216295Ssyrinx			if (isvalid_fchar(*value, namelen) > 0) {
407216295Ssyrinx				filename[namelen++] = *value;
408216295Ssyrinx				continue;
409216295Ssyrinx			}
410216295Ssyrinx
411216295Ssyrinx			if (*value == ',' )
412216295Ssyrinx				value++;
413216295Ssyrinx			else if (*value == '\0')
414216295Ssyrinx				;
415216295Ssyrinx			else {
416216295Ssyrinx				if (!isascii(*value) || !isprint(*value))
417216295Ssyrinx					warnx("Unexpected character %#2x in"
418216295Ssyrinx					    " filename", (u_int) *value);
419216295Ssyrinx				else
420216295Ssyrinx					warnx("Illegal character '%c' in"
421216295Ssyrinx					    " filename", *value);
422216295Ssyrinx				return (-1);
423216295Ssyrinx			}
424216295Ssyrinx
425216295Ssyrinx			filename[namelen]='\0';
426216295Ssyrinx			break;
427216295Ssyrinx		}
428216295Ssyrinx
429216295Ssyrinx		if ((namelen == MAXPATHLEN) && (filename[MAXPATHLEN] != '\0')) {
430216295Ssyrinx			warnx("Filename %s too long", filename);
431216295Ssyrinx			return (-1);
432216295Ssyrinx		}
433216295Ssyrinx
434216295Ssyrinx		if (add_filename(snmptoolctx, filename, cut, 0) < 0) {
435216295Ssyrinx			warnx("Error adding file %s to list", filename);
436216295Ssyrinx			return (-1);
437216295Ssyrinx		}
438216295Ssyrinx	} while (*value != '\0');
439216295Ssyrinx
440216295Ssyrinx	return(1);
441216295Ssyrinx}
442216295Ssyrinx
443216295Ssyrinxstatic int32_t
444216295Ssyrinxparse_ascii(char *ascii, uint8_t *binstr, size_t binlen)
445216295Ssyrinx{
446300471Sngie	char dptr[3];
447300471Sngie	size_t count;
448300471Sngie	int32_t alen, i, saved_errno;
449216295Ssyrinx	uint32_t val;
450216295Ssyrinx
451228990Suqs	/* Filter 0x at the beginning */
452216295Ssyrinx	if ((alen = strlen(ascii)) > 2 && ascii[0] == '0' && ascii[1] == 'x')
453216295Ssyrinx		i = 2;
454216295Ssyrinx	else
455216295Ssyrinx		i = 0;
456216295Ssyrinx
457216295Ssyrinx	saved_errno = errno;
458216295Ssyrinx	errno = 0;
459216295Ssyrinx	for (count = 0; i < alen; i += 2) {
460216295Ssyrinx		/* XXX: consider strlen(ascii) % 2 != 0 */
461216295Ssyrinx		dptr[0] = ascii[i];
462216295Ssyrinx		dptr[1] = ascii[i + 1];
463216295Ssyrinx		dptr[2] = '\0';
464216295Ssyrinx		if ((val = strtoul(dptr, NULL, 16)) > 0xFF || errno != 0) {
465216295Ssyrinx			errno = saved_errno;
466216295Ssyrinx			return (-1);
467216295Ssyrinx		}
468216295Ssyrinx		binstr[count] = (uint8_t) val;
469216295Ssyrinx		if (++count >= binlen) {
470228990Suqs			warnx("Key %s too long - truncating to %zu octets",
471216295Ssyrinx			    ascii, binlen);
472216295Ssyrinx			break;
473216295Ssyrinx		}
474216295Ssyrinx	}
475216295Ssyrinx
476216295Ssyrinx	return (count);
477216295Ssyrinx}
478216295Ssyrinx
479216295Ssyrinx/*
480216295Ssyrinx * Functions to parse common input options for client tools and fill in the
481216295Ssyrinx * snmp_client structure.
482216295Ssyrinx */
483216295Ssyrinxint32_t
484300471Sngieparse_authentication(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
485216295Ssyrinx{
486216295Ssyrinx	int32_t count, subopt;
487216295Ssyrinx	char *val, *option;
488216295Ssyrinx	const char *const subopts[] = {
489216295Ssyrinx		"proto",
490216295Ssyrinx		"key",
491216295Ssyrinx		NULL
492216295Ssyrinx	};
493216295Ssyrinx
494216295Ssyrinx	assert(opt_arg != NULL);
495216295Ssyrinx	count = 1;
496216295Ssyrinx	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
497216295Ssyrinx		switch (subopt) {
498216295Ssyrinx		case 0:
499216295Ssyrinx			if (val == NULL) {
500216295Ssyrinx				warnx("Suboption 'proto' requires an argument");
501216295Ssyrinx				return (-1);
502216295Ssyrinx			}
503216295Ssyrinx			if (strlen(val) != 3) {
504216295Ssyrinx				warnx("Unknown auth protocol - %s", val);
505216295Ssyrinx				return (-1);
506216295Ssyrinx			}
507216295Ssyrinx			if (strncasecmp("md5", val, strlen("md5")) == 0)
508216295Ssyrinx				snmp_client.user.auth_proto =
509216295Ssyrinx				    SNMP_AUTH_HMAC_MD5;
510216295Ssyrinx			else if (strncasecmp("sha", val, strlen("sha")) == 0)
511216295Ssyrinx				snmp_client.user.auth_proto =
512216295Ssyrinx				    SNMP_AUTH_HMAC_SHA;
513216295Ssyrinx			else {
514216295Ssyrinx				warnx("Unknown auth protocol - %s", val);
515216295Ssyrinx				return (-1);
516216295Ssyrinx			}
517216295Ssyrinx			break;
518216295Ssyrinx		case 1:
519216295Ssyrinx			if (val == NULL) {
520216295Ssyrinx				warnx("Suboption 'key' requires an argument");
521216295Ssyrinx				return (-1);
522216295Ssyrinx			}
523216295Ssyrinx			if (parse_ascii(val, snmp_client.user.auth_key,
524216295Ssyrinx			    SNMP_AUTH_KEY_SIZ) < 0) {
525216295Ssyrinx				warnx("Bad authentication key- %s", val);
526216295Ssyrinx				return (-1);
527216295Ssyrinx			}
528216295Ssyrinx			break;
529216295Ssyrinx		default:
530216295Ssyrinx			warnx("Unknown suboption - '%s'", suboptarg);
531216295Ssyrinx			return (-1);
532216295Ssyrinx		}
533216295Ssyrinx		count += 1;
534216295Ssyrinx	}
535216295Ssyrinx	return (2/* count */);
536216295Ssyrinx}
537216295Ssyrinx
538216295Ssyrinxint32_t
539300471Sngieparse_privacy(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
540216295Ssyrinx{
541216295Ssyrinx	int32_t count, subopt;
542216295Ssyrinx	char *val, *option;
543216295Ssyrinx	const char *const subopts[] = {
544216295Ssyrinx		"proto",
545216295Ssyrinx		"key",
546216295Ssyrinx		NULL
547216295Ssyrinx	};
548216295Ssyrinx
549216295Ssyrinx	assert(opt_arg != NULL);
550216295Ssyrinx	count = 1;
551216295Ssyrinx	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
552216295Ssyrinx		switch (subopt) {
553216295Ssyrinx		case 0:
554216295Ssyrinx			if (val == NULL) {
555216295Ssyrinx				warnx("Suboption 'proto' requires an argument");
556216295Ssyrinx				return (-1);
557216295Ssyrinx			}
558216295Ssyrinx			if (strlen(val) != 3) {
559216295Ssyrinx				warnx("Unknown privacy protocol - %s", val);
560216295Ssyrinx				return (-1);
561216295Ssyrinx			}
562216295Ssyrinx			if (strncasecmp("aes", val, strlen("aes")) == 0)
563216295Ssyrinx				snmp_client.user.priv_proto = SNMP_PRIV_AES;
564216295Ssyrinx			else if (strncasecmp("des", val, strlen("des")) == 0)
565216295Ssyrinx				snmp_client.user.priv_proto = SNMP_PRIV_DES;
566216295Ssyrinx			else {
567216295Ssyrinx				warnx("Unknown privacy protocol - %s", val);
568216295Ssyrinx				return (-1);
569216295Ssyrinx			}
570216295Ssyrinx			break;
571216295Ssyrinx		case 1:
572216295Ssyrinx			if (val == NULL) {
573216295Ssyrinx				warnx("Suboption 'key' requires an argument");
574216295Ssyrinx				return (-1);
575216295Ssyrinx			}
576216295Ssyrinx			if (parse_ascii(val, snmp_client.user.priv_key,
577216295Ssyrinx			    SNMP_PRIV_KEY_SIZ) < 0) {
578216295Ssyrinx				warnx("Bad privacy key- %s", val);
579216295Ssyrinx				return (-1);
580216295Ssyrinx			}
581216295Ssyrinx			break;
582216295Ssyrinx		default:
583216295Ssyrinx			warnx("Unknown suboption - '%s'", suboptarg);
584216295Ssyrinx			return (-1);
585216295Ssyrinx		}
586216295Ssyrinx		count += 1;
587216295Ssyrinx	}
588216295Ssyrinx	return (2/* count */);
589216295Ssyrinx}
590216295Ssyrinx
591216295Ssyrinxint32_t
592300471Sngieparse_context(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
593216295Ssyrinx{
594216295Ssyrinx	int32_t count, subopt;
595216295Ssyrinx	char *val, *option;
596216295Ssyrinx	const char *const subopts[] = {
597216295Ssyrinx		"context",
598216295Ssyrinx		"context-engine",
599216295Ssyrinx		NULL
600216295Ssyrinx	};
601216295Ssyrinx
602216295Ssyrinx	assert(opt_arg != NULL);
603216295Ssyrinx	count = 1;
604216295Ssyrinx	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
605216295Ssyrinx		switch (subopt) {
606216295Ssyrinx		case 0:
607216295Ssyrinx			if (val == NULL) {
608216295Ssyrinx				warnx("Suboption 'context' - no argument");
609216295Ssyrinx				return (-1);
610216295Ssyrinx			}
611216295Ssyrinx			strlcpy(snmp_client.cname, val, SNMP_CONTEXT_NAME_SIZ);
612216295Ssyrinx			break;
613216295Ssyrinx		case 1:
614216295Ssyrinx			if (val == NULL) {
615216295Ssyrinx				warnx("Suboption 'context-engine' - no argument");
616216295Ssyrinx				return (-1);
617216295Ssyrinx			}
618301655Sngie			if ((int32_t)(snmp_client.clen = parse_ascii(val,
619301655Sngie			    snmp_client.cengine, SNMP_ENGINE_ID_SIZ)) == -1) {
620216295Ssyrinx				warnx("Bad EngineID - %s", val);
621216295Ssyrinx				return (-1);
622216295Ssyrinx			}
623216295Ssyrinx			break;
624216295Ssyrinx		default:
625216295Ssyrinx			warnx("Unknown suboption - '%s'", suboptarg);
626216295Ssyrinx			return (-1);
627216295Ssyrinx		}
628216295Ssyrinx		count += 1;
629216295Ssyrinx	}
630216295Ssyrinx	return (2/* count */);
631216295Ssyrinx}
632216295Ssyrinx
633216295Ssyrinxint32_t
634300471Sngieparse_user_security(struct snmp_toolinfo *snmptoolctx __unused, char *opt_arg)
635216295Ssyrinx{
636216295Ssyrinx	int32_t count, subopt, saved_errno;
637216295Ssyrinx	char *val, *option;
638216295Ssyrinx	const char *const subopts[] = {
639216295Ssyrinx		"engine",
640216295Ssyrinx		"engine-boots",
641216295Ssyrinx		"engine-time",
642216295Ssyrinx		"name",
643216295Ssyrinx		NULL
644216295Ssyrinx	};
645216295Ssyrinx
646216295Ssyrinx	assert(opt_arg != NULL);
647216295Ssyrinx	count = 1;
648216295Ssyrinx	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
649216295Ssyrinx		switch (subopt) {
650216295Ssyrinx		case 0:
651216295Ssyrinx			if (val == NULL) {
652216295Ssyrinx				warnx("Suboption 'engine' - no argument");
653216295Ssyrinx				return (-1);
654216295Ssyrinx			}
655310903Sngie			snmp_client.engine.engine_len = parse_ascii(val,
656216295Ssyrinx			    snmp_client.engine.engine_id, SNMP_ENGINE_ID_SIZ);
657301655Sngie			if ((int32_t)snmp_client.engine.engine_len == -1) {
658216295Ssyrinx				warnx("Bad EngineID - %s", val);
659216295Ssyrinx				return (-1);
660216295Ssyrinx			}
661216295Ssyrinx			break;
662216295Ssyrinx		case 1:
663216295Ssyrinx			if (val == NULL) {
664216295Ssyrinx				warnx("Suboption 'engine-boots' - no argument");
665216295Ssyrinx				return (-1);
666216295Ssyrinx			}
667216295Ssyrinx			saved_errno = errno;
668216295Ssyrinx			errno = 0;
669216295Ssyrinx			snmp_client.engine.engine_boots = strtoul(val, NULL, 10);
670216295Ssyrinx			if (errno != 0) {
671311595Sngie				warn("Bad 'engine-boots' value %s", val);
672216295Ssyrinx				errno = saved_errno;
673216295Ssyrinx				return (-1);
674216295Ssyrinx			}
675216295Ssyrinx			errno = saved_errno;
676216295Ssyrinx			break;
677216295Ssyrinx		case 2:
678216295Ssyrinx			if (val == NULL) {
679216295Ssyrinx				warnx("Suboption 'engine-time' - no argument");
680216295Ssyrinx				return (-1);
681216295Ssyrinx			}
682216295Ssyrinx			saved_errno = errno;
683216295Ssyrinx			errno = 0;
684216295Ssyrinx			snmp_client.engine.engine_time = strtoul(val, NULL, 10);
685216295Ssyrinx			if (errno != 0) {
686311595Sngie				warn("Bad 'engine-time' value %s", val);
687216295Ssyrinx				errno = saved_errno;
688216295Ssyrinx				return (-1);
689216295Ssyrinx			}
690216295Ssyrinx			errno = saved_errno;
691216295Ssyrinx			break;
692216295Ssyrinx		case 3:
693216295Ssyrinx			strlcpy(snmp_client.user.sec_name, val,
694216295Ssyrinx			    SNMP_ADM_STR32_SIZ);
695216295Ssyrinx			break;
696216295Ssyrinx		default:
697216295Ssyrinx			warnx("Unknown suboption - '%s'", suboptarg);
698216295Ssyrinx			return (-1);
699216295Ssyrinx		}
700216295Ssyrinx		count += 1;
701216295Ssyrinx	}
702216295Ssyrinx	return (2/* count */);
703216295Ssyrinx}
704216295Ssyrinx
705216295Ssyrinxint32_t
706216295Ssyrinxparse_file(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
707216295Ssyrinx{
708216295Ssyrinx	assert(opt_arg != NULL);
709216295Ssyrinx
710216295Ssyrinx	if (parse_flist(snmptoolctx, opt_arg, NULL, &IsoOrgDod_OID) < 0)
711216295Ssyrinx		return (-1);
712216295Ssyrinx
713216295Ssyrinx	return (2);
714216295Ssyrinx}
715216295Ssyrinx
716216295Ssyrinxint32_t
717216295Ssyrinxparse_include(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
718216295Ssyrinx{
719216295Ssyrinx	char path[MAXPATHLEN + 1];
720216295Ssyrinx	int32_t cut_dflt, len, subopt;
721216295Ssyrinx	struct asn_oid cut;
722216295Ssyrinx	char *val, *option;
723216295Ssyrinx	const char *const subopts[] = {
724216295Ssyrinx		"cut",
725216295Ssyrinx		"path",
726216295Ssyrinx		"file",
727216295Ssyrinx		NULL
728216295Ssyrinx	};
729216295Ssyrinx
730216295Ssyrinx#define	INC_CUT		0
731216295Ssyrinx#define	INC_PATH	1
732216295Ssyrinx#define	INC_LIST	2
733216295Ssyrinx
734216295Ssyrinx	assert(opt_arg != NULL);
735216295Ssyrinx
736216295Ssyrinx	/* if (opt == 'i')
737216295Ssyrinx		free_filelist(snmptoolctx, ); */
738216295Ssyrinx	/*
739216295Ssyrinx	 * This function should be called only after getopt(3) - otherwise if
740216295Ssyrinx	 * no previous validation of opt_arg strlen() may not return what is
741216295Ssyrinx	 * expected.
742216295Ssyrinx	 */
743216295Ssyrinx
744216295Ssyrinx	path[0] = '\0';
745216295Ssyrinx	memset(&cut, 0, sizeof(struct asn_oid));
746216295Ssyrinx	cut_dflt = -1;
747216295Ssyrinx
748216295Ssyrinx	while ((subopt = getsubopt1(&opt_arg, subopts, &val, &option)) != EOF) {
749216295Ssyrinx		switch (subopt) {
750216295Ssyrinx		    case INC_CUT:
751216295Ssyrinx			if (val == NULL) {
752216295Ssyrinx				warnx("Suboption 'cut' requires an argument");
753216295Ssyrinx				return (-1);
754216295Ssyrinx			} else {
755216295Ssyrinx				if (snmp_parse_numoid(val, &cut) < 0)
756216295Ssyrinx					return (-1);
757216295Ssyrinx			}
758216295Ssyrinx			cut_dflt = 1;
759216295Ssyrinx			break;
760216295Ssyrinx
761216295Ssyrinx		    case INC_PATH:
762216295Ssyrinx			if ((len = parse_path(val)) < 0)
763216295Ssyrinx				return (-1);
764216295Ssyrinx			strlcpy(path, val, len + 1);
765216295Ssyrinx			break;
766216295Ssyrinx
767216295Ssyrinx		    case INC_LIST:
768216295Ssyrinx			if (val == NULL)
769216295Ssyrinx				return (-1);
770216295Ssyrinx			if (cut_dflt == -1)
771216295Ssyrinx				len = parse_flist(snmptoolctx, val, path, &IsoOrgDod_OID);
772216295Ssyrinx			else
773216295Ssyrinx				len = parse_flist(snmptoolctx, val, path, &cut);
774216295Ssyrinx			if (len < 0)
775216295Ssyrinx				return (-1);
776216295Ssyrinx			break;
777216295Ssyrinx
778216295Ssyrinx		    default:
779216295Ssyrinx			warnx("Unknown suboption - '%s'", suboptarg);
780216295Ssyrinx			return (-1);
781216295Ssyrinx		}
782216295Ssyrinx	}
783216295Ssyrinx
784216295Ssyrinx	/* XXX: Fix me - returning two is wrong here */
785216295Ssyrinx	return (2);
786216295Ssyrinx}
787216295Ssyrinx
788216295Ssyrinxint32_t
789216295Ssyrinxparse_server(char *opt_arg)
790216295Ssyrinx{
791216295Ssyrinx	assert(opt_arg != NULL);
792216295Ssyrinx
793216295Ssyrinx	if (snmp_parse_server(&snmp_client, opt_arg) < 0)
794216295Ssyrinx		return (-1);
795216295Ssyrinx
796216295Ssyrinx	if (snmp_client.trans > SNMP_TRANS_UDP && snmp_client.chost == NULL) {
797300276Struckman		if ((snmp_client.chost = malloc(strlen(SNMP_DEFAULT_LOCAL) + 1))
798216295Ssyrinx		    == NULL) {
799216295Ssyrinx			syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
800216295Ssyrinx			return (-1);
801216295Ssyrinx		}
802216295Ssyrinx		strcpy(snmp_client.chost, SNMP_DEFAULT_LOCAL);
803216295Ssyrinx	}
804216295Ssyrinx
805216295Ssyrinx	return (2);
806216295Ssyrinx}
807216295Ssyrinx
808216295Ssyrinxint32_t
809216295Ssyrinxparse_timeout(char *opt_arg)
810216295Ssyrinx{
811216295Ssyrinx	int32_t v, saved_errno;
812216295Ssyrinx
813216295Ssyrinx	assert(opt_arg != NULL);
814216295Ssyrinx
815216295Ssyrinx	saved_errno = errno;
816216295Ssyrinx	errno = 0;
817216295Ssyrinx
818216295Ssyrinx	v = strtol(opt_arg, NULL, 10);
819216295Ssyrinx	if (errno != 0) {
820311595Sngie		warn("Error parsing timeout value");
821216295Ssyrinx		errno = saved_errno;
822216295Ssyrinx		return (-1);
823216295Ssyrinx	}
824216295Ssyrinx
825216295Ssyrinx	snmp_client.timeout.tv_sec = v;
826216295Ssyrinx	errno = saved_errno;
827216295Ssyrinx	return (2);
828216295Ssyrinx}
829216295Ssyrinx
830216295Ssyrinxint32_t
831216295Ssyrinxparse_retry(char *opt_arg)
832216295Ssyrinx{
833216295Ssyrinx	uint32_t v;
834216295Ssyrinx	int32_t saved_errno;
835216295Ssyrinx
836216295Ssyrinx	assert(opt_arg != NULL);
837216295Ssyrinx
838216295Ssyrinx	saved_errno = errno;
839216295Ssyrinx	errno = 0;
840216295Ssyrinx
841216295Ssyrinx	v = strtoul(opt_arg, NULL, 10);
842216295Ssyrinx	if (errno != 0) {
843311595Sngie		warn("Error parsing retries count");
844216295Ssyrinx		errno = saved_errno;
845216295Ssyrinx		return (-1);
846216295Ssyrinx	}
847216295Ssyrinx
848216295Ssyrinx	snmp_client.retries = v;
849216295Ssyrinx	errno = saved_errno;
850216295Ssyrinx	return (2);
851216295Ssyrinx}
852216295Ssyrinx
853216295Ssyrinxint32_t
854216295Ssyrinxparse_version(char *opt_arg)
855216295Ssyrinx{
856216295Ssyrinx	uint32_t v;
857216295Ssyrinx	int32_t saved_errno;
858216295Ssyrinx
859216295Ssyrinx	assert(opt_arg != NULL);
860216295Ssyrinx
861216295Ssyrinx	saved_errno = errno;
862216295Ssyrinx	errno = 0;
863216295Ssyrinx
864216295Ssyrinx	v = strtoul(opt_arg, NULL, 10);
865216295Ssyrinx	if (errno != 0) {
866311595Sngie		warn("Error parsing version");
867216295Ssyrinx		errno = saved_errno;
868216295Ssyrinx		return (-1);
869216295Ssyrinx	}
870216295Ssyrinx
871216295Ssyrinx	switch (v) {
872216295Ssyrinx		case 1:
873216295Ssyrinx			snmp_client.version = SNMP_V1;
874216295Ssyrinx			break;
875216295Ssyrinx		case 2:
876216295Ssyrinx			snmp_client.version = SNMP_V2c;
877216295Ssyrinx			break;
878216295Ssyrinx		case 3:
879216295Ssyrinx			snmp_client.version = SNMP_V3;
880216295Ssyrinx			break;
881216295Ssyrinx		default:
882216295Ssyrinx			warnx("Unsupported SNMP version - %u", v);
883216295Ssyrinx			errno = saved_errno;
884216295Ssyrinx			return (-1);
885216295Ssyrinx	}
886216295Ssyrinx
887216295Ssyrinx	errno = saved_errno;
888216295Ssyrinx	return (2);
889216295Ssyrinx}
890216295Ssyrinx
891216295Ssyrinxint32_t
892216295Ssyrinxparse_local_path(char *opt_arg)
893216295Ssyrinx{
894216295Ssyrinx	assert(opt_arg != NULL);
895216295Ssyrinx
896216295Ssyrinx	if (sizeof(opt_arg) > sizeof(SNMP_LOCAL_PATH)) {
897216295Ssyrinx		warnx("Filename too long - %s", opt_arg);
898216295Ssyrinx		return (-1);
899216295Ssyrinx	}
900216295Ssyrinx
901216295Ssyrinx	strlcpy(snmp_client.local_path, opt_arg, sizeof(SNMP_LOCAL_PATH));
902216295Ssyrinx	return (2);
903216295Ssyrinx}
904216295Ssyrinx
905216295Ssyrinxint32_t
906216295Ssyrinxparse_buflen(char *opt_arg)
907216295Ssyrinx{
908216295Ssyrinx	uint32_t size;
909216295Ssyrinx	int32_t saved_errno;
910216295Ssyrinx
911216295Ssyrinx	assert(opt_arg != NULL);
912216295Ssyrinx
913216295Ssyrinx	saved_errno = errno;
914216295Ssyrinx	errno = 0;
915216295Ssyrinx
916216295Ssyrinx	size = strtoul(opt_arg, NULL, 10);
917216295Ssyrinx	if (errno != 0) {
918311595Sngie		warn("Error parsing buffer size");
919216295Ssyrinx		errno = saved_errno;
920216295Ssyrinx		return (-1);
921216295Ssyrinx	}
922216295Ssyrinx
923216295Ssyrinx	if (size > MAX_BUFF_SIZE) {
924216295Ssyrinx		warnx("Buffer size too big - %d max allowed", MAX_BUFF_SIZE);
925216295Ssyrinx		errno = saved_errno;
926216295Ssyrinx		return (-1);
927216295Ssyrinx	}
928216295Ssyrinx
929216295Ssyrinx	snmp_client.txbuflen = snmp_client.rxbuflen = size;
930216295Ssyrinx	errno = saved_errno;
931216295Ssyrinx	return (2);
932216295Ssyrinx}
933216295Ssyrinx
934216295Ssyrinxint32_t
935216295Ssyrinxparse_debug(void)
936216295Ssyrinx{
937216295Ssyrinx	snmp_client.dump_pdus = 1;
938216295Ssyrinx	return (1);
939216295Ssyrinx}
940216295Ssyrinx
941216295Ssyrinxint32_t
942216295Ssyrinxparse_discovery(struct snmp_toolinfo *snmptoolctx)
943216295Ssyrinx{
944216295Ssyrinx	SET_EDISCOVER(snmptoolctx);
945216295Ssyrinx	snmp_client.version = SNMP_V3;
946216295Ssyrinx	return (1);
947216295Ssyrinx}
948216295Ssyrinx
949216295Ssyrinxint32_t
950216295Ssyrinxparse_local_key(struct snmp_toolinfo *snmptoolctx)
951216295Ssyrinx{
952216295Ssyrinx	SET_LOCALKEY(snmptoolctx);
953216295Ssyrinx	snmp_client.version = SNMP_V3;
954216295Ssyrinx	return (1);
955216295Ssyrinx}
956216295Ssyrinx
957216295Ssyrinxint32_t
958216295Ssyrinxparse_num_oids(struct snmp_toolinfo *snmptoolctx)
959216295Ssyrinx{
960216295Ssyrinx	SET_NUMERIC(snmptoolctx);
961216295Ssyrinx	return (1);
962216295Ssyrinx}
963216295Ssyrinx
964216295Ssyrinxint32_t
965216295Ssyrinxparse_output(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
966216295Ssyrinx{
967216295Ssyrinx	assert(opt_arg != NULL);
968216295Ssyrinx
969216295Ssyrinx	if (strlen(opt_arg) > strlen("verbose")) {
970216295Ssyrinx		warnx( "Invalid output option - %s",opt_arg);
971216295Ssyrinx		return (-1);
972216295Ssyrinx	}
973216295Ssyrinx
974216295Ssyrinx	if (strncasecmp(opt_arg, "short", strlen(opt_arg)) == 0)
975216295Ssyrinx		SET_OUTPUT(snmptoolctx, OUTPUT_SHORT);
976216295Ssyrinx	else if (strncasecmp(opt_arg, "verbose", strlen(opt_arg)) == 0)
977216295Ssyrinx		SET_OUTPUT(snmptoolctx, OUTPUT_VERBOSE);
978216295Ssyrinx	else if (strncasecmp(opt_arg,"tabular", strlen(opt_arg)) == 0)
979216295Ssyrinx		SET_OUTPUT(snmptoolctx, OUTPUT_TABULAR);
980216295Ssyrinx	else if (strncasecmp(opt_arg, "quiet", strlen(opt_arg)) == 0)
981216295Ssyrinx		SET_OUTPUT(snmptoolctx, OUTPUT_QUIET);
982216295Ssyrinx	else {
983216295Ssyrinx		warnx( "Invalid output option - %s", opt_arg);
984216295Ssyrinx		return (-1);
985216295Ssyrinx	}
986216295Ssyrinx
987216295Ssyrinx	return (2);
988216295Ssyrinx}
989216295Ssyrinx
990216295Ssyrinxint32_t
991216295Ssyrinxparse_errors(struct snmp_toolinfo *snmptoolctx)
992216295Ssyrinx{
993216295Ssyrinx	SET_RETRY(snmptoolctx);
994216295Ssyrinx	return (1);
995216295Ssyrinx}
996216295Ssyrinx
997216295Ssyrinxint32_t
998216295Ssyrinxparse_skip_access(struct snmp_toolinfo *snmptoolctx)
999216295Ssyrinx{
1000216295Ssyrinx	SET_ERRIGNORE(snmptoolctx);
1001216295Ssyrinx	return (1);
1002216295Ssyrinx}
1003216295Ssyrinx
1004216295Ssyrinxchar *
1005216295Ssyrinxsnmp_parse_suboid(char *str, struct asn_oid *oid)
1006216295Ssyrinx{
1007216295Ssyrinx	char *endptr;
1008216295Ssyrinx	asn_subid_t suboid;
1009216295Ssyrinx
1010216295Ssyrinx	if (*str == '.')
1011216295Ssyrinx		str++;
1012216295Ssyrinx
1013216295Ssyrinx	if (*str < '0' || *str > '9')
1014216295Ssyrinx		return (str);
1015216295Ssyrinx
1016216295Ssyrinx	do {
1017216295Ssyrinx		suboid = strtoul(str, &endptr, 10);
1018216295Ssyrinx		if ((asn_subid_t) suboid > ASN_MAXID) {
1019216295Ssyrinx			warnx("Suboid %u > ASN_MAXID", suboid);
1020216295Ssyrinx			return (NULL);
1021216295Ssyrinx		}
1022216295Ssyrinx		if (snmp_suboid_append(oid, suboid) < 0)
1023216295Ssyrinx			return (NULL);
1024216295Ssyrinx		str = endptr + 1;
1025216295Ssyrinx	} while (*endptr == '.');
1026216295Ssyrinx
1027216295Ssyrinx	return (endptr);
1028216295Ssyrinx}
1029216295Ssyrinx
1030216295Ssyrinxstatic char *
1031216295Ssyrinxsnmp_int2asn_oid(char *str, struct asn_oid *oid)
1032216295Ssyrinx{
1033216295Ssyrinx	char *endptr;
1034216295Ssyrinx	int32_t v, saved_errno;
1035216295Ssyrinx
1036216295Ssyrinx	saved_errno = errno;
1037216295Ssyrinx	errno = 0;
1038216295Ssyrinx
1039216295Ssyrinx	v = strtol(str, &endptr, 10);
1040216295Ssyrinx	if (errno != 0) {
1041311595Sngie		warn("Integer value %s not supported", str);
1042216295Ssyrinx		errno = saved_errno;
1043216295Ssyrinx		return (NULL);
1044216295Ssyrinx	}
1045216295Ssyrinx	errno = saved_errno;
1046216295Ssyrinx
1047216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1048216295Ssyrinx		return (NULL);
1049216295Ssyrinx
1050216295Ssyrinx	return (endptr);
1051216295Ssyrinx}
1052216295Ssyrinx
1053216295Ssyrinx/* It is a bit weird to have a table indexed by OID but still... */
1054216295Ssyrinxstatic char *
1055216295Ssyrinxsnmp_oid2asn_oid(struct snmp_toolinfo *snmptoolctx, char *str,
1056216295Ssyrinx    struct asn_oid *oid)
1057216295Ssyrinx{
1058216295Ssyrinx	int32_t i;
1059300559Sngie	char string[MAXSTR + 1], *endptr;
1060216295Ssyrinx	struct snmp_object obj;
1061216295Ssyrinx
1062216295Ssyrinx	for (i = 0; i < MAXSTR; i++)
1063216295Ssyrinx		if (isalpha (*(str + i)) == 0)
1064216295Ssyrinx			break;
1065216295Ssyrinx
1066216295Ssyrinx	endptr = str + i;
1067216295Ssyrinx	memset(&obj, 0, sizeof(struct snmp_object));
1068216295Ssyrinx	if (i == 0) {
1069216295Ssyrinx		if ((endptr = snmp_parse_suboid(str, &(obj.val.var))) == NULL)
1070216295Ssyrinx			return (NULL);
1071216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) obj.val.var.len) < 0)
1072216295Ssyrinx			return (NULL);
1073216295Ssyrinx	} else {
1074216295Ssyrinx		strlcpy(string, str, i + 1);
1075216295Ssyrinx		if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
1076299016Sngie			warnx("Unknown string - %s", string);
1077216295Ssyrinx			return (NULL);
1078216295Ssyrinx		}
1079216295Ssyrinx	}
1080216295Ssyrinx
1081216295Ssyrinx	asn_append_oid(oid, &(obj.val.var));
1082216295Ssyrinx	return (endptr);
1083216295Ssyrinx}
1084216295Ssyrinx
1085216295Ssyrinxstatic char *
1086216295Ssyrinxsnmp_ip2asn_oid(char *str, struct asn_oid *oid)
1087216295Ssyrinx{
1088216295Ssyrinx	uint32_t v;
1089216295Ssyrinx	int32_t i;
1090216295Ssyrinx	char *endptr, *ptr;
1091216295Ssyrinx
1092216295Ssyrinx	ptr = str;
1093310912Sngie
1094216295Ssyrinx	for (i = 0; i < 4; i++) {
1095216295Ssyrinx		v = strtoul(ptr, &endptr, 10);
1096216295Ssyrinx		if (v > 0xff)
1097216295Ssyrinx			return (NULL);
1098216295Ssyrinx		if (*endptr != '.' && strchr("],\0", *endptr) == NULL && i != 3)
1099216295Ssyrinx			return (NULL);
1100216295Ssyrinx		if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1101216295Ssyrinx			return (NULL);
1102216295Ssyrinx		ptr = endptr + 1;
1103216295Ssyrinx	}
1104216295Ssyrinx
1105216295Ssyrinx	return (endptr);
1106216295Ssyrinx}
1107216295Ssyrinx
1108216295Ssyrinx/* 32-bit counter, gauge, timeticks. */
1109216295Ssyrinxstatic char *
1110216295Ssyrinxsnmp_uint2asn_oid(char *str, struct asn_oid *oid)
1111216295Ssyrinx{
1112216295Ssyrinx	char *endptr;
1113216295Ssyrinx	uint32_t v;
1114216295Ssyrinx	int32_t saved_errno;
1115216295Ssyrinx
1116216295Ssyrinx	saved_errno = errno;
1117216295Ssyrinx	errno = 0;
1118216295Ssyrinx
1119216295Ssyrinx	v = strtoul(str, &endptr, 10);
1120216295Ssyrinx	if (errno != 0) {
1121311595Sngie		warn("Integer value %s not supported", str);
1122216295Ssyrinx		errno = saved_errno;
1123216295Ssyrinx		return (NULL);
1124216295Ssyrinx	}
1125216295Ssyrinx	errno = saved_errno;
1126216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) v) < 0)
1127216295Ssyrinx		return (NULL);
1128216295Ssyrinx
1129216295Ssyrinx	return (endptr);
1130216295Ssyrinx}
1131216295Ssyrinx
1132216295Ssyrinxstatic char *
1133216295Ssyrinxsnmp_cnt64_2asn_oid(char *str, struct asn_oid *oid)
1134216295Ssyrinx{
1135216295Ssyrinx	char *endptr;
1136216295Ssyrinx	uint64_t v;
1137216295Ssyrinx	int32_t saved_errno;
1138216295Ssyrinx
1139216295Ssyrinx	saved_errno = errno;
1140216295Ssyrinx	errno = 0;
1141216295Ssyrinx
1142216295Ssyrinx	v = strtoull(str, &endptr, 10);
1143216295Ssyrinx
1144216295Ssyrinx	if (errno != 0) {
1145311595Sngie		warn("Integer value %s not supported", str);
1146216295Ssyrinx		errno = saved_errno;
1147216295Ssyrinx		return (NULL);
1148216295Ssyrinx	}
1149216295Ssyrinx	errno = saved_errno;
1150216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v & 0xffffffff)) < 0)
1151216295Ssyrinx		return (NULL);
1152216295Ssyrinx
1153216295Ssyrinx	if (snmp_suboid_append(oid, (asn_subid_t) (v >> 32)) < 0)
1154216295Ssyrinx		return (NULL);
1155216295Ssyrinx
1156216295Ssyrinx	return (endptr);
1157216295Ssyrinx}
1158216295Ssyrinx
1159216295Ssyrinxenum snmp_syntax
1160216295Ssyrinxparse_syntax(char *str)
1161216295Ssyrinx{
1162216295Ssyrinx	int32_t i;
1163216295Ssyrinx
1164216295Ssyrinx	for (i = 0; i < SNMP_SYNTAX_UNKNOWN; i++) {
1165216295Ssyrinx		if (strncmp(syntax_strings[i].str, str,
1166216295Ssyrinx		    strlen(syntax_strings[i].str)) == 0)
1167216295Ssyrinx			return (syntax_strings[i].stx);
1168216295Ssyrinx	}
1169216295Ssyrinx
1170216295Ssyrinx	return (SNMP_SYNTAX_NULL);
1171216295Ssyrinx}
1172216295Ssyrinx
1173216295Ssyrinxstatic char *
1174216295Ssyrinxsnmp_parse_subindex(struct snmp_toolinfo *snmptoolctx, char *str,
1175216295Ssyrinx    struct index *idx, struct snmp_object *object)
1176216295Ssyrinx{
1177216295Ssyrinx	char *ptr;
1178216295Ssyrinx	int32_t i;
1179216295Ssyrinx	enum snmp_syntax stx;
1180216295Ssyrinx	char syntax[MAX_CMD_SYNTAX_LEN];
1181216295Ssyrinx
1182216295Ssyrinx	ptr = str;
1183216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
1184216295Ssyrinx		for (i = 0; i < MAX_CMD_SYNTAX_LEN ; i++) {
1185216295Ssyrinx			if (*(ptr + i) == ':')
1186216295Ssyrinx				break;
1187216295Ssyrinx		}
1188216295Ssyrinx
1189216295Ssyrinx		if (i >= MAX_CMD_SYNTAX_LEN) {
1190216295Ssyrinx			warnx("Unknown syntax in OID - %s", str);
1191216295Ssyrinx			return (NULL);
1192216295Ssyrinx		}
1193216295Ssyrinx		/* Expect a syntax string here. */
1194216295Ssyrinx		if ((stx = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
1195216295Ssyrinx			warnx("Invalid  syntax - %s",syntax);
1196216295Ssyrinx			return (NULL);
1197216295Ssyrinx		}
1198216295Ssyrinx
1199216295Ssyrinx		if (stx != idx->syntax && !ISSET_ERRIGNORE(snmptoolctx)) {
1200216295Ssyrinx			warnx("Syntax mismatch - %d expected, %d given",
1201216295Ssyrinx			    idx->syntax, stx);
1202216295Ssyrinx			return (NULL);
1203216295Ssyrinx		}
1204216295Ssyrinx		/*
1205216295Ssyrinx		 * That is where the suboid started + the syntax length + one
1206216295Ssyrinx		 * character for ':'.
1207216295Ssyrinx		 */
1208216295Ssyrinx		ptr = str + i + 1;
1209216295Ssyrinx	} else
1210216295Ssyrinx		stx = idx->syntax;
1211216295Ssyrinx
1212216295Ssyrinx	switch (stx) {
1213216295Ssyrinx		case SNMP_SYNTAX_INTEGER:
1214216295Ssyrinx			return (snmp_int2asn_oid(ptr, &(object->val.var)));
1215216295Ssyrinx		case SNMP_SYNTAX_OID:
1216216295Ssyrinx			return (snmp_oid2asn_oid(snmptoolctx, ptr,
1217216295Ssyrinx			    &(object->val.var)));
1218216295Ssyrinx		case SNMP_SYNTAX_IPADDRESS:
1219216295Ssyrinx			return (snmp_ip2asn_oid(ptr, &(object->val.var)));
1220216295Ssyrinx		case SNMP_SYNTAX_COUNTER:
1221216295Ssyrinx			/* FALLTHROUGH */
1222216295Ssyrinx		case SNMP_SYNTAX_GAUGE:
1223216295Ssyrinx			/* FALLTHROUGH */
1224216295Ssyrinx		case SNMP_SYNTAX_TIMETICKS:
1225216295Ssyrinx			return (snmp_uint2asn_oid(ptr, &(object->val.var)));
1226216295Ssyrinx		case SNMP_SYNTAX_COUNTER64:
1227216295Ssyrinx			return (snmp_cnt64_2asn_oid(ptr, &(object->val.var)));
1228216295Ssyrinx		case SNMP_SYNTAX_OCTETSTRING:
1229216295Ssyrinx			return (snmp_tc2oid(idx->tc, ptr, &(object->val.var)));
1230216295Ssyrinx		default:
1231216295Ssyrinx			/* NOTREACHED */
1232216295Ssyrinx			break;
1233216295Ssyrinx	}
1234216295Ssyrinx
1235216295Ssyrinx	return (NULL);
1236216295Ssyrinx}
1237216295Ssyrinx
1238216295Ssyrinxchar *
1239216295Ssyrinxsnmp_parse_index(struct snmp_toolinfo *snmptoolctx, char *str,
1240216295Ssyrinx    struct snmp_object *object)
1241216295Ssyrinx{
1242216295Ssyrinx	char *ptr;
1243216295Ssyrinx	struct index *temp;
1244216295Ssyrinx
1245216295Ssyrinx	if (object->info->table_idx == NULL)
1246216295Ssyrinx		return (NULL);
1247216295Ssyrinx
1248216295Ssyrinx	ptr = NULL;
1249216295Ssyrinx	STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(object)), link) {
1250216295Ssyrinx		if ((ptr = snmp_parse_subindex(snmptoolctx, str, temp, object))
1251216295Ssyrinx		    == NULL)
1252216295Ssyrinx			return (NULL);
1253216295Ssyrinx
1254216295Ssyrinx		if (*ptr != ',' && *ptr != ']')
1255216295Ssyrinx			return (NULL);
1256216295Ssyrinx		str = ptr + 1;
1257216295Ssyrinx	}
1258216295Ssyrinx
1259216295Ssyrinx	if (ptr == NULL || *ptr != ']') {
1260216295Ssyrinx		warnx("Mismatching index - %s", str);
1261216295Ssyrinx		return (NULL);
1262216295Ssyrinx	}
1263216295Ssyrinx
1264216295Ssyrinx	return (ptr + 1);
1265216295Ssyrinx}
1266216295Ssyrinx
1267216295Ssyrinx/*
1268216295Ssyrinx * Fill in the struct asn_oid member of snmp_value with suboids from input.
1269216295Ssyrinx * If an error occurs - print message on stderr and return (-1).
1270216295Ssyrinx * If all is ok - return the length of the oid.
1271216295Ssyrinx */
1272216295Ssyrinxint32_t
1273216295Ssyrinxsnmp_parse_numoid(char *argv, struct asn_oid *var)
1274216295Ssyrinx{
1275216295Ssyrinx	char *endptr, *str;
1276216295Ssyrinx	asn_subid_t suboid;
1277216295Ssyrinx
1278216295Ssyrinx	str = argv;
1279216295Ssyrinx
1280216295Ssyrinx	if (*str == '.')
1281216295Ssyrinx		str++;
1282216295Ssyrinx
1283216295Ssyrinx	do {
1284216295Ssyrinx		if (var->len == ASN_MAXOIDLEN) {
1285216295Ssyrinx			warnx("Oid too long - %u", var->len);
1286216295Ssyrinx			return (-1);
1287216295Ssyrinx		}
1288216295Ssyrinx
1289216295Ssyrinx		suboid = strtoul(str, &endptr, 10);
1290216295Ssyrinx		if (suboid > ASN_MAXID) {
1291216295Ssyrinx			warnx("Oid too long - %u", var->len);
1292216295Ssyrinx			return (-1);
1293216295Ssyrinx		}
1294216295Ssyrinx
1295216295Ssyrinx		var->subs[var->len++] = suboid;
1296216295Ssyrinx		str = endptr + 1;
1297216295Ssyrinx	} while ( *endptr == '.');
1298216295Ssyrinx
1299216295Ssyrinx	if (*endptr != '\0') {
1300216295Ssyrinx		warnx("Invalid oid string - %s", argv);
1301216295Ssyrinx		return (-1);
1302216295Ssyrinx	}
1303216295Ssyrinx
1304216295Ssyrinx	return (var->len);
1305216295Ssyrinx}
1306216295Ssyrinx
1307216295Ssyrinx/* Append a length 1 suboid to an asn_oid structure. */
1308216295Ssyrinxint32_t
1309216295Ssyrinxsnmp_suboid_append(struct asn_oid *var, asn_subid_t suboid)
1310216295Ssyrinx{
1311216295Ssyrinx	if (var == NULL)
1312216295Ssyrinx		return (-1);
1313216295Ssyrinx
1314216295Ssyrinx	if (var->len >= ASN_MAXOIDLEN) {
1315216295Ssyrinx		warnx("Oid too long - %u", var->len);
1316216295Ssyrinx		return (-1);
1317216295Ssyrinx	}
1318216295Ssyrinx
1319216295Ssyrinx	var->subs[var->len++] = suboid;
1320216295Ssyrinx
1321216295Ssyrinx	return (1);
1322216295Ssyrinx}
1323216295Ssyrinx
1324216295Ssyrinx/* Pop the last suboid from an asn_oid structure. */
1325216295Ssyrinxint32_t
1326216295Ssyrinxsnmp_suboid_pop(struct asn_oid *var)
1327216295Ssyrinx{
1328216295Ssyrinx	asn_subid_t suboid;
1329216295Ssyrinx
1330216295Ssyrinx	if (var == NULL)
1331216295Ssyrinx		return (-1);
1332216295Ssyrinx
1333216295Ssyrinx	if (var->len < 1)
1334216295Ssyrinx		return (-1);
1335216295Ssyrinx
1336216295Ssyrinx	suboid = var->subs[--(var->len)];
1337216295Ssyrinx	var->subs[var->len] = 0;
1338216295Ssyrinx
1339216295Ssyrinx	return (suboid);
1340216295Ssyrinx}
1341216295Ssyrinx
1342216295Ssyrinx/*
1343216295Ssyrinx * Parse the command-line provided string into an OID - alocate memory for a new
1344216295Ssyrinx * snmp object, fill in its fields and insert it in the object list. A
1345216295Ssyrinx * (snmp_verify_inoid_f) function must be provided to validate the input string.
1346216295Ssyrinx */
1347216295Ssyrinxint32_t
1348216295Ssyrinxsnmp_object_add(struct snmp_toolinfo *snmptoolctx, snmp_verify_inoid_f func,
1349216295Ssyrinx    char *string)
1350216295Ssyrinx{
1351216295Ssyrinx	struct snmp_object *obj;
1352216295Ssyrinx
1353216295Ssyrinx	if (snmptoolctx == NULL)
1354216295Ssyrinx		return (-1);
1355216295Ssyrinx
1356216295Ssyrinx	/* XXX-BZ does that chack make sense? */
1357216295Ssyrinx	if (snmptoolctx->objects >= SNMP_MAX_BINDINGS) {
1358216295Ssyrinx		warnx("Too many bindings in PDU - %u", snmptoolctx->objects + 1);
1359216295Ssyrinx		return (-1);
1360216295Ssyrinx	}
1361216295Ssyrinx
1362300471Sngie	if ((obj = calloc(1, sizeof(struct snmp_object))) == NULL) {
1363216295Ssyrinx		syslog(LOG_ERR, "malloc() failed: %s", strerror(errno));
1364216295Ssyrinx		return (-1);
1365216295Ssyrinx	}
1366216295Ssyrinx
1367216295Ssyrinx	if (func(snmptoolctx, obj, string) < 0) {
1368216295Ssyrinx		warnx("Invalid OID - %s", string);
1369216295Ssyrinx		free(obj);
1370216295Ssyrinx		return (-1);
1371216295Ssyrinx	}
1372216295Ssyrinx
1373216295Ssyrinx	snmptoolctx->objects++;
1374216295Ssyrinx	SLIST_INSERT_HEAD(&snmptoolctx->snmp_objectlist, obj, link);
1375216295Ssyrinx
1376216295Ssyrinx	return (1);
1377216295Ssyrinx}
1378216295Ssyrinx
1379216295Ssyrinx/* Given an OID, find it in the object list and remove it. */
1380216295Ssyrinxint32_t
1381216295Ssyrinxsnmp_object_remove(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1382216295Ssyrinx{
1383216295Ssyrinx	struct snmp_object *temp;
1384216295Ssyrinx
1385216295Ssyrinx	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist)) {
1386216295Ssyrinx		warnx("Object list already empty");
1387216295Ssyrinx		return (-1);
1388216295Ssyrinx	}
1389216295Ssyrinx
1390216295Ssyrinx
1391216295Ssyrinx	SLIST_FOREACH(temp, &snmptoolctx->snmp_objectlist, link)
1392216295Ssyrinx		if (asn_compare_oid(&(temp->val.var), oid) == 0)
1393216295Ssyrinx			break;
1394216295Ssyrinx
1395216295Ssyrinx	if (temp == NULL) {
1396216295Ssyrinx		warnx("No such object in list");
1397216295Ssyrinx		return (-1);
1398216295Ssyrinx	}
1399216295Ssyrinx
1400216295Ssyrinx	SLIST_REMOVE(&snmptoolctx->snmp_objectlist, temp, snmp_object, link);
1401216295Ssyrinx	if (temp->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1402216295Ssyrinx	    temp->val.v.octetstring.octets != NULL)
1403216295Ssyrinx		free(temp->val.v.octetstring.octets);
1404216295Ssyrinx	free(temp);
1405216295Ssyrinx
1406216295Ssyrinx	return (1);
1407216295Ssyrinx}
1408216295Ssyrinx
1409216295Ssyrinxstatic void
1410216295Ssyrinxsnmp_object_freeall(struct snmp_toolinfo *snmptoolctx)
1411216295Ssyrinx{
1412216295Ssyrinx	struct snmp_object *o;
1413216295Ssyrinx
1414216295Ssyrinx	while ((o = SLIST_FIRST(&snmptoolctx->snmp_objectlist)) != NULL) {
1415216295Ssyrinx		SLIST_REMOVE_HEAD(&snmptoolctx->snmp_objectlist, link);
1416216295Ssyrinx
1417216295Ssyrinx		if (o->val.syntax == SNMP_SYNTAX_OCTETSTRING &&
1418216295Ssyrinx		    o->val.v.octetstring.octets != NULL)
1419216295Ssyrinx			free(o->val.v.octetstring.octets);
1420216295Ssyrinx		free(o);
1421216295Ssyrinx	}
1422216295Ssyrinx}
1423216295Ssyrinx
1424216295Ssyrinx/* Do all possible memory release before exit. */
1425216295Ssyrinxvoid
1426216295Ssyrinxsnmp_tool_freeall(struct snmp_toolinfo *snmptoolctx)
1427216295Ssyrinx{
1428216295Ssyrinx	if (snmp_client.chost != NULL) {
1429216295Ssyrinx		free(snmp_client.chost);
1430216295Ssyrinx		snmp_client.chost = NULL;
1431216295Ssyrinx	}
1432216295Ssyrinx
1433216295Ssyrinx	if (snmp_client.cport != NULL) {
1434216295Ssyrinx		free(snmp_client.cport);
1435216295Ssyrinx		snmp_client.cport = NULL;
1436216295Ssyrinx	}
1437216295Ssyrinx
1438216295Ssyrinx	snmp_mapping_free(snmptoolctx);
1439216295Ssyrinx	free_filelist(snmptoolctx);
1440216295Ssyrinx	snmp_object_freeall(snmptoolctx);
1441216295Ssyrinx
1442216295Ssyrinx	if (snmptoolctx->passwd != NULL) {
1443216295Ssyrinx		free(snmptoolctx->passwd);
1444216295Ssyrinx		snmptoolctx->passwd = NULL;
1445216295Ssyrinx	}
1446216295Ssyrinx}
1447216295Ssyrinx
1448216295Ssyrinx/*
1449216295Ssyrinx * Fill all variables from the object list into a PDU. (snmp_verify_vbind_f)
1450216295Ssyrinx * function should check whether the variable is consistent in this PDU
1451216295Ssyrinx * (e.g do not add non-leaf OIDs to a GET PDU, or OIDs with read access only to
1452216295Ssyrinx * a SET PDU) - might be NULL though. (snmp_add_vbind_f) function is the
1453216295Ssyrinx * function actually adds the variable to the PDU and must not be NULL.
1454216295Ssyrinx */
1455216295Ssyrinxint32_t
1456216295Ssyrinxsnmp_pdu_add_bindings(struct snmp_toolinfo *snmptoolctx,
1457216295Ssyrinx    snmp_verify_vbind_f vfunc, snmp_add_vbind_f afunc,
1458216295Ssyrinx    struct snmp_pdu *pdu, int32_t maxcount)
1459216295Ssyrinx{
1460216295Ssyrinx	int32_t nbindings, abind;
1461216295Ssyrinx	struct snmp_object *obj;
1462216295Ssyrinx
1463216295Ssyrinx	if (pdu == NULL || afunc == NULL)
1464216295Ssyrinx		return (-1);
1465216295Ssyrinx
1466216295Ssyrinx	/* Return 0 in case of no more work todo. */
1467216295Ssyrinx	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist))
1468216295Ssyrinx		return (0);
1469310903Sngie
1470216295Ssyrinx	if (maxcount < 0 || maxcount > SNMP_MAX_BINDINGS) {
1471216295Ssyrinx		warnx("maxcount out of range: <0 || >SNMP_MAX_BINDINGS");
1472216295Ssyrinx		return (-1);
1473216295Ssyrinx	}
1474216295Ssyrinx
1475216295Ssyrinx	nbindings = 0;
1476216295Ssyrinx	SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link) {
1477216295Ssyrinx		if ((vfunc != NULL) && (vfunc(snmptoolctx, pdu, obj) < 0)) {
1478216295Ssyrinx			nbindings = -1;
1479216295Ssyrinx			break;
1480216295Ssyrinx		}
1481216295Ssyrinx		if ((abind = afunc(pdu, obj)) < 0) {
1482216295Ssyrinx			nbindings = -1;
1483216295Ssyrinx			break;
1484216295Ssyrinx		}
1485216295Ssyrinx
1486216295Ssyrinx		if (abind > 0) {
1487216295Ssyrinx			/* Do not put more varbindings than requested. */
1488216295Ssyrinx			if (++nbindings >= maxcount)
1489216295Ssyrinx				break;
1490216295Ssyrinx		}
1491216295Ssyrinx	}
1492216295Ssyrinx
1493216295Ssyrinx	return (nbindings);
1494216295Ssyrinx}
1495216295Ssyrinx
1496216295Ssyrinx/*
1497216295Ssyrinx * Locate an object in the object list and set a corresponding error status.
1498216295Ssyrinx */
1499216295Ssyrinxint32_t
1500216295Ssyrinxsnmp_object_seterror(struct snmp_toolinfo *snmptoolctx,
1501216295Ssyrinx    struct snmp_value *err_value, int32_t error_status)
1502216295Ssyrinx{
1503216295Ssyrinx	struct snmp_object *obj;
1504216295Ssyrinx
1505216295Ssyrinx	if (SLIST_EMPTY(&snmptoolctx->snmp_objectlist) || err_value == NULL)
1506216295Ssyrinx		return (-1);
1507216295Ssyrinx
1508216295Ssyrinx	SLIST_FOREACH(obj, &snmptoolctx->snmp_objectlist, link)
1509216295Ssyrinx		if (asn_compare_oid(&(err_value->var), &(obj->val.var)) == 0) {
1510216295Ssyrinx			obj->error = error_status;
1511216295Ssyrinx			return (1);
1512216295Ssyrinx		}
1513216295Ssyrinx
1514216295Ssyrinx	return (0);
1515216295Ssyrinx}
1516216295Ssyrinx
1517216295Ssyrinx/*
1518228990Suqs * Check a PDU received in response to a SNMP_PDU_GET/SNMP_PDU_GETBULK request
1519216295Ssyrinx * but don't compare syntaxes - when sending a request PDU they must be null.
1520216295Ssyrinx * This is a (almost) complete copy of snmp_pdu_check() - with matching syntaxes
1521228990Suqs * checks and some other checks skipped.
1522216295Ssyrinx */
1523216295Ssyrinxint32_t
1524216295Ssyrinxsnmp_parse_get_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1525216295Ssyrinx{
1526216295Ssyrinx	uint32_t i;
1527216295Ssyrinx
1528216295Ssyrinx	for (i = 0; i < req->nbindings; i++) {
1529216295Ssyrinx		if (asn_compare_oid(&req->bindings[i].var,
1530216295Ssyrinx		    &resp->bindings[i].var) != 0) {
1531216295Ssyrinx			warnx("Bad OID in response");
1532216295Ssyrinx			return (-1);
1533216295Ssyrinx		}
1534216295Ssyrinx
1535216295Ssyrinx		if (snmp_client.version != SNMP_V1 && (resp->bindings[i].syntax
1536216295Ssyrinx		    == SNMP_SYNTAX_NOSUCHOBJECT || resp->bindings[i].syntax ==
1537216295Ssyrinx		    SNMP_SYNTAX_NOSUCHINSTANCE))
1538216295Ssyrinx			return (0);
1539216295Ssyrinx	}
1540216295Ssyrinx
1541216295Ssyrinx	return (1);
1542216295Ssyrinx}
1543216295Ssyrinx
1544216295Ssyrinxint32_t
1545216295Ssyrinxsnmp_parse_getbulk_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1546216295Ssyrinx{
1547216295Ssyrinx	int32_t N, R, M, r;
1548216295Ssyrinx
1549216295Ssyrinx	if (req->error_status > (int32_t) resp->nbindings) {
1550216295Ssyrinx		warnx("Bad number of bindings in response");
1551216295Ssyrinx		return (-1);
1552216295Ssyrinx	}
1553216295Ssyrinx
1554216295Ssyrinx	for (N = 0; N < req->error_status; N++) {
1555216295Ssyrinx		if (asn_is_suboid(&req->bindings[N].var,
1556216295Ssyrinx		    &resp->bindings[N].var) == 0)
1557216295Ssyrinx			return (0);
1558216295Ssyrinx		if (resp->bindings[N].syntax == SNMP_SYNTAX_ENDOFMIBVIEW)
1559216295Ssyrinx			return (0);
1560216295Ssyrinx	}
1561216295Ssyrinx
1562216295Ssyrinx	for (R = N , r = N; R  < (int32_t) req->nbindings; R++) {
1563216295Ssyrinx		for (M = 0; M < req->error_index && (r + M) <
1564216295Ssyrinx		    (int32_t) resp->nbindings; M++) {
1565216295Ssyrinx			if (asn_is_suboid(&req->bindings[R].var,
1566216295Ssyrinx			    &resp->bindings[r + M].var) == 0)
1567216295Ssyrinx				return (0);
1568216295Ssyrinx
1569216295Ssyrinx			if (resp->bindings[r + M].syntax ==
1570216295Ssyrinx			    SNMP_SYNTAX_ENDOFMIBVIEW) {
1571216295Ssyrinx				M++;
1572216295Ssyrinx				break;
1573216295Ssyrinx			}
1574216295Ssyrinx		}
1575216295Ssyrinx		r += M;
1576216295Ssyrinx	}
1577216295Ssyrinx
1578216295Ssyrinx	return (0);
1579216295Ssyrinx}
1580216295Ssyrinx
1581216295Ssyrinxint32_t
1582216295Ssyrinxsnmp_parse_getnext_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1583216295Ssyrinx{
1584216295Ssyrinx	uint32_t i;
1585216295Ssyrinx
1586216295Ssyrinx	for (i = 0; i < req->nbindings; i++) {
1587216295Ssyrinx		if (asn_is_suboid(&req->bindings[i].var, &resp->bindings[i].var)
1588216295Ssyrinx		    == 0)
1589216295Ssyrinx			return (0);
1590216295Ssyrinx
1591216295Ssyrinx		if (resp->version != SNMP_V1 && resp->bindings[i].syntax ==
1592216295Ssyrinx		    SNMP_SYNTAX_ENDOFMIBVIEW)
1593216295Ssyrinx			return (0);
1594216295Ssyrinx	}
1595216295Ssyrinx
1596216295Ssyrinx	return (1);
1597216295Ssyrinx}
1598216295Ssyrinx
1599216295Ssyrinx/*
1600228990Suqs * Should be called to check a response to get/getnext/getbulk.
1601216295Ssyrinx */
1602216295Ssyrinxint32_t
1603216295Ssyrinxsnmp_parse_resp(struct snmp_pdu *resp, struct snmp_pdu *req)
1604216295Ssyrinx{
1605216295Ssyrinx	if (resp == NULL || req == NULL)
1606216295Ssyrinx		return (-2);
1607216295Ssyrinx
1608216295Ssyrinx	if (resp->version != req->version) {
1609216295Ssyrinx		warnx("Response has wrong version");
1610216295Ssyrinx		return (-1);
1611216295Ssyrinx	}
1612216295Ssyrinx
1613216295Ssyrinx	if (resp->error_status == SNMP_ERR_NOSUCHNAME) {
1614216295Ssyrinx		warnx("Error - No Such Name");
1615216295Ssyrinx		return (0);
1616216295Ssyrinx	}
1617216295Ssyrinx
1618216295Ssyrinx	if (resp->error_status != SNMP_ERR_NOERROR) {
1619228990Suqs		warnx("Error %d in response", resp->error_status);
1620216295Ssyrinx		return (-1);
1621216295Ssyrinx	}
1622216295Ssyrinx
1623216295Ssyrinx	if (resp->nbindings != req->nbindings && req->type != SNMP_PDU_GETBULK){
1624216295Ssyrinx		warnx("Bad number of bindings in response");
1625216295Ssyrinx		return (-1);
1626216295Ssyrinx	}
1627216295Ssyrinx
1628216295Ssyrinx	switch (req->type) {
1629216295Ssyrinx		case SNMP_PDU_GET:
1630216295Ssyrinx			return (snmp_parse_get_resp(resp,req));
1631216295Ssyrinx		case SNMP_PDU_GETBULK:
1632216295Ssyrinx			return (snmp_parse_getbulk_resp(resp,req));
1633216295Ssyrinx		case SNMP_PDU_GETNEXT:
1634216295Ssyrinx			return (snmp_parse_getnext_resp(resp,req));
1635216295Ssyrinx		default:
1636216295Ssyrinx			/* NOTREACHED */
1637216295Ssyrinx			break;
1638216295Ssyrinx	}
1639216295Ssyrinx
1640216295Ssyrinx	return (-2);
1641216295Ssyrinx}
1642216295Ssyrinx
1643216295Ssyrinxstatic void
1644216295Ssyrinxsnmp_output_octetstring(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1645216295Ssyrinx    uint32_t len, uint8_t *octets)
1646216295Ssyrinx{
1647216295Ssyrinx	char *buf;
1648216295Ssyrinx
1649216295Ssyrinx	if (len == 0 || octets == NULL)
1650216295Ssyrinx		return;
1651216295Ssyrinx
1652216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1653216295Ssyrinx		fprintf(stdout, "%s : ",
1654216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_OCTETSTRING].str);
1655216295Ssyrinx
1656216295Ssyrinx	if ((buf = snmp_oct2tc(tc, len, (char *) octets)) != NULL) {
1657216295Ssyrinx		fprintf(stdout, "%s", buf);
1658216295Ssyrinx		free(buf);
1659216295Ssyrinx	}
1660216295Ssyrinx}
1661216295Ssyrinx
1662216295Ssyrinxstatic void
1663216295Ssyrinxsnmp_output_octetindex(struct snmp_toolinfo *snmptoolctx, enum snmp_tc tc,
1664216295Ssyrinx    struct asn_oid *oid)
1665216295Ssyrinx{
1666216295Ssyrinx	uint32_t i;
1667216295Ssyrinx	uint8_t *s;
1668216295Ssyrinx
1669216295Ssyrinx	if ((s = malloc(oid->subs[0] + 1)) == NULL)
1670216295Ssyrinx		syslog(LOG_ERR, "malloc failed - %s", strerror(errno));
1671216295Ssyrinx	else {
1672216295Ssyrinx		for (i = 0; i < oid->subs[0]; i++)
1673216295Ssyrinx			s[i] = (u_char) (oid->subs[i + 1]);
1674216295Ssyrinx
1675216295Ssyrinx		snmp_output_octetstring(snmptoolctx, tc, oid->subs[0], s);
1676216295Ssyrinx		free(s);
1677216295Ssyrinx	}
1678216295Ssyrinx}
1679216295Ssyrinx
1680216295Ssyrinx/*
1681216295Ssyrinx * Check and output syntax type and value.
1682216295Ssyrinx */
1683216295Ssyrinxstatic void
1684216295Ssyrinxsnmp_output_oid_value(struct snmp_toolinfo *snmptoolctx, struct asn_oid *oid)
1685216295Ssyrinx{
1686216295Ssyrinx	char oid_string[ASN_OIDSTRLEN];
1687216295Ssyrinx	struct snmp_object obj;
1688216295Ssyrinx
1689216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1690216295Ssyrinx		fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_OID].str);
1691216295Ssyrinx
1692216295Ssyrinx	if(!ISSET_NUMERIC(snmptoolctx)) {
1693216295Ssyrinx		memset(&obj, 0, sizeof(struct snmp_object));
1694216295Ssyrinx		asn_append_oid(&(obj.val.var), oid);
1695216295Ssyrinx
1696216295Ssyrinx		if (snmp_lookup_enumstring(snmptoolctx, &obj) > 0)
1697216295Ssyrinx			fprintf(stdout, "%s" , obj.info->string);
1698216295Ssyrinx		else if (snmp_lookup_oidstring(snmptoolctx, &obj) > 0)
1699216295Ssyrinx			fprintf(stdout, "%s" , obj.info->string);
1700216295Ssyrinx		else if (snmp_lookup_nodestring(snmptoolctx, &obj) > 0)
1701216295Ssyrinx			fprintf(stdout, "%s" , obj.info->string);
1702216295Ssyrinx		else {
1703216295Ssyrinx			(void) asn_oid2str_r(oid, oid_string);
1704216295Ssyrinx			fprintf(stdout, "%s", oid_string);
1705216295Ssyrinx		}
1706216295Ssyrinx	} else {
1707216295Ssyrinx		(void) asn_oid2str_r(oid, oid_string);
1708216295Ssyrinx		fprintf(stdout, "%s", oid_string);
1709216295Ssyrinx	}
1710216295Ssyrinx}
1711216295Ssyrinx
1712216295Ssyrinxstatic void
1713216295Ssyrinxsnmp_output_int(struct snmp_toolinfo *snmptoolctx, struct enum_pairs *enums,
1714216295Ssyrinx    int32_t int_val)
1715216295Ssyrinx{
1716216295Ssyrinx	char *string;
1717216295Ssyrinx
1718216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1719216295Ssyrinx		fprintf(stdout, "%s : ",
1720216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_INTEGER].str);
1721216295Ssyrinx
1722216295Ssyrinx	if (enums != NULL && (string = enum_string_lookup(enums, int_val))
1723216295Ssyrinx	    != NULL)
1724216295Ssyrinx		fprintf(stdout, "%s", string);
1725216295Ssyrinx	else
1726216295Ssyrinx		fprintf(stdout, "%d", int_val);
1727216295Ssyrinx}
1728216295Ssyrinx
1729216295Ssyrinxstatic void
1730216295Ssyrinxsnmp_output_ipaddress(struct snmp_toolinfo *snmptoolctx, uint8_t *ip)
1731216295Ssyrinx{
1732216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1733216295Ssyrinx		fprintf(stdout, "%s : ",
1734216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_IPADDRESS].str);
1735216295Ssyrinx
1736216295Ssyrinx	fprintf(stdout, "%u.%u.%u.%u", ip[0], ip[1], ip[2], ip[3]);
1737216295Ssyrinx}
1738216295Ssyrinx
1739216295Ssyrinxstatic void
1740216295Ssyrinxsnmp_output_counter(struct snmp_toolinfo *snmptoolctx, uint32_t counter)
1741216295Ssyrinx{
1742216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1743216295Ssyrinx		fprintf(stdout, "%s : ",
1744216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_COUNTER].str);
1745216295Ssyrinx
1746216295Ssyrinx	fprintf(stdout, "%u", counter);
1747216295Ssyrinx}
1748216295Ssyrinx
1749216295Ssyrinxstatic void
1750216295Ssyrinxsnmp_output_gauge(struct snmp_toolinfo *snmptoolctx, uint32_t gauge)
1751216295Ssyrinx{
1752216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1753216295Ssyrinx		fprintf(stdout, "%s : ", syntax_strings[SNMP_SYNTAX_GAUGE].str);
1754216295Ssyrinx
1755216295Ssyrinx	fprintf(stdout, "%u", gauge);
1756216295Ssyrinx}
1757216295Ssyrinx
1758216295Ssyrinxstatic void
1759216295Ssyrinxsnmp_output_ticks(struct snmp_toolinfo *snmptoolctx, uint32_t ticks)
1760216295Ssyrinx{
1761216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1762216295Ssyrinx		fprintf(stdout, "%s : ",
1763216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_TIMETICKS].str);
1764216295Ssyrinx
1765216295Ssyrinx	fprintf(stdout, "%u", ticks);
1766216295Ssyrinx}
1767216295Ssyrinx
1768216295Ssyrinxstatic void
1769216295Ssyrinxsnmp_output_counter64(struct snmp_toolinfo *snmptoolctx, uint64_t counter64)
1770216295Ssyrinx{
1771216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE)
1772216295Ssyrinx		fprintf(stdout, "%s : ",
1773216295Ssyrinx		    syntax_strings[SNMP_SYNTAX_COUNTER64].str);
1774216295Ssyrinx
1775216295Ssyrinx	fprintf(stdout,"%ju", counter64);
1776216295Ssyrinx}
1777216295Ssyrinx
1778216295Ssyrinxint32_t
1779216295Ssyrinxsnmp_output_numval(struct snmp_toolinfo *snmptoolctx, struct snmp_value *val,
1780216295Ssyrinx    struct snmp_oid2str *entry)
1781216295Ssyrinx{
1782216295Ssyrinx	if (val == NULL)
1783216295Ssyrinx		return (-1);
1784216295Ssyrinx
1785216295Ssyrinx	if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1786216295Ssyrinx		fprintf(stdout, " = ");
1787216295Ssyrinx
1788216295Ssyrinx	switch (val->syntax) {
1789216295Ssyrinx	    case SNMP_SYNTAX_INTEGER:
1790216295Ssyrinx		if (entry != NULL)
1791216295Ssyrinx			snmp_output_int(snmptoolctx, entry->snmp_enum,
1792216295Ssyrinx			    val->v.integer);
1793216295Ssyrinx		else
1794216295Ssyrinx			snmp_output_int(snmptoolctx, NULL, val->v.integer);
1795216295Ssyrinx		break;
1796216295Ssyrinx
1797216295Ssyrinx	    case SNMP_SYNTAX_OCTETSTRING:
1798216295Ssyrinx		if (entry != NULL)
1799216295Ssyrinx			snmp_output_octetstring(snmptoolctx, entry->tc,
1800216295Ssyrinx			    val->v.octetstring.len, val->v.octetstring.octets);
1801216295Ssyrinx		else
1802216295Ssyrinx			snmp_output_octetstring(snmptoolctx, SNMP_STRING,
1803216295Ssyrinx			    val->v.octetstring.len, val->v.octetstring.octets);
1804216295Ssyrinx		break;
1805216295Ssyrinx
1806216295Ssyrinx	    case SNMP_SYNTAX_OID:
1807216295Ssyrinx		snmp_output_oid_value(snmptoolctx, &(val->v.oid));
1808216295Ssyrinx		break;
1809216295Ssyrinx
1810216295Ssyrinx	    case SNMP_SYNTAX_IPADDRESS:
1811216295Ssyrinx		snmp_output_ipaddress(snmptoolctx, val->v.ipaddress);
1812216295Ssyrinx		break;
1813216295Ssyrinx
1814216295Ssyrinx	    case SNMP_SYNTAX_COUNTER:
1815216295Ssyrinx		snmp_output_counter(snmptoolctx, val->v.uint32);
1816216295Ssyrinx		break;
1817216295Ssyrinx
1818216295Ssyrinx	    case SNMP_SYNTAX_GAUGE:
1819216295Ssyrinx		snmp_output_gauge(snmptoolctx, val->v.uint32);
1820216295Ssyrinx		break;
1821216295Ssyrinx
1822216295Ssyrinx	    case SNMP_SYNTAX_TIMETICKS:
1823216295Ssyrinx		snmp_output_ticks(snmptoolctx, val->v.uint32);
1824216295Ssyrinx		break;
1825216295Ssyrinx
1826216295Ssyrinx	    case SNMP_SYNTAX_COUNTER64:
1827216295Ssyrinx		snmp_output_counter64(snmptoolctx, val->v.counter64);
1828216295Ssyrinx		break;
1829216295Ssyrinx
1830216295Ssyrinx	    case SNMP_SYNTAX_NOSUCHOBJECT:
1831216295Ssyrinx		fprintf(stdout, "No Such Object\n");
1832216295Ssyrinx		return (val->syntax);
1833216295Ssyrinx
1834216295Ssyrinx	    case SNMP_SYNTAX_NOSUCHINSTANCE:
1835216295Ssyrinx		fprintf(stdout, "No Such Instance\n");
1836216295Ssyrinx		return (val->syntax);
1837216295Ssyrinx
1838216295Ssyrinx	    case SNMP_SYNTAX_ENDOFMIBVIEW:
1839216295Ssyrinx		fprintf(stdout, "End of Mib View\n");
1840216295Ssyrinx		return (val->syntax);
1841216295Ssyrinx
1842216295Ssyrinx	    case SNMP_SYNTAX_NULL:
1843216295Ssyrinx		/* NOTREACHED */
1844216295Ssyrinx		fprintf(stdout, "agent returned NULL Syntax\n");
1845216295Ssyrinx		return (val->syntax);
1846216295Ssyrinx
1847216295Ssyrinx	    default:
1848216295Ssyrinx		/* NOTREACHED - If here - then all went completely wrong. */
1849216295Ssyrinx		fprintf(stdout, "agent returned unknown syntax\n");
1850216295Ssyrinx		return (-1);
1851216295Ssyrinx	}
1852216295Ssyrinx
1853216295Ssyrinx	fprintf(stdout, "\n");
1854216295Ssyrinx
1855216295Ssyrinx	return (0);
1856216295Ssyrinx}
1857216295Ssyrinx
1858216295Ssyrinxstatic int32_t
1859216295Ssyrinxsnmp_fill_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *obj,
1860216295Ssyrinx    struct snmp_value *val)
1861216295Ssyrinx{
1862216295Ssyrinx	int32_t rc;
1863216295Ssyrinx	asn_subid_t suboid;
1864216295Ssyrinx
1865216295Ssyrinx	if (obj == NULL || val == NULL)
1866216295Ssyrinx		return (-1);
1867216295Ssyrinx
1868216295Ssyrinx	if ((suboid = snmp_suboid_pop(&(val->var))) > ASN_MAXID)
1869216295Ssyrinx		return (-1);
1870216295Ssyrinx
1871216295Ssyrinx	memset(obj, 0, sizeof(struct snmp_object));
1872216295Ssyrinx	asn_append_oid(&(obj->val.var), &(val->var));
1873216295Ssyrinx	obj->val.syntax = val->syntax;
1874216295Ssyrinx
1875216295Ssyrinx	if (obj->val.syntax > 0)
1876216295Ssyrinx		rc = snmp_lookup_leafstring(snmptoolctx, obj);
1877216295Ssyrinx	else
1878216295Ssyrinx		rc = snmp_lookup_nonleaf_string(snmptoolctx, obj);
1879216295Ssyrinx
1880216295Ssyrinx	(void) snmp_suboid_append(&(val->var), suboid);
1881216295Ssyrinx	(void) snmp_suboid_append(&(obj->val.var), suboid);
1882216295Ssyrinx
1883216295Ssyrinx	return (rc);
1884216295Ssyrinx}
1885216295Ssyrinx
1886216295Ssyrinxstatic int32_t
1887216295Ssyrinxsnmp_output_index(struct snmp_toolinfo *snmptoolctx, struct index *stx,
1888216295Ssyrinx    struct asn_oid *oid)
1889216295Ssyrinx{
1890216295Ssyrinx	uint8_t ip[4];
1891216295Ssyrinx	uint32_t bytes = 1;
1892216295Ssyrinx	uint64_t cnt64;
1893216295Ssyrinx	struct asn_oid temp, out;
1894216295Ssyrinx
1895216295Ssyrinx	if (oid->len < bytes)
1896216295Ssyrinx		return (-1);
1897216295Ssyrinx
1898216295Ssyrinx	memset(&temp, 0, sizeof(struct asn_oid));
1899216295Ssyrinx	asn_append_oid(&temp, oid);
1900216295Ssyrinx
1901216295Ssyrinx	switch (stx->syntax) {
1902216295Ssyrinx	    case SNMP_SYNTAX_INTEGER:
1903216295Ssyrinx		snmp_output_int(snmptoolctx, stx->snmp_enum, temp.subs[0]);
1904216295Ssyrinx		break;
1905216295Ssyrinx
1906216295Ssyrinx	    case SNMP_SYNTAX_OCTETSTRING:
1907216295Ssyrinx		if ((temp.subs[0] > temp.len -1 ) || (temp.subs[0] >
1908216295Ssyrinx		    ASN_MAXOCTETSTRING))
1909216295Ssyrinx			return (-1);
1910216295Ssyrinx		snmp_output_octetindex(snmptoolctx, stx->tc, &temp);
1911216295Ssyrinx		bytes += temp.subs[0];
1912216295Ssyrinx		break;
1913216295Ssyrinx
1914216295Ssyrinx	    case SNMP_SYNTAX_OID:
1915216295Ssyrinx		if ((temp.subs[0] > temp.len -1) || (temp.subs[0] >
1916216295Ssyrinx		    ASN_MAXOIDLEN))
1917216295Ssyrinx			return (-1);
1918216295Ssyrinx
1919216295Ssyrinx		bytes += temp.subs[0];
1920216295Ssyrinx		memset(&out, 0, sizeof(struct asn_oid));
1921216295Ssyrinx		asn_slice_oid(&out, &temp, 1, bytes);
1922216295Ssyrinx		snmp_output_oid_value(snmptoolctx, &out);
1923216295Ssyrinx		break;
1924216295Ssyrinx
1925216295Ssyrinx	    case SNMP_SYNTAX_IPADDRESS:
1926216295Ssyrinx		if (temp.len < 4)
1927216295Ssyrinx			return (-1);
1928216295Ssyrinx		for (bytes = 0; bytes < 4; bytes++)
1929216295Ssyrinx			ip[bytes] = temp.subs[bytes];
1930216295Ssyrinx
1931216295Ssyrinx		snmp_output_ipaddress(snmptoolctx, ip);
1932216295Ssyrinx		bytes = 4;
1933216295Ssyrinx		break;
1934216295Ssyrinx
1935216295Ssyrinx	    case SNMP_SYNTAX_COUNTER:
1936216295Ssyrinx		snmp_output_counter(snmptoolctx, temp.subs[0]);
1937216295Ssyrinx		break;
1938216295Ssyrinx
1939216295Ssyrinx	    case SNMP_SYNTAX_GAUGE:
1940216295Ssyrinx		snmp_output_gauge(snmptoolctx, temp.subs[0]);
1941216295Ssyrinx		break;
1942216295Ssyrinx
1943216295Ssyrinx	    case SNMP_SYNTAX_TIMETICKS:
1944216295Ssyrinx		snmp_output_ticks(snmptoolctx, temp.subs[0]);
1945216295Ssyrinx		break;
1946216295Ssyrinx
1947216295Ssyrinx	    case SNMP_SYNTAX_COUNTER64:
1948216295Ssyrinx		if (oid->len < 2)
1949216295Ssyrinx			return (-1);
1950216295Ssyrinx		bytes = 2;
1951216295Ssyrinx		memcpy(&cnt64, temp.subs, bytes);
1952216295Ssyrinx		snmp_output_counter64(snmptoolctx, cnt64);
1953216295Ssyrinx		break;
1954216295Ssyrinx
1955216295Ssyrinx	    default:
1956216295Ssyrinx		return (-1);
1957216295Ssyrinx	}
1958216295Ssyrinx
1959216295Ssyrinx	return (bytes);
1960216295Ssyrinx}
1961216295Ssyrinx
1962216295Ssyrinxstatic int32_t
1963216295Ssyrinxsnmp_output_object(struct snmp_toolinfo *snmptoolctx, struct snmp_object *o)
1964216295Ssyrinx{
1965216295Ssyrinx	int32_t i, first, len;
1966216295Ssyrinx	struct asn_oid oid;
1967216295Ssyrinx	struct index *temp;
1968216295Ssyrinx
1969216295Ssyrinx	if (ISSET_NUMERIC(snmptoolctx))
1970216295Ssyrinx		return (-1);
1971216295Ssyrinx
1972216295Ssyrinx	if (o->info->table_idx == NULL) {
1973216295Ssyrinx		fprintf(stdout,"%s.%d", o->info->string,
1974216295Ssyrinx		    o->val.var.subs[o->val.var.len - 1]);
1975216295Ssyrinx		return (1);
1976216295Ssyrinx	}
1977216295Ssyrinx
1978216295Ssyrinx	fprintf(stdout,"%s[", o->info->string);
1979216295Ssyrinx	memset(&oid, 0, sizeof(struct asn_oid));
1980216295Ssyrinx
1981216295Ssyrinx	len = 1;
1982216295Ssyrinx	asn_slice_oid(&oid, &(o->val.var), (o->info->table_idx->var.len + len),
1983216295Ssyrinx	    o->val.var.len);
1984216295Ssyrinx
1985216295Ssyrinx	first = 1;
1986216295Ssyrinx	STAILQ_FOREACH(temp, &(OBJECT_IDX_LIST(o)), link) {
1987216295Ssyrinx		if(first)
1988216295Ssyrinx			first = 0;
1989216295Ssyrinx		else
1990216295Ssyrinx			fprintf(stdout, ", ");
1991216295Ssyrinx		if ((i = snmp_output_index(snmptoolctx, temp, &oid)) < 0)
1992216295Ssyrinx			break;
1993216295Ssyrinx		len += i;
1994216295Ssyrinx		memset(&oid, 0, sizeof(struct asn_oid));
1995216295Ssyrinx		asn_slice_oid(&oid, &(o->val.var),
1996216295Ssyrinx		    (o->info->table_idx->var.len + len), o->val.var.len + 1);
1997216295Ssyrinx	}
1998216295Ssyrinx
1999216295Ssyrinx	fprintf(stdout,"]");
2000216295Ssyrinx	return (1);
2001216295Ssyrinx}
2002216295Ssyrinx
2003216295Ssyrinxvoid
2004216295Ssyrinxsnmp_output_err_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu)
2005216295Ssyrinx{
2006311590Sngie	struct snmp_object *object;
2007216295Ssyrinx	char buf[ASN_OIDSTRLEN];
2008216295Ssyrinx
2009216295Ssyrinx	if (pdu == NULL || (pdu->error_index > (int32_t) pdu->nbindings)) {
2010311590Sngie		fprintf(stdout, "Invalid error index in PDU\n");
2011216295Ssyrinx		return;
2012216295Ssyrinx	}
2013216295Ssyrinx
2014311590Sngie	if ((object = calloc(1, sizeof(struct snmp_object))) == NULL) {
2015311590Sngie		fprintf(stdout, "calloc: %s", strerror(errno));
2016311590Sngie		return;
2017311590Sngie	}
2018311590Sngie
2019216295Ssyrinx	fprintf(stdout, "Agent %s:%s returned error \n", snmp_client.chost,
2020216295Ssyrinx	    snmp_client.cport);
2021216295Ssyrinx
2022311590Sngie	if (!ISSET_NUMERIC(snmptoolctx) && (snmp_fill_object(snmptoolctx, object,
2023216295Ssyrinx	    &(pdu->bindings[pdu->error_index - 1])) > 0))
2024311590Sngie		snmp_output_object(snmptoolctx, object);
2025216295Ssyrinx	else {
2026216295Ssyrinx		asn_oid2str_r(&(pdu->bindings[pdu->error_index - 1].var), buf);
2027216295Ssyrinx		fprintf(stdout,"%s", buf);
2028216295Ssyrinx	}
2029216295Ssyrinx
2030216295Ssyrinx	fprintf(stdout," caused error - ");
2031216295Ssyrinx	if ((pdu->error_status > 0) && (pdu->error_status <=
2032216295Ssyrinx	    SNMP_ERR_INCONS_NAME))
2033216295Ssyrinx		fprintf(stdout, "%s\n", error_strings[pdu->error_status].str);
2034216295Ssyrinx	else
2035216295Ssyrinx		fprintf(stdout,"%s\n", error_strings[SNMP_ERR_UNKNOWN].str);
2036311590Sngie
2037311590Sngie	free(object);
2038311590Sngie	object = NULL;
2039216295Ssyrinx}
2040216295Ssyrinx
2041216295Ssyrinxint32_t
2042229933Ssyrinxsnmp_output_resp(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
2043229933Ssyrinx    struct asn_oid *root)
2044216295Ssyrinx{
2045311590Sngie	struct snmp_object *object;
2046311153Sngie	char p[ASN_OIDSTRLEN];
2047216295Ssyrinx	int32_t error;
2048216295Ssyrinx	uint32_t i;
2049216295Ssyrinx
2050311590Sngie	if ((object = calloc(1, sizeof(struct snmp_object))) == NULL)
2051311590Sngie		return (-1);
2052311590Sngie
2053229933Ssyrinx	i = error = 0;
2054229933Ssyrinx	while (i < pdu->nbindings) {
2055229933Ssyrinx		if (root != NULL && !(asn_is_suboid(root,
2056229933Ssyrinx		    &(pdu->bindings[i].var))))
2057229933Ssyrinx			break;
2058229933Ssyrinx
2059216295Ssyrinx		if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET) {
2060216295Ssyrinx			if (!ISSET_NUMERIC(snmptoolctx) &&
2061311590Sngie			    (snmp_fill_object(snmptoolctx, object,
2062216295Ssyrinx			    &(pdu->bindings[i])) > 0))
2063311590Sngie				snmp_output_object(snmptoolctx, object);
2064216295Ssyrinx			else {
2065216295Ssyrinx				asn_oid2str_r(&(pdu->bindings[i].var), p);
2066216295Ssyrinx				fprintf(stdout, "%s", p);
2067216295Ssyrinx			}
2068216295Ssyrinx		}
2069311590Sngie		error |= snmp_output_numval(snmptoolctx, &(pdu->bindings[i]),
2070311590Sngie		    object->info);
2071229933Ssyrinx		i++;
2072216295Ssyrinx	}
2073216295Ssyrinx
2074311590Sngie	free(object);
2075311590Sngie	object = NULL;
2076311590Sngie
2077229933Ssyrinx	if (error)
2078229933Ssyrinx		return (-1);
2079229933Ssyrinx
2080229933Ssyrinx	return (i);
2081216295Ssyrinx}
2082216295Ssyrinx
2083216295Ssyrinxvoid
2084216295Ssyrinxsnmp_output_engine(void)
2085216295Ssyrinx{
2086216295Ssyrinx	uint32_t i;
2087216295Ssyrinx	char *cptr, engine[2 * SNMP_ENGINE_ID_SIZ + 2];
2088216295Ssyrinx
2089216295Ssyrinx	cptr = engine;
2090216295Ssyrinx	for (i = 0; i < snmp_client.engine.engine_len; i++)
2091216295Ssyrinx		cptr += sprintf(cptr, "%.2x", snmp_client.engine.engine_id[i]);
2092216295Ssyrinx	*cptr++ = '\0';
2093216295Ssyrinx
2094216295Ssyrinx	fprintf(stdout, "Engine ID 0x%s\n", engine);
2095216295Ssyrinx	fprintf(stdout, "Boots : %u\t\tTime : %d\n",
2096216295Ssyrinx	    snmp_client.engine.engine_boots,
2097216295Ssyrinx	    snmp_client.engine.engine_time);
2098216295Ssyrinx}
2099216295Ssyrinx
2100216295Ssyrinxvoid
2101216295Ssyrinxsnmp_output_keys(void)
2102216295Ssyrinx{
2103216295Ssyrinx	uint32_t i, keylen = 0;
2104216295Ssyrinx	char *cptr, extkey[2 * SNMP_AUTH_KEY_SIZ + 2];
2105216295Ssyrinx
2106216295Ssyrinx	fprintf(stdout, "Localized keys for %s\n", snmp_client.user.sec_name);
2107216295Ssyrinx	if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_MD5) {
2108216295Ssyrinx		fprintf(stdout, "MD5 : 0x");
2109216295Ssyrinx		keylen = SNMP_AUTH_HMACMD5_KEY_SIZ;
2110216295Ssyrinx	} else if (snmp_client.user.auth_proto == SNMP_AUTH_HMAC_SHA) {
2111216295Ssyrinx		fprintf(stdout, "SHA : 0x");
2112216295Ssyrinx		keylen = SNMP_AUTH_HMACSHA_KEY_SIZ;
2113216295Ssyrinx	}
2114216295Ssyrinx	if (snmp_client.user.auth_proto != SNMP_AUTH_NOAUTH) {
2115216295Ssyrinx		cptr = extkey;
2116216295Ssyrinx		for (i = 0; i < keylen; i++)
2117216295Ssyrinx			cptr += sprintf(cptr, "%.2x",
2118216295Ssyrinx			    snmp_client.user.auth_key[i]);
2119216295Ssyrinx		*cptr++ = '\0';
2120216295Ssyrinx		fprintf(stdout, "%s\n", extkey);
2121216295Ssyrinx	}
2122216295Ssyrinx
2123216295Ssyrinx	if (snmp_client.user.priv_proto == SNMP_PRIV_DES) {
2124216295Ssyrinx		fprintf(stdout, "DES : 0x");
2125216295Ssyrinx		keylen = SNMP_PRIV_DES_KEY_SIZ;
2126216295Ssyrinx	} else if (snmp_client.user.priv_proto == SNMP_PRIV_AES) {
2127216295Ssyrinx		fprintf(stdout, "AES : 0x");
2128216295Ssyrinx		keylen = SNMP_PRIV_AES_KEY_SIZ;
2129216295Ssyrinx	}
2130216295Ssyrinx	if (snmp_client.user.priv_proto != SNMP_PRIV_NOPRIV) {
2131216295Ssyrinx		cptr = extkey;
2132216295Ssyrinx		for (i = 0; i < keylen; i++)
2133216295Ssyrinx			cptr += sprintf(cptr, "%.2x",
2134216295Ssyrinx			    snmp_client.user.priv_key[i]);
2135216295Ssyrinx		*cptr++ = '\0';
2136216295Ssyrinx		fprintf(stdout, "%s\n", extkey);
2137216295Ssyrinx	}
2138216295Ssyrinx}
2139