xref: /freebsd/contrib/bsnmp/lib/snmp.c (revision 7750ad47a9a7dbc83f87158464170c8640723293)
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 
59 static void snmp_error_func(const char *, ...);
60 static void snmp_printf_func(const char *, ...);
61 
62 void (*snmp_error)(const char *, ...) = snmp_error_func;
63 void (*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  */
69 static enum asn_err
70 get_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  */
196 enum asn_err
197 snmp_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 
243 static enum asn_err
244 parse_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 
281 static enum asn_err
282 parse_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 
352 static enum snmp_code
353 pdu_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  */
426 enum snmp_code
427 snmp_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 
459 enum snmp_code
460 snmp_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 
546 enum snmp_code
547 snmp_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 
632 enum snmp_code
633 snmp_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  */
675 int
676 snmp_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  */
733 enum snmp_code
734 snmp_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 
837 static enum asn_err
838 snmp_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 
852 enum snmp_code
853 snmp_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  */
904 enum asn_err
905 snmp_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  */
991 enum snmp_code
992 snmp_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 
1007 static void
1008 dump_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 
1073 static __inline void
1074 dump_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 
1085 static __inline void
1086 dump_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 
1094 void
1095 snmp_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 
1150 void
1151 snmp_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 
1158 int
1159 snmp_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 
1179 void
1180 snmp_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 
1208 void
1209 snmp_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  */
1220 int
1221 snmp_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 
1433 static void
1434 snmp_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 
1445 static void
1446 snmp_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