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(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(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_TRAP2 &&
768		    pdu->type != SNMP_PDU_REPORT)
769			pdu->flags |= SNMP_MSG_REPORT_FLAG;
770
771		if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
772		    != ASN_ERR_OK)
773			return (SNMP_CODE_FAILED);
774
775		if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
776			return (SNMP_CODE_FAILED);
777
778		if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
779			return (SNMP_CODE_FAILED);
780
781		if (pdu->security_model != SNMP_SECMODEL_USM)
782			return (SNMP_CODE_FAILED);
783
784		if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
785			return (SNMP_CODE_FAILED);
786
787		/*  View-based Access Conntrol information */
788		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
789		    ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
790			return (SNMP_CODE_FAILED);
791
792		if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
793		    pdu->context_engine_len) != ASN_ERR_OK)
794			return (SNMP_CODE_FAILED);
795
796		if (asn_put_octetstring(b, (u_char *)pdu->context_name,
797		    strlen(pdu->context_name)) != ASN_ERR_OK)
798			return (SNMP_CODE_FAILED);
799	} else {
800		if (asn_put_octetstring(b, (u_char *)pdu->community,
801		    strlen(pdu->community)) != ASN_ERR_OK)
802			return (SNMP_CODE_FAILED);
803	}
804
805	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
806	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
807		return (SNMP_CODE_FAILED);
808
809	if (pdu->type == SNMP_PDU_TRAP) {
810		if (pdu->version != SNMP_V1 ||
811		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
812		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
813		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
814		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
815		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
816			return (SNMP_CODE_FAILED);
817	} else {
818		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
819		    pdu->type == SNMP_PDU_INFORM ||
820		    pdu->type == SNMP_PDU_TRAP2 ||
821		    pdu->type == SNMP_PDU_REPORT))
822			return (SNMP_CODE_FAILED);
823
824		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
825		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
826		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
827			return (SNMP_CODE_FAILED);
828	}
829
830	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
831	    &pdu->vars_ptr) != ASN_ERR_OK)
832		return (SNMP_CODE_FAILED);
833
834	return (SNMP_CODE_OK);
835}
836
837static enum asn_err
838snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
839{
840	asn_len_t padlen;
841
842	if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
843		padlen = 8 - (pdu->scoped_len % 8);
844		if (asn_pad(b, padlen) != ASN_ERR_OK)
845			return (ASN_ERR_FAILED);
846		pdu->scoped_len += padlen;
847	}
848
849	return (ASN_ERR_OK);
850}
851
852enum snmp_code
853snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
854{
855	size_t moved = 0;
856	enum snmp_code code;
857
858	if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
859	    asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
860		return (SNMP_CODE_FAILED);
861
862	if (pdu->version == SNMP_V3) {
863		if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
864			return (SNMP_CODE_FAILED);
865
866		pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
867		if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK)
868			return (SNMP_CODE_FAILED);
869
870		if (pdu->security_model != SNMP_SECMODEL_USM)
871			return (SNMP_CODE_FAILED);
872
873		if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
874			return (SNMP_CODE_FAILED);
875
876		if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
877		    asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
878			return (SNMP_CODE_FAILED);
879	}
880
881	if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
882		return (SNMP_CODE_FAILED);
883
884	pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
885	pdu->digest_ptr -= moved;
886
887	if (pdu->version == SNMP_V3) {
888		if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
889		    SNMP_CODE_OK)
890			return (SNMP_CODE_FAILED);
891
892		if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
893			memcpy(pdu->digest_ptr, pdu->msg_digest,
894			    sizeof(pdu->msg_digest));
895	}
896
897	return (SNMP_CODE_OK);
898}
899
900/*
901 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
902 * Be sure not to cobber b, when something fails.
903 */
904enum asn_err
905snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
906{
907	u_char *ptr;
908	enum asn_err err;
909	struct asn_buf save = *b;
910
911	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
912	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
913		*b = save;
914		return (err);
915	}
916
917	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
918		*b = save;
919		return (err);
920	}
921
922	switch (binding->syntax) {
923
924	  case SNMP_SYNTAX_NULL:
925		err = asn_put_null(b);
926		break;
927
928	  case SNMP_SYNTAX_INTEGER:
929		err = asn_put_integer(b, binding->v.integer);
930		break;
931
932	  case SNMP_SYNTAX_OCTETSTRING:
933		err = asn_put_octetstring(b, binding->v.octetstring.octets,
934		    binding->v.octetstring.len);
935		break;
936
937	  case SNMP_SYNTAX_OID:
938		err = asn_put_objid(b, &binding->v.oid);
939		break;
940
941	  case SNMP_SYNTAX_IPADDRESS:
942		err = asn_put_ipaddress(b, binding->v.ipaddress);
943		break;
944
945	  case SNMP_SYNTAX_TIMETICKS:
946		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
947		break;
948
949	  case SNMP_SYNTAX_COUNTER:
950		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
951		break;
952
953	  case SNMP_SYNTAX_GAUGE:
954		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
955		break;
956
957	  case SNMP_SYNTAX_COUNTER64:
958		err = asn_put_counter64(b, binding->v.counter64);
959		break;
960
961	  case SNMP_SYNTAX_NOSUCHOBJECT:
962		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
963		break;
964
965	  case SNMP_SYNTAX_NOSUCHINSTANCE:
966		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
967		break;
968
969	  case SNMP_SYNTAX_ENDOFMIBVIEW:
970		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
971		break;
972	}
973
974	if (err != ASN_ERR_OK) {
975		*b = save;
976		return (err);
977	}
978
979	err = asn_commit_header(b, ptr, NULL);
980	if (err != ASN_ERR_OK) {
981		*b = save;
982		return (err);
983	}
984
985	return (ASN_ERR_OK);
986}
987
988/*
989 * Encode an PDU.
990 */
991enum snmp_code
992snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
993{
994	u_int idx;
995	enum snmp_code err;
996
997	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
998		return (err);
999	for (idx = 0; idx < pdu->nbindings; idx++)
1000		if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx]))
1001		    != ASN_ERR_OK)
1002			return (SNMP_CODE_FAILED);
1003
1004	return (snmp_fix_encoding(resp_b, pdu));
1005}
1006
1007static void
1008dump_binding(const struct snmp_value *b)
1009{
1010	u_int i;
1011	char buf[ASN_OIDSTRLEN];
1012
1013	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1014	switch (b->syntax) {
1015
1016	  case SNMP_SYNTAX_NULL:
1017		snmp_printf("NULL");
1018		break;
1019
1020	  case SNMP_SYNTAX_INTEGER:
1021		snmp_printf("INTEGER %d", b->v.integer);
1022		break;
1023
1024	  case SNMP_SYNTAX_OCTETSTRING:
1025		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1026		for (i = 0; i < b->v.octetstring.len; i++)
1027			snmp_printf(" %02x", b->v.octetstring.octets[i]);
1028		break;
1029
1030	  case SNMP_SYNTAX_OID:
1031		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1032		break;
1033
1034	  case SNMP_SYNTAX_IPADDRESS:
1035		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1036		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1037		break;
1038
1039	  case SNMP_SYNTAX_COUNTER:
1040		snmp_printf("COUNTER %u", b->v.uint32);
1041		break;
1042
1043	  case SNMP_SYNTAX_GAUGE:
1044		snmp_printf("GAUGE %u", b->v.uint32);
1045		break;
1046
1047	  case SNMP_SYNTAX_TIMETICKS:
1048		snmp_printf("TIMETICKS %u", b->v.uint32);
1049		break;
1050
1051	  case SNMP_SYNTAX_COUNTER64:
1052		snmp_printf("COUNTER64 %lld", b->v.counter64);
1053		break;
1054
1055	  case SNMP_SYNTAX_NOSUCHOBJECT:
1056		snmp_printf("NoSuchObject");
1057		break;
1058
1059	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1060		snmp_printf("NoSuchInstance");
1061		break;
1062
1063	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1064		snmp_printf("EndOfMibView");
1065		break;
1066
1067	  default:
1068		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1069		break;
1070	}
1071}
1072
1073static __inline void
1074dump_bindings(const struct snmp_pdu *pdu)
1075{
1076	u_int i;
1077
1078	for (i = 0; i < pdu->nbindings; i++) {
1079		snmp_printf(" [%u]: ", i);
1080		dump_binding(&pdu->bindings[i]);
1081		snmp_printf("\n");
1082	}
1083}
1084
1085static __inline void
1086dump_notrap(const struct snmp_pdu *pdu)
1087{
1088	snmp_printf(" request_id=%d", pdu->request_id);
1089	snmp_printf(" error_status=%d", pdu->error_status);
1090	snmp_printf(" error_index=%d\n", pdu->error_index);
1091	dump_bindings(pdu);
1092}
1093
1094void
1095snmp_pdu_dump(const struct snmp_pdu *pdu)
1096{
1097	char buf[ASN_OIDSTRLEN];
1098	const char *vers;
1099	static const char *types[] = {
1100		[SNMP_PDU_GET] =	"GET",
1101		[SNMP_PDU_GETNEXT] =	"GETNEXT",
1102		[SNMP_PDU_RESPONSE] =	"RESPONSE",
1103		[SNMP_PDU_SET] =	"SET",
1104		[SNMP_PDU_TRAP] =	"TRAPv1",
1105		[SNMP_PDU_GETBULK] =	"GETBULK",
1106		[SNMP_PDU_INFORM] =	"INFORM",
1107		[SNMP_PDU_TRAP2] =	"TRAPv2",
1108		[SNMP_PDU_REPORT] =	"REPORT",
1109	};
1110
1111	if (pdu->version == SNMP_V1)
1112		vers = "SNMPv1";
1113	else if (pdu->version == SNMP_V2c)
1114		vers = "SNMPv2c";
1115	else if (pdu->version == SNMP_V3)
1116		vers = "SNMPv3";
1117	else
1118		vers = "v?";
1119
1120	switch (pdu->type) {
1121	  case SNMP_PDU_TRAP:
1122		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1123		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1124		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1125		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1126		snmp_printf(" generic_trap=%d", pdu->generic_trap);
1127		snmp_printf(" specific_trap=%d", pdu->specific_trap);
1128		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1129		dump_bindings(pdu);
1130		break;
1131
1132	  case SNMP_PDU_GET:
1133	  case SNMP_PDU_GETNEXT:
1134	  case SNMP_PDU_RESPONSE:
1135	  case SNMP_PDU_SET:
1136	  case SNMP_PDU_GETBULK:
1137	  case SNMP_PDU_INFORM:
1138	  case SNMP_PDU_TRAP2:
1139	  case SNMP_PDU_REPORT:
1140		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1141		dump_notrap(pdu);
1142		break;
1143
1144	  default:
1145		snmp_printf("bad pdu type %u\n", pdu->type);
1146		break;
1147	}
1148}
1149
1150void
1151snmp_value_free(struct snmp_value *value)
1152{
1153	if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1154		free(value->v.octetstring.octets);
1155	value->syntax = SNMP_SYNTAX_NULL;
1156}
1157
1158int
1159snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1160{
1161	to->var = from->var;
1162	to->syntax = from->syntax;
1163
1164	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1165		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1166			to->v.octetstring.octets = NULL;
1167		else {
1168			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1169			if (to->v.octetstring.octets == NULL)
1170				return (-1);
1171			(void)memcpy(to->v.octetstring.octets,
1172			    from->v.octetstring.octets, to->v.octetstring.len);
1173		}
1174	} else
1175		to->v = from->v;
1176	return (0);
1177}
1178
1179void
1180snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1181{
1182	int32_t rval;
1183
1184	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1185		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1186
1187	switch (pdu->user.priv_proto) {
1188	case SNMP_PRIV_DES:
1189		memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1190		    sizeof(pdu->engine.engine_boots));
1191		rval = random();
1192		memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1193		    sizeof(int32_t));
1194		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1195		break;
1196	case SNMP_PRIV_AES:
1197		rval = random();
1198		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1199		rval = random();
1200		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1201		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1202		break;
1203	default:
1204		break;
1205	}
1206}
1207
1208void
1209snmp_pdu_free(struct snmp_pdu *pdu)
1210{
1211	u_int i;
1212
1213	for (i = 0; i < pdu->nbindings; i++)
1214		snmp_value_free(&pdu->bindings[i]);
1215}
1216
1217/*
1218 * Parse an ASCII SNMP value into the binary form
1219 */
1220int
1221snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1222{
1223	char *end;
1224
1225	switch (syntax) {
1226
1227	  case SNMP_SYNTAX_NULL:
1228	  case SNMP_SYNTAX_NOSUCHOBJECT:
1229	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1230	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1231		if (*str != '\0')
1232			return (-1);
1233		return (0);
1234
1235	  case SNMP_SYNTAX_INTEGER:
1236		v->integer = strtoll(str, &end, 0);
1237		if (*end != '\0')
1238			return (-1);
1239		return (0);
1240
1241	  case SNMP_SYNTAX_OCTETSTRING:
1242	    {
1243		u_long len;	/* actual length of string */
1244		u_long alloc;	/* allocate length of string */
1245		u_char *octs;	/* actual octets */
1246		u_long oct;	/* actual octet */
1247		u_char *nocts;	/* to avoid memory leak */
1248		u_char c;	/* actual character */
1249
1250# define STUFFC(C)							\
1251		if (alloc == len) {					\
1252			alloc += 100;					\
1253			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1254				free(octs);				\
1255				return (-1);				\
1256			}						\
1257			octs = nocts;					\
1258		}							\
1259		octs[len++] = (C);
1260
1261		len = alloc = 0;
1262		octs = NULL;
1263
1264		if (*str == '"') {
1265			str++;
1266			while((c = *str++) != '\0') {
1267				if (c == '"') {
1268					if (*str != '\0') {
1269						free(octs);
1270						return (-1);
1271					}
1272					break;
1273				}
1274				if (c == '\\') {
1275					switch (c = *str++) {
1276
1277					  case '\\':
1278						break;
1279					  case 'a':
1280						c = '\a';
1281						break;
1282					  case 'b':
1283						c = '\b';
1284						break;
1285					  case 'f':
1286						c = '\f';
1287						break;
1288					  case 'n':
1289						c = '\n';
1290						break;
1291					  case 'r':
1292						c = '\r';
1293						break;
1294					  case 't':
1295						c = '\t';
1296						break;
1297					  case 'v':
1298						c = '\v';
1299						break;
1300					  case 'x':
1301						c = 0;
1302						if (!isxdigit(*str))
1303							break;
1304						if (isdigit(*str))
1305							c = *str++ - '0';
1306						else if (isupper(*str))
1307							c = *str++ - 'A' + 10;
1308						else
1309							c = *str++ - 'a' + 10;
1310						if (!isxdigit(*str))
1311							break;
1312						if (isdigit(*str))
1313							c += *str++ - '0';
1314						else if (isupper(*str))
1315							c += *str++ - 'A' + 10;
1316						else
1317							c += *str++ - 'a' + 10;
1318						break;
1319					  case '0': case '1': case '2':
1320					  case '3': case '4': case '5':
1321					  case '6': case '7':
1322						c = *str++ - '0';
1323						if (*str < '0' || *str > '7')
1324							break;
1325						c = *str++ - '0';
1326						if (*str < '0' || *str > '7')
1327							break;
1328						c = *str++ - '0';
1329						break;
1330					  default:
1331						break;
1332					}
1333				}
1334				STUFFC(c);
1335			}
1336		} else {
1337			while (*str != '\0') {
1338				oct = strtoul(str, &end, 16);
1339				str = end;
1340				if (oct > 0xff) {
1341					free(octs);
1342					return (-1);
1343				}
1344				STUFFC(oct);
1345				if (*str == ':')
1346					str++;
1347				else if(*str != '\0') {
1348					free(octs);
1349					return (-1);
1350				}
1351			}
1352		}
1353		v->octetstring.octets = octs;
1354		v->octetstring.len = len;
1355		return (0);
1356# undef STUFFC
1357	    }
1358
1359	  case SNMP_SYNTAX_OID:
1360	    {
1361		u_long subid;
1362
1363		v->oid.len = 0;
1364
1365		for (;;) {
1366			if (v->oid.len == ASN_MAXOIDLEN)
1367				return (-1);
1368			subid = strtoul(str, &end, 10);
1369			str = end;
1370			if (subid > ASN_MAXID)
1371				return (-1);
1372			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1373			if (*str == '\0')
1374				break;
1375			if (*str != '.')
1376				return (-1);
1377			str++;
1378		}
1379		return (0);
1380	    }
1381
1382	  case SNMP_SYNTAX_IPADDRESS:
1383	    {
1384		struct hostent *he;
1385		u_long ip[4];
1386		int n;
1387
1388		if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1389		    &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1390		    ip[0] <= 0xff && ip[1] <= 0xff &&
1391		    ip[2] <= 0xff && ip[3] <= 0xff) {
1392			v->ipaddress[0] = (u_char)ip[0];
1393			v->ipaddress[1] = (u_char)ip[1];
1394			v->ipaddress[2] = (u_char)ip[2];
1395			v->ipaddress[3] = (u_char)ip[3];
1396			return (0);
1397		}
1398
1399		if ((he = gethostbyname(str)) == NULL)
1400			return (-1);
1401		if (he->h_addrtype != AF_INET)
1402			return (-1);
1403
1404		v->ipaddress[0] = he->h_addr[0];
1405		v->ipaddress[1] = he->h_addr[1];
1406		v->ipaddress[2] = he->h_addr[2];
1407		v->ipaddress[3] = he->h_addr[3];
1408		return (0);
1409	    }
1410
1411	  case SNMP_SYNTAX_COUNTER:
1412	  case SNMP_SYNTAX_GAUGE:
1413	  case SNMP_SYNTAX_TIMETICKS:
1414	    {
1415		uint64_t sub;
1416
1417		sub = strtoull(str, &end, 0);
1418		if (*end != '\0' || sub > 0xffffffff)
1419			return (-1);
1420		v->uint32 = (uint32_t)sub;
1421		return (0);
1422	    }
1423
1424	  case SNMP_SYNTAX_COUNTER64:
1425		v->counter64 = strtoull(str, &end, 0);
1426		if (*end != '\0')
1427			return (-1);
1428		return (0);
1429	}
1430	abort();
1431}
1432
1433static void
1434snmp_error_func(const char *fmt, ...)
1435{
1436	va_list ap;
1437
1438	va_start(ap, fmt);
1439	fprintf(stderr, "SNMP: ");
1440	vfprintf(stderr, fmt, ap);
1441	fprintf(stderr, "\n");
1442	va_end(ap);
1443}
1444
1445static void
1446snmp_printf_func(const char *fmt, ...)
1447{
1448	va_list ap;
1449
1450	va_start(ap, fmt);
1451	vfprintf(stderr, fmt, ap);
1452	va_end(ap);
1453}
1454