160484Sobrien/* 260484Sobrien * Copyright (c) 2001-2003 360484Sobrien * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 460484Sobrien * All rights reserved. 560484Sobrien * 660484Sobrien * Author: Harti Brandt <harti@freebsd.org> 760484Sobrien * 860484Sobrien * Copyright (c) 2010 The FreeBSD Foundation 960484Sobrien * All rights reserved. 1060484Sobrien * 1160484Sobrien * Portions of this software were developed by Shteryana Sotirova Shopova 1260484Sobrien * under sponsorship from the FreeBSD Foundation. 1360484Sobrien * 1460484Sobrien * Redistribution and use in source and binary forms, with or without 1560484Sobrien * modification, are permitted provided that the following conditions 1660484Sobrien * are met: 1760484Sobrien * 1. Redistributions of source code must retain the above copyright 1860484Sobrien * notice, this list of conditions and the following disclaimer. 1960484Sobrien * 2. Redistributions in binary form must reproduce the above copyright 2060484Sobrien * notice, this list of conditions and the following disclaimer in the 2160484Sobrien * documentation and/or other materials provided with the distribution. 2260484Sobrien * 2360484Sobrien * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND 2460484Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2560484Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2660484Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE 2760484Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2860484Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2960484Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3060484Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3160484Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3260484Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3360484Sobrien * SUCH DAMAGE. 3460484Sobrien * 3560484Sobrien * $Begemot: bsnmp/lib/snmp.c,v 1.40 2005/10/04 14:32:42 brandt_h Exp $ 3660484Sobrien * 3760484Sobrien * SNMP 3860484Sobrien */ 3960484Sobrien#include <sys/types.h> 4060484Sobrien#include <sys/socket.h> 4160484Sobrien#include <stdio.h> 4260484Sobrien#include <stdlib.h> 4360484Sobrien#include <stddef.h> 4460484Sobrien#include <stdarg.h> 4560484Sobrien#ifdef HAVE_STDINT_H 4660484Sobrien#include <stdint.h> 4760484Sobrien#elif defined(HAVE_INTTYPES_H) 4860484Sobrien#include <inttypes.h> 4960484Sobrien#endif 5060484Sobrien#include <string.h> 5160484Sobrien#include <ctype.h> 5260484Sobrien#include <netdb.h> 5360484Sobrien#include <errno.h> 5460484Sobrien 5560484Sobrien#include "asn1.h" 5660484Sobrien#include "snmp.h" 5760484Sobrien#include "snmppriv.h" 5860484Sobrien 5960484Sobrienstatic void snmp_error_func(const char *, ...); 6060484Sobrienstatic void snmp_printf_func(const char *, ...); 6160484Sobrien 6260484Sobrienvoid (*snmp_error)(const char *, ...) = snmp_error_func; 6360484Sobrienvoid (*snmp_printf)(const char *, ...) = snmp_printf_func; 6460484Sobrien 6560484Sobrien/* 6660484Sobrien * Get the next variable binding from the list. 6760484Sobrien * ASN errors on the sequence or the OID are always fatal. 6860484Sobrien */ 6960484Sobrienstatic enum asn_err 7060484Sobrienget_var_binding(struct asn_buf *b, struct snmp_value *binding) 7160484Sobrien{ 7260484Sobrien u_char type; 7360484Sobrien asn_len_t len, trailer; 7460484Sobrien enum asn_err err; 7560484Sobrien 7660484Sobrien if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 7760484Sobrien snmp_error("cannot parse varbind header"); 7860484Sobrien return (ASN_ERR_FAILED); 7960484Sobrien } 8060484Sobrien 8160484Sobrien /* temporary truncate the length so that the parser does not 8260484Sobrien * eat up bytes behind the sequence in the case the encoding is 8360484Sobrien * wrong of inner elements. */ 8460484Sobrien trailer = b->asn_len - len; 8560484Sobrien b->asn_len = len; 8660484Sobrien 8760484Sobrien if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { 8860484Sobrien snmp_error("cannot parse binding objid"); 8960484Sobrien return (ASN_ERR_FAILED); 9060484Sobrien } 9160484Sobrien if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 9260484Sobrien snmp_error("cannot parse binding value header"); 9360484Sobrien return (ASN_ERR_FAILED); 9460484Sobrien } 9560484Sobrien 9660484Sobrien switch (type) { 9760484Sobrien 9860484Sobrien case ASN_TYPE_NULL: 9960484Sobrien binding->syntax = SNMP_SYNTAX_NULL; 10060484Sobrien err = asn_get_null_raw(b, len); 10160484Sobrien break; 10260484Sobrien 10360484Sobrien case ASN_TYPE_INTEGER: 10460484Sobrien binding->syntax = SNMP_SYNTAX_INTEGER; 10560484Sobrien err = asn_get_integer_raw(b, len, &binding->v.integer); 10660484Sobrien break; 10760484Sobrien 10860484Sobrien case ASN_TYPE_OCTETSTRING: 10960484Sobrien binding->syntax = SNMP_SYNTAX_OCTETSTRING; 11060484Sobrien binding->v.octetstring.octets = malloc(len); 11160484Sobrien if (binding->v.octetstring.octets == NULL) { 11260484Sobrien snmp_error("%s", strerror(errno)); 11360484Sobrien return (ASN_ERR_FAILED); 11460484Sobrien } 11560484Sobrien binding->v.octetstring.len = len; 11660484Sobrien err = asn_get_octetstring_raw(b, len, 11760484Sobrien binding->v.octetstring.octets, 11860484Sobrien &binding->v.octetstring.len); 11960484Sobrien if (ASN_ERR_STOPPED(err)) { 12060484Sobrien free(binding->v.octetstring.octets); 12160484Sobrien binding->v.octetstring.octets = NULL; 12260484Sobrien } 12360484Sobrien break; 12460484Sobrien 12560484Sobrien case ASN_TYPE_OBJID: 12660484Sobrien binding->syntax = SNMP_SYNTAX_OID; 12760484Sobrien err = asn_get_objid_raw(b, len, &binding->v.oid); 12860484Sobrien break; 12960484Sobrien 13060484Sobrien case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: 13160484Sobrien binding->syntax = SNMP_SYNTAX_IPADDRESS; 13260484Sobrien err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); 13360484Sobrien break; 13460484Sobrien 13560484Sobrien case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: 13660484Sobrien binding->syntax = SNMP_SYNTAX_TIMETICKS; 13760484Sobrien err = asn_get_uint32_raw(b, len, &binding->v.uint32); 13860484Sobrien break; 13960484Sobrien 14060484Sobrien case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: 14160484Sobrien binding->syntax = SNMP_SYNTAX_COUNTER; 14260484Sobrien err = asn_get_uint32_raw(b, len, &binding->v.uint32); 14360484Sobrien break; 14460484Sobrien 14560484Sobrien case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: 14660484Sobrien binding->syntax = SNMP_SYNTAX_GAUGE; 14760484Sobrien err = asn_get_uint32_raw(b, len, &binding->v.uint32); 14860484Sobrien break; 14960484Sobrien 15060484Sobrien case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: 15160484Sobrien binding->syntax = SNMP_SYNTAX_COUNTER64; 15260484Sobrien err = asn_get_counter64_raw(b, len, &binding->v.counter64); 15360484Sobrien break; 15460484Sobrien 15560484Sobrien case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: 15660484Sobrien binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; 15760484Sobrien err = asn_get_null_raw(b, len); 15860484Sobrien break; 15960484Sobrien 16060484Sobrien case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: 16160484Sobrien binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 16260484Sobrien err = asn_get_null_raw(b, len); 16360484Sobrien break; 16460484Sobrien 16560484Sobrien case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: 16660484Sobrien binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 16760484Sobrien err = asn_get_null_raw(b, len); 16860484Sobrien break; 16960484Sobrien 17060484Sobrien default: 17160484Sobrien if ((err = asn_skip(b, len)) == ASN_ERR_OK) 17260484Sobrien err = ASN_ERR_TAG; 17360484Sobrien snmp_error("bad binding value type 0x%x", type); 17460484Sobrien break; 17560484Sobrien } 17660484Sobrien 17760484Sobrien if (ASN_ERR_STOPPED(err)) { 17860484Sobrien snmp_error("cannot parse binding value"); 17960484Sobrien return (err); 18060484Sobrien } 18189857Sobrien 18260484Sobrien if (b->asn_len != 0) 18360484Sobrien snmp_error("ignoring junk at end of binding"); 18460484Sobrien 18560484Sobrien b->asn_len = trailer; 18660484Sobrien 18760484Sobrien return (err); 18860484Sobrien} 18960484Sobrien 19060484Sobrien/* 19160484Sobrien * Parse the different PDUs contents. Any ASN error in the outer components 19260484Sobrien * are fatal. Only errors in variable values may be tolerated. If all 19360484Sobrien * components can be parsed it returns either ASN_ERR_OK or the first 19460484Sobrien * error that was found. 19560484Sobrien */ 19660484Sobrienenum asn_err 19760484Sobriensnmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 19860484Sobrien{ 19960484Sobrien if (pdu->type == SNMP_PDU_TRAP) { 20060484Sobrien if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { 20160484Sobrien snmp_error("cannot parse trap enterprise"); 20260484Sobrien return (ASN_ERR_FAILED); 20360484Sobrien } 20460484Sobrien if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { 20560484Sobrien snmp_error("cannot parse trap agent address"); 20660484Sobrien return (ASN_ERR_FAILED); 20760484Sobrien } 20860484Sobrien if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { 20960484Sobrien snmp_error("cannot parse 'generic-trap'"); 21060484Sobrien return (ASN_ERR_FAILED); 21160484Sobrien } 21260484Sobrien if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { 21360484Sobrien snmp_error("cannot parse 'specific-trap'"); 21460484Sobrien return (ASN_ERR_FAILED); 21560484Sobrien } 21660484Sobrien if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { 21760484Sobrien snmp_error("cannot parse trap 'time-stamp'"); 21860484Sobrien return (ASN_ERR_FAILED); 21960484Sobrien } 22060484Sobrien } else { 22160484Sobrien if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { 22260484Sobrien snmp_error("cannot parse 'request-id'"); 22360484Sobrien return (ASN_ERR_FAILED); 22460484Sobrien } 22560484Sobrien if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { 22660484Sobrien snmp_error("cannot parse 'error_status'"); 22760484Sobrien return (ASN_ERR_FAILED); 22860484Sobrien } 22960484Sobrien if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { 23060484Sobrien snmp_error("cannot parse 'error_index'"); 23160484Sobrien return (ASN_ERR_FAILED); 23260484Sobrien } 23360484Sobrien } 23460484Sobrien 23560484Sobrien if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { 23660484Sobrien snmp_error("cannot get varlist header"); 23760484Sobrien return (ASN_ERR_FAILED); 23860484Sobrien } 23960484Sobrien 24060484Sobrien return (ASN_ERR_OK); 24160484Sobrien} 24260484Sobrien 24360484Sobrienstatic enum asn_err 24460484Sobrienparse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 24560484Sobrien{ 24660484Sobrien asn_len_t len, trailer; 24760484Sobrien struct snmp_value *v; 24860484Sobrien enum asn_err err, err1; 24960484Sobrien 25060484Sobrien err = snmp_parse_pdus_hdr(b, pdu, &len); 25160484Sobrien if (ASN_ERR_STOPPED(err)) 25260484Sobrien return (err); 25360484Sobrien 25460484Sobrien trailer = b->asn_len - len; 25560484Sobrien 25660484Sobrien v = pdu->bindings; 25760484Sobrien err = ASN_ERR_OK; 25860484Sobrien while (b->asn_len != 0) { 25960484Sobrien if (pdu->nbindings == SNMP_MAX_BINDINGS) { 26060484Sobrien snmp_error("too many bindings (> %u) in PDU", 26160484Sobrien SNMP_MAX_BINDINGS); 26260484Sobrien return (ASN_ERR_FAILED); 26360484Sobrien } 26460484Sobrien err1 = get_var_binding(b, v); 26560484Sobrien if (ASN_ERR_STOPPED(err1)) 26660484Sobrien return (ASN_ERR_FAILED); 26760484Sobrien if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { 26860484Sobrien err = err1; 26960484Sobrien *ip = pdu->nbindings + 1; 27060484Sobrien } 27160484Sobrien pdu->nbindings++; 27260484Sobrien v++; 27360484Sobrien } 27460484Sobrien 27560484Sobrien b->asn_len = trailer; 27660484Sobrien 27760484Sobrien return (err); 27860484Sobrien} 27960484Sobrien 28060484Sobrien 28160484Sobrienstatic enum asn_err 28260484Sobrienparse_secparams(struct asn_buf *b, struct snmp_pdu *pdu) 28360484Sobrien{ 28460484Sobrien asn_len_t octs_len; 28560484Sobrien u_char buf[256]; /* XXX: calc max possible size here */ 28660484Sobrien struct asn_buf tb; 28760484Sobrien 28860484Sobrien memset(buf, 0, 256); 28960484Sobrien tb.asn_ptr = buf; 29060484Sobrien tb.asn_len = 256; 29160484Sobrien 29260484Sobrien if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) { 29360484Sobrien snmp_error("cannot parse usm header"); 29460484Sobrien return (ASN_ERR_FAILED); 29560484Sobrien } 29660484Sobrien 29760484Sobrien if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) { 29860484Sobrien snmp_error("cannot decode usm header"); 29960484Sobrien return (ASN_ERR_FAILED); 30060484Sobrien } 30160484Sobrien 30260484Sobrien octs_len = SNMP_ENGINE_ID_SIZ; 30360484Sobrien if (asn_get_octetstring(&tb, (u_char *)&pdu->engine.engine_id, 30460484Sobrien &octs_len) != ASN_ERR_OK) { 30560484Sobrien snmp_error("cannot decode msg engine id"); 30660484Sobrien return (ASN_ERR_FAILED); 30760484Sobrien } 30860484Sobrien pdu->engine.engine_len = octs_len; 30960484Sobrien 31060484Sobrien if (asn_get_integer(&tb, &pdu->engine.engine_boots) != ASN_ERR_OK) { 31160484Sobrien snmp_error("cannot decode msg engine boots"); 31260484Sobrien return (ASN_ERR_FAILED); 31360484Sobrien } 31460484Sobrien 31560484Sobrien if (asn_get_integer(&tb, &pdu->engine.engine_time) != ASN_ERR_OK) { 31660484Sobrien snmp_error("cannot decode msg engine time"); 31760484Sobrien return (ASN_ERR_FAILED); 31860484Sobrien } 31960484Sobrien 32060484Sobrien octs_len = SNMP_ADM_STR32_SIZ - 1; 32160484Sobrien if (asn_get_octetstring(&tb, (u_char *)&pdu->user.sec_name, &octs_len) 32260484Sobrien != ASN_ERR_OK) { 32360484Sobrien snmp_error("cannot decode msg user name"); 32460484Sobrien return (ASN_ERR_FAILED); 32560484Sobrien } 32660484Sobrien pdu->user.sec_name[octs_len] = '\0'; 32760484Sobrien 32860484Sobrien octs_len = sizeof(pdu->msg_digest); 32960484Sobrien if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_digest, &octs_len) != 33060484Sobrien ASN_ERR_OK || ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0 && 33160484Sobrien octs_len != sizeof(pdu->msg_digest))) { 33260484Sobrien snmp_error("cannot decode msg authentication param"); 33360484Sobrien return (ASN_ERR_FAILED); 33460484Sobrien } 33560484Sobrien 33660484Sobrien octs_len = sizeof(pdu->msg_salt); 33760484Sobrien if (asn_get_octetstring(&tb, (u_char *)&pdu->msg_salt, &octs_len) != 33860484Sobrien ASN_ERR_OK ||((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && 33960484Sobrien octs_len != sizeof(pdu->msg_salt))) { 34060484Sobrien snmp_error("cannot decode msg authentication param"); 34160484Sobrien return (ASN_ERR_FAILED); 34260484Sobrien } 34360484Sobrien 34460484Sobrien if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 34560484Sobrien pdu->digest_ptr = b->asn_ptr - SNMP_USM_AUTH_SIZE; 34660484Sobrien pdu->digest_ptr -= octs_len + ASN_MAXLENLEN; 34760484Sobrien } 34860484Sobrien 34960484Sobrien return (ASN_ERR_OK); 35060484Sobrien} 35160484Sobrien 35260484Sobrienstatic enum snmp_code 35360484Sobrienpdu_encode_secparams(struct asn_buf *b, struct snmp_pdu *pdu) 35460484Sobrien{ 35560484Sobrien u_char buf[256], *sptr; 35660484Sobrien struct asn_buf tb; 35760484Sobrien size_t auth_off, moved = 0; 35860484Sobrien 35960484Sobrien auth_off = 0; 36060484Sobrien memset(buf, 0, 256); 36160484Sobrien tb.asn_ptr = buf; 36260484Sobrien tb.asn_len = 256; 36360484Sobrien 36460484Sobrien if (asn_put_temp_header(&tb, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 36560484Sobrien &sptr) != ASN_ERR_OK) 36660484Sobrien return (SNMP_CODE_FAILED); 36760484Sobrien 36860484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->engine.engine_id, 36960484Sobrien pdu->engine.engine_len) != ASN_ERR_OK) 37060484Sobrien return (SNMP_CODE_FAILED); 37160484Sobrien 37260484Sobrien if (asn_put_integer(&tb, pdu->engine.engine_boots) != ASN_ERR_OK) 37360484Sobrien return (SNMP_CODE_FAILED); 37460484Sobrien 37560484Sobrien if (asn_put_integer(&tb, pdu->engine.engine_time) != ASN_ERR_OK) 37660484Sobrien return (SNMP_CODE_FAILED); 37760484Sobrien 37860484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->user.sec_name, 37960484Sobrien strlen(pdu->user.sec_name)) != ASN_ERR_OK) 38060484Sobrien return (SNMP_CODE_FAILED); 38160484Sobrien 38260484Sobrien if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) { 38360484Sobrien auth_off = sizeof(buf) - tb.asn_len + ASN_MAXLENLEN; 38460484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 38560484Sobrien sizeof(pdu->msg_digest)) != ASN_ERR_OK) 38660484Sobrien return (SNMP_CODE_FAILED); 38760484Sobrien } else { 38860484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->msg_digest, 0) 38960484Sobrien != ASN_ERR_OK) 39060484Sobrien return (SNMP_CODE_FAILED); 39160484Sobrien } 39260484Sobrien 39360484Sobrien if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0) { 39460484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 39560484Sobrien sizeof(pdu->msg_salt)) != ASN_ERR_OK) 39660484Sobrien return (SNMP_CODE_FAILED); 39760484Sobrien } else { 39860484Sobrien if (asn_put_octetstring(&tb, (u_char *)pdu->msg_salt, 0) 39960484Sobrien != ASN_ERR_OK) 40060484Sobrien return (SNMP_CODE_FAILED); 40160484Sobrien } 40260484Sobrien 40360484Sobrien if (asn_commit_header(&tb, sptr, &moved) != ASN_ERR_OK) 40460484Sobrien return (SNMP_CODE_FAILED); 40560484Sobrien 40660484Sobrien if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) 40760484Sobrien pdu->digest_ptr = b->asn_ptr + auth_off - moved; 40860484Sobrien 40960484Sobrien if (asn_put_octetstring(b, buf, sizeof(buf) - tb.asn_len) != ASN_ERR_OK) 41089857Sobrien return (SNMP_CODE_FAILED); 41160484Sobrien pdu->digest_ptr += ASN_MAXLENLEN; 41260484Sobrien 41360484Sobrien if ((pdu->flags & SNMP_MSG_PRIV_FLAG) != 0 && asn_put_temp_header(b, 41460484Sobrien ASN_TYPE_OCTETSTRING, &pdu->encrypted_ptr) != ASN_ERR_OK) 41560484Sobrien return (SNMP_CODE_FAILED); 41660484Sobrien 41760484Sobrien return (SNMP_CODE_OK); 41860484Sobrien} 41960484Sobrien 42060484Sobrien/* 42160484Sobrien * Decode the PDU except for the variable bindings itself. 42260484Sobrien * If decoding fails because of a bad binding, but the rest can be 42360484Sobrien * decoded, ip points to the index of the failed variable (errors 42460484Sobrien * OORANGE, BADLEN or BADVERS). 42560484Sobrien */ 42660484Sobrienenum snmp_code 42760484Sobriensnmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 42860484Sobrien{ 42960484Sobrien enum snmp_code code; 43060484Sobrien 43160484Sobrien if ((code = snmp_pdu_decode_header(b, pdu)) != SNMP_CODE_OK) 43260484Sobrien return (code); 43360484Sobrien 43460484Sobrien if (pdu->version == SNMP_V3) { 43560484Sobrien if (pdu->security_model != SNMP_SECMODEL_USM) 43660484Sobrien return (SNMP_CODE_FAILED); 43760484Sobrien if ((code = snmp_pdu_decode_secmode(b, pdu)) != SNMP_CODE_OK) 43860484Sobrien return (code); 43960484Sobrien } 44060484Sobrien 44160484Sobrien code = snmp_pdu_decode_scoped(b, pdu, ip); 44260484Sobrien 44360484Sobrien switch (code) { 44460484Sobrien case SNMP_CODE_FAILED: 44560484Sobrien snmp_pdu_free(pdu); 44660484Sobrien break; 44760484Sobrien 44860484Sobrien case SNMP_CODE_BADENC: 44960484Sobrien if (pdu->version == SNMP_Verr) 45060484Sobrien return (SNMP_CODE_BADVERS); 45160484Sobrien 45260484Sobrien default: 45360484Sobrien break; 45460484Sobrien } 45560484Sobrien 45660484Sobrien return (code); 45760484Sobrien} 45860484Sobrien 45960484Sobrienenum snmp_code 46060484Sobriensnmp_pdu_decode_header(struct asn_buf *b, struct snmp_pdu *pdu) 46160484Sobrien{ 46260484Sobrien int32_t version; 46360484Sobrien u_int octs_len; 46460484Sobrien asn_len_t len; 46560484Sobrien 46660484Sobrien pdu->outer_ptr = b->asn_ptr; 46760484Sobrien pdu->outer_len = b->asn_len; 46860484Sobrien 46960484Sobrien if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 47060484Sobrien snmp_error("cannot decode pdu header"); 47160484Sobrien return (SNMP_CODE_FAILED); 47260484Sobrien } 47360484Sobrien if (b->asn_len < len) { 47460484Sobrien snmp_error("outer sequence value too short"); 47560484Sobrien return (SNMP_CODE_FAILED); 47660484Sobrien } 47760484Sobrien if (b->asn_len != len) { 47860484Sobrien snmp_error("ignoring trailing junk in message"); 47960484Sobrien b->asn_len = len; 48060484Sobrien } 48160484Sobrien 48260484Sobrien if (asn_get_integer(b, &version) != ASN_ERR_OK) { 48360484Sobrien snmp_error("cannot decode version"); 48460484Sobrien return (SNMP_CODE_FAILED); 48560484Sobrien } 48660484Sobrien 48760484Sobrien if (version == 0) 48860484Sobrien pdu->version = SNMP_V1; 48960484Sobrien else if (version == 1) 49060484Sobrien pdu->version = SNMP_V2c; 49160484Sobrien else if (version == 3) 49260484Sobrien pdu->version = SNMP_V3; 49360484Sobrien else { 49460484Sobrien pdu->version = SNMP_Verr; 49560484Sobrien snmp_error("unsupported SNMP version"); 49660484Sobrien return (SNMP_CODE_BADENC); 49760484Sobrien } 49860484Sobrien 49960484Sobrien if (pdu->version == SNMP_V3) { 50060484Sobrien if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 50160484Sobrien snmp_error("cannot decode pdu global data header"); 50260484Sobrien return (SNMP_CODE_FAILED); 50360484Sobrien } 50460484Sobrien 50560484Sobrien if (asn_get_integer(b, &pdu->identifier) != ASN_ERR_OK) { 50660484Sobrien snmp_error("cannot decode msg indetifier"); 50760484Sobrien return (SNMP_CODE_FAILED); 50860484Sobrien } 50960484Sobrien 51060484Sobrien if (asn_get_integer(b, &pdu->engine.max_msg_size) 51160484Sobrien != ASN_ERR_OK) { 51260484Sobrien snmp_error("cannot decode msg size"); 51360484Sobrien return (SNMP_CODE_FAILED); 51460484Sobrien } 51560484Sobrien 51660484Sobrien octs_len = 1; 51760484Sobrien if (asn_get_octetstring(b, (u_char *)&pdu->flags, 51860484Sobrien &octs_len) != ASN_ERR_OK) { 51960484Sobrien snmp_error("cannot decode msg flags"); 52060484Sobrien return (SNMP_CODE_FAILED); 52160484Sobrien } 52260484Sobrien 52360484Sobrien if (asn_get_integer(b, &pdu->security_model) != ASN_ERR_OK) { 52460484Sobrien snmp_error("cannot decode msg size"); 52560484Sobrien return (SNMP_CODE_FAILED); 52660484Sobrien } 52760484Sobrien 52860484Sobrien if (pdu->security_model != SNMP_SECMODEL_USM) 52960484Sobrien return (SNMP_CODE_FAILED); 53060484Sobrien 53160484Sobrien if (parse_secparams(b, pdu) != ASN_ERR_OK) 53260484Sobrien return (SNMP_CODE_FAILED); 53360484Sobrien } else { 53460484Sobrien octs_len = SNMP_COMMUNITY_MAXLEN; 53560484Sobrien if (asn_get_octetstring(b, (u_char *)pdu->community, 53660484Sobrien &octs_len) != ASN_ERR_OK) { 53760484Sobrien snmp_error("cannot decode community"); 53860484Sobrien return (SNMP_CODE_FAILED); 53960484Sobrien } 54060484Sobrien pdu->community[octs_len] = '\0'; 54160484Sobrien } 54260484Sobrien 54360484Sobrien return (SNMP_CODE_OK); 54460484Sobrien} 54560484Sobrien 54660484Sobrienenum snmp_code 54760484Sobriensnmp_pdu_decode_scoped(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 54860484Sobrien{ 54960484Sobrien u_char type; 55060484Sobrien asn_len_t len, trailer; 55160484Sobrien enum asn_err err; 55260484Sobrien 55360484Sobrien if (pdu->version == SNMP_V3) { 55460484Sobrien if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 55560484Sobrien snmp_error("cannot decode scoped pdu header"); 55660484Sobrien return (SNMP_CODE_FAILED); 55760484Sobrien } 55860484Sobrien 55960484Sobrien len = SNMP_ENGINE_ID_SIZ; 56060484Sobrien if (asn_get_octetstring(b, (u_char *)&pdu->context_engine, 56160484Sobrien &len) != ASN_ERR_OK) { 56260484Sobrien snmp_error("cannot decode msg context engine"); 56360484Sobrien return (SNMP_CODE_FAILED); 56460484Sobrien } 56560484Sobrien pdu->context_engine_len = len; 56660484Sobrien 56760484Sobrien len = SNMP_CONTEXT_NAME_SIZ; 56860484Sobrien if (asn_get_octetstring(b, (u_char *)&pdu->context_name, 56960484Sobrien &len) != ASN_ERR_OK) { 57060484Sobrien snmp_error("cannot decode msg context name"); 57160484Sobrien return (SNMP_CODE_FAILED); 57260484Sobrien } 57360484Sobrien pdu->context_name[len] = '\0'; 57460484Sobrien } 57560484Sobrien 57660484Sobrien if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 57760484Sobrien snmp_error("cannot get pdu header"); 57860484Sobrien return (SNMP_CODE_FAILED); 57960484Sobrien } 58060484Sobrien if ((type & ~ASN_TYPE_MASK) != 58160484Sobrien (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 58260484Sobrien snmp_error("bad pdu header tag"); 58360484Sobrien return (SNMP_CODE_FAILED); 58460484Sobrien } 58560484Sobrien pdu->type = type & ASN_TYPE_MASK; 58660484Sobrien 58760484Sobrien switch (pdu->type) { 58860484Sobrien 58960484Sobrien case SNMP_PDU_GET: 59060484Sobrien case SNMP_PDU_GETNEXT: 59160484Sobrien case SNMP_PDU_RESPONSE: 59260484Sobrien case SNMP_PDU_SET: 59360484Sobrien break; 59460484Sobrien 59560484Sobrien case SNMP_PDU_TRAP: 59660484Sobrien if (pdu->version != SNMP_V1) { 59760484Sobrien snmp_error("bad pdu type %u", pdu->type); 59860484Sobrien return (SNMP_CODE_FAILED); 59960484Sobrien } 60060484Sobrien break; 60160484Sobrien 60260484Sobrien case SNMP_PDU_GETBULK: 60360484Sobrien case SNMP_PDU_INFORM: 60460484Sobrien case SNMP_PDU_TRAP2: 60560484Sobrien case SNMP_PDU_REPORT: 60660484Sobrien if (pdu->version == SNMP_V1) { 60760484Sobrien snmp_error("bad pdu type %u", pdu->type); 60860484Sobrien return (SNMP_CODE_FAILED); 60960484Sobrien } 61060484Sobrien break; 61160484Sobrien 61260484Sobrien default: 61360484Sobrien snmp_error("bad pdu type %u", pdu->type); 61460484Sobrien return (SNMP_CODE_FAILED); 61560484Sobrien } 61660484Sobrien 61760484Sobrien trailer = b->asn_len - len; 61860484Sobrien b->asn_len = len; 61960484Sobrien 62060484Sobrien err = parse_pdus(b, pdu, ip); 62160484Sobrien if (ASN_ERR_STOPPED(err)) 62260484Sobrien return (SNMP_CODE_FAILED); 62360484Sobrien 62460484Sobrien if (b->asn_len != 0) 62560484Sobrien snmp_error("ignoring trailing junk after pdu"); 62660484Sobrien 62760484Sobrien b->asn_len = trailer; 62860484Sobrien 62960484Sobrien return (SNMP_CODE_OK); 63060484Sobrien} 63160484Sobrien 63260484Sobrienenum snmp_code 63360484Sobriensnmp_pdu_decode_secmode(struct asn_buf *b, struct snmp_pdu *pdu) 63460484Sobrien{ 63560484Sobrien u_char type; 63660484Sobrien enum snmp_code code; 63760484Sobrien uint8_t digest[SNMP_USM_AUTH_SIZE]; 63860484Sobrien 63960484Sobrien if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && 64060484Sobrien (pdu->flags & SNMP_MSG_AUTH_FLAG) == 0) 64160484Sobrien return (SNMP_CODE_BADSECLEVEL); 64260484Sobrien 64360484Sobrien if ((code = snmp_pdu_calc_digest(pdu, digest)) != 64460484Sobrien SNMP_CODE_OK) 64560484Sobrien return (SNMP_CODE_FAILED); 64660484Sobrien 64760484Sobrien if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH && 64860484Sobrien memcmp(digest, pdu->msg_digest, sizeof(pdu->msg_digest)) != 0) 64960484Sobrien return (SNMP_CODE_BADDIGEST); 65060484Sobrien 65160484Sobrien if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && (asn_get_header(b, &type, 65260484Sobrien &pdu->scoped_len) != ASN_ERR_OK || type != ASN_TYPE_OCTETSTRING)) { 65360484Sobrien snmp_error("cannot decode encrypted pdu"); 65460484Sobrien return (SNMP_CODE_FAILED); 65560484Sobrien } 65660484Sobrien pdu->scoped_ptr = b->asn_ptr; 65760484Sobrien 65860484Sobrien if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && 65960484Sobrien (pdu->flags & SNMP_MSG_PRIV_FLAG) == 0) 66060484Sobrien return (SNMP_CODE_BADSECLEVEL); 66160484Sobrien 66260484Sobrien if ((code = snmp_pdu_decrypt(pdu)) != SNMP_CODE_OK) 66360484Sobrien return (SNMP_CODE_FAILED); 66460484Sobrien 66560484Sobrien return (code); 66660484Sobrien} 66760484Sobrien 66860484Sobrien/* 66960484Sobrien * Check whether what we have is the complete PDU by snooping at the 67060484Sobrien * enclosing structure header. This returns: 67160484Sobrien * -1 if there are ASN.1 errors 67260484Sobrien * 0 if we need more data 67360484Sobrien * > 0 the length of this PDU 67460484Sobrien */ 67560484Sobrienint 67660484Sobriensnmp_pdu_snoop(const struct asn_buf *b0) 67760484Sobrien{ 67860484Sobrien u_int length; 67960484Sobrien asn_len_t len; 68060484Sobrien struct asn_buf b = *b0; 68160484Sobrien 68260484Sobrien /* <0x10|0x20> <len> <data...> */ 68360484Sobrien 68460484Sobrien if (b.asn_len == 0) 68560484Sobrien return (0); 68660484Sobrien if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { 68760484Sobrien asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); 68860484Sobrien return (-1); 68960484Sobrien } 69060484Sobrien b.asn_len--; 69160484Sobrien b.asn_cptr++; 69260484Sobrien 69360484Sobrien if (b.asn_len == 0) 69460484Sobrien return (0); 69560484Sobrien 69660484Sobrien if (*b.asn_cptr & 0x80) { 69760484Sobrien /* long length */ 69860484Sobrien length = *b.asn_cptr++ & 0x7f; 69960484Sobrien b.asn_len--; 70060484Sobrien if (length == 0) { 70160484Sobrien asn_error(&b, "indefinite length not supported"); 70260484Sobrien return (-1); 70360484Sobrien } 70460484Sobrien if (length > ASN_MAXLENLEN) { 70560484Sobrien asn_error(&b, "long length too long (%u)", length); 70660484Sobrien return (-1); 70760484Sobrien } 70860484Sobrien if (length > b.asn_len) 70960484Sobrien return (0); 71060484Sobrien len = 0; 71160484Sobrien while (length--) { 71260484Sobrien len = (len << 8) | *b.asn_cptr++; 71360484Sobrien b.asn_len--; 71460484Sobrien } 71560484Sobrien } else { 71660484Sobrien len = *b.asn_cptr++; 71760484Sobrien b.asn_len--; 71860484Sobrien } 71960484Sobrien 72060484Sobrien if (len > b.asn_len) 72160484Sobrien return (0); 72260484Sobrien 72360484Sobrien return (len + b.asn_cptr - b0->asn_cptr); 72460484Sobrien} 72560484Sobrien 72660484Sobrien/* 72760484Sobrien * Encode the SNMP PDU without the variable bindings field. 72860484Sobrien * We do this the rather uneffective way by 72960484Sobrien * moving things around and assuming that the length field will never 73060484Sobrien * use more than 2 bytes. 73160484Sobrien * We need a number of pointers to apply the fixes afterwards. 73260484Sobrien */ 73360484Sobrienenum snmp_code 73460484Sobriensnmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) 73560484Sobrien{ 73660484Sobrien enum asn_err err; 73760484Sobrien u_char *v3_hdr_ptr; 73860484Sobrien 73960484Sobrien if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 74060484Sobrien &pdu->outer_ptr) != ASN_ERR_OK) 74160484Sobrien return (SNMP_CODE_FAILED); 74260484Sobrien 74360484Sobrien if (pdu->version == SNMP_V1) 74460484Sobrien err = asn_put_integer(b, 0); 74560484Sobrien else if (pdu->version == SNMP_V2c) 74660484Sobrien err = asn_put_integer(b, 1); 74760484Sobrien else if (pdu->version == SNMP_V3) 74860484Sobrien err = asn_put_integer(b, 3); 74960484Sobrien else 75060484Sobrien return (SNMP_CODE_BADVERS); 75160484Sobrien if (err != ASN_ERR_OK) 75260484Sobrien return (SNMP_CODE_FAILED); 75360484Sobrien 75460484Sobrien if (pdu->version == SNMP_V3) { 75560484Sobrien if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 75660484Sobrien ASN_TYPE_CONSTRUCTED), &v3_hdr_ptr) != ASN_ERR_OK) 75760484Sobrien return (SNMP_CODE_FAILED); 75860484Sobrien 75960484Sobrien if (asn_put_integer(b, pdu->identifier) != ASN_ERR_OK) 76060484Sobrien return (SNMP_CODE_FAILED); 76160484Sobrien 76260484Sobrien if (asn_put_integer(b, pdu->engine.max_msg_size) != ASN_ERR_OK) 76360484Sobrien return (SNMP_CODE_FAILED); 76460484Sobrien 76560484Sobrien if (pdu->type != SNMP_PDU_RESPONSE && 76660484Sobrien pdu->type != SNMP_PDU_TRAP && 76760484Sobrien pdu->type != SNMP_PDU_TRAP2 && 76860484Sobrien pdu->type != SNMP_PDU_REPORT) 76960484Sobrien pdu->flags |= SNMP_MSG_REPORT_FLAG; 77060484Sobrien 77160484Sobrien if (asn_put_octetstring(b, (u_char *)&pdu->flags, 1) 77260484Sobrien != ASN_ERR_OK) 77360484Sobrien return (SNMP_CODE_FAILED); 77460484Sobrien 77560484Sobrien if (asn_put_integer(b, pdu->security_model) != ASN_ERR_OK) 77660484Sobrien return (SNMP_CODE_FAILED); 77760484Sobrien 77860484Sobrien if (asn_commit_header(b, v3_hdr_ptr, NULL) != ASN_ERR_OK) 77960484Sobrien return (SNMP_CODE_FAILED); 78060484Sobrien 78160484Sobrien if (pdu->security_model != SNMP_SECMODEL_USM) 78260484Sobrien return (SNMP_CODE_FAILED); 78360484Sobrien 78460484Sobrien if (pdu_encode_secparams(b, pdu) != SNMP_CODE_OK) 78560484Sobrien return (SNMP_CODE_FAILED); 78660484Sobrien 78760484Sobrien /* View-based Access Conntrol information */ 78860484Sobrien if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 78960484Sobrien ASN_TYPE_CONSTRUCTED), &pdu->scoped_ptr) != ASN_ERR_OK) 79060484Sobrien return (SNMP_CODE_FAILED); 79160484Sobrien 79260484Sobrien if (asn_put_octetstring(b, (u_char *)pdu->context_engine, 79360484Sobrien pdu->context_engine_len) != ASN_ERR_OK) 79460484Sobrien return (SNMP_CODE_FAILED); 79560484Sobrien 79660484Sobrien if (asn_put_octetstring(b, (u_char *)pdu->context_name, 79760484Sobrien strlen(pdu->context_name)) != ASN_ERR_OK) 79860484Sobrien return (SNMP_CODE_FAILED); 79960484Sobrien } else { 80060484Sobrien if (asn_put_octetstring(b, (u_char *)pdu->community, 80160484Sobrien strlen(pdu->community)) != ASN_ERR_OK) 80260484Sobrien return (SNMP_CODE_FAILED); 80360484Sobrien } 80460484Sobrien 80560484Sobrien if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | 80660484Sobrien pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) 80760484Sobrien return (SNMP_CODE_FAILED); 80860484Sobrien 80960484Sobrien if (pdu->type == SNMP_PDU_TRAP) { 81060484Sobrien if (pdu->version != SNMP_V1 || 81160484Sobrien asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || 81260484Sobrien asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || 81360484Sobrien asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || 81460484Sobrien asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || 81560484Sobrien asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) 81660484Sobrien return (SNMP_CODE_FAILED); 81760484Sobrien } else { 81860484Sobrien if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || 81960484Sobrien pdu->type == SNMP_PDU_INFORM || 82060484Sobrien pdu->type == SNMP_PDU_TRAP2 || 82160484Sobrien pdu->type == SNMP_PDU_REPORT)) 82260484Sobrien return (SNMP_CODE_FAILED); 82360484Sobrien 82460484Sobrien if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || 82560484Sobrien asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || 82660484Sobrien asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) 82760484Sobrien return (SNMP_CODE_FAILED); 82860484Sobrien } 82960484Sobrien 83060484Sobrien if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 83160484Sobrien &pdu->vars_ptr) != ASN_ERR_OK) 83260484Sobrien return (SNMP_CODE_FAILED); 83360484Sobrien 83460484Sobrien return (SNMP_CODE_OK); 83560484Sobrien} 83660484Sobrien 83760484Sobrienstatic enum asn_err 83860484Sobriensnmp_pdu_fix_padd(struct asn_buf *b, struct snmp_pdu *pdu) 83960484Sobrien{ 84060484Sobrien asn_len_t padlen; 84160484Sobrien 84260484Sobrien if (pdu->user.priv_proto == SNMP_PRIV_DES && pdu->scoped_len % 8 != 0) { 84360484Sobrien padlen = 8 - (pdu->scoped_len % 8); 84460484Sobrien if (asn_pad(b, padlen) != ASN_ERR_OK) 84560484Sobrien return (ASN_ERR_FAILED); 84660484Sobrien pdu->scoped_len += padlen; 84760484Sobrien } 84860484Sobrien 84960484Sobrien return (ASN_ERR_OK); 85060484Sobrien} 85160484Sobrien 85260484Sobrienenum snmp_code 85360484Sobriensnmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu) 85460484Sobrien{ 85560484Sobrien size_t moved = 0; 85660484Sobrien enum snmp_code code; 85760484Sobrien 85860484Sobrien if (asn_commit_header(b, pdu->vars_ptr, NULL) != ASN_ERR_OK || 85960484Sobrien asn_commit_header(b, pdu->pdu_ptr, NULL) != ASN_ERR_OK) 86060484Sobrien return (SNMP_CODE_FAILED); 86160484Sobrien 86260484Sobrien if (pdu->version == SNMP_V3) { 86360484Sobrien if (asn_commit_header(b, pdu->scoped_ptr, NULL) != ASN_ERR_OK) 86460484Sobrien return (SNMP_CODE_FAILED); 86560484Sobrien 86660484Sobrien pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr; 86760484Sobrien if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK) 86860484Sobrien return (SNMP_CODE_FAILED); 86960484Sobrien 87060484Sobrien if (pdu->security_model != SNMP_SECMODEL_USM) 87160484Sobrien return (SNMP_CODE_FAILED); 87260484Sobrien 87360484Sobrien if (snmp_pdu_encrypt(pdu) != SNMP_CODE_OK) 87460484Sobrien return (SNMP_CODE_FAILED); 87560484Sobrien 87660484Sobrien if (pdu->user.priv_proto != SNMP_PRIV_NOPRIV && 87760484Sobrien asn_commit_header(b, pdu->encrypted_ptr, NULL) != ASN_ERR_OK) 87860484Sobrien return (SNMP_CODE_FAILED); 87960484Sobrien } 88060484Sobrien 88160484Sobrien if (asn_commit_header(b, pdu->outer_ptr, &moved) != ASN_ERR_OK) 88260484Sobrien return (SNMP_CODE_FAILED); 88360484Sobrien 88460484Sobrien pdu->outer_len = b->asn_ptr - pdu->outer_ptr; 88560484Sobrien pdu->digest_ptr -= moved; 88660484Sobrien 88760484Sobrien if (pdu->version == SNMP_V3) { 88860484Sobrien if ((code = snmp_pdu_calc_digest(pdu, pdu->msg_digest)) != 88960484Sobrien SNMP_CODE_OK) 89060484Sobrien return (SNMP_CODE_FAILED); 89160484Sobrien 89260484Sobrien if ((pdu->flags & SNMP_MSG_AUTH_FLAG) != 0) 89360484Sobrien memcpy(pdu->digest_ptr, pdu->msg_digest, 89460484Sobrien sizeof(pdu->msg_digest)); 89560484Sobrien } 89660484Sobrien 89760484Sobrien return (SNMP_CODE_OK); 89860484Sobrien} 89960484Sobrien 90060484Sobrien/* 90160484Sobrien * Encode a binding. Caller must ensure, that the syntax is ok for that version. 90260484Sobrien * Be sure not to cobber b, when something fails. 90360484Sobrien */ 90460484Sobrienenum asn_err 90560484Sobriensnmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) 90660484Sobrien{ 90760484Sobrien u_char *ptr; 90860484Sobrien enum asn_err err; 90960484Sobrien struct asn_buf save = *b; 91060484Sobrien 91160484Sobrien if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 91260484Sobrien ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { 91360484Sobrien *b = save; 91460484Sobrien return (err); 91560484Sobrien } 91660484Sobrien 91760484Sobrien if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { 91860484Sobrien *b = save; 91960484Sobrien return (err); 92060484Sobrien } 92160484Sobrien 92260484Sobrien switch (binding->syntax) { 92360484Sobrien 92460484Sobrien case SNMP_SYNTAX_NULL: 92560484Sobrien err = asn_put_null(b); 92660484Sobrien break; 92760484Sobrien 92860484Sobrien case SNMP_SYNTAX_INTEGER: 92960484Sobrien err = asn_put_integer(b, binding->v.integer); 93060484Sobrien break; 93160484Sobrien 93260484Sobrien case SNMP_SYNTAX_OCTETSTRING: 93360484Sobrien err = asn_put_octetstring(b, binding->v.octetstring.octets, 93460484Sobrien binding->v.octetstring.len); 93560484Sobrien break; 93660484Sobrien 93760484Sobrien case SNMP_SYNTAX_OID: 93860484Sobrien err = asn_put_objid(b, &binding->v.oid); 93960484Sobrien break; 94060484Sobrien 94160484Sobrien case SNMP_SYNTAX_IPADDRESS: 94260484Sobrien err = asn_put_ipaddress(b, binding->v.ipaddress); 94360484Sobrien break; 94460484Sobrien 94560484Sobrien case SNMP_SYNTAX_TIMETICKS: 94660484Sobrien err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); 94760484Sobrien break; 94860484Sobrien 94960484Sobrien case SNMP_SYNTAX_COUNTER: 95060484Sobrien err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); 95160484Sobrien break; 95260484Sobrien 95360484Sobrien case SNMP_SYNTAX_GAUGE: 95460484Sobrien err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); 95560484Sobrien break; 95660484Sobrien 95760484Sobrien case SNMP_SYNTAX_COUNTER64: 95860484Sobrien err = asn_put_counter64(b, binding->v.counter64); 95960484Sobrien break; 96060484Sobrien 96160484Sobrien case SNMP_SYNTAX_NOSUCHOBJECT: 96260484Sobrien err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); 96360484Sobrien break; 96460484Sobrien 96560484Sobrien case SNMP_SYNTAX_NOSUCHINSTANCE: 96660484Sobrien err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); 96760484Sobrien break; 96860484Sobrien 96960484Sobrien case SNMP_SYNTAX_ENDOFMIBVIEW: 97060484Sobrien err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); 97160484Sobrien break; 97260484Sobrien } 97360484Sobrien 97460484Sobrien if (err != ASN_ERR_OK) { 97560484Sobrien *b = save; 97660484Sobrien return (err); 97760484Sobrien } 97860484Sobrien 97960484Sobrien err = asn_commit_header(b, ptr, NULL); 98060484Sobrien if (err != ASN_ERR_OK) { 98160484Sobrien *b = save; 98260484Sobrien return (err); 98360484Sobrien } 98460484Sobrien 98560484Sobrien return (ASN_ERR_OK); 98660484Sobrien} 98760484Sobrien 98860484Sobrien/* 98960484Sobrien * Encode an PDU. 99060484Sobrien */ 99160484Sobrienenum snmp_code 99260484Sobriensnmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 99360484Sobrien{ 99460484Sobrien u_int idx; 99560484Sobrien enum snmp_code err; 99660484Sobrien 99760484Sobrien if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) 99860484Sobrien return (err); 99960484Sobrien for (idx = 0; idx < pdu->nbindings; idx++) 100060484Sobrien if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) 100160484Sobrien != ASN_ERR_OK) 100260484Sobrien return (SNMP_CODE_FAILED); 100360484Sobrien 100460484Sobrien return (snmp_fix_encoding(resp_b, pdu)); 100560484Sobrien} 100660484Sobrien 100760484Sobrienstatic void 100860484Sobriendump_binding(const struct snmp_value *b) 100960484Sobrien{ 101060484Sobrien u_int i; 101160484Sobrien char buf[ASN_OIDSTRLEN]; 101260484Sobrien 101360484Sobrien snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); 101460484Sobrien switch (b->syntax) { 101560484Sobrien 101660484Sobrien case SNMP_SYNTAX_NULL: 101760484Sobrien snmp_printf("NULL"); 101860484Sobrien break; 101960484Sobrien 102060484Sobrien case SNMP_SYNTAX_INTEGER: 102160484Sobrien snmp_printf("INTEGER %d", b->v.integer); 102260484Sobrien break; 102360484Sobrien 102460484Sobrien case SNMP_SYNTAX_OCTETSTRING: 102560484Sobrien snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); 102660484Sobrien for (i = 0; i < b->v.octetstring.len; i++) 102760484Sobrien snmp_printf(" %02x", b->v.octetstring.octets[i]); 102860484Sobrien break; 102960484Sobrien 103060484Sobrien case SNMP_SYNTAX_OID: 103160484Sobrien snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); 103260484Sobrien break; 103360484Sobrien 103460484Sobrien case SNMP_SYNTAX_IPADDRESS: 103560484Sobrien snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], 103660484Sobrien b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); 103760484Sobrien break; 103860484Sobrien 103960484Sobrien case SNMP_SYNTAX_COUNTER: 104060484Sobrien snmp_printf("COUNTER %u", b->v.uint32); 104160484Sobrien break; 104260484Sobrien 104360484Sobrien case SNMP_SYNTAX_GAUGE: 104460484Sobrien snmp_printf("GAUGE %u", b->v.uint32); 104560484Sobrien break; 104660484Sobrien 104760484Sobrien case SNMP_SYNTAX_TIMETICKS: 104860484Sobrien snmp_printf("TIMETICKS %u", b->v.uint32); 104960484Sobrien break; 105060484Sobrien 105160484Sobrien case SNMP_SYNTAX_COUNTER64: 105260484Sobrien snmp_printf("COUNTER64 %lld", b->v.counter64); 105360484Sobrien break; 105460484Sobrien 105560484Sobrien case SNMP_SYNTAX_NOSUCHOBJECT: 105660484Sobrien snmp_printf("NoSuchObject"); 105760484Sobrien break; 105860484Sobrien 105960484Sobrien case SNMP_SYNTAX_NOSUCHINSTANCE: 106060484Sobrien snmp_printf("NoSuchInstance"); 106160484Sobrien break; 106260484Sobrien 106360484Sobrien case SNMP_SYNTAX_ENDOFMIBVIEW: 106460484Sobrien snmp_printf("EndOfMibView"); 106560484Sobrien break; 106660484Sobrien 106760484Sobrien default: 106860484Sobrien snmp_printf("UNKNOWN SYNTAX %u", b->syntax); 106960484Sobrien break; 107060484Sobrien } 107160484Sobrien} 107260484Sobrien 107360484Sobrienstatic __inline void 107460484Sobriendump_bindings(const struct snmp_pdu *pdu) 107560484Sobrien{ 107660484Sobrien u_int i; 107760484Sobrien 107860484Sobrien for (i = 0; i < pdu->nbindings; i++) { 107960484Sobrien snmp_printf(" [%u]: ", i); 108060484Sobrien dump_binding(&pdu->bindings[i]); 108160484Sobrien snmp_printf("\n"); 108260484Sobrien } 108360484Sobrien} 108460484Sobrien 108560484Sobrienstatic __inline void 108660484Sobriendump_notrap(const struct snmp_pdu *pdu) 108760484Sobrien{ 108860484Sobrien snmp_printf(" request_id=%d", pdu->request_id); 108960484Sobrien snmp_printf(" error_status=%d", pdu->error_status); 109060484Sobrien snmp_printf(" error_index=%d\n", pdu->error_index); 109160484Sobrien dump_bindings(pdu); 109260484Sobrien} 109360484Sobrien 109460484Sobrienvoid 109560484Sobriensnmp_pdu_dump(const struct snmp_pdu *pdu) 109660484Sobrien{ 109760484Sobrien char buf[ASN_OIDSTRLEN]; 109860484Sobrien const char *vers; 109960484Sobrien static const char *types[] = { 110060484Sobrien [SNMP_PDU_GET] = "GET", 110160484Sobrien [SNMP_PDU_GETNEXT] = "GETNEXT", 110260484Sobrien [SNMP_PDU_RESPONSE] = "RESPONSE", 110360484Sobrien [SNMP_PDU_SET] = "SET", 110460484Sobrien [SNMP_PDU_TRAP] = "TRAPv1", 110560484Sobrien [SNMP_PDU_GETBULK] = "GETBULK", 110660484Sobrien [SNMP_PDU_INFORM] = "INFORM", 110760484Sobrien [SNMP_PDU_TRAP2] = "TRAPv2", 110860484Sobrien [SNMP_PDU_REPORT] = "REPORT", 110960484Sobrien }; 111060484Sobrien 111160484Sobrien if (pdu->version == SNMP_V1) 111260484Sobrien vers = "SNMPv1"; 111360484Sobrien else if (pdu->version == SNMP_V2c) 111460484Sobrien vers = "SNMPv2c"; 111560484Sobrien else if (pdu->version == SNMP_V3) 111660484Sobrien vers = "SNMPv3"; 111760484Sobrien else 111860484Sobrien vers = "v?"; 111960484Sobrien 112060484Sobrien switch (pdu->type) { 112160484Sobrien case SNMP_PDU_TRAP: 112260484Sobrien snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 112360484Sobrien snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); 112460484Sobrien snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], 112560484Sobrien pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); 112660484Sobrien snmp_printf(" generic_trap=%d", pdu->generic_trap); 112760484Sobrien snmp_printf(" specific_trap=%d", pdu->specific_trap); 112860484Sobrien snmp_printf(" time-stamp=%u\n", pdu->time_stamp); 112960484Sobrien dump_bindings(pdu); 113060484Sobrien break; 113160484Sobrien 113260484Sobrien case SNMP_PDU_GET: 113360484Sobrien case SNMP_PDU_GETNEXT: 113460484Sobrien case SNMP_PDU_RESPONSE: 113560484Sobrien case SNMP_PDU_SET: 113660484Sobrien case SNMP_PDU_GETBULK: 113760484Sobrien case SNMP_PDU_INFORM: 113860484Sobrien case SNMP_PDU_TRAP2: 113960484Sobrien case SNMP_PDU_REPORT: 114060484Sobrien snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 114160484Sobrien dump_notrap(pdu); 114260484Sobrien break; 114360484Sobrien 114460484Sobrien default: 114560484Sobrien snmp_printf("bad pdu type %u\n", pdu->type); 114660484Sobrien break; 114760484Sobrien } 114860484Sobrien} 114960484Sobrien 115060484Sobrienvoid 115160484Sobriensnmp_value_free(struct snmp_value *value) 115260484Sobrien{ 115360484Sobrien if (value->syntax == SNMP_SYNTAX_OCTETSTRING) 115460484Sobrien free(value->v.octetstring.octets); 115560484Sobrien value->syntax = SNMP_SYNTAX_NULL; 115660484Sobrien} 115760484Sobrien 115860484Sobrienint 115960484Sobriensnmp_value_copy(struct snmp_value *to, const struct snmp_value *from) 116060484Sobrien{ 116160484Sobrien to->var = from->var; 116260484Sobrien to->syntax = from->syntax; 116360484Sobrien 116460484Sobrien if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { 116560484Sobrien if ((to->v.octetstring.len = from->v.octetstring.len) == 0) 116660484Sobrien to->v.octetstring.octets = NULL; 116760484Sobrien else { 116860484Sobrien to->v.octetstring.octets = malloc(to->v.octetstring.len); 116960484Sobrien if (to->v.octetstring.octets == NULL) 117060484Sobrien return (-1); 117160484Sobrien (void)memcpy(to->v.octetstring.octets, 117260484Sobrien from->v.octetstring.octets, to->v.octetstring.len); 117360484Sobrien } 117460484Sobrien } else 117560484Sobrien to->v = from->v; 117660484Sobrien return (0); 117760484Sobrien} 117860484Sobrien 117960484Sobrienvoid 118060484Sobriensnmp_pdu_init_secparams(struct snmp_pdu *pdu) 118160484Sobrien{ 118260484Sobrien int32_t rval; 118360484Sobrien 118460484Sobrien if (pdu->user.auth_proto != SNMP_AUTH_NOAUTH) 118560484Sobrien pdu->flags |= SNMP_MSG_AUTH_FLAG; 118660484Sobrien 118760484Sobrien switch (pdu->user.priv_proto) { 118860484Sobrien case SNMP_PRIV_DES: 118960484Sobrien memcpy(pdu->msg_salt, &pdu->engine.engine_boots, 119060484Sobrien sizeof(pdu->engine.engine_boots)); 119160484Sobrien rval = random(); 119260484Sobrien memcpy(pdu->msg_salt + sizeof(pdu->engine.engine_boots), &rval, 119360484Sobrien sizeof(int32_t)); 119460484Sobrien pdu->flags |= SNMP_MSG_PRIV_FLAG; 119560484Sobrien break; 119660484Sobrien case SNMP_PRIV_AES: 119760484Sobrien rval = random(); 119860484Sobrien memcpy(pdu->msg_salt, &rval, sizeof(int32_t)); 119960484Sobrien rval = random(); 120060484Sobrien memcpy(pdu->msg_salt + sizeof(int32_t), &rval, sizeof(int32_t)); 120160484Sobrien pdu->flags |= SNMP_MSG_PRIV_FLAG; 120260484Sobrien break; 120360484Sobrien default: 120460484Sobrien break; 120560484Sobrien } 120660484Sobrien} 120760484Sobrien 120860484Sobrienvoid 120960484Sobriensnmp_pdu_free(struct snmp_pdu *pdu) 121060484Sobrien{ 121160484Sobrien u_int i; 121260484Sobrien 121360484Sobrien for (i = 0; i < pdu->nbindings; i++) 121460484Sobrien snmp_value_free(&pdu->bindings[i]); 121560484Sobrien} 121660484Sobrien 121760484Sobrien/* 121860484Sobrien * Parse an ASCII SNMP value into the binary form 121960484Sobrien */ 122060484Sobrienint 122160484Sobriensnmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) 122260484Sobrien{ 122360484Sobrien char *end; 122460484Sobrien 122560484Sobrien switch (syntax) { 122660484Sobrien 122760484Sobrien case SNMP_SYNTAX_NULL: 122860484Sobrien case SNMP_SYNTAX_NOSUCHOBJECT: 122960484Sobrien case SNMP_SYNTAX_NOSUCHINSTANCE: 123060484Sobrien case SNMP_SYNTAX_ENDOFMIBVIEW: 123160484Sobrien if (*str != '\0') 123260484Sobrien return (-1); 123360484Sobrien return (0); 123460484Sobrien 123560484Sobrien case SNMP_SYNTAX_INTEGER: 123660484Sobrien v->integer = strtoll(str, &end, 0); 123760484Sobrien if (*end != '\0') 123860484Sobrien return (-1); 123960484Sobrien return (0); 124060484Sobrien 124160484Sobrien case SNMP_SYNTAX_OCTETSTRING: 124260484Sobrien { 124360484Sobrien u_long len; /* actual length of string */ 124460484Sobrien u_long alloc; /* allocate length of string */ 124560484Sobrien u_char *octs; /* actual octets */ 124660484Sobrien u_long oct; /* actual octet */ 124760484Sobrien u_char *nocts; /* to avoid memory leak */ 124860484Sobrien u_char c; /* actual character */ 124960484Sobrien 125060484Sobrien# define STUFFC(C) \ 125160484Sobrien if (alloc == len) { \ 125260484Sobrien alloc += 100; \ 125360484Sobrien if ((nocts = realloc(octs, alloc)) == NULL) { \ 125460484Sobrien free(octs); \ 125560484Sobrien return (-1); \ 125660484Sobrien } \ 125760484Sobrien octs = nocts; \ 125860484Sobrien } \ 125960484Sobrien octs[len++] = (C); 126060484Sobrien 126160484Sobrien len = alloc = 0; 126260484Sobrien octs = NULL; 126360484Sobrien 126460484Sobrien if (*str == '"') { 126560484Sobrien str++; 126660484Sobrien while((c = *str++) != '\0') { 126760484Sobrien if (c == '"') { 126860484Sobrien if (*str != '\0') { 126960484Sobrien free(octs); 127060484Sobrien return (-1); 127160484Sobrien } 127260484Sobrien break; 127360484Sobrien } 127460484Sobrien if (c == '\\') { 127560484Sobrien switch (c = *str++) { 127660484Sobrien 127760484Sobrien case '\\': 127860484Sobrien break; 127960484Sobrien case 'a': 128060484Sobrien c = '\a'; 128160484Sobrien break; 128260484Sobrien case 'b': 128360484Sobrien c = '\b'; 128460484Sobrien break; 128560484Sobrien case 'f': 128660484Sobrien c = '\f'; 128760484Sobrien break; 128860484Sobrien case 'n': 128960484Sobrien c = '\n'; 129060484Sobrien break; 129160484Sobrien case 'r': 129260484Sobrien c = '\r'; 129360484Sobrien break; 129460484Sobrien case 't': 129560484Sobrien c = '\t'; 129660484Sobrien break; 129760484Sobrien case 'v': 129860484Sobrien c = '\v'; 129960484Sobrien break; 130060484Sobrien case 'x': 130160484Sobrien c = 0; 130260484Sobrien if (!isxdigit(*str)) 130360484Sobrien break; 130460484Sobrien if (isdigit(*str)) 130560484Sobrien c = *str++ - '0'; 130660484Sobrien else if (isupper(*str)) 130760484Sobrien c = *str++ - 'A' + 10; 130860484Sobrien else 130960484Sobrien c = *str++ - 'a' + 10; 131060484Sobrien if (!isxdigit(*str)) 131160484Sobrien break; 131260484Sobrien if (isdigit(*str)) 131360484Sobrien c += *str++ - '0'; 131460484Sobrien else if (isupper(*str)) 131560484Sobrien c += *str++ - 'A' + 10; 131660484Sobrien else 131760484Sobrien c += *str++ - 'a' + 10; 131860484Sobrien break; 131960484Sobrien case '0': case '1': case '2': 132060484Sobrien case '3': case '4': case '5': 132160484Sobrien case '6': case '7': 132260484Sobrien c = *str++ - '0'; 132360484Sobrien if (*str < '0' || *str > '7') 132460484Sobrien break; 132560484Sobrien c = *str++ - '0'; 132660484Sobrien if (*str < '0' || *str > '7') 132760484Sobrien break; 132860484Sobrien c = *str++ - '0'; 132960484Sobrien break; 133060484Sobrien default: 133160484Sobrien break; 133260484Sobrien } 133360484Sobrien } 133460484Sobrien STUFFC(c); 133560484Sobrien } 133660484Sobrien } else { 133760484Sobrien while (*str != '\0') { 133860484Sobrien oct = strtoul(str, &end, 16); 133960484Sobrien str = end; 134060484Sobrien if (oct > 0xff) { 134160484Sobrien free(octs); 134260484Sobrien return (-1); 134360484Sobrien } 134460484Sobrien STUFFC(oct); 134560484Sobrien if (*str == ':') 134660484Sobrien str++; 134760484Sobrien else if(*str != '\0') { 134860484Sobrien free(octs); 134960484Sobrien return (-1); 135060484Sobrien } 135160484Sobrien } 135260484Sobrien } 135360484Sobrien v->octetstring.octets = octs; 135460484Sobrien v->octetstring.len = len; 135560484Sobrien return (0); 135660484Sobrien# undef STUFFC 135760484Sobrien } 135860484Sobrien 135960484Sobrien case SNMP_SYNTAX_OID: 136060484Sobrien { 136160484Sobrien u_long subid; 136260484Sobrien 136360484Sobrien v->oid.len = 0; 136460484Sobrien 136560484Sobrien for (;;) { 136660484Sobrien if (v->oid.len == ASN_MAXOIDLEN) 136760484Sobrien return (-1); 136860484Sobrien subid = strtoul(str, &end, 10); 136960484Sobrien str = end; 137060484Sobrien if (subid > ASN_MAXID) 137160484Sobrien return (-1); 137260484Sobrien v->oid.subs[v->oid.len++] = (asn_subid_t)subid; 137360484Sobrien if (*str == '\0') 137460484Sobrien break; 137560484Sobrien if (*str != '.') 137660484Sobrien return (-1); 137760484Sobrien str++; 137860484Sobrien } 137960484Sobrien return (0); 138060484Sobrien } 138160484Sobrien 138260484Sobrien case SNMP_SYNTAX_IPADDRESS: 138360484Sobrien { 138460484Sobrien struct hostent *he; 138560484Sobrien u_long ip[4]; 138660484Sobrien int n; 138760484Sobrien 138860484Sobrien if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], 138960484Sobrien &ip[3], &n) == 4 && (size_t)n == strlen(str) && 139060484Sobrien ip[0] <= 0xff && ip[1] <= 0xff && 139160484Sobrien ip[2] <= 0xff && ip[3] <= 0xff) { 139260484Sobrien v->ipaddress[0] = (u_char)ip[0]; 139360484Sobrien v->ipaddress[1] = (u_char)ip[1]; 139460484Sobrien v->ipaddress[2] = (u_char)ip[2]; 139560484Sobrien v->ipaddress[3] = (u_char)ip[3]; 139660484Sobrien return (0); 139760484Sobrien } 139860484Sobrien 139960484Sobrien if ((he = gethostbyname(str)) == NULL) 140060484Sobrien return (-1); 140160484Sobrien if (he->h_addrtype != AF_INET) 140260484Sobrien return (-1); 140360484Sobrien 140460484Sobrien v->ipaddress[0] = he->h_addr[0]; 140560484Sobrien v->ipaddress[1] = he->h_addr[1]; 140660484Sobrien v->ipaddress[2] = he->h_addr[2]; 140760484Sobrien v->ipaddress[3] = he->h_addr[3]; 140860484Sobrien return (0); 140960484Sobrien } 141060484Sobrien 141160484Sobrien case SNMP_SYNTAX_COUNTER: 141260484Sobrien case SNMP_SYNTAX_GAUGE: 141360484Sobrien case SNMP_SYNTAX_TIMETICKS: 141460484Sobrien { 141560484Sobrien uint64_t sub; 141660484Sobrien 141760484Sobrien sub = strtoull(str, &end, 0); 141860484Sobrien if (*end != '\0' || sub > 0xffffffff) 141960484Sobrien return (-1); 142060484Sobrien v->uint32 = (uint32_t)sub; 142160484Sobrien return (0); 142260484Sobrien } 142360484Sobrien 142460484Sobrien case SNMP_SYNTAX_COUNTER64: 142560484Sobrien v->counter64 = strtoull(str, &end, 0); 142660484Sobrien if (*end != '\0') 142760484Sobrien return (-1); 142860484Sobrien return (0); 142960484Sobrien } 143060484Sobrien abort(); 143160484Sobrien} 143260484Sobrien 143360484Sobrienstatic void 143460484Sobriensnmp_error_func(const char *fmt, ...) 143560484Sobrien{ 143660484Sobrien va_list ap; 143760484Sobrien 143860484Sobrien va_start(ap, fmt); 143960484Sobrien fprintf(stderr, "SNMP: "); 144060484Sobrien vfprintf(stderr, fmt, ap); 144160484Sobrien fprintf(stderr, "\n"); 144260484Sobrien va_end(ap); 144360484Sobrien} 144460484Sobrien 144560484Sobrienstatic void 144660484Sobriensnmp_printf_func(const char *fmt, ...) 144760484Sobrien{ 144860484Sobrien va_list ap; 144960484Sobrien 145060484Sobrien va_start(ap, fmt); 145160484Sobrien vfprintf(stderr, fmt, ap); 145260484Sobrien va_end(ap); 145360484Sobrien} 145460484Sobrien