xref: /freebsd/usr.sbin/bsnmpd/tools/bsnmptools/bsnmpget.c (revision f021e3573519ff192fc708cda9ca4bba264c96f7)
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  * Bsnmpget and bsnmpwalk are simple tools for querying SNMP agents,
30a7398723SShteryana Shopova  * bsnmpset can be used to set MIB objects in an agent.
31a7398723SShteryana Shopova  */
32a7398723SShteryana Shopova 
33a7398723SShteryana Shopova #include <sys/queue.h>
34a7398723SShteryana Shopova #include <sys/types.h>
35a7398723SShteryana Shopova 
36a7398723SShteryana Shopova #include <assert.h>
37a7398723SShteryana Shopova #include <ctype.h>
38a7398723SShteryana Shopova #include <err.h>
39a7398723SShteryana Shopova #include <errno.h>
40a7398723SShteryana Shopova #include <stdarg.h>
41a7398723SShteryana Shopova #include <stdio.h>
42a7398723SShteryana Shopova #include <stdlib.h>
43a7398723SShteryana Shopova #include <string.h>
44a7398723SShteryana Shopova #include <syslog.h>
45a7398723SShteryana Shopova #include <unistd.h>
46a7398723SShteryana Shopova 
47a7398723SShteryana Shopova #include <bsnmp/asn1.h>
48a7398723SShteryana Shopova #include <bsnmp/snmp.h>
49a7398723SShteryana Shopova #include <bsnmp/snmpclient.h>
50a7398723SShteryana Shopova #include "bsnmptc.h"
51a7398723SShteryana Shopova #include "bsnmptools.h"
52a7398723SShteryana Shopova 
53a7398723SShteryana Shopova static const char *program_name = NULL;
54a7398723SShteryana Shopova static enum program_e {
55a7398723SShteryana Shopova 	BSNMPGET,
56a7398723SShteryana Shopova 	BSNMPWALK,
57a7398723SShteryana Shopova 	BSNMPSET
58a7398723SShteryana Shopova } program;
59a7398723SShteryana Shopova 
60a7398723SShteryana Shopova /* *****************************************************************************
61a7398723SShteryana Shopova  * Common bsnmptools functions.
62a7398723SShteryana Shopova  */
63a7398723SShteryana Shopova static void
usage(void)64a7398723SShteryana Shopova usage(void)
65a7398723SShteryana Shopova {
66a7398723SShteryana Shopova 	fprintf(stderr,
67a7398723SShteryana Shopova "Usage:\n"
68a7398723SShteryana Shopova "%s %s [-A options] [-b buffersize] [-C options] [-I options]\n"
69a7398723SShteryana Shopova "\t[-i filelist] [-l filename]%s [-o output] [-P options]\n"
70a7398723SShteryana Shopova "\t%s[-r retries] [-s [trans::][community@][server][:port]]\n"
71a7398723SShteryana Shopova "\t[-t timeout] [-U options] [-v version]%s\n",
72a7398723SShteryana Shopova 	program_name,
73a7398723SShteryana Shopova 	(program == BSNMPGET) ? "[-aDdehnK]" :
74a7398723SShteryana Shopova 	    (program == BSNMPWALK) ? "[-dhnK]" :
75a7398723SShteryana Shopova 	    (program == BSNMPSET) ? "[-adehnK]" :
76a7398723SShteryana Shopova 	    "",
77b9288caaSShteryana Shopova 	(program == BSNMPGET || program == BSNMPWALK) ?
78b9288caaSShteryana Shopova 	" [-M max-repetitions] [-N non-repeaters]" : "",
79b9288caaSShteryana Shopova 	(program == BSNMPGET || program == BSNMPWALK) ? "[-p pdu] " : "",
80a7398723SShteryana Shopova 	(program == BSNMPGET) ? " OID [OID ...]" :
81a7398723SShteryana Shopova 	    (program == BSNMPWALK || program == BSNMPSET) ? " [OID ...]" :
82a7398723SShteryana Shopova 	    ""
83a7398723SShteryana Shopova 	);
84a7398723SShteryana Shopova }
85a7398723SShteryana Shopova 
86a7398723SShteryana Shopova static int32_t
parse_max_repetitions(struct snmp_toolinfo * snmptoolctx,char * opt_arg)87a7398723SShteryana Shopova parse_max_repetitions(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
88a7398723SShteryana Shopova {
89a7398723SShteryana Shopova 	uint32_t v;
90a7398723SShteryana Shopova 
91a7398723SShteryana Shopova 	assert(opt_arg != NULL);
92a7398723SShteryana Shopova 
93a7398723SShteryana Shopova 	v = strtoul(opt_arg, (void *) NULL, 10);
94a7398723SShteryana Shopova 
95a7398723SShteryana Shopova 	if (v > SNMP_MAX_BINDINGS) {
96a7398723SShteryana Shopova 		warnx("Max repetitions value greater than %d maximum allowed.",
97a7398723SShteryana Shopova 		    SNMP_MAX_BINDINGS);
98a7398723SShteryana Shopova 		return (-1);
99a7398723SShteryana Shopova 	}
100a7398723SShteryana Shopova 
101a7398723SShteryana Shopova 	SET_MAXREP(snmptoolctx, v);
102a7398723SShteryana Shopova 	return (2);
103a7398723SShteryana Shopova }
104a7398723SShteryana Shopova 
105a7398723SShteryana Shopova static int32_t
parse_non_repeaters(struct snmp_toolinfo * snmptoolctx,char * opt_arg)106a7398723SShteryana Shopova parse_non_repeaters(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
107a7398723SShteryana Shopova {
108a7398723SShteryana Shopova 	uint32_t v;
109a7398723SShteryana Shopova 
110a7398723SShteryana Shopova 	assert(opt_arg != NULL);
111a7398723SShteryana Shopova 
112a7398723SShteryana Shopova 	v = strtoul(opt_arg, (void *) NULL, 10);
113a7398723SShteryana Shopova 
114a7398723SShteryana Shopova 	if (v > SNMP_MAX_BINDINGS) {
115a7398723SShteryana Shopova 		warnx("Non repeaters value greater than %d maximum allowed.",
116a7398723SShteryana Shopova 		    SNMP_MAX_BINDINGS);
117a7398723SShteryana Shopova 		return (-1);
118a7398723SShteryana Shopova 	}
119a7398723SShteryana Shopova 
120a7398723SShteryana Shopova 	SET_NONREP(snmptoolctx, v);
121a7398723SShteryana Shopova 	return (2);
122a7398723SShteryana Shopova }
123a7398723SShteryana Shopova 
124a7398723SShteryana Shopova static int32_t
parse_pdu_type(struct snmp_toolinfo * snmptoolctx,char * opt_arg)125a7398723SShteryana Shopova parse_pdu_type(struct snmp_toolinfo *snmptoolctx, char *opt_arg)
126a7398723SShteryana Shopova {
127a7398723SShteryana Shopova 	assert(opt_arg != NULL);
128a7398723SShteryana Shopova 
129a7398723SShteryana Shopova 	if (strcasecmp(opt_arg, "getbulk") == 0)
130a7398723SShteryana Shopova 		SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETBULK);
131a7398723SShteryana Shopova 	else if (strcasecmp(opt_arg, "getnext") == 0)
132a7398723SShteryana Shopova 		SET_PDUTYPE(snmptoolctx, SNMP_PDU_GETNEXT);
133a7398723SShteryana Shopova 	else if (strcasecmp(opt_arg, "get") == 0)
134a7398723SShteryana Shopova 		SET_PDUTYPE(snmptoolctx, SNMP_PDU_GET);
135a7398723SShteryana Shopova 	else {
136a7398723SShteryana Shopova 		warnx("PDU type '%s' not supported.", opt_arg);
137a7398723SShteryana Shopova 		return (-1);
138a7398723SShteryana Shopova 	}
139a7398723SShteryana Shopova 
140a7398723SShteryana Shopova 	return (2);
141a7398723SShteryana Shopova }
142a7398723SShteryana Shopova 
143a7398723SShteryana Shopova static int32_t
snmptool_parse_options(struct snmp_toolinfo * snmptoolctx,int argc,char ** argv)144a7398723SShteryana Shopova snmptool_parse_options(struct snmp_toolinfo *snmptoolctx, int argc, char **argv)
145a7398723SShteryana Shopova {
146a7398723SShteryana Shopova 	int32_t count, optnum = 0;
147a7398723SShteryana Shopova 	int ch;
148a7398723SShteryana Shopova 	const char *opts;
149a7398723SShteryana Shopova 
150a7398723SShteryana Shopova 	switch (program) {
151a7398723SShteryana Shopova 		case BSNMPWALK:
152b9288caaSShteryana Shopova 			opts = "dhnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
153a7398723SShteryana Shopova 			break;
154a7398723SShteryana Shopova 		case BSNMPGET:
155a7398723SShteryana Shopova 			opts = "aDdehnKA:b:C:I:i:l:M:N:o:P:p:r:s:t:U:v:";
156a7398723SShteryana Shopova 			break;
157a7398723SShteryana Shopova 		case BSNMPSET:
158a7398723SShteryana Shopova 			opts = "adehnKA:b:C:I:i:l:o:P:r:s:t:U:v:";
159a7398723SShteryana Shopova 			break;
160a7398723SShteryana Shopova 		default:
161a7398723SShteryana Shopova 			return (-1);
162a7398723SShteryana Shopova 	}
163a7398723SShteryana Shopova 
164a7398723SShteryana Shopova 	while ((ch = getopt(argc, argv, opts)) != EOF) {
165a7398723SShteryana Shopova 		switch (ch) {
166a7398723SShteryana Shopova 		case 'A':
167a7398723SShteryana Shopova 			count = parse_authentication(snmptoolctx, optarg);
168a7398723SShteryana Shopova 			break;
169a7398723SShteryana Shopova 		case 'a':
170a7398723SShteryana Shopova 			count = parse_skip_access(snmptoolctx);
171a7398723SShteryana Shopova 			break;
172a7398723SShteryana Shopova 		case 'b':
173a7398723SShteryana Shopova 			count = parse_buflen(optarg);
174a7398723SShteryana Shopova 			break;
175a7398723SShteryana Shopova 		case 'D':
176a7398723SShteryana Shopova 			count = parse_discovery(snmptoolctx);
177a7398723SShteryana Shopova 			break;
178a7398723SShteryana Shopova 		case 'd':
179a7398723SShteryana Shopova 			count = parse_debug();
180a7398723SShteryana Shopova 			break;
181a7398723SShteryana Shopova 		case 'e':
182a7398723SShteryana Shopova 			count = parse_errors(snmptoolctx);
183a7398723SShteryana Shopova 			break;
184a7398723SShteryana Shopova 		case 'h':
185a7398723SShteryana Shopova 			usage();
186a7398723SShteryana Shopova 			return (-2);
187a7398723SShteryana Shopova 		case 'C':
188a7398723SShteryana Shopova 			count = parse_context(snmptoolctx, optarg);
189a7398723SShteryana Shopova 			break;
190a7398723SShteryana Shopova 		case 'I':
191a7398723SShteryana Shopova 			count = parse_include(snmptoolctx, optarg);
192a7398723SShteryana Shopova 			break;
193a7398723SShteryana Shopova 		case 'i':
194a7398723SShteryana Shopova 			count = parse_file(snmptoolctx, optarg);
195a7398723SShteryana Shopova 			break;
196a7398723SShteryana Shopova 		case 'K':
197a7398723SShteryana Shopova 			count = parse_local_key(snmptoolctx);
198a7398723SShteryana Shopova 			break;
199a7398723SShteryana Shopova 		case 'l':
200a7398723SShteryana Shopova 			count = parse_local_path(optarg);
201a7398723SShteryana Shopova 			break;
202a7398723SShteryana Shopova 		case 'M':
203a7398723SShteryana Shopova 			count = parse_max_repetitions(snmptoolctx, optarg);
204a7398723SShteryana Shopova 			break;
205a7398723SShteryana Shopova 		case 'N':
206a7398723SShteryana Shopova 			count = parse_non_repeaters(snmptoolctx, optarg);
207a7398723SShteryana Shopova 			break;
208a7398723SShteryana Shopova 		case 'n':
209a7398723SShteryana Shopova 			count = parse_num_oids(snmptoolctx);
210a7398723SShteryana Shopova 			break;
211a7398723SShteryana Shopova 		case 'o':
212a7398723SShteryana Shopova 			count = parse_output(snmptoolctx, optarg);
213a7398723SShteryana Shopova 			break;
214a7398723SShteryana Shopova 		case 'P':
215a7398723SShteryana Shopova 			count = parse_privacy(snmptoolctx, optarg);
216a7398723SShteryana Shopova 			break;
217a7398723SShteryana Shopova 		case 'p':
218a7398723SShteryana Shopova 			count = parse_pdu_type(snmptoolctx, optarg);
219a7398723SShteryana Shopova 			break;
220a7398723SShteryana Shopova 		case 'r':
221a7398723SShteryana Shopova 			count = parse_retry(optarg);
222a7398723SShteryana Shopova 			break;
223a7398723SShteryana Shopova 		case 's':
224a7398723SShteryana Shopova 			count = parse_server(optarg);
225a7398723SShteryana Shopova 			break;
226a7398723SShteryana Shopova 		case 't':
227a7398723SShteryana Shopova 			count = parse_timeout(optarg);
228a7398723SShteryana Shopova 			break;
229a7398723SShteryana Shopova 		case 'U':
230a7398723SShteryana Shopova 			count = parse_user_security(snmptoolctx, optarg);
231a7398723SShteryana Shopova 			break;
232a7398723SShteryana Shopova 		case 'v':
233a7398723SShteryana Shopova 			count = parse_version(optarg);
234a7398723SShteryana Shopova 			break;
235a7398723SShteryana Shopova 		case '?':
236a7398723SShteryana Shopova 		default:
237a7398723SShteryana Shopova 			usage();
238a7398723SShteryana Shopova 			return (-1);
239a7398723SShteryana Shopova 		}
240a7398723SShteryana Shopova 		if (count < 0)
241a7398723SShteryana Shopova 			return (-1);
242a7398723SShteryana Shopova 	    optnum += count;
243a7398723SShteryana Shopova 	}
244a7398723SShteryana Shopova 
245a7398723SShteryana Shopova 	return (optnum);
246a7398723SShteryana Shopova }
247a7398723SShteryana Shopova 
248a7398723SShteryana Shopova /*
249a7398723SShteryana Shopova  * Read user input OID - one of following formats:
2503df5ecacSUlrich Spörlein  * 1) 1.2.1.1.2.1.0 - that is if option numeric was given;
251a7398723SShteryana Shopova  * 2) string - in such case append .0 to the asn_oid subs;
2523df5ecacSUlrich Spörlein  * 3) string.1 - no additional processing required in such case.
253a7398723SShteryana Shopova  */
254a7398723SShteryana Shopova static char *
snmptools_parse_stroid(struct snmp_toolinfo * snmptoolctx,struct snmp_object * obj,char * argv)255a7398723SShteryana Shopova snmptools_parse_stroid(struct snmp_toolinfo *snmptoolctx,
256a7398723SShteryana Shopova     struct snmp_object *obj, char *argv)
257a7398723SShteryana Shopova {
258a7398723SShteryana Shopova 	char string[MAXSTR], *str;
259a7398723SShteryana Shopova 	int32_t i = 0;
260a7398723SShteryana Shopova 	struct asn_oid in_oid;
261a7398723SShteryana Shopova 
262a7398723SShteryana Shopova 	str = argv;
263a7398723SShteryana Shopova 
264a7398723SShteryana Shopova 	if (*str == '.')
265a7398723SShteryana Shopova 		str++;
266a7398723SShteryana Shopova 
267a7398723SShteryana Shopova 	while (isalpha(*str) || *str == '_' || (i != 0 && isdigit(*str))) {
268a7398723SShteryana Shopova 		str++;
269a7398723SShteryana Shopova 		i++;
270a7398723SShteryana Shopova 	}
271a7398723SShteryana Shopova 
272a7398723SShteryana Shopova 	if (i <= 0 || i >= MAXSTR)
273a7398723SShteryana Shopova 		return (NULL);
274a7398723SShteryana Shopova 
275a7398723SShteryana Shopova 	memset(&in_oid, 0, sizeof(struct asn_oid));
276a7398723SShteryana Shopova 	if ((str = snmp_parse_suboid((argv + i), &in_oid)) == NULL) {
277a7398723SShteryana Shopova 		warnx("Invalid OID - %s", argv);
278a7398723SShteryana Shopova 		return (NULL);
279a7398723SShteryana Shopova 	}
280a7398723SShteryana Shopova 
281a7398723SShteryana Shopova 	strlcpy(string, argv, i + 1);
282a7398723SShteryana Shopova 	if (snmp_lookup_oidall(snmptoolctx, obj, string) < 0) {
283a7398723SShteryana Shopova 		warnx("No entry for %s in mapping lists", string);
284a7398723SShteryana Shopova 		return (NULL);
285a7398723SShteryana Shopova 	}
286a7398723SShteryana Shopova 
287a7398723SShteryana Shopova 	/* If OID given on command line append it. */
288a7398723SShteryana Shopova 	if (in_oid.len > 0)
289a7398723SShteryana Shopova 		asn_append_oid(&(obj->val.var), &in_oid);
290a7398723SShteryana Shopova 	else if (*str == '[') {
291a7398723SShteryana Shopova 		if ((str = snmp_parse_index(snmptoolctx, str + 1, obj)) == NULL)
292a7398723SShteryana Shopova 			return (NULL);
293a7398723SShteryana Shopova 	} else if (obj->val.syntax > 0 && GET_PDUTYPE(snmptoolctx) ==
294a7398723SShteryana Shopova 	    SNMP_PDU_GET) {
295a7398723SShteryana Shopova 		if (snmp_suboid_append(&(obj->val.var), (asn_subid_t) 0) < 0)
296a7398723SShteryana Shopova 			return (NULL);
297a7398723SShteryana Shopova 	}
298a7398723SShteryana Shopova 
299a7398723SShteryana Shopova 	return (str);
300a7398723SShteryana Shopova }
301a7398723SShteryana Shopova 
302a7398723SShteryana Shopova static int32_t
snmptools_parse_oid(struct snmp_toolinfo * snmptoolctx,struct snmp_object * obj,char * argv)303a7398723SShteryana Shopova snmptools_parse_oid(struct snmp_toolinfo *snmptoolctx,
304a7398723SShteryana Shopova     struct snmp_object *obj, char *argv)
305a7398723SShteryana Shopova {
306a7398723SShteryana Shopova 	if (argv == NULL)
307a7398723SShteryana Shopova 		return (-1);
308a7398723SShteryana Shopova 
309a7398723SShteryana Shopova 	if (ISSET_NUMERIC(snmptoolctx)) {
310a7398723SShteryana Shopova 		if (snmp_parse_numoid(argv, &(obj->val.var)) < 0)
311a7398723SShteryana Shopova 			return (-1);
312a7398723SShteryana Shopova 	} else {
313a7398723SShteryana Shopova 		if (snmptools_parse_stroid(snmptoolctx, obj, argv) == NULL &&
314a7398723SShteryana Shopova 		    snmp_parse_numoid(argv, &(obj->val.var)) < 0)
315a7398723SShteryana Shopova 			return (-1);
316a7398723SShteryana Shopova 	}
317a7398723SShteryana Shopova 
318a7398723SShteryana Shopova 	return (1);
319a7398723SShteryana Shopova }
320a7398723SShteryana Shopova 
321a7398723SShteryana Shopova static int32_t
snmptool_add_vbind(struct snmp_pdu * pdu,struct snmp_object * obj)322a7398723SShteryana Shopova snmptool_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
323a7398723SShteryana Shopova {
324a7398723SShteryana Shopova 	if (obj->error > 0)
325a7398723SShteryana Shopova 		return (0);
326a7398723SShteryana Shopova 
327a7398723SShteryana Shopova 	asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
328a7398723SShteryana Shopova 	pdu->nbindings++;
329a7398723SShteryana Shopova 
330a7398723SShteryana Shopova 	return (pdu->nbindings);
331a7398723SShteryana Shopova }
332a7398723SShteryana Shopova 
333a7398723SShteryana Shopova /* *****************************************************************************
334a7398723SShteryana Shopova  * bsnmpget private functions.
335a7398723SShteryana Shopova  */
336a7398723SShteryana Shopova static int32_t
snmpget_verify_vbind(struct snmp_toolinfo * snmptoolctx,struct snmp_pdu * pdu,struct snmp_object * obj)337a7398723SShteryana Shopova snmpget_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
338a7398723SShteryana Shopova     struct snmp_object *obj)
339a7398723SShteryana Shopova {
340a7398723SShteryana Shopova 	if (pdu->version == SNMP_V1 && obj->val.syntax ==
341a7398723SShteryana Shopova 	    SNMP_SYNTAX_COUNTER64) {
342a7398723SShteryana Shopova 		warnx("64-bit counters are not supported in SNMPv1 PDU");
343a7398723SShteryana Shopova 		return (-1);
344a7398723SShteryana Shopova 	}
345a7398723SShteryana Shopova 
346a7398723SShteryana Shopova 	if (ISSET_NUMERIC(snmptoolctx) || pdu->type == SNMP_PDU_GETNEXT ||
347a7398723SShteryana Shopova 	    pdu->type == SNMP_PDU_GETBULK)
348a7398723SShteryana Shopova 		return (1);
349a7398723SShteryana Shopova 
350a7398723SShteryana Shopova 	if (pdu->type == SNMP_PDU_GET && obj->val.syntax == SNMP_SYNTAX_NULL) {
351a7398723SShteryana Shopova 		warnx("Only leaf object values can be added to GET PDU");
352a7398723SShteryana Shopova 		return (-1);
353a7398723SShteryana Shopova 	}
354a7398723SShteryana Shopova 
355a7398723SShteryana Shopova 	return (1);
356a7398723SShteryana Shopova }
357a7398723SShteryana Shopova 
358a7398723SShteryana Shopova /*
359a7398723SShteryana Shopova  * In case of a getbulk PDU, the error_status and error_index fields are used by
360a7398723SShteryana Shopova  * libbsnmp to hold the values of the non-repeaters and max-repetitions fields
361a7398723SShteryana Shopova  * that are present only in the getbulk - so before sending the PDU make sure
362a7398723SShteryana Shopova  * these have correct values as well.
363a7398723SShteryana Shopova  */
364a7398723SShteryana Shopova static void
snmpget_fix_getbulk(struct snmp_pdu * pdu,uint32_t max_rep,uint32_t non_rep)365a7398723SShteryana Shopova snmpget_fix_getbulk(struct snmp_pdu *pdu, uint32_t max_rep, uint32_t non_rep)
366a7398723SShteryana Shopova {
367a7398723SShteryana Shopova 	assert(pdu != NULL);
368a7398723SShteryana Shopova 
369a7398723SShteryana Shopova 	if (pdu->nbindings < non_rep)
370a7398723SShteryana Shopova 		pdu->error_status = pdu->nbindings;
371a7398723SShteryana Shopova 	else
372a7398723SShteryana Shopova 		pdu->error_status = non_rep;
373a7398723SShteryana Shopova 
374a7398723SShteryana Shopova 	if (max_rep > 0)
375a7398723SShteryana Shopova 		pdu->error_index = max_rep;
376a7398723SShteryana Shopova 	else
377a7398723SShteryana Shopova 		pdu->error_index = 1;
378a7398723SShteryana Shopova }
379a7398723SShteryana Shopova 
380a7398723SShteryana Shopova static int
snmptool_get(struct snmp_toolinfo * snmptoolctx)381a7398723SShteryana Shopova snmptool_get(struct snmp_toolinfo *snmptoolctx)
382a7398723SShteryana Shopova {
383a7398723SShteryana Shopova 	struct snmp_pdu req, resp;
384a7398723SShteryana Shopova 
385a7398723SShteryana Shopova 	snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
386a7398723SShteryana Shopova 
387a7398723SShteryana Shopova 	while ((snmp_pdu_add_bindings(snmptoolctx, snmpget_verify_vbind,
388a7398723SShteryana Shopova 	     snmptool_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
389a7398723SShteryana Shopova 
390a7398723SShteryana Shopova 		if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
391a7398723SShteryana Shopova 			snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
392a7398723SShteryana Shopova 			    GET_NONREP(snmptoolctx));
393a7398723SShteryana Shopova 
394a7398723SShteryana Shopova 		if (snmp_dialog(&req, &resp) == -1) {
3957c933da6SEnji Cooper 			warn("Snmp dialog");
396a7398723SShteryana Shopova 			break;
397a7398723SShteryana Shopova 		}
398a7398723SShteryana Shopova 
399a7398723SShteryana Shopova 		if (snmp_parse_resp(&resp, &req) >= 0) {
400b9288caaSShteryana Shopova 			snmp_output_resp(snmptoolctx, &resp, NULL);
401570afb92SEnji Cooper 			snmp_pdu_free(&resp);
402a7398723SShteryana Shopova 			break;
403a7398723SShteryana Shopova 		}
404a7398723SShteryana Shopova 
405a7398723SShteryana Shopova 		snmp_output_err_resp(snmptoolctx, &resp);
406a7398723SShteryana Shopova 		if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK ||
407570afb92SEnji Cooper 		    !ISSET_RETRY(snmptoolctx)) {
408570afb92SEnji Cooper 			snmp_pdu_free(&resp);
409a7398723SShteryana Shopova 			break;
410570afb92SEnji Cooper 		}
411a7398723SShteryana Shopova 
412a7398723SShteryana Shopova 		/*
413a7398723SShteryana Shopova 		 * Loop through the object list and set object->error to the
414a7398723SShteryana Shopova 		 * varbinding that caused the error.
415a7398723SShteryana Shopova 		 */
416a7398723SShteryana Shopova 		if (snmp_object_seterror(snmptoolctx,
417a7398723SShteryana Shopova 		    &(resp.bindings[resp.error_index - 1]),
418570afb92SEnji Cooper 		    resp.error_status) <= 0) {
419570afb92SEnji Cooper 			snmp_pdu_free(&resp);
420a7398723SShteryana Shopova 			break;
421570afb92SEnji Cooper 		}
422a7398723SShteryana Shopova 
423a7398723SShteryana Shopova 		fprintf(stderr, "Retrying...\n");
424a7398723SShteryana Shopova 		snmp_pdu_free(&resp);
425a7398723SShteryana Shopova 		snmp_pdu_create(&req, GET_PDUTYPE(snmptoolctx));
426a7398723SShteryana Shopova 	}
427a7398723SShteryana Shopova 
4281b135e4fSEnji Cooper 	snmp_pdu_free(&req);
429a7398723SShteryana Shopova 
430a7398723SShteryana Shopova 	return (0);
431a7398723SShteryana Shopova }
432a7398723SShteryana Shopova 
433a7398723SShteryana Shopova 
434a7398723SShteryana Shopova /* *****************************************************************************
435a7398723SShteryana Shopova  * bsnmpwalk private functions.
436a7398723SShteryana Shopova  */
437a7398723SShteryana Shopova /* The default tree to walk. */
438a7398723SShteryana Shopova static const struct asn_oid snmp_mibII_OID = {
439a7398723SShteryana Shopova 	6 , { 1, 3, 6, 1, 2, 1 }
440a7398723SShteryana Shopova };
441a7398723SShteryana Shopova 
442a7398723SShteryana Shopova static int32_t
snmpwalk_add_default(struct snmp_toolinfo * snmptoolctx __unused,struct snmp_object * obj,char * string __unused)443a7398723SShteryana Shopova snmpwalk_add_default(struct snmp_toolinfo *snmptoolctx __unused,
444a7398723SShteryana Shopova     struct snmp_object *obj, char *string __unused)
445a7398723SShteryana Shopova {
446a7398723SShteryana Shopova 	asn_append_oid(&(obj->val.var), &snmp_mibII_OID);
447a7398723SShteryana Shopova 	return (1);
448a7398723SShteryana Shopova }
449a7398723SShteryana Shopova 
450a7398723SShteryana Shopova /*
451a7398723SShteryana Shopova  * Prepare the next GetNext/Get PDU to send.
452a7398723SShteryana Shopova  */
453a7398723SShteryana Shopova static void
snmpwalk_nextpdu_create(uint32_t op,struct asn_oid * var,struct snmp_pdu * pdu)454a7398723SShteryana Shopova snmpwalk_nextpdu_create(uint32_t op, struct asn_oid *var, struct snmp_pdu *pdu)
455a7398723SShteryana Shopova {
456a7398723SShteryana Shopova 	snmp_pdu_create(pdu, op);
457a7398723SShteryana Shopova 	asn_append_oid(&(pdu->bindings[0].var), var);
458a7398723SShteryana Shopova 	pdu->nbindings = 1;
459a7398723SShteryana Shopova }
460a7398723SShteryana Shopova 
461a7398723SShteryana Shopova static int
snmptool_walk(struct snmp_toolinfo * snmptoolctx)462a7398723SShteryana Shopova snmptool_walk(struct snmp_toolinfo *snmptoolctx)
463a7398723SShteryana Shopova {
464a7398723SShteryana Shopova 	struct snmp_pdu req, resp;
4653df5ecacSUlrich Spörlein 	struct asn_oid root;	/* Keep the initial oid. */
466a7398723SShteryana Shopova 	int32_t outputs, rc;
467b9288caaSShteryana Shopova 	uint32_t op;
468a7398723SShteryana Shopova 
469b9288caaSShteryana Shopova 	if (GET_PDUTYPE(snmptoolctx) == SNMP_PDU_GETBULK)
470b9288caaSShteryana Shopova 		op = SNMP_PDU_GETBULK;
471b9288caaSShteryana Shopova 	else
472b9288caaSShteryana Shopova 		op = SNMP_PDU_GETNEXT;
473b9288caaSShteryana Shopova 
474b9288caaSShteryana Shopova 	snmp_pdu_create(&req, op);
475a7398723SShteryana Shopova 
476a7398723SShteryana Shopova 	while ((rc = snmp_pdu_add_bindings(snmptoolctx, NULL,
477a7398723SShteryana Shopova 	    snmptool_add_vbind, &req, 1)) > 0) {
478a7398723SShteryana Shopova 
479a7398723SShteryana Shopova 		/* Remember the root where the walk started from. */
480a7398723SShteryana Shopova 		memset(&root, 0, sizeof(struct asn_oid));
481a7398723SShteryana Shopova 		asn_append_oid(&root, &(req.bindings[0].var));
482a7398723SShteryana Shopova 
483b9288caaSShteryana Shopova 		if (op == SNMP_PDU_GETBULK)
484b9288caaSShteryana Shopova 			snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
485b9288caaSShteryana Shopova 			    GET_NONREP(snmptoolctx));
486b9288caaSShteryana Shopova 
487a7398723SShteryana Shopova 		outputs = 0;
488a7398723SShteryana Shopova 		while (snmp_dialog(&req, &resp) >= 0) {
489a7398723SShteryana Shopova 			if ((snmp_parse_resp(&resp, &req)) < 0) {
490a7398723SShteryana Shopova 				snmp_output_err_resp(snmptoolctx, &resp);
491a7398723SShteryana Shopova 				snmp_pdu_free(&resp);
492a7398723SShteryana Shopova 				outputs = -1;
493a7398723SShteryana Shopova 				break;
494a7398723SShteryana Shopova 			}
495a7398723SShteryana Shopova 
496b9288caaSShteryana Shopova 			rc = snmp_output_resp(snmptoolctx, &resp, &root);
497b9288caaSShteryana Shopova 			if (rc < 0) {
498a7398723SShteryana Shopova 				snmp_pdu_free(&resp);
499a7398723SShteryana Shopova 				outputs = -1;
500a7398723SShteryana Shopova 				break;
501a7398723SShteryana Shopova 			}
502b9288caaSShteryana Shopova 
503b9288caaSShteryana Shopova 			outputs += rc;
504a7398723SShteryana Shopova 
505*f021e357SShteryana Shopova 			if ((u_int)rc < resp.nbindings || resp.nbindings == 0) {
506570afb92SEnji Cooper 				snmp_pdu_free(&resp);
507b9288caaSShteryana Shopova 				break;
508570afb92SEnji Cooper 			}
509b9288caaSShteryana Shopova 
510b9288caaSShteryana Shopova 			snmpwalk_nextpdu_create(op,
511b9288caaSShteryana Shopova 			    &(resp.bindings[resp.nbindings - 1].var), &req);
512b9288caaSShteryana Shopova 			if (op == SNMP_PDU_GETBULK)
513b9288caaSShteryana Shopova 				snmpget_fix_getbulk(&req, GET_MAXREP(snmptoolctx),
514b9288caaSShteryana Shopova 				    GET_NONREP(snmptoolctx));
5151b135e4fSEnji Cooper 			snmp_pdu_free(&resp);
516a7398723SShteryana Shopova 		}
517a7398723SShteryana Shopova 
518a7398723SShteryana Shopova 		/* Just in case our root was a leaf. */
519a7398723SShteryana Shopova 		if (outputs == 0) {
520a7398723SShteryana Shopova 			snmpwalk_nextpdu_create(SNMP_PDU_GET, &root, &req);
521a7398723SShteryana Shopova 			if (snmp_dialog(&req, &resp) == SNMP_CODE_OK) {
522a7398723SShteryana Shopova 				if (snmp_parse_resp(&resp, &req) < 0)
523a7398723SShteryana Shopova 					snmp_output_err_resp(snmptoolctx, &resp);
524a7398723SShteryana Shopova 				else
525570afb92SEnji Cooper 					snmp_output_resp(snmptoolctx, &resp,
526570afb92SEnji Cooper 					    NULL);
5271b135e4fSEnji Cooper 				snmp_pdu_free(&resp);
528a7398723SShteryana Shopova 			} else
5297c933da6SEnji Cooper 				warn("Snmp dialog");
530a7398723SShteryana Shopova 		}
531a7398723SShteryana Shopova 
532a7398723SShteryana Shopova 		if (snmp_object_remove(snmptoolctx, &root) < 0) {
533a7398723SShteryana Shopova 			warnx("snmp_object_remove");
534a7398723SShteryana Shopova 			break;
535a7398723SShteryana Shopova 		}
536a7398723SShteryana Shopova 
5371b135e4fSEnji Cooper 		snmp_pdu_free(&req);
538b9288caaSShteryana Shopova 		snmp_pdu_create(&req, op);
539a7398723SShteryana Shopova 	}
540a7398723SShteryana Shopova 
5411b135e4fSEnji Cooper 	snmp_pdu_free(&req);
5421b135e4fSEnji Cooper 
543a7398723SShteryana Shopova 	if (rc == 0)
544a7398723SShteryana Shopova 		return (0);
545a7398723SShteryana Shopova 	else
546a7398723SShteryana Shopova 		return (1);
547a7398723SShteryana Shopova }
548a7398723SShteryana Shopova 
549a7398723SShteryana Shopova /* *****************************************************************************
550a7398723SShteryana Shopova  * bsnmpset private functions.
551a7398723SShteryana Shopova  */
552a7398723SShteryana Shopova 
553a7398723SShteryana Shopova static int32_t
parse_oid_numeric(struct snmp_value * value,char * val)554a7398723SShteryana Shopova parse_oid_numeric(struct snmp_value *value, char *val)
555a7398723SShteryana Shopova {
556a7398723SShteryana Shopova 	char *endptr;
557a7398723SShteryana Shopova 	int32_t saved_errno;
558a7398723SShteryana Shopova 	asn_subid_t suboid;
559a7398723SShteryana Shopova 
560a7398723SShteryana Shopova 	do {
561a7398723SShteryana Shopova 		saved_errno = errno;
562a7398723SShteryana Shopova 		errno = 0;
563a7398723SShteryana Shopova 		suboid = strtoul(val, &endptr, 10);
564a7398723SShteryana Shopova 		if (errno != 0) {
5657c933da6SEnji Cooper 			warn("Value %s not supported", val);
566a7398723SShteryana Shopova 			errno = saved_errno;
567a7398723SShteryana Shopova 			return (-1);
568a7398723SShteryana Shopova 		}
569a7398723SShteryana Shopova 		errno = saved_errno;
570a7398723SShteryana Shopova 		if ((asn_subid_t) suboid > ASN_MAXID) {
571a7398723SShteryana Shopova 			warnx("Suboid %u > ASN_MAXID", suboid);
572a7398723SShteryana Shopova 			return (-1);
573a7398723SShteryana Shopova 		}
574a7398723SShteryana Shopova 		if (snmp_suboid_append(&(value->v.oid), suboid) < 0)
575a7398723SShteryana Shopova 			return (-1);
576a7398723SShteryana Shopova 		val = endptr + 1;
577a7398723SShteryana Shopova 	} while (*endptr == '.');
578a7398723SShteryana Shopova 
579a7398723SShteryana Shopova 	if (*endptr != '\0')
580a7398723SShteryana Shopova 		warnx("OID value %s not supported", val);
581a7398723SShteryana Shopova 
582a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_OID;
583a7398723SShteryana Shopova 	return (0);
584a7398723SShteryana Shopova }
585a7398723SShteryana Shopova 
586a7398723SShteryana Shopova /*
587a7398723SShteryana Shopova  * Allow OID leaf in both forms:
588a7398723SShteryana Shopova  * 1) 1.3.6.1.2... ->  in such case call directly the function reading raw OIDs;
589a7398723SShteryana Shopova  * 2) begemotSnmpdAgentFreeBSD -> lookup the ASN OID corresponding to that.
590a7398723SShteryana Shopova  */
591a7398723SShteryana Shopova static int32_t
parse_oid_string(struct snmp_toolinfo * snmptoolctx,struct snmp_value * value,char * string)592a7398723SShteryana Shopova parse_oid_string(struct snmp_toolinfo *snmptoolctx,
593a7398723SShteryana Shopova     struct snmp_value *value, char *string)
594a7398723SShteryana Shopova {
595a7398723SShteryana Shopova 	struct snmp_object obj;
596a7398723SShteryana Shopova 
597a7398723SShteryana Shopova 	if (isdigit(string[0]))
598a7398723SShteryana Shopova 		return (parse_oid_numeric(value, string));
599a7398723SShteryana Shopova 
600a7398723SShteryana Shopova 	memset(&obj, 0, sizeof(struct snmp_object));
601a7398723SShteryana Shopova 	if (snmp_lookup_enumoid(snmptoolctx, &obj, string) < 0) {
602a7398723SShteryana Shopova 		warnx("Unknown OID enum string - %s", string);
603a7398723SShteryana Shopova 		return (-1);
604a7398723SShteryana Shopova 	}
605a7398723SShteryana Shopova 
606a7398723SShteryana Shopova 	asn_append_oid(&(value->v.oid), &(obj.val.var));
607a7398723SShteryana Shopova 	return (1);
608a7398723SShteryana Shopova }
609a7398723SShteryana Shopova 
610a7398723SShteryana Shopova static int32_t
parse_ip(struct snmp_value * value,char * val)611a7398723SShteryana Shopova parse_ip(struct snmp_value * value, char * val)
612a7398723SShteryana Shopova {
613a7398723SShteryana Shopova 	char *endptr, *str;
614f16a380fSEnji Cooper 	int32_t i;
615f16a380fSEnji Cooper 	uint32_t v;
616a7398723SShteryana Shopova 
617a7398723SShteryana Shopova 	str = val;
618a7398723SShteryana Shopova 	for (i = 0; i < 4; i++) {
619a7398723SShteryana Shopova 		v = strtoul(str, &endptr, 10);
620a7398723SShteryana Shopova 		if (v > 0xff)
621a7398723SShteryana Shopova 			return (-1);
622a7398723SShteryana Shopova 		if (*endptr != '.' && *endptr != '\0' && i != 3)
623a7398723SShteryana Shopova 			break;
624a7398723SShteryana Shopova 		str = endptr + 1;
625a7398723SShteryana Shopova 		value->v.ipaddress[i] = (uint8_t) v;
626a7398723SShteryana Shopova 	}
627a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_IPADDRESS;
628f16a380fSEnji Cooper 
629a7398723SShteryana Shopova 	return (0);
630a7398723SShteryana Shopova }
631a7398723SShteryana Shopova 
632a7398723SShteryana Shopova static int32_t
parse_int(struct snmp_value * value,char * val)633a7398723SShteryana Shopova parse_int(struct snmp_value *value, char *val)
634a7398723SShteryana Shopova {
635a7398723SShteryana Shopova 	char *endptr;
636a7398723SShteryana Shopova 	int32_t v, saved_errno;
637a7398723SShteryana Shopova 
638a7398723SShteryana Shopova 	saved_errno = errno;
639a7398723SShteryana Shopova 	errno = 0;
640a7398723SShteryana Shopova 
641a7398723SShteryana Shopova 	v = strtol(val, &endptr, 10);
642a7398723SShteryana Shopova 
643a7398723SShteryana Shopova 	if (errno != 0) {
6447c933da6SEnji Cooper 		warn("Value %s not supported", val);
645a7398723SShteryana Shopova 		errno = saved_errno;
646a7398723SShteryana Shopova 		return (-1);
647a7398723SShteryana Shopova 	}
648a7398723SShteryana Shopova 
649a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_INTEGER;
650a7398723SShteryana Shopova 	value->v.integer = v;
651a7398723SShteryana Shopova 	errno = saved_errno;
652a7398723SShteryana Shopova 
653a7398723SShteryana Shopova 	return (0);
654a7398723SShteryana Shopova }
655a7398723SShteryana Shopova 
656a7398723SShteryana Shopova static int32_t
parse_int_string(struct snmp_object * object,char * val)657a7398723SShteryana Shopova parse_int_string(struct snmp_object *object, char *val)
658a7398723SShteryana Shopova {
659a7398723SShteryana Shopova 	int32_t	v;
660a7398723SShteryana Shopova 
661a7398723SShteryana Shopova 	if (isdigit(val[0]))
662a7398723SShteryana Shopova 		return ((parse_int(&(object->val), val)));
663a7398723SShteryana Shopova 
664a7398723SShteryana Shopova 	if (object->info == NULL) {
665a7398723SShteryana Shopova 		warnx("Unknown enumerated integer type - %s", val);
666a7398723SShteryana Shopova 		return (-1);
667a7398723SShteryana Shopova 	}
668a7398723SShteryana Shopova 	if ((v = enum_number_lookup(object->info->snmp_enum, val)) < 0)
669a7398723SShteryana Shopova 		warnx("Unknown enumerated integer type - %s", val);
670a7398723SShteryana Shopova 
671a7398723SShteryana Shopova 	object->val.v.integer = v;
672a7398723SShteryana Shopova 	return (1);
673a7398723SShteryana Shopova }
674a7398723SShteryana Shopova 
675a7398723SShteryana Shopova /*
676a7398723SShteryana Shopova  * Here syntax may be one of SNMP_SYNTAX_COUNTER, SNMP_SYNTAX_GAUGE,
677a7398723SShteryana Shopova  * SNMP_SYNTAX_TIMETICKS.
678a7398723SShteryana Shopova  */
679a7398723SShteryana Shopova static int32_t
parse_uint(struct snmp_value * value,char * val)680a7398723SShteryana Shopova parse_uint(struct snmp_value *value, char *val)
681a7398723SShteryana Shopova {
682a7398723SShteryana Shopova 	char *endptr;
683a7398723SShteryana Shopova 	uint32_t v = 0;
684a7398723SShteryana Shopova 	int32_t saved_errno;
685a7398723SShteryana Shopova 
686a7398723SShteryana Shopova 	saved_errno = errno;
687a7398723SShteryana Shopova 	errno = 0;
688a7398723SShteryana Shopova 
689a7398723SShteryana Shopova 	v = strtoul(val, &endptr, 10);
690a7398723SShteryana Shopova 
691a7398723SShteryana Shopova 	if (errno != 0) {
6927c933da6SEnji Cooper 		warn("Value %s not supported", val);
693a7398723SShteryana Shopova 		errno = saved_errno;
694a7398723SShteryana Shopova 		return (-1);
695a7398723SShteryana Shopova 	}
696a7398723SShteryana Shopova 
697a7398723SShteryana Shopova 	value->v.uint32 = v;
698a7398723SShteryana Shopova 	errno = saved_errno;
699a7398723SShteryana Shopova 
700a7398723SShteryana Shopova 	return (0);
701a7398723SShteryana Shopova }
702a7398723SShteryana Shopova 
703a7398723SShteryana Shopova static int32_t
parse_ticks(struct snmp_value * value,char * val)704a7398723SShteryana Shopova parse_ticks(struct snmp_value *value, char *val)
705a7398723SShteryana Shopova {
706a7398723SShteryana Shopova 	if (parse_uint(value, val) < 0)
707a7398723SShteryana Shopova 		return (-1);
708a7398723SShteryana Shopova 
709a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_TIMETICKS;
710a7398723SShteryana Shopova 	return (0);
711a7398723SShteryana Shopova }
712a7398723SShteryana Shopova 
713a7398723SShteryana Shopova static int32_t
parse_gauge(struct snmp_value * value,char * val)714a7398723SShteryana Shopova parse_gauge(struct snmp_value *value, char *val)
715a7398723SShteryana Shopova {
716a7398723SShteryana Shopova 	if (parse_uint(value, val) < 0)
717a7398723SShteryana Shopova 		return (-1);
718a7398723SShteryana Shopova 
719a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_GAUGE;
720a7398723SShteryana Shopova 	return (0);
721a7398723SShteryana Shopova }
722a7398723SShteryana Shopova 
723a7398723SShteryana Shopova static int32_t
parse_counter(struct snmp_value * value,char * val)724a7398723SShteryana Shopova parse_counter(struct snmp_value *value, char *val)
725a7398723SShteryana Shopova {
726a7398723SShteryana Shopova 	if (parse_uint(value, val) < 0)
727a7398723SShteryana Shopova 		return (-1);
728a7398723SShteryana Shopova 
729a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_COUNTER;
730a7398723SShteryana Shopova 	return (0);
731a7398723SShteryana Shopova }
732a7398723SShteryana Shopova 
733a7398723SShteryana Shopova static int32_t
parse_uint64(struct snmp_value * value,char * val)734a7398723SShteryana Shopova parse_uint64(struct snmp_value *value, char *val)
735a7398723SShteryana Shopova {
736a7398723SShteryana Shopova 	char *endptr;
737a7398723SShteryana Shopova 	int32_t saved_errno;
738a7398723SShteryana Shopova 	uint64_t v;
739a7398723SShteryana Shopova 
740a7398723SShteryana Shopova 	saved_errno = errno;
741a7398723SShteryana Shopova 	errno = 0;
742a7398723SShteryana Shopova 
743a7398723SShteryana Shopova 	v = strtoull(val, &endptr, 10);
744a7398723SShteryana Shopova 
745a7398723SShteryana Shopova 	if (errno != 0) {
7467c933da6SEnji Cooper 		warnx("Value %s not supported", val);
747a7398723SShteryana Shopova 		errno = saved_errno;
748a7398723SShteryana Shopova 		return (-1);
749a7398723SShteryana Shopova 	}
750a7398723SShteryana Shopova 
751a7398723SShteryana Shopova 	value->syntax = SNMP_SYNTAX_COUNTER64;
752a7398723SShteryana Shopova 	value->v.counter64 = v;
753a7398723SShteryana Shopova 	errno = saved_errno;
754a7398723SShteryana Shopova 
755a7398723SShteryana Shopova 	return (0);
756a7398723SShteryana Shopova }
757a7398723SShteryana Shopova 
758a7398723SShteryana Shopova static int32_t
parse_syntax_val(struct snmp_value * value,enum snmp_syntax syntax,char * val)759a7398723SShteryana Shopova parse_syntax_val(struct snmp_value *value, enum snmp_syntax syntax, char *val)
760a7398723SShteryana Shopova {
761a7398723SShteryana Shopova 	switch (syntax) {
762a7398723SShteryana Shopova 		case SNMP_SYNTAX_INTEGER:
763a7398723SShteryana Shopova 			return (parse_int(value, val));
764a7398723SShteryana Shopova 		case SNMP_SYNTAX_IPADDRESS:
765a7398723SShteryana Shopova 			return (parse_ip(value, val));
766a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER:
767a7398723SShteryana Shopova 			return (parse_counter(value, val));
768a7398723SShteryana Shopova 		case SNMP_SYNTAX_GAUGE:
769a7398723SShteryana Shopova 			return (parse_gauge(value, val));
770a7398723SShteryana Shopova 		case SNMP_SYNTAX_TIMETICKS:
771a7398723SShteryana Shopova 			return (parse_ticks(value, val));
772a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER64:
773a7398723SShteryana Shopova 			return (parse_uint64(value, val));
774a7398723SShteryana Shopova 		case SNMP_SYNTAX_OCTETSTRING:
775a7398723SShteryana Shopova 			return (snmp_tc2oct(SNMP_STRING, value, val));
776a7398723SShteryana Shopova 		case SNMP_SYNTAX_OID:
777a7398723SShteryana Shopova 			return (parse_oid_numeric(value, val));
778a7398723SShteryana Shopova 		default:
779a7398723SShteryana Shopova 			/* NOTREACHED */
780a7398723SShteryana Shopova 			break;
781a7398723SShteryana Shopova 	}
782a7398723SShteryana Shopova 
783a7398723SShteryana Shopova 	return (-1);
784a7398723SShteryana Shopova }
785a7398723SShteryana Shopova 
786a7398723SShteryana Shopova /*
787a7398723SShteryana Shopova  * Parse a command line argument of type OID=syntax:value and fill in whatever
788a7398723SShteryana Shopova  * fields can be derived from the input into snmp_value structure. Reads numeric
789a7398723SShteryana Shopova  * OIDs.
790a7398723SShteryana Shopova  */
791a7398723SShteryana Shopova static int32_t
parse_pair_numoid_val(char * str,struct snmp_value * snmp_val)792a7398723SShteryana Shopova parse_pair_numoid_val(char *str, struct snmp_value *snmp_val)
793a7398723SShteryana Shopova {
794a7398723SShteryana Shopova 	int32_t cnt;
795a7398723SShteryana Shopova 	char *ptr;
796a7398723SShteryana Shopova 	enum snmp_syntax syntax;
797a7398723SShteryana Shopova 	char oid_str[ASN_OIDSTRLEN];
798a7398723SShteryana Shopova 
799a7398723SShteryana Shopova 	ptr = str;
800a7398723SShteryana Shopova 	for (cnt = 0; cnt < ASN_OIDSTRLEN; cnt++)
801a7398723SShteryana Shopova 		if (ptr[cnt] == '=')
802a7398723SShteryana Shopova 			break;
803a7398723SShteryana Shopova 
804a7398723SShteryana Shopova 	if (cnt >= ASN_OIDSTRLEN) {
805a7398723SShteryana Shopova 		warnx("OID too long - %s", str);
806a7398723SShteryana Shopova 		return (-1);
807a7398723SShteryana Shopova 	}
808a7398723SShteryana Shopova 	strlcpy(oid_str, ptr, (size_t) (cnt + 1));
809a7398723SShteryana Shopova 
810a7398723SShteryana Shopova 	ptr = str + cnt + 1;
811a7398723SShteryana Shopova 	for (cnt = 0; cnt < MAX_CMD_SYNTAX_LEN; cnt++)
812a7398723SShteryana Shopova 		if(ptr[cnt] == ':')
813a7398723SShteryana Shopova 			break;
814a7398723SShteryana Shopova 
815a7398723SShteryana Shopova 	if (cnt >= MAX_CMD_SYNTAX_LEN) {
816a7398723SShteryana Shopova 		warnx("Unknown syntax in OID - %s", str);
817a7398723SShteryana Shopova 		return (-1);
818a7398723SShteryana Shopova 	}
819a7398723SShteryana Shopova 
820a7398723SShteryana Shopova 	if ((syntax = parse_syntax(ptr)) <= SNMP_SYNTAX_NULL) {
821a7398723SShteryana Shopova 		warnx("Unknown syntax in OID - %s", ptr);
822a7398723SShteryana Shopova 		return (-1);
823a7398723SShteryana Shopova 	}
824a7398723SShteryana Shopova 
825a7398723SShteryana Shopova 	ptr = ptr + cnt + 1;
826a7398723SShteryana Shopova 	for (cnt = 0; cnt < MAX_OCTSTRING_LEN; cnt++)
827a7398723SShteryana Shopova 		if (ptr[cnt] == '\0')
828a7398723SShteryana Shopova 			break;
829a7398723SShteryana Shopova 
830a7398723SShteryana Shopova 	if (ptr[cnt] != '\0') {
831a7398723SShteryana Shopova 		warnx("Value string too long - %s", ptr);
832a7398723SShteryana Shopova 		return (-1);
833a7398723SShteryana Shopova 	}
834a7398723SShteryana Shopova 
835a7398723SShteryana Shopova 	/*
836a7398723SShteryana Shopova 	 * Here try parsing the OIDs and syntaxes and then check values - have
837a7398723SShteryana Shopova 	 * to know syntax to check value boundaries.
838a7398723SShteryana Shopova 	 */
839a7398723SShteryana Shopova 	if (snmp_parse_numoid(oid_str, &(snmp_val->var)) < 0) {
840a7398723SShteryana Shopova 		warnx("Error parsing OID %s", oid_str);
841a7398723SShteryana Shopova 		return (-1);
842a7398723SShteryana Shopova 	}
843a7398723SShteryana Shopova 
844a7398723SShteryana Shopova 	if (parse_syntax_val(snmp_val, syntax, ptr) < 0)
845a7398723SShteryana Shopova 		return (-1);
846a7398723SShteryana Shopova 
847a7398723SShteryana Shopova 	return (1);
848a7398723SShteryana Shopova }
849a7398723SShteryana Shopova 
850a7398723SShteryana Shopova static int32_t
parse_syntax_strval(struct snmp_toolinfo * snmptoolctx,struct snmp_object * object,char * str)85130dcd18bSEnji Cooper parse_syntax_strval(struct snmp_toolinfo *snmptoolctx,
85230dcd18bSEnji Cooper     struct snmp_object *object, char *str)
853a7398723SShteryana Shopova {
854a7398723SShteryana Shopova 	uint32_t len;
855a7398723SShteryana Shopova 	enum snmp_syntax syn;
856a7398723SShteryana Shopova 
857a7398723SShteryana Shopova 	/*
858a7398723SShteryana Shopova 	 * Syntax string here not required  - still may be present.
859a7398723SShteryana Shopova 	 */
860a7398723SShteryana Shopova 
861a7398723SShteryana Shopova 	if (GET_OUTPUT(snmptoolctx) == OUTPUT_VERBOSE) {
862a7398723SShteryana Shopova 		for (len = 0 ; *(str + len) != ':'; len++) {
863a7398723SShteryana Shopova 			if (*(str + len) == '\0') {
864a7398723SShteryana Shopova 				warnx("Syntax missing in value - %s", str);
865a7398723SShteryana Shopova 				return (-1);
866a7398723SShteryana Shopova 			}
867a7398723SShteryana Shopova 		}
868a7398723SShteryana Shopova 		if ((syn = parse_syntax(str)) <= SNMP_SYNTAX_NULL) {
869a7398723SShteryana Shopova 			warnx("Unknown syntax in - %s", str);
870a7398723SShteryana Shopova 			return (-1);
871a7398723SShteryana Shopova 		}
872a7398723SShteryana Shopova 		if (syn != object->val.syntax) {
873a7398723SShteryana Shopova 			if (!ISSET_ERRIGNORE(snmptoolctx)) {
874a7398723SShteryana Shopova 				warnx("Bad syntax in - %s", str);
875a7398723SShteryana Shopova 				return (-1);
876a7398723SShteryana Shopova 			} else
877a7398723SShteryana Shopova 				object->val.syntax = syn;
878a7398723SShteryana Shopova 		}
879a7398723SShteryana Shopova 		len++;
880a7398723SShteryana Shopova 	} else
881a7398723SShteryana Shopova 		len = 0;
882a7398723SShteryana Shopova 
883a7398723SShteryana Shopova 	switch (object->val.syntax) {
884a7398723SShteryana Shopova 		case SNMP_SYNTAX_INTEGER:
885a7398723SShteryana Shopova 			return (parse_int_string(object, str + len));
886a7398723SShteryana Shopova 		case SNMP_SYNTAX_IPADDRESS:
887a7398723SShteryana Shopova 			return (parse_ip(&(object->val), str + len));
888a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER:
889a7398723SShteryana Shopova 			return (parse_counter(&(object->val), str + len));
890a7398723SShteryana Shopova 		case SNMP_SYNTAX_GAUGE:
891a7398723SShteryana Shopova 			return (parse_gauge(&(object->val), str + len));
892a7398723SShteryana Shopova 		case SNMP_SYNTAX_TIMETICKS:
893a7398723SShteryana Shopova 			return (parse_ticks(&(object->val), str + len));
894a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER64:
895a7398723SShteryana Shopova 			return (parse_uint64(&(object->val), str + len));
896a7398723SShteryana Shopova 		case SNMP_SYNTAX_OCTETSTRING:
897a7398723SShteryana Shopova 			return (snmp_tc2oct(object->info->tc, &(object->val),
898a7398723SShteryana Shopova 			    str + len));
899a7398723SShteryana Shopova 		case SNMP_SYNTAX_OID:
900a7398723SShteryana Shopova 			return (parse_oid_string(snmptoolctx, &(object->val),
901a7398723SShteryana Shopova 			    str + len));
902a7398723SShteryana Shopova 		default:
903a7398723SShteryana Shopova 			/* NOTREACHED */
904a7398723SShteryana Shopova 			break;
905a7398723SShteryana Shopova 	}
906a7398723SShteryana Shopova 
907a7398723SShteryana Shopova 	return (-1);
908a7398723SShteryana Shopova }
909a7398723SShteryana Shopova 
910a7398723SShteryana Shopova static int32_t
parse_pair_stroid_val(struct snmp_toolinfo * snmptoolctx,struct snmp_object * obj,char * argv)911a7398723SShteryana Shopova parse_pair_stroid_val(struct snmp_toolinfo *snmptoolctx,
912a7398723SShteryana Shopova     struct snmp_object *obj, char *argv)
913a7398723SShteryana Shopova {
914a7398723SShteryana Shopova 	char *ptr;
915a7398723SShteryana Shopova 
916a7398723SShteryana Shopova 	if ((ptr = snmptools_parse_stroid(snmptoolctx, obj, argv)) == NULL)
917a7398723SShteryana Shopova 		return (-1);
918a7398723SShteryana Shopova 
919a7398723SShteryana Shopova 	if (*ptr != '=') {
920a7398723SShteryana Shopova 		warnx("Value to set expected after OID");
921a7398723SShteryana Shopova 		return (-1);
922a7398723SShteryana Shopova 	}
923a7398723SShteryana Shopova 
92430dcd18bSEnji Cooper 	if (parse_syntax_strval(snmptoolctx, obj, ptr + 1) < 0)
925a7398723SShteryana Shopova 		return (-1);
926a7398723SShteryana Shopova 
927a7398723SShteryana Shopova 	return (1);
928a7398723SShteryana Shopova }
929a7398723SShteryana Shopova 
930a7398723SShteryana Shopova 
931a7398723SShteryana Shopova static int32_t
snmpset_parse_oid(struct snmp_toolinfo * snmptoolctx,struct snmp_object * obj,char * argv)932a7398723SShteryana Shopova snmpset_parse_oid(struct snmp_toolinfo *snmptoolctx,
933a7398723SShteryana Shopova     struct snmp_object *obj, char *argv)
934a7398723SShteryana Shopova {
935a7398723SShteryana Shopova 	if (argv == NULL)
936a7398723SShteryana Shopova 		return (-1);
937a7398723SShteryana Shopova 
938a7398723SShteryana Shopova 	if (ISSET_NUMERIC(snmptoolctx)) {
939a7398723SShteryana Shopova 		if (parse_pair_numoid_val(argv, &(obj->val)) < 0)
940a7398723SShteryana Shopova 			return (-1);
941a7398723SShteryana Shopova 	} else {
942a7398723SShteryana Shopova 		if (parse_pair_stroid_val(snmptoolctx, obj, argv) < 0)
943a7398723SShteryana Shopova 			return (-1);
944a7398723SShteryana Shopova 	}
945a7398723SShteryana Shopova 
946a7398723SShteryana Shopova 	return (1);
947a7398723SShteryana Shopova }
948a7398723SShteryana Shopova 
949a7398723SShteryana Shopova static int32_t
add_ip_syntax(struct snmp_value * dst,struct snmp_value * src)950a7398723SShteryana Shopova add_ip_syntax(struct snmp_value *dst, struct snmp_value *src)
951a7398723SShteryana Shopova {
952a7398723SShteryana Shopova 	int8_t i;
953a7398723SShteryana Shopova 
954a7398723SShteryana Shopova 	dst->syntax = SNMP_SYNTAX_IPADDRESS;
955a7398723SShteryana Shopova 	for (i = 0; i < 4; i++)
956a7398723SShteryana Shopova 		dst->v.ipaddress[i] = src->v.ipaddress[i];
957a7398723SShteryana Shopova 
958a7398723SShteryana Shopova 	return (1);
959a7398723SShteryana Shopova }
960a7398723SShteryana Shopova 
961a7398723SShteryana Shopova static int32_t
add_octstring_syntax(struct snmp_value * dst,struct snmp_value * src)962a7398723SShteryana Shopova add_octstring_syntax(struct snmp_value *dst, struct snmp_value *src)
963a7398723SShteryana Shopova {
964a7398723SShteryana Shopova 	if (src->v.octetstring.len > ASN_MAXOCTETSTRING) {
965a7398723SShteryana Shopova 		warnx("OctetString len too big - %u", src->v.octetstring.len);
966a7398723SShteryana Shopova 		return (-1);
967a7398723SShteryana Shopova 	}
968a7398723SShteryana Shopova 
969a7398723SShteryana Shopova 	if ((dst->v.octetstring.octets = malloc(src->v.octetstring.len)) ==
970a7398723SShteryana Shopova 	    NULL) {
971a7398723SShteryana Shopova 		syslog(LOG_ERR, "malloc() failed - %s", strerror(errno));
972a7398723SShteryana Shopova 		return (-1);
973a7398723SShteryana Shopova 	}
974a7398723SShteryana Shopova 
975a7398723SShteryana Shopova 	memcpy(dst->v.octetstring.octets, src->v.octetstring.octets,
976a7398723SShteryana Shopova 	    src->v.octetstring.len);
977a7398723SShteryana Shopova 	dst->syntax = SNMP_SYNTAX_OCTETSTRING;
978a7398723SShteryana Shopova 	dst->v.octetstring.len = src->v.octetstring.len;
979a7398723SShteryana Shopova 
980a7398723SShteryana Shopova 	return(0);
981a7398723SShteryana Shopova }
982a7398723SShteryana Shopova 
983a7398723SShteryana Shopova static int32_t
add_oid_syntax(struct snmp_value * dst,struct snmp_value * src)984a7398723SShteryana Shopova add_oid_syntax(struct snmp_value *dst, struct snmp_value *src)
985a7398723SShteryana Shopova {
986a7398723SShteryana Shopova 	asn_append_oid(&(dst->v.oid), &(src->v.oid));
987a7398723SShteryana Shopova 	dst->syntax = SNMP_SYNTAX_OID;
988a7398723SShteryana Shopova 	return (0);
989a7398723SShteryana Shopova }
990a7398723SShteryana Shopova 
991a7398723SShteryana Shopova /*
992a7398723SShteryana Shopova  * Check syntax - if one of SNMP_SYNTAX_NULL, SNMP_SYNTAX_NOSUCHOBJECT,
993a7398723SShteryana Shopova  * SNMP_SYNTAX_NOSUCHINSTANCE, SNMP_SYNTAX_ENDOFMIBVIEW or anything not known -
994a7398723SShteryana Shopova  * return error.
995a7398723SShteryana Shopova  */
996a7398723SShteryana Shopova static int32_t
snmpset_add_value(struct snmp_value * dst,struct snmp_value * src)997a7398723SShteryana Shopova snmpset_add_value(struct snmp_value *dst, struct snmp_value *src)
998a7398723SShteryana Shopova {
999a7398723SShteryana Shopova 	if (dst == NULL || src == NULL)
1000a7398723SShteryana Shopova 		return (-1);
1001a7398723SShteryana Shopova 
1002a7398723SShteryana Shopova 	switch (src->syntax) {
1003a7398723SShteryana Shopova 		case SNMP_SYNTAX_INTEGER:
1004a7398723SShteryana Shopova 			dst->v.integer = src->v.integer;
1005a7398723SShteryana Shopova 			dst->syntax = SNMP_SYNTAX_INTEGER;
1006a7398723SShteryana Shopova 			break;
1007a7398723SShteryana Shopova 		case SNMP_SYNTAX_TIMETICKS:
1008a7398723SShteryana Shopova 			dst->v.uint32 = src->v.uint32;
1009a7398723SShteryana Shopova 			dst->syntax = SNMP_SYNTAX_TIMETICKS;
1010a7398723SShteryana Shopova 			break;
1011a7398723SShteryana Shopova 		case SNMP_SYNTAX_GAUGE:
1012a7398723SShteryana Shopova 			dst->v.uint32 = src->v.uint32;
1013a7398723SShteryana Shopova 			dst->syntax = SNMP_SYNTAX_GAUGE;
1014a7398723SShteryana Shopova 			break;
1015a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER:
1016a7398723SShteryana Shopova 			dst->v.uint32 = src->v.uint32;
1017a7398723SShteryana Shopova 			dst->syntax = SNMP_SYNTAX_COUNTER;
1018a7398723SShteryana Shopova 			break;
1019a7398723SShteryana Shopova 		case SNMP_SYNTAX_COUNTER64:
1020a7398723SShteryana Shopova 			dst->v.counter64 = src->v.counter64;
1021a7398723SShteryana Shopova 			dst->syntax = SNMP_SYNTAX_COUNTER64;
1022a7398723SShteryana Shopova 			break;
1023a7398723SShteryana Shopova 		case SNMP_SYNTAX_IPADDRESS:
1024a7398723SShteryana Shopova 			add_ip_syntax(dst, src);
1025a7398723SShteryana Shopova 			break;
1026a7398723SShteryana Shopova 		case SNMP_SYNTAX_OCTETSTRING:
1027a7398723SShteryana Shopova 			add_octstring_syntax(dst, src);
1028a7398723SShteryana Shopova 			break;
1029a7398723SShteryana Shopova 		case SNMP_SYNTAX_OID:
1030a7398723SShteryana Shopova 			add_oid_syntax(dst, src);
1031a7398723SShteryana Shopova 			break;
1032a7398723SShteryana Shopova 		default:
1033a7398723SShteryana Shopova 			warnx("Unknown syntax %d", src->syntax);
1034a7398723SShteryana Shopova 			return (-1);
1035a7398723SShteryana Shopova 	}
1036a7398723SShteryana Shopova 
1037a7398723SShteryana Shopova 	return (0);
1038a7398723SShteryana Shopova }
1039a7398723SShteryana Shopova 
1040a7398723SShteryana Shopova static int32_t
snmpset_verify_vbind(struct snmp_toolinfo * snmptoolctx,struct snmp_pdu * pdu,struct snmp_object * obj)1041a7398723SShteryana Shopova snmpset_verify_vbind(struct snmp_toolinfo *snmptoolctx, struct snmp_pdu *pdu,
1042a7398723SShteryana Shopova     struct snmp_object *obj)
1043a7398723SShteryana Shopova {
1044a7398723SShteryana Shopova 	if (pdu->version == SNMP_V1 && obj->val.syntax ==
1045a7398723SShteryana Shopova 	    SNMP_SYNTAX_COUNTER64) {
1046a7398723SShteryana Shopova 		warnx("64-bit counters are not supported in SNMPv1 PDU");
1047a7398723SShteryana Shopova 		return (-1);
1048a7398723SShteryana Shopova 	}
1049a7398723SShteryana Shopova 
1050a7398723SShteryana Shopova 	if (ISSET_NUMERIC(snmptoolctx) || ISSET_ERRIGNORE(snmptoolctx))
1051a7398723SShteryana Shopova 		return (1);
1052a7398723SShteryana Shopova 
1053a7398723SShteryana Shopova 	if (obj->info->access < SNMP_ACCESS_SET) {
1054a7398723SShteryana Shopova 		warnx("Object %s not accessible for set - try 'bsnmpset -a'",
1055a7398723SShteryana Shopova 		    obj->info->string);
1056a7398723SShteryana Shopova 		return (-1);
1057a7398723SShteryana Shopova 	}
1058a7398723SShteryana Shopova 
1059a7398723SShteryana Shopova 	return (1);
1060a7398723SShteryana Shopova }
1061a7398723SShteryana Shopova 
1062a7398723SShteryana Shopova static int32_t
snmpset_add_vbind(struct snmp_pdu * pdu,struct snmp_object * obj)1063a7398723SShteryana Shopova snmpset_add_vbind(struct snmp_pdu *pdu, struct snmp_object *obj)
1064a7398723SShteryana Shopova {
1065a7398723SShteryana Shopova 	if (pdu->nbindings > SNMP_MAX_BINDINGS) {
1066a7398723SShteryana Shopova 		warnx("Too many OIDs for one PDU");
1067a7398723SShteryana Shopova 		return (-1);
1068a7398723SShteryana Shopova 	}
1069a7398723SShteryana Shopova 
1070a7398723SShteryana Shopova 	if (obj->error > 0)
1071a7398723SShteryana Shopova 		return (0);
1072a7398723SShteryana Shopova 
1073a7398723SShteryana Shopova 	if (snmpset_add_value(&(pdu->bindings[pdu->nbindings]), &(obj->val))
1074a7398723SShteryana Shopova 	    < 0)
1075a7398723SShteryana Shopova 		return (-1);
1076a7398723SShteryana Shopova 
1077a7398723SShteryana Shopova 	asn_append_oid(&(pdu->bindings[pdu->nbindings].var), &(obj->val.var));
1078a7398723SShteryana Shopova 	pdu->nbindings++;
1079a7398723SShteryana Shopova 
1080a7398723SShteryana Shopova 	return (pdu->nbindings);
1081a7398723SShteryana Shopova }
1082a7398723SShteryana Shopova 
1083a7398723SShteryana Shopova static int
snmptool_set(struct snmp_toolinfo * snmptoolctx)1084a7398723SShteryana Shopova snmptool_set(struct snmp_toolinfo *snmptoolctx)
1085a7398723SShteryana Shopova {
1086a7398723SShteryana Shopova 	struct snmp_pdu req, resp;
1087a7398723SShteryana Shopova 
1088a7398723SShteryana Shopova 	snmp_pdu_create(&req, SNMP_PDU_SET);
1089a7398723SShteryana Shopova 
1090a7398723SShteryana Shopova 	while ((snmp_pdu_add_bindings(snmptoolctx, snmpset_verify_vbind,
1091a7398723SShteryana Shopova 	    snmpset_add_vbind, &req, SNMP_MAX_BINDINGS)) > 0) {
1092a7398723SShteryana Shopova 		if (snmp_dialog(&req, &resp)) {
10937c933da6SEnji Cooper 			warn("Snmp dialog");
1094a7398723SShteryana Shopova 			break;
1095a7398723SShteryana Shopova 		}
1096a7398723SShteryana Shopova 
1097a7398723SShteryana Shopova 		if (snmp_pdu_check(&req, &resp) > 0) {
1098a7398723SShteryana Shopova 			if (GET_OUTPUT(snmptoolctx) != OUTPUT_QUIET)
1099b9288caaSShteryana Shopova 				snmp_output_resp(snmptoolctx, &resp, NULL);
1100570afb92SEnji Cooper 			snmp_pdu_free(&resp);
1101a7398723SShteryana Shopova 			break;
1102a7398723SShteryana Shopova 		}
1103a7398723SShteryana Shopova 
1104a7398723SShteryana Shopova 		snmp_output_err_resp(snmptoolctx, &resp);
1105570afb92SEnji Cooper 		if (!ISSET_RETRY(snmptoolctx)) {
1106570afb92SEnji Cooper 			snmp_pdu_free(&resp);
1107a7398723SShteryana Shopova 			break;
1108570afb92SEnji Cooper 		}
1109a7398723SShteryana Shopova 
1110a7398723SShteryana Shopova 		if (snmp_object_seterror(snmptoolctx,
1111a7398723SShteryana Shopova 		    &(resp.bindings[resp.error_index - 1]),
1112570afb92SEnji Cooper 		    resp.error_status) <= 0) {
1113570afb92SEnji Cooper 			snmp_pdu_free(&resp);
1114a7398723SShteryana Shopova 			break;
1115570afb92SEnji Cooper 		}
1116a7398723SShteryana Shopova 
1117a7398723SShteryana Shopova 		fprintf(stderr, "Retrying...\n");
1118a7398723SShteryana Shopova 		snmp_pdu_free(&req);
1119a7398723SShteryana Shopova 		snmp_pdu_create(&req, SNMP_PDU_SET);
1120a7398723SShteryana Shopova 	}
1121a7398723SShteryana Shopova 
1122570afb92SEnji Cooper 	snmp_pdu_free(&req);
1123a7398723SShteryana Shopova 
1124a7398723SShteryana Shopova 	return (0);
1125a7398723SShteryana Shopova }
1126a7398723SShteryana Shopova 
1127a7398723SShteryana Shopova /* *****************************************************************************
1128a7398723SShteryana Shopova  * main
1129a7398723SShteryana Shopova  */
1130a7398723SShteryana Shopova /*
1131a7398723SShteryana Shopova  * According to command line options prepare SNMP Get | GetNext | GetBulk PDU.
11323df5ecacSUlrich Spörlein  * Wait for a response and print it.
1133a7398723SShteryana Shopova  */
1134a7398723SShteryana Shopova /*
1135a7398723SShteryana Shopova  * Do a 'snmp walk' - according to command line options request for values
1136a7398723SShteryana Shopova  * lexicographically subsequent and subrooted at a common node. Send a GetNext
11373df5ecacSUlrich Spörlein  * PDU requesting the value for each next variable and print the response. Stop
11383df5ecacSUlrich Spörlein  * when a Response PDU is received that contains the value of a variable not
1139a7398723SShteryana Shopova  * subrooted at the variable the walk started.
1140a7398723SShteryana Shopova  */
1141a7398723SShteryana Shopova int
main(int argc,char ** argv)1142a7398723SShteryana Shopova main(int argc, char ** argv)
1143a7398723SShteryana Shopova {
1144a7398723SShteryana Shopova 	struct snmp_toolinfo snmptoolctx;
1145a7398723SShteryana Shopova 	int32_t oid_cnt, last_oid, opt_num;
1146a7398723SShteryana Shopova 	int rc = 0;
1147a7398723SShteryana Shopova 
1148a7398723SShteryana Shopova 	/* Make sure program_name is set and valid. */
1149a7398723SShteryana Shopova 	if (*argv == NULL)
1150a7398723SShteryana Shopova 		program_name = "snmptool";
1151a7398723SShteryana Shopova 	else {
1152a7398723SShteryana Shopova 		program_name = strrchr(*argv, '/');
1153a7398723SShteryana Shopova 		if (program_name != NULL)
1154a7398723SShteryana Shopova 			program_name++;
1155a7398723SShteryana Shopova 		else
1156a7398723SShteryana Shopova 			program_name = *argv;
1157a7398723SShteryana Shopova 	}
1158a7398723SShteryana Shopova 
1159a7398723SShteryana Shopova 	if (program_name == NULL) {
1160a7398723SShteryana Shopova 		fprintf(stderr, "Error: No program name?\n");
1161a7398723SShteryana Shopova 		exit (1);
1162a7398723SShteryana Shopova 	} else if (strcmp(program_name, "bsnmpget") == 0)
1163a7398723SShteryana Shopova 		program = BSNMPGET;
1164a7398723SShteryana Shopova 	else if (strcmp(program_name, "bsnmpwalk") == 0)
1165a7398723SShteryana Shopova 		program = BSNMPWALK;
1166a7398723SShteryana Shopova 	else if (strcmp(program_name, "bsnmpset") == 0)
1167a7398723SShteryana Shopova 		program = BSNMPSET;
1168a7398723SShteryana Shopova 	else {
1169a7398723SShteryana Shopova 		fprintf(stderr, "Unknown snmp tool name '%s'.\n", program_name);
1170a7398723SShteryana Shopova 		exit (1);
1171a7398723SShteryana Shopova 	}
1172a7398723SShteryana Shopova 
1173a7398723SShteryana Shopova 	/* Initialize. */
1174a7398723SShteryana Shopova 	if (snmptool_init(&snmptoolctx) < 0)
1175a7398723SShteryana Shopova 		exit (1);
1176a7398723SShteryana Shopova 
1177a7398723SShteryana Shopova 	if ((opt_num = snmptool_parse_options(&snmptoolctx, argc, argv)) < 0) {
1178a7398723SShteryana Shopova 		snmp_tool_freeall(&snmptoolctx);
1179a7398723SShteryana Shopova 		/* On -h (help) exit without error. */
1180a7398723SShteryana Shopova 		if (opt_num == -2)
1181a7398723SShteryana Shopova 			exit(0);
1182a7398723SShteryana Shopova 		else
1183a7398723SShteryana Shopova 			exit(1);
1184a7398723SShteryana Shopova 	}
1185a7398723SShteryana Shopova 
1186a7398723SShteryana Shopova 	oid_cnt = argc - opt_num - 1;
1187a7398723SShteryana Shopova 	if (oid_cnt == 0) {
1188a7398723SShteryana Shopova 		switch (program) {
1189a7398723SShteryana Shopova 		case BSNMPGET:
1190a7398723SShteryana Shopova 			if (!ISSET_EDISCOVER(&snmptoolctx) &&
1191a7398723SShteryana Shopova 			    !ISSET_LOCALKEY(&snmptoolctx)) {
1192a7398723SShteryana Shopova 				fprintf(stderr, "No OID given.\n");
1193a7398723SShteryana Shopova 				usage();
1194a7398723SShteryana Shopova 				snmp_tool_freeall(&snmptoolctx);
1195a7398723SShteryana Shopova 				exit(1);
1196a7398723SShteryana Shopova 			}
1197a7398723SShteryana Shopova 			break;
1198a7398723SShteryana Shopova 
1199a7398723SShteryana Shopova 		case BSNMPWALK:
1200a7398723SShteryana Shopova 			if (snmp_object_add(&snmptoolctx, snmpwalk_add_default,
1201a7398723SShteryana Shopova 			    NULL) < 0) {
1202a7398723SShteryana Shopova 				fprintf(stderr,
1203a7398723SShteryana Shopova 				    "Error setting default subtree.\n");
1204a7398723SShteryana Shopova 				snmp_tool_freeall(&snmptoolctx);
1205a7398723SShteryana Shopova 				exit(1);
1206a7398723SShteryana Shopova 			}
1207a7398723SShteryana Shopova 			break;
1208a7398723SShteryana Shopova 
1209a7398723SShteryana Shopova 		case BSNMPSET:
1210a7398723SShteryana Shopova 			fprintf(stderr, "No OID given.\n");
1211a7398723SShteryana Shopova 			usage();
1212a7398723SShteryana Shopova 			snmp_tool_freeall(&snmptoolctx);
1213a7398723SShteryana Shopova 			exit(1);
1214a7398723SShteryana Shopova 		}
1215a7398723SShteryana Shopova 	}
1216a7398723SShteryana Shopova 
1217a7398723SShteryana Shopova 	if (snmp_import_all(&snmptoolctx) < 0) {
1218a7398723SShteryana Shopova 		snmp_tool_freeall(&snmptoolctx);
1219a7398723SShteryana Shopova 		exit(1);
1220a7398723SShteryana Shopova 	}
1221a7398723SShteryana Shopova 
1222a7398723SShteryana Shopova 	/* A simple sanity check - can not send GETBULK when using SNMPv1. */
1223a7398723SShteryana Shopova 	if (program == BSNMPGET && snmp_client.version == SNMP_V1 &&
1224a7398723SShteryana Shopova 	    GET_PDUTYPE(&snmptoolctx) == SNMP_PDU_GETBULK) {
1225a7398723SShteryana Shopova 		fprintf(stderr, "Cannot send GETBULK PDU with SNMPv1.\n");
1226a7398723SShteryana Shopova 		snmp_tool_freeall(&snmptoolctx);
1227a7398723SShteryana Shopova 		exit(1);
1228a7398723SShteryana Shopova 	}
1229a7398723SShteryana Shopova 
1230a7398723SShteryana Shopova 	for (last_oid = argc - 1; oid_cnt > 0; last_oid--, oid_cnt--) {
1231a7398723SShteryana Shopova 		if ((snmp_object_add(&snmptoolctx, (program == BSNMPSET) ?
1232a7398723SShteryana Shopova 		    snmpset_parse_oid : snmptools_parse_oid,
1233a7398723SShteryana Shopova 		    argv[last_oid])) < 0) {
1234a7398723SShteryana Shopova 			fprintf(stderr, "Error parsing OID string '%s'.\n",
1235a7398723SShteryana Shopova 			    argv[last_oid]);
1236a7398723SShteryana Shopova 			snmp_tool_freeall(&snmptoolctx);
1237a7398723SShteryana Shopova 			exit(1);
1238a7398723SShteryana Shopova 		}
1239a7398723SShteryana Shopova 	}
1240a7398723SShteryana Shopova 
1241a7398723SShteryana Shopova 	if (snmp_open(NULL, NULL, NULL, NULL)) {
12427c933da6SEnji Cooper 		warn("Failed to open snmp session");
1243a7398723SShteryana Shopova 		snmp_tool_freeall(&snmptoolctx);
1244a7398723SShteryana Shopova 		exit(1);
1245a7398723SShteryana Shopova 	}
1246a7398723SShteryana Shopova 
1247a7398723SShteryana Shopova 	if (snmp_client.version == SNMP_V3 && snmp_client.engine.engine_len == 0)
1248a7398723SShteryana Shopova 		SET_EDISCOVER(&snmptoolctx);
1249a7398723SShteryana Shopova 
1250a7398723SShteryana Shopova 	if (ISSET_EDISCOVER(&snmptoolctx) &&
1251a7398723SShteryana Shopova 	    snmp_discover_engine(snmptoolctx.passwd) < 0) {
12527c933da6SEnji Cooper 		warn("Unknown SNMP Engine ID");
1253a7398723SShteryana Shopova 		rc = 1;
1254a7398723SShteryana Shopova 		goto cleanup;
1255a7398723SShteryana Shopova 	}
1256a7398723SShteryana Shopova 
1257a7398723SShteryana Shopova 	if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1258a7398723SShteryana Shopova 	    ISSET_EDISCOVER(&snmptoolctx))
1259a7398723SShteryana Shopova 		snmp_output_engine();
1260a7398723SShteryana Shopova 
1261a7398723SShteryana Shopova 	if (snmp_client.version == SNMP_V3 && ISSET_LOCALKEY(&snmptoolctx) &&
1262a7398723SShteryana Shopova 	    !ISSET_EDISCOVER(&snmptoolctx)) {
1263a7398723SShteryana Shopova 		if (snmp_passwd_to_keys(&snmp_client.user,
1264a7398723SShteryana Shopova 		    snmptoolctx.passwd) != SNMP_CODE_OK ||
1265a7398723SShteryana Shopova 		    snmp_get_local_keys(&snmp_client.user,
1266a7398723SShteryana Shopova 		    snmp_client.engine.engine_id,
1267a7398723SShteryana Shopova 		    snmp_client.engine.engine_len) != SNMP_CODE_OK) {
12687c933da6SEnji Cooper 		    	warn("Failed to get keys");
1269a7398723SShteryana Shopova 			rc = 1;
1270a7398723SShteryana Shopova 			goto cleanup;
1271a7398723SShteryana Shopova 		}
1272a7398723SShteryana Shopova 	}
1273a7398723SShteryana Shopova 
1274a7398723SShteryana Shopova 	if (GET_OUTPUT(&snmptoolctx) == OUTPUT_VERBOSE ||
1275a7398723SShteryana Shopova 	    ISSET_EDISCOVER(&snmptoolctx))
1276a7398723SShteryana Shopova 		snmp_output_keys();
1277a7398723SShteryana Shopova 
1278a7398723SShteryana Shopova 	if (ISSET_EDISCOVER(&snmptoolctx) && snmptoolctx.objects == 0)
1279a7398723SShteryana Shopova 		goto cleanup;
1280a7398723SShteryana Shopova 
1281a7398723SShteryana Shopova 	switch (program) {
1282a7398723SShteryana Shopova 	case BSNMPGET:
1283a7398723SShteryana Shopova 		rc = snmptool_get(&snmptoolctx);
1284a7398723SShteryana Shopova 		break;
1285a7398723SShteryana Shopova 	case BSNMPWALK:
1286a7398723SShteryana Shopova 		rc = snmptool_walk(&snmptoolctx);
1287a7398723SShteryana Shopova 		break;
1288a7398723SShteryana Shopova 	case BSNMPSET:
1289a7398723SShteryana Shopova 		rc = snmptool_set(&snmptoolctx);
1290a7398723SShteryana Shopova 		break;
1291a7398723SShteryana Shopova 	}
1292a7398723SShteryana Shopova 
1293a7398723SShteryana Shopova 
1294a7398723SShteryana Shopova cleanup:
1295a7398723SShteryana Shopova 	snmp_tool_freeall(&snmptoolctx);
1296a7398723SShteryana Shopova 	snmp_close();
1297a7398723SShteryana Shopova 
1298a7398723SShteryana Shopova 	exit(rc);
1299a7398723SShteryana Shopova }
1300