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