PageRenderTime 116ms CodeModel.GetById 12ms app.highlight 95ms RepoModel.GetById 1ms app.codeStats 0ms

/contrib/bsnmp/lib/snmp.c

https://bitbucket.org/freebsd/freebsd-head/
C | 1453 lines | 1146 code | 223 blank | 84 comment | 394 complexity | 84cc7c07a3f1e42cb84f51467d0d25c2 MD5 | raw file
   1/*
   2 * Copyright (c) 2001-2003
   3 *	Fraunhofer Institute for Open Communication Systems (FhG Fokus).
   4 *	All rights reserved.
   5 *
   6 * Author: Harti Brandt <harti@freebsd.org>
   7 * 
   8 * Copyright (c) 2010 The FreeBSD Foundation
   9 * All rights reserved.
  10 *
  11 * Portions of this software were developed by Shteryana Sotirova Shopova
  12 * under sponsorship from the FreeBSD Foundation.
  13 *
  14 * Redistribution and use in source and binary forms, with or without
  15 * modification, are permitted provided that the following conditions
  16 * are met:
  17 * 1. Redistributions of source code must retain the above copyright
  18 *    notice, this list of conditions and the following disclaimer.
  19 * 2. Redistributions in binary form must reproduce the above copyright
  20 *    notice, this list of conditions and the following disclaimer in the
  21 *    documentation and/or other materials provided with the distribution.
  22 * 
  23 * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  26 * ARE DISCLAIMED.  IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE
  27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  33 * SUCH DAMAGE.
  34 *
  35 * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $
  36 *
  37 * SNMP
  38 */
  39#include <sys/types.h>
  40#include <sys/socket.h>
  41#include <stdio.h>
  42#include <stdlib.h>
  43#include <stddef.h>
  44#include <stdarg.h>
  45#ifdef HAVE_STDINT_H
  46#include <stdint.h>
  47#elif defined(HAVE_INTTYPES_H)
  48#include <inttypes.h>
  49#endif
  50#include <string.h>
  51#include <ctype.h>
  52#include <netdb.h>
  53#include <errno.h>
  54
  55#include "asn1.h"
  56#include "snmp.h"
  57#include "snmppriv.h"
  58
  59static void snmp_error_func(const char *, ...);
  60static void snmp_printf_func(const char *, ...);
  61
  62void (*snmp_error)(const char *, ...) = snmp_error_func;
  63void (*snmp_printf)(const char *, ...) = snmp_printf_func;
  64
  65/*
  66 * Get the next variable binding from the list.
  67 * ASN errors on the sequence or the OID are always fatal.
  68 */
  69static enum asn_err
  70get_var_binding(struct asn_buf *b, struct snmp_value *binding)
  71{
  72	u_char type;
  73	asn_len_t len, trailer;
  74	enum asn_err err;
  75
  76	if (asn_get_sequence(b, &len) != ASN_ERR_OK) {
  77		snmp_error("cannot parse varbind header");
  78		return (ASN_ERR_FAILED);
  79	}
  80
  81	/* temporary truncate the length so that the parser does not
  82	 * eat up bytes behind the sequence in the case the encoding is
  83	 * wrong of inner elements. */
  84	trailer = b->asn_len - len;
  85	b->asn_len = len;
  86
  87	if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) {
  88		snmp_error("cannot parse binding objid");
  89		return (ASN_ERR_FAILED);
  90	}
  91	if (asn_get_header(b, &type, &len) != ASN_ERR_OK) {
  92		snmp_error("cannot parse binding value header");
  93		return (ASN_ERR_FAILED);
  94	}
  95
  96	switch (type) {
  97
  98	  case ASN_TYPE_NULL:
  99		binding->syntax = SNMP_SYNTAX_NULL;
 100		err = asn_get_null_raw(b, len);
 101		break;
 102
 103	  case ASN_TYPE_INTEGER:
 104		binding->syntax = SNMP_SYNTAX_INTEGER;
 105		err = asn_get_integer_raw(b, len, &binding->v.integer);
 106		break;
 107
 108	  case ASN_TYPE_OCTETSTRING:
 109		binding->syntax = SNMP_SYNTAX_OCTETSTRING;
 110		binding->v.octetstring.octets = malloc(len);
 111		if (binding->v.octetstring.octets == NULL) {
 112			snmp_error("%s", strerror(errno));
 113			return (ASN_ERR_FAILED);
 114		}
 115		binding->v.octetstring.len = len;
 116		err = asn_get_octetstring_raw(b, len,
 117		    binding->v.octetstring.octets,
 118		    &binding->v.octetstring.len);
 119		if (ASN_ERR_STOPPED(err)) {
 120			free(binding->v.octetstring.octets);
 121			binding->v.octetstring.octets = NULL;
 122		}
 123		break;
 124
 125	  case ASN_TYPE_OBJID:
 126		binding->syntax = SNMP_SYNTAX_OID;
 127		err = asn_get_objid_raw(b, len, &binding->v.oid);
 128		break;
 129
 130	  case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS:
 131		binding->syntax = SNMP_SYNTAX_IPADDRESS;
 132		err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress);
 133		break;
 134
 135	  case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS:
 136		binding->syntax = SNMP_SYNTAX_TIMETICKS;
 137		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
 138		break;
 139
 140	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER:
 141		binding->syntax = SNMP_SYNTAX_COUNTER;
 142		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
 143		break;
 144
 145	  case ASN_CLASS_APPLICATION|ASN_APP_GAUGE:
 146		binding->syntax = SNMP_SYNTAX_GAUGE;
 147		err = asn_get_uint32_raw(b, len, &binding->v.uint32);
 148		break;
 149
 150	  case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64:
 151		binding->syntax = SNMP_SYNTAX_COUNTER64;
 152		err = asn_get_counter64_raw(b, len, &binding->v.counter64);
 153		break;
 154
 155	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT:
 156		binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT;
 157		err = asn_get_null_raw(b, len);
 158		break;
 159
 160	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE:
 161		binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE;
 162		err = asn_get_null_raw(b, len);
 163		break;
 164
 165	  case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW:
 166		binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW;
 167		err = asn_get_null_raw(b, len);
 168		break;
 169
 170	  default:
 171		if ((err = asn_skip(b, len)) == ASN_ERR_OK)
 172			err = ASN_ERR_TAG;
 173		snmp_error("bad binding value type 0x%x", type);
 174		break;
 175	}
 176
 177	if (ASN_ERR_STOPPED(err)) {
 178		snmp_error("cannot parse binding value");
 179		return (err);
 180	}
 181
 182	if (b->asn_len != 0)
 183		snmp_error("ignoring junk at end of binding");
 184
 185	b->asn_len = trailer;
 186
 187	return (err);
 188}
 189
 190/*
 191 * Parse the different PDUs contents. Any ASN error in the outer components
 192 * are fatal. Only errors in variable values may be tolerated. If all
 193 * components can be parsed it returns either ASN_ERR_OK or the first
 194 * error that was found.
 195 */
 196enum asn_err
 197snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp)
 198{
 199	if (pdu->type == SNMP_PDU_TRAP) {
 200		if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) {
 201			snmp_error("cannot parse trap enterprise");
 202			return (ASN_ERR_FAILED);
 203		}
 204		if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) {
 205			snmp_error("cannot parse trap agent address");
 206			return (ASN_ERR_FAILED);
 207		}
 208		if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) {
 209			snmp_error("cannot parse 'generic-trap'");
 210			return (ASN_ERR_FAILED);
 211		}
 212		if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) {
 213			snmp_error("cannot parse 'specific-trap'");
 214			return (ASN_ERR_FAILED);
 215		}
 216		if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) {
 217			snmp_error("cannot parse trap 'time-stamp'");
 218			return (ASN_ERR_FAILED);
 219		}
 220	} else {
 221		if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) {
 222			snmp_error("cannot parse 'request-id'");
 223			return (ASN_ERR_FAILED);
 224		}
 225		if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) {
 226			snmp_error("cannot parse 'error_status'");
 227			return (ASN_ERR_FAILED);
 228		}
 229		if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) {
 230			snmp_error("cannot parse 'error_index'");
 231			return (ASN_ERR_FAILED);
 232		}
 233	}
 234
 235	if (asn_get_sequence(b, lenp) != ASN_ERR_OK) {
 236		snmp_error("cannot get varlist header");
 237		return (ASN_ERR_FAILED);
 238	}
 239
 240	return (ASN_ERR_OK);
 241}
 242
 243static enum asn_err
 244parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip)
 245{
 246	asn_len_t len, trailer;
 247	struct snmp_value *v;
 248	enum asn_err err, err1;
 249
 250	err = snmp_parse_pdus_hdr(b, pdu, &len);
 251	if (ASN_ERR_STOPPED(err))
 252		return (err);
 253
 254	trailer = b->asn_len - len;
 255
 256	v = pdu->bindings;
 257	err = ASN_ERR_OK;
 258	while (b->asn_len != 0) {
 259		if (pdu->nbindings == SNMP_MAX_BINDINGS) {
 260			snmp_error("too many bindings (> %u) in PDU",
 261			    SNMP_MAX_BINDINGS);
 262			return (ASN_ERR_FAILED);
 263		}
 264		err1 = get_var_binding(b, v);
 265		if (ASN_ERR_STOPPED(err1))
 266			return (ASN_ERR_FAILED);
 267		if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) {
 268			err = err1;
 269			*ip = pdu->nbindings + 1;
 270		}
 271		pdu->nbindings++;
 272		v++;
 273	}
 274
 275	b->asn_len = trailer;
 276
 277	return (err);
 278}
 279
 280
 281static enum asn_err
 282parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu)
 283{
 284	asn_len_t octs_len;
 285	u_char buf[256]; /* XXX: calc max possible size here */
 286	struct asn_buf tb;
 287
 288	memset(buf, 0, 256);
 289	tb.asn_ptr = buf;
 290	tb.asn_len = 256;
 291
 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
 352static enum snmp_code
 353pdu_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 */
 426enum snmp_code
 427snmp_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
 459enum snmp_code
 460snmp_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
 546enum snmp_code
 547snmp_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
 632enum snmp_code
 633snmp_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 */
 675int
 676snmp_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 */
 733enum snmp_code
 734snmp_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
 837static enum asn_err
 838snmp_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
 852enum snmp_code
 853snmp_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 */
 904enum asn_err
 905snmp_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 */
 991enum snmp_code
 992snmp_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
1007static void
1008dump_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
1073static __inline void
1074dump_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
1085static __inline void
1086dump_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
1094void
1095snmp_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
1150void
1151snmp_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
1158int
1159snmp_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
1179void
1180snmp_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
1208void
1209snmp_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 */
1220int
1221snmp_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
1433static void
1434snmp_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
1445static void
1446snmp_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}