1122394Sharti/*
2122394Sharti * Copyright (c) 2001-2003
3122394Sharti *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
4122394Sharti *	All rights reserved.
5122394Sharti *
6122394Sharti * Author: Harti Brandt <harti@freebsd.org>
7133211Sharti *
8216294Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation
9216294Ssyrinx * All rights reserved.
10216294Ssyrinx *
11216294Ssyrinx * Portions of this software were developed by Shteryana Sotirova Shopova
12216294Ssyrinx * under sponsorship from the FreeBSD Foundation.
13216294Ssyrinx *
14133211Sharti * Redistribution and use in source and binary forms, with or without
15133211Sharti * modification, are permitted provided that the following conditions
16133211Sharti * are met:
17133211Sharti * 1. Redistributions of source code must retain the above copyright
18133211Sharti *    notice, this list of conditions and the following disclaimer.
19122394Sharti * 2. Redistributions in binary form must reproduce the above copyright
20122394Sharti *    notice, this list of conditions and the following disclaimer in the
21122394Sharti *    documentation and/or other materials provided with the distribution.
22133211Sharti *
23133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
24133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26133211Sharti * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
27133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33133211Sharti * SUCH DAMAGE.
34122394Sharti *
35150920Sharti * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
36122394Sharti *
37122394Sharti * SNMP
38122394Sharti */
39122394Sharti#include <sys/types.h>
40122394Sharti#include <sys/socket.h>
41122394Sharti#include <stdio.h>
42122394Sharti#include <stdlib.h>
43122394Sharti#include <stddef.h>
44122394Sharti#include <stdarg.h>
45150920Sharti#ifdef HAVE_STDINT_H
46133211Sharti#include <stdint.h>
47150920Sharti#elif defined(HAVE_INTTYPES_H)
48150920Sharti#include <inttypes.h>
49150920Sharti#endif
50122394Sharti#include <string.h>
51122394Sharti#include <ctype.h>
52122394Sharti#include <netdb.h>
53122394Sharti#include <errno.h>
54122394Sharti
55122394Sharti#include "asn1.h"
56122394Sharti#include "snmp.h"
57122394Sharti#include "snmppriv.h"
58122394Sharti
59122394Shartistatic void snmp_error_func(const char *, ...);
60122394Shartistatic void snmp_printf_func(const char *, ...);
61122394Sharti
62122394Shartivoid (*snmp_error)(const char *, ...) = snmp_error_func;
63122394Shartivoid (*snmp_printf)(const char *, ...) = snmp_printf_func;
64122394Sharti
65122394Sharti/*
66122394Sharti * Get the next variable binding from the list.
67122394Sharti * ASN errors on the sequence or the OID are always fatal.
68122394Sharti */
69122394Shartistatic enum asn_err
70122394Shartiget_var_binding(struct asn_buf *b, struct snmp_value *binding)
71122394Sharti{
72122394Sharti	u_char type;
73122394Sharti	asn_len_t len, trailer;
74122394Sharti	enum asn_err err;
75122394Sharti
76122394Sharti	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
77122394Sharti		snmp_error("cannot parse varbind header");
78122394Sharti		return (ASN_ERR_FAILED);
79122394Sharti	}
80122394Sharti
81122394Sharti	/* temporary truncate the length so that the parser does not
82122394Sharti	 * eat up bytes behind the sequence in the case the encoding is
83122394Sharti	 * wrong of inner elements. */
84122394Sharti	trailer = b->asn_len - len;
85122394Sharti	b->asn_len = len;
86122394Sharti
87122394Sharti	if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
88122394Sharti		snmp_error("cannot parse binding objid");
89122394Sharti		return (ASN_ERR_FAILED);
90122394Sharti	}
91122394Sharti	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
92122394Sharti		snmp_error("cannot parse binding value header");
93122394Sharti		return (ASN_ERR_FAILED);
94122394Sharti	}
95122394Sharti
96122394Sharti	switch (type) {
97122394Sharti
98122394Sharti	  case ASN_TYPE_NULL:
99122394Sharti		binding->syntax = SNMP_SYNTAX_NULL;
100122394Sharti		err = asn_get_null_raw(b, len);
101122394Sharti		break;
102122394Sharti
103122394Sharti	  case ASN_TYPE_INTEGER:
104122394Sharti		binding->syntax = SNMP_SYNTAX_INTEGER;
105122394Sharti		err = asn_get_integer_raw(b, len, &binding->v.integer);
106122394Sharti		break;
107122394Sharti
108122394Sharti	  case ASN_TYPE_OCTETSTRING:
109122394Sharti		binding->syntax = SNMP_SYNTAX_OCTETSTRING;
110122394Sharti		binding->v.octetstring.octets = malloc(len);
111122394Sharti		if (binding->v.octetstring.octets == NULL) {
112122394Sharti			snmp_error("%s", strerror(errno));
113122394Sharti			return (ASN_ERR_FAILED);
114122394Sharti		}
115122394Sharti		binding->v.octetstring.len = len;
116122394Sharti		err = asn_get_octetstring_raw(b, len,
117122394Sharti		    binding->v.octetstring.octets,
118122394Sharti		    &binding->v.octetstring.len);
119122394Sharti		if (ASN_ERR_STOPPED(err)) {
120122394Sharti			free(binding->v.octetstring.octets);
121122394Sharti			binding->v.octetstring.octets = NULL;
122122394Sharti		}
123122394Sharti		break;
124122394Sharti
125122394Sharti	  case ASN_TYPE_OBJID:
126122394Sharti		binding->syntax = SNMP_SYNTAX_OID;
127122394Sharti		err = asn_get_objid_raw(b, len, &binding->v.oid);
128122394Sharti		break;
129122394Sharti
130122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
131122394Sharti		binding->syntax = SNMP_SYNTAX_IPADDRESS;
132122394Sharti		err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
133122394Sharti		break;
134122394Sharti
135122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
136122394Sharti		binding->syntax = SNMP_SYNTAX_TIMETICKS;
137122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
138122394Sharti		break;
139122394Sharti
140122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
141122394Sharti		binding->syntax = SNMP_SYNTAX_COUNTER;
142122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
143122394Sharti		break;
144122394Sharti
145122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
146122394Sharti		binding->syntax = SNMP_SYNTAX_GAUGE;
147122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
148122394Sharti		break;
149122394Sharti
150122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
151122394Sharti		binding->syntax = SNMP_SYNTAX_COUNTER64;
152122394Sharti		err = asn_get_counter64_raw(b, len, &binding->v.counter64);
153122394Sharti		break;
154122394Sharti
155122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
156122394Sharti		binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
157122394Sharti		err = asn_get_null_raw(b, len);
158122394Sharti		break;
159122394Sharti
160122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
161122394Sharti		binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
162122394Sharti		err = asn_get_null_raw(b, len);
163122394Sharti		break;
164122394Sharti
165122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
166122394Sharti		binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
167122394Sharti		err = asn_get_null_raw(b, len);
168122394Sharti		break;
169122394Sharti
170122394Sharti	  default:
171122394Sharti		if ((err = asn_skip(b, len)) == ASN_ERR_OK)
172122394Sharti			err = ASN_ERR_TAG;
173122394Sharti		snmp_error("bad binding value type 0x%x", type);
174122394Sharti		break;
175122394Sharti	}
176122394Sharti
177122394Sharti	if (ASN_ERR_STOPPED(err)) {
178122394Sharti		snmp_error("cannot parse binding value");
179122394Sharti		return (err);
180122394Sharti	}
181122394Sharti
182122394Sharti	if (b->asn_len != 0)
183122394Sharti		snmp_error("ignoring junk at end of binding");
184122394Sharti
185122394Sharti	b->asn_len = trailer;
186122394Sharti
187122394Sharti	return (err);
188122394Sharti}
189122394Sharti
190122394Sharti/*
191122394Sharti * Parse the different PDUs contents. Any ASN error in the outer components
192122394Sharti * are fatal. Only errors in variable values may be tolerated. If all
193122394Sharti * components can be parsed it returns either ASN_ERR_OK or the first
194122394Sharti * error that was found.
195122394Sharti */
196122394Shartienum asn_err
197122394Shartisnmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
198122394Sharti{
199122394Sharti	if (pdu->type == SNMP_PDU_TRAP) {
200122394Sharti		if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
201122394Sharti			snmp_error("cannot parse trap enterprise");
202122394Sharti			return (ASN_ERR_FAILED);
203122394Sharti		}
204122394Sharti		if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
205122394Sharti			snmp_error("cannot parse trap agent address");
206122394Sharti			return (ASN_ERR_FAILED);
207122394Sharti		}
208122394Sharti		if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
209122394Sharti			snmp_error("cannot parse 'generic-trap'");
210122394Sharti			return (ASN_ERR_FAILED);
211122394Sharti		}
212122394Sharti		if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
213122394Sharti			snmp_error("cannot parse 'specific-trap'");
214122394Sharti			return (ASN_ERR_FAILED);
215122394Sharti		}
216122394Sharti		if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
217122394Sharti			snmp_error("cannot parse trap 'time-stamp'");
218122394Sharti			return (ASN_ERR_FAILED);
219122394Sharti		}
220122394Sharti	} else {
221122394Sharti		if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
222122394Sharti			snmp_error("cannot parse 'request-id'");
223122394Sharti			return (ASN_ERR_FAILED);
224122394Sharti		}
225122394Sharti		if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
226122394Sharti			snmp_error("cannot parse 'error_status'");
227122394Sharti			return (ASN_ERR_FAILED);
228122394Sharti		}
229122394Sharti		if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
230122394Sharti			snmp_error("cannot parse 'error_index'");
231122394Sharti			return (ASN_ERR_FAILED);
232122394Sharti		}
233122394Sharti	}
234122394Sharti
235122394Sharti	if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
236122394Sharti		snmp_error("cannot get varlist header");
237122394Sharti		return (ASN_ERR_FAILED);
238122394Sharti	}
239122394Sharti
240122394Sharti	return (ASN_ERR_OK);
241122394Sharti}
242122394Sharti
243122394Shartistatic enum asn_err
244122394Shartiparse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
245122394Sharti{
246122394Sharti	asn_len_t len, trailer;
247122394Sharti	struct snmp_value *v;
248122394Sharti	enum asn_err err, err1;
249122394Sharti
250122394Sharti	err = snmp_parse_pdus_hdr(b, pdu, &len);
251122394Sharti	if (ASN_ERR_STOPPED(err))
252122394Sharti		return (err);
253122394Sharti
254122394Sharti	trailer = b->asn_len - len;
255122394Sharti
256122394Sharti	v = pdu->bindings;
257122394Sharti	err = ASN_ERR_OK;
258122394Sharti	while (b->asn_len != 0) {
259122394Sharti		if (pdu->nbindings == SNMP_MAX_BINDINGS) {
260122394Sharti			snmp_error("too many bindings (> %u) in PDU",
261122394Sharti			    SNMP_MAX_BINDINGS);
262122394Sharti			return (ASN_ERR_FAILED);
263122394Sharti		}
264122394Sharti		err1 = get_var_binding(b, v);
265122394Sharti		if (ASN_ERR_STOPPED(err1))
266122394Sharti			return (ASN_ERR_FAILED);
267122394Sharti		if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
268122394Sharti			err = err1;
269122394Sharti			*ip = pdu->nbindings + 1;
270122394Sharti		}
271122394Sharti		pdu->nbindings++;
272122394Sharti		v++;
273122394Sharti	}
274122394Sharti
275122394Sharti	b->asn_len = trailer;
276122394Sharti
277122394Sharti	return (err);
278122394Sharti}
279122394Sharti
280216294Ssyrinx
281216294Ssyrinxstatic enum asn_err
282216294Ssyrinxparse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
283216294Ssyrinx{
284216294Ssyrinx	asn_len_t octs_len;
285216294Ssyrinx	u_char buf[256]; /* XXX: calc max possible size here */
286216294Ssyrinx	struct asn_buf tb;
287216294Ssyrinx
288216294Ssyrinx	memset(buf, 0, 256);
289216294Ssyrinx	tb.asn_ptr = buf;
290216294Ssyrinx	tb.asn_len = 256;
291216294Ssyrinx
292216294Ssyrinx	if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) {
293216294Ssyrinx		snmp_error("cannot parse usm header");
294216294Ssyrinx		return (ASN_ERR_FAILED);
295216294Ssyrinx	}
296216294Ssyrinx
297216294Ssyrinx	if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
298216294Ssyrinx		snmp_error("cannot decode usm header");
299216294Ssyrinx		return (ASN_ERR_FAILED);
300216294Ssyrinx	}
301216294Ssyrinx
302216294Ssyrinx	octs_len = SNMP_ENGINE_ID_SIZ;
303216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
304216294Ssyrinx	    &octs_len) != ASN_ERR_OK) {
305216294Ssyrinx		snmp_error("cannot decode msg engine id");
306216294Ssyrinx		return (ASN_ERR_FAILED);
307216294Ssyrinx	}
308216294Ssyrinx	pdu->engine.engine_len = octs_len;
309216294Ssyrinx
310216294Ssyrinx	if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
311216294Ssyrinx		snmp_error("cannot decode msg engine boots");
312216294Ssyrinx		return (ASN_ERR_FAILED);
313216294Ssyrinx	}
314216294Ssyrinx
315216294Ssyrinx	if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
316216294Ssyrinx		snmp_error("cannot decode msg engine time");
317216294Ssyrinx		return (ASN_ERR_FAILED);
318216294Ssyrinx	}
319216294Ssyrinx
320216294Ssyrinx	octs_len = SNMP_ADM_STR32_SIZ - 1;
321216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
322216294Ssyrinx	    != ASN_ERR_OK) {
323216294Ssyrinx		snmp_error("cannot decode msg user name");
324216294Ssyrinx		return (ASN_ERR_FAILED);
325216294Ssyrinx	}
326216294Ssyrinx	pdu->user.sec_name[octs_len] = '\0';
327216294Ssyrinx
328216294Ssyrinx	octs_len = sizeof(pdu->msg_digest);
329216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
330216294Ssyrinx	    ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
331216294Ssyrinx	    octs_len != sizeof(pdu->msg_digest))) {
332216294Ssyrinx		snmp_error("cannot decode msg authentication param");
333216294Ssyrinx		return (ASN_ERR_FAILED);
334216294Ssyrinx	}
335216294Ssyrinx
336216294Ssyrinx	octs_len = sizeof(pdu->msg_salt);
337216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
338216294Ssyrinx	    ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
339216294Ssyrinx	    octs_len != sizeof(pdu->msg_salt))) {
340216294Ssyrinx		snmp_error("cannot decode msg authentication param");
341216294Ssyrinx		return (ASN_ERR_FAILED);
342216294Ssyrinx	}
343216294Ssyrinx
344216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
345216294Ssyrinx		pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
346216294Ssyrinx		pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
347216294Ssyrinx	}
348216294Ssyrinx
349216294Ssyrinx	return (ASN_ERR_OK);
350216294Ssyrinx}
351216294Ssyrinx
352216294Ssyrinxstatic enum snmp_code
353216294Ssyrinxpdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
354216294Ssyrinx{
355216294Ssyrinx	u_char buf[256], *sptr;
356216294Ssyrinx        struct asn_buf tb;
357216294Ssyrinx        size_t auth_off, moved = 0;
358216294Ssyrinx
359216294Ssyrinx	auth_off = 0;
360216294Ssyrinx	memset(buf, 0, 256);
361216294Ssyrinx	tb.asn_ptr = buf;
362216294Ssyrinx	tb.asn_len = 256;
363216294Ssyrinx
364216294Ssyrinx	if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
365216294Ssyrinx	    &sptr) != ASN_ERR_OK)
366216294Ssyrinx		return (SNMP_CODE_FAILED);
367216294Ssyrinx
368216294Ssyrinx	if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
369216294Ssyrinx	    pdu->engine.engine_len) != ASN_ERR_OK)
370216294Ssyrinx		return (SNMP_CODE_FAILED);
371216294Ssyrinx
372216294Ssyrinx	if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
373216294Ssyrinx		return (SNMP_CODE_FAILED);
374216294Ssyrinx
375216294Ssyrinx	if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
376216294Ssyrinx		return (SNMP_CODE_FAILED);
377216294Ssyrinx
378216294Ssyrinx	if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
379216294Ssyrinx	    strlen(pdu->user.sec_name)) != ASN_ERR_OK)
380216294Ssyrinx		return (SNMP_CODE_FAILED);
381216294Ssyrinx
382216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
383216294Ssyrinx		auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
384216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
385216294Ssyrinx		    sizeof(pdu->msg_digest)) != ASN_ERR_OK)
386216294Ssyrinx			return (SNMP_CODE_FAILED);
387216294Ssyrinx	} else {
388216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
389216294Ssyrinx		    != ASN_ERR_OK)
390216294Ssyrinx			return (SNMP_CODE_FAILED);
391216294Ssyrinx	}
392216294Ssyrinx
393216294Ssyrinx	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
394216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
395216294Ssyrinx		    sizeof(pdu->msg_salt)) != ASN_ERR_OK)
396216294Ssyrinx			return (SNMP_CODE_FAILED);
397216294Ssyrinx	} else {
398216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
399216294Ssyrinx		    != ASN_ERR_OK)
400216294Ssyrinx			return (SNMP_CODE_FAILED);
401216294Ssyrinx	}
402216294Ssyrinx
403216294Ssyrinx	if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
404216294Ssyrinx		return (SNMP_CODE_FAILED);
405216294Ssyrinx
406216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
407216294Ssyrinx		pdu->digest_ptr = b->asn_ptr + auth_off - moved;
408216294Ssyrinx
409216294Ssyrinx	if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
410216294Ssyrinx		return (SNMP_CODE_FAILED);
411216294Ssyrinx	pdu->digest_ptr += ASN_MAXLENLEN;
412216294Ssyrinx
413216294Ssyrinx	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
414216294Ssyrinx	    ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
415216294Ssyrinx			return (SNMP_CODE_FAILED);
416216294Ssyrinx
417216294Ssyrinx	return (SNMP_CODE_OK);
418216294Ssyrinx}
419216294Ssyrinx
420122394Sharti/*
421216294Ssyrinx * Decode the PDU except for the variable bindings itself.
422216294Ssyrinx * If decoding fails because of a bad binding, but the rest can be
423216294Ssyrinx * decoded, ip points to the index of the failed variable (errors
424216294Ssyrinx * OORANGE, BADLEN or BADVERS).
425122394Sharti */
426216294Ssyrinxenum snmp_code
427216294Ssyrinxsnmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
428122394Sharti{
429216294Ssyrinx	enum snmp_code code;
430216294Ssyrinx
431216294Ssyrinx	if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
432216294Ssyrinx		return (code);
433216294Ssyrinx
434216294Ssyrinx	if (pdu->version == SNMP_V3) {
435216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
436216294Ssyrinx			return (SNMP_CODE_FAILED);
437216294Ssyrinx		if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
438216294Ssyrinx			return (code);
439216294Ssyrinx	}
440216294Ssyrinx
441216294Ssyrinx	code = snmp_pdu_decode_scoped(b, pdu, ip);
442216294Ssyrinx
443216294Ssyrinx	switch (code) {
444216294Ssyrinx	  case SNMP_CODE_FAILED:
445216294Ssyrinx		snmp_pdu_free(pdu);
446216294Ssyrinx		break;
447216294Ssyrinx
448216294Ssyrinx	  case SNMP_CODE_BADENC:
449216294Ssyrinx		if (pdu->version == SNMP_Verr)
450216294Ssyrinx			return (SNMP_CODE_BADVERS);
451216294Ssyrinx
452216294Ssyrinx	  default:
453216294Ssyrinx		break;
454216294Ssyrinx	}
455216294Ssyrinx
456216294Ssyrinx	return (code);
457216294Ssyrinx}
458216294Ssyrinx
459216294Ssyrinxenum snmp_code
460216294Ssyrinxsnmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
461216294Ssyrinx{
462122394Sharti	int32_t version;
463216294Ssyrinx	u_int octs_len;
464216294Ssyrinx	asn_len_t len;
465122394Sharti
466216294Ssyrinx	pdu->outer_ptr = b->asn_ptr;
467216294Ssyrinx	pdu->outer_len = b->asn_len;
468216294Ssyrinx
469216294Ssyrinx	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
470216294Ssyrinx		snmp_error("cannot decode pdu header");
471216294Ssyrinx		return (SNMP_CODE_FAILED);
472216294Ssyrinx	}
473216294Ssyrinx	if (b->asn_len < len) {
474216294Ssyrinx		snmp_error("outer sequence value too short");
475216294Ssyrinx		return (SNMP_CODE_FAILED);
476216294Ssyrinx	}
477216294Ssyrinx	if (b->asn_len != len) {
478216294Ssyrinx		snmp_error("ignoring trailing junk in message");
479216294Ssyrinx		b->asn_len = len;
480216294Ssyrinx	}
481216294Ssyrinx
482122394Sharti	if (asn_get_integer(b, &version) != ASN_ERR_OK) {
483122394Sharti		snmp_error("cannot decode version");
484216294Ssyrinx		return (SNMP_CODE_FAILED);
485122394Sharti	}
486122394Sharti
487216294Ssyrinx	if (version == 0)
488122394Sharti		pdu->version = SNMP_V1;
489216294Ssyrinx	else if (version == 1)
490122394Sharti		pdu->version = SNMP_V2c;
491216294Ssyrinx	else if (version == 3)
492216294Ssyrinx		pdu->version = SNMP_V3;
493216294Ssyrinx	else {
494122394Sharti		pdu->version = SNMP_Verr;
495122394Sharti		snmp_error("unsupported SNMP version");
496216294Ssyrinx		return (SNMP_CODE_BADENC);
497122394Sharti	}
498122394Sharti
499216294Ssyrinx	if (pdu->version == SNMP_V3) {
500216294Ssyrinx		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
501216294Ssyrinx			snmp_error("cannot decode pdu global data header");
502216294Ssyrinx			return (SNMP_CODE_FAILED);
503216294Ssyrinx		}
504216294Ssyrinx
505216294Ssyrinx		if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
506216294Ssyrinx			snmp_error("cannot decode msg indetifier");
507216294Ssyrinx			return (SNMP_CODE_FAILED);
508216294Ssyrinx		}
509216294Ssyrinx
510216294Ssyrinx		if (asn_get_integer(b, &pdu->engine.max_msg_size)
511216294Ssyrinx		    != ASN_ERR_OK) {
512216294Ssyrinx			snmp_error("cannot decode msg size");
513216294Ssyrinx			return (SNMP_CODE_FAILED);
514216294Ssyrinx		}
515216294Ssyrinx
516216294Ssyrinx		octs_len = 1;
517216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->flags,
518216294Ssyrinx		    &octs_len) != ASN_ERR_OK) {
519216294Ssyrinx			snmp_error("cannot decode msg flags");
520216294Ssyrinx			return (SNMP_CODE_FAILED);
521216294Ssyrinx		}
522216294Ssyrinx
523216294Ssyrinx		if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
524216294Ssyrinx			snmp_error("cannot decode msg size");
525216294Ssyrinx			return (SNMP_CODE_FAILED);
526216294Ssyrinx		}
527216294Ssyrinx
528216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
529216294Ssyrinx			return (SNMP_CODE_FAILED);
530216294Ssyrinx
531216294Ssyrinx		if (parse_secparams(b, pdu) != ASN_ERR_OK)
532216294Ssyrinx			return (SNMP_CODE_FAILED);
533216294Ssyrinx	} else {
534216294Ssyrinx		octs_len = SNMP_COMMUNITY_MAXLEN;
535216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)pdu->community,
536216294Ssyrinx		    &octs_len) != ASN_ERR_OK) {
537216294Ssyrinx			snmp_error("cannot decode community");
538216294Ssyrinx			return (SNMP_CODE_FAILED);
539216294Ssyrinx		}
540216294Ssyrinx		pdu->community[octs_len] = '\0';
541122394Sharti	}
542122394Sharti
543216294Ssyrinx	return (SNMP_CODE_OK);
544216294Ssyrinx}
545216294Ssyrinx
546216294Ssyrinxenum snmp_code
547216294Ssyrinxsnmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
548216294Ssyrinx{
549216294Ssyrinx	u_char type;
550216294Ssyrinx	asn_len_t len, trailer;
551216294Ssyrinx	enum asn_err err;
552216294Ssyrinx
553216294Ssyrinx	if (pdu->version == SNMP_V3) {
554216294Ssyrinx		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
555216294Ssyrinx			snmp_error("cannot decode scoped pdu header");
556216294Ssyrinx			return (SNMP_CODE_FAILED);
557216294Ssyrinx		}
558216294Ssyrinx
559216294Ssyrinx		len = SNMP_ENGINE_ID_SIZ;
560216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
561216294Ssyrinx		    &len) != ASN_ERR_OK) {
562216294Ssyrinx			snmp_error("cannot decode msg context engine");
563216294Ssyrinx			return (SNMP_CODE_FAILED);
564216294Ssyrinx		}
565216294Ssyrinx		pdu->context_engine_len = len;
566216294Ssyrinx
567216294Ssyrinx		len = SNMP_CONTEXT_NAME_SIZ;
568216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
569216294Ssyrinx		    &len) != ASN_ERR_OK) {
570216294Ssyrinx			snmp_error("cannot decode msg context name");
571216294Ssyrinx			return (SNMP_CODE_FAILED);
572216294Ssyrinx		}
573216294Ssyrinx		pdu->context_name[len] = '\0';
574216294Ssyrinx	}
575216294Ssyrinx
576216294Ssyrinx	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
577122394Sharti		snmp_error("cannot get pdu header");
578216294Ssyrinx		return (SNMP_CODE_FAILED);
579122394Sharti	}
580122394Sharti	if ((type & ~ASN_TYPE_MASK) !=
581122394Sharti	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
582122394Sharti		snmp_error("bad pdu header tag");
583216294Ssyrinx		return (SNMP_CODE_FAILED);
584122394Sharti	}
585122394Sharti	pdu->type = type & ASN_TYPE_MASK;
586122394Sharti
587122394Sharti	switch (pdu->type) {
588122394Sharti
589122394Sharti	  case SNMP_PDU_GET:
590122394Sharti	  case SNMP_PDU_GETNEXT:
591122394Sharti	  case SNMP_PDU_RESPONSE:
592122394Sharti	  case SNMP_PDU_SET:
593122394Sharti		break;
594122394Sharti
595122394Sharti	  case SNMP_PDU_TRAP:
596122394Sharti		if (pdu->version != SNMP_V1) {
597122394Sharti			snmp_error("bad pdu type %u", pdu->type);
598216294Ssyrinx			return (SNMP_CODE_FAILED);
599122394Sharti		}
600122394Sharti		break;
601122394Sharti
602122394Sharti	  case SNMP_PDU_GETBULK:
603122394Sharti	  case SNMP_PDU_INFORM:
604122394Sharti	  case SNMP_PDU_TRAP2:
605122394Sharti	  case SNMP_PDU_REPORT:
606122394Sharti		if (pdu->version == SNMP_V1) {
607122394Sharti			snmp_error("bad pdu type %u", pdu->type);
608216294Ssyrinx			return (SNMP_CODE_FAILED);
609122394Sharti		}
610122394Sharti		break;
611122394Sharti
612122394Sharti	  default:
613122394Sharti		snmp_error("bad pdu type %u", pdu->type);
614216294Ssyrinx		return (SNMP_CODE_FAILED);
615122394Sharti	}
616122394Sharti
617122394Sharti	trailer = b->asn_len - len;
618122394Sharti	b->asn_len = len;
619122394Sharti
620122394Sharti	err = parse_pdus(b, pdu, ip);
621122394Sharti	if (ASN_ERR_STOPPED(err))
622216294Ssyrinx		return (SNMP_CODE_FAILED);
623122394Sharti
624122394Sharti	if (b->asn_len != 0)
625122394Sharti		snmp_error("ignoring trailing junk after pdu");
626122394Sharti
627122394Sharti	b->asn_len = trailer;
628122394Sharti
629216294Ssyrinx	return (SNMP_CODE_OK);
630122394Sharti}
631122394Sharti
632122394Shartienum snmp_code
633216294Ssyrinxsnmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
634122394Sharti{
635216294Ssyrinx	u_char type;
636216294Ssyrinx	enum snmp_code code;
637216294Ssyrinx	uint8_t	digest[SNMP_USM_AUTH_SIZE];
638122394Sharti
639216294Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
640216294Ssyrinx	    (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
641216294Ssyrinx		return (SNMP_CODE_BADSECLEVEL);
642122394Sharti
643216482Ssyrinx	if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
644216294Ssyrinx	    SNMP_CODE_OK)
645122394Sharti		return (SNMP_CODE_FAILED);
646216294Ssyrinx
647216294Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
648216294Ssyrinx	    memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
649216294Ssyrinx		return (SNMP_CODE_BADDIGEST);
650216294Ssyrinx
651216294Ssyrinx	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
652216294Ssyrinx	    &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
653216294Ssyrinx		snmp_error("cannot decode encrypted pdu");
654122394Sharti		return (SNMP_CODE_FAILED);
655122394Sharti	}
656216294Ssyrinx	pdu->scoped_ptr = b->asn_ptr;
657122394Sharti
658216294Ssyrinx	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
659216294Ssyrinx	    (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
660216294Ssyrinx		return (SNMP_CODE_BADSECLEVEL);
661122394Sharti
662216482Ssyrinx	if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
663122394Sharti		return (SNMP_CODE_FAILED);
664122394Sharti
665216294Ssyrinx	return (code);
666122394Sharti}
667122394Sharti
668122394Sharti/*
669124861Sharti * Check whether what we have is the complete PDU by snooping at the
670124861Sharti * enclosing structure header. This returns:
671124861Sharti *   -1		if there are ASN.1 errors
672124861Sharti *    0		if we need more data
673124861Sharti *  > 0		the length of this PDU
674124861Sharti */
675124861Shartiint
676124861Shartisnmp_pdu_snoop(const struct asn_buf *b0)
677124861Sharti{
678124861Sharti	u_int length;
679124861Sharti	asn_len_t len;
680124861Sharti	struct asn_buf b = *b0;
681124861Sharti
682124861Sharti	/* <0x10|0x20> <len> <data...> */
683124861Sharti
684124861Sharti	if (b.asn_len == 0)
685124861Sharti		return (0);
686124861Sharti	if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
687124861Sharti		asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
688124861Sharti		return (-1);
689124861Sharti	}
690124861Sharti	b.asn_len--;
691124861Sharti	b.asn_cptr++;
692124861Sharti
693124861Sharti	if (b.asn_len == 0)
694124861Sharti		return (0);
695124861Sharti
696124861Sharti	if (*b.asn_cptr & 0x80) {
697124861Sharti		/* long length */
698124861Sharti		length = *b.asn_cptr++ & 0x7f;
699124861Sharti		b.asn_len--;
700124861Sharti		if (length == 0) {
701124861Sharti			asn_error(&b, "indefinite length not supported");
702124861Sharti			return (-1);
703124861Sharti		}
704124861Sharti		if (length > ASN_MAXLENLEN) {
705124861Sharti			asn_error(&b, "long length too long (%u)", length);
706124861Sharti			return (-1);
707124861Sharti		}
708124861Sharti		if (length > b.asn_len)
709124861Sharti			return (0);
710124861Sharti		len = 0;
711124861Sharti		while (length--) {
712124861Sharti			len = (len << 8) | *b.asn_cptr++;
713124861Sharti			b.asn_len--;
714124861Sharti		}
715124861Sharti	} else {
716124861Sharti		len = *b.asn_cptr++;
717124861Sharti		b.asn_len--;
718124861Sharti	}
719124861Sharti
720124861Sharti	if (len > b.asn_len)
721124861Sharti		return (0);
722124861Sharti
723124861Sharti	return (len + b.asn_cptr - b0->asn_cptr);
724124861Sharti}
725124861Sharti
726124861Sharti/*
727122394Sharti * Encode the SNMP PDU without the variable bindings field.
728122394Sharti * We do this the rather uneffective way by
729122394Sharti * moving things around and assuming that the length field will never
730122394Sharti * use more than 2 bytes.
731122394Sharti * We need a number of pointers to apply the fixes afterwards.
732122394Sharti */
733122394Shartienum snmp_code
734122394Shartisnmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
735122394Sharti{
736122394Sharti	enum asn_err err;
737216294Ssyrinx	u_char *v3_hdr_ptr;
738122394Sharti
739122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
740122394Sharti	    &pdu->outer_ptr) != ASN_ERR_OK)
741122394Sharti		return (SNMP_CODE_FAILED);
742122394Sharti
743122394Sharti	if (pdu->version == SNMP_V1)
744122394Sharti		err = asn_put_integer(b, 0);
745122394Sharti	else if (pdu->version == SNMP_V2c)
746122394Sharti		err = asn_put_integer(b, 1);
747216294Ssyrinx	else if (pdu->version == SNMP_V3)
748216294Ssyrinx		err = asn_put_integer(b, 3);
749122394Sharti	else
750122394Sharti		return (SNMP_CODE_BADVERS);
751122394Sharti	if (err != ASN_ERR_OK)
752122394Sharti		return (SNMP_CODE_FAILED);
753122394Sharti
754216294Ssyrinx	if (pdu->version == SNMP_V3) {
755216294Ssyrinx		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
756216294Ssyrinx		    ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
757216294Ssyrinx			return (SNMP_CODE_FAILED);
758216294Ssyrinx
759216294Ssyrinx		if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
760216294Ssyrinx			return (SNMP_CODE_FAILED);
761122394Sharti
762216294Ssyrinx		if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
763216294Ssyrinx			return (SNMP_CODE_FAILED);
764216294Ssyrinx
765216294Ssyrinx		if (pdu->type != SNMP_PDU_RESPONSE &&
766216294Ssyrinx		    pdu->type != SNMP_PDU_TRAP &&
767216594Ssyrinx		    pdu->type != SNMP_PDU_TRAP2 &&
768216294Ssyrinx		    pdu->type != SNMP_PDU_REPORT)
769216294Ssyrinx			pdu->flags |= SNMP_MSG_REPORT_FLAG;
770216294Ssyrinx
771216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
772216294Ssyrinx		    != ASN_ERR_OK)
773216294Ssyrinx			return (SNMP_CODE_FAILED);
774216294Ssyrinx
775216294Ssyrinx		if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
776216294Ssyrinx			return (SNMP_CODE_FAILED);
777216294Ssyrinx
778216294Ssyrinx		if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
779216294Ssyrinx			return (SNMP_CODE_FAILED);
780216294Ssyrinx
781216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
782216294Ssyrinx			return (SNMP_CODE_FAILED);
783216294Ssyrinx
784216294Ssyrinx		if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
785216294Ssyrinx			return (SNMP_CODE_FAILED);
786216294Ssyrinx
787216294Ssyrinx		/*  View-based Access Conntrol information */
788216294Ssyrinx		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
789216294Ssyrinx		    ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
790216294Ssyrinx			return (SNMP_CODE_FAILED);
791216294Ssyrinx
792216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
793216294Ssyrinx		    pdu->context_engine_len) != ASN_ERR_OK)
794216294Ssyrinx			return (SNMP_CODE_FAILED);
795216294Ssyrinx
796216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->context_name,
797216294Ssyrinx		    strlen(pdu->context_name)) != ASN_ERR_OK)
798216294Ssyrinx			return (SNMP_CODE_FAILED);
799216294Ssyrinx	} else {
800216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->community,
801216294Ssyrinx		    strlen(pdu->community)) != ASN_ERR_OK)
802216294Ssyrinx			return (SNMP_CODE_FAILED);
803216294Ssyrinx	}
804216294Ssyrinx
805122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
806122394Sharti	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
807122394Sharti		return (SNMP_CODE_FAILED);
808122394Sharti
809122394Sharti	if (pdu->type == SNMP_PDU_TRAP) {
810122394Sharti		if (pdu->version != SNMP_V1 ||
811122394Sharti		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
812122394Sharti		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
813122394Sharti		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
814122394Sharti		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
815122394Sharti		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
816122394Sharti			return (SNMP_CODE_FAILED);
817122394Sharti	} else {
818122394Sharti		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
819122394Sharti		    pdu->type == SNMP_PDU_INFORM ||
820122394Sharti		    pdu->type == SNMP_PDU_TRAP2 ||
821122394Sharti		    pdu->type == SNMP_PDU_REPORT))
822122394Sharti			return (SNMP_CODE_FAILED);
823122394Sharti
824122394Sharti		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
825122394Sharti		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
826122394Sharti		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
827122394Sharti			return (SNMP_CODE_FAILED);
828122394Sharti	}
829122394Sharti
830122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
831122394Sharti	    &pdu->vars_ptr) != ASN_ERR_OK)
832122394Sharti		return (SNMP_CODE_FAILED);
833122394Sharti
834122394Sharti	return (SNMP_CODE_OK);
835122394Sharti}
836122394Sharti
837216294Ssyrinxstatic enum asn_err
838216294Ssyrinxsnmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
839216294Ssyrinx{
840216294Ssyrinx	asn_len_t padlen;
841216294Ssyrinx
842216294Ssyrinx	if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
843216294Ssyrinx		padlen = 8 - (pdu->scoped_len % 8);
844216294Ssyrinx		if (asn_pad(b, padlen) != ASN_ERR_OK)
845216294Ssyrinx			return (ASN_ERR_FAILED);
846216294Ssyrinx		pdu->scoped_len += padlen;
847216294Ssyrinx	}
848216294Ssyrinx
849216294Ssyrinx	return (ASN_ERR_OK);
850216294Ssyrinx}
851216294Ssyrinx
852122394Shartienum snmp_code
853216294Ssyrinxsnmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
854122394Sharti{
855216294Ssyrinx	size_t moved = 0;
856216294Ssyrinx	enum snmp_code code;
857216294Ssyrinx
858216294Ssyrinx	if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
859216294Ssyrinx	    asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
860122394Sharti		return (SNMP_CODE_FAILED);
861216294Ssyrinx
862216294Ssyrinx	if (pdu->version == SNMP_V3) {
863216294Ssyrinx		if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
864216294Ssyrinx			return (SNMP_CODE_FAILED);
865216294Ssyrinx
866216294Ssyrinx		pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
867216294Ssyrinx		if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
868216294Ssyrinx			return (SNMP_CODE_FAILED);
869216294Ssyrinx
870216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
871216294Ssyrinx			return (SNMP_CODE_FAILED);
872216294Ssyrinx
873216482Ssyrinx		if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
874216294Ssyrinx			return (SNMP_CODE_FAILED);
875216294Ssyrinx
876216294Ssyrinx		if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
877216294Ssyrinx		    asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
878216294Ssyrinx			return (SNMP_CODE_FAILED);
879216294Ssyrinx	}
880216294Ssyrinx
881216294Ssyrinx	if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
882216294Ssyrinx		return (SNMP_CODE_FAILED);
883216294Ssyrinx
884216294Ssyrinx	pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
885216294Ssyrinx	pdu->digest_ptr -= moved;
886216294Ssyrinx
887216294Ssyrinx	if (pdu->version == SNMP_V3) {
888216482Ssyrinx		if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
889216294Ssyrinx		    SNMP_CODE_OK)
890216294Ssyrinx			return (SNMP_CODE_FAILED);
891216294Ssyrinx
892216294Ssyrinx		if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
893216294Ssyrinx			memcpy(pdu->digest_ptr, pdu->msg_digest,
894216294Ssyrinx			    sizeof(pdu->msg_digest));
895216294Ssyrinx	}
896216294Ssyrinx
897122394Sharti	return (SNMP_CODE_OK);
898122394Sharti}
899122394Sharti
900122394Sharti/*
901122394Sharti * Encode a binding. Caller must ensure, that the syntax is ok for that version.
902122394Sharti * Be sure not to cobber b, when something fails.
903122394Sharti */
904122394Shartienum asn_err
905122394Shartisnmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
906122394Sharti{
907122394Sharti	u_char *ptr;
908122394Sharti	enum asn_err err;
909122394Sharti	struct asn_buf save = *b;
910122394Sharti
911122394Sharti	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
912122394Sharti	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
913122394Sharti		*b = save;
914122394Sharti		return (err);
915122394Sharti	}
916122394Sharti
917122394Sharti	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
918122394Sharti		*b = save;
919122394Sharti		return (err);
920122394Sharti	}
921122394Sharti
922122394Sharti	switch (binding->syntax) {
923122394Sharti
924122394Sharti	  case SNMP_SYNTAX_NULL:
925122394Sharti		err = asn_put_null(b);
926122394Sharti		break;
927122394Sharti
928122394Sharti	  case SNMP_SYNTAX_INTEGER:
929122394Sharti		err = asn_put_integer(b, binding->v.integer);
930122394Sharti		break;
931122394Sharti
932122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
933122394Sharti		err = asn_put_octetstring(b, binding->v.octetstring.octets,
934122394Sharti		    binding->v.octetstring.len);
935122394Sharti		break;
936122394Sharti
937122394Sharti	  case SNMP_SYNTAX_OID:
938122394Sharti		err = asn_put_objid(b, &binding->v.oid);
939122394Sharti		break;
940122394Sharti
941122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
942122394Sharti		err = asn_put_ipaddress(b, binding->v.ipaddress);
943122394Sharti		break;
944122394Sharti
945122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
946122394Sharti		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
947122394Sharti		break;
948122394Sharti
949122394Sharti	  case SNMP_SYNTAX_COUNTER:
950122394Sharti		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
951122394Sharti		break;
952122394Sharti
953122394Sharti	  case SNMP_SYNTAX_GAUGE:
954122394Sharti		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
955122394Sharti		break;
956122394Sharti
957122394Sharti	  case SNMP_SYNTAX_COUNTER64:
958122394Sharti		err = asn_put_counter64(b, binding->v.counter64);
959122394Sharti		break;
960122394Sharti
961122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
962122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
963122394Sharti		break;
964122394Sharti
965122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
966122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
967122394Sharti		break;
968122394Sharti
969122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
970122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
971122394Sharti		break;
972122394Sharti	}
973122394Sharti
974122394Sharti	if (err != ASN_ERR_OK) {
975122394Sharti		*b = save;
976122394Sharti		return (err);
977122394Sharti	}
978122394Sharti
979216294Ssyrinx	err = asn_commit_header(b, ptr, NULL);
980122394Sharti	if (err != ASN_ERR_OK) {
981122394Sharti		*b = save;
982122394Sharti		return (err);
983122394Sharti	}
984122394Sharti
985122394Sharti	return (ASN_ERR_OK);
986122394Sharti}
987122394Sharti
988122394Sharti/*
989122394Sharti * Encode an PDU.
990122394Sharti */
991122394Shartienum snmp_code
992122394Shartisnmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
993122394Sharti{
994122394Sharti	u_int idx;
995122394Sharti	enum snmp_code err;
996122394Sharti
997122394Sharti	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
998122394Sharti		return (err);
999122394Sharti	for (idx = 0; idx < pdu->nbindings; idx++)
1000122394Sharti		if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
1001122394Sharti		    != ASN_ERR_OK)
1002122394Sharti			return (SNMP_CODE_FAILED);
1003122394Sharti
1004122394Sharti	return (snmp_fix_encoding(resp_b, pdu));
1005122394Sharti}
1006122394Sharti
1007122394Shartistatic void
1008122394Shartidump_binding(const struct snmp_value *b)
1009122394Sharti{
1010122394Sharti	u_int i;
1011122394Sharti	char buf[ASN_OIDSTRLEN];
1012122394Sharti
1013122394Sharti	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1014122394Sharti	switch (b->syntax) {
1015122394Sharti
1016122394Sharti	  case SNMP_SYNTAX_NULL:
1017122394Sharti		snmp_printf("NULL");
1018122394Sharti		break;
1019122394Sharti
1020122394Sharti	  case SNMP_SYNTAX_INTEGER:
1021122394Sharti		snmp_printf("INTEGER %d", b->v.integer);
1022122394Sharti		break;
1023122394Sharti
1024122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
1025122394Sharti		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1026122394Sharti		for (i = 0; i < b->v.octetstring.len; i++)
1027122394Sharti			snmp_printf(" %02x", b->v.octetstring.octets[i]);
1028122394Sharti		break;
1029122394Sharti
1030122394Sharti	  case SNMP_SYNTAX_OID:
1031122394Sharti		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1032122394Sharti		break;
1033122394Sharti
1034122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
1035122394Sharti		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1036122394Sharti		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1037122394Sharti		break;
1038122394Sharti
1039122394Sharti	  case SNMP_SYNTAX_COUNTER:
1040122394Sharti		snmp_printf("COUNTER %u", b->v.uint32);
1041122394Sharti		break;
1042122394Sharti
1043122394Sharti	  case SNMP_SYNTAX_GAUGE:
1044122394Sharti		snmp_printf("GAUGE %u", b->v.uint32);
1045122394Sharti		break;
1046122394Sharti
1047122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
1048122394Sharti		snmp_printf("TIMETICKS %u", b->v.uint32);
1049122394Sharti		break;
1050122394Sharti
1051122394Sharti	  case SNMP_SYNTAX_COUNTER64:
1052122394Sharti		snmp_printf("COUNTER64 %lld", b->v.counter64);
1053122394Sharti		break;
1054122394Sharti
1055122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
1056122394Sharti		snmp_printf("NoSuchObject");
1057122394Sharti		break;
1058122394Sharti
1059122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1060122394Sharti		snmp_printf("NoSuchInstance");
1061122394Sharti		break;
1062122394Sharti
1063122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1064122394Sharti		snmp_printf("EndOfMibView");
1065122394Sharti		break;
1066122394Sharti
1067122394Sharti	  default:
1068122394Sharti		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1069122394Sharti		break;
1070122394Sharti	}
1071122394Sharti}
1072122394Sharti
1073122394Shartistatic __inline void
1074122394Shartidump_bindings(const struct snmp_pdu *pdu)
1075122394Sharti{
1076122394Sharti	u_int i;
1077122394Sharti
1078122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
1079122394Sharti		snmp_printf(" [%u]: ", i);
1080122394Sharti		dump_binding(&pdu->bindings[i]);
1081122394Sharti		snmp_printf("\n");
1082122394Sharti	}
1083122394Sharti}
1084122394Sharti
1085122394Shartistatic __inline void
1086122394Shartidump_notrap(const struct snmp_pdu *pdu)
1087122394Sharti{
1088122394Sharti	snmp_printf(" request_id=%d", pdu->request_id);
1089122394Sharti	snmp_printf(" error_status=%d", pdu->error_status);
1090122394Sharti	snmp_printf(" error_index=%d\n", pdu->error_index);
1091122394Sharti	dump_bindings(pdu);
1092122394Sharti}
1093122394Sharti
1094122394Shartivoid
1095122394Shartisnmp_pdu_dump(const struct snmp_pdu *pdu)
1096122394Sharti{
1097122394Sharti	char buf[ASN_OIDSTRLEN];
1098122394Sharti	const char *vers;
1099122394Sharti	static const char *types[] = {
1100122394Sharti		[SNMP_PDU_GET] =	"GET",
1101122394Sharti		[SNMP_PDU_GETNEXT] =	"GETNEXT",
1102122394Sharti		[SNMP_PDU_RESPONSE] =	"RESPONSE",
1103122394Sharti		[SNMP_PDU_SET] =	"SET",
1104122394Sharti		[SNMP_PDU_TRAP] =	"TRAPv1",
1105122394Sharti		[SNMP_PDU_GETBULK] =	"GETBULK",
1106122394Sharti		[SNMP_PDU_INFORM] =	"INFORM",
1107122394Sharti		[SNMP_PDU_TRAP2] =	"TRAPv2",
1108122394Sharti		[SNMP_PDU_REPORT] =	"REPORT",
1109122394Sharti	};
1110122394Sharti
1111122394Sharti	if (pdu->version == SNMP_V1)
1112122394Sharti		vers = "SNMPv1";
1113122394Sharti	else if (pdu->version == SNMP_V2c)
1114122394Sharti		vers = "SNMPv2c";
1115216294Ssyrinx	else if (pdu->version == SNMP_V3)
1116216294Ssyrinx		vers = "SNMPv3";
1117122394Sharti	else
1118122394Sharti		vers = "v?";
1119122394Sharti
1120122394Sharti	switch (pdu->type) {
1121122394Sharti	  case SNMP_PDU_TRAP:
1122122394Sharti		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1123122394Sharti		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1124122394Sharti		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1125122394Sharti		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1126122394Sharti		snmp_printf(" generic_trap=%d", pdu->generic_trap);
1127122394Sharti		snmp_printf(" specific_trap=%d", pdu->specific_trap);
1128122394Sharti		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1129122394Sharti		dump_bindings(pdu);
1130122394Sharti		break;
1131122394Sharti
1132122394Sharti	  case SNMP_PDU_GET:
1133122394Sharti	  case SNMP_PDU_GETNEXT:
1134122394Sharti	  case SNMP_PDU_RESPONSE:
1135122394Sharti	  case SNMP_PDU_SET:
1136122394Sharti	  case SNMP_PDU_GETBULK:
1137122394Sharti	  case SNMP_PDU_INFORM:
1138122394Sharti	  case SNMP_PDU_TRAP2:
1139122394Sharti	  case SNMP_PDU_REPORT:
1140122394Sharti		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1141122394Sharti		dump_notrap(pdu);
1142122394Sharti		break;
1143122394Sharti
1144122394Sharti	  default:
1145122394Sharti		snmp_printf("bad pdu type %u\n", pdu->type);
1146122394Sharti		break;
1147122394Sharti	}
1148122394Sharti}
1149122394Sharti
1150122394Shartivoid
1151122394Shartisnmp_value_free(struct snmp_value *value)
1152122394Sharti{
1153122394Sharti	if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1154122394Sharti		free(value->v.octetstring.octets);
1155122394Sharti	value->syntax = SNMP_SYNTAX_NULL;
1156122394Sharti}
1157122394Sharti
1158122394Shartiint
1159122394Shartisnmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1160122394Sharti{
1161122394Sharti	to->var = from->var;
1162122394Sharti	to->syntax = from->syntax;
1163122394Sharti
1164122394Sharti	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1165122394Sharti		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1166122394Sharti			to->v.octetstring.octets = NULL;
1167122394Sharti		else {
1168122394Sharti			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1169122394Sharti			if (to->v.octetstring.octets == NULL)
1170122394Sharti				return (-1);
1171122394Sharti			(void)memcpy(to->v.octetstring.octets,
1172122394Sharti			    from->v.octetstring.octets, to->v.octetstring.len);
1173122394Sharti		}
1174122394Sharti	} else
1175122394Sharti		to->v = from->v;
1176122394Sharti	return (0);
1177122394Sharti}
1178122394Sharti
1179122394Shartivoid
1180216594Ssyrinxsnmp_pdu_init_secparams(struct snmp_pdu *pdu)
1181216294Ssyrinx{
1182216294Ssyrinx	int32_t rval;
1183216294Ssyrinx
1184216594Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1185216294Ssyrinx		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1186216294Ssyrinx
1187216594Ssyrinx	switch (pdu->user.priv_proto) {
1188216294Ssyrinx	case SNMP_PRIV_DES:
1189216594Ssyrinx		memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1190216594Ssyrinx		    sizeof(pdu->engine.engine_boots));
1191216294Ssyrinx		rval = random();
1192216594Ssyrinx		memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1193216294Ssyrinx		    sizeof(int32_t));
1194216294Ssyrinx		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1195216294Ssyrinx		break;
1196216294Ssyrinx	case SNMP_PRIV_AES:
1197216294Ssyrinx		rval = random();
1198216294Ssyrinx		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1199216294Ssyrinx		rval = random();
1200216294Ssyrinx		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1201216294Ssyrinx		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1202216294Ssyrinx		break;
1203216294Ssyrinx	default:
1204216294Ssyrinx		break;
1205216294Ssyrinx	}
1206216294Ssyrinx}
1207216294Ssyrinx
1208216294Ssyrinxvoid
1209122394Shartisnmp_pdu_free(struct snmp_pdu *pdu)
1210122394Sharti{
1211122394Sharti	u_int i;
1212122394Sharti
1213122394Sharti	for (i = 0; i < pdu->nbindings; i++)
1214122394Sharti		snmp_value_free(&pdu->bindings[i]);
1215122394Sharti}
1216122394Sharti
1217122394Sharti/*
1218122394Sharti * Parse an ASCII SNMP value into the binary form
1219122394Sharti */
1220122394Shartiint
1221122394Shartisnmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1222122394Sharti{
1223122394Sharti	char *end;
1224122394Sharti
1225122394Sharti	switch (syntax) {
1226122394Sharti
1227122394Sharti	  case SNMP_SYNTAX_NULL:
1228122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
1229122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1230122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1231122394Sharti		if (*str != '\0')
1232122394Sharti			return (-1);
1233122394Sharti		return (0);
1234122394Sharti
1235122394Sharti	  case SNMP_SYNTAX_INTEGER:
1236122394Sharti		v->integer = strtoll(str, &end, 0);
1237122394Sharti		if (*end != '\0')
1238122394Sharti			return (-1);
1239122394Sharti		return (0);
1240122394Sharti
1241122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
1242122394Sharti	    {
1243122394Sharti		u_long len;	/* actual length of string */
1244122394Sharti		u_long alloc;	/* allocate length of string */
1245122394Sharti		u_char *octs;	/* actual octets */
1246122394Sharti		u_long oct;	/* actual octet */
1247122394Sharti		u_char *nocts;	/* to avoid memory leak */
1248122394Sharti		u_char c;	/* actual character */
1249122394Sharti
1250122394Sharti# define STUFFC(C)							\
1251122394Sharti		if (alloc == len) {					\
1252122394Sharti			alloc += 100;					\
1253122394Sharti			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1254122394Sharti				free(octs);				\
1255122394Sharti				return (-1);				\
1256122394Sharti			}						\
1257122394Sharti			octs = nocts;					\
1258122394Sharti		}							\
1259122394Sharti		octs[len++] = (C);
1260122394Sharti
1261122394Sharti		len = alloc = 0;
1262122394Sharti		octs = NULL;
1263122394Sharti
1264122394Sharti		if (*str == '"') {
1265122394Sharti			str++;
1266122394Sharti			while((c = *str++) != '\0') {
1267122394Sharti				if (c == '"') {
1268122394Sharti					if (*str != '\0') {
1269122394Sharti						free(octs);
1270122394Sharti						return (-1);
1271122394Sharti					}
1272122394Sharti					break;
1273122394Sharti				}
1274122394Sharti				if (c == '\\') {
1275122394Sharti					switch (c = *str++) {
1276122394Sharti
1277122394Sharti					  case '\\':
1278122394Sharti						break;
1279122394Sharti					  case 'a':
1280122394Sharti						c = '\a';
1281122394Sharti						break;
1282122394Sharti					  case 'b':
1283122394Sharti						c = '\b';
1284122394Sharti						break;
1285122394Sharti					  case 'f':
1286122394Sharti						c = '\f';
1287122394Sharti						break;
1288122394Sharti					  case 'n':
1289122394Sharti						c = '\n';
1290122394Sharti						break;
1291122394Sharti					  case 'r':
1292122394Sharti						c = '\r';
1293122394Sharti						break;
1294122394Sharti					  case 't':
1295122394Sharti						c = '\t';
1296122394Sharti						break;
1297122394Sharti					  case 'v':
1298122394Sharti						c = '\v';
1299122394Sharti						break;
1300122394Sharti					  case 'x':
1301122394Sharti						c = 0;
1302122394Sharti						if (!isxdigit(*str))
1303122394Sharti							break;
1304122394Sharti						if (isdigit(*str))
1305122394Sharti							c = *str++ - '0';
1306122394Sharti						else if (isupper(*str))
1307122394Sharti							c = *str++ - 'A' + 10;
1308122394Sharti						else
1309122394Sharti							c = *str++ - 'a' + 10;
1310122394Sharti						if (!isxdigit(*str))
1311122394Sharti							break;
1312122394Sharti						if (isdigit(*str))
1313122394Sharti							c += *str++ - '0';
1314122394Sharti						else if (isupper(*str))
1315122394Sharti							c += *str++ - 'A' + 10;
1316122394Sharti						else
1317122394Sharti							c += *str++ - 'a' + 10;
1318122394Sharti						break;
1319122394Sharti					  case '0': case '1': case '2':
1320122394Sharti					  case '3': case '4': case '5':
1321122394Sharti					  case '6': case '7':
1322122394Sharti						c = *str++ - '0';
1323122394Sharti						if (*str < '0' || *str > '7')
1324122394Sharti							break;
1325122394Sharti						c = *str++ - '0';
1326122394Sharti						if (*str < '0' || *str > '7')
1327122394Sharti							break;
1328122394Sharti						c = *str++ - '0';
1329122394Sharti						break;
1330122394Sharti					  default:
1331122394Sharti						break;
1332122394Sharti					}
1333122394Sharti				}
1334122394Sharti				STUFFC(c);
1335122394Sharti			}
1336122394Sharti		} else {
1337122394Sharti			while (*str != '\0') {
1338122394Sharti				oct = strtoul(str, &end, 16);
1339122394Sharti				str = end;
1340122394Sharti				if (oct > 0xff) {
1341122394Sharti					free(octs);
1342122394Sharti					return (-1);
1343122394Sharti				}
1344122394Sharti				STUFFC(oct);
1345122394Sharti				if (*str == ':')
1346122394Sharti					str++;
1347122394Sharti				else if(*str != '\0') {
1348122394Sharti					free(octs);
1349122394Sharti					return (-1);
1350122394Sharti				}
1351122394Sharti			}
1352122394Sharti		}
1353122394Sharti		v->octetstring.octets = octs;
1354122394Sharti		v->octetstring.len = len;
1355122394Sharti		return (0);
1356122394Sharti# undef STUFFC
1357122394Sharti	    }
1358122394Sharti
1359122394Sharti	  case SNMP_SYNTAX_OID:
1360122394Sharti	    {
1361122394Sharti		u_long subid;
1362122394Sharti
1363122394Sharti		v->oid.len = 0;
1364122394Sharti
1365122394Sharti		for (;;) {
1366122394Sharti			if (v->oid.len == ASN_MAXOIDLEN)
1367122394Sharti				return (-1);
1368122394Sharti			subid = strtoul(str, &end, 10);
1369122394Sharti			str = end;
1370122394Sharti			if (subid > ASN_MAXID)
1371122394Sharti				return (-1);
1372122394Sharti			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1373122394Sharti			if (*str == '\0')
1374122394Sharti				break;
1375122394Sharti			if (*str != '.')
1376122394Sharti				return (-1);
1377122394Sharti			str++;
1378122394Sharti		}
1379122394Sharti		return (0);
1380122394Sharti	    }
1381122394Sharti
1382122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
1383122394Sharti	    {
1384122394Sharti		struct hostent *he;
1385122394Sharti		u_long ip[4];
1386122394Sharti		int n;
1387122394Sharti
1388122394Sharti		if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1389122394Sharti		    &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1390122394Sharti		    ip[0] <= 0xff && ip[1] <= 0xff &&
1391122394Sharti		    ip[2] <= 0xff && ip[3] <= 0xff) {
1392122394Sharti			v->ipaddress[0] = (u_char)ip[0];
1393122394Sharti			v->ipaddress[1] = (u_char)ip[1];
1394122394Sharti			v->ipaddress[2] = (u_char)ip[2];
1395122394Sharti			v->ipaddress[3] = (u_char)ip[3];
1396122394Sharti			return (0);
1397122394Sharti		}
1398122394Sharti
1399122394Sharti		if ((he = gethostbyname(str)) == NULL)
1400122394Sharti			return (-1);
1401122394Sharti		if (he->h_addrtype != AF_INET)
1402122394Sharti			return (-1);
1403122394Sharti
1404122394Sharti		v->ipaddress[0] = he->h_addr[0];
1405122394Sharti		v->ipaddress[1] = he->h_addr[1];
1406122394Sharti		v->ipaddress[2] = he->h_addr[2];
1407122394Sharti		v->ipaddress[3] = he->h_addr[3];
1408122394Sharti		return (0);
1409122394Sharti	    }
1410122394Sharti
1411122394Sharti	  case SNMP_SYNTAX_COUNTER:
1412122394Sharti	  case SNMP_SYNTAX_GAUGE:
1413122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
1414122394Sharti	    {
1415133211Sharti		uint64_t sub;
1416122394Sharti
1417122394Sharti		sub = strtoull(str, &end, 0);
1418122394Sharti		if (*end != '\0' || sub > 0xffffffff)
1419122394Sharti			return (-1);
1420133211Sharti		v->uint32 = (uint32_t)sub;
1421122394Sharti		return (0);
1422122394Sharti	    }
1423122394Sharti
1424122394Sharti	  case SNMP_SYNTAX_COUNTER64:
1425122394Sharti		v->counter64 = strtoull(str, &end, 0);
1426122394Sharti		if (*end != '\0')
1427122394Sharti			return (-1);
1428122394Sharti		return (0);
1429122394Sharti	}
1430122394Sharti	abort();
1431122394Sharti}
1432122394Sharti
1433122394Shartistatic void
1434122394Shartisnmp_error_func(const char *fmt, ...)
1435122394Sharti{
1436122394Sharti	va_list ap;
1437122394Sharti
1438122394Sharti	va_start(ap, fmt);
1439122394Sharti	fprintf(stderr, "SNMP: ");
1440122394Sharti	vfprintf(stderr, fmt, ap);
1441122394Sharti	fprintf(stderr, "\n");
1442122394Sharti	va_end(ap);
1443122394Sharti}
1444122394Sharti
1445122394Shartistatic void
1446122394Shartisnmp_printf_func(const char *fmt, ...)
1447122394Sharti{
1448122394Sharti	va_list ap;
1449122394Sharti
1450122394Sharti	va_start(ap, fmt);
1451122394Sharti	vfprintf(stderr, fmt, ap);
1452122394Sharti	va_end(ap);
1453122394Sharti}
1454