xref: /freebsd/contrib/bsnmp/lib/snmp.c (revision b3e7694832e81d7a904a10f525f8797b753bf0d3)
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 
61 static void snmp_error_func(const char *, ...);
62 static void snmp_printf_func(const char *, ...);
63 
64 void (*snmp_error)(const char *, ...) = snmp_error_func;
65 void (*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  */
71 static enum asn_err
72 get_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  */
198 enum asn_err
199 snmp_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 
245 static enum asn_err
246 parse_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 
283 static enum asn_err
284 parse_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 = 256;
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 
356 static enum snmp_code
357 pdu_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  */
430 enum snmp_code
431 snmp_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 
463 enum snmp_code
464 snmp_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 
550 enum snmp_code
551 snmp_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 
636 enum snmp_code
637 snmp_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  */
679 int
680 snmp_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  */
737 enum snmp_code
738 snmp_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 
841 static enum asn_err
842 snmp_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 
856 enum snmp_code
857 snmp_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  */
908 enum asn_err
909 snmp_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  */
995 enum snmp_code
996 snmp_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 
1011 static void
1012 dump_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 
1077 static __inline void
1078 dump_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 
1089 static __inline void
1090 dump_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 
1098 void
1099 snmp_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 
1154 void
1155 snmp_value_free(struct snmp_value *value)
1156 {
1157 
1158 	if (value->syntax == SNMP_SYNTAX_OCTETSTRING) {
1159 		free(value->v.octetstring.octets);
1160 		value->v.octetstring.octets = NULL;
1161 	}
1162 	value->syntax = SNMP_SYNTAX_NULL;
1163 }
1164 
1165 int
1166 snmp_value_copy(struct snmp_value *to, const struct snmp_value *from)
1167 {
1168 	to->var = from->var;
1169 	to->syntax = from->syntax;
1170 
1171 	if (from->syntax == SNMP_SYNTAX_OCTETSTRING) {
1172 		if ((to->v.octetstring.len = from->v.octetstring.len) == 0)
1173 			to->v.octetstring.octets = NULL;
1174 		else {
1175 			to->v.octetstring.octets = malloc(to->v.octetstring.len);
1176 			if (to->v.octetstring.octets == NULL)
1177 				return (-1);
1178 			(void)memcpy(to->v.octetstring.octets,
1179 			    from->v.octetstring.octets, to->v.octetstring.len);
1180 		}
1181 	} else
1182 		to->v = from->v;
1183 	return (0);
1184 }
1185 
1186 void
1187 snmp_pdu_init_secparams(struct snmp_pdu *pdu)
1188 {
1189 	int32_t rval;
1190 
1191 	if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH)
1192 		pdu->flags |= SNMP_MSG_AUTH_FLAG;
1193 
1194 	switch (pdu->user.priv_proto) {
1195 	case SNMP_PRIV_DES:
1196 		memcpy(pdu->msg_salt, &pdu->engine.engine_boots,
1197 		    sizeof(pdu->engine.engine_boots));
1198 		rval = random();
1199 		memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval,
1200 		    sizeof(int32_t));
1201 		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1202 		break;
1203 	case SNMP_PRIV_AES:
1204 		rval = random();
1205 		memcpy(pdu->msg_salt, &rval, sizeof(int32_t));
1206 		rval = random();
1207 		memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t));
1208 		pdu->flags |= SNMP_MSG_PRIV_FLAG;
1209 		break;
1210 	default:
1211 		break;
1212 	}
1213 }
1214 
1215 void
1216 snmp_pdu_free(struct snmp_pdu *pdu)
1217 {
1218 	u_int i;
1219 
1220 	for (i = 0; i < pdu->nbindings; i++)
1221 		snmp_value_free(&pdu->bindings[i]);
1222 	pdu->nbindings = 0;
1223 }
1224 
1225 /*
1226  * Parse an ASCII SNMP value into the binary form
1227  */
1228 int
1229 snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v)
1230 {
1231 	char *end;
1232 
1233 	switch (syntax) {
1234 
1235 	  case SNMP_SYNTAX_NULL:
1236 	  case SNMP_SYNTAX_NOSUCHOBJECT:
1237 	  case SNMP_SYNTAX_NOSUCHINSTANCE:
1238 	  case SNMP_SYNTAX_ENDOFMIBVIEW:
1239 		if (*str != '\0')
1240 			return (-1);
1241 		return (0);
1242 
1243 	  case SNMP_SYNTAX_INTEGER:
1244 		v->integer = strtoll(str, &end, 0);
1245 		if (*end != '\0')
1246 			return (-1);
1247 		return (0);
1248 
1249 	  case SNMP_SYNTAX_OCTETSTRING:
1250 	    {
1251 		u_long len;	/* actual length of string */
1252 		u_long alloc;	/* allocate length of string */
1253 		u_char *octs;	/* actual octets */
1254 		u_long oct;	/* actual octet */
1255 		u_char *nocts;	/* to avoid memory leak */
1256 		u_char c;	/* actual character */
1257 
1258 # define STUFFC(C)							\
1259 		if (alloc == len) {					\
1260 			alloc += 100;					\
1261 			if ((nocts = realloc(octs, alloc)) == NULL) {	\
1262 				free(octs);				\
1263 				return (-1);				\
1264 			}						\
1265 			octs = nocts;					\
1266 		}							\
1267 		octs[len++] = (C);
1268 
1269 		len = alloc = 0;
1270 		octs = NULL;
1271 
1272 		if (*str == '"') {
1273 			str++;
1274 			while((c = *str++) != '\0') {
1275 				if (c == '"') {
1276 					if (*str != '\0') {
1277 						free(octs);
1278 						return (-1);
1279 					}
1280 					break;
1281 				}
1282 				if (c == '\\') {
1283 					switch (c = *str++) {
1284 
1285 					  case '\\':
1286 						break;
1287 					  case 'a':
1288 						c = '\a';
1289 						break;
1290 					  case 'b':
1291 						c = '\b';
1292 						break;
1293 					  case 'f':
1294 						c = '\f';
1295 						break;
1296 					  case 'n':
1297 						c = '\n';
1298 						break;
1299 					  case 'r':
1300 						c = '\r';
1301 						break;
1302 					  case 't':
1303 						c = '\t';
1304 						break;
1305 					  case 'v':
1306 						c = '\v';
1307 						break;
1308 					  case 'x':
1309 						c = 0;
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 						if (!isxdigit(*str))
1319 							break;
1320 						if (isdigit(*str))
1321 							c += *str++ - '0';
1322 						else if (isupper(*str))
1323 							c += *str++ - 'A' + 10;
1324 						else
1325 							c += *str++ - 'a' + 10;
1326 						break;
1327 					  case '0': case '1': case '2':
1328 					  case '3': case '4': case '5':
1329 					  case '6': case '7':
1330 						c = *str++ - '0';
1331 						if (*str < '0' || *str > '7')
1332 							break;
1333 						c = *str++ - '0';
1334 						if (*str < '0' || *str > '7')
1335 							break;
1336 						c = *str++ - '0';
1337 						break;
1338 					  default:
1339 						break;
1340 					}
1341 				}
1342 				STUFFC(c);
1343 			}
1344 		} else {
1345 			while (*str != '\0') {
1346 				oct = strtoul(str, &end, 16);
1347 				str = end;
1348 				if (oct > 0xff) {
1349 					free(octs);
1350 					return (-1);
1351 				}
1352 				STUFFC(oct);
1353 				if (*str == ':')
1354 					str++;
1355 				else if(*str != '\0') {
1356 					free(octs);
1357 					return (-1);
1358 				}
1359 			}
1360 		}
1361 		v->octetstring.octets = octs;
1362 		v->octetstring.len = len;
1363 		return (0);
1364 # undef STUFFC
1365 	    }
1366 
1367 	  case SNMP_SYNTAX_OID:
1368 	    {
1369 		u_long subid;
1370 
1371 		v->oid.len = 0;
1372 
1373 		for (;;) {
1374 			if (v->oid.len == ASN_MAXOIDLEN)
1375 				return (-1);
1376 			subid = strtoul(str, &end, 10);
1377 			str = end;
1378 			if (subid > ASN_MAXID)
1379 				return (-1);
1380 			v->oid.subs[v->oid.len++] = (asn_subid_t)subid;
1381 			if (*str == '\0')
1382 				break;
1383 			if (*str != '.')
1384 				return (-1);
1385 			str++;
1386 		}
1387 		return (0);
1388 	    }
1389 
1390 	  case SNMP_SYNTAX_IPADDRESS:
1391 	    {
1392 		struct hostent *he;
1393 
1394 		if (inet_pton(AF_INET, str, &v->ipaddress) == 1)
1395 			return (0);
1396 		if ((he = gethostbyname2(str, AF_INET)) == NULL)
1397 			return (-1);
1398 		if (he->h_addrtype != AF_INET)
1399 			return (-1);
1400 
1401 		memcpy(v->ipaddress, he->h_addr, sizeof(v->ipaddress));
1402 
1403 		return (0);
1404 	    }
1405 
1406 	  case SNMP_SYNTAX_COUNTER:
1407 	  case SNMP_SYNTAX_GAUGE:
1408 	  case SNMP_SYNTAX_TIMETICKS:
1409 	    {
1410 		uint64_t sub;
1411 
1412 		sub = strtoull(str, &end, 0);
1413 		if (*end != '\0' || sub > 0xffffffff)
1414 			return (-1);
1415 		v->uint32 = (uint32_t)sub;
1416 		return (0);
1417 	    }
1418 
1419 	  case SNMP_SYNTAX_COUNTER64:
1420 		v->counter64 = strtoull(str, &end, 0);
1421 		if (*end != '\0')
1422 			return (-1);
1423 		return (0);
1424 	}
1425 	abort();
1426 }
1427 
1428 static void
1429 snmp_error_func(const char *fmt, ...)
1430 {
1431 	va_list ap;
1432 
1433 	va_start(ap, fmt);
1434 	fprintf(stderr, "SNMP: ");
1435 	vfprintf(stderr, fmt, ap);
1436 	fprintf(stderr, "\n");
1437 	va_end(ap);
1438 }
1439 
1440 static void
1441 snmp_printf_func(const char *fmt, ...)
1442 {
1443 	va_list ap;
1444 
1445 	va_start(ap, fmt);
1446 	vfprintf(stderr, fmt, ap);
1447 	va_end(ap);
1448 }
1449