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