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>
7310903Sngie *
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.
22310903Sngie *
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>
41310673Sngie#include <ctype.h>
42310673Sngie#include <errno.h>
43310673Sngie#include <netdb.h>
44122394Sharti#include <stdio.h>
45122394Sharti#include <stdlib.h>
46122394Sharti#include <stddef.h>
47122394Sharti#include <stdarg.h>
48310673Sngie#include <string.h>
49150920Sharti#ifdef HAVE_STDINT_H
50133211Sharti#include <stdint.h>
51150920Sharti#elif defined(HAVE_INTTYPES_H)
52150920Sharti#include <inttypes.h>
53150920Sharti#endif
54311603Sngie#include <netinet/in.h>
55311603Sngie#include <arpa/inet.h>
56122394Sharti
57122394Sharti#include "asn1.h"
58122394Sharti#include "snmp.h"
59122394Sharti#include "snmppriv.h"
60122394Sharti
61122394Shartistatic void snmp_error_func(const char *, ...);
62122394Shartistatic void snmp_printf_func(const char *, ...);
63122394Sharti
64122394Shartivoid (*snmp_error)(const char *, ...) = snmp_error_func;
65122394Shartivoid (*snmp_printf)(const char *, ...) = snmp_printf_func;
66122394Sharti
67122394Sharti/*
68122394Sharti * Get the next variable binding from the list.
69122394Sharti * ASN errors on the sequence or the OID are always fatal.
70122394Sharti */
71122394Shartistatic enum asn_err
72122394Shartiget_var_binding(struct asn_buf *b, struct snmp_value *binding)
73122394Sharti{
74122394Sharti	u_char type;
75122394Sharti	asn_len_t len, trailer;
76122394Sharti	enum asn_err err;
77122394Sharti
78122394Sharti	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
79122394Sharti		snmp_error("cannot parse varbind header");
80122394Sharti		return (ASN_ERR_FAILED);
81122394Sharti	}
82122394Sharti
83122394Sharti	/* temporary truncate the length so that the parser does not
84122394Sharti	 * eat up bytes behind the sequence in the case the encoding is
85122394Sharti	 * wrong of inner elements. */
86122394Sharti	trailer = b->asn_len - len;
87122394Sharti	b->asn_len = len;
88122394Sharti
89122394Sharti	if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
90122394Sharti		snmp_error("cannot parse binding objid");
91122394Sharti		return (ASN_ERR_FAILED);
92122394Sharti	}
93122394Sharti	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
94122394Sharti		snmp_error("cannot parse binding value header");
95122394Sharti		return (ASN_ERR_FAILED);
96122394Sharti	}
97122394Sharti
98122394Sharti	switch (type) {
99122394Sharti
100122394Sharti	  case ASN_TYPE_NULL:
101122394Sharti		binding->syntax = SNMP_SYNTAX_NULL;
102122394Sharti		err = asn_get_null_raw(b, len);
103122394Sharti		break;
104122394Sharti
105122394Sharti	  case ASN_TYPE_INTEGER:
106122394Sharti		binding->syntax = SNMP_SYNTAX_INTEGER;
107122394Sharti		err = asn_get_integer_raw(b, len, &binding->v.integer);
108122394Sharti		break;
109122394Sharti
110122394Sharti	  case ASN_TYPE_OCTETSTRING:
111122394Sharti		binding->syntax = SNMP_SYNTAX_OCTETSTRING;
112122394Sharti		binding->v.octetstring.octets = malloc(len);
113122394Sharti		if (binding->v.octetstring.octets == NULL) {
114122394Sharti			snmp_error("%s", strerror(errno));
115122394Sharti			return (ASN_ERR_FAILED);
116122394Sharti		}
117122394Sharti		binding->v.octetstring.len = len;
118122394Sharti		err = asn_get_octetstring_raw(b, len,
119122394Sharti		    binding->v.octetstring.octets,
120122394Sharti		    &binding->v.octetstring.len);
121122394Sharti		if (ASN_ERR_STOPPED(err)) {
122122394Sharti			free(binding->v.octetstring.octets);
123122394Sharti			binding->v.octetstring.octets = NULL;
124122394Sharti		}
125122394Sharti		break;
126122394Sharti
127122394Sharti	  case ASN_TYPE_OBJID:
128122394Sharti		binding->syntax = SNMP_SYNTAX_OID;
129122394Sharti		err = asn_get_objid_raw(b, len, &binding->v.oid);
130122394Sharti		break;
131122394Sharti
132122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
133122394Sharti		binding->syntax = SNMP_SYNTAX_IPADDRESS;
134122394Sharti		err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
135122394Sharti		break;
136122394Sharti
137122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
138122394Sharti		binding->syntax = SNMP_SYNTAX_TIMETICKS;
139122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
140122394Sharti		break;
141122394Sharti
142122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
143122394Sharti		binding->syntax = SNMP_SYNTAX_COUNTER;
144122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
145122394Sharti		break;
146122394Sharti
147122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
148122394Sharti		binding->syntax = SNMP_SYNTAX_GAUGE;
149122394Sharti		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
150122394Sharti		break;
151122394Sharti
152122394Sharti	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
153122394Sharti		binding->syntax = SNMP_SYNTAX_COUNTER64;
154122394Sharti		err = asn_get_counter64_raw(b, len, &binding->v.counter64);
155122394Sharti		break;
156122394Sharti
157122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
158122394Sharti		binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
159122394Sharti		err = asn_get_null_raw(b, len);
160122394Sharti		break;
161122394Sharti
162122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
163122394Sharti		binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
164122394Sharti		err = asn_get_null_raw(b, len);
165122394Sharti		break;
166122394Sharti
167122394Sharti	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
168122394Sharti		binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
169122394Sharti		err = asn_get_null_raw(b, len);
170122394Sharti		break;
171122394Sharti
172122394Sharti	  default:
173122394Sharti		if ((err = asn_skip(b, len)) == ASN_ERR_OK)
174122394Sharti			err = ASN_ERR_TAG;
175122394Sharti		snmp_error("bad binding value type 0x%x", type);
176122394Sharti		break;
177122394Sharti	}
178122394Sharti
179122394Sharti	if (ASN_ERR_STOPPED(err)) {
180122394Sharti		snmp_error("cannot parse binding value");
181122394Sharti		return (err);
182122394Sharti	}
183122394Sharti
184122394Sharti	if (b->asn_len != 0)
185122394Sharti		snmp_error("ignoring junk at end of binding");
186122394Sharti
187122394Sharti	b->asn_len = trailer;
188122394Sharti
189122394Sharti	return (err);
190122394Sharti}
191122394Sharti
192122394Sharti/*
193122394Sharti * Parse the different PDUs contents. Any ASN error in the outer components
194122394Sharti * are fatal. Only errors in variable values may be tolerated. If all
195122394Sharti * components can be parsed it returns either ASN_ERR_OK or the first
196122394Sharti * error that was found.
197122394Sharti */
198122394Shartienum asn_err
199122394Shartisnmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
200122394Sharti{
201122394Sharti	if (pdu->type == SNMP_PDU_TRAP) {
202122394Sharti		if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
203122394Sharti			snmp_error("cannot parse trap enterprise");
204122394Sharti			return (ASN_ERR_FAILED);
205122394Sharti		}
206122394Sharti		if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
207122394Sharti			snmp_error("cannot parse trap agent address");
208122394Sharti			return (ASN_ERR_FAILED);
209122394Sharti		}
210122394Sharti		if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
211122394Sharti			snmp_error("cannot parse 'generic-trap'");
212122394Sharti			return (ASN_ERR_FAILED);
213122394Sharti		}
214122394Sharti		if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
215122394Sharti			snmp_error("cannot parse 'specific-trap'");
216122394Sharti			return (ASN_ERR_FAILED);
217122394Sharti		}
218122394Sharti		if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
219122394Sharti			snmp_error("cannot parse trap 'time-stamp'");
220122394Sharti			return (ASN_ERR_FAILED);
221122394Sharti		}
222122394Sharti	} else {
223122394Sharti		if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
224122394Sharti			snmp_error("cannot parse 'request-id'");
225122394Sharti			return (ASN_ERR_FAILED);
226122394Sharti		}
227122394Sharti		if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
228122394Sharti			snmp_error("cannot parse 'error_status'");
229122394Sharti			return (ASN_ERR_FAILED);
230122394Sharti		}
231122394Sharti		if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
232122394Sharti			snmp_error("cannot parse 'error_index'");
233122394Sharti			return (ASN_ERR_FAILED);
234122394Sharti		}
235122394Sharti	}
236122394Sharti
237122394Sharti	if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
238122394Sharti		snmp_error("cannot get varlist header");
239122394Sharti		return (ASN_ERR_FAILED);
240122394Sharti	}
241122394Sharti
242122394Sharti	return (ASN_ERR_OK);
243122394Sharti}
244122394Sharti
245122394Shartistatic enum asn_err
246122394Shartiparse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
247122394Sharti{
248122394Sharti	asn_len_t len, trailer;
249122394Sharti	struct snmp_value *v;
250122394Sharti	enum asn_err err, err1;
251122394Sharti
252122394Sharti	err = snmp_parse_pdus_hdr(b, pdu, &len);
253122394Sharti	if (ASN_ERR_STOPPED(err))
254122394Sharti		return (err);
255122394Sharti
256122394Sharti	trailer = b->asn_len - len;
257122394Sharti
258122394Sharti	v = pdu->bindings;
259122394Sharti	err = ASN_ERR_OK;
260122394Sharti	while (b->asn_len != 0) {
261122394Sharti		if (pdu->nbindings == SNMP_MAX_BINDINGS) {
262122394Sharti			snmp_error("too many bindings (> %u) in PDU",
263122394Sharti			    SNMP_MAX_BINDINGS);
264122394Sharti			return (ASN_ERR_FAILED);
265122394Sharti		}
266122394Sharti		err1 = get_var_binding(b, v);
267122394Sharti		if (ASN_ERR_STOPPED(err1))
268122394Sharti			return (ASN_ERR_FAILED);
269122394Sharti		if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
270122394Sharti			err = err1;
271122394Sharti			*ip = pdu->nbindings + 1;
272122394Sharti		}
273122394Sharti		pdu->nbindings++;
274122394Sharti		v++;
275122394Sharti	}
276122394Sharti
277122394Sharti	b->asn_len = trailer;
278122394Sharti
279122394Sharti	return (err);
280122394Sharti}
281122394Sharti
282216294Ssyrinx
283216294Ssyrinxstatic enum asn_err
284216294Ssyrinxparse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
285216294Ssyrinx{
286216294Ssyrinx	asn_len_t octs_len;
287216294Ssyrinx	u_char buf[256]; /* XXX: calc max possible size here */
288216294Ssyrinx	struct asn_buf tb;
289216294Ssyrinx
290216294Ssyrinx	memset(buf, 0, 256);
291216294Ssyrinx	tb.asn_ptr = buf;
292216294Ssyrinx	tb.asn_len = 256;
293301661Sngie	u_int len;
294216294Ssyrinx
295301661Sngie	if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) {
296216294Ssyrinx		snmp_error("cannot parse usm header");
297216294Ssyrinx		return (ASN_ERR_FAILED);
298216294Ssyrinx	}
299301661Sngie	tb.asn_len = len;
300216294Ssyrinx
301216294Ssyrinx	if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
302216294Ssyrinx		snmp_error("cannot decode usm header");
303216294Ssyrinx		return (ASN_ERR_FAILED);
304216294Ssyrinx	}
305216294Ssyrinx
306216294Ssyrinx	octs_len = SNMP_ENGINE_ID_SIZ;
307216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
308216294Ssyrinx	    &octs_len) != ASN_ERR_OK) {
309216294Ssyrinx		snmp_error("cannot decode msg engine id");
310216294Ssyrinx		return (ASN_ERR_FAILED);
311216294Ssyrinx	}
312216294Ssyrinx	pdu->engine.engine_len = octs_len;
313216294Ssyrinx
314216294Ssyrinx	if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
315216294Ssyrinx		snmp_error("cannot decode msg engine boots");
316216294Ssyrinx		return (ASN_ERR_FAILED);
317216294Ssyrinx	}
318216294Ssyrinx
319216294Ssyrinx	if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
320216294Ssyrinx		snmp_error("cannot decode msg engine time");
321216294Ssyrinx		return (ASN_ERR_FAILED);
322216294Ssyrinx	}
323216294Ssyrinx
324216294Ssyrinx	octs_len = SNMP_ADM_STR32_SIZ - 1;
325216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
326216294Ssyrinx	    != ASN_ERR_OK) {
327216294Ssyrinx		snmp_error("cannot decode msg user name");
328216294Ssyrinx		return (ASN_ERR_FAILED);
329216294Ssyrinx	}
330216294Ssyrinx	pdu->user.sec_name[octs_len] = '\0';
331216294Ssyrinx
332216294Ssyrinx	octs_len = sizeof(pdu->msg_digest);
333216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
334216294Ssyrinx	    ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
335216294Ssyrinx	    octs_len != sizeof(pdu->msg_digest))) {
336216294Ssyrinx		snmp_error("cannot decode msg authentication param");
337216294Ssyrinx		return (ASN_ERR_FAILED);
338216294Ssyrinx	}
339216294Ssyrinx
340216294Ssyrinx	octs_len = sizeof(pdu->msg_salt);
341216294Ssyrinx	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
342216294Ssyrinx	    ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
343216294Ssyrinx	    octs_len != sizeof(pdu->msg_salt))) {
344216294Ssyrinx		snmp_error("cannot decode msg authentication param");
345216294Ssyrinx		return (ASN_ERR_FAILED);
346216294Ssyrinx	}
347216294Ssyrinx
348216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
349216294Ssyrinx		pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
350216294Ssyrinx		pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
351216294Ssyrinx	}
352216294Ssyrinx
353216294Ssyrinx	return (ASN_ERR_OK);
354216294Ssyrinx}
355216294Ssyrinx
356216294Ssyrinxstatic enum snmp_code
357216294Ssyrinxpdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
358216294Ssyrinx{
359216294Ssyrinx	u_char buf[256], *sptr;
360310910Sngie	struct asn_buf tb;
361310910Sngie	size_t auth_off, moved = 0;
362216294Ssyrinx
363216294Ssyrinx	auth_off = 0;
364216294Ssyrinx	memset(buf, 0, 256);
365216294Ssyrinx	tb.asn_ptr = buf;
366216294Ssyrinx	tb.asn_len = 256;
367216294Ssyrinx
368216294Ssyrinx	if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
369216294Ssyrinx	    &sptr) != ASN_ERR_OK)
370216294Ssyrinx		return (SNMP_CODE_FAILED);
371216294Ssyrinx
372216294Ssyrinx	if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
373216294Ssyrinx	    pdu->engine.engine_len) != ASN_ERR_OK)
374216294Ssyrinx		return (SNMP_CODE_FAILED);
375216294Ssyrinx
376216294Ssyrinx	if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
377216294Ssyrinx		return (SNMP_CODE_FAILED);
378216294Ssyrinx
379216294Ssyrinx	if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
380216294Ssyrinx		return (SNMP_CODE_FAILED);
381216294Ssyrinx
382216294Ssyrinx	if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
383216294Ssyrinx	    strlen(pdu->user.sec_name)) != ASN_ERR_OK)
384216294Ssyrinx		return (SNMP_CODE_FAILED);
385216294Ssyrinx
386216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
387216294Ssyrinx		auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
388216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
389216294Ssyrinx		    sizeof(pdu->msg_digest)) != ASN_ERR_OK)
390216294Ssyrinx			return (SNMP_CODE_FAILED);
391216294Ssyrinx	} else {
392216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
393216294Ssyrinx		    != ASN_ERR_OK)
394216294Ssyrinx			return (SNMP_CODE_FAILED);
395216294Ssyrinx	}
396216294Ssyrinx
397216294Ssyrinx	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
398216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
399216294Ssyrinx		    sizeof(pdu->msg_salt)) != ASN_ERR_OK)
400216294Ssyrinx			return (SNMP_CODE_FAILED);
401216294Ssyrinx	} else {
402216294Ssyrinx		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
403216294Ssyrinx		    != ASN_ERR_OK)
404216294Ssyrinx			return (SNMP_CODE_FAILED);
405216294Ssyrinx	}
406216294Ssyrinx
407216294Ssyrinx	if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
408216294Ssyrinx		return (SNMP_CODE_FAILED);
409216294Ssyrinx
410216294Ssyrinx	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
411216294Ssyrinx		pdu->digest_ptr = b->asn_ptr + auth_off - moved;
412216294Ssyrinx
413216294Ssyrinx	if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
414216294Ssyrinx		return (SNMP_CODE_FAILED);
415216294Ssyrinx	pdu->digest_ptr += ASN_MAXLENLEN;
416216294Ssyrinx
417216294Ssyrinx	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
418216294Ssyrinx	    ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
419216294Ssyrinx			return (SNMP_CODE_FAILED);
420216294Ssyrinx
421216294Ssyrinx	return (SNMP_CODE_OK);
422216294Ssyrinx}
423216294Ssyrinx
424122394Sharti/*
425216294Ssyrinx * Decode the PDU except for the variable bindings itself.
426216294Ssyrinx * If decoding fails because of a bad binding, but the rest can be
427216294Ssyrinx * decoded, ip points to the index of the failed variable (errors
428216294Ssyrinx * OORANGE, BADLEN or BADVERS).
429122394Sharti */
430216294Ssyrinxenum snmp_code
431216294Ssyrinxsnmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
432122394Sharti{
433216294Ssyrinx	enum snmp_code code;
434216294Ssyrinx
435216294Ssyrinx	if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
436216294Ssyrinx		return (code);
437216294Ssyrinx
438216294Ssyrinx	if (pdu->version == SNMP_V3) {
439216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
440216294Ssyrinx			return (SNMP_CODE_FAILED);
441216294Ssyrinx		if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
442216294Ssyrinx			return (code);
443216294Ssyrinx	}
444216294Ssyrinx
445216294Ssyrinx	code = snmp_pdu_decode_scoped(b, pdu, ip);
446216294Ssyrinx
447216294Ssyrinx	switch (code) {
448216294Ssyrinx	  case SNMP_CODE_FAILED:
449216294Ssyrinx		snmp_pdu_free(pdu);
450216294Ssyrinx		break;
451216294Ssyrinx
452216294Ssyrinx	  case SNMP_CODE_BADENC:
453216294Ssyrinx		if (pdu->version == SNMP_Verr)
454216294Ssyrinx			return (SNMP_CODE_BADVERS);
455216294Ssyrinx
456216294Ssyrinx	  default:
457216294Ssyrinx		break;
458216294Ssyrinx	}
459216294Ssyrinx
460216294Ssyrinx	return (code);
461216294Ssyrinx}
462216294Ssyrinx
463216294Ssyrinxenum snmp_code
464216294Ssyrinxsnmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
465216294Ssyrinx{
466122394Sharti	int32_t version;
467216294Ssyrinx	u_int octs_len;
468216294Ssyrinx	asn_len_t len;
469122394Sharti
470216294Ssyrinx	pdu->outer_ptr = b->asn_ptr;
471216294Ssyrinx	pdu->outer_len = b->asn_len;
472216294Ssyrinx
473216294Ssyrinx	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
474216294Ssyrinx		snmp_error("cannot decode pdu header");
475216294Ssyrinx		return (SNMP_CODE_FAILED);
476216294Ssyrinx	}
477216294Ssyrinx	if (b->asn_len < len) {
478216294Ssyrinx		snmp_error("outer sequence value too short");
479216294Ssyrinx		return (SNMP_CODE_FAILED);
480216294Ssyrinx	}
481216294Ssyrinx	if (b->asn_len != len) {
482216294Ssyrinx		snmp_error("ignoring trailing junk in message");
483216294Ssyrinx		b->asn_len = len;
484216294Ssyrinx	}
485216294Ssyrinx
486122394Sharti	if (asn_get_integer(b, &version) != ASN_ERR_OK) {
487122394Sharti		snmp_error("cannot decode version");
488216294Ssyrinx		return (SNMP_CODE_FAILED);
489122394Sharti	}
490122394Sharti
491216294Ssyrinx	if (version == 0)
492122394Sharti		pdu->version = SNMP_V1;
493216294Ssyrinx	else if (version == 1)
494122394Sharti		pdu->version = SNMP_V2c;
495216294Ssyrinx	else if (version == 3)
496216294Ssyrinx		pdu->version = SNMP_V3;
497216294Ssyrinx	else {
498122394Sharti		pdu->version = SNMP_Verr;
499122394Sharti		snmp_error("unsupported SNMP version");
500216294Ssyrinx		return (SNMP_CODE_BADENC);
501122394Sharti	}
502122394Sharti
503216294Ssyrinx	if (pdu->version == SNMP_V3) {
504216294Ssyrinx		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
505216294Ssyrinx			snmp_error("cannot decode pdu global data header");
506216294Ssyrinx			return (SNMP_CODE_FAILED);
507216294Ssyrinx		}
508216294Ssyrinx
509216294Ssyrinx		if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
510216294Ssyrinx			snmp_error("cannot decode msg indetifier");
511216294Ssyrinx			return (SNMP_CODE_FAILED);
512216294Ssyrinx		}
513216294Ssyrinx
514216294Ssyrinx		if (asn_get_integer(b, &pdu->engine.max_msg_size)
515216294Ssyrinx		    != ASN_ERR_OK) {
516216294Ssyrinx			snmp_error("cannot decode msg size");
517216294Ssyrinx			return (SNMP_CODE_FAILED);
518216294Ssyrinx		}
519216294Ssyrinx
520216294Ssyrinx		octs_len = 1;
521216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->flags,
522216294Ssyrinx		    &octs_len) != ASN_ERR_OK) {
523216294Ssyrinx			snmp_error("cannot decode msg flags");
524216294Ssyrinx			return (SNMP_CODE_FAILED);
525216294Ssyrinx		}
526216294Ssyrinx
527216294Ssyrinx		if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
528216294Ssyrinx			snmp_error("cannot decode msg size");
529216294Ssyrinx			return (SNMP_CODE_FAILED);
530216294Ssyrinx		}
531216294Ssyrinx
532216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
533216294Ssyrinx			return (SNMP_CODE_FAILED);
534216294Ssyrinx
535216294Ssyrinx		if (parse_secparams(b, pdu) != ASN_ERR_OK)
536216294Ssyrinx			return (SNMP_CODE_FAILED);
537216294Ssyrinx	} else {
538216294Ssyrinx		octs_len = SNMP_COMMUNITY_MAXLEN;
539216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)pdu->community,
540216294Ssyrinx		    &octs_len) != ASN_ERR_OK) {
541216294Ssyrinx			snmp_error("cannot decode community");
542216294Ssyrinx			return (SNMP_CODE_FAILED);
543216294Ssyrinx		}
544216294Ssyrinx		pdu->community[octs_len] = '\0';
545122394Sharti	}
546122394Sharti
547216294Ssyrinx	return (SNMP_CODE_OK);
548216294Ssyrinx}
549216294Ssyrinx
550216294Ssyrinxenum snmp_code
551216294Ssyrinxsnmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
552216294Ssyrinx{
553216294Ssyrinx	u_char type;
554216294Ssyrinx	asn_len_t len, trailer;
555216294Ssyrinx	enum asn_err err;
556216294Ssyrinx
557216294Ssyrinx	if (pdu->version == SNMP_V3) {
558216294Ssyrinx		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
559216294Ssyrinx			snmp_error("cannot decode scoped pdu header");
560216294Ssyrinx			return (SNMP_CODE_FAILED);
561216294Ssyrinx		}
562216294Ssyrinx
563216294Ssyrinx		len = SNMP_ENGINE_ID_SIZ;
564216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
565216294Ssyrinx		    &len) != ASN_ERR_OK) {
566216294Ssyrinx			snmp_error("cannot decode msg context engine");
567216294Ssyrinx			return (SNMP_CODE_FAILED);
568216294Ssyrinx		}
569216294Ssyrinx		pdu->context_engine_len = len;
570216294Ssyrinx
571216294Ssyrinx		len = SNMP_CONTEXT_NAME_SIZ;
572216294Ssyrinx		if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
573216294Ssyrinx		    &len) != ASN_ERR_OK) {
574216294Ssyrinx			snmp_error("cannot decode msg context name");
575216294Ssyrinx			return (SNMP_CODE_FAILED);
576216294Ssyrinx		}
577216294Ssyrinx		pdu->context_name[len] = '\0';
578216294Ssyrinx	}
579216294Ssyrinx
580216294Ssyrinx	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
581122394Sharti		snmp_error("cannot get pdu header");
582216294Ssyrinx		return (SNMP_CODE_FAILED);
583122394Sharti	}
584122394Sharti	if ((type & ~ASN_TYPE_MASK) !=
585122394Sharti	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
586122394Sharti		snmp_error("bad pdu header tag");
587216294Ssyrinx		return (SNMP_CODE_FAILED);
588122394Sharti	}
589122394Sharti	pdu->type = type & ASN_TYPE_MASK;
590122394Sharti
591122394Sharti	switch (pdu->type) {
592122394Sharti
593122394Sharti	  case SNMP_PDU_GET:
594122394Sharti	  case SNMP_PDU_GETNEXT:
595122394Sharti	  case SNMP_PDU_RESPONSE:
596122394Sharti	  case SNMP_PDU_SET:
597122394Sharti		break;
598122394Sharti
599122394Sharti	  case SNMP_PDU_TRAP:
600122394Sharti		if (pdu->version != SNMP_V1) {
601122394Sharti			snmp_error("bad pdu type %u", pdu->type);
602216294Ssyrinx			return (SNMP_CODE_FAILED);
603122394Sharti		}
604122394Sharti		break;
605122394Sharti
606122394Sharti	  case SNMP_PDU_GETBULK:
607122394Sharti	  case SNMP_PDU_INFORM:
608122394Sharti	  case SNMP_PDU_TRAP2:
609122394Sharti	  case SNMP_PDU_REPORT:
610122394Sharti		if (pdu->version == SNMP_V1) {
611122394Sharti			snmp_error("bad pdu type %u", pdu->type);
612216294Ssyrinx			return (SNMP_CODE_FAILED);
613122394Sharti		}
614122394Sharti		break;
615122394Sharti
616122394Sharti	  default:
617122394Sharti		snmp_error("bad pdu type %u", pdu->type);
618216294Ssyrinx		return (SNMP_CODE_FAILED);
619122394Sharti	}
620122394Sharti
621122394Sharti	trailer = b->asn_len - len;
622122394Sharti	b->asn_len = len;
623122394Sharti
624122394Sharti	err = parse_pdus(b, pdu, ip);
625122394Sharti	if (ASN_ERR_STOPPED(err))
626216294Ssyrinx		return (SNMP_CODE_FAILED);
627122394Sharti
628122394Sharti	if (b->asn_len != 0)
629122394Sharti		snmp_error("ignoring trailing junk after pdu");
630122394Sharti
631122394Sharti	b->asn_len = trailer;
632122394Sharti
633216294Ssyrinx	return (SNMP_CODE_OK);
634122394Sharti}
635122394Sharti
636122394Shartienum snmp_code
637216294Ssyrinxsnmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
638122394Sharti{
639216294Ssyrinx	u_char type;
640216294Ssyrinx	enum snmp_code code;
641216294Ssyrinx	uint8_t	digest[SNMP_USM_AUTH_SIZE];
642122394Sharti
643216294Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
644216294Ssyrinx	    (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
645216294Ssyrinx		return (SNMP_CODE_BADSECLEVEL);
646122394Sharti
647216482Ssyrinx	if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
648216294Ssyrinx	    SNMP_CODE_OK)
649122394Sharti		return (SNMP_CODE_FAILED);
650216294Ssyrinx
651216294Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
652216294Ssyrinx	    memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
653216294Ssyrinx		return (SNMP_CODE_BADDIGEST);
654216294Ssyrinx
655216294Ssyrinx	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
656216294Ssyrinx	    &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
657216294Ssyrinx		snmp_error("cannot decode encrypted pdu");
658122394Sharti		return (SNMP_CODE_FAILED);
659122394Sharti	}
660216294Ssyrinx	pdu->scoped_ptr = b->asn_ptr;
661122394Sharti
662216294Ssyrinx	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
663216294Ssyrinx	    (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
664216294Ssyrinx		return (SNMP_CODE_BADSECLEVEL);
665122394Sharti
666216482Ssyrinx	if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
667122394Sharti		return (SNMP_CODE_FAILED);
668122394Sharti
669216294Ssyrinx	return (code);
670122394Sharti}
671122394Sharti
672122394Sharti/*
673124861Sharti * Check whether what we have is the complete PDU by snooping at the
674124861Sharti * enclosing structure header. This returns:
675124861Sharti *   -1		if there are ASN.1 errors
676124861Sharti *    0		if we need more data
677124861Sharti *  > 0		the length of this PDU
678124861Sharti */
679124861Shartiint
680124861Shartisnmp_pdu_snoop(const struct asn_buf *b0)
681124861Sharti{
682124861Sharti	u_int length;
683124861Sharti	asn_len_t len;
684124861Sharti	struct asn_buf b = *b0;
685124861Sharti
686124861Sharti	/* <0x10|0x20> <len> <data...> */
687310903Sngie
688124861Sharti	if (b.asn_len == 0)
689124861Sharti		return (0);
690124861Sharti	if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
691124861Sharti		asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
692124861Sharti		return (-1);
693124861Sharti	}
694124861Sharti	b.asn_len--;
695124861Sharti	b.asn_cptr++;
696124861Sharti
697124861Sharti	if (b.asn_len == 0)
698124861Sharti		return (0);
699124861Sharti
700124861Sharti	if (*b.asn_cptr & 0x80) {
701124861Sharti		/* long length */
702124861Sharti		length = *b.asn_cptr++ & 0x7f;
703124861Sharti		b.asn_len--;
704124861Sharti		if (length == 0) {
705124861Sharti			asn_error(&b, "indefinite length not supported");
706124861Sharti			return (-1);
707124861Sharti		}
708124861Sharti		if (length > ASN_MAXLENLEN) {
709124861Sharti			asn_error(&b, "long length too long (%u)", length);
710124861Sharti			return (-1);
711124861Sharti		}
712124861Sharti		if (length > b.asn_len)
713124861Sharti			return (0);
714124861Sharti		len = 0;
715124861Sharti		while (length--) {
716124861Sharti			len = (len << 8) | *b.asn_cptr++;
717124861Sharti			b.asn_len--;
718124861Sharti		}
719124861Sharti	} else {
720124861Sharti		len = *b.asn_cptr++;
721124861Sharti		b.asn_len--;
722124861Sharti	}
723124861Sharti
724124861Sharti	if (len > b.asn_len)
725124861Sharti		return (0);
726124861Sharti
727124861Sharti	return (len + b.asn_cptr - b0->asn_cptr);
728124861Sharti}
729124861Sharti
730124861Sharti/*
731122394Sharti * Encode the SNMP PDU without the variable bindings field.
732122394Sharti * We do this the rather uneffective way by
733122394Sharti * moving things around and assuming that the length field will never
734122394Sharti * use more than 2 bytes.
735122394Sharti * We need a number of pointers to apply the fixes afterwards.
736122394Sharti */
737122394Shartienum snmp_code
738122394Shartisnmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
739122394Sharti{
740122394Sharti	enum asn_err err;
741216294Ssyrinx	u_char *v3_hdr_ptr;
742122394Sharti
743122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
744122394Sharti	    &pdu->outer_ptr) != ASN_ERR_OK)
745122394Sharti		return (SNMP_CODE_FAILED);
746122394Sharti
747122394Sharti	if (pdu->version == SNMP_V1)
748122394Sharti		err = asn_put_integer(b, 0);
749122394Sharti	else if (pdu->version == SNMP_V2c)
750122394Sharti		err = asn_put_integer(b, 1);
751216294Ssyrinx	else if (pdu->version == SNMP_V3)
752216294Ssyrinx		err = asn_put_integer(b, 3);
753122394Sharti	else
754122394Sharti		return (SNMP_CODE_BADVERS);
755122394Sharti	if (err != ASN_ERR_OK)
756122394Sharti		return (SNMP_CODE_FAILED);
757122394Sharti
758216294Ssyrinx	if (pdu->version == SNMP_V3) {
759216294Ssyrinx		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
760216294Ssyrinx		    ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
761216294Ssyrinx			return (SNMP_CODE_FAILED);
762310903Sngie
763216294Ssyrinx		if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
764216294Ssyrinx			return (SNMP_CODE_FAILED);
765122394Sharti
766216294Ssyrinx		if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
767216294Ssyrinx			return (SNMP_CODE_FAILED);
768216294Ssyrinx
769216294Ssyrinx		if (pdu->type != SNMP_PDU_RESPONSE &&
770216294Ssyrinx		    pdu->type != SNMP_PDU_TRAP &&
771216594Ssyrinx		    pdu->type != SNMP_PDU_TRAP2 &&
772216294Ssyrinx		    pdu->type != SNMP_PDU_REPORT)
773216294Ssyrinx			pdu->flags |= SNMP_MSG_REPORT_FLAG;
774216294Ssyrinx
775216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
776216294Ssyrinx		    != ASN_ERR_OK)
777216294Ssyrinx			return (SNMP_CODE_FAILED);
778216294Ssyrinx
779216294Ssyrinx		if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
780216294Ssyrinx			return (SNMP_CODE_FAILED);
781216294Ssyrinx
782216294Ssyrinx		if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
783216294Ssyrinx			return (SNMP_CODE_FAILED);
784216294Ssyrinx
785216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
786216294Ssyrinx			return (SNMP_CODE_FAILED);
787216294Ssyrinx
788216294Ssyrinx		if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
789216294Ssyrinx			return (SNMP_CODE_FAILED);
790216294Ssyrinx
791216294Ssyrinx		/*  View-based Access Conntrol information */
792216294Ssyrinx		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
793216294Ssyrinx		    ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
794216294Ssyrinx			return (SNMP_CODE_FAILED);
795216294Ssyrinx
796216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
797216294Ssyrinx		    pdu->context_engine_len) != ASN_ERR_OK)
798216294Ssyrinx			return (SNMP_CODE_FAILED);
799216294Ssyrinx
800216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->context_name,
801216294Ssyrinx		    strlen(pdu->context_name)) != ASN_ERR_OK)
802216294Ssyrinx			return (SNMP_CODE_FAILED);
803216294Ssyrinx	} else {
804216294Ssyrinx		if (asn_put_octetstring(b, (u_char *)pdu->community,
805216294Ssyrinx		    strlen(pdu->community)) != ASN_ERR_OK)
806216294Ssyrinx			return (SNMP_CODE_FAILED);
807216294Ssyrinx	}
808216294Ssyrinx
809122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
810122394Sharti	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
811122394Sharti		return (SNMP_CODE_FAILED);
812122394Sharti
813122394Sharti	if (pdu->type == SNMP_PDU_TRAP) {
814122394Sharti		if (pdu->version != SNMP_V1 ||
815122394Sharti		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
816122394Sharti		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
817122394Sharti		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
818122394Sharti		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
819122394Sharti		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
820122394Sharti			return (SNMP_CODE_FAILED);
821122394Sharti	} else {
822122394Sharti		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
823122394Sharti		    pdu->type == SNMP_PDU_INFORM ||
824122394Sharti		    pdu->type == SNMP_PDU_TRAP2 ||
825122394Sharti		    pdu->type == SNMP_PDU_REPORT))
826122394Sharti			return (SNMP_CODE_FAILED);
827122394Sharti
828122394Sharti		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
829122394Sharti		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
830122394Sharti		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
831122394Sharti			return (SNMP_CODE_FAILED);
832122394Sharti	}
833122394Sharti
834122394Sharti	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
835122394Sharti	    &pdu->vars_ptr) != ASN_ERR_OK)
836122394Sharti		return (SNMP_CODE_FAILED);
837122394Sharti
838122394Sharti	return (SNMP_CODE_OK);
839122394Sharti}
840122394Sharti
841216294Ssyrinxstatic enum asn_err
842216294Ssyrinxsnmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
843216294Ssyrinx{
844216294Ssyrinx	asn_len_t padlen;
845216294Ssyrinx
846216294Ssyrinx	if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
847216294Ssyrinx		padlen = 8 - (pdu->scoped_len % 8);
848216294Ssyrinx		if (asn_pad(b, padlen) != ASN_ERR_OK)
849216294Ssyrinx			return (ASN_ERR_FAILED);
850216294Ssyrinx		pdu->scoped_len += padlen;
851216294Ssyrinx	}
852216294Ssyrinx
853216294Ssyrinx	return (ASN_ERR_OK);
854216294Ssyrinx}
855216294Ssyrinx
856122394Shartienum snmp_code
857216294Ssyrinxsnmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
858122394Sharti{
859216294Ssyrinx	size_t moved = 0;
860216294Ssyrinx	enum snmp_code code;
861216294Ssyrinx
862216294Ssyrinx	if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
863216294Ssyrinx	    asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
864122394Sharti		return (SNMP_CODE_FAILED);
865216294Ssyrinx
866216294Ssyrinx	if (pdu->version == SNMP_V3) {
867216294Ssyrinx		if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
868216294Ssyrinx			return (SNMP_CODE_FAILED);
869216294Ssyrinx
870216294Ssyrinx		pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
871301661Sngie		if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK)
872216294Ssyrinx			return (SNMP_CODE_FAILED);
873216294Ssyrinx
874216294Ssyrinx		if (pdu->security_model != SNMP_SECMODEL_USM)
875216294Ssyrinx			return (SNMP_CODE_FAILED);
876216294Ssyrinx
877216482Ssyrinx		if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
878216294Ssyrinx			return (SNMP_CODE_FAILED);
879216294Ssyrinx
880216294Ssyrinx		if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
881216294Ssyrinx		    asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
882216294Ssyrinx			return (SNMP_CODE_FAILED);
883216294Ssyrinx	}
884216294Ssyrinx
885216294Ssyrinx	if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
886216294Ssyrinx		return (SNMP_CODE_FAILED);
887216294Ssyrinx
888216294Ssyrinx	pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
889216294Ssyrinx	pdu->digest_ptr -= moved;
890216294Ssyrinx
891216294Ssyrinx	if (pdu->version == SNMP_V3) {
892216482Ssyrinx		if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
893216294Ssyrinx		    SNMP_CODE_OK)
894216294Ssyrinx			return (SNMP_CODE_FAILED);
895216294Ssyrinx
896216294Ssyrinx		if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
897216294Ssyrinx			memcpy(pdu->digest_ptr, pdu->msg_digest,
898216294Ssyrinx			    sizeof(pdu->msg_digest));
899216294Ssyrinx	}
900216294Ssyrinx
901122394Sharti	return (SNMP_CODE_OK);
902122394Sharti}
903122394Sharti
904122394Sharti/*
905122394Sharti * Encode a binding. Caller must ensure, that the syntax is ok for that version.
906122394Sharti * Be sure not to cobber b, when something fails.
907122394Sharti */
908122394Shartienum asn_err
909122394Shartisnmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
910122394Sharti{
911122394Sharti	u_char *ptr;
912122394Sharti	enum asn_err err;
913122394Sharti	struct asn_buf save = *b;
914122394Sharti
915122394Sharti	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
916122394Sharti	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
917122394Sharti		*b = save;
918122394Sharti		return (err);
919122394Sharti	}
920122394Sharti
921122394Sharti	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
922122394Sharti		*b = save;
923122394Sharti		return (err);
924122394Sharti	}
925122394Sharti
926122394Sharti	switch (binding->syntax) {
927122394Sharti
928122394Sharti	  case SNMP_SYNTAX_NULL:
929122394Sharti		err = asn_put_null(b);
930122394Sharti		break;
931122394Sharti
932122394Sharti	  case SNMP_SYNTAX_INTEGER:
933122394Sharti		err = asn_put_integer(b, binding->v.integer);
934122394Sharti		break;
935122394Sharti
936122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
937122394Sharti		err = asn_put_octetstring(b, binding->v.octetstring.octets,
938122394Sharti		    binding->v.octetstring.len);
939122394Sharti		break;
940122394Sharti
941122394Sharti	  case SNMP_SYNTAX_OID:
942122394Sharti		err = asn_put_objid(b, &binding->v.oid);
943122394Sharti		break;
944122394Sharti
945122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
946122394Sharti		err = asn_put_ipaddress(b, binding->v.ipaddress);
947122394Sharti		break;
948122394Sharti
949122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
950122394Sharti		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
951122394Sharti		break;
952122394Sharti
953122394Sharti	  case SNMP_SYNTAX_COUNTER:
954122394Sharti		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
955122394Sharti		break;
956122394Sharti
957122394Sharti	  case SNMP_SYNTAX_GAUGE:
958122394Sharti		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
959122394Sharti		break;
960122394Sharti
961122394Sharti	  case SNMP_SYNTAX_COUNTER64:
962122394Sharti		err = asn_put_counter64(b, binding->v.counter64);
963122394Sharti		break;
964122394Sharti
965122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
966122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
967122394Sharti		break;
968122394Sharti
969122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
970122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
971122394Sharti		break;
972122394Sharti
973122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
974122394Sharti		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
975122394Sharti		break;
976122394Sharti	}
977122394Sharti
978122394Sharti	if (err != ASN_ERR_OK) {
979122394Sharti		*b = save;
980122394Sharti		return (err);
981122394Sharti	}
982122394Sharti
983216294Ssyrinx	err = asn_commit_header(b, ptr, NULL);
984122394Sharti	if (err != ASN_ERR_OK) {
985122394Sharti		*b = save;
986122394Sharti		return (err);
987122394Sharti	}
988122394Sharti
989122394Sharti	return (ASN_ERR_OK);
990122394Sharti}
991122394Sharti
992122394Sharti/*
993122394Sharti * Encode an PDU.
994122394Sharti */
995122394Shartienum snmp_code
996122394Shartisnmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
997122394Sharti{
998122394Sharti	u_int idx;
999122394Sharti	enum snmp_code err;
1000122394Sharti
1001122394Sharti	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
1002122394Sharti		return (err);
1003122394Sharti	for (idx = 0; idx < pdu->nbindings; idx++)
1004301661Sngie		if (snmp_binding_encode(resp_b, &pdu->bindings[idx])
1005122394Sharti		    != ASN_ERR_OK)
1006122394Sharti			return (SNMP_CODE_FAILED);
1007122394Sharti
1008122394Sharti	return (snmp_fix_encoding(resp_b, pdu));
1009122394Sharti}
1010122394Sharti
1011122394Shartistatic void
1012122394Shartidump_binding(const struct snmp_value *b)
1013122394Sharti{
1014122394Sharti	u_int i;
1015122394Sharti	char buf[ASN_OIDSTRLEN];
1016122394Sharti
1017122394Sharti	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1018122394Sharti	switch (b->syntax) {
1019122394Sharti
1020122394Sharti	  case SNMP_SYNTAX_NULL:
1021122394Sharti		snmp_printf("NULL");
1022122394Sharti		break;
1023122394Sharti
1024122394Sharti	  case SNMP_SYNTAX_INTEGER:
1025122394Sharti		snmp_printf("INTEGER %d", b->v.integer);
1026122394Sharti		break;
1027122394Sharti
1028122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
1029122394Sharti		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1030122394Sharti		for (i = 0; i < b->v.octetstring.len; i++)
1031122394Sharti			snmp_printf(" %02x", b->v.octetstring.octets[i]);
1032122394Sharti		break;
1033122394Sharti
1034122394Sharti	  case SNMP_SYNTAX_OID:
1035122394Sharti		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1036122394Sharti		break;
1037122394Sharti
1038122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
1039122394Sharti		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1040122394Sharti		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1041122394Sharti		break;
1042122394Sharti
1043122394Sharti	  case SNMP_SYNTAX_COUNTER:
1044122394Sharti		snmp_printf("COUNTER %u", b->v.uint32);
1045122394Sharti		break;
1046122394Sharti
1047122394Sharti	  case SNMP_SYNTAX_GAUGE:
1048122394Sharti		snmp_printf("GAUGE %u", b->v.uint32);
1049122394Sharti		break;
1050122394Sharti
1051122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
1052122394Sharti		snmp_printf("TIMETICKS %u", b->v.uint32);
1053122394Sharti		break;
1054122394Sharti
1055122394Sharti	  case SNMP_SYNTAX_COUNTER64:
1056122394Sharti		snmp_printf("COUNTER64 %lld", b->v.counter64);
1057122394Sharti		break;
1058122394Sharti
1059122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
1060122394Sharti		snmp_printf("NoSuchObject");
1061122394Sharti		break;
1062122394Sharti
1063122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1064122394Sharti		snmp_printf("NoSuchInstance");
1065122394Sharti		break;
1066122394Sharti
1067122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1068122394Sharti		snmp_printf("EndOfMibView");
1069122394Sharti		break;
1070122394Sharti
1071122394Sharti	  default:
1072122394Sharti		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1073122394Sharti		break;
1074122394Sharti	}
1075122394Sharti}
1076122394Sharti
1077122394Shartistatic __inline void
1078122394Shartidump_bindings(const struct snmp_pdu *pdu)
1079122394Sharti{
1080122394Sharti	u_int i;
1081122394Sharti
1082122394Sharti	for (i = 0; i < pdu->nbindings; i++) {
1083122394Sharti		snmp_printf(" [%u]: ", i);
1084122394Sharti		dump_binding(&pdu->bindings[i]);
1085122394Sharti		snmp_printf("\n");
1086122394Sharti	}
1087122394Sharti}
1088122394Sharti
1089122394Shartistatic __inline void
1090122394Shartidump_notrap(const struct snmp_pdu *pdu)
1091122394Sharti{
1092122394Sharti	snmp_printf(" request_id=%d", pdu->request_id);
1093122394Sharti	snmp_printf(" error_status=%d", pdu->error_status);
1094122394Sharti	snmp_printf(" error_index=%d\n", pdu->error_index);
1095122394Sharti	dump_bindings(pdu);
1096122394Sharti}
1097122394Sharti
1098122394Shartivoid
1099122394Shartisnmp_pdu_dump(const struct snmp_pdu *pdu)
1100122394Sharti{
1101122394Sharti	char buf[ASN_OIDSTRLEN];
1102122394Sharti	const char *vers;
1103122394Sharti	static const char *types[] = {
1104122394Sharti		[SNMP_PDU_GET] =	"GET",
1105122394Sharti		[SNMP_PDU_GETNEXT] =	"GETNEXT",
1106122394Sharti		[SNMP_PDU_RESPONSE] =	"RESPONSE",
1107122394Sharti		[SNMP_PDU_SET] =	"SET",
1108122394Sharti		[SNMP_PDU_TRAP] =	"TRAPv1",
1109122394Sharti		[SNMP_PDU_GETBULK] =	"GETBULK",
1110122394Sharti		[SNMP_PDU_INFORM] =	"INFORM",
1111122394Sharti		[SNMP_PDU_TRAP2] =	"TRAPv2",
1112122394Sharti		[SNMP_PDU_REPORT] =	"REPORT",
1113122394Sharti	};
1114122394Sharti
1115122394Sharti	if (pdu->version == SNMP_V1)
1116122394Sharti		vers = "SNMPv1";
1117122394Sharti	else if (pdu->version == SNMP_V2c)
1118122394Sharti		vers = "SNMPv2c";
1119216294Ssyrinx	else if (pdu->version == SNMP_V3)
1120216294Ssyrinx		vers = "SNMPv3";
1121122394Sharti	else
1122122394Sharti		vers = "v?";
1123122394Sharti
1124122394Sharti	switch (pdu->type) {
1125122394Sharti	  case SNMP_PDU_TRAP:
1126122394Sharti		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1127122394Sharti		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1128122394Sharti		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1129122394Sharti		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1130122394Sharti		snmp_printf(" generic_trap=%d", pdu->generic_trap);
1131122394Sharti		snmp_printf(" specific_trap=%d", pdu->specific_trap);
1132122394Sharti		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1133122394Sharti		dump_bindings(pdu);
1134122394Sharti		break;
1135122394Sharti
1136122394Sharti	  case SNMP_PDU_GET:
1137122394Sharti	  case SNMP_PDU_GETNEXT:
1138122394Sharti	  case SNMP_PDU_RESPONSE:
1139122394Sharti	  case SNMP_PDU_SET:
1140122394Sharti	  case SNMP_PDU_GETBULK:
1141122394Sharti	  case SNMP_PDU_INFORM:
1142122394Sharti	  case SNMP_PDU_TRAP2:
1143122394Sharti	  case SNMP_PDU_REPORT:
1144122394Sharti		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1145122394Sharti		dump_notrap(pdu);
1146122394Sharti		break;
1147122394Sharti
1148122394Sharti	  default:
1149122394Sharti		snmp_printf("bad pdu type %u\n", pdu->type);
1150122394Sharti		break;
1151122394Sharti	}
1152122394Sharti}
1153122394Sharti
1154122394Shartivoid
1155122394Shartisnmp_value_free(struct snmp_value *value)
1156122394Sharti{
1157312047Sngie
1158312047Sngie	if (value->syntax == SNMP_SYNTAX_OCTETSTRING) {
1159122394Sharti		free(value->v.octetstring.octets);
1160312047Sngie		value->v.octetstring.octets = NULL;
1161312047Sngie	}
1162122394Sharti	value->syntax = SNMP_SYNTAX_NULL;
1163122394Sharti}
1164122394Sharti
1165122394Shartiint
1166122394Shartisnmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1167122394Sharti{
1168122394Sharti	to->var = from->var;
1169122394Sharti	to->syntax = from->syntax;
1170122394Sharti
1171122394Sharti	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1172122394Sharti		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1173122394Sharti			to->v.octetstring.octets = NULL;
1174122394Sharti		else {
1175122394Sharti			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1176122394Sharti			if (to->v.octetstring.octets == NULL)
1177122394Sharti				return (-1);
1178122394Sharti			(void)memcpy(to->v.octetstring.octets,
1179122394Sharti			    from->v.octetstring.octets, to->v.octetstring.len);
1180122394Sharti		}
1181122394Sharti	} else
1182122394Sharti		to->v = from->v;
1183122394Sharti	return (0);
1184122394Sharti}
1185122394Sharti
1186122394Shartivoid
1187216594Ssyrinxsnmp_pdu_init_secparams(struct snmp_pdu *pdu)
1188216294Ssyrinx{
1189216294Ssyrinx	int32_t rval;
1190216294Ssyrinx
1191216594Ssyrinx	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1192216294Ssyrinx		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1193216294Ssyrinx
1194216594Ssyrinx	switch (pdu->user.priv_proto) {
1195216294Ssyrinx	case SNMP_PRIV_DES:
1196216594Ssyrinx		memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1197216594Ssyrinx		    sizeof(pdu->engine.engine_boots));
1198216294Ssyrinx		rval = random();
1199216594Ssyrinx		memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1200216294Ssyrinx		    sizeof(int32_t));
1201216294Ssyrinx		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1202216294Ssyrinx		break;
1203216294Ssyrinx	case SNMP_PRIV_AES:
1204216294Ssyrinx		rval = random();
1205216294Ssyrinx		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1206216294Ssyrinx		rval = random();
1207216294Ssyrinx		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1208216294Ssyrinx		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1209216294Ssyrinx		break;
1210216294Ssyrinx	default:
1211216294Ssyrinx		break;
1212216294Ssyrinx	}
1213216294Ssyrinx}
1214216294Ssyrinx
1215216294Ssyrinxvoid
1216122394Shartisnmp_pdu_free(struct snmp_pdu *pdu)
1217122394Sharti{
1218122394Sharti	u_int i;
1219122394Sharti
1220122394Sharti	for (i = 0; i < pdu->nbindings; i++)
1221122394Sharti		snmp_value_free(&pdu->bindings[i]);
1222312047Sngie	pdu->nbindings = 0;
1223122394Sharti}
1224122394Sharti
1225122394Sharti/*
1226122394Sharti * Parse an ASCII SNMP value into the binary form
1227122394Sharti */
1228122394Shartiint
1229122394Shartisnmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1230122394Sharti{
1231122394Sharti	char *end;
1232122394Sharti
1233122394Sharti	switch (syntax) {
1234122394Sharti
1235122394Sharti	  case SNMP_SYNTAX_NULL:
1236122394Sharti	  case SNMP_SYNTAX_NOSUCHOBJECT:
1237122394Sharti	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1238122394Sharti	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1239122394Sharti		if (*str != '\0')
1240122394Sharti			return (-1);
1241122394Sharti		return (0);
1242122394Sharti
1243122394Sharti	  case SNMP_SYNTAX_INTEGER:
1244122394Sharti		v->integer = strtoll(str, &end, 0);
1245122394Sharti		if (*end != '\0')
1246122394Sharti			return (-1);
1247122394Sharti		return (0);
1248122394Sharti
1249122394Sharti	  case SNMP_SYNTAX_OCTETSTRING:
1250122394Sharti	    {
1251122394Sharti		u_long len;	/* actual length of string */
1252122394Sharti		u_long alloc;	/* allocate length of string */
1253122394Sharti		u_char *octs;	/* actual octets */
1254122394Sharti		u_long oct;	/* actual octet */
1255122394Sharti		u_char *nocts;	/* to avoid memory leak */
1256122394Sharti		u_char c;	/* actual character */
1257122394Sharti
1258122394Sharti# define STUFFC(C)							\
1259122394Sharti		if (alloc == len) {					\
1260122394Sharti			alloc += 100;					\
1261122394Sharti			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1262122394Sharti				free(octs);				\
1263122394Sharti				return (-1);				\
1264122394Sharti			}						\
1265122394Sharti			octs = nocts;					\
1266122394Sharti		}							\
1267122394Sharti		octs[len++] = (C);
1268122394Sharti
1269122394Sharti		len = alloc = 0;
1270122394Sharti		octs = NULL;
1271122394Sharti
1272122394Sharti		if (*str == '"') {
1273122394Sharti			str++;
1274122394Sharti			while((c = *str++) != '\0') {
1275122394Sharti				if (c == '"') {
1276122394Sharti					if (*str != '\0') {
1277122394Sharti						free(octs);
1278122394Sharti						return (-1);
1279122394Sharti					}
1280122394Sharti					break;
1281122394Sharti				}
1282122394Sharti				if (c == '\\') {
1283122394Sharti					switch (c = *str++) {
1284122394Sharti
1285122394Sharti					  case '\\':
1286122394Sharti						break;
1287122394Sharti					  case 'a':
1288122394Sharti						c = '\a';
1289122394Sharti						break;
1290122394Sharti					  case 'b':
1291122394Sharti						c = '\b';
1292122394Sharti						break;
1293122394Sharti					  case 'f':
1294122394Sharti						c = '\f';
1295122394Sharti						break;
1296122394Sharti					  case 'n':
1297122394Sharti						c = '\n';
1298122394Sharti						break;
1299122394Sharti					  case 'r':
1300122394Sharti						c = '\r';
1301122394Sharti						break;
1302122394Sharti					  case 't':
1303122394Sharti						c = '\t';
1304122394Sharti						break;
1305122394Sharti					  case 'v':
1306122394Sharti						c = '\v';
1307122394Sharti						break;
1308122394Sharti					  case 'x':
1309122394Sharti						c = 0;
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						if (!isxdigit(*str))
1319122394Sharti							break;
1320122394Sharti						if (isdigit(*str))
1321122394Sharti							c += *str++ - '0';
1322122394Sharti						else if (isupper(*str))
1323122394Sharti							c += *str++ - 'A' + 10;
1324122394Sharti						else
1325122394Sharti							c += *str++ - 'a' + 10;
1326122394Sharti						break;
1327122394Sharti					  case '0': case '1': case '2':
1328122394Sharti					  case '3': case '4': case '5':
1329122394Sharti					  case '6': case '7':
1330122394Sharti						c = *str++ - '0';
1331122394Sharti						if (*str < '0' || *str > '7')
1332122394Sharti							break;
1333122394Sharti						c = *str++ - '0';
1334122394Sharti						if (*str < '0' || *str > '7')
1335122394Sharti							break;
1336122394Sharti						c = *str++ - '0';
1337122394Sharti						break;
1338122394Sharti					  default:
1339122394Sharti						break;
1340122394Sharti					}
1341122394Sharti				}
1342122394Sharti				STUFFC(c);
1343122394Sharti			}
1344122394Sharti		} else {
1345122394Sharti			while (*str != '\0') {
1346122394Sharti				oct = strtoul(str, &end, 16);
1347122394Sharti				str = end;
1348122394Sharti				if (oct > 0xff) {
1349122394Sharti					free(octs);
1350122394Sharti					return (-1);
1351122394Sharti				}
1352122394Sharti				STUFFC(oct);
1353122394Sharti				if (*str == ':')
1354122394Sharti					str++;
1355122394Sharti				else if(*str != '\0') {
1356122394Sharti					free(octs);
1357122394Sharti					return (-1);
1358122394Sharti				}
1359122394Sharti			}
1360122394Sharti		}
1361122394Sharti		v->octetstring.octets = octs;
1362122394Sharti		v->octetstring.len = len;
1363122394Sharti		return (0);
1364122394Sharti# undef STUFFC
1365122394Sharti	    }
1366122394Sharti
1367122394Sharti	  case SNMP_SYNTAX_OID:
1368122394Sharti	    {
1369122394Sharti		u_long subid;
1370122394Sharti
1371122394Sharti		v->oid.len = 0;
1372122394Sharti
1373122394Sharti		for (;;) {
1374122394Sharti			if (v->oid.len == ASN_MAXOIDLEN)
1375122394Sharti				return (-1);
1376122394Sharti			subid = strtoul(str, &end, 10);
1377122394Sharti			str = end;
1378122394Sharti			if (subid > ASN_MAXID)
1379122394Sharti				return (-1);
1380122394Sharti			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1381122394Sharti			if (*str == '\0')
1382122394Sharti				break;
1383122394Sharti			if (*str != '.')
1384122394Sharti				return (-1);
1385122394Sharti			str++;
1386122394Sharti		}
1387122394Sharti		return (0);
1388122394Sharti	    }
1389122394Sharti
1390122394Sharti	  case SNMP_SYNTAX_IPADDRESS:
1391122394Sharti	    {
1392122394Sharti		struct hostent *he;
1393122394Sharti
1394311603Sngie		if (inet_pton(AF_INET, str, &v->ipaddress) == 1)
1395122394Sharti			return (0);
1396311603Sngie		if ((he = gethostbyname2(str, AF_INET)) == NULL)
1397122394Sharti			return (-1);
1398122394Sharti		if (he->h_addrtype != AF_INET)
1399122394Sharti			return (-1);
1400122394Sharti
1401311603Sngie		memcpy(v->ipaddress, he->h_addr, sizeof(v->ipaddress));
1402311603Sngie
1403122394Sharti		return (0);
1404122394Sharti	    }
1405122394Sharti
1406122394Sharti	  case SNMP_SYNTAX_COUNTER:
1407122394Sharti	  case SNMP_SYNTAX_GAUGE:
1408122394Sharti	  case SNMP_SYNTAX_TIMETICKS:
1409122394Sharti	    {
1410133211Sharti		uint64_t sub;
1411122394Sharti
1412122394Sharti		sub = strtoull(str, &end, 0);
1413122394Sharti		if (*end != '\0' || sub > 0xffffffff)
1414122394Sharti			return (-1);
1415133211Sharti		v->uint32 = (uint32_t)sub;
1416122394Sharti		return (0);
1417122394Sharti	    }
1418122394Sharti
1419122394Sharti	  case SNMP_SYNTAX_COUNTER64:
1420122394Sharti		v->counter64 = strtoull(str, &end, 0);
1421122394Sharti		if (*end != '\0')
1422122394Sharti			return (-1);
1423122394Sharti		return (0);
1424122394Sharti	}
1425122394Sharti	abort();
1426122394Sharti}
1427122394Sharti
1428122394Shartistatic void
1429122394Shartisnmp_error_func(const char *fmt, ...)
1430122394Sharti{
1431122394Sharti	va_list ap;
1432122394Sharti
1433122394Sharti	va_start(ap, fmt);
1434122394Sharti	fprintf(stderr, "SNMP: ");
1435122394Sharti	vfprintf(stderr, fmt, ap);
1436122394Sharti	fprintf(stderr, "\n");
1437122394Sharti	va_end(ap);
1438122394Sharti}
1439122394Sharti
1440122394Shartistatic void
1441122394Shartisnmp_printf_func(const char *fmt, ...)
1442122394Sharti{
1443122394Sharti	va_list ap;
1444122394Sharti
1445122394Sharti	va_start(ap, fmt);
1446122394Sharti	vfprintf(stderr, fmt, ap);
1447122394Sharti	va_end(ap);
1448122394Sharti}
1449