snmp.c revision 301661
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	u_int len;
292
293	if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) {
294		snmp_error("cannot parse usm header");
295		return (ASN_ERR_FAILED);
296	}
297	tb.asn_len = len;
298
299	if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) {
300		snmp_error("cannot decode usm header");
301		return (ASN_ERR_FAILED);
302	}
303
304	octs_len = SNMP_ENGINE_ID_SIZ;
305	if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id,
306	    &octs_len) != ASN_ERR_OK) {
307		snmp_error("cannot decode msg engine id");
308		return (ASN_ERR_FAILED);
309	}
310	pdu->engine.engine_len = octs_len;
311
312	if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) {
313		snmp_error("cannot decode msg engine boots");
314		return (ASN_ERR_FAILED);
315	}
316
317	if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) {
318		snmp_error("cannot decode msg engine time");
319		return (ASN_ERR_FAILED);
320	}
321
322	octs_len = SNMP_ADM_STR32_SIZ - 1;
323	if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len)
324	    != ASN_ERR_OK) {
325		snmp_error("cannot decode msg user name");
326		return (ASN_ERR_FAILED);
327	}
328	pdu->user.sec_name[octs_len] = '\0';
329
330	octs_len = sizeof(pdu->msg_digest);
331	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) !=
332	    ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 &&
333	    octs_len != sizeof(pdu->msg_digest))) {
334		snmp_error("cannot decode msg authentication param");
335		return (ASN_ERR_FAILED);
336	}
337
338	octs_len = sizeof(pdu->msg_salt);
339	if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) !=
340	    ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 &&
341	    octs_len != sizeof(pdu->msg_salt))) {
342		snmp_error("cannot decode msg authentication param");
343		return (ASN_ERR_FAILED);
344	}
345
346	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
347		pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE;
348		pdu->digest_ptr -= octs_len + ASN_MAXLENLEN;
349	}
350
351	return (ASN_ERR_OK);
352}
353
354static enum snmp_code
355pdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
356{
357	u_char buf[256], *sptr;
358        struct asn_buf tb;
359        size_t auth_off, moved = 0;
360
361	auth_off = 0;
362	memset(buf, 0, 256);
363	tb.asn_ptr = buf;
364	tb.asn_len = 256;
365
366	if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
367	    &sptr) != ASN_ERR_OK)
368		return (SNMP_CODE_FAILED);
369
370	if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id,
371	    pdu->engine.engine_len) != ASN_ERR_OK)
372		return (SNMP_CODE_FAILED);
373
374	if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK)
375		return (SNMP_CODE_FAILED);
376
377	if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK)
378		return (SNMP_CODE_FAILED);
379
380	if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name,
381	    strlen(pdu->user.sec_name)) != ASN_ERR_OK)
382		return (SNMP_CODE_FAILED);
383
384	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) {
385		auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN;
386		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest,
387		    sizeof(pdu->msg_digest)) != ASN_ERR_OK)
388			return (SNMP_CODE_FAILED);
389	} else {
390		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0)
391		    != ASN_ERR_OK)
392			return (SNMP_CODE_FAILED);
393	}
394
395	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) {
396		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt,
397		    sizeof(pdu->msg_salt)) != ASN_ERR_OK)
398			return (SNMP_CODE_FAILED);
399	} else {
400		if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0)
401		    != ASN_ERR_OK)
402			return (SNMP_CODE_FAILED);
403	}
404
405	if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK)
406		return (SNMP_CODE_FAILED);
407
408	if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
409		pdu->digest_ptr = b->asn_ptr + auth_off - moved;
410
411	if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK)
412		return (SNMP_CODE_FAILED);
413	pdu->digest_ptr += ASN_MAXLENLEN;
414
415	if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b,
416	    ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK)
417			return (SNMP_CODE_FAILED);
418
419	return (SNMP_CODE_OK);
420}
421
422/*
423 * Decode the PDU except for the variable bindings itself.
424 * If decoding fails because of a bad binding, but the rest can be
425 * decoded, ip points to the index of the failed variable (errors
426 * OORANGE, BADLEN or BADVERS).
427 */
428enum snmp_code
429snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
430{
431	enum snmp_code code;
432
433	if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK)
434		return (code);
435
436	if (pdu->version == SNMP_V3) {
437		if (pdu->security_model != SNMP_SECMODEL_USM)
438			return (SNMP_CODE_FAILED);
439		if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK)
440			return (code);
441	}
442
443	code = snmp_pdu_decode_scoped(b, pdu, ip);
444
445	switch (code) {
446	  case SNMP_CODE_FAILED:
447		snmp_pdu_free(pdu);
448		break;
449
450	  case SNMP_CODE_BADENC:
451		if (pdu->version == SNMP_Verr)
452			return (SNMP_CODE_BADVERS);
453
454	  default:
455		break;
456	}
457
458	return (code);
459}
460
461enum snmp_code
462snmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu)
463{
464	int32_t version;
465	u_int octs_len;
466	asn_len_t len;
467
468	pdu->outer_ptr = b->asn_ptr;
469	pdu->outer_len = b->asn_len;
470
471	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
472		snmp_error("cannot decode pdu header");
473		return (SNMP_CODE_FAILED);
474	}
475	if (b->asn_len < len) {
476		snmp_error("outer sequence value too short");
477		return (SNMP_CODE_FAILED);
478	}
479	if (b->asn_len != len) {
480		snmp_error("ignoring trailing junk in message");
481		b->asn_len = len;
482	}
483
484	if (asn_get_integer(b, &version) != ASN_ERR_OK) {
485		snmp_error("cannot decode version");
486		return (SNMP_CODE_FAILED);
487	}
488
489	if (version == 0)
490		pdu->version = SNMP_V1;
491	else if (version == 1)
492		pdu->version = SNMP_V2c;
493	else if (version == 3)
494		pdu->version = SNMP_V3;
495	else {
496		pdu->version = SNMP_Verr;
497		snmp_error("unsupported SNMP version");
498		return (SNMP_CODE_BADENC);
499	}
500
501	if (pdu->version == SNMP_V3) {
502		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
503			snmp_error("cannot decode pdu global data header");
504			return (SNMP_CODE_FAILED);
505		}
506
507		if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) {
508			snmp_error("cannot decode msg indetifier");
509			return (SNMP_CODE_FAILED);
510		}
511
512		if (asn_get_integer(b, &pdu->engine.max_msg_size)
513		    != ASN_ERR_OK) {
514			snmp_error("cannot decode msg size");
515			return (SNMP_CODE_FAILED);
516		}
517
518		octs_len = 1;
519		if (asn_get_octetstring(b, (u_char *)&pdu->flags,
520		    &octs_len) != ASN_ERR_OK) {
521			snmp_error("cannot decode msg flags");
522			return (SNMP_CODE_FAILED);
523		}
524
525		if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) {
526			snmp_error("cannot decode msg size");
527			return (SNMP_CODE_FAILED);
528		}
529
530		if (pdu->security_model != SNMP_SECMODEL_USM)
531			return (SNMP_CODE_FAILED);
532
533		if (parse_secparams(b, pdu) != ASN_ERR_OK)
534			return (SNMP_CODE_FAILED);
535	} else {
536		octs_len = SNMP_COMMUNITY_MAXLEN;
537		if (asn_get_octetstring(b, (u_char *)pdu->community,
538		    &octs_len) != ASN_ERR_OK) {
539			snmp_error("cannot decode community");
540			return (SNMP_CODE_FAILED);
541		}
542		pdu->community[octs_len] = '\0';
543	}
544
545	return (SNMP_CODE_OK);
546}
547
548enum snmp_code
549snmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
550{
551	u_char type;
552	asn_len_t len, trailer;
553	enum asn_err err;
554
555	if (pdu->version == SNMP_V3) {
556		if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
557			snmp_error("cannot decode scoped pdu header");
558			return (SNMP_CODE_FAILED);
559		}
560
561		len = SNMP_ENGINE_ID_SIZ;
562		if (asn_get_octetstring(b, (u_char *)&pdu->context_engine,
563		    &len) != ASN_ERR_OK) {
564			snmp_error("cannot decode msg context engine");
565			return (SNMP_CODE_FAILED);
566		}
567		pdu->context_engine_len = len;
568
569		len = SNMP_CONTEXT_NAME_SIZ;
570		if (asn_get_octetstring(b, (u_char *)&pdu->context_name,
571		    &len) != ASN_ERR_OK) {
572			snmp_error("cannot decode msg context name");
573			return (SNMP_CODE_FAILED);
574		}
575		pdu->context_name[len] = '\0';
576	}
577
578	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
579		snmp_error("cannot get pdu header");
580		return (SNMP_CODE_FAILED);
581	}
582	if ((type & ~ASN_TYPE_MASK) !=
583	    (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) {
584		snmp_error("bad pdu header tag");
585		return (SNMP_CODE_FAILED);
586	}
587	pdu->type = type & ASN_TYPE_MASK;
588
589	switch (pdu->type) {
590
591	  case SNMP_PDU_GET:
592	  case SNMP_PDU_GETNEXT:
593	  case SNMP_PDU_RESPONSE:
594	  case SNMP_PDU_SET:
595		break;
596
597	  case SNMP_PDU_TRAP:
598		if (pdu->version != SNMP_V1) {
599			snmp_error("bad pdu type %u", pdu->type);
600			return (SNMP_CODE_FAILED);
601		}
602		break;
603
604	  case SNMP_PDU_GETBULK:
605	  case SNMP_PDU_INFORM:
606	  case SNMP_PDU_TRAP2:
607	  case SNMP_PDU_REPORT:
608		if (pdu->version == SNMP_V1) {
609			snmp_error("bad pdu type %u", pdu->type);
610			return (SNMP_CODE_FAILED);
611		}
612		break;
613
614	  default:
615		snmp_error("bad pdu type %u", pdu->type);
616		return (SNMP_CODE_FAILED);
617	}
618
619	trailer = b->asn_len - len;
620	b->asn_len = len;
621
622	err = parse_pdus(b, pdu, ip);
623	if (ASN_ERR_STOPPED(err))
624		return (SNMP_CODE_FAILED);
625
626	if (b->asn_len != 0)
627		snmp_error("ignoring trailing junk after pdu");
628
629	b->asn_len = trailer;
630
631	return (SNMP_CODE_OK);
632}
633
634enum snmp_code
635snmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu)
636{
637	u_char type;
638	enum snmp_code code;
639	uint8_t	digest[SNMP_USM_AUTH_SIZE];
640
641	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
642	    (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0)
643		return (SNMP_CODE_BADSECLEVEL);
644
645	if ((code = snmp_pdu_calc_digest(pdu, digest)) !=
646	    SNMP_CODE_OK)
647		return (SNMP_CODE_FAILED);
648
649	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH &&
650	    memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0)
651		return (SNMP_CODE_BADDIGEST);
652
653	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type,
654	    &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) {
655		snmp_error("cannot decode encrypted pdu");
656		return (SNMP_CODE_FAILED);
657	}
658	pdu->scoped_ptr = b->asn_ptr;
659
660	if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
661	    (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0)
662		return (SNMP_CODE_BADSECLEVEL);
663
664	if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK)
665		return (SNMP_CODE_FAILED);
666
667	return (code);
668}
669
670/*
671 * Check whether what we have is the complete PDU by snooping at the
672 * enclosing structure header. This returns:
673 *   -1		if there are ASN.1 errors
674 *    0		if we need more data
675 *  > 0		the length of this PDU
676 */
677int
678snmp_pdu_snoop(const struct asn_buf *b0)
679{
680	u_int length;
681	asn_len_t len;
682	struct asn_buf b = *b0;
683
684	/* <0x10|0x20> <len> <data...> */
685
686	if (b.asn_len == 0)
687		return (0);
688	if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) {
689		asn_error(&b, "bad sequence type %u", b.asn_cptr[0]);
690		return (-1);
691	}
692	b.asn_len--;
693	b.asn_cptr++;
694
695	if (b.asn_len == 0)
696		return (0);
697
698	if (*b.asn_cptr & 0x80) {
699		/* long length */
700		length = *b.asn_cptr++ & 0x7f;
701		b.asn_len--;
702		if (length == 0) {
703			asn_error(&b, "indefinite length not supported");
704			return (-1);
705		}
706		if (length > ASN_MAXLENLEN) {
707			asn_error(&b, "long length too long (%u)", length);
708			return (-1);
709		}
710		if (length > b.asn_len)
711			return (0);
712		len = 0;
713		while (length--) {
714			len = (len << 8) | *b.asn_cptr++;
715			b.asn_len--;
716		}
717	} else {
718		len = *b.asn_cptr++;
719		b.asn_len--;
720	}
721
722	if (len > b.asn_len)
723		return (0);
724
725	return (len + b.asn_cptr - b0->asn_cptr);
726}
727
728/*
729 * Encode the SNMP PDU without the variable bindings field.
730 * We do this the rather uneffective way by
731 * moving things around and assuming that the length field will never
732 * use more than 2 bytes.
733 * We need a number of pointers to apply the fixes afterwards.
734 */
735enum snmp_code
736snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu)
737{
738	enum asn_err err;
739	u_char *v3_hdr_ptr;
740
741	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
742	    &pdu->outer_ptr) != ASN_ERR_OK)
743		return (SNMP_CODE_FAILED);
744
745	if (pdu->version == SNMP_V1)
746		err = asn_put_integer(b, 0);
747	else if (pdu->version == SNMP_V2c)
748		err = asn_put_integer(b, 1);
749	else if (pdu->version == SNMP_V3)
750		err = asn_put_integer(b, 3);
751	else
752		return (SNMP_CODE_BADVERS);
753	if (err != ASN_ERR_OK)
754		return (SNMP_CODE_FAILED);
755
756	if (pdu->version == SNMP_V3) {
757		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
758		    ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK)
759			return (SNMP_CODE_FAILED);
760
761		if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK)
762			return (SNMP_CODE_FAILED);
763
764		if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK)
765			return (SNMP_CODE_FAILED);
766
767		if (pdu->type != SNMP_PDU_RESPONSE &&
768		    pdu->type != SNMP_PDU_TRAP &&
769		    pdu->type != SNMP_PDU_TRAP2 &&
770		    pdu->type != SNMP_PDU_REPORT)
771			pdu->flags |= SNMP_MSG_REPORT_FLAG;
772
773		if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1)
774		    != ASN_ERR_OK)
775			return (SNMP_CODE_FAILED);
776
777		if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK)
778			return (SNMP_CODE_FAILED);
779
780		if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK)
781			return (SNMP_CODE_FAILED);
782
783		if (pdu->security_model != SNMP_SECMODEL_USM)
784			return (SNMP_CODE_FAILED);
785
786		if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK)
787			return (SNMP_CODE_FAILED);
788
789		/*  View-based Access Conntrol information */
790		if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
791		    ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK)
792			return (SNMP_CODE_FAILED);
793
794		if (asn_put_octetstring(b, (u_char *)pdu->context_engine,
795		    pdu->context_engine_len) != ASN_ERR_OK)
796			return (SNMP_CODE_FAILED);
797
798		if (asn_put_octetstring(b, (u_char *)pdu->context_name,
799		    strlen(pdu->context_name)) != ASN_ERR_OK)
800			return (SNMP_CODE_FAILED);
801	} else {
802		if (asn_put_octetstring(b, (u_char *)pdu->community,
803		    strlen(pdu->community)) != ASN_ERR_OK)
804			return (SNMP_CODE_FAILED);
805	}
806
807	if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT |
808	    pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK)
809		return (SNMP_CODE_FAILED);
810
811	if (pdu->type == SNMP_PDU_TRAP) {
812		if (pdu->version != SNMP_V1 ||
813		    asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK ||
814		    asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK ||
815		    asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK ||
816		    asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK ||
817		    asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK)
818			return (SNMP_CODE_FAILED);
819	} else {
820		if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK ||
821		    pdu->type == SNMP_PDU_INFORM ||
822		    pdu->type == SNMP_PDU_TRAP2 ||
823		    pdu->type == SNMP_PDU_REPORT))
824			return (SNMP_CODE_FAILED);
825
826		if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK ||
827		    asn_put_integer(b, pdu->error_status) != ASN_ERR_OK ||
828		    asn_put_integer(b, pdu->error_index) != ASN_ERR_OK)
829			return (SNMP_CODE_FAILED);
830	}
831
832	if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED),
833	    &pdu->vars_ptr) != ASN_ERR_OK)
834		return (SNMP_CODE_FAILED);
835
836	return (SNMP_CODE_OK);
837}
838
839static enum asn_err
840snmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu)
841{
842	asn_len_t padlen;
843
844	if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) {
845		padlen = 8 - (pdu->scoped_len % 8);
846		if (asn_pad(b, padlen) != ASN_ERR_OK)
847			return (ASN_ERR_FAILED);
848		pdu->scoped_len += padlen;
849	}
850
851	return (ASN_ERR_OK);
852}
853
854enum snmp_code
855snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu)
856{
857	size_t moved = 0;
858	enum snmp_code code;
859
860	if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK ||
861	    asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK)
862		return (SNMP_CODE_FAILED);
863
864	if (pdu->version == SNMP_V3) {
865		if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK)
866			return (SNMP_CODE_FAILED);
867
868		pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr;
869		if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK)
870			return (SNMP_CODE_FAILED);
871
872		if (pdu->security_model != SNMP_SECMODEL_USM)
873			return (SNMP_CODE_FAILED);
874
875		if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK)
876			return (SNMP_CODE_FAILED);
877
878		if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV &&
879		    asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK)
880			return (SNMP_CODE_FAILED);
881	}
882
883	if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK)
884		return (SNMP_CODE_FAILED);
885
886	pdu->outer_len = b->asn_ptr - pdu->outer_ptr;
887	pdu->digest_ptr -= moved;
888
889	if (pdu->version == SNMP_V3) {
890		if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) !=
891		    SNMP_CODE_OK)
892			return (SNMP_CODE_FAILED);
893
894		if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0)
895			memcpy(pdu->digest_ptr, pdu->msg_digest,
896			    sizeof(pdu->msg_digest));
897	}
898
899	return (SNMP_CODE_OK);
900}
901
902/*
903 * Encode a binding. Caller must ensure, that the syntax is ok for that version.
904 * Be sure not to cobber b, when something fails.
905 */
906enum asn_err
907snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding)
908{
909	u_char *ptr;
910	enum asn_err err;
911	struct asn_buf save = *b;
912
913	if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE |
914	    ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) {
915		*b = save;
916		return (err);
917	}
918
919	if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) {
920		*b = save;
921		return (err);
922	}
923
924	switch (binding->syntax) {
925
926	  case SNMP_SYNTAX_NULL:
927		err = asn_put_null(b);
928		break;
929
930	  case SNMP_SYNTAX_INTEGER:
931		err = asn_put_integer(b, binding->v.integer);
932		break;
933
934	  case SNMP_SYNTAX_OCTETSTRING:
935		err = asn_put_octetstring(b, binding->v.octetstring.octets,
936		    binding->v.octetstring.len);
937		break;
938
939	  case SNMP_SYNTAX_OID:
940		err = asn_put_objid(b, &binding->v.oid);
941		break;
942
943	  case SNMP_SYNTAX_IPADDRESS:
944		err = asn_put_ipaddress(b, binding->v.ipaddress);
945		break;
946
947	  case SNMP_SYNTAX_TIMETICKS:
948		err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32);
949		break;
950
951	  case SNMP_SYNTAX_COUNTER:
952		err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32);
953		break;
954
955	  case SNMP_SYNTAX_GAUGE:
956		err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32);
957		break;
958
959	  case SNMP_SYNTAX_COUNTER64:
960		err = asn_put_counter64(b, binding->v.counter64);
961		break;
962
963	  case SNMP_SYNTAX_NOSUCHOBJECT:
964		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT);
965		break;
966
967	  case SNMP_SYNTAX_NOSUCHINSTANCE:
968		err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE);
969		break;
970
971	  case SNMP_SYNTAX_ENDOFMIBVIEW:
972		err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW);
973		break;
974	}
975
976	if (err != ASN_ERR_OK) {
977		*b = save;
978		return (err);
979	}
980
981	err = asn_commit_header(b, ptr, NULL);
982	if (err != ASN_ERR_OK) {
983		*b = save;
984		return (err);
985	}
986
987	return (ASN_ERR_OK);
988}
989
990/*
991 * Encode an PDU.
992 */
993enum snmp_code
994snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b)
995{
996	u_int idx;
997	enum snmp_code err;
998
999	if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK)
1000		return (err);
1001	for (idx = 0; idx < pdu->nbindings; idx++)
1002		if (snmp_binding_encode(resp_b, &pdu->bindings[idx])
1003		    != ASN_ERR_OK)
1004			return (SNMP_CODE_FAILED);
1005
1006	return (snmp_fix_encoding(resp_b, pdu));
1007}
1008
1009static void
1010dump_binding(const struct snmp_value *b)
1011{
1012	u_int i;
1013	char buf[ASN_OIDSTRLEN];
1014
1015	snmp_printf("%s=", asn_oid2str_r(&b->var, buf));
1016	switch (b->syntax) {
1017
1018	  case SNMP_SYNTAX_NULL:
1019		snmp_printf("NULL");
1020		break;
1021
1022	  case SNMP_SYNTAX_INTEGER:
1023		snmp_printf("INTEGER %d", b->v.integer);
1024		break;
1025
1026	  case SNMP_SYNTAX_OCTETSTRING:
1027		snmp_printf("OCTET STRING %lu:", b->v.octetstring.len);
1028		for (i = 0; i < b->v.octetstring.len; i++)
1029			snmp_printf(" %02x", b->v.octetstring.octets[i]);
1030		break;
1031
1032	  case SNMP_SYNTAX_OID:
1033		snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf));
1034		break;
1035
1036	  case SNMP_SYNTAX_IPADDRESS:
1037		snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0],
1038		    b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]);
1039		break;
1040
1041	  case SNMP_SYNTAX_COUNTER:
1042		snmp_printf("COUNTER %u", b->v.uint32);
1043		break;
1044
1045	  case SNMP_SYNTAX_GAUGE:
1046		snmp_printf("GAUGE %u", b->v.uint32);
1047		break;
1048
1049	  case SNMP_SYNTAX_TIMETICKS:
1050		snmp_printf("TIMETICKS %u", b->v.uint32);
1051		break;
1052
1053	  case SNMP_SYNTAX_COUNTER64:
1054		snmp_printf("COUNTER64 %lld", b->v.counter64);
1055		break;
1056
1057	  case SNMP_SYNTAX_NOSUCHOBJECT:
1058		snmp_printf("NoSuchObject");
1059		break;
1060
1061	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1062		snmp_printf("NoSuchInstance");
1063		break;
1064
1065	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1066		snmp_printf("EndOfMibView");
1067		break;
1068
1069	  default:
1070		snmp_printf("UNKNOWN SYNTAX %u", b->syntax);
1071		break;
1072	}
1073}
1074
1075static __inline void
1076dump_bindings(const struct snmp_pdu *pdu)
1077{
1078	u_int i;
1079
1080	for (i = 0; i < pdu->nbindings; i++) {
1081		snmp_printf(" [%u]: ", i);
1082		dump_binding(&pdu->bindings[i]);
1083		snmp_printf("\n");
1084	}
1085}
1086
1087static __inline void
1088dump_notrap(const struct snmp_pdu *pdu)
1089{
1090	snmp_printf(" request_id=%d", pdu->request_id);
1091	snmp_printf(" error_status=%d", pdu->error_status);
1092	snmp_printf(" error_index=%d\n", pdu->error_index);
1093	dump_bindings(pdu);
1094}
1095
1096void
1097snmp_pdu_dump(const struct snmp_pdu *pdu)
1098{
1099	char buf[ASN_OIDSTRLEN];
1100	const char *vers;
1101	static const char *types[] = {
1102		[SNMP_PDU_GET] =	"GET",
1103		[SNMP_PDU_GETNEXT] =	"GETNEXT",
1104		[SNMP_PDU_RESPONSE] =	"RESPONSE",
1105		[SNMP_PDU_SET] =	"SET",
1106		[SNMP_PDU_TRAP] =	"TRAPv1",
1107		[SNMP_PDU_GETBULK] =	"GETBULK",
1108		[SNMP_PDU_INFORM] =	"INFORM",
1109		[SNMP_PDU_TRAP2] =	"TRAPv2",
1110		[SNMP_PDU_REPORT] =	"REPORT",
1111	};
1112
1113	if (pdu->version == SNMP_V1)
1114		vers = "SNMPv1";
1115	else if (pdu->version == SNMP_V2c)
1116		vers = "SNMPv2c";
1117	else if (pdu->version == SNMP_V3)
1118		vers = "SNMPv3";
1119	else
1120		vers = "v?";
1121
1122	switch (pdu->type) {
1123	  case SNMP_PDU_TRAP:
1124		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1125		snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf));
1126		snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0],
1127		    pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]);
1128		snmp_printf(" generic_trap=%d", pdu->generic_trap);
1129		snmp_printf(" specific_trap=%d", pdu->specific_trap);
1130		snmp_printf(" time-stamp=%u\n", pdu->time_stamp);
1131		dump_bindings(pdu);
1132		break;
1133
1134	  case SNMP_PDU_GET:
1135	  case SNMP_PDU_GETNEXT:
1136	  case SNMP_PDU_RESPONSE:
1137	  case SNMP_PDU_SET:
1138	  case SNMP_PDU_GETBULK:
1139	  case SNMP_PDU_INFORM:
1140	  case SNMP_PDU_TRAP2:
1141	  case SNMP_PDU_REPORT:
1142		snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community);
1143		dump_notrap(pdu);
1144		break;
1145
1146	  default:
1147		snmp_printf("bad pdu type %u\n", pdu->type);
1148		break;
1149	}
1150}
1151
1152void
1153snmp_value_free(struct snmp_value *value)
1154{
1155	if (value->syntax == SNMP_SYNTAX_OCTETSTRING)
1156		free(value->v.octetstring.octets);
1157	value->syntax = SNMP_SYNTAX_NULL;
1158}
1159
1160int
1161snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1162{
1163	to->var = from->var;
1164	to->syntax = from->syntax;
1165
1166	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1167		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1168			to->v.octetstring.octets = NULL;
1169		else {
1170			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1171			if (to->v.octetstring.octets == NULL)
1172				return (-1);
1173			(void)memcpy(to->v.octetstring.octets,
1174			    from->v.octetstring.octets, to->v.octetstring.len);
1175		}
1176	} else
1177		to->v = from->v;
1178	return (0);
1179}
1180
1181void
1182snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1183{
1184	int32_t rval;
1185
1186	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1187		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1188
1189	switch (pdu->user.priv_proto) {
1190	case SNMP_PRIV_DES:
1191		memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1192		    sizeof(pdu->engine.engine_boots));
1193		rval = random();
1194		memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1195		    sizeof(int32_t));
1196		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1197		break;
1198	case SNMP_PRIV_AES:
1199		rval = random();
1200		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1201		rval = random();
1202		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1203		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1204		break;
1205	default:
1206		break;
1207	}
1208}
1209
1210void
1211snmp_pdu_free(struct snmp_pdu *pdu)
1212{
1213	u_int i;
1214
1215	for (i = 0; i < pdu->nbindings; i++)
1216		snmp_value_free(&pdu->bindings[i]);
1217}
1218
1219/*
1220 * Parse an ASCII SNMP value into the binary form
1221 */
1222int
1223snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1224{
1225	char *end;
1226
1227	switch (syntax) {
1228
1229	  case SNMP_SYNTAX_NULL:
1230	  case SNMP_SYNTAX_NOSUCHOBJECT:
1231	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1232	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1233		if (*str != '\0')
1234			return (-1);
1235		return (0);
1236
1237	  case SNMP_SYNTAX_INTEGER:
1238		v->integer = strtoll(str, &end, 0);
1239		if (*end != '\0')
1240			return (-1);
1241		return (0);
1242
1243	  case SNMP_SYNTAX_OCTETSTRING:
1244	    {
1245		u_long len;	/* actual length of string */
1246		u_long alloc;	/* allocate length of string */
1247		u_char *octs;	/* actual octets */
1248		u_long oct;	/* actual octet */
1249		u_char *nocts;	/* to avoid memory leak */
1250		u_char c;	/* actual character */
1251
1252# define STUFFC(C)							\
1253		if (alloc == len) {					\
1254			alloc += 100;					\
1255			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1256				free(octs);				\
1257				return (-1);				\
1258			}						\
1259			octs = nocts;					\
1260		}							\
1261		octs[len++] = (C);
1262
1263		len = alloc = 0;
1264		octs = NULL;
1265
1266		if (*str == '"') {
1267			str++;
1268			while((c = *str++) != '\0') {
1269				if (c == '"') {
1270					if (*str != '\0') {
1271						free(octs);
1272						return (-1);
1273					}
1274					break;
1275				}
1276				if (c == '\\') {
1277					switch (c = *str++) {
1278
1279					  case '\\':
1280						break;
1281					  case 'a':
1282						c = '\a';
1283						break;
1284					  case 'b':
1285						c = '\b';
1286						break;
1287					  case 'f':
1288						c = '\f';
1289						break;
1290					  case 'n':
1291						c = '\n';
1292						break;
1293					  case 'r':
1294						c = '\r';
1295						break;
1296					  case 't':
1297						c = '\t';
1298						break;
1299					  case 'v':
1300						c = '\v';
1301						break;
1302					  case 'x':
1303						c = 0;
1304						if (!isxdigit(*str))
1305							break;
1306						if (isdigit(*str))
1307							c = *str++ - '0';
1308						else if (isupper(*str))
1309							c = *str++ - 'A' + 10;
1310						else
1311							c = *str++ - 'a' + 10;
1312						if (!isxdigit(*str))
1313							break;
1314						if (isdigit(*str))
1315							c += *str++ - '0';
1316						else if (isupper(*str))
1317							c += *str++ - 'A' + 10;
1318						else
1319							c += *str++ - 'a' + 10;
1320						break;
1321					  case '0': case '1': case '2':
1322					  case '3': case '4': case '5':
1323					  case '6': case '7':
1324						c = *str++ - '0';
1325						if (*str < '0' || *str > '7')
1326							break;
1327						c = *str++ - '0';
1328						if (*str < '0' || *str > '7')
1329							break;
1330						c = *str++ - '0';
1331						break;
1332					  default:
1333						break;
1334					}
1335				}
1336				STUFFC(c);
1337			}
1338		} else {
1339			while (*str != '\0') {
1340				oct = strtoul(str, &end, 16);
1341				str = end;
1342				if (oct > 0xff) {
1343					free(octs);
1344					return (-1);
1345				}
1346				STUFFC(oct);
1347				if (*str == ':')
1348					str++;
1349				else if(*str != '\0') {
1350					free(octs);
1351					return (-1);
1352				}
1353			}
1354		}
1355		v->octetstring.octets = octs;
1356		v->octetstring.len = len;
1357		return (0);
1358# undef STUFFC
1359	    }
1360
1361	  case SNMP_SYNTAX_OID:
1362	    {
1363		u_long subid;
1364
1365		v->oid.len = 0;
1366
1367		for (;;) {
1368			if (v->oid.len == ASN_MAXOIDLEN)
1369				return (-1);
1370			subid = strtoul(str, &end, 10);
1371			str = end;
1372			if (subid > ASN_MAXID)
1373				return (-1);
1374			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1375			if (*str == '\0')
1376				break;
1377			if (*str != '.')
1378				return (-1);
1379			str++;
1380		}
1381		return (0);
1382	    }
1383
1384	  case SNMP_SYNTAX_IPADDRESS:
1385	    {
1386		struct hostent *he;
1387		u_long ip[4];
1388		int n;
1389
1390		if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2],
1391		    &ip[3], &n) == 4 && (size_t)n == strlen(str) &&
1392		    ip[0] <= 0xff && ip[1] <= 0xff &&
1393		    ip[2] <= 0xff && ip[3] <= 0xff) {
1394			v->ipaddress[0] = (u_char)ip[0];
1395			v->ipaddress[1] = (u_char)ip[1];
1396			v->ipaddress[2] = (u_char)ip[2];
1397			v->ipaddress[3] = (u_char)ip[3];
1398			return (0);
1399		}
1400
1401		if ((he = gethostbyname(str)) == NULL)
1402			return (-1);
1403		if (he->h_addrtype != AF_INET)
1404			return (-1);
1405
1406		v->ipaddress[0] = he->h_addr[0];
1407		v->ipaddress[1] = he->h_addr[1];
1408		v->ipaddress[2] = he->h_addr[2];
1409		v->ipaddress[3] = he->h_addr[3];
1410		return (0);
1411	    }
1412
1413	  case SNMP_SYNTAX_COUNTER:
1414	  case SNMP_SYNTAX_GAUGE:
1415	  case SNMP_SYNTAX_TIMETICKS:
1416	    {
1417		uint64_t sub;
1418
1419		sub = strtoull(str, &end, 0);
1420		if (*end != '\0' || sub > 0xffffffff)
1421			return (-1);
1422		v->uint32 = (uint32_t)sub;
1423		return (0);
1424	    }
1425
1426	  case SNMP_SYNTAX_COUNTER64:
1427		v->counter64 = strtoull(str, &end, 0);
1428		if (*end != '\0')
1429			return (-1);
1430		return (0);
1431	}
1432	abort();
1433}
1434
1435static void
1436snmp_error_func(const char *fmt, ...)
1437{
1438	va_list ap;
1439
1440	va_start(ap, fmt);
1441	fprintf(stderr, "SNMP: ");
1442	vfprintf(stderr, fmt, ap);
1443	fprintf(stderr, "\n");
1444	va_end(ap);
1445}
1446
1447static void
1448snmp_printf_func(const char *fmt, ...)
1449{
1450	va_list ap;
1451
1452	va_start(ap, fmt);
1453	vfprintf(stderr, fmt, ap);
1454	va_end(ap);
1455}
1456