xref: /freebsd/contrib/bsnmp/lib/snmp.c (revision 09d325677d53a12c79a43664ff29871e92247629)
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 	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 
354 static enum snmp_code
355 pdu_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  */
428 enum snmp_code
429 snmp_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 
461 enum snmp_code
462 snmp_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 
548 enum snmp_code
549 snmp_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 
634 enum snmp_code
635 snmp_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  */
677 int
678 snmp_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  */
735 enum snmp_code
736 snmp_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 
839 static enum asn_err
840 snmp_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 
854 enum snmp_code
855 snmp_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  */
906 enum asn_err
907 snmp_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  */
993 enum snmp_code
994 snmp_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 
1009 static void
1010 dump_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 
1075 static __inline void
1076 dump_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 
1087 static __inline void
1088 dump_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 
1096 void
1097 snmp_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 
1152 void
1153 snmp_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 
1160 int
1161 snmp_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 
1181 void
1182 snmp_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 
1210 void
1211 snmp_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  */
1222 int
1223 snmp_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 
1435 static void
1436 snmp_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 
1447 static void
1448 snmp_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