xref: /freebsd/contrib/bsnmp/lib/snmp.c (revision 135f7de5ddb65ddb53a072113961b7d779a72f1b)
1f06ca4afSHartmut Brandt /*
2f06ca4afSHartmut Brandt  * Copyright (c) 2001-2003
3f06ca4afSHartmut Brandt  *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4f06ca4afSHartmut Brandt  *	All rights reserved.
5f06ca4afSHartmut Brandt  *
6f06ca4afSHartmut Brandt  * Author: Harti Brandt <harti@freebsd.org>
7f06ca4afSHartmut Brandt  *
8*135f7de5SShteryana Shopova  * Copyright (c) 2010 The FreeBSD Foundation
9*135f7de5SShteryana Shopova  * All rights reserved.
10*135f7de5SShteryana Shopova  *
11*135f7de5SShteryana Shopova  * Portions of this software were developed by Shteryana Sotirova Shopova
12*135f7de5SShteryana Shopova  * under sponsorship from the FreeBSD Foundation.
13*135f7de5SShteryana Shopova  *
14896052c1SHartmut Brandt  * Redistribution and use in source and binary forms, with or without
15896052c1SHartmut Brandt  * modification, are permitted provided that the following conditions
16896052c1SHartmut Brandt  * are met:
17896052c1SHartmut Brandt  * 1. Redistributions of source code must retain the above copyright
18896052c1SHartmut Brandt  *    notice, this list of conditions and the following disclaimer.
19f06ca4afSHartmut Brandt  * 2. Redistributions in binary form must reproduce the above copyright
20f06ca4afSHartmut Brandt  *    notice, this list of conditions and the following disclaimer in the
21f06ca4afSHartmut Brandt  *    documentation and/or other materials provided with the distribution.
22f06ca4afSHartmut Brandt  *
23896052c1SHartmut Brandt  * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24896052c1SHartmut Brandt  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25896052c1SHartmut Brandt  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26896052c1SHartmut Brandt  * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27896052c1SHartmut Brandt  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28896052c1SHartmut Brandt  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29896052c1SHartmut Brandt  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30896052c1SHartmut Brandt  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31896052c1SHartmut Brandt  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32896052c1SHartmut Brandt  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33896052c1SHartmut Brandt  * SUCH DAMAGE.
34f06ca4afSHartmut Brandt  *
35165c5d31SHartmut Brandt  * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
36f06ca4afSHartmut Brandt  *
37f06ca4afSHartmut Brandt  * SNMP
38f06ca4afSHartmut Brandt  */
39f06ca4afSHartmut Brandt #include <sys/types.h>
40f06ca4afSHartmut Brandt #include <sys/socket.h>
41f06ca4afSHartmut Brandt #include <stdio.h>
42f06ca4afSHartmut Brandt #include <stdlib.h>
43f06ca4afSHartmut Brandt #include <stddef.h>
44f06ca4afSHartmut Brandt #include <stdarg.h>
45165c5d31SHartmut Brandt #ifdef HAVE_STDINT_H
46896052c1SHartmut Brandt #include <stdint.h>
47165c5d31SHartmut Brandt #elif defined(HAVE_INTTYPES_H)
48165c5d31SHartmut Brandt #include <inttypes.h>
49165c5d31SHartmut Brandt #endif
50f06ca4afSHartmut Brandt #include <string.h>
51f06ca4afSHartmut Brandt #include <ctype.h>
52f06ca4afSHartmut Brandt #include <netdb.h>
53f06ca4afSHartmut Brandt #include <errno.h>
54f06ca4afSHartmut Brandt 
55f06ca4afSHartmut Brandt #include "asn1.h"
56f06ca4afSHartmut Brandt #include "snmp.h"
57f06ca4afSHartmut Brandt #include "snmppriv.h"
58f06ca4afSHartmut Brandt 
59f06ca4afSHartmut Brandt static void snmp_error_func(const char *, ...);
60f06ca4afSHartmut Brandt static void snmp_printf_func(const char *, ...);
61f06ca4afSHartmut Brandt 
62f06ca4afSHartmut Brandt void (*snmp_error)(const char *, ...) = snmp_error_func;
63f06ca4afSHartmut Brandt void (*snmp_printf)(const char *, ...) = snmp_printf_func;
64f06ca4afSHartmut Brandt 
65f06ca4afSHartmut Brandt /*
66f06ca4afSHartmut Brandt  * Get the next variable binding from the list.
67f06ca4afSHartmut Brandt  * ASN errors on the sequence or the OID are always fatal.
68f06ca4afSHartmut Brandt  */
69f06ca4afSHartmut Brandt static enum asn_err
70f06ca4afSHartmut Brandt get_var_binding(struct asn_buf *b, struct snmp_value *binding)
71f06ca4afSHartmut Brandt {
72f06ca4afSHartmut Brandt 	u_char type;
73f06ca4afSHartmut Brandt 	asn_len_t len, trailer;
74f06ca4afSHartmut Brandt 	enum asn_err err;
75f06ca4afSHartmut Brandt 
76f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
77f06ca4afSHartmut Brandt 		snmp_error("cannot parse varbind header");
78f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
79f06ca4afSHartmut Brandt 	}
80f06ca4afSHartmut Brandt 
81f06ca4afSHartmut Brandt 	/* temporary truncate the length so that the parser does not
82f06ca4afSHartmut Brandt 	 * eat up bytes behind the sequence in the case the encoding is
83f06ca4afSHartmut Brandt 	 * wrong of inner elements. */
84f06ca4afSHartmut Brandt 	trailer = b->asn_len - len;
85f06ca4afSHartmut Brandt 	b->asn_len = len;
86f06ca4afSHartmut Brandt 
87f06ca4afSHartmut Brandt 	if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
88f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding objid");
89f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
90f06ca4afSHartmut Brandt 	}
91f06ca4afSHartmut Brandt 	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
92f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding value header");
93f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
94f06ca4afSHartmut Brandt 	}
95f06ca4afSHartmut Brandt 
96f06ca4afSHartmut Brandt 	switch (type) {
97f06ca4afSHartmut Brandt 
98f06ca4afSHartmut Brandt 	  case ASN_TYPE_NULL:
99f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NULL;
100f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
101f06ca4afSHartmut Brandt 		break;
102f06ca4afSHartmut Brandt 
103f06ca4afSHartmut Brandt 	  case ASN_TYPE_INTEGER:
104f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_INTEGER;
105f06ca4afSHartmut Brandt 		err = asn_get_integer_raw(b, len, &binding->v.integer);
106f06ca4afSHartmut Brandt 		break;
107f06ca4afSHartmut Brandt 
108f06ca4afSHartmut Brandt 	  case ASN_TYPE_OCTETSTRING:
109f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_OCTETSTRING;
110f06ca4afSHartmut Brandt 		binding->v.octetstring.octets = malloc(len);
111f06ca4afSHartmut Brandt 		if (binding->v.octetstring.octets == NULL) {
112f06ca4afSHartmut Brandt 			snmp_error("%s", strerror(errno));
113f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
114f06ca4afSHartmut Brandt 		}
115f06ca4afSHartmut Brandt 		binding->v.octetstring.len = len;
116f06ca4afSHartmut Brandt 		err = asn_get_octetstring_raw(b, len,
117f06ca4afSHartmut Brandt 		    binding->v.octetstring.octets,
118f06ca4afSHartmut Brandt 		    &binding->v.octetstring.len);
119f06ca4afSHartmut Brandt 		if (ASN_ERR_STOPPED(err)) {
120f06ca4afSHartmut Brandt 			free(binding->v.octetstring.octets);
121f06ca4afSHartmut Brandt 			binding->v.octetstring.octets = NULL;
122f06ca4afSHartmut Brandt 		}
123f06ca4afSHartmut Brandt 		break;
124f06ca4afSHartmut Brandt 
125f06ca4afSHartmut Brandt 	  case ASN_TYPE_OBJID:
126f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_OID;
127f06ca4afSHartmut Brandt 		err = asn_get_objid_raw(b, len, &binding->v.oid);
128f06ca4afSHartmut Brandt 		break;
129f06ca4afSHartmut Brandt 
130f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
131f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_IPADDRESS;
132f06ca4afSHartmut Brandt 		err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
133f06ca4afSHartmut Brandt 		break;
134f06ca4afSHartmut Brandt 
135f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
136f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_TIMETICKS;
137f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138f06ca4afSHartmut Brandt 		break;
139f06ca4afSHartmut Brandt 
140f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
141f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_COUNTER;
142f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
143f06ca4afSHartmut Brandt 		break;
144f06ca4afSHartmut Brandt 
145f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
146f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_GAUGE;
147f06ca4afSHartmut Brandt 		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
148f06ca4afSHartmut Brandt 		break;
149f06ca4afSHartmut Brandt 
150f06ca4afSHartmut Brandt 	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
151f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_COUNTER64;
152f06ca4afSHartmut Brandt 		err = asn_get_counter64_raw(b, len, &binding->v.counter64);
153f06ca4afSHartmut Brandt 		break;
154f06ca4afSHartmut Brandt 
155f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
156f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
157f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
158f06ca4afSHartmut Brandt 		break;
159f06ca4afSHartmut Brandt 
160f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
161f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
162f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
163f06ca4afSHartmut Brandt 		break;
164f06ca4afSHartmut Brandt 
165f06ca4afSHartmut Brandt 	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
166f06ca4afSHartmut Brandt 		binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
167f06ca4afSHartmut Brandt 		err = asn_get_null_raw(b, len);
168f06ca4afSHartmut Brandt 		break;
169f06ca4afSHartmut Brandt 
170f06ca4afSHartmut Brandt 	  default:
171f06ca4afSHartmut Brandt 		if ((err = asn_skip(b, len)) == ASN_ERR_OK)
172f06ca4afSHartmut Brandt 			err = ASN_ERR_TAG;
173f06ca4afSHartmut Brandt 		snmp_error("bad binding value type 0x%x", type);
174f06ca4afSHartmut Brandt 		break;
175f06ca4afSHartmut Brandt 	}
176f06ca4afSHartmut Brandt 
177f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err)) {
178f06ca4afSHartmut Brandt 		snmp_error("cannot parse binding value");
179f06ca4afSHartmut Brandt 		return (err);
180f06ca4afSHartmut Brandt 	}
181f06ca4afSHartmut Brandt 
182f06ca4afSHartmut Brandt 	if (b->asn_len != 0)
183f06ca4afSHartmut Brandt 		snmp_error("ignoring junk at end of binding");
184f06ca4afSHartmut Brandt 
185f06ca4afSHartmut Brandt 	b->asn_len = trailer;
186f06ca4afSHartmut Brandt 
187f06ca4afSHartmut Brandt 	return (err);
188f06ca4afSHartmut Brandt }
189f06ca4afSHartmut Brandt 
190f06ca4afSHartmut Brandt /*
191f06ca4afSHartmut Brandt  * Parse the different PDUs contents. Any ASN error in the outer components
192f06ca4afSHartmut Brandt  * are fatal. Only errors in variable values may be tolerated. If all
193f06ca4afSHartmut Brandt  * components can be parsed it returns either ASN_ERR_OK or the first
194f06ca4afSHartmut Brandt  * error that was found.
195f06ca4afSHartmut Brandt  */
196f06ca4afSHartmut Brandt enum asn_err
197f06ca4afSHartmut Brandt snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
198f06ca4afSHartmut Brandt {
199f06ca4afSHartmut Brandt 	if (pdu->type == SNMP_PDU_TRAP) {
200f06ca4afSHartmut Brandt 		if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
201f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap enterprise");
202f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
203f06ca4afSHartmut Brandt 		}
204f06ca4afSHartmut Brandt 		if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
205f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap agent address");
206f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
207f06ca4afSHartmut Brandt 		}
208f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
209f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'generic-trap'");
210f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
211f06ca4afSHartmut Brandt 		}
212f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
213f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'specific-trap'");
214f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
215f06ca4afSHartmut Brandt 		}
216f06ca4afSHartmut Brandt 		if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
217f06ca4afSHartmut Brandt 			snmp_error("cannot parse trap 'time-stamp'");
218f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
219f06ca4afSHartmut Brandt 		}
220f06ca4afSHartmut Brandt 	} else {
221f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
222f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'request-id'");
223f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
224f06ca4afSHartmut Brandt 		}
225f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
226f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'error_status'");
227f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
228f06ca4afSHartmut Brandt 		}
229f06ca4afSHartmut Brandt 		if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
230f06ca4afSHartmut Brandt 			snmp_error("cannot parse 'error_index'");
231f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
232f06ca4afSHartmut Brandt 		}
233f06ca4afSHartmut Brandt 	}
234f06ca4afSHartmut Brandt 
235f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
236f06ca4afSHartmut Brandt 		snmp_error("cannot get varlist header");
237f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
238f06ca4afSHartmut Brandt 	}
239f06ca4afSHartmut Brandt 
240f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
241f06ca4afSHartmut Brandt }
242f06ca4afSHartmut Brandt 
243f06ca4afSHartmut Brandt static enum asn_err
244f06ca4afSHartmut Brandt parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
245f06ca4afSHartmut Brandt {
246f06ca4afSHartmut Brandt 	asn_len_t len, trailer;
247f06ca4afSHartmut Brandt 	struct snmp_value *v;
248f06ca4afSHartmut Brandt 	enum asn_err err, err1;
249f06ca4afSHartmut Brandt 
250f06ca4afSHartmut Brandt 	err = snmp_parse_pdus_hdr(b, pdu, &len);
251f06ca4afSHartmut Brandt 	if (ASN_ERR_STOPPED(err))
252f06ca4afSHartmut Brandt 		return (err);
253f06ca4afSHartmut Brandt 
254f06ca4afSHartmut Brandt 	trailer = b->asn_len - len;
255f06ca4afSHartmut Brandt 
256f06ca4afSHartmut Brandt 	v = pdu->bindings;
257f06ca4afSHartmut Brandt 	err = ASN_ERR_OK;
258f06ca4afSHartmut Brandt 	while (b->asn_len != 0) {
259f06ca4afSHartmut Brandt 		if (pdu->nbindings == SNMP_MAX_BINDINGS) {
260f06ca4afSHartmut Brandt 			snmp_error("too many bindings (> %u) in PDU",
261f06ca4afSHartmut Brandt 			    SNMP_MAX_BINDINGS);
262f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
263f06ca4afSHartmut Brandt 		}
264f06ca4afSHartmut Brandt 		err1 = get_var_binding(b, v);
265f06ca4afSHartmut Brandt 		if (ASN_ERR_STOPPED(err1))
266f06ca4afSHartmut Brandt 			return (ASN_ERR_FAILED);
267f06ca4afSHartmut Brandt 		if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
268f06ca4afSHartmut Brandt 			err = err1;
269f06ca4afSHartmut Brandt 			*ip = pdu->nbindings + 1;
270f06ca4afSHartmut Brandt 		}
271f06ca4afSHartmut Brandt 		pdu->nbindings++;
272f06ca4afSHartmut Brandt 		v++;
273f06ca4afSHartmut Brandt 	}
274f06ca4afSHartmut Brandt 
275f06ca4afSHartmut Brandt 	b->asn_len = trailer;
276f06ca4afSHartmut Brandt 
277f06ca4afSHartmut Brandt 	return (err);
278f06ca4afSHartmut Brandt }
279f06ca4afSHartmut Brandt 
280*135f7de5SShteryana Shopova 
281*135f7de5SShteryana Shopova static enum asn_err
282*135f7de5SShteryana Shopova parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
283f06ca4afSHartmut Brandt {
284*135f7de5SShteryana Shopova 	asn_len_t octs_len;
285*135f7de5SShteryana Shopova 	u_char buf[256]; /* XXX: calc max possible size here */
286*135f7de5SShteryana Shopova 	struct asn_buf tb;
287f06ca4afSHartmut Brandt 
288*135f7de5SShteryana Shopova 	memset(buf, 0, 256);
289*135f7de5SShteryana Shopova 	tb.asn_ptr = buf;
290*135f7de5SShteryana Shopova 	tb.asn_len = 256;
291*135f7de5SShteryana Shopova 
292*135f7de5SShteryana Shopova 	if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
293*135f7de5SShteryana Shopova 		snmp_error("cannot parse usm header");
294f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
295f06ca4afSHartmut Brandt 	}
296f06ca4afSHartmut Brandt 
297*135f7de5SShteryana Shopova 	if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
298*135f7de5SShteryana Shopova 		snmp_error("cannot decode usm header");
299f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
300f06ca4afSHartmut Brandt 	}
301f06ca4afSHartmut Brandt 
302*135f7de5SShteryana Shopova 	octs_len = SNMP_ENGINE_ID_SIZ;
303*135f7de5SShteryana Shopova 	if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
304*135f7de5SShteryana Shopova 	    &octs_len) != ASN_ERR_OK) {
305*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg engine id");
306f06ca4afSHartmut Brandt 		return (ASN_ERR_FAILED);
307f06ca4afSHartmut Brandt 	}
308*135f7de5SShteryana Shopova 	pdu->engine.engine_len = octs_len;
309*135f7de5SShteryana Shopova 
310*135f7de5SShteryana Shopova 	if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
311*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg engine boots");
312*135f7de5SShteryana Shopova 		return (ASN_ERR_FAILED);
313*135f7de5SShteryana Shopova 	}
314*135f7de5SShteryana Shopova 
315*135f7de5SShteryana Shopova 	if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
316*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg engine time");
317*135f7de5SShteryana Shopova 		return (ASN_ERR_FAILED);
318*135f7de5SShteryana Shopova 	}
319*135f7de5SShteryana Shopova 
320*135f7de5SShteryana Shopova 	octs_len = SNMP_ADM_STR32_SIZ - 1;
321*135f7de5SShteryana Shopova 	if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
322*135f7de5SShteryana Shopova 	    != ASN_ERR_OK) {
323*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg user name");
324*135f7de5SShteryana Shopova 		return (ASN_ERR_FAILED);
325*135f7de5SShteryana Shopova 	}
326*135f7de5SShteryana Shopova 	pdu->user.sec_name[octs_len] = '\0';
327*135f7de5SShteryana Shopova 
328*135f7de5SShteryana Shopova 	octs_len = sizeof(pdu->msg_digest);
329*135f7de5SShteryana Shopova 	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
330*135f7de5SShteryana Shopova 	    ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
331*135f7de5SShteryana Shopova 	    octs_len != sizeof(pdu->msg_digest))) {
332*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg authentication param");
333*135f7de5SShteryana Shopova 		return (ASN_ERR_FAILED);
334*135f7de5SShteryana Shopova 	}
335*135f7de5SShteryana Shopova 
336*135f7de5SShteryana Shopova 	octs_len = sizeof(pdu->msg_salt);
337*135f7de5SShteryana Shopova 	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
338*135f7de5SShteryana Shopova 	    ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
339*135f7de5SShteryana Shopova 	    octs_len != sizeof(pdu->msg_salt))) {
340*135f7de5SShteryana Shopova 		snmp_error("cannot decode msg authentication param");
341*135f7de5SShteryana Shopova 		return (ASN_ERR_FAILED);
342*135f7de5SShteryana Shopova 	}
343*135f7de5SShteryana Shopova 
344*135f7de5SShteryana Shopova 	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
345*135f7de5SShteryana Shopova 		pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
346*135f7de5SShteryana Shopova 		pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
347*135f7de5SShteryana Shopova 	}
348f06ca4afSHartmut Brandt 
349f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
350f06ca4afSHartmut Brandt }
351f06ca4afSHartmut Brandt 
352*135f7de5SShteryana Shopova static enum snmp_code
353*135f7de5SShteryana Shopova pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
354f06ca4afSHartmut Brandt {
355*135f7de5SShteryana Shopova 	u_char buf[256], *sptr;
356*135f7de5SShteryana Shopova         struct asn_buf tb;
357*135f7de5SShteryana Shopova         size_t auth_off, moved = 0;
358f06ca4afSHartmut Brandt 
359*135f7de5SShteryana Shopova 	auth_off = 0;
360*135f7de5SShteryana Shopova 	memset(buf, 0, 256);
361*135f7de5SShteryana Shopova 	tb.asn_ptr = buf;
362*135f7de5SShteryana Shopova 	tb.asn_len = 256;
363f06ca4afSHartmut Brandt 
364*135f7de5SShteryana Shopova 	if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
365*135f7de5SShteryana Shopova 	    &sptr) != ASN_ERR_OK)
366*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
367f06ca4afSHartmut Brandt 
368*135f7de5SShteryana Shopova 	if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
369*135f7de5SShteryana Shopova 	    pdu->engine.engine_len) != ASN_ERR_OK)
370*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
371f06ca4afSHartmut Brandt 
372*135f7de5SShteryana Shopova 	if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
373*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
374f06ca4afSHartmut Brandt 
375*135f7de5SShteryana Shopova 	if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
376*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
377f06ca4afSHartmut Brandt 
378*135f7de5SShteryana Shopova 	if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
379*135f7de5SShteryana Shopova 	    strlen(pdu->user.sec_name)) != ASN_ERR_OK)
380*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
381*135f7de5SShteryana Shopova 
382*135f7de5SShteryana Shopova 	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
383*135f7de5SShteryana Shopova 		auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
384*135f7de5SShteryana Shopova 		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
385*135f7de5SShteryana Shopova 		    sizeof(pdu->msg_digest)) != ASN_ERR_OK)
386*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
387*135f7de5SShteryana Shopova 	} else {
388*135f7de5SShteryana Shopova 		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
389*135f7de5SShteryana Shopova 		    != ASN_ERR_OK)
390*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
391*135f7de5SShteryana Shopova 	}
392*135f7de5SShteryana Shopova 
393*135f7de5SShteryana Shopova 	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
394*135f7de5SShteryana Shopova 		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
395*135f7de5SShteryana Shopova 		    sizeof(pdu->msg_salt)) != ASN_ERR_OK)
396*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
397*135f7de5SShteryana Shopova 	} else {
398*135f7de5SShteryana Shopova 		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
399*135f7de5SShteryana Shopova 		    != ASN_ERR_OK)
400*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
401*135f7de5SShteryana Shopova 	}
402*135f7de5SShteryana Shopova 
403*135f7de5SShteryana Shopova 	if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
404*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
405*135f7de5SShteryana Shopova 
406*135f7de5SShteryana Shopova 	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
407*135f7de5SShteryana Shopova 		pdu->digest_ptr = b->asn_ptr + auth_off - moved;
408*135f7de5SShteryana Shopova 
409*135f7de5SShteryana Shopova 	if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
410*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
411*135f7de5SShteryana Shopova 	pdu->digest_ptr += ASN_MAXLENLEN;
412*135f7de5SShteryana Shopova 
413*135f7de5SShteryana Shopova 	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
414*135f7de5SShteryana Shopova 	    ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
415*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
416*135f7de5SShteryana Shopova 
417*135f7de5SShteryana Shopova 	return (SNMP_CODE_OK);
418f06ca4afSHartmut Brandt }
419f06ca4afSHartmut Brandt 
420f06ca4afSHartmut Brandt /*
421f06ca4afSHartmut Brandt  * Decode the PDU except for the variable bindings itself.
422f06ca4afSHartmut Brandt  * If decoding fails because of a bad binding, but the rest can be
423f06ca4afSHartmut Brandt  * decoded, ip points to the index of the failed variable (errors
424f06ca4afSHartmut Brandt  * OORANGE, BADLEN or BADVERS).
425f06ca4afSHartmut Brandt  */
426f06ca4afSHartmut Brandt enum snmp_code
427f06ca4afSHartmut Brandt snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
428f06ca4afSHartmut Brandt {
429*135f7de5SShteryana Shopova 	enum snmp_code code;
430*135f7de5SShteryana Shopova 
431*135f7de5SShteryana Shopova 	if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
432*135f7de5SShteryana Shopova 		return (code);
433*135f7de5SShteryana Shopova 
434*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
435*135f7de5SShteryana Shopova 		if (pdu->security_model != SNMP_SECMODEL_USM)
436*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
437*135f7de5SShteryana Shopova 		if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
438*135f7de5SShteryana Shopova 			return (code);
439*135f7de5SShteryana Shopova 	}
440*135f7de5SShteryana Shopova 
441*135f7de5SShteryana Shopova 	code = snmp_pdu_decode_scoped(b, pdu, ip);
442*135f7de5SShteryana Shopova 
443*135f7de5SShteryana Shopova 	switch (code) {
444*135f7de5SShteryana Shopova 	  case SNMP_CODE_FAILED:
445*135f7de5SShteryana Shopova 		snmp_pdu_free(pdu);
446*135f7de5SShteryana Shopova 		break;
447*135f7de5SShteryana Shopova 
448*135f7de5SShteryana Shopova 	  case SNMP_CODE_BADENC:
449*135f7de5SShteryana Shopova 		if (pdu->version == SNMP_Verr)
450*135f7de5SShteryana Shopova 			return (SNMP_CODE_BADVERS);
451*135f7de5SShteryana Shopova 
452*135f7de5SShteryana Shopova 	  default:
453*135f7de5SShteryana Shopova 		break;
454*135f7de5SShteryana Shopova 	}
455*135f7de5SShteryana Shopova 
456*135f7de5SShteryana Shopova 	return (code);
457*135f7de5SShteryana Shopova }
458*135f7de5SShteryana Shopova 
459*135f7de5SShteryana Shopova enum snmp_code
460*135f7de5SShteryana Shopova snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
461*135f7de5SShteryana Shopova {
462*135f7de5SShteryana Shopova 	int32_t version;
463*135f7de5SShteryana Shopova 	u_int octs_len;
464f06ca4afSHartmut Brandt 	asn_len_t len;
465f06ca4afSHartmut Brandt 
466*135f7de5SShteryana Shopova 	pdu->outer_ptr = b->asn_ptr;
467*135f7de5SShteryana Shopova 	pdu->outer_len = b->asn_len;
468f06ca4afSHartmut Brandt 
469f06ca4afSHartmut Brandt 	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
470f06ca4afSHartmut Brandt 		snmp_error("cannot decode pdu header");
471f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
472f06ca4afSHartmut Brandt 	}
473f06ca4afSHartmut Brandt 	if (b->asn_len < len) {
474f06ca4afSHartmut Brandt 		snmp_error("outer sequence value too short");
475f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
476f06ca4afSHartmut Brandt 	}
477f06ca4afSHartmut Brandt 	if (b->asn_len != len) {
478f06ca4afSHartmut Brandt 		snmp_error("ignoring trailing junk in message");
479f06ca4afSHartmut Brandt 		b->asn_len = len;
480f06ca4afSHartmut Brandt 	}
481f06ca4afSHartmut Brandt 
482*135f7de5SShteryana Shopova 	if (asn_get_integer(b, &version) != ASN_ERR_OK) {
483*135f7de5SShteryana Shopova 		snmp_error("cannot decode version");
484f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
485*135f7de5SShteryana Shopova 	}
486f06ca4afSHartmut Brandt 
487*135f7de5SShteryana Shopova 	if (version == 0)
488*135f7de5SShteryana Shopova 		pdu->version = SNMP_V1;
489*135f7de5SShteryana Shopova 	else if (version == 1)
490*135f7de5SShteryana Shopova 		pdu->version = SNMP_V2c;
491*135f7de5SShteryana Shopova 	else if (version == 3)
492*135f7de5SShteryana Shopova 		pdu->version = SNMP_V3;
493*135f7de5SShteryana Shopova 	else {
494*135f7de5SShteryana Shopova 		pdu->version = SNMP_Verr;
495*135f7de5SShteryana Shopova 		snmp_error("unsupported SNMP version");
496f06ca4afSHartmut Brandt 		return (SNMP_CODE_BADENC);
497f06ca4afSHartmut Brandt 	}
498f06ca4afSHartmut Brandt 
499*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
500*135f7de5SShteryana Shopova 		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
501*135f7de5SShteryana Shopova 			snmp_error("cannot decode pdu global data header");
502*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
503*135f7de5SShteryana Shopova 		}
504*135f7de5SShteryana Shopova 
505*135f7de5SShteryana Shopova 		if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
506*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg indetifier");
507*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
508*135f7de5SShteryana Shopova 		}
509*135f7de5SShteryana Shopova 
510*135f7de5SShteryana Shopova 		if (asn_get_integer(b, &pdu->engine.max_msg_size)
511*135f7de5SShteryana Shopova 		    != ASN_ERR_OK) {
512*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg size");
513*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
514*135f7de5SShteryana Shopova 		}
515*135f7de5SShteryana Shopova 
516*135f7de5SShteryana Shopova 		octs_len = 1;
517*135f7de5SShteryana Shopova 		if (asn_get_octetstring(b, (u_char *)&pdu->flags,
518*135f7de5SShteryana Shopova 		    &octs_len) != ASN_ERR_OK) {
519*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg flags");
520*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
521*135f7de5SShteryana Shopova 		}
522*135f7de5SShteryana Shopova 
523*135f7de5SShteryana Shopova 		if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
524*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg size");
525*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
526*135f7de5SShteryana Shopova 		}
527*135f7de5SShteryana Shopova 
528*135f7de5SShteryana Shopova 		if (pdu->security_model != SNMP_SECMODEL_USM)
529*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
530*135f7de5SShteryana Shopova 
531*135f7de5SShteryana Shopova 		if (parse_secparams(b, pdu) != ASN_ERR_OK)
532*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
533*135f7de5SShteryana Shopova 	} else {
534*135f7de5SShteryana Shopova 		octs_len = SNMP_COMMUNITY_MAXLEN;
535*135f7de5SShteryana Shopova 		if (asn_get_octetstring(b, (u_char *)pdu->community,
536*135f7de5SShteryana Shopova 		    &octs_len) != ASN_ERR_OK) {
537*135f7de5SShteryana Shopova 			snmp_error("cannot decode community");
538*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
539*135f7de5SShteryana Shopova 		}
540*135f7de5SShteryana Shopova 		pdu->community[octs_len] = '\0';
541*135f7de5SShteryana Shopova 	}
542*135f7de5SShteryana Shopova 
543f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
544f06ca4afSHartmut Brandt }
545f06ca4afSHartmut Brandt 
546*135f7de5SShteryana Shopova enum snmp_code
547*135f7de5SShteryana Shopova snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
548*135f7de5SShteryana Shopova {
549*135f7de5SShteryana Shopova 	u_char type;
550*135f7de5SShteryana Shopova 	asn_len_t len, trailer;
551*135f7de5SShteryana Shopova 	enum asn_err err;
552*135f7de5SShteryana Shopova 
553*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
554*135f7de5SShteryana Shopova 		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
555*135f7de5SShteryana Shopova 			snmp_error("cannot decode scoped pdu header");
556*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
557*135f7de5SShteryana Shopova 		}
558*135f7de5SShteryana Shopova 
559*135f7de5SShteryana Shopova 		len = SNMP_ENGINE_ID_SIZ;
560*135f7de5SShteryana Shopova 		if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
561*135f7de5SShteryana Shopova 		    &len) != ASN_ERR_OK) {
562*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg context engine");
563*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
564*135f7de5SShteryana Shopova 		}
565*135f7de5SShteryana Shopova 		pdu->context_engine_len = len;
566*135f7de5SShteryana Shopova 
567*135f7de5SShteryana Shopova 		len = SNMP_CONTEXT_NAME_SIZ;
568*135f7de5SShteryana Shopova 		if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
569*135f7de5SShteryana Shopova 		    &len) != ASN_ERR_OK) {
570*135f7de5SShteryana Shopova 			snmp_error("cannot decode msg context name");
571*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
572*135f7de5SShteryana Shopova 		}
573*135f7de5SShteryana Shopova 		pdu->context_name[len] = '\0';
574*135f7de5SShteryana Shopova 	}
575*135f7de5SShteryana Shopova 
576*135f7de5SShteryana Shopova 	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
577*135f7de5SShteryana Shopova 		snmp_error("cannot get pdu header");
578*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
579*135f7de5SShteryana Shopova 	}
580*135f7de5SShteryana Shopova 	if ((type & ~ASN_TYPE_MASK) !=
581*135f7de5SShteryana Shopova 	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
582*135f7de5SShteryana Shopova 		snmp_error("bad pdu header tag");
583*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
584*135f7de5SShteryana Shopova 	}
585*135f7de5SShteryana Shopova 	pdu->type = type & ASN_TYPE_MASK;
586*135f7de5SShteryana Shopova 
587*135f7de5SShteryana Shopova 	switch (pdu->type) {
588*135f7de5SShteryana Shopova 
589*135f7de5SShteryana Shopova 	  case SNMP_PDU_GET:
590*135f7de5SShteryana Shopova 	  case SNMP_PDU_GETNEXT:
591*135f7de5SShteryana Shopova 	  case SNMP_PDU_RESPONSE:
592*135f7de5SShteryana Shopova 	  case SNMP_PDU_SET:
593*135f7de5SShteryana Shopova 		break;
594*135f7de5SShteryana Shopova 
595*135f7de5SShteryana Shopova 	  case SNMP_PDU_TRAP:
596*135f7de5SShteryana Shopova 		if (pdu->version != SNMP_V1) {
597*135f7de5SShteryana Shopova 			snmp_error("bad pdu type %u", pdu->type);
598*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
599*135f7de5SShteryana Shopova 		}
600*135f7de5SShteryana Shopova 		break;
601*135f7de5SShteryana Shopova 
602*135f7de5SShteryana Shopova 	  case SNMP_PDU_GETBULK:
603*135f7de5SShteryana Shopova 	  case SNMP_PDU_INFORM:
604*135f7de5SShteryana Shopova 	  case SNMP_PDU_TRAP2:
605*135f7de5SShteryana Shopova 	  case SNMP_PDU_REPORT:
606*135f7de5SShteryana Shopova 		if (pdu->version == SNMP_V1) {
607*135f7de5SShteryana Shopova 			snmp_error("bad pdu type %u", pdu->type);
608*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
609*135f7de5SShteryana Shopova 		}
610*135f7de5SShteryana Shopova 		break;
611*135f7de5SShteryana Shopova 
612*135f7de5SShteryana Shopova 	  default:
613*135f7de5SShteryana Shopova 		snmp_error("bad pdu type %u", pdu->type);
614*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
615*135f7de5SShteryana Shopova 	}
616*135f7de5SShteryana Shopova 
617*135f7de5SShteryana Shopova 	trailer = b->asn_len - len;
618*135f7de5SShteryana Shopova 	b->asn_len = len;
619*135f7de5SShteryana Shopova 
620*135f7de5SShteryana Shopova 	err = parse_pdus(b, pdu, ip);
621*135f7de5SShteryana Shopova 	if (ASN_ERR_STOPPED(err))
622*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
623*135f7de5SShteryana Shopova 
624*135f7de5SShteryana Shopova 	if (b->asn_len != 0)
625*135f7de5SShteryana Shopova 		snmp_error("ignoring trailing junk after pdu");
626*135f7de5SShteryana Shopova 
627*135f7de5SShteryana Shopova 	b->asn_len = trailer;
628*135f7de5SShteryana Shopova 
629*135f7de5SShteryana Shopova 	return (SNMP_CODE_OK);
630*135f7de5SShteryana Shopova }
631*135f7de5SShteryana Shopova 
632*135f7de5SShteryana Shopova enum snmp_code
633*135f7de5SShteryana Shopova snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
634*135f7de5SShteryana Shopova {
635*135f7de5SShteryana Shopova 	u_char type;
636*135f7de5SShteryana Shopova 	enum snmp_code code;
637*135f7de5SShteryana Shopova 	uint8_t	digest[SNMP_USM_AUTH_SIZE];
638*135f7de5SShteryana Shopova 
639*135f7de5SShteryana Shopova 	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
640*135f7de5SShteryana Shopova 	    (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
641*135f7de5SShteryana Shopova 		return (SNMP_CODE_BADSECLEVEL);
642*135f7de5SShteryana Shopova 
643*135f7de5SShteryana Shopova 	if ((code = snmp_pdu_calc_digest(b, pdu, digest)) !=
644*135f7de5SShteryana Shopova 	    SNMP_CODE_OK)
645*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
646*135f7de5SShteryana Shopova 
647*135f7de5SShteryana Shopova 	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
648*135f7de5SShteryana Shopova 	    memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
649*135f7de5SShteryana Shopova 		return (SNMP_CODE_BADDIGEST);
650*135f7de5SShteryana Shopova 
651*135f7de5SShteryana Shopova 	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
652*135f7de5SShteryana Shopova 	    &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
653*135f7de5SShteryana Shopova 		snmp_error("cannot decode encrypted pdu");
654*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
655*135f7de5SShteryana Shopova 	}
656*135f7de5SShteryana Shopova 	pdu->scoped_ptr = b->asn_ptr;
657*135f7de5SShteryana Shopova 
658*135f7de5SShteryana Shopova 	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
659*135f7de5SShteryana Shopova 	    (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
660*135f7de5SShteryana Shopova 		return (SNMP_CODE_BADSECLEVEL);
661*135f7de5SShteryana Shopova 
662*135f7de5SShteryana Shopova 	if ((code = snmp_pdu_decrypt(b, pdu)) != SNMP_CODE_OK)
663*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
664*135f7de5SShteryana Shopova 
665*135f7de5SShteryana Shopova 	return (code);
666*135f7de5SShteryana Shopova }
667*135f7de5SShteryana Shopova 
668f06ca4afSHartmut Brandt /*
66970af00a1SHartmut Brandt  * Check whether what we have is the complete PDU by snooping at the
67070af00a1SHartmut Brandt  * enclosing structure header. This returns:
67170af00a1SHartmut Brandt  *   -1		if there are ASN.1 errors
67270af00a1SHartmut Brandt  *    0		if we need more data
67370af00a1SHartmut Brandt  *  > 0		the length of this PDU
67470af00a1SHartmut Brandt  */
67570af00a1SHartmut Brandt int
67670af00a1SHartmut Brandt snmp_pdu_snoop(const struct asn_buf *b0)
67770af00a1SHartmut Brandt {
67870af00a1SHartmut Brandt 	u_int length;
67970af00a1SHartmut Brandt 	asn_len_t len;
68070af00a1SHartmut Brandt 	struct asn_buf b = *b0;
68170af00a1SHartmut Brandt 
68270af00a1SHartmut Brandt 	/* <0x10|0x20> <len> <data...> */
68370af00a1SHartmut Brandt 
68470af00a1SHartmut Brandt 	if (b.asn_len == 0)
68570af00a1SHartmut Brandt 		return (0);
68670af00a1SHartmut Brandt 	if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
68770af00a1SHartmut Brandt 		asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
68870af00a1SHartmut Brandt 		return (-1);
68970af00a1SHartmut Brandt 	}
69070af00a1SHartmut Brandt 	b.asn_len--;
69170af00a1SHartmut Brandt 	b.asn_cptr++;
69270af00a1SHartmut Brandt 
69370af00a1SHartmut Brandt 	if (b.asn_len == 0)
69470af00a1SHartmut Brandt 		return (0);
69570af00a1SHartmut Brandt 
69670af00a1SHartmut Brandt 	if (*b.asn_cptr & 0x80) {
69770af00a1SHartmut Brandt 		/* long length */
69870af00a1SHartmut Brandt 		length = *b.asn_cptr++ & 0x7f;
69970af00a1SHartmut Brandt 		b.asn_len--;
70070af00a1SHartmut Brandt 		if (length == 0) {
70170af00a1SHartmut Brandt 			asn_error(&b, "indefinite length not supported");
70270af00a1SHartmut Brandt 			return (-1);
70370af00a1SHartmut Brandt 		}
70470af00a1SHartmut Brandt 		if (length > ASN_MAXLENLEN) {
70570af00a1SHartmut Brandt 			asn_error(&b, "long length too long (%u)", length);
70670af00a1SHartmut Brandt 			return (-1);
70770af00a1SHartmut Brandt 		}
70870af00a1SHartmut Brandt 		if (length > b.asn_len)
70970af00a1SHartmut Brandt 			return (0);
71070af00a1SHartmut Brandt 		len = 0;
71170af00a1SHartmut Brandt 		while (length--) {
71270af00a1SHartmut Brandt 			len = (len << 8) | *b.asn_cptr++;
71370af00a1SHartmut Brandt 			b.asn_len--;
71470af00a1SHartmut Brandt 		}
71570af00a1SHartmut Brandt 	} else {
71670af00a1SHartmut Brandt 		len = *b.asn_cptr++;
71770af00a1SHartmut Brandt 		b.asn_len--;
71870af00a1SHartmut Brandt 	}
71970af00a1SHartmut Brandt 
72070af00a1SHartmut Brandt 	if (len > b.asn_len)
72170af00a1SHartmut Brandt 		return (0);
72270af00a1SHartmut Brandt 
72370af00a1SHartmut Brandt 	return (len + b.asn_cptr - b0->asn_cptr);
72470af00a1SHartmut Brandt }
72570af00a1SHartmut Brandt 
72670af00a1SHartmut Brandt /*
727f06ca4afSHartmut Brandt  * Encode the SNMP PDU without the variable bindings field.
728f06ca4afSHartmut Brandt  * We do this the rather uneffective way by
729f06ca4afSHartmut Brandt  * moving things around and assuming that the length field will never
730f06ca4afSHartmut Brandt  * use more than 2 bytes.
731f06ca4afSHartmut Brandt  * We need a number of pointers to apply the fixes afterwards.
732f06ca4afSHartmut Brandt  */
733f06ca4afSHartmut Brandt enum snmp_code
734f06ca4afSHartmut Brandt snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
735f06ca4afSHartmut Brandt {
736f06ca4afSHartmut Brandt 	enum asn_err err;
737*135f7de5SShteryana Shopova 	u_char *v3_hdr_ptr;
738f06ca4afSHartmut Brandt 
739f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
740f06ca4afSHartmut Brandt 	    &pdu->outer_ptr) != ASN_ERR_OK)
741f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
742f06ca4afSHartmut Brandt 
743f06ca4afSHartmut Brandt 	if (pdu->version == SNMP_V1)
744f06ca4afSHartmut Brandt 		err = asn_put_integer(b, 0);
745f06ca4afSHartmut Brandt 	else if (pdu->version == SNMP_V2c)
746f06ca4afSHartmut Brandt 		err = asn_put_integer(b, 1);
747*135f7de5SShteryana Shopova 	else if (pdu->version == SNMP_V3)
748*135f7de5SShteryana Shopova 		err = asn_put_integer(b, 3);
749f06ca4afSHartmut Brandt 	else
750f06ca4afSHartmut Brandt 		return (SNMP_CODE_BADVERS);
751f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK)
752f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
753f06ca4afSHartmut Brandt 
754*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
755*135f7de5SShteryana Shopova 		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
756*135f7de5SShteryana Shopova 		    ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
757*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
758*135f7de5SShteryana Shopova 
759*135f7de5SShteryana Shopova 		if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
760*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
761*135f7de5SShteryana Shopova 
762*135f7de5SShteryana Shopova 		if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
763*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
764*135f7de5SShteryana Shopova 
765*135f7de5SShteryana Shopova 		if (pdu->type != SNMP_PDU_RESPONSE &&
766*135f7de5SShteryana Shopova 		    pdu->type != SNMP_PDU_TRAP &&
767*135f7de5SShteryana Shopova 		    pdu->type != SNMP_PDU_REPORT)
768*135f7de5SShteryana Shopova 			pdu->flags |= SNMP_MSG_REPORT_FLAG;
769*135f7de5SShteryana Shopova 
770*135f7de5SShteryana Shopova 		if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
771*135f7de5SShteryana Shopova 		    != ASN_ERR_OK)
772*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
773*135f7de5SShteryana Shopova 
774*135f7de5SShteryana Shopova 		if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
775*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
776*135f7de5SShteryana Shopova 
777*135f7de5SShteryana Shopova 		if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
778*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
779*135f7de5SShteryana Shopova 
780*135f7de5SShteryana Shopova 		if (pdu->security_model != SNMP_SECMODEL_USM)
781*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
782*135f7de5SShteryana Shopova 
783*135f7de5SShteryana Shopova 		if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
784*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
785*135f7de5SShteryana Shopova 
786*135f7de5SShteryana Shopova 		/*  View-based Access Conntrol information */
787*135f7de5SShteryana Shopova 		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
788*135f7de5SShteryana Shopova 		    ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
789*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
790*135f7de5SShteryana Shopova 
791*135f7de5SShteryana Shopova 		if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
792*135f7de5SShteryana Shopova 		    pdu->context_engine_len) != ASN_ERR_OK)
793*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
794*135f7de5SShteryana Shopova 
795*135f7de5SShteryana Shopova 		if (asn_put_octetstring(b, (u_char *)pdu->context_name,
796*135f7de5SShteryana Shopova 		    strlen(pdu->context_name)) != ASN_ERR_OK)
797*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
798*135f7de5SShteryana Shopova 	} else {
799f06ca4afSHartmut Brandt 		if (asn_put_octetstring(b, (u_char *)pdu->community,
800f06ca4afSHartmut Brandt 		    strlen(pdu->community)) != ASN_ERR_OK)
801f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
802*135f7de5SShteryana Shopova 	}
803f06ca4afSHartmut Brandt 
804f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
805f06ca4afSHartmut Brandt 	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
806f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
807f06ca4afSHartmut Brandt 
808f06ca4afSHartmut Brandt 	if (pdu->type == SNMP_PDU_TRAP) {
809f06ca4afSHartmut Brandt 		if (pdu->version != SNMP_V1 ||
810f06ca4afSHartmut Brandt 		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
811f06ca4afSHartmut Brandt 		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
812f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
813f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
814f06ca4afSHartmut Brandt 		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
815f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
816f06ca4afSHartmut Brandt 	} else {
817f06ca4afSHartmut Brandt 		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
818f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_INFORM ||
819f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_TRAP2 ||
820f06ca4afSHartmut Brandt 		    pdu->type == SNMP_PDU_REPORT))
821f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
822f06ca4afSHartmut Brandt 
823f06ca4afSHartmut Brandt 		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
824f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
825f06ca4afSHartmut Brandt 		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
826f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
827f06ca4afSHartmut Brandt 	}
828f06ca4afSHartmut Brandt 
829f06ca4afSHartmut Brandt 	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
830f06ca4afSHartmut Brandt 	    &pdu->vars_ptr) != ASN_ERR_OK)
831f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
832f06ca4afSHartmut Brandt 
833f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
834f06ca4afSHartmut Brandt }
835f06ca4afSHartmut Brandt 
836*135f7de5SShteryana Shopova static enum asn_err
837*135f7de5SShteryana Shopova snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
838f06ca4afSHartmut Brandt {
839*135f7de5SShteryana Shopova 	asn_len_t padlen;
840*135f7de5SShteryana Shopova 
841*135f7de5SShteryana Shopova 	if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
842*135f7de5SShteryana Shopova 		padlen = 8 - (pdu->scoped_len % 8);
843*135f7de5SShteryana Shopova 		if (asn_pad(b, padlen) != ASN_ERR_OK)
844*135f7de5SShteryana Shopova 			return (ASN_ERR_FAILED);
845*135f7de5SShteryana Shopova 		pdu->scoped_len += padlen;
846*135f7de5SShteryana Shopova 	}
847*135f7de5SShteryana Shopova 
848*135f7de5SShteryana Shopova 	return (ASN_ERR_OK);
849*135f7de5SShteryana Shopova }
850*135f7de5SShteryana Shopova 
851*135f7de5SShteryana Shopova enum snmp_code
852*135f7de5SShteryana Shopova snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
853*135f7de5SShteryana Shopova {
854*135f7de5SShteryana Shopova 	size_t moved = 0;
855*135f7de5SShteryana Shopova 	enum snmp_code code;
856*135f7de5SShteryana Shopova 
857*135f7de5SShteryana Shopova 	if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
858*135f7de5SShteryana Shopova 	    asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
859f06ca4afSHartmut Brandt 		return (SNMP_CODE_FAILED);
860*135f7de5SShteryana Shopova 
861*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
862*135f7de5SShteryana Shopova 		if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
863*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
864*135f7de5SShteryana Shopova 
865*135f7de5SShteryana Shopova 		pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
866*135f7de5SShteryana Shopova 		if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
867*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
868*135f7de5SShteryana Shopova 
869*135f7de5SShteryana Shopova 		if (pdu->security_model != SNMP_SECMODEL_USM)
870*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
871*135f7de5SShteryana Shopova 
872*135f7de5SShteryana Shopova 		if (snmp_pdu_encrypt(b, pdu) != SNMP_CODE_OK)
873*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
874*135f7de5SShteryana Shopova 
875*135f7de5SShteryana Shopova 		if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
876*135f7de5SShteryana Shopova 		    asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
877*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
878*135f7de5SShteryana Shopova 	}
879*135f7de5SShteryana Shopova 
880*135f7de5SShteryana Shopova 	if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
881*135f7de5SShteryana Shopova 		return (SNMP_CODE_FAILED);
882*135f7de5SShteryana Shopova 
883*135f7de5SShteryana Shopova 	pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
884*135f7de5SShteryana Shopova 	pdu->digest_ptr -= moved;
885*135f7de5SShteryana Shopova 
886*135f7de5SShteryana Shopova 	if (pdu->version == SNMP_V3) {
887*135f7de5SShteryana Shopova 		if ((code = snmp_pdu_calc_digest(b, pdu, pdu->msg_digest)) !=
888*135f7de5SShteryana Shopova 		    SNMP_CODE_OK)
889*135f7de5SShteryana Shopova 			return (SNMP_CODE_FAILED);
890*135f7de5SShteryana Shopova 
891*135f7de5SShteryana Shopova 		if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
892*135f7de5SShteryana Shopova 			memcpy(pdu->digest_ptr, pdu->msg_digest,
893*135f7de5SShteryana Shopova 			    sizeof(pdu->msg_digest));
894*135f7de5SShteryana Shopova 	}
895*135f7de5SShteryana Shopova 
896f06ca4afSHartmut Brandt 	return (SNMP_CODE_OK);
897f06ca4afSHartmut Brandt }
898f06ca4afSHartmut Brandt 
899f06ca4afSHartmut Brandt /*
900f06ca4afSHartmut Brandt  * Encode a binding. Caller must ensure, that the syntax is ok for that version.
901f06ca4afSHartmut Brandt  * Be sure not to cobber b, when something fails.
902f06ca4afSHartmut Brandt  */
903f06ca4afSHartmut Brandt enum asn_err
904f06ca4afSHartmut Brandt snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
905f06ca4afSHartmut Brandt {
906f06ca4afSHartmut Brandt 	u_char *ptr;
907f06ca4afSHartmut Brandt 	enum asn_err err;
908f06ca4afSHartmut Brandt 	struct asn_buf save = *b;
909f06ca4afSHartmut Brandt 
910f06ca4afSHartmut Brandt 	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
911f06ca4afSHartmut Brandt 	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
912f06ca4afSHartmut Brandt 		*b = save;
913f06ca4afSHartmut Brandt 		return (err);
914f06ca4afSHartmut Brandt 	}
915f06ca4afSHartmut Brandt 
916f06ca4afSHartmut Brandt 	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
917f06ca4afSHartmut Brandt 		*b = save;
918f06ca4afSHartmut Brandt 		return (err);
919f06ca4afSHartmut Brandt 	}
920f06ca4afSHartmut Brandt 
921f06ca4afSHartmut Brandt 	switch (binding->syntax) {
922f06ca4afSHartmut Brandt 
923f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
924f06ca4afSHartmut Brandt 		err = asn_put_null(b);
925f06ca4afSHartmut Brandt 		break;
926f06ca4afSHartmut Brandt 
927f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
928f06ca4afSHartmut Brandt 		err = asn_put_integer(b, binding->v.integer);
929f06ca4afSHartmut Brandt 		break;
930f06ca4afSHartmut Brandt 
931f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
932f06ca4afSHartmut Brandt 		err = asn_put_octetstring(b, binding->v.octetstring.octets,
933f06ca4afSHartmut Brandt 		    binding->v.octetstring.len);
934f06ca4afSHartmut Brandt 		break;
935f06ca4afSHartmut Brandt 
936f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
937f06ca4afSHartmut Brandt 		err = asn_put_objid(b, &binding->v.oid);
938f06ca4afSHartmut Brandt 		break;
939f06ca4afSHartmut Brandt 
940f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
941f06ca4afSHartmut Brandt 		err = asn_put_ipaddress(b, binding->v.ipaddress);
942f06ca4afSHartmut Brandt 		break;
943f06ca4afSHartmut Brandt 
944f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
945f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
946f06ca4afSHartmut Brandt 		break;
947f06ca4afSHartmut Brandt 
948f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
949f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
950f06ca4afSHartmut Brandt 		break;
951f06ca4afSHartmut Brandt 
952f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
953f06ca4afSHartmut Brandt 		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
954f06ca4afSHartmut Brandt 		break;
955f06ca4afSHartmut Brandt 
956f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
957f06ca4afSHartmut Brandt 		err = asn_put_counter64(b, binding->v.counter64);
958f06ca4afSHartmut Brandt 		break;
959f06ca4afSHartmut Brandt 
960f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
961f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
962f06ca4afSHartmut Brandt 		break;
963f06ca4afSHartmut Brandt 
964f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
965f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
966f06ca4afSHartmut Brandt 		break;
967f06ca4afSHartmut Brandt 
968f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
969f06ca4afSHartmut Brandt 		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
970f06ca4afSHartmut Brandt 		break;
971f06ca4afSHartmut Brandt 	}
972f06ca4afSHartmut Brandt 
973f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK) {
974f06ca4afSHartmut Brandt 		*b = save;
975f06ca4afSHartmut Brandt 		return (err);
976f06ca4afSHartmut Brandt 	}
977f06ca4afSHartmut Brandt 
978*135f7de5SShteryana Shopova 	err = asn_commit_header(b, ptr, NULL);
979f06ca4afSHartmut Brandt 	if (err != ASN_ERR_OK) {
980f06ca4afSHartmut Brandt 		*b = save;
981f06ca4afSHartmut Brandt 		return (err);
982f06ca4afSHartmut Brandt 	}
983f06ca4afSHartmut Brandt 
984f06ca4afSHartmut Brandt 	return (ASN_ERR_OK);
985f06ca4afSHartmut Brandt }
986f06ca4afSHartmut Brandt 
987f06ca4afSHartmut Brandt /*
988f06ca4afSHartmut Brandt  * Encode an PDU.
989f06ca4afSHartmut Brandt  */
990f06ca4afSHartmut Brandt enum snmp_code
991f06ca4afSHartmut Brandt snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
992f06ca4afSHartmut Brandt {
993f06ca4afSHartmut Brandt 	u_int idx;
994f06ca4afSHartmut Brandt 	enum snmp_code err;
995f06ca4afSHartmut Brandt 
996f06ca4afSHartmut Brandt 	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
997f06ca4afSHartmut Brandt 		return (err);
998f06ca4afSHartmut Brandt 	for (idx = 0; idx < pdu->nbindings; idx++)
999f06ca4afSHartmut Brandt 		if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
1000f06ca4afSHartmut Brandt 		    != ASN_ERR_OK)
1001f06ca4afSHartmut Brandt 			return (SNMP_CODE_FAILED);
1002f06ca4afSHartmut Brandt 
1003f06ca4afSHartmut Brandt 	return (snmp_fix_encoding(resp_b, pdu));
1004f06ca4afSHartmut Brandt }
1005f06ca4afSHartmut Brandt 
1006f06ca4afSHartmut Brandt static void
1007f06ca4afSHartmut Brandt dump_binding(const struct snmp_value *b)
1008f06ca4afSHartmut Brandt {
1009f06ca4afSHartmut Brandt 	u_int i;
1010f06ca4afSHartmut Brandt 	char buf[ASN_OIDSTRLEN];
1011f06ca4afSHartmut Brandt 
1012f06ca4afSHartmut Brandt 	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1013f06ca4afSHartmut Brandt 	switch (b->syntax) {
1014f06ca4afSHartmut Brandt 
1015f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
1016f06ca4afSHartmut Brandt 		snmp_printf("NULL");
1017f06ca4afSHartmut Brandt 		break;
1018f06ca4afSHartmut Brandt 
1019f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
1020f06ca4afSHartmut Brandt 		snmp_printf("INTEGER %d", b->v.integer);
1021f06ca4afSHartmut Brandt 		break;
1022f06ca4afSHartmut Brandt 
1023f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
1024f06ca4afSHartmut Brandt 		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1025f06ca4afSHartmut Brandt 		for (i = 0; i < b->v.octetstring.len; i++)
1026f06ca4afSHartmut Brandt 			snmp_printf(" %02x", b->v.octetstring.octets[i]);
1027f06ca4afSHartmut Brandt 		break;
1028f06ca4afSHartmut Brandt 
1029f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
1030f06ca4afSHartmut Brandt 		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1031f06ca4afSHartmut Brandt 		break;
1032f06ca4afSHartmut Brandt 
1033f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
1034f06ca4afSHartmut Brandt 		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1035f06ca4afSHartmut Brandt 		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1036f06ca4afSHartmut Brandt 		break;
1037f06ca4afSHartmut Brandt 
1038f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
1039f06ca4afSHartmut Brandt 		snmp_printf("COUNTER %u", b->v.uint32);
1040f06ca4afSHartmut Brandt 		break;
1041f06ca4afSHartmut Brandt 
1042f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
1043f06ca4afSHartmut Brandt 		snmp_printf("GAUGE %u", b->v.uint32);
1044f06ca4afSHartmut Brandt 		break;
1045f06ca4afSHartmut Brandt 
1046f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
1047f06ca4afSHartmut Brandt 		snmp_printf("TIMETICKS %u", b->v.uint32);
1048f06ca4afSHartmut Brandt 		break;
1049f06ca4afSHartmut Brandt 
1050f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
1051f06ca4afSHartmut Brandt 		snmp_printf("COUNTER64 %lld", b->v.counter64);
1052f06ca4afSHartmut Brandt 		break;
1053f06ca4afSHartmut Brandt 
1054f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
1055f06ca4afSHartmut Brandt 		snmp_printf("NoSuchObject");
1056f06ca4afSHartmut Brandt 		break;
1057f06ca4afSHartmut Brandt 
1058f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1059f06ca4afSHartmut Brandt 		snmp_printf("NoSuchInstance");
1060f06ca4afSHartmut Brandt 		break;
1061f06ca4afSHartmut Brandt 
1062f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1063f06ca4afSHartmut Brandt 		snmp_printf("EndOfMibView");
1064f06ca4afSHartmut Brandt 		break;
1065f06ca4afSHartmut Brandt 
1066f06ca4afSHartmut Brandt 	  default:
1067f06ca4afSHartmut Brandt 		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1068f06ca4afSHartmut Brandt 		break;
1069f06ca4afSHartmut Brandt 	}
1070f06ca4afSHartmut Brandt }
1071f06ca4afSHartmut Brandt 
1072f06ca4afSHartmut Brandt static __inline void
1073f06ca4afSHartmut Brandt dump_bindings(const struct snmp_pdu *pdu)
1074f06ca4afSHartmut Brandt {
1075f06ca4afSHartmut Brandt 	u_int i;
1076f06ca4afSHartmut Brandt 
1077f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++) {
1078f06ca4afSHartmut Brandt 		snmp_printf(" [%u]: ", i);
1079f06ca4afSHartmut Brandt 		dump_binding(&pdu->bindings[i]);
1080f06ca4afSHartmut Brandt 		snmp_printf("\n");
1081f06ca4afSHartmut Brandt 	}
1082f06ca4afSHartmut Brandt }
1083f06ca4afSHartmut Brandt 
1084f06ca4afSHartmut Brandt static __inline void
1085f06ca4afSHartmut Brandt dump_notrap(const struct snmp_pdu *pdu)
1086f06ca4afSHartmut Brandt {
1087f06ca4afSHartmut Brandt 	snmp_printf(" request_id=%d", pdu->request_id);
1088f06ca4afSHartmut Brandt 	snmp_printf(" error_status=%d", pdu->error_status);
1089f06ca4afSHartmut Brandt 	snmp_printf(" error_index=%d\n", pdu->error_index);
1090f06ca4afSHartmut Brandt 	dump_bindings(pdu);
1091f06ca4afSHartmut Brandt }
1092f06ca4afSHartmut Brandt 
1093f06ca4afSHartmut Brandt void
1094f06ca4afSHartmut Brandt snmp_pdu_dump(const struct snmp_pdu *pdu)
1095f06ca4afSHartmut Brandt {
1096f06ca4afSHartmut Brandt 	char buf[ASN_OIDSTRLEN];
1097f06ca4afSHartmut Brandt 	const char *vers;
1098f06ca4afSHartmut Brandt 	static const char *types[] = {
1099f06ca4afSHartmut Brandt 		[SNMP_PDU_GET] =	"GET",
1100f06ca4afSHartmut Brandt 		[SNMP_PDU_GETNEXT] =	"GETNEXT",
1101f06ca4afSHartmut Brandt 		[SNMP_PDU_RESPONSE] =	"RESPONSE",
1102f06ca4afSHartmut Brandt 		[SNMP_PDU_SET] =	"SET",
1103f06ca4afSHartmut Brandt 		[SNMP_PDU_TRAP] =	"TRAPv1",
1104f06ca4afSHartmut Brandt 		[SNMP_PDU_GETBULK] =	"GETBULK",
1105f06ca4afSHartmut Brandt 		[SNMP_PDU_INFORM] =	"INFORM",
1106f06ca4afSHartmut Brandt 		[SNMP_PDU_TRAP2] =	"TRAPv2",
1107f06ca4afSHartmut Brandt 		[SNMP_PDU_REPORT] =	"REPORT",
1108f06ca4afSHartmut Brandt 	};
1109f06ca4afSHartmut Brandt 
1110f06ca4afSHartmut Brandt 	if (pdu->version == SNMP_V1)
1111f06ca4afSHartmut Brandt 		vers = "SNMPv1";
1112f06ca4afSHartmut Brandt 	else if (pdu->version == SNMP_V2c)
1113f06ca4afSHartmut Brandt 		vers = "SNMPv2c";
1114*135f7de5SShteryana Shopova 	else if (pdu->version == SNMP_V3)
1115*135f7de5SShteryana Shopova 		vers = "SNMPv3";
1116f06ca4afSHartmut Brandt 	else
1117f06ca4afSHartmut Brandt 		vers = "v?";
1118f06ca4afSHartmut Brandt 
1119f06ca4afSHartmut Brandt 	switch (pdu->type) {
1120f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP:
1121f06ca4afSHartmut Brandt 		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1122f06ca4afSHartmut Brandt 		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1123f06ca4afSHartmut Brandt 		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1124f06ca4afSHartmut Brandt 		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1125f06ca4afSHartmut Brandt 		snmp_printf(" generic_trap=%d", pdu->generic_trap);
1126f06ca4afSHartmut Brandt 		snmp_printf(" specific_trap=%d", pdu->specific_trap);
1127f06ca4afSHartmut Brandt 		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1128f06ca4afSHartmut Brandt 		dump_bindings(pdu);
1129f06ca4afSHartmut Brandt 		break;
1130f06ca4afSHartmut Brandt 
1131f06ca4afSHartmut Brandt 	  case SNMP_PDU_GET:
1132f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETNEXT:
1133f06ca4afSHartmut Brandt 	  case SNMP_PDU_RESPONSE:
1134f06ca4afSHartmut Brandt 	  case SNMP_PDU_SET:
1135f06ca4afSHartmut Brandt 	  case SNMP_PDU_GETBULK:
1136f06ca4afSHartmut Brandt 	  case SNMP_PDU_INFORM:
1137f06ca4afSHartmut Brandt 	  case SNMP_PDU_TRAP2:
1138f06ca4afSHartmut Brandt 	  case SNMP_PDU_REPORT:
1139f06ca4afSHartmut Brandt 		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1140f06ca4afSHartmut Brandt 		dump_notrap(pdu);
1141f06ca4afSHartmut Brandt 		break;
1142f06ca4afSHartmut Brandt 
1143f06ca4afSHartmut Brandt 	  default:
1144f06ca4afSHartmut Brandt 		snmp_printf("bad pdu type %u\n", pdu->type);
1145f06ca4afSHartmut Brandt 		break;
1146f06ca4afSHartmut Brandt 	}
1147f06ca4afSHartmut Brandt }
1148f06ca4afSHartmut Brandt 
1149f06ca4afSHartmut Brandt void
1150f06ca4afSHartmut Brandt snmp_value_free(struct snmp_value *value)
1151f06ca4afSHartmut Brandt {
1152f06ca4afSHartmut Brandt 	if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1153f06ca4afSHartmut Brandt 		free(value->v.octetstring.octets);
1154f06ca4afSHartmut Brandt 	value->syntax = SNMP_SYNTAX_NULL;
1155f06ca4afSHartmut Brandt }
1156f06ca4afSHartmut Brandt 
1157f06ca4afSHartmut Brandt int
1158f06ca4afSHartmut Brandt snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1159f06ca4afSHartmut Brandt {
1160f06ca4afSHartmut Brandt 	to->var = from->var;
1161f06ca4afSHartmut Brandt 	to->syntax = from->syntax;
1162f06ca4afSHartmut Brandt 
1163f06ca4afSHartmut Brandt 	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1164f06ca4afSHartmut Brandt 		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1165f06ca4afSHartmut Brandt 			to->v.octetstring.octets = NULL;
1166f06ca4afSHartmut Brandt 		else {
1167f06ca4afSHartmut Brandt 			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1168f06ca4afSHartmut Brandt 			if (to->v.octetstring.octets == NULL)
1169f06ca4afSHartmut Brandt 				return (-1);
1170f06ca4afSHartmut Brandt 			(void)memcpy(to->v.octetstring.octets,
1171f06ca4afSHartmut Brandt 			    from->v.octetstring.octets, to->v.octetstring.len);
1172f06ca4afSHartmut Brandt 		}
1173f06ca4afSHartmut Brandt 	} else
1174f06ca4afSHartmut Brandt 		to->v = from->v;
1175f06ca4afSHartmut Brandt 	return (0);
1176f06ca4afSHartmut Brandt }
1177f06ca4afSHartmut Brandt 
1178f06ca4afSHartmut Brandt void
1179*135f7de5SShteryana Shopova snmp_pdu_init_secparams(struct snmp_pdu *pdu, struct snmp_engine *eng,
1180*135f7de5SShteryana Shopova     struct snmp_user *user)
1181*135f7de5SShteryana Shopova {
1182*135f7de5SShteryana Shopova 	int32_t rval;
1183*135f7de5SShteryana Shopova 
1184*135f7de5SShteryana Shopova 	memcpy(&pdu->engine, eng, sizeof(pdu->engine));
1185*135f7de5SShteryana Shopova 	memcpy(&pdu->user, user, sizeof(pdu->user));
1186*135f7de5SShteryana Shopova 
1187*135f7de5SShteryana Shopova 	if (user->auth_proto != SNMP_AUTH_NOAUTH)
1188*135f7de5SShteryana Shopova 		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1189*135f7de5SShteryana Shopova 
1190*135f7de5SShteryana Shopova 	switch (user->priv_proto) {
1191*135f7de5SShteryana Shopova 	case SNMP_PRIV_DES:
1192*135f7de5SShteryana Shopova 		memcpy(pdu->msg_salt, &eng->engine_boots,
1193*135f7de5SShteryana Shopova 		    sizeof(eng->engine_boots));
1194*135f7de5SShteryana Shopova 		rval = random();
1195*135f7de5SShteryana Shopova 		memcpy(pdu->msg_salt + sizeof(eng->engine_boots), &rval,
1196*135f7de5SShteryana Shopova 		    sizeof(int32_t));
1197*135f7de5SShteryana Shopova 		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1198*135f7de5SShteryana Shopova 		break;
1199*135f7de5SShteryana Shopova 	case SNMP_PRIV_AES:
1200*135f7de5SShteryana Shopova 		rval = random();
1201*135f7de5SShteryana Shopova 		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1202*135f7de5SShteryana Shopova 		rval = random();
1203*135f7de5SShteryana Shopova 		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1204*135f7de5SShteryana Shopova 		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1205*135f7de5SShteryana Shopova 		break;
1206*135f7de5SShteryana Shopova 	default:
1207*135f7de5SShteryana Shopova 		break;
1208*135f7de5SShteryana Shopova 	}
1209*135f7de5SShteryana Shopova }
1210*135f7de5SShteryana Shopova 
1211*135f7de5SShteryana Shopova void
1212f06ca4afSHartmut Brandt snmp_pdu_free(struct snmp_pdu *pdu)
1213f06ca4afSHartmut Brandt {
1214f06ca4afSHartmut Brandt 	u_int i;
1215f06ca4afSHartmut Brandt 
1216f06ca4afSHartmut Brandt 	for (i = 0; i < pdu->nbindings; i++)
1217f06ca4afSHartmut Brandt 		snmp_value_free(&pdu->bindings[i]);
1218f06ca4afSHartmut Brandt }
1219f06ca4afSHartmut Brandt 
1220f06ca4afSHartmut Brandt /*
1221f06ca4afSHartmut Brandt  * Parse an ASCII SNMP value into the binary form
1222f06ca4afSHartmut Brandt  */
1223f06ca4afSHartmut Brandt int
1224f06ca4afSHartmut Brandt snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1225f06ca4afSHartmut Brandt {
1226f06ca4afSHartmut Brandt 	char *end;
1227f06ca4afSHartmut Brandt 
1228f06ca4afSHartmut Brandt 	switch (syntax) {
1229f06ca4afSHartmut Brandt 
1230f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NULL:
1231f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHOBJECT:
1232f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1233f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1234f06ca4afSHartmut Brandt 		if (*str != '\0')
1235f06ca4afSHartmut Brandt 			return (-1);
1236f06ca4afSHartmut Brandt 		return (0);
1237f06ca4afSHartmut Brandt 
1238f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_INTEGER:
1239f06ca4afSHartmut Brandt 		v->integer = strtoll(str, &end, 0);
1240f06ca4afSHartmut Brandt 		if (*end != '\0')
1241f06ca4afSHartmut Brandt 			return (-1);
1242f06ca4afSHartmut Brandt 		return (0);
1243f06ca4afSHartmut Brandt 
1244f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OCTETSTRING:
1245f06ca4afSHartmut Brandt 	    {
1246f06ca4afSHartmut Brandt 		u_long len;	/* actual length of string */
1247f06ca4afSHartmut Brandt 		u_long alloc;	/* allocate length of string */
1248f06ca4afSHartmut Brandt 		u_char *octs;	/* actual octets */
1249f06ca4afSHartmut Brandt 		u_long oct;	/* actual octet */
1250f06ca4afSHartmut Brandt 		u_char *nocts;	/* to avoid memory leak */
1251f06ca4afSHartmut Brandt 		u_char c;	/* actual character */
1252f06ca4afSHartmut Brandt 
1253f06ca4afSHartmut Brandt # define STUFFC(C)							\
1254f06ca4afSHartmut Brandt 		if (alloc == len) {					\
1255f06ca4afSHartmut Brandt 			alloc += 100;					\
1256f06ca4afSHartmut Brandt 			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1257f06ca4afSHartmut Brandt 				free(octs);				\
1258f06ca4afSHartmut Brandt 				return (-1);				\
1259f06ca4afSHartmut Brandt 			}						\
1260f06ca4afSHartmut Brandt 			octs = nocts;					\
1261f06ca4afSHartmut Brandt 		}							\
1262f06ca4afSHartmut Brandt 		octs[len++] = (C);
1263f06ca4afSHartmut Brandt 
1264f06ca4afSHartmut Brandt 		len = alloc = 0;
1265f06ca4afSHartmut Brandt 		octs = NULL;
1266f06ca4afSHartmut Brandt 
1267f06ca4afSHartmut Brandt 		if (*str == '"') {
1268f06ca4afSHartmut Brandt 			str++;
1269f06ca4afSHartmut Brandt 			while((c = *str++) != '\0') {
1270f06ca4afSHartmut Brandt 				if (c == '"') {
1271f06ca4afSHartmut Brandt 					if (*str != '\0') {
1272f06ca4afSHartmut Brandt 						free(octs);
1273f06ca4afSHartmut Brandt 						return (-1);
1274f06ca4afSHartmut Brandt 					}
1275f06ca4afSHartmut Brandt 					break;
1276f06ca4afSHartmut Brandt 				}
1277f06ca4afSHartmut Brandt 				if (c == '\\') {
1278f06ca4afSHartmut Brandt 					switch (c = *str++) {
1279f06ca4afSHartmut Brandt 
1280f06ca4afSHartmut Brandt 					  case '\\':
1281f06ca4afSHartmut Brandt 						break;
1282f06ca4afSHartmut Brandt 					  case 'a':
1283f06ca4afSHartmut Brandt 						c = '\a';
1284f06ca4afSHartmut Brandt 						break;
1285f06ca4afSHartmut Brandt 					  case 'b':
1286f06ca4afSHartmut Brandt 						c = '\b';
1287f06ca4afSHartmut Brandt 						break;
1288f06ca4afSHartmut Brandt 					  case 'f':
1289f06ca4afSHartmut Brandt 						c = '\f';
1290f06ca4afSHartmut Brandt 						break;
1291f06ca4afSHartmut Brandt 					  case 'n':
1292f06ca4afSHartmut Brandt 						c = '\n';
1293f06ca4afSHartmut Brandt 						break;
1294f06ca4afSHartmut Brandt 					  case 'r':
1295f06ca4afSHartmut Brandt 						c = '\r';
1296f06ca4afSHartmut Brandt 						break;
1297f06ca4afSHartmut Brandt 					  case 't':
1298f06ca4afSHartmut Brandt 						c = '\t';
1299f06ca4afSHartmut Brandt 						break;
1300f06ca4afSHartmut Brandt 					  case 'v':
1301f06ca4afSHartmut Brandt 						c = '\v';
1302f06ca4afSHartmut Brandt 						break;
1303f06ca4afSHartmut Brandt 					  case 'x':
1304f06ca4afSHartmut Brandt 						c = 0;
1305f06ca4afSHartmut Brandt 						if (!isxdigit(*str))
1306f06ca4afSHartmut Brandt 							break;
1307f06ca4afSHartmut Brandt 						if (isdigit(*str))
1308f06ca4afSHartmut Brandt 							c = *str++ - '0';
1309f06ca4afSHartmut Brandt 						else if (isupper(*str))
1310f06ca4afSHartmut Brandt 							c = *str++ - 'A' + 10;
1311f06ca4afSHartmut Brandt 						else
1312f06ca4afSHartmut Brandt 							c = *str++ - 'a' + 10;
1313f06ca4afSHartmut Brandt 						if (!isxdigit(*str))
1314f06ca4afSHartmut Brandt 							break;
1315f06ca4afSHartmut Brandt 						if (isdigit(*str))
1316f06ca4afSHartmut Brandt 							c += *str++ - '0';
1317f06ca4afSHartmut Brandt 						else if (isupper(*str))
1318f06ca4afSHartmut Brandt 							c += *str++ - 'A' + 10;
1319f06ca4afSHartmut Brandt 						else
1320f06ca4afSHartmut Brandt 							c += *str++ - 'a' + 10;
1321f06ca4afSHartmut Brandt 						break;
1322f06ca4afSHartmut Brandt 					  case '0': case '1': case '2':
1323f06ca4afSHartmut Brandt 					  case '3': case '4': case '5':
1324f06ca4afSHartmut Brandt 					  case '6': case '7':
1325f06ca4afSHartmut Brandt 						c = *str++ - '0';
1326f06ca4afSHartmut Brandt 						if (*str < '0' || *str > '7')
1327f06ca4afSHartmut Brandt 							break;
1328f06ca4afSHartmut Brandt 						c = *str++ - '0';
1329f06ca4afSHartmut Brandt 						if (*str < '0' || *str > '7')
1330f06ca4afSHartmut Brandt 							break;
1331f06ca4afSHartmut Brandt 						c = *str++ - '0';
1332f06ca4afSHartmut Brandt 						break;
1333f06ca4afSHartmut Brandt 					  default:
1334f06ca4afSHartmut Brandt 						break;
1335f06ca4afSHartmut Brandt 					}
1336f06ca4afSHartmut Brandt 				}
1337f06ca4afSHartmut Brandt 				STUFFC(c);
1338f06ca4afSHartmut Brandt 			}
1339f06ca4afSHartmut Brandt 		} else {
1340f06ca4afSHartmut Brandt 			while (*str != '\0') {
1341f06ca4afSHartmut Brandt 				oct = strtoul(str, &end, 16);
1342f06ca4afSHartmut Brandt 				str = end;
1343f06ca4afSHartmut Brandt 				if (oct > 0xff) {
1344f06ca4afSHartmut Brandt 					free(octs);
1345f06ca4afSHartmut Brandt 					return (-1);
1346f06ca4afSHartmut Brandt 				}
1347f06ca4afSHartmut Brandt 				STUFFC(oct);
1348f06ca4afSHartmut Brandt 				if (*str == ':')
1349f06ca4afSHartmut Brandt 					str++;
1350f06ca4afSHartmut Brandt 				else if(*str != '\0') {
1351f06ca4afSHartmut Brandt 					free(octs);
1352f06ca4afSHartmut Brandt 					return (-1);
1353f06ca4afSHartmut Brandt 				}
1354f06ca4afSHartmut Brandt 			}
1355f06ca4afSHartmut Brandt 		}
1356f06ca4afSHartmut Brandt 		v->octetstring.octets = octs;
1357f06ca4afSHartmut Brandt 		v->octetstring.len = len;
1358f06ca4afSHartmut Brandt 		return (0);
1359f06ca4afSHartmut Brandt # undef STUFFC
1360f06ca4afSHartmut Brandt 	    }
1361f06ca4afSHartmut Brandt 
1362f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_OID:
1363f06ca4afSHartmut Brandt 	    {
1364f06ca4afSHartmut Brandt 		u_long subid;
1365f06ca4afSHartmut Brandt 
1366f06ca4afSHartmut Brandt 		v->oid.len = 0;
1367f06ca4afSHartmut Brandt 
1368f06ca4afSHartmut Brandt 		for (;;) {
1369f06ca4afSHartmut Brandt 			if (v->oid.len == ASN_MAXOIDLEN)
1370f06ca4afSHartmut Brandt 				return (-1);
1371f06ca4afSHartmut Brandt 			subid = strtoul(str, &end, 10);
1372f06ca4afSHartmut Brandt 			str = end;
1373f06ca4afSHartmut Brandt 			if (subid > ASN_MAXID)
1374f06ca4afSHartmut Brandt 				return (-1);
1375f06ca4afSHartmut Brandt 			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1376f06ca4afSHartmut Brandt 			if (*str == '\0')
1377f06ca4afSHartmut Brandt 				break;
1378f06ca4afSHartmut Brandt 			if (*str != '.')
1379f06ca4afSHartmut Brandt 				return (-1);
1380f06ca4afSHartmut Brandt 			str++;
1381f06ca4afSHartmut Brandt 		}
1382f06ca4afSHartmut Brandt 		return (0);
1383f06ca4afSHartmut Brandt 	    }
1384f06ca4afSHartmut Brandt 
1385f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_IPADDRESS:
1386f06ca4afSHartmut Brandt 	    {
1387f06ca4afSHartmut Brandt 		struct hostent *he;
1388f06ca4afSHartmut Brandt 		u_long ip[4];
1389f06ca4afSHartmut Brandt 		int n;
1390f06ca4afSHartmut Brandt 
1391f06ca4afSHartmut Brandt 		if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1392f06ca4afSHartmut Brandt 		    &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1393f06ca4afSHartmut Brandt 		    ip[0] <= 0xff && ip[1] <= 0xff &&
1394f06ca4afSHartmut Brandt 		    ip[2] <= 0xff && ip[3] <= 0xff) {
1395f06ca4afSHartmut Brandt 			v->ipaddress[0] = (u_char)ip[0];
1396f06ca4afSHartmut Brandt 			v->ipaddress[1] = (u_char)ip[1];
1397f06ca4afSHartmut Brandt 			v->ipaddress[2] = (u_char)ip[2];
1398f06ca4afSHartmut Brandt 			v->ipaddress[3] = (u_char)ip[3];
1399f06ca4afSHartmut Brandt 			return (0);
1400f06ca4afSHartmut Brandt 		}
1401f06ca4afSHartmut Brandt 
1402f06ca4afSHartmut Brandt 		if ((he = gethostbyname(str)) == NULL)
1403f06ca4afSHartmut Brandt 			return (-1);
1404f06ca4afSHartmut Brandt 		if (he->h_addrtype != AF_INET)
1405f06ca4afSHartmut Brandt 			return (-1);
1406f06ca4afSHartmut Brandt 
1407f06ca4afSHartmut Brandt 		v->ipaddress[0] = he->h_addr[0];
1408f06ca4afSHartmut Brandt 		v->ipaddress[1] = he->h_addr[1];
1409f06ca4afSHartmut Brandt 		v->ipaddress[2] = he->h_addr[2];
1410f06ca4afSHartmut Brandt 		v->ipaddress[3] = he->h_addr[3];
1411f06ca4afSHartmut Brandt 		return (0);
1412f06ca4afSHartmut Brandt 	    }
1413f06ca4afSHartmut Brandt 
1414f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER:
1415f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_GAUGE:
1416f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_TIMETICKS:
1417f06ca4afSHartmut Brandt 	    {
1418896052c1SHartmut Brandt 		uint64_t sub;
1419f06ca4afSHartmut Brandt 
1420f06ca4afSHartmut Brandt 		sub = strtoull(str, &end, 0);
1421f06ca4afSHartmut Brandt 		if (*end != '\0' || sub > 0xffffffff)
1422f06ca4afSHartmut Brandt 			return (-1);
1423896052c1SHartmut Brandt 		v->uint32 = (uint32_t)sub;
1424f06ca4afSHartmut Brandt 		return (0);
1425f06ca4afSHartmut Brandt 	    }
1426f06ca4afSHartmut Brandt 
1427f06ca4afSHartmut Brandt 	  case SNMP_SYNTAX_COUNTER64:
1428f06ca4afSHartmut Brandt 		v->counter64 = strtoull(str, &end, 0);
1429f06ca4afSHartmut Brandt 		if (*end != '\0')
1430f06ca4afSHartmut Brandt 			return (-1);
1431f06ca4afSHartmut Brandt 		return (0);
1432f06ca4afSHartmut Brandt 	}
1433f06ca4afSHartmut Brandt 	abort();
1434f06ca4afSHartmut Brandt }
1435f06ca4afSHartmut Brandt 
1436f06ca4afSHartmut Brandt static void
1437f06ca4afSHartmut Brandt snmp_error_func(const char *fmt, ...)
1438f06ca4afSHartmut Brandt {
1439f06ca4afSHartmut Brandt 	va_list ap;
1440f06ca4afSHartmut Brandt 
1441f06ca4afSHartmut Brandt 	va_start(ap, fmt);
1442f06ca4afSHartmut Brandt 	fprintf(stderr, "SNMP: ");
1443f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
1444f06ca4afSHartmut Brandt 	fprintf(stderr, "\n");
1445f06ca4afSHartmut Brandt 	va_end(ap);
1446f06ca4afSHartmut Brandt }
1447f06ca4afSHartmut Brandt 
1448f06ca4afSHartmut Brandt static void
1449f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...)
1450f06ca4afSHartmut Brandt {
1451f06ca4afSHartmut Brandt 	va_list ap;
1452f06ca4afSHartmut Brandt 
1453f06ca4afSHartmut Brandt 	va_start(ap, fmt);
1454f06ca4afSHartmut Brandt 	vfprintf(stderr, fmt, ap);
1455f06ca4afSHartmut Brandt 	va_end(ap);
1456f06ca4afSHartmut Brandt }
1457