1122394Sharti/* 2122394Sharti * Copyright (c) 2001-2003 3122394Sharti * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4122394Sharti * All rights reserved. 5122394Sharti * 6122394Sharti * Author: Harti Brandt <harti@freebsd.org> 7133211Sharti * 8216294Ssyrinx * Copyright (c) 2010 The FreeBSD Foundation 9216294Ssyrinx * All rights reserved. 10216294Ssyrinx * 11216294Ssyrinx * Portions of this software were developed by Shteryana Sotirova Shopova 12216294Ssyrinx * under sponsorship from the FreeBSD Foundation. 13216294Ssyrinx * 14133211Sharti * Redistribution and use in source and binary forms, with or without 15133211Sharti * modification, are permitted provided that the following conditions 16133211Sharti * are met: 17133211Sharti * 1. Redistributions of source code must retain the above copyright 18133211Sharti * notice, this list of conditions and the following disclaimer. 19122394Sharti * 2. Redistributions in binary form must reproduce the above copyright 20122394Sharti * notice, this list of conditions and the following disclaimer in the 21122394Sharti * documentation and/or other materials provided with the distribution. 22133211Sharti * 23133211Sharti * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 24133211Sharti * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 25133211Sharti * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 26133211Sharti * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 27133211Sharti * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 28133211Sharti * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 29133211Sharti * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 30133211Sharti * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 31133211Sharti * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 32133211Sharti * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 33133211Sharti * SUCH DAMAGE. 34122394Sharti * 35150920Sharti * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $ 36122394Sharti * 37122394Sharti * SNMP 38122394Sharti */ 39122394Sharti#include <sys/types.h> 40122394Sharti#include <sys/socket.h> 41122394Sharti#include <stdio.h> 42122394Sharti#include <stdlib.h> 43122394Sharti#include <stddef.h> 44122394Sharti#include <stdarg.h> 45150920Sharti#ifdef HAVE_STDINT_H 46133211Sharti#include <stdint.h> 47150920Sharti#elif defined(HAVE_INTTYPES_H) 48150920Sharti#include <inttypes.h> 49150920Sharti#endif 50122394Sharti#include <string.h> 51122394Sharti#include <ctype.h> 52122394Sharti#include <netdb.h> 53122394Sharti#include <errno.h> 54122394Sharti 55122394Sharti#include "asn1.h" 56122394Sharti#include "snmp.h" 57122394Sharti#include "snmppriv.h" 58122394Sharti 59122394Shartistatic void snmp_error_func(const char *, ...); 60122394Shartistatic void snmp_printf_func(const char *, ...); 61122394Sharti 62122394Shartivoid (*snmp_error)(const char *, ...) = snmp_error_func; 63122394Shartivoid (*snmp_printf)(const char *, ...) = snmp_printf_func; 64122394Sharti 65122394Sharti/* 66122394Sharti * Get the next variable binding from the list. 67122394Sharti * ASN errors on the sequence or the OID are always fatal. 68122394Sharti */ 69122394Shartistatic enum asn_err 70122394Shartiget_var_binding(struct asn_buf *b, struct snmp_value *binding) 71122394Sharti{ 72122394Sharti u_char type; 73122394Sharti asn_len_t len, trailer; 74122394Sharti enum asn_err err; 75122394Sharti 76122394Sharti if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 77122394Sharti snmp_error("cannot parse varbind header"); 78122394Sharti return (ASN_ERR_FAILED); 79122394Sharti } 80122394Sharti 81122394Sharti /* temporary truncate the length so that the parser does not 82122394Sharti * eat up bytes behind the sequence in the case the encoding is 83122394Sharti * wrong of inner elements. */ 84122394Sharti trailer = b->asn_len - len; 85122394Sharti b->asn_len = len; 86122394Sharti 87122394Sharti if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { 88122394Sharti snmp_error("cannot parse binding objid"); 89122394Sharti return (ASN_ERR_FAILED); 90122394Sharti } 91122394Sharti if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 92122394Sharti snmp_error("cannot parse binding value header"); 93122394Sharti return (ASN_ERR_FAILED); 94122394Sharti } 95122394Sharti 96122394Sharti switch (type) { 97122394Sharti 98122394Sharti case ASN_TYPE_NULL: 99122394Sharti binding->syntax = SNMP_SYNTAX_NULL; 100122394Sharti err = asn_get_null_raw(b, len); 101122394Sharti break; 102122394Sharti 103122394Sharti case ASN_TYPE_INTEGER: 104122394Sharti binding->syntax = SNMP_SYNTAX_INTEGER; 105122394Sharti err = asn_get_integer_raw(b, len, &binding->v.integer); 106122394Sharti break; 107122394Sharti 108122394Sharti case ASN_TYPE_OCTETSTRING: 109122394Sharti binding->syntax = SNMP_SYNTAX_OCTETSTRING; 110122394Sharti binding->v.octetstring.octets = malloc(len); 111122394Sharti if (binding->v.octetstring.octets == NULL) { 112122394Sharti snmp_error("%s", strerror(errno)); 113122394Sharti return (ASN_ERR_FAILED); 114122394Sharti } 115122394Sharti binding->v.octetstring.len = len; 116122394Sharti err = asn_get_octetstring_raw(b, len, 117122394Sharti binding->v.octetstring.octets, 118122394Sharti &binding->v.octetstring.len); 119122394Sharti if (ASN_ERR_STOPPED(err)) { 120122394Sharti free(binding->v.octetstring.octets); 121122394Sharti binding->v.octetstring.octets = NULL; 122122394Sharti } 123122394Sharti break; 124122394Sharti 125122394Sharti case ASN_TYPE_OBJID: 126122394Sharti binding->syntax = SNMP_SYNTAX_OID; 127122394Sharti err = asn_get_objid_raw(b, len, &binding->v.oid); 128122394Sharti break; 129122394Sharti 130122394Sharti case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: 131122394Sharti binding->syntax = SNMP_SYNTAX_IPADDRESS; 132122394Sharti err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); 133122394Sharti break; 134122394Sharti 135122394Sharti case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: 136122394Sharti binding->syntax = SNMP_SYNTAX_TIMETICKS; 137122394Sharti err = asn_get_uint32_raw(b, len, &binding->v.uint32); 138122394Sharti break; 139122394Sharti 140122394Sharti case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: 141122394Sharti binding->syntax = SNMP_SYNTAX_COUNTER; 142122394Sharti err = asn_get_uint32_raw(b, len, &binding->v.uint32); 143122394Sharti break; 144122394Sharti 145122394Sharti case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: 146122394Sharti binding->syntax = SNMP_SYNTAX_GAUGE; 147122394Sharti err = asn_get_uint32_raw(b, len, &binding->v.uint32); 148122394Sharti break; 149122394Sharti 150122394Sharti case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: 151122394Sharti binding->syntax = SNMP_SYNTAX_COUNTER64; 152122394Sharti err = asn_get_counter64_raw(b, len, &binding->v.counter64); 153122394Sharti break; 154122394Sharti 155122394Sharti case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: 156122394Sharti binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; 157122394Sharti err = asn_get_null_raw(b, len); 158122394Sharti break; 159122394Sharti 160122394Sharti case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: 161122394Sharti binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 162122394Sharti err = asn_get_null_raw(b, len); 163122394Sharti break; 164122394Sharti 165122394Sharti case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: 166122394Sharti binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 167122394Sharti err = asn_get_null_raw(b, len); 168122394Sharti break; 169122394Sharti 170122394Sharti default: 171122394Sharti if ((err = asn_skip(b, len)) == ASN_ERR_OK) 172122394Sharti err = ASN_ERR_TAG; 173122394Sharti snmp_error("bad binding value type 0x%x", type); 174122394Sharti break; 175122394Sharti } 176122394Sharti 177122394Sharti if (ASN_ERR_STOPPED(err)) { 178122394Sharti snmp_error("cannot parse binding value"); 179122394Sharti return (err); 180122394Sharti } 181122394Sharti 182122394Sharti if (b->asn_len != 0) 183122394Sharti snmp_error("ignoring junk at end of binding"); 184122394Sharti 185122394Sharti b->asn_len = trailer; 186122394Sharti 187122394Sharti return (err); 188122394Sharti} 189122394Sharti 190122394Sharti/* 191122394Sharti * Parse the different PDUs contents. Any ASN error in the outer components 192122394Sharti * are fatal. Only errors in variable values may be tolerated. If all 193122394Sharti * components can be parsed it returns either ASN_ERR_OK or the first 194122394Sharti * error that was found. 195122394Sharti */ 196122394Shartienum asn_err 197122394Shartisnmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 198122394Sharti{ 199122394Sharti if (pdu->type == SNMP_PDU_TRAP) { 200122394Sharti if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { 201122394Sharti snmp_error("cannot parse trap enterprise"); 202122394Sharti return (ASN_ERR_FAILED); 203122394Sharti } 204122394Sharti if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { 205122394Sharti snmp_error("cannot parse trap agent address"); 206122394Sharti return (ASN_ERR_FAILED); 207122394Sharti } 208122394Sharti if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { 209122394Sharti snmp_error("cannot parse 'generic-trap'"); 210122394Sharti return (ASN_ERR_FAILED); 211122394Sharti } 212122394Sharti if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { 213122394Sharti snmp_error("cannot parse 'specific-trap'"); 214122394Sharti return (ASN_ERR_FAILED); 215122394Sharti } 216122394Sharti if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { 217122394Sharti snmp_error("cannot parse trap 'time-stamp'"); 218122394Sharti return (ASN_ERR_FAILED); 219122394Sharti } 220122394Sharti } else { 221122394Sharti if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { 222122394Sharti snmp_error("cannot parse 'request-id'"); 223122394Sharti return (ASN_ERR_FAILED); 224122394Sharti } 225122394Sharti if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { 226122394Sharti snmp_error("cannot parse 'error_status'"); 227122394Sharti return (ASN_ERR_FAILED); 228122394Sharti } 229122394Sharti if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { 230122394Sharti snmp_error("cannot parse 'error_index'"); 231122394Sharti return (ASN_ERR_FAILED); 232122394Sharti } 233122394Sharti } 234122394Sharti 235122394Sharti if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { 236122394Sharti snmp_error("cannot get varlist header"); 237122394Sharti return (ASN_ERR_FAILED); 238122394Sharti } 239122394Sharti 240122394Sharti return (ASN_ERR_OK); 241122394Sharti} 242122394Sharti 243122394Shartistatic enum asn_err 244122394Shartiparse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 245122394Sharti{ 246122394Sharti asn_len_t len, trailer; 247122394Sharti struct snmp_value *v; 248122394Sharti enum asn_err err, err1; 249122394Sharti 250122394Sharti err = snmp_parse_pdus_hdr(b, pdu, &len); 251122394Sharti if (ASN_ERR_STOPPED(err)) 252122394Sharti return (err); 253122394Sharti 254122394Sharti trailer = b->asn_len - len; 255122394Sharti 256122394Sharti v = pdu->bindings; 257122394Sharti err = ASN_ERR_OK; 258122394Sharti while (b->asn_len != 0) { 259122394Sharti if (pdu->nbindings == SNMP_MAX_BINDINGS) { 260122394Sharti snmp_error("too many bindings (> %u) in PDU", 261122394Sharti SNMP_MAX_BINDINGS); 262122394Sharti return (ASN_ERR_FAILED); 263122394Sharti } 264122394Sharti err1 = get_var_binding(b, v); 265122394Sharti if (ASN_ERR_STOPPED(err1)) 266122394Sharti return (ASN_ERR_FAILED); 267122394Sharti if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { 268122394Sharti err = err1; 269122394Sharti *ip = pdu->nbindings + 1; 270122394Sharti } 271122394Sharti pdu->nbindings++; 272122394Sharti v++; 273122394Sharti } 274122394Sharti 275122394Sharti b->asn_len = trailer; 276122394Sharti 277122394Sharti return (err); 278122394Sharti} 279122394Sharti 280216294Ssyrinx 281216294Ssyrinxstatic enum asn_err 282216294Ssyrinxparse_secparams(struct asn_buf *b, struct snmp_pdu *pdu) 283216294Ssyrinx{ 284216294Ssyrinx asn_len_t octs_len; 285216294Ssyrinx u_char buf[256]; /* XXX: calc max possible size here */ 286216294Ssyrinx struct asn_buf tb; 287216294Ssyrinx 288216294Ssyrinx memset(buf, 0, 256); 289216294Ssyrinx tb.asn_ptr = buf; 290216294Ssyrinx tb.asn_len = 256; 291216294Ssyrinx 292216294Ssyrinx if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) { 293216294Ssyrinx snmp_error("cannot parse usm header"); 294216294Ssyrinx return (ASN_ERR_FAILED); 295216294Ssyrinx } 296216294Ssyrinx 297216294Ssyrinx if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) { 298216294Ssyrinx snmp_error("cannot decode usm header"); 299216294Ssyrinx return (ASN_ERR_FAILED); 300216294Ssyrinx } 301216294Ssyrinx 302216294Ssyrinx octs_len = SNMP_ENGINE_ID_SIZ; 303216294Ssyrinx if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id, 304216294Ssyrinx &octs_len) != ASN_ERR_OK) { 305216294Ssyrinx snmp_error("cannot decode msg engine id"); 306216294Ssyrinx return (ASN_ERR_FAILED); 307216294Ssyrinx } 308216294Ssyrinx pdu->engine.engine_len = octs_len; 309216294Ssyrinx 310216294Ssyrinx if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) { 311216294Ssyrinx snmp_error("cannot decode msg engine boots"); 312216294Ssyrinx return (ASN_ERR_FAILED); 313216294Ssyrinx } 314216294Ssyrinx 315216294Ssyrinx if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) { 316216294Ssyrinx snmp_error("cannot decode msg engine time"); 317216294Ssyrinx return (ASN_ERR_FAILED); 318216294Ssyrinx } 319216294Ssyrinx 320216294Ssyrinx octs_len = SNMP_ADM_STR32_SIZ - 1; 321216294Ssyrinx if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len) 322216294Ssyrinx != ASN_ERR_OK) { 323216294Ssyrinx snmp_error("cannot decode msg user name"); 324216294Ssyrinx return (ASN_ERR_FAILED); 325216294Ssyrinx } 326216294Ssyrinx pdu->user.sec_name[octs_len] = '\0'; 327216294Ssyrinx 328216294Ssyrinx octs_len = sizeof(pdu->msg_digest); 329216294Ssyrinx if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) != 330216294Ssyrinx ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 && 331216294Ssyrinx octs_len != sizeof(pdu->msg_digest))) { 332216294Ssyrinx snmp_error("cannot decode msg authentication param"); 333216294Ssyrinx return (ASN_ERR_FAILED); 334216294Ssyrinx } 335216294Ssyrinx 336216294Ssyrinx octs_len = sizeof(pdu->msg_salt); 337216294Ssyrinx if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) != 338216294Ssyrinx ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 339216294Ssyrinx octs_len != sizeof(pdu->msg_salt))) { 340216294Ssyrinx snmp_error("cannot decode msg authentication param"); 341216294Ssyrinx return (ASN_ERR_FAILED); 342216294Ssyrinx } 343216294Ssyrinx 344216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 345216294Ssyrinx pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE; 346216294Ssyrinx pdu->digest_ptr -= octs_len + ASN_MAXLENLEN; 347216294Ssyrinx } 348216294Ssyrinx 349216294Ssyrinx return (ASN_ERR_OK); 350216294Ssyrinx} 351216294Ssyrinx 352216294Ssyrinxstatic enum snmp_code 353216294Ssyrinxpdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu) 354216294Ssyrinx{ 355216294Ssyrinx u_char buf[256], *sptr; 356216294Ssyrinx struct asn_buf tb; 357216294Ssyrinx size_t auth_off, moved = 0; 358216294Ssyrinx 359216294Ssyrinx auth_off = 0; 360216294Ssyrinx memset(buf, 0, 256); 361216294Ssyrinx tb.asn_ptr = buf; 362216294Ssyrinx tb.asn_len = 256; 363216294Ssyrinx 364216294Ssyrinx if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 365216294Ssyrinx &sptr) != ASN_ERR_OK) 366216294Ssyrinx return (SNMP_CODE_FAILED); 367216294Ssyrinx 368216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id, 369216294Ssyrinx pdu->engine.engine_len) != ASN_ERR_OK) 370216294Ssyrinx return (SNMP_CODE_FAILED); 371216294Ssyrinx 372216294Ssyrinx if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK) 373216294Ssyrinx return (SNMP_CODE_FAILED); 374216294Ssyrinx 375216294Ssyrinx if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK) 376216294Ssyrinx return (SNMP_CODE_FAILED); 377216294Ssyrinx 378216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name, 379216294Ssyrinx strlen(pdu->user.sec_name)) != ASN_ERR_OK) 380216294Ssyrinx return (SNMP_CODE_FAILED); 381216294Ssyrinx 382216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 383216294Ssyrinx auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN; 384216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 385216294Ssyrinx sizeof(pdu->msg_digest)) != ASN_ERR_OK) 386216294Ssyrinx return (SNMP_CODE_FAILED); 387216294Ssyrinx } else { 388216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0) 389216294Ssyrinx != ASN_ERR_OK) 390216294Ssyrinx return (SNMP_CODE_FAILED); 391216294Ssyrinx } 392216294Ssyrinx 393216294Ssyrinx if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) { 394216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 395216294Ssyrinx sizeof(pdu->msg_salt)) != ASN_ERR_OK) 396216294Ssyrinx return (SNMP_CODE_FAILED); 397216294Ssyrinx } else { 398216294Ssyrinx if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0) 399216294Ssyrinx != ASN_ERR_OK) 400216294Ssyrinx return (SNMP_CODE_FAILED); 401216294Ssyrinx } 402216294Ssyrinx 403216294Ssyrinx if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK) 404216294Ssyrinx return (SNMP_CODE_FAILED); 405216294Ssyrinx 406216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) 407216294Ssyrinx pdu->digest_ptr = b->asn_ptr + auth_off - moved; 408216294Ssyrinx 409216294Ssyrinx if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK) 410216294Ssyrinx return (SNMP_CODE_FAILED); 411216294Ssyrinx pdu->digest_ptr += ASN_MAXLENLEN; 412216294Ssyrinx 413216294Ssyrinx if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b, 414216294Ssyrinx ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK) 415216294Ssyrinx return (SNMP_CODE_FAILED); 416216294Ssyrinx 417216294Ssyrinx return (SNMP_CODE_OK); 418216294Ssyrinx} 419216294Ssyrinx 420122394Sharti/* 421216294Ssyrinx * Decode the PDU except for the variable bindings itself. 422216294Ssyrinx * If decoding fails because of a bad binding, but the rest can be 423216294Ssyrinx * decoded, ip points to the index of the failed variable (errors 424216294Ssyrinx * OORANGE, BADLEN or BADVERS). 425122394Sharti */ 426216294Ssyrinxenum snmp_code 427216294Ssyrinxsnmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 428122394Sharti{ 429216294Ssyrinx enum snmp_code code; 430216294Ssyrinx 431216294Ssyrinx if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK) 432216294Ssyrinx return (code); 433216294Ssyrinx 434216294Ssyrinx if (pdu->version == SNMP_V3) { 435216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) 436216294Ssyrinx return (SNMP_CODE_FAILED); 437216294Ssyrinx if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK) 438216294Ssyrinx return (code); 439216294Ssyrinx } 440216294Ssyrinx 441216294Ssyrinx code = snmp_pdu_decode_scoped(b, pdu, ip); 442216294Ssyrinx 443216294Ssyrinx switch (code) { 444216294Ssyrinx case SNMP_CODE_FAILED: 445216294Ssyrinx snmp_pdu_free(pdu); 446216294Ssyrinx break; 447216294Ssyrinx 448216294Ssyrinx case SNMP_CODE_BADENC: 449216294Ssyrinx if (pdu->version == SNMP_Verr) 450216294Ssyrinx return (SNMP_CODE_BADVERS); 451216294Ssyrinx 452216294Ssyrinx default: 453216294Ssyrinx break; 454216294Ssyrinx } 455216294Ssyrinx 456216294Ssyrinx return (code); 457216294Ssyrinx} 458216294Ssyrinx 459216294Ssyrinxenum snmp_code 460216294Ssyrinxsnmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu) 461216294Ssyrinx{ 462122394Sharti int32_t version; 463216294Ssyrinx u_int octs_len; 464216294Ssyrinx asn_len_t len; 465122394Sharti 466216294Ssyrinx pdu->outer_ptr = b->asn_ptr; 467216294Ssyrinx pdu->outer_len = b->asn_len; 468216294Ssyrinx 469216294Ssyrinx if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 470216294Ssyrinx snmp_error("cannot decode pdu header"); 471216294Ssyrinx return (SNMP_CODE_FAILED); 472216294Ssyrinx } 473216294Ssyrinx if (b->asn_len < len) { 474216294Ssyrinx snmp_error("outer sequence value too short"); 475216294Ssyrinx return (SNMP_CODE_FAILED); 476216294Ssyrinx } 477216294Ssyrinx if (b->asn_len != len) { 478216294Ssyrinx snmp_error("ignoring trailing junk in message"); 479216294Ssyrinx b->asn_len = len; 480216294Ssyrinx } 481216294Ssyrinx 482122394Sharti if (asn_get_integer(b, &version) != ASN_ERR_OK) { 483122394Sharti snmp_error("cannot decode version"); 484216294Ssyrinx return (SNMP_CODE_FAILED); 485122394Sharti } 486122394Sharti 487216294Ssyrinx if (version == 0) 488122394Sharti pdu->version = SNMP_V1; 489216294Ssyrinx else if (version == 1) 490122394Sharti pdu->version = SNMP_V2c; 491216294Ssyrinx else if (version == 3) 492216294Ssyrinx pdu->version = SNMP_V3; 493216294Ssyrinx else { 494122394Sharti pdu->version = SNMP_Verr; 495122394Sharti snmp_error("unsupported SNMP version"); 496216294Ssyrinx return (SNMP_CODE_BADENC); 497122394Sharti } 498122394Sharti 499216294Ssyrinx if (pdu->version == SNMP_V3) { 500216294Ssyrinx if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 501216294Ssyrinx snmp_error("cannot decode pdu global data header"); 502216294Ssyrinx return (SNMP_CODE_FAILED); 503216294Ssyrinx } 504216294Ssyrinx 505216294Ssyrinx if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) { 506216294Ssyrinx snmp_error("cannot decode msg indetifier"); 507216294Ssyrinx return (SNMP_CODE_FAILED); 508216294Ssyrinx } 509216294Ssyrinx 510216294Ssyrinx if (asn_get_integer(b, &pdu->engine.max_msg_size) 511216294Ssyrinx != ASN_ERR_OK) { 512216294Ssyrinx snmp_error("cannot decode msg size"); 513216294Ssyrinx return (SNMP_CODE_FAILED); 514216294Ssyrinx } 515216294Ssyrinx 516216294Ssyrinx octs_len = 1; 517216294Ssyrinx if (asn_get_octetstring(b, (u_char *)&pdu->flags, 518216294Ssyrinx &octs_len) != ASN_ERR_OK) { 519216294Ssyrinx snmp_error("cannot decode msg flags"); 520216294Ssyrinx return (SNMP_CODE_FAILED); 521216294Ssyrinx } 522216294Ssyrinx 523216294Ssyrinx if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) { 524216294Ssyrinx snmp_error("cannot decode msg size"); 525216294Ssyrinx return (SNMP_CODE_FAILED); 526216294Ssyrinx } 527216294Ssyrinx 528216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) 529216294Ssyrinx return (SNMP_CODE_FAILED); 530216294Ssyrinx 531216294Ssyrinx if (parse_secparams(b, pdu) != ASN_ERR_OK) 532216294Ssyrinx return (SNMP_CODE_FAILED); 533216294Ssyrinx } else { 534216294Ssyrinx octs_len = SNMP_COMMUNITY_MAXLEN; 535216294Ssyrinx if (asn_get_octetstring(b, (u_char *)pdu->community, 536216294Ssyrinx &octs_len) != ASN_ERR_OK) { 537216294Ssyrinx snmp_error("cannot decode community"); 538216294Ssyrinx return (SNMP_CODE_FAILED); 539216294Ssyrinx } 540216294Ssyrinx pdu->community[octs_len] = '\0'; 541122394Sharti } 542122394Sharti 543216294Ssyrinx return (SNMP_CODE_OK); 544216294Ssyrinx} 545216294Ssyrinx 546216294Ssyrinxenum snmp_code 547216294Ssyrinxsnmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 548216294Ssyrinx{ 549216294Ssyrinx u_char type; 550216294Ssyrinx asn_len_t len, trailer; 551216294Ssyrinx enum asn_err err; 552216294Ssyrinx 553216294Ssyrinx if (pdu->version == SNMP_V3) { 554216294Ssyrinx if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 555216294Ssyrinx snmp_error("cannot decode scoped pdu header"); 556216294Ssyrinx return (SNMP_CODE_FAILED); 557216294Ssyrinx } 558216294Ssyrinx 559216294Ssyrinx len = SNMP_ENGINE_ID_SIZ; 560216294Ssyrinx if (asn_get_octetstring(b, (u_char *)&pdu->context_engine, 561216294Ssyrinx &len) != ASN_ERR_OK) { 562216294Ssyrinx snmp_error("cannot decode msg context engine"); 563216294Ssyrinx return (SNMP_CODE_FAILED); 564216294Ssyrinx } 565216294Ssyrinx pdu->context_engine_len = len; 566216294Ssyrinx 567216294Ssyrinx len = SNMP_CONTEXT_NAME_SIZ; 568216294Ssyrinx if (asn_get_octetstring(b, (u_char *)&pdu->context_name, 569216294Ssyrinx &len) != ASN_ERR_OK) { 570216294Ssyrinx snmp_error("cannot decode msg context name"); 571216294Ssyrinx return (SNMP_CODE_FAILED); 572216294Ssyrinx } 573216294Ssyrinx pdu->context_name[len] = '\0'; 574216294Ssyrinx } 575216294Ssyrinx 576216294Ssyrinx if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 577122394Sharti snmp_error("cannot get pdu header"); 578216294Ssyrinx return (SNMP_CODE_FAILED); 579122394Sharti } 580122394Sharti if ((type & ~ASN_TYPE_MASK) != 581122394Sharti (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 582122394Sharti snmp_error("bad pdu header tag"); 583216294Ssyrinx return (SNMP_CODE_FAILED); 584122394Sharti } 585122394Sharti pdu->type = type & ASN_TYPE_MASK; 586122394Sharti 587122394Sharti switch (pdu->type) { 588122394Sharti 589122394Sharti case SNMP_PDU_GET: 590122394Sharti case SNMP_PDU_GETNEXT: 591122394Sharti case SNMP_PDU_RESPONSE: 592122394Sharti case SNMP_PDU_SET: 593122394Sharti break; 594122394Sharti 595122394Sharti case SNMP_PDU_TRAP: 596122394Sharti if (pdu->version != SNMP_V1) { 597122394Sharti snmp_error("bad pdu type %u", pdu->type); 598216294Ssyrinx return (SNMP_CODE_FAILED); 599122394Sharti } 600122394Sharti break; 601122394Sharti 602122394Sharti case SNMP_PDU_GETBULK: 603122394Sharti case SNMP_PDU_INFORM: 604122394Sharti case SNMP_PDU_TRAP2: 605122394Sharti case SNMP_PDU_REPORT: 606122394Sharti if (pdu->version == SNMP_V1) { 607122394Sharti snmp_error("bad pdu type %u", pdu->type); 608216294Ssyrinx return (SNMP_CODE_FAILED); 609122394Sharti } 610122394Sharti break; 611122394Sharti 612122394Sharti default: 613122394Sharti snmp_error("bad pdu type %u", pdu->type); 614216294Ssyrinx return (SNMP_CODE_FAILED); 615122394Sharti } 616122394Sharti 617122394Sharti trailer = b->asn_len - len; 618122394Sharti b->asn_len = len; 619122394Sharti 620122394Sharti err = parse_pdus(b, pdu, ip); 621122394Sharti if (ASN_ERR_STOPPED(err)) 622216294Ssyrinx return (SNMP_CODE_FAILED); 623122394Sharti 624122394Sharti if (b->asn_len != 0) 625122394Sharti snmp_error("ignoring trailing junk after pdu"); 626122394Sharti 627122394Sharti b->asn_len = trailer; 628122394Sharti 629216294Ssyrinx return (SNMP_CODE_OK); 630122394Sharti} 631122394Sharti 632122394Shartienum snmp_code 633216294Ssyrinxsnmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu) 634122394Sharti{ 635216294Ssyrinx u_char type; 636216294Ssyrinx enum snmp_code code; 637216294Ssyrinx uint8_t digest[SNMP_USM_AUTH_SIZE]; 638122394Sharti 639216294Ssyrinx if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && 640216294Ssyrinx (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) 641216294Ssyrinx return (SNMP_CODE_BADSECLEVEL); 642122394Sharti 643216482Ssyrinx if ((code = snmp_pdu_calc_digest(pdu, digest)) != 644216294Ssyrinx SNMP_CODE_OK) 645122394Sharti return (SNMP_CODE_FAILED); 646216294Ssyrinx 647216294Ssyrinx if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && 648216294Ssyrinx memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0) 649216294Ssyrinx return (SNMP_CODE_BADDIGEST); 650216294Ssyrinx 651216294Ssyrinx if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type, 652216294Ssyrinx &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) { 653216294Ssyrinx snmp_error("cannot decode encrypted pdu"); 654122394Sharti return (SNMP_CODE_FAILED); 655122394Sharti } 656216294Ssyrinx pdu->scoped_ptr = b->asn_ptr; 657122394Sharti 658216294Ssyrinx if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && 659216294Ssyrinx (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0) 660216294Ssyrinx return (SNMP_CODE_BADSECLEVEL); 661122394Sharti 662216482Ssyrinx if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK) 663122394Sharti return (SNMP_CODE_FAILED); 664122394Sharti 665216294Ssyrinx return (code); 666122394Sharti} 667122394Sharti 668122394Sharti/* 669124861Sharti * Check whether what we have is the complete PDU by snooping at the 670124861Sharti * enclosing structure header. This returns: 671124861Sharti * -1 if there are ASN.1 errors 672124861Sharti * 0 if we need more data 673124861Sharti * > 0 the length of this PDU 674124861Sharti */ 675124861Shartiint 676124861Shartisnmp_pdu_snoop(const struct asn_buf *b0) 677124861Sharti{ 678124861Sharti u_int length; 679124861Sharti asn_len_t len; 680124861Sharti struct asn_buf b = *b0; 681124861Sharti 682124861Sharti /* <0x10|0x20> <len> <data...> */ 683124861Sharti 684124861Sharti if (b.asn_len == 0) 685124861Sharti return (0); 686124861Sharti if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { 687124861Sharti asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); 688124861Sharti return (-1); 689124861Sharti } 690124861Sharti b.asn_len--; 691124861Sharti b.asn_cptr++; 692124861Sharti 693124861Sharti if (b.asn_len == 0) 694124861Sharti return (0); 695124861Sharti 696124861Sharti if (*b.asn_cptr & 0x80) { 697124861Sharti /* long length */ 698124861Sharti length = *b.asn_cptr++ & 0x7f; 699124861Sharti b.asn_len--; 700124861Sharti if (length == 0) { 701124861Sharti asn_error(&b, "indefinite length not supported"); 702124861Sharti return (-1); 703124861Sharti } 704124861Sharti if (length > ASN_MAXLENLEN) { 705124861Sharti asn_error(&b, "long length too long (%u)", length); 706124861Sharti return (-1); 707124861Sharti } 708124861Sharti if (length > b.asn_len) 709124861Sharti return (0); 710124861Sharti len = 0; 711124861Sharti while (length--) { 712124861Sharti len = (len << 8) | *b.asn_cptr++; 713124861Sharti b.asn_len--; 714124861Sharti } 715124861Sharti } else { 716124861Sharti len = *b.asn_cptr++; 717124861Sharti b.asn_len--; 718124861Sharti } 719124861Sharti 720124861Sharti if (len > b.asn_len) 721124861Sharti return (0); 722124861Sharti 723124861Sharti return (len + b.asn_cptr - b0->asn_cptr); 724124861Sharti} 725124861Sharti 726124861Sharti/* 727122394Sharti * Encode the SNMP PDU without the variable bindings field. 728122394Sharti * We do this the rather uneffective way by 729122394Sharti * moving things around and assuming that the length field will never 730122394Sharti * use more than 2 bytes. 731122394Sharti * We need a number of pointers to apply the fixes afterwards. 732122394Sharti */ 733122394Shartienum snmp_code 734122394Shartisnmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) 735122394Sharti{ 736122394Sharti enum asn_err err; 737216294Ssyrinx u_char *v3_hdr_ptr; 738122394Sharti 739122394Sharti if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 740122394Sharti &pdu->outer_ptr) != ASN_ERR_OK) 741122394Sharti return (SNMP_CODE_FAILED); 742122394Sharti 743122394Sharti if (pdu->version == SNMP_V1) 744122394Sharti err = asn_put_integer(b, 0); 745122394Sharti else if (pdu->version == SNMP_V2c) 746122394Sharti err = asn_put_integer(b, 1); 747216294Ssyrinx else if (pdu->version == SNMP_V3) 748216294Ssyrinx err = asn_put_integer(b, 3); 749122394Sharti else 750122394Sharti return (SNMP_CODE_BADVERS); 751122394Sharti if (err != ASN_ERR_OK) 752122394Sharti return (SNMP_CODE_FAILED); 753122394Sharti 754216294Ssyrinx if (pdu->version == SNMP_V3) { 755216294Ssyrinx if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 756216294Ssyrinx ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK) 757216294Ssyrinx return (SNMP_CODE_FAILED); 758216294Ssyrinx 759216294Ssyrinx if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK) 760216294Ssyrinx return (SNMP_CODE_FAILED); 761122394Sharti 762216294Ssyrinx if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK) 763216294Ssyrinx return (SNMP_CODE_FAILED); 764216294Ssyrinx 765216294Ssyrinx if (pdu->type != SNMP_PDU_RESPONSE && 766216294Ssyrinx pdu->type != SNMP_PDU_TRAP && 767216594Ssyrinx pdu->type != SNMP_PDU_TRAP2 && 768216294Ssyrinx pdu->type != SNMP_PDU_REPORT) 769216294Ssyrinx pdu->flags |= SNMP_MSG_REPORT_FLAG; 770216294Ssyrinx 771216294Ssyrinx if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1) 772216294Ssyrinx != ASN_ERR_OK) 773216294Ssyrinx return (SNMP_CODE_FAILED); 774216294Ssyrinx 775216294Ssyrinx if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK) 776216294Ssyrinx return (SNMP_CODE_FAILED); 777216294Ssyrinx 778216294Ssyrinx if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK) 779216294Ssyrinx return (SNMP_CODE_FAILED); 780216294Ssyrinx 781216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) 782216294Ssyrinx return (SNMP_CODE_FAILED); 783216294Ssyrinx 784216294Ssyrinx if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK) 785216294Ssyrinx return (SNMP_CODE_FAILED); 786216294Ssyrinx 787216294Ssyrinx /* View-based Access Conntrol information */ 788216294Ssyrinx if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 789216294Ssyrinx ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK) 790216294Ssyrinx return (SNMP_CODE_FAILED); 791216294Ssyrinx 792216294Ssyrinx if (asn_put_octetstring(b, (u_char *)pdu->context_engine, 793216294Ssyrinx pdu->context_engine_len) != ASN_ERR_OK) 794216294Ssyrinx return (SNMP_CODE_FAILED); 795216294Ssyrinx 796216294Ssyrinx if (asn_put_octetstring(b, (u_char *)pdu->context_name, 797216294Ssyrinx strlen(pdu->context_name)) != ASN_ERR_OK) 798216294Ssyrinx return (SNMP_CODE_FAILED); 799216294Ssyrinx } else { 800216294Ssyrinx if (asn_put_octetstring(b, (u_char *)pdu->community, 801216294Ssyrinx strlen(pdu->community)) != ASN_ERR_OK) 802216294Ssyrinx return (SNMP_CODE_FAILED); 803216294Ssyrinx } 804216294Ssyrinx 805122394Sharti if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | 806122394Sharti pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) 807122394Sharti return (SNMP_CODE_FAILED); 808122394Sharti 809122394Sharti if (pdu->type == SNMP_PDU_TRAP) { 810122394Sharti if (pdu->version != SNMP_V1 || 811122394Sharti asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || 812122394Sharti asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || 813122394Sharti asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || 814122394Sharti asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || 815122394Sharti asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) 816122394Sharti return (SNMP_CODE_FAILED); 817122394Sharti } else { 818122394Sharti if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || 819122394Sharti pdu->type == SNMP_PDU_INFORM || 820122394Sharti pdu->type == SNMP_PDU_TRAP2 || 821122394Sharti pdu->type == SNMP_PDU_REPORT)) 822122394Sharti return (SNMP_CODE_FAILED); 823122394Sharti 824122394Sharti if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || 825122394Sharti asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || 826122394Sharti asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) 827122394Sharti return (SNMP_CODE_FAILED); 828122394Sharti } 829122394Sharti 830122394Sharti if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 831122394Sharti &pdu->vars_ptr) != ASN_ERR_OK) 832122394Sharti return (SNMP_CODE_FAILED); 833122394Sharti 834122394Sharti return (SNMP_CODE_OK); 835122394Sharti} 836122394Sharti 837216294Ssyrinxstatic enum asn_err 838216294Ssyrinxsnmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu) 839216294Ssyrinx{ 840216294Ssyrinx asn_len_t padlen; 841216294Ssyrinx 842216294Ssyrinx if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) { 843216294Ssyrinx padlen = 8 - (pdu->scoped_len % 8); 844216294Ssyrinx if (asn_pad(b, padlen) != ASN_ERR_OK) 845216294Ssyrinx return (ASN_ERR_FAILED); 846216294Ssyrinx pdu->scoped_len += padlen; 847216294Ssyrinx } 848216294Ssyrinx 849216294Ssyrinx return (ASN_ERR_OK); 850216294Ssyrinx} 851216294Ssyrinx 852122394Shartienum snmp_code 853216294Ssyrinxsnmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu) 854122394Sharti{ 855216294Ssyrinx size_t moved = 0; 856216294Ssyrinx enum snmp_code code; 857216294Ssyrinx 858216294Ssyrinx if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK || 859216294Ssyrinx asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK) 860122394Sharti return (SNMP_CODE_FAILED); 861216294Ssyrinx 862216294Ssyrinx if (pdu->version == SNMP_V3) { 863216294Ssyrinx if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK) 864216294Ssyrinx return (SNMP_CODE_FAILED); 865216294Ssyrinx 866216294Ssyrinx pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr; 867216294Ssyrinx if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK) 868216294Ssyrinx return (SNMP_CODE_FAILED); 869216294Ssyrinx 870216294Ssyrinx if (pdu->security_model != SNMP_SECMODEL_USM) 871216294Ssyrinx return (SNMP_CODE_FAILED); 872216294Ssyrinx 873216482Ssyrinx if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK) 874216294Ssyrinx return (SNMP_CODE_FAILED); 875216294Ssyrinx 876216294Ssyrinx if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && 877216294Ssyrinx asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK) 878216294Ssyrinx return (SNMP_CODE_FAILED); 879216294Ssyrinx } 880216294Ssyrinx 881216294Ssyrinx if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK) 882216294Ssyrinx return (SNMP_CODE_FAILED); 883216294Ssyrinx 884216294Ssyrinx pdu->outer_len = b->asn_ptr - pdu->outer_ptr; 885216294Ssyrinx pdu->digest_ptr -= moved; 886216294Ssyrinx 887216294Ssyrinx if (pdu->version == SNMP_V3) { 888216482Ssyrinx if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) != 889216294Ssyrinx SNMP_CODE_OK) 890216294Ssyrinx return (SNMP_CODE_FAILED); 891216294Ssyrinx 892216294Ssyrinx if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) 893216294Ssyrinx memcpy(pdu->digest_ptr, pdu->msg_digest, 894216294Ssyrinx sizeof(pdu->msg_digest)); 895216294Ssyrinx } 896216294Ssyrinx 897122394Sharti return (SNMP_CODE_OK); 898122394Sharti} 899122394Sharti 900122394Sharti/* 901122394Sharti * Encode a binding. Caller must ensure, that the syntax is ok for that version. 902122394Sharti * Be sure not to cobber b, when something fails. 903122394Sharti */ 904122394Shartienum asn_err 905122394Shartisnmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) 906122394Sharti{ 907122394Sharti u_char *ptr; 908122394Sharti enum asn_err err; 909122394Sharti struct asn_buf save = *b; 910122394Sharti 911122394Sharti if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 912122394Sharti ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { 913122394Sharti *b = save; 914122394Sharti return (err); 915122394Sharti } 916122394Sharti 917122394Sharti if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { 918122394Sharti *b = save; 919122394Sharti return (err); 920122394Sharti } 921122394Sharti 922122394Sharti switch (binding->syntax) { 923122394Sharti 924122394Sharti case SNMP_SYNTAX_NULL: 925122394Sharti err = asn_put_null(b); 926122394Sharti break; 927122394Sharti 928122394Sharti case SNMP_SYNTAX_INTEGER: 929122394Sharti err = asn_put_integer(b, binding->v.integer); 930122394Sharti break; 931122394Sharti 932122394Sharti case SNMP_SYNTAX_OCTETSTRING: 933122394Sharti err = asn_put_octetstring(b, binding->v.octetstring.octets, 934122394Sharti binding->v.octetstring.len); 935122394Sharti break; 936122394Sharti 937122394Sharti case SNMP_SYNTAX_OID: 938122394Sharti err = asn_put_objid(b, &binding->v.oid); 939122394Sharti break; 940122394Sharti 941122394Sharti case SNMP_SYNTAX_IPADDRESS: 942122394Sharti err = asn_put_ipaddress(b, binding->v.ipaddress); 943122394Sharti break; 944122394Sharti 945122394Sharti case SNMP_SYNTAX_TIMETICKS: 946122394Sharti err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); 947122394Sharti break; 948122394Sharti 949122394Sharti case SNMP_SYNTAX_COUNTER: 950122394Sharti err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); 951122394Sharti break; 952122394Sharti 953122394Sharti case SNMP_SYNTAX_GAUGE: 954122394Sharti err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); 955122394Sharti break; 956122394Sharti 957122394Sharti case SNMP_SYNTAX_COUNTER64: 958122394Sharti err = asn_put_counter64(b, binding->v.counter64); 959122394Sharti break; 960122394Sharti 961122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 962122394Sharti err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); 963122394Sharti break; 964122394Sharti 965122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 966122394Sharti err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); 967122394Sharti break; 968122394Sharti 969122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 970122394Sharti err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); 971122394Sharti break; 972122394Sharti } 973122394Sharti 974122394Sharti if (err != ASN_ERR_OK) { 975122394Sharti *b = save; 976122394Sharti return (err); 977122394Sharti } 978122394Sharti 979216294Ssyrinx err = asn_commit_header(b, ptr, NULL); 980122394Sharti if (err != ASN_ERR_OK) { 981122394Sharti *b = save; 982122394Sharti return (err); 983122394Sharti } 984122394Sharti 985122394Sharti return (ASN_ERR_OK); 986122394Sharti} 987122394Sharti 988122394Sharti/* 989122394Sharti * Encode an PDU. 990122394Sharti */ 991122394Shartienum snmp_code 992122394Shartisnmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 993122394Sharti{ 994122394Sharti u_int idx; 995122394Sharti enum snmp_code err; 996122394Sharti 997122394Sharti if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) 998122394Sharti return (err); 999122394Sharti for (idx = 0; idx < pdu->nbindings; idx++) 1000122394Sharti if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) 1001122394Sharti != ASN_ERR_OK) 1002122394Sharti return (SNMP_CODE_FAILED); 1003122394Sharti 1004122394Sharti return (snmp_fix_encoding(resp_b, pdu)); 1005122394Sharti} 1006122394Sharti 1007122394Shartistatic void 1008122394Shartidump_binding(const struct snmp_value *b) 1009122394Sharti{ 1010122394Sharti u_int i; 1011122394Sharti char buf[ASN_OIDSTRLEN]; 1012122394Sharti 1013122394Sharti snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); 1014122394Sharti switch (b->syntax) { 1015122394Sharti 1016122394Sharti case SNMP_SYNTAX_NULL: 1017122394Sharti snmp_printf("NULL"); 1018122394Sharti break; 1019122394Sharti 1020122394Sharti case SNMP_SYNTAX_INTEGER: 1021122394Sharti snmp_printf("INTEGER %d", b->v.integer); 1022122394Sharti break; 1023122394Sharti 1024122394Sharti case SNMP_SYNTAX_OCTETSTRING: 1025122394Sharti snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); 1026122394Sharti for (i = 0; i < b->v.octetstring.len; i++) 1027122394Sharti snmp_printf(" %02x", b->v.octetstring.octets[i]); 1028122394Sharti break; 1029122394Sharti 1030122394Sharti case SNMP_SYNTAX_OID: 1031122394Sharti snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); 1032122394Sharti break; 1033122394Sharti 1034122394Sharti case SNMP_SYNTAX_IPADDRESS: 1035122394Sharti snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], 1036122394Sharti b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); 1037122394Sharti break; 1038122394Sharti 1039122394Sharti case SNMP_SYNTAX_COUNTER: 1040122394Sharti snmp_printf("COUNTER %u", b->v.uint32); 1041122394Sharti break; 1042122394Sharti 1043122394Sharti case SNMP_SYNTAX_GAUGE: 1044122394Sharti snmp_printf("GAUGE %u", b->v.uint32); 1045122394Sharti break; 1046122394Sharti 1047122394Sharti case SNMP_SYNTAX_TIMETICKS: 1048122394Sharti snmp_printf("TIMETICKS %u", b->v.uint32); 1049122394Sharti break; 1050122394Sharti 1051122394Sharti case SNMP_SYNTAX_COUNTER64: 1052122394Sharti snmp_printf("COUNTER64 %lld", b->v.counter64); 1053122394Sharti break; 1054122394Sharti 1055122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 1056122394Sharti snmp_printf("NoSuchObject"); 1057122394Sharti break; 1058122394Sharti 1059122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 1060122394Sharti snmp_printf("NoSuchInstance"); 1061122394Sharti break; 1062122394Sharti 1063122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 1064122394Sharti snmp_printf("EndOfMibView"); 1065122394Sharti break; 1066122394Sharti 1067122394Sharti default: 1068122394Sharti snmp_printf("UNKNOWN SYNTAX %u", b->syntax); 1069122394Sharti break; 1070122394Sharti } 1071122394Sharti} 1072122394Sharti 1073122394Shartistatic __inline void 1074122394Shartidump_bindings(const struct snmp_pdu *pdu) 1075122394Sharti{ 1076122394Sharti u_int i; 1077122394Sharti 1078122394Sharti for (i = 0; i < pdu->nbindings; i++) { 1079122394Sharti snmp_printf(" [%u]: ", i); 1080122394Sharti dump_binding(&pdu->bindings[i]); 1081122394Sharti snmp_printf("\n"); 1082122394Sharti } 1083122394Sharti} 1084122394Sharti 1085122394Shartistatic __inline void 1086122394Shartidump_notrap(const struct snmp_pdu *pdu) 1087122394Sharti{ 1088122394Sharti snmp_printf(" request_id=%d", pdu->request_id); 1089122394Sharti snmp_printf(" error_status=%d", pdu->error_status); 1090122394Sharti snmp_printf(" error_index=%d\n", pdu->error_index); 1091122394Sharti dump_bindings(pdu); 1092122394Sharti} 1093122394Sharti 1094122394Shartivoid 1095122394Shartisnmp_pdu_dump(const struct snmp_pdu *pdu) 1096122394Sharti{ 1097122394Sharti char buf[ASN_OIDSTRLEN]; 1098122394Sharti const char *vers; 1099122394Sharti static const char *types[] = { 1100122394Sharti [SNMP_PDU_GET] = "GET", 1101122394Sharti [SNMP_PDU_GETNEXT] = "GETNEXT", 1102122394Sharti [SNMP_PDU_RESPONSE] = "RESPONSE", 1103122394Sharti [SNMP_PDU_SET] = "SET", 1104122394Sharti [SNMP_PDU_TRAP] = "TRAPv1", 1105122394Sharti [SNMP_PDU_GETBULK] = "GETBULK", 1106122394Sharti [SNMP_PDU_INFORM] = "INFORM", 1107122394Sharti [SNMP_PDU_TRAP2] = "TRAPv2", 1108122394Sharti [SNMP_PDU_REPORT] = "REPORT", 1109122394Sharti }; 1110122394Sharti 1111122394Sharti if (pdu->version == SNMP_V1) 1112122394Sharti vers = "SNMPv1"; 1113122394Sharti else if (pdu->version == SNMP_V2c) 1114122394Sharti vers = "SNMPv2c"; 1115216294Ssyrinx else if (pdu->version == SNMP_V3) 1116216294Ssyrinx vers = "SNMPv3"; 1117122394Sharti else 1118122394Sharti vers = "v?"; 1119122394Sharti 1120122394Sharti switch (pdu->type) { 1121122394Sharti case SNMP_PDU_TRAP: 1122122394Sharti snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 1123122394Sharti snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); 1124122394Sharti snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], 1125122394Sharti pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); 1126122394Sharti snmp_printf(" generic_trap=%d", pdu->generic_trap); 1127122394Sharti snmp_printf(" specific_trap=%d", pdu->specific_trap); 1128122394Sharti snmp_printf(" time-stamp=%u\n", pdu->time_stamp); 1129122394Sharti dump_bindings(pdu); 1130122394Sharti break; 1131122394Sharti 1132122394Sharti case SNMP_PDU_GET: 1133122394Sharti case SNMP_PDU_GETNEXT: 1134122394Sharti case SNMP_PDU_RESPONSE: 1135122394Sharti case SNMP_PDU_SET: 1136122394Sharti case SNMP_PDU_GETBULK: 1137122394Sharti case SNMP_PDU_INFORM: 1138122394Sharti case SNMP_PDU_TRAP2: 1139122394Sharti case SNMP_PDU_REPORT: 1140122394Sharti snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 1141122394Sharti dump_notrap(pdu); 1142122394Sharti break; 1143122394Sharti 1144122394Sharti default: 1145122394Sharti snmp_printf("bad pdu type %u\n", pdu->type); 1146122394Sharti break; 1147122394Sharti } 1148122394Sharti} 1149122394Sharti 1150122394Shartivoid 1151122394Shartisnmp_value_free(struct snmp_value *value) 1152122394Sharti{ 1153122394Sharti if (value->syntax == SNMP_SYNTAX_OCTETSTRING) 1154122394Sharti free(value->v.octetstring.octets); 1155122394Sharti value->syntax = SNMP_SYNTAX_NULL; 1156122394Sharti} 1157122394Sharti 1158122394Shartiint 1159122394Shartisnmp_value_copy(struct snmp_value *to, const struct snmp_value *from) 1160122394Sharti{ 1161122394Sharti to->var = from->var; 1162122394Sharti to->syntax = from->syntax; 1163122394Sharti 1164122394Sharti if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { 1165122394Sharti if ((to->v.octetstring.len = from->v.octetstring.len) == 0) 1166122394Sharti to->v.octetstring.octets = NULL; 1167122394Sharti else { 1168122394Sharti to->v.octetstring.octets = malloc(to->v.octetstring.len); 1169122394Sharti if (to->v.octetstring.octets == NULL) 1170122394Sharti return (-1); 1171122394Sharti (void)memcpy(to->v.octetstring.octets, 1172122394Sharti from->v.octetstring.octets, to->v.octetstring.len); 1173122394Sharti } 1174122394Sharti } else 1175122394Sharti to->v = from->v; 1176122394Sharti return (0); 1177122394Sharti} 1178122394Sharti 1179122394Shartivoid 1180216594Ssyrinxsnmp_pdu_init_secparams(struct snmp_pdu *pdu) 1181216294Ssyrinx{ 1182216294Ssyrinx int32_t rval; 1183216294Ssyrinx 1184216594Ssyrinx if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) 1185216294Ssyrinx pdu->flags |= SNMP_MSG_AUTH_FLAG; 1186216294Ssyrinx 1187216594Ssyrinx switch (pdu->user.priv_proto) { 1188216294Ssyrinx case SNMP_PRIV_DES: 1189216594Ssyrinx memcpy(pdu->msg_salt, &pdu->engine.engine_boots, 1190216594Ssyrinx sizeof(pdu->engine.engine_boots)); 1191216294Ssyrinx rval = random(); 1192216594Ssyrinx memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval, 1193216294Ssyrinx sizeof(int32_t)); 1194216294Ssyrinx pdu->flags |= SNMP_MSG_PRIV_FLAG; 1195216294Ssyrinx break; 1196216294Ssyrinx case SNMP_PRIV_AES: 1197216294Ssyrinx rval = random(); 1198216294Ssyrinx memcpy(pdu->msg_salt, &rval, sizeof(int32_t)); 1199216294Ssyrinx rval = random(); 1200216294Ssyrinx memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t)); 1201216294Ssyrinx pdu->flags |= SNMP_MSG_PRIV_FLAG; 1202216294Ssyrinx break; 1203216294Ssyrinx default: 1204216294Ssyrinx break; 1205216294Ssyrinx } 1206216294Ssyrinx} 1207216294Ssyrinx 1208216294Ssyrinxvoid 1209122394Shartisnmp_pdu_free(struct snmp_pdu *pdu) 1210122394Sharti{ 1211122394Sharti u_int i; 1212122394Sharti 1213122394Sharti for (i = 0; i < pdu->nbindings; i++) 1214122394Sharti snmp_value_free(&pdu->bindings[i]); 1215122394Sharti} 1216122394Sharti 1217122394Sharti/* 1218122394Sharti * Parse an ASCII SNMP value into the binary form 1219122394Sharti */ 1220122394Shartiint 1221122394Shartisnmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) 1222122394Sharti{ 1223122394Sharti char *end; 1224122394Sharti 1225122394Sharti switch (syntax) { 1226122394Sharti 1227122394Sharti case SNMP_SYNTAX_NULL: 1228122394Sharti case SNMP_SYNTAX_NOSUCHOBJECT: 1229122394Sharti case SNMP_SYNTAX_NOSUCHINSTANCE: 1230122394Sharti case SNMP_SYNTAX_ENDOFMIBVIEW: 1231122394Sharti if (*str != '\0') 1232122394Sharti return (-1); 1233122394Sharti return (0); 1234122394Sharti 1235122394Sharti case SNMP_SYNTAX_INTEGER: 1236122394Sharti v->integer = strtoll(str, &end, 0); 1237122394Sharti if (*end != '\0') 1238122394Sharti return (-1); 1239122394Sharti return (0); 1240122394Sharti 1241122394Sharti case SNMP_SYNTAX_OCTETSTRING: 1242122394Sharti { 1243122394Sharti u_long len; /* actual length of string */ 1244122394Sharti u_long alloc; /* allocate length of string */ 1245122394Sharti u_char *octs; /* actual octets */ 1246122394Sharti u_long oct; /* actual octet */ 1247122394Sharti u_char *nocts; /* to avoid memory leak */ 1248122394Sharti u_char c; /* actual character */ 1249122394Sharti 1250122394Sharti# define STUFFC(C) \ 1251122394Sharti if (alloc == len) { \ 1252122394Sharti alloc += 100; \ 1253122394Sharti if ((nocts = realloc(octs, alloc)) == NULL) { \ 1254122394Sharti free(octs); \ 1255122394Sharti return (-1); \ 1256122394Sharti } \ 1257122394Sharti octs = nocts; \ 1258122394Sharti } \ 1259122394Sharti octs[len++] = (C); 1260122394Sharti 1261122394Sharti len = alloc = 0; 1262122394Sharti octs = NULL; 1263122394Sharti 1264122394Sharti if (*str == '"') { 1265122394Sharti str++; 1266122394Sharti while((c = *str++) != '\0') { 1267122394Sharti if (c == '"') { 1268122394Sharti if (*str != '\0') { 1269122394Sharti free(octs); 1270122394Sharti return (-1); 1271122394Sharti } 1272122394Sharti break; 1273122394Sharti } 1274122394Sharti if (c == '\\') { 1275122394Sharti switch (c = *str++) { 1276122394Sharti 1277122394Sharti case '\\': 1278122394Sharti break; 1279122394Sharti case 'a': 1280122394Sharti c = '\a'; 1281122394Sharti break; 1282122394Sharti case 'b': 1283122394Sharti c = '\b'; 1284122394Sharti break; 1285122394Sharti case 'f': 1286122394Sharti c = '\f'; 1287122394Sharti break; 1288122394Sharti case 'n': 1289122394Sharti c = '\n'; 1290122394Sharti break; 1291122394Sharti case 'r': 1292122394Sharti c = '\r'; 1293122394Sharti break; 1294122394Sharti case 't': 1295122394Sharti c = '\t'; 1296122394Sharti break; 1297122394Sharti case 'v': 1298122394Sharti c = '\v'; 1299122394Sharti break; 1300122394Sharti case 'x': 1301122394Sharti c = 0; 1302122394Sharti if (!isxdigit(*str)) 1303122394Sharti break; 1304122394Sharti if (isdigit(*str)) 1305122394Sharti c = *str++ - '0'; 1306122394Sharti else if (isupper(*str)) 1307122394Sharti c = *str++ - 'A' + 10; 1308122394Sharti else 1309122394Sharti c = *str++ - 'a' + 10; 1310122394Sharti if (!isxdigit(*str)) 1311122394Sharti break; 1312122394Sharti if (isdigit(*str)) 1313122394Sharti c += *str++ - '0'; 1314122394Sharti else if (isupper(*str)) 1315122394Sharti c += *str++ - 'A' + 10; 1316122394Sharti else 1317122394Sharti c += *str++ - 'a' + 10; 1318122394Sharti break; 1319122394Sharti case '0': case '1': case '2': 1320122394Sharti case '3': case '4': case '5': 1321122394Sharti case '6': case '7': 1322122394Sharti c = *str++ - '0'; 1323122394Sharti if (*str < '0' || *str > '7') 1324122394Sharti break; 1325122394Sharti c = *str++ - '0'; 1326122394Sharti if (*str < '0' || *str > '7') 1327122394Sharti break; 1328122394Sharti c = *str++ - '0'; 1329122394Sharti break; 1330122394Sharti default: 1331122394Sharti break; 1332122394Sharti } 1333122394Sharti } 1334122394Sharti STUFFC(c); 1335122394Sharti } 1336122394Sharti } else { 1337122394Sharti while (*str != '\0') { 1338122394Sharti oct = strtoul(str, &end, 16); 1339122394Sharti str = end; 1340122394Sharti if (oct > 0xff) { 1341122394Sharti free(octs); 1342122394Sharti return (-1); 1343122394Sharti } 1344122394Sharti STUFFC(oct); 1345122394Sharti if (*str == ':') 1346122394Sharti str++; 1347122394Sharti else if(*str != '\0') { 1348122394Sharti free(octs); 1349122394Sharti return (-1); 1350122394Sharti } 1351122394Sharti } 1352122394Sharti } 1353122394Sharti v->octetstring.octets = octs; 1354122394Sharti v->octetstring.len = len; 1355122394Sharti return (0); 1356122394Sharti# undef STUFFC 1357122394Sharti } 1358122394Sharti 1359122394Sharti case SNMP_SYNTAX_OID: 1360122394Sharti { 1361122394Sharti u_long subid; 1362122394Sharti 1363122394Sharti v->oid.len = 0; 1364122394Sharti 1365122394Sharti for (;;) { 1366122394Sharti if (v->oid.len == ASN_MAXOIDLEN) 1367122394Sharti return (-1); 1368122394Sharti subid = strtoul(str, &end, 10); 1369122394Sharti str = end; 1370122394Sharti if (subid > ASN_MAXID) 1371122394Sharti return (-1); 1372122394Sharti v->oid.subs[v->oid.len++] = (asn_subid_t)subid; 1373122394Sharti if (*str == '\0') 1374122394Sharti break; 1375122394Sharti if (*str != '.') 1376122394Sharti return (-1); 1377122394Sharti str++; 1378122394Sharti } 1379122394Sharti return (0); 1380122394Sharti } 1381122394Sharti 1382122394Sharti case SNMP_SYNTAX_IPADDRESS: 1383122394Sharti { 1384122394Sharti struct hostent *he; 1385122394Sharti u_long ip[4]; 1386122394Sharti int n; 1387122394Sharti 1388122394Sharti if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], 1389122394Sharti &ip[3], &n) == 4 && (size_t)n == strlen(str) && 1390122394Sharti ip[0] <= 0xff && ip[1] <= 0xff && 1391122394Sharti ip[2] <= 0xff && ip[3] <= 0xff) { 1392122394Sharti v->ipaddress[0] = (u_char)ip[0]; 1393122394Sharti v->ipaddress[1] = (u_char)ip[1]; 1394122394Sharti v->ipaddress[2] = (u_char)ip[2]; 1395122394Sharti v->ipaddress[3] = (u_char)ip[3]; 1396122394Sharti return (0); 1397122394Sharti } 1398122394Sharti 1399122394Sharti if ((he = gethostbyname(str)) == NULL) 1400122394Sharti return (-1); 1401122394Sharti if (he->h_addrtype != AF_INET) 1402122394Sharti return (-1); 1403122394Sharti 1404122394Sharti v->ipaddress[0] = he->h_addr[0]; 1405122394Sharti v->ipaddress[1] = he->h_addr[1]; 1406122394Sharti v->ipaddress[2] = he->h_addr[2]; 1407122394Sharti v->ipaddress[3] = he->h_addr[3]; 1408122394Sharti return (0); 1409122394Sharti } 1410122394Sharti 1411122394Sharti case SNMP_SYNTAX_COUNTER: 1412122394Sharti case SNMP_SYNTAX_GAUGE: 1413122394Sharti case SNMP_SYNTAX_TIMETICKS: 1414122394Sharti { 1415133211Sharti uint64_t sub; 1416122394Sharti 1417122394Sharti sub = strtoull(str, &end, 0); 1418122394Sharti if (*end != '\0' || sub > 0xffffffff) 1419122394Sharti return (-1); 1420133211Sharti v->uint32 = (uint32_t)sub; 1421122394Sharti return (0); 1422122394Sharti } 1423122394Sharti 1424122394Sharti case SNMP_SYNTAX_COUNTER64: 1425122394Sharti v->counter64 = strtoull(str, &end, 0); 1426122394Sharti if (*end != '\0') 1427122394Sharti return (-1); 1428122394Sharti return (0); 1429122394Sharti } 1430122394Sharti abort(); 1431122394Sharti} 1432122394Sharti 1433122394Shartistatic void 1434122394Shartisnmp_error_func(const char *fmt, ...) 1435122394Sharti{ 1436122394Sharti va_list ap; 1437122394Sharti 1438122394Sharti va_start(ap, fmt); 1439122394Sharti fprintf(stderr, "SNMP: "); 1440122394Sharti vfprintf(stderr, fmt, ap); 1441122394Sharti fprintf(stderr, "\n"); 1442122394Sharti va_end(ap); 1443122394Sharti} 1444122394Sharti 1445122394Shartistatic void 1446122394Shartisnmp_printf_func(const char *fmt, ...) 1447122394Sharti{ 1448122394Sharti va_list ap; 1449122394Sharti 1450122394Sharti va_start(ap, fmt); 1451122394Sharti vfprintf(stderr, fmt, ap); 1452122394Sharti va_end(ap); 1453122394Sharti} 1454