1f06ca4afSHartmut Brandt /* 2f06ca4afSHartmut Brandt * Copyright (c) 2001-2003 3f06ca4afSHartmut Brandt * Fraunhofer Institute for Open Communication Systems (FhG Fokus). 4f06ca4afSHartmut Brandt * All rights reserved. 5f06ca4afSHartmut Brandt * 6f06ca4afSHartmut Brandt * Author: Harti Brandt <harti@freebsd.org> 7f06ca4afSHartmut Brandt * 8f06ca4afSHartmut Brandt * Redistribution of this software and documentation and use in source and 9f06ca4afSHartmut Brandt * binary forms, with or without modification, are permitted provided that 10f06ca4afSHartmut Brandt * the following conditions are met: 11f06ca4afSHartmut Brandt * 12f06ca4afSHartmut Brandt * 1. Redistributions of source code or documentation must retain the above 13f06ca4afSHartmut Brandt * copyright notice, this list of conditions and the following disclaimer. 14f06ca4afSHartmut Brandt * 2. Redistributions in binary form must reproduce the above copyright 15f06ca4afSHartmut Brandt * notice, this list of conditions and the following disclaimer in the 16f06ca4afSHartmut Brandt * documentation and/or other materials provided with the distribution. 17f06ca4afSHartmut Brandt * 3. Neither the name of the Institute nor the names of its contributors 18f06ca4afSHartmut Brandt * may be used to endorse or promote products derived from this software 19f06ca4afSHartmut Brandt * without specific prior written permission. 20f06ca4afSHartmut Brandt * 21f06ca4afSHartmut Brandt * THIS SOFTWARE AND DOCUMENTATION IS PROVIDED BY FRAUNHOFER FOKUS 22f06ca4afSHartmut Brandt * AND ITS CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 23f06ca4afSHartmut Brandt * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 24f06ca4afSHartmut Brandt * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 25f06ca4afSHartmut Brandt * FRAUNHOFER FOKUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 26f06ca4afSHartmut Brandt * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27f06ca4afSHartmut Brandt * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, 28f06ca4afSHartmut Brandt * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 29f06ca4afSHartmut Brandt * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 30f06ca4afSHartmut Brandt * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 31f06ca4afSHartmut Brandt * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32f06ca4afSHartmut Brandt * 33f06ca4afSHartmut Brandt * $Begemot: bsnmp/lib/snmp.c,v 1.34 2003/01/28 13:44:34 hbb Exp $ 34f06ca4afSHartmut Brandt * 35f06ca4afSHartmut Brandt * SNMP 36f06ca4afSHartmut Brandt */ 37f06ca4afSHartmut Brandt #include <sys/types.h> 38f06ca4afSHartmut Brandt #include <sys/socket.h> 39f06ca4afSHartmut Brandt #include <stdio.h> 40f06ca4afSHartmut Brandt #include <stdlib.h> 41f06ca4afSHartmut Brandt #include <stddef.h> 42f06ca4afSHartmut Brandt #include <stdarg.h> 43f06ca4afSHartmut Brandt #include <string.h> 44f06ca4afSHartmut Brandt #include <ctype.h> 45f06ca4afSHartmut Brandt #include <netdb.h> 46f06ca4afSHartmut Brandt #include <errno.h> 47f06ca4afSHartmut Brandt 48f06ca4afSHartmut Brandt #include "asn1.h" 49f06ca4afSHartmut Brandt #include "snmp.h" 50f06ca4afSHartmut Brandt #include "snmppriv.h" 51f06ca4afSHartmut Brandt 52f06ca4afSHartmut Brandt static void snmp_error_func(const char *, ...); 53f06ca4afSHartmut Brandt static void snmp_printf_func(const char *, ...); 54f06ca4afSHartmut Brandt 55f06ca4afSHartmut Brandt void (*snmp_error)(const char *, ...) = snmp_error_func; 56f06ca4afSHartmut Brandt void (*snmp_printf)(const char *, ...) = snmp_printf_func; 57f06ca4afSHartmut Brandt 58f06ca4afSHartmut Brandt 59f06ca4afSHartmut Brandt /* 60f06ca4afSHartmut Brandt * Get the next variable binding from the list. 61f06ca4afSHartmut Brandt * ASN errors on the sequence or the OID are always fatal. 62f06ca4afSHartmut Brandt */ 63f06ca4afSHartmut Brandt static enum asn_err 64f06ca4afSHartmut Brandt get_var_binding(struct asn_buf *b, struct snmp_value *binding) 65f06ca4afSHartmut Brandt { 66f06ca4afSHartmut Brandt u_char type; 67f06ca4afSHartmut Brandt asn_len_t len, trailer; 68f06ca4afSHartmut Brandt enum asn_err err; 69f06ca4afSHartmut Brandt 70f06ca4afSHartmut Brandt if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 71f06ca4afSHartmut Brandt snmp_error("cannot parse varbind header"); 72f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 73f06ca4afSHartmut Brandt } 74f06ca4afSHartmut Brandt 75f06ca4afSHartmut Brandt /* temporary truncate the length so that the parser does not 76f06ca4afSHartmut Brandt * eat up bytes behind the sequence in the case the encoding is 77f06ca4afSHartmut Brandt * wrong of inner elements. */ 78f06ca4afSHartmut Brandt trailer = b->asn_len - len; 79f06ca4afSHartmut Brandt b->asn_len = len; 80f06ca4afSHartmut Brandt 81f06ca4afSHartmut Brandt if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { 82f06ca4afSHartmut Brandt snmp_error("cannot parse binding objid"); 83f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 84f06ca4afSHartmut Brandt } 85f06ca4afSHartmut Brandt if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { 86f06ca4afSHartmut Brandt snmp_error("cannot parse binding value header"); 87f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 88f06ca4afSHartmut Brandt } 89f06ca4afSHartmut Brandt 90f06ca4afSHartmut Brandt switch (type) { 91f06ca4afSHartmut Brandt 92f06ca4afSHartmut Brandt case ASN_TYPE_NULL: 93f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_NULL; 94f06ca4afSHartmut Brandt err = asn_get_null_raw(b, len); 95f06ca4afSHartmut Brandt break; 96f06ca4afSHartmut Brandt 97f06ca4afSHartmut Brandt case ASN_TYPE_INTEGER: 98f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_INTEGER; 99f06ca4afSHartmut Brandt err = asn_get_integer_raw(b, len, &binding->v.integer); 100f06ca4afSHartmut Brandt break; 101f06ca4afSHartmut Brandt 102f06ca4afSHartmut Brandt case ASN_TYPE_OCTETSTRING: 103f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_OCTETSTRING; 104f06ca4afSHartmut Brandt binding->v.octetstring.octets = malloc(len); 105f06ca4afSHartmut Brandt if (binding->v.octetstring.octets == NULL) { 106f06ca4afSHartmut Brandt snmp_error("%s", strerror(errno)); 107f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 108f06ca4afSHartmut Brandt } 109f06ca4afSHartmut Brandt binding->v.octetstring.len = len; 110f06ca4afSHartmut Brandt err = asn_get_octetstring_raw(b, len, 111f06ca4afSHartmut Brandt binding->v.octetstring.octets, 112f06ca4afSHartmut Brandt &binding->v.octetstring.len); 113f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err)) { 114f06ca4afSHartmut Brandt free(binding->v.octetstring.octets); 115f06ca4afSHartmut Brandt binding->v.octetstring.octets = NULL; 116f06ca4afSHartmut Brandt } 117f06ca4afSHartmut Brandt break; 118f06ca4afSHartmut Brandt 119f06ca4afSHartmut Brandt case ASN_TYPE_OBJID: 120f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_OID; 121f06ca4afSHartmut Brandt err = asn_get_objid_raw(b, len, &binding->v.oid); 122f06ca4afSHartmut Brandt break; 123f06ca4afSHartmut Brandt 124f06ca4afSHartmut Brandt case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: 125f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_IPADDRESS; 126f06ca4afSHartmut Brandt err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); 127f06ca4afSHartmut Brandt break; 128f06ca4afSHartmut Brandt 129f06ca4afSHartmut Brandt case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: 130f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_TIMETICKS; 131f06ca4afSHartmut Brandt err = asn_get_uint32_raw(b, len, &binding->v.uint32); 132f06ca4afSHartmut Brandt break; 133f06ca4afSHartmut Brandt 134f06ca4afSHartmut Brandt case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: 135f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_COUNTER; 136f06ca4afSHartmut Brandt err = asn_get_uint32_raw(b, len, &binding->v.uint32); 137f06ca4afSHartmut Brandt break; 138f06ca4afSHartmut Brandt 139f06ca4afSHartmut Brandt case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: 140f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_GAUGE; 141f06ca4afSHartmut Brandt err = asn_get_uint32_raw(b, len, &binding->v.uint32); 142f06ca4afSHartmut Brandt break; 143f06ca4afSHartmut Brandt 144f06ca4afSHartmut Brandt case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: 145f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_COUNTER64; 146f06ca4afSHartmut Brandt err = asn_get_counter64_raw(b, len, &binding->v.counter64); 147f06ca4afSHartmut Brandt break; 148f06ca4afSHartmut Brandt 149f06ca4afSHartmut Brandt case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: 150f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; 151f06ca4afSHartmut Brandt err = asn_get_null_raw(b, len); 152f06ca4afSHartmut Brandt break; 153f06ca4afSHartmut Brandt 154f06ca4afSHartmut Brandt case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: 155f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; 156f06ca4afSHartmut Brandt err = asn_get_null_raw(b, len); 157f06ca4afSHartmut Brandt break; 158f06ca4afSHartmut Brandt 159f06ca4afSHartmut Brandt case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: 160f06ca4afSHartmut Brandt binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; 161f06ca4afSHartmut Brandt err = asn_get_null_raw(b, len); 162f06ca4afSHartmut Brandt break; 163f06ca4afSHartmut Brandt 164f06ca4afSHartmut Brandt default: 165f06ca4afSHartmut Brandt if ((err = asn_skip(b, len)) == ASN_ERR_OK) 166f06ca4afSHartmut Brandt err = ASN_ERR_TAG; 167f06ca4afSHartmut Brandt snmp_error("bad binding value type 0x%x", type); 168f06ca4afSHartmut Brandt break; 169f06ca4afSHartmut Brandt } 170f06ca4afSHartmut Brandt 171f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err)) { 172f06ca4afSHartmut Brandt snmp_error("cannot parse binding value"); 173f06ca4afSHartmut Brandt return (err); 174f06ca4afSHartmut Brandt } 175f06ca4afSHartmut Brandt 176f06ca4afSHartmut Brandt if (b->asn_len != 0) 177f06ca4afSHartmut Brandt snmp_error("ignoring junk at end of binding"); 178f06ca4afSHartmut Brandt 179f06ca4afSHartmut Brandt b->asn_len = trailer; 180f06ca4afSHartmut Brandt 181f06ca4afSHartmut Brandt return (err); 182f06ca4afSHartmut Brandt } 183f06ca4afSHartmut Brandt 184f06ca4afSHartmut Brandt /* 185f06ca4afSHartmut Brandt * Parse the different PDUs contents. Any ASN error in the outer components 186f06ca4afSHartmut Brandt * are fatal. Only errors in variable values may be tolerated. If all 187f06ca4afSHartmut Brandt * components can be parsed it returns either ASN_ERR_OK or the first 188f06ca4afSHartmut Brandt * error that was found. 189f06ca4afSHartmut Brandt */ 190f06ca4afSHartmut Brandt enum asn_err 191f06ca4afSHartmut Brandt snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 192f06ca4afSHartmut Brandt { 193f06ca4afSHartmut Brandt if (pdu->type == SNMP_PDU_TRAP) { 194f06ca4afSHartmut Brandt if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { 195f06ca4afSHartmut Brandt snmp_error("cannot parse trap enterprise"); 196f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 197f06ca4afSHartmut Brandt } 198f06ca4afSHartmut Brandt if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { 199f06ca4afSHartmut Brandt snmp_error("cannot parse trap agent address"); 200f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 201f06ca4afSHartmut Brandt } 202f06ca4afSHartmut Brandt if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { 203f06ca4afSHartmut Brandt snmp_error("cannot parse 'generic-trap'"); 204f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 205f06ca4afSHartmut Brandt } 206f06ca4afSHartmut Brandt if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { 207f06ca4afSHartmut Brandt snmp_error("cannot parse 'specific-trap'"); 208f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 209f06ca4afSHartmut Brandt } 210f06ca4afSHartmut Brandt if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { 211f06ca4afSHartmut Brandt snmp_error("cannot parse trap 'time-stamp'"); 212f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 213f06ca4afSHartmut Brandt } 214f06ca4afSHartmut Brandt } else { 215f06ca4afSHartmut Brandt if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { 216f06ca4afSHartmut Brandt snmp_error("cannot parse 'request-id'"); 217f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 218f06ca4afSHartmut Brandt } 219f06ca4afSHartmut Brandt if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { 220f06ca4afSHartmut Brandt snmp_error("cannot parse 'error_status'"); 221f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 222f06ca4afSHartmut Brandt } 223f06ca4afSHartmut Brandt if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { 224f06ca4afSHartmut Brandt snmp_error("cannot parse 'error_index'"); 225f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 226f06ca4afSHartmut Brandt } 227f06ca4afSHartmut Brandt } 228f06ca4afSHartmut Brandt 229f06ca4afSHartmut Brandt if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { 230f06ca4afSHartmut Brandt snmp_error("cannot get varlist header"); 231f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 232f06ca4afSHartmut Brandt } 233f06ca4afSHartmut Brandt 234f06ca4afSHartmut Brandt return (ASN_ERR_OK); 235f06ca4afSHartmut Brandt } 236f06ca4afSHartmut Brandt 237f06ca4afSHartmut Brandt static enum asn_err 238f06ca4afSHartmut Brandt parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 239f06ca4afSHartmut Brandt { 240f06ca4afSHartmut Brandt asn_len_t len, trailer; 241f06ca4afSHartmut Brandt struct snmp_value *v; 242f06ca4afSHartmut Brandt enum asn_err err, err1; 243f06ca4afSHartmut Brandt 244f06ca4afSHartmut Brandt err = snmp_parse_pdus_hdr(b, pdu, &len); 245f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err)) 246f06ca4afSHartmut Brandt return (err); 247f06ca4afSHartmut Brandt 248f06ca4afSHartmut Brandt trailer = b->asn_len - len; 249f06ca4afSHartmut Brandt 250f06ca4afSHartmut Brandt v = pdu->bindings; 251f06ca4afSHartmut Brandt err = ASN_ERR_OK; 252f06ca4afSHartmut Brandt while (b->asn_len != 0) { 253f06ca4afSHartmut Brandt if (pdu->nbindings == SNMP_MAX_BINDINGS) { 254f06ca4afSHartmut Brandt snmp_error("too many bindings (> %u) in PDU", 255f06ca4afSHartmut Brandt SNMP_MAX_BINDINGS); 256f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 257f06ca4afSHartmut Brandt } 258f06ca4afSHartmut Brandt err1 = get_var_binding(b, v); 259f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err1)) 260f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 261f06ca4afSHartmut Brandt if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { 262f06ca4afSHartmut Brandt err = err1; 263f06ca4afSHartmut Brandt *ip = pdu->nbindings + 1; 264f06ca4afSHartmut Brandt } 265f06ca4afSHartmut Brandt pdu->nbindings++; 266f06ca4afSHartmut Brandt v++; 267f06ca4afSHartmut Brandt } 268f06ca4afSHartmut Brandt 269f06ca4afSHartmut Brandt b->asn_len = trailer; 270f06ca4afSHartmut Brandt 271f06ca4afSHartmut Brandt return (err); 272f06ca4afSHartmut Brandt } 273f06ca4afSHartmut Brandt 274f06ca4afSHartmut Brandt /* 275f06ca4afSHartmut Brandt * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'. 276f06ca4afSHartmut Brandt */ 277f06ca4afSHartmut Brandt enum asn_err 278f06ca4afSHartmut Brandt snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) 279f06ca4afSHartmut Brandt { 280f06ca4afSHartmut Brandt int32_t version; 281f06ca4afSHartmut Brandt u_char type; 282f06ca4afSHartmut Brandt u_int comm_len; 283f06ca4afSHartmut Brandt 284f06ca4afSHartmut Brandt if (asn_get_integer(b, &version) != ASN_ERR_OK) { 285f06ca4afSHartmut Brandt snmp_error("cannot decode version"); 286f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 287f06ca4afSHartmut Brandt } 288f06ca4afSHartmut Brandt 289f06ca4afSHartmut Brandt if (version == 0) { 290f06ca4afSHartmut Brandt pdu->version = SNMP_V1; 291f06ca4afSHartmut Brandt } else if (version == 1) { 292f06ca4afSHartmut Brandt pdu->version = SNMP_V2c; 293f06ca4afSHartmut Brandt } else { 294f06ca4afSHartmut Brandt pdu->version = SNMP_Verr; 295f06ca4afSHartmut Brandt snmp_error("unsupported SNMP version"); 296f06ca4afSHartmut Brandt return (ASN_ERR_TAG); 297f06ca4afSHartmut Brandt } 298f06ca4afSHartmut Brandt 299f06ca4afSHartmut Brandt comm_len = SNMP_COMMUNITY_MAXLEN; 300f06ca4afSHartmut Brandt if (asn_get_octetstring(b, (u_char *)pdu->community, 301f06ca4afSHartmut Brandt &comm_len) != ASN_ERR_OK) { 302f06ca4afSHartmut Brandt snmp_error("cannot decode community"); 303f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 304f06ca4afSHartmut Brandt } 305f06ca4afSHartmut Brandt pdu->community[comm_len] = '\0'; 306f06ca4afSHartmut Brandt 307f06ca4afSHartmut Brandt if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) { 308f06ca4afSHartmut Brandt snmp_error("cannot get pdu header"); 309f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 310f06ca4afSHartmut Brandt } 311f06ca4afSHartmut Brandt if ((type & ~ASN_TYPE_MASK) != 312f06ca4afSHartmut Brandt (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { 313f06ca4afSHartmut Brandt snmp_error("bad pdu header tag"); 314f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 315f06ca4afSHartmut Brandt } 316f06ca4afSHartmut Brandt pdu->type = type & ASN_TYPE_MASK; 317f06ca4afSHartmut Brandt 318f06ca4afSHartmut Brandt switch (pdu->type) { 319f06ca4afSHartmut Brandt 320f06ca4afSHartmut Brandt case SNMP_PDU_GET: 321f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 322f06ca4afSHartmut Brandt case SNMP_PDU_RESPONSE: 323f06ca4afSHartmut Brandt case SNMP_PDU_SET: 324f06ca4afSHartmut Brandt break; 325f06ca4afSHartmut Brandt 326f06ca4afSHartmut Brandt case SNMP_PDU_TRAP: 327f06ca4afSHartmut Brandt if (pdu->version != SNMP_V1) { 328f06ca4afSHartmut Brandt snmp_error("bad pdu type %u", pdu->type); 329f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 330f06ca4afSHartmut Brandt } 331f06ca4afSHartmut Brandt break; 332f06ca4afSHartmut Brandt 333f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 334f06ca4afSHartmut Brandt case SNMP_PDU_INFORM: 335f06ca4afSHartmut Brandt case SNMP_PDU_TRAP2: 336f06ca4afSHartmut Brandt case SNMP_PDU_REPORT: 337f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) { 338f06ca4afSHartmut Brandt snmp_error("bad pdu type %u", pdu->type); 339f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 340f06ca4afSHartmut Brandt } 341f06ca4afSHartmut Brandt break; 342f06ca4afSHartmut Brandt 343f06ca4afSHartmut Brandt default: 344f06ca4afSHartmut Brandt snmp_error("bad pdu type %u", pdu->type); 345f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 346f06ca4afSHartmut Brandt } 347f06ca4afSHartmut Brandt 348f06ca4afSHartmut Brandt 349f06ca4afSHartmut Brandt if (*lenp > b->asn_len) { 350f06ca4afSHartmut Brandt snmp_error("pdu length too long"); 351f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 352f06ca4afSHartmut Brandt } 353f06ca4afSHartmut Brandt 354f06ca4afSHartmut Brandt return (ASN_ERR_OK); 355f06ca4afSHartmut Brandt } 356f06ca4afSHartmut Brandt 357f06ca4afSHartmut Brandt static enum asn_err 358f06ca4afSHartmut Brandt parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 359f06ca4afSHartmut Brandt { 360f06ca4afSHartmut Brandt enum asn_err err; 361f06ca4afSHartmut Brandt asn_len_t len, trailer; 362f06ca4afSHartmut Brandt 363f06ca4afSHartmut Brandt err = snmp_parse_message_hdr(b, pdu, &len); 364f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err)) 365f06ca4afSHartmut Brandt return (err); 366f06ca4afSHartmut Brandt 367f06ca4afSHartmut Brandt trailer = b->asn_len - len; 368f06ca4afSHartmut Brandt b->asn_len = len; 369f06ca4afSHartmut Brandt 370f06ca4afSHartmut Brandt err = parse_pdus(b, pdu, ip); 371f06ca4afSHartmut Brandt if (ASN_ERR_STOPPED(err)) 372f06ca4afSHartmut Brandt return (ASN_ERR_FAILED); 373f06ca4afSHartmut Brandt 374f06ca4afSHartmut Brandt if (b->asn_len != 0) 375f06ca4afSHartmut Brandt snmp_error("ignoring trailing junk after pdu"); 376f06ca4afSHartmut Brandt 377f06ca4afSHartmut Brandt b->asn_len = trailer; 378f06ca4afSHartmut Brandt 379f06ca4afSHartmut Brandt return (err); 380f06ca4afSHartmut Brandt } 381f06ca4afSHartmut Brandt 382f06ca4afSHartmut Brandt /* 383f06ca4afSHartmut Brandt * Decode the PDU except for the variable bindings itself. 384f06ca4afSHartmut Brandt * If decoding fails because of a bad binding, but the rest can be 385f06ca4afSHartmut Brandt * decoded, ip points to the index of the failed variable (errors 386f06ca4afSHartmut Brandt * OORANGE, BADLEN or BADVERS). 387f06ca4afSHartmut Brandt */ 388f06ca4afSHartmut Brandt enum snmp_code 389f06ca4afSHartmut Brandt snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) 390f06ca4afSHartmut Brandt { 391f06ca4afSHartmut Brandt asn_len_t len; 392f06ca4afSHartmut Brandt 393f06ca4afSHartmut Brandt memset(pdu, 0, sizeof(*pdu)); 394f06ca4afSHartmut Brandt 395f06ca4afSHartmut Brandt if (asn_get_sequence(b, &len) != ASN_ERR_OK) { 396f06ca4afSHartmut Brandt snmp_error("cannot decode pdu header"); 397f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 398f06ca4afSHartmut Brandt } 399f06ca4afSHartmut Brandt if (b->asn_len < len) { 400f06ca4afSHartmut Brandt snmp_error("outer sequence value too short"); 401f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 402f06ca4afSHartmut Brandt } 403f06ca4afSHartmut Brandt if (b->asn_len != len) { 404f06ca4afSHartmut Brandt snmp_error("ignoring trailing junk in message"); 405f06ca4afSHartmut Brandt b->asn_len = len; 406f06ca4afSHartmut Brandt } 407f06ca4afSHartmut Brandt 408f06ca4afSHartmut Brandt switch (parse_message(b, pdu, ip)) { 409f06ca4afSHartmut Brandt 410f06ca4afSHartmut Brandt case ASN_ERR_OK: 411f06ca4afSHartmut Brandt return (SNMP_CODE_OK); 412f06ca4afSHartmut Brandt 413f06ca4afSHartmut Brandt case ASN_ERR_FAILED: 414f06ca4afSHartmut Brandt case ASN_ERR_EOBUF: 415f06ca4afSHartmut Brandt snmp_pdu_free(pdu); 416f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 417f06ca4afSHartmut Brandt 418f06ca4afSHartmut Brandt case ASN_ERR_BADLEN: 419f06ca4afSHartmut Brandt return (SNMP_CODE_BADLEN); 420f06ca4afSHartmut Brandt 421f06ca4afSHartmut Brandt case ASN_ERR_RANGE: 422f06ca4afSHartmut Brandt return (SNMP_CODE_OORANGE); 423f06ca4afSHartmut Brandt 424f06ca4afSHartmut Brandt case ASN_ERR_TAG: 425f06ca4afSHartmut Brandt if (pdu->version == SNMP_Verr) 426f06ca4afSHartmut Brandt return (SNMP_CODE_BADVERS); 427f06ca4afSHartmut Brandt else 428f06ca4afSHartmut Brandt return (SNMP_CODE_BADENC); 429f06ca4afSHartmut Brandt } 430f06ca4afSHartmut Brandt 431f06ca4afSHartmut Brandt return (SNMP_CODE_OK); 432f06ca4afSHartmut Brandt } 433f06ca4afSHartmut Brandt 434f06ca4afSHartmut Brandt /* 435f06ca4afSHartmut Brandt * Encode the SNMP PDU without the variable bindings field. 436f06ca4afSHartmut Brandt * We do this the rather uneffective way by 437f06ca4afSHartmut Brandt * moving things around and assuming that the length field will never 438f06ca4afSHartmut Brandt * use more than 2 bytes. 439f06ca4afSHartmut Brandt * We need a number of pointers to apply the fixes afterwards. 440f06ca4afSHartmut Brandt */ 441f06ca4afSHartmut Brandt enum snmp_code 442f06ca4afSHartmut Brandt snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) 443f06ca4afSHartmut Brandt { 444f06ca4afSHartmut Brandt enum asn_err err; 445f06ca4afSHartmut Brandt 446f06ca4afSHartmut Brandt if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 447f06ca4afSHartmut Brandt &pdu->outer_ptr) != ASN_ERR_OK) 448f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 449f06ca4afSHartmut Brandt 450f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 451f06ca4afSHartmut Brandt err = asn_put_integer(b, 0); 452f06ca4afSHartmut Brandt else if (pdu->version == SNMP_V2c) 453f06ca4afSHartmut Brandt err = asn_put_integer(b, 1); 454f06ca4afSHartmut Brandt else 455f06ca4afSHartmut Brandt return (SNMP_CODE_BADVERS); 456f06ca4afSHartmut Brandt if (err != ASN_ERR_OK) 457f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 458f06ca4afSHartmut Brandt 459f06ca4afSHartmut Brandt if (asn_put_octetstring(b, (u_char *)pdu->community, 460f06ca4afSHartmut Brandt strlen(pdu->community)) != ASN_ERR_OK) 461f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 462f06ca4afSHartmut Brandt 463f06ca4afSHartmut Brandt if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | 464f06ca4afSHartmut Brandt pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) 465f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 466f06ca4afSHartmut Brandt 467f06ca4afSHartmut Brandt if (pdu->type == SNMP_PDU_TRAP) { 468f06ca4afSHartmut Brandt if (pdu->version != SNMP_V1 || 469f06ca4afSHartmut Brandt asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || 470f06ca4afSHartmut Brandt asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || 471f06ca4afSHartmut Brandt asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || 472f06ca4afSHartmut Brandt asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || 473f06ca4afSHartmut Brandt asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) 474f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 475f06ca4afSHartmut Brandt } else { 476f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || 477f06ca4afSHartmut Brandt pdu->type == SNMP_PDU_INFORM || 478f06ca4afSHartmut Brandt pdu->type == SNMP_PDU_TRAP2 || 479f06ca4afSHartmut Brandt pdu->type == SNMP_PDU_REPORT)) 480f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 481f06ca4afSHartmut Brandt 482f06ca4afSHartmut Brandt if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || 483f06ca4afSHartmut Brandt asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || 484f06ca4afSHartmut Brandt asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) 485f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 486f06ca4afSHartmut Brandt } 487f06ca4afSHartmut Brandt 488f06ca4afSHartmut Brandt if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), 489f06ca4afSHartmut Brandt &pdu->vars_ptr) != ASN_ERR_OK) 490f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 491f06ca4afSHartmut Brandt 492f06ca4afSHartmut Brandt return (SNMP_CODE_OK); 493f06ca4afSHartmut Brandt } 494f06ca4afSHartmut Brandt 495f06ca4afSHartmut Brandt enum snmp_code 496f06ca4afSHartmut Brandt snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu) 497f06ca4afSHartmut Brandt { 498f06ca4afSHartmut Brandt if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK || 499f06ca4afSHartmut Brandt asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK || 500f06ca4afSHartmut Brandt asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK) 501f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 502f06ca4afSHartmut Brandt return (SNMP_CODE_OK); 503f06ca4afSHartmut Brandt } 504f06ca4afSHartmut Brandt 505f06ca4afSHartmut Brandt /* 506f06ca4afSHartmut Brandt * Encode a binding. Caller must ensure, that the syntax is ok for that version. 507f06ca4afSHartmut Brandt * Be sure not to cobber b, when something fails. 508f06ca4afSHartmut Brandt */ 509f06ca4afSHartmut Brandt enum asn_err 510f06ca4afSHartmut Brandt snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) 511f06ca4afSHartmut Brandt { 512f06ca4afSHartmut Brandt u_char *ptr; 513f06ca4afSHartmut Brandt enum asn_err err; 514f06ca4afSHartmut Brandt struct asn_buf save = *b; 515f06ca4afSHartmut Brandt 516f06ca4afSHartmut Brandt if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | 517f06ca4afSHartmut Brandt ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { 518f06ca4afSHartmut Brandt *b = save; 519f06ca4afSHartmut Brandt return (err); 520f06ca4afSHartmut Brandt } 521f06ca4afSHartmut Brandt 522f06ca4afSHartmut Brandt if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { 523f06ca4afSHartmut Brandt *b = save; 524f06ca4afSHartmut Brandt return (err); 525f06ca4afSHartmut Brandt } 526f06ca4afSHartmut Brandt 527f06ca4afSHartmut Brandt switch (binding->syntax) { 528f06ca4afSHartmut Brandt 529f06ca4afSHartmut Brandt case SNMP_SYNTAX_NULL: 530f06ca4afSHartmut Brandt err = asn_put_null(b); 531f06ca4afSHartmut Brandt break; 532f06ca4afSHartmut Brandt 533f06ca4afSHartmut Brandt case SNMP_SYNTAX_INTEGER: 534f06ca4afSHartmut Brandt err = asn_put_integer(b, binding->v.integer); 535f06ca4afSHartmut Brandt break; 536f06ca4afSHartmut Brandt 537f06ca4afSHartmut Brandt case SNMP_SYNTAX_OCTETSTRING: 538f06ca4afSHartmut Brandt err = asn_put_octetstring(b, binding->v.octetstring.octets, 539f06ca4afSHartmut Brandt binding->v.octetstring.len); 540f06ca4afSHartmut Brandt break; 541f06ca4afSHartmut Brandt 542f06ca4afSHartmut Brandt case SNMP_SYNTAX_OID: 543f06ca4afSHartmut Brandt err = asn_put_objid(b, &binding->v.oid); 544f06ca4afSHartmut Brandt break; 545f06ca4afSHartmut Brandt 546f06ca4afSHartmut Brandt case SNMP_SYNTAX_IPADDRESS: 547f06ca4afSHartmut Brandt err = asn_put_ipaddress(b, binding->v.ipaddress); 548f06ca4afSHartmut Brandt break; 549f06ca4afSHartmut Brandt 550f06ca4afSHartmut Brandt case SNMP_SYNTAX_TIMETICKS: 551f06ca4afSHartmut Brandt err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); 552f06ca4afSHartmut Brandt break; 553f06ca4afSHartmut Brandt 554f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER: 555f06ca4afSHartmut Brandt err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); 556f06ca4afSHartmut Brandt break; 557f06ca4afSHartmut Brandt 558f06ca4afSHartmut Brandt case SNMP_SYNTAX_GAUGE: 559f06ca4afSHartmut Brandt err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); 560f06ca4afSHartmut Brandt break; 561f06ca4afSHartmut Brandt 562f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER64: 563f06ca4afSHartmut Brandt err = asn_put_counter64(b, binding->v.counter64); 564f06ca4afSHartmut Brandt break; 565f06ca4afSHartmut Brandt 566f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHOBJECT: 567f06ca4afSHartmut Brandt err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); 568f06ca4afSHartmut Brandt break; 569f06ca4afSHartmut Brandt 570f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHINSTANCE: 571f06ca4afSHartmut Brandt err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); 572f06ca4afSHartmut Brandt break; 573f06ca4afSHartmut Brandt 574f06ca4afSHartmut Brandt case SNMP_SYNTAX_ENDOFMIBVIEW: 575f06ca4afSHartmut Brandt err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); 576f06ca4afSHartmut Brandt break; 577f06ca4afSHartmut Brandt } 578f06ca4afSHartmut Brandt 579f06ca4afSHartmut Brandt if (err != ASN_ERR_OK) { 580f06ca4afSHartmut Brandt *b = save; 581f06ca4afSHartmut Brandt return (err); 582f06ca4afSHartmut Brandt } 583f06ca4afSHartmut Brandt 584f06ca4afSHartmut Brandt err = asn_commit_header(b, ptr); 585f06ca4afSHartmut Brandt if (err != ASN_ERR_OK) { 586f06ca4afSHartmut Brandt *b = save; 587f06ca4afSHartmut Brandt return (err); 588f06ca4afSHartmut Brandt } 589f06ca4afSHartmut Brandt 590f06ca4afSHartmut Brandt return (ASN_ERR_OK); 591f06ca4afSHartmut Brandt } 592f06ca4afSHartmut Brandt 593f06ca4afSHartmut Brandt /* 594f06ca4afSHartmut Brandt * Encode an PDU. 595f06ca4afSHartmut Brandt */ 596f06ca4afSHartmut Brandt enum snmp_code 597f06ca4afSHartmut Brandt snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 598f06ca4afSHartmut Brandt { 599f06ca4afSHartmut Brandt u_int idx; 600f06ca4afSHartmut Brandt enum snmp_code err; 601f06ca4afSHartmut Brandt 602f06ca4afSHartmut Brandt if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) 603f06ca4afSHartmut Brandt return (err); 604f06ca4afSHartmut Brandt for (idx = 0; idx < pdu->nbindings; idx++) 605f06ca4afSHartmut Brandt if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) 606f06ca4afSHartmut Brandt != ASN_ERR_OK) 607f06ca4afSHartmut Brandt return (SNMP_CODE_FAILED); 608f06ca4afSHartmut Brandt 609f06ca4afSHartmut Brandt return (snmp_fix_encoding(resp_b, pdu)); 610f06ca4afSHartmut Brandt } 611f06ca4afSHartmut Brandt 612f06ca4afSHartmut Brandt static void 613f06ca4afSHartmut Brandt dump_binding(const struct snmp_value *b) 614f06ca4afSHartmut Brandt { 615f06ca4afSHartmut Brandt u_int i; 616f06ca4afSHartmut Brandt char buf[ASN_OIDSTRLEN]; 617f06ca4afSHartmut Brandt 618f06ca4afSHartmut Brandt snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); 619f06ca4afSHartmut Brandt switch (b->syntax) { 620f06ca4afSHartmut Brandt 621f06ca4afSHartmut Brandt case SNMP_SYNTAX_NULL: 622f06ca4afSHartmut Brandt snmp_printf("NULL"); 623f06ca4afSHartmut Brandt break; 624f06ca4afSHartmut Brandt 625f06ca4afSHartmut Brandt case SNMP_SYNTAX_INTEGER: 626f06ca4afSHartmut Brandt snmp_printf("INTEGER %d", b->v.integer); 627f06ca4afSHartmut Brandt break; 628f06ca4afSHartmut Brandt 629f06ca4afSHartmut Brandt case SNMP_SYNTAX_OCTETSTRING: 630f06ca4afSHartmut Brandt snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); 631f06ca4afSHartmut Brandt for (i = 0; i < b->v.octetstring.len; i++) 632f06ca4afSHartmut Brandt snmp_printf(" %02x", b->v.octetstring.octets[i]); 633f06ca4afSHartmut Brandt break; 634f06ca4afSHartmut Brandt 635f06ca4afSHartmut Brandt case SNMP_SYNTAX_OID: 636f06ca4afSHartmut Brandt snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); 637f06ca4afSHartmut Brandt break; 638f06ca4afSHartmut Brandt 639f06ca4afSHartmut Brandt case SNMP_SYNTAX_IPADDRESS: 640f06ca4afSHartmut Brandt snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], 641f06ca4afSHartmut Brandt b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); 642f06ca4afSHartmut Brandt break; 643f06ca4afSHartmut Brandt 644f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER: 645f06ca4afSHartmut Brandt snmp_printf("COUNTER %u", b->v.uint32); 646f06ca4afSHartmut Brandt break; 647f06ca4afSHartmut Brandt 648f06ca4afSHartmut Brandt case SNMP_SYNTAX_GAUGE: 649f06ca4afSHartmut Brandt snmp_printf("GAUGE %u", b->v.uint32); 650f06ca4afSHartmut Brandt break; 651f06ca4afSHartmut Brandt 652f06ca4afSHartmut Brandt case SNMP_SYNTAX_TIMETICKS: 653f06ca4afSHartmut Brandt snmp_printf("TIMETICKS %u", b->v.uint32); 654f06ca4afSHartmut Brandt break; 655f06ca4afSHartmut Brandt 656f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER64: 657f06ca4afSHartmut Brandt snmp_printf("COUNTER64 %lld", b->v.counter64); 658f06ca4afSHartmut Brandt break; 659f06ca4afSHartmut Brandt 660f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHOBJECT: 661f06ca4afSHartmut Brandt snmp_printf("NoSuchObject"); 662f06ca4afSHartmut Brandt break; 663f06ca4afSHartmut Brandt 664f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHINSTANCE: 665f06ca4afSHartmut Brandt snmp_printf("NoSuchInstance"); 666f06ca4afSHartmut Brandt break; 667f06ca4afSHartmut Brandt 668f06ca4afSHartmut Brandt case SNMP_SYNTAX_ENDOFMIBVIEW: 669f06ca4afSHartmut Brandt snmp_printf("EndOfMibView"); 670f06ca4afSHartmut Brandt break; 671f06ca4afSHartmut Brandt 672f06ca4afSHartmut Brandt default: 673f06ca4afSHartmut Brandt snmp_printf("UNKNOWN SYNTAX %u", b->syntax); 674f06ca4afSHartmut Brandt break; 675f06ca4afSHartmut Brandt } 676f06ca4afSHartmut Brandt } 677f06ca4afSHartmut Brandt 678f06ca4afSHartmut Brandt static __inline void 679f06ca4afSHartmut Brandt dump_bindings(const struct snmp_pdu *pdu) 680f06ca4afSHartmut Brandt { 681f06ca4afSHartmut Brandt u_int i; 682f06ca4afSHartmut Brandt 683f06ca4afSHartmut Brandt for (i = 0; i < pdu->nbindings; i++) { 684f06ca4afSHartmut Brandt snmp_printf(" [%u]: ", i); 685f06ca4afSHartmut Brandt dump_binding(&pdu->bindings[i]); 686f06ca4afSHartmut Brandt snmp_printf("\n"); 687f06ca4afSHartmut Brandt } 688f06ca4afSHartmut Brandt } 689f06ca4afSHartmut Brandt 690f06ca4afSHartmut Brandt static __inline void 691f06ca4afSHartmut Brandt dump_notrap(const struct snmp_pdu *pdu) 692f06ca4afSHartmut Brandt { 693f06ca4afSHartmut Brandt snmp_printf(" request_id=%d", pdu->request_id); 694f06ca4afSHartmut Brandt snmp_printf(" error_status=%d", pdu->error_status); 695f06ca4afSHartmut Brandt snmp_printf(" error_index=%d\n", pdu->error_index); 696f06ca4afSHartmut Brandt dump_bindings(pdu); 697f06ca4afSHartmut Brandt } 698f06ca4afSHartmut Brandt 699f06ca4afSHartmut Brandt void 700f06ca4afSHartmut Brandt snmp_pdu_dump(const struct snmp_pdu *pdu) 701f06ca4afSHartmut Brandt { 702f06ca4afSHartmut Brandt char buf[ASN_OIDSTRLEN]; 703f06ca4afSHartmut Brandt const char *vers; 704f06ca4afSHartmut Brandt static const char *types[] = { 705f06ca4afSHartmut Brandt [SNMP_PDU_GET] = "GET", 706f06ca4afSHartmut Brandt [SNMP_PDU_GETNEXT] = "GETNEXT", 707f06ca4afSHartmut Brandt [SNMP_PDU_RESPONSE] = "RESPONSE", 708f06ca4afSHartmut Brandt [SNMP_PDU_SET] = "SET", 709f06ca4afSHartmut Brandt [SNMP_PDU_TRAP] = "TRAPv1", 710f06ca4afSHartmut Brandt [SNMP_PDU_GETBULK] = "GETBULK", 711f06ca4afSHartmut Brandt [SNMP_PDU_INFORM] = "INFORM", 712f06ca4afSHartmut Brandt [SNMP_PDU_TRAP2] = "TRAPv2", 713f06ca4afSHartmut Brandt [SNMP_PDU_REPORT] = "REPORT", 714f06ca4afSHartmut Brandt }; 715f06ca4afSHartmut Brandt 716f06ca4afSHartmut Brandt if (pdu->version == SNMP_V1) 717f06ca4afSHartmut Brandt vers = "SNMPv1"; 718f06ca4afSHartmut Brandt else if (pdu->version == SNMP_V2c) 719f06ca4afSHartmut Brandt vers = "SNMPv2c"; 720f06ca4afSHartmut Brandt else 721f06ca4afSHartmut Brandt vers = "v?"; 722f06ca4afSHartmut Brandt 723f06ca4afSHartmut Brandt switch (pdu->type) { 724f06ca4afSHartmut Brandt case SNMP_PDU_TRAP: 725f06ca4afSHartmut Brandt snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 726f06ca4afSHartmut Brandt snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); 727f06ca4afSHartmut Brandt snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], 728f06ca4afSHartmut Brandt pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); 729f06ca4afSHartmut Brandt snmp_printf(" generic_trap=%d", pdu->generic_trap); 730f06ca4afSHartmut Brandt snmp_printf(" specific_trap=%d", pdu->specific_trap); 731f06ca4afSHartmut Brandt snmp_printf(" time-stamp=%u\n", pdu->time_stamp); 732f06ca4afSHartmut Brandt dump_bindings(pdu); 733f06ca4afSHartmut Brandt break; 734f06ca4afSHartmut Brandt 735f06ca4afSHartmut Brandt case SNMP_PDU_GET: 736f06ca4afSHartmut Brandt case SNMP_PDU_GETNEXT: 737f06ca4afSHartmut Brandt case SNMP_PDU_RESPONSE: 738f06ca4afSHartmut Brandt case SNMP_PDU_SET: 739f06ca4afSHartmut Brandt case SNMP_PDU_GETBULK: 740f06ca4afSHartmut Brandt case SNMP_PDU_INFORM: 741f06ca4afSHartmut Brandt case SNMP_PDU_TRAP2: 742f06ca4afSHartmut Brandt case SNMP_PDU_REPORT: 743f06ca4afSHartmut Brandt snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); 744f06ca4afSHartmut Brandt dump_notrap(pdu); 745f06ca4afSHartmut Brandt break; 746f06ca4afSHartmut Brandt 747f06ca4afSHartmut Brandt default: 748f06ca4afSHartmut Brandt snmp_printf("bad pdu type %u\n", pdu->type); 749f06ca4afSHartmut Brandt break; 750f06ca4afSHartmut Brandt } 751f06ca4afSHartmut Brandt } 752f06ca4afSHartmut Brandt 753f06ca4afSHartmut Brandt void 754f06ca4afSHartmut Brandt snmp_value_free(struct snmp_value *value) 755f06ca4afSHartmut Brandt { 756f06ca4afSHartmut Brandt if (value->syntax == SNMP_SYNTAX_OCTETSTRING) 757f06ca4afSHartmut Brandt free(value->v.octetstring.octets); 758f06ca4afSHartmut Brandt value->syntax = SNMP_SYNTAX_NULL; 759f06ca4afSHartmut Brandt } 760f06ca4afSHartmut Brandt 761f06ca4afSHartmut Brandt int 762f06ca4afSHartmut Brandt snmp_value_copy(struct snmp_value *to, const struct snmp_value *from) 763f06ca4afSHartmut Brandt { 764f06ca4afSHartmut Brandt to->var = from->var; 765f06ca4afSHartmut Brandt to->syntax = from->syntax; 766f06ca4afSHartmut Brandt 767f06ca4afSHartmut Brandt if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { 768f06ca4afSHartmut Brandt if ((to->v.octetstring.len = from->v.octetstring.len) == 0) 769f06ca4afSHartmut Brandt to->v.octetstring.octets = NULL; 770f06ca4afSHartmut Brandt else { 771f06ca4afSHartmut Brandt to->v.octetstring.octets = malloc(to->v.octetstring.len); 772f06ca4afSHartmut Brandt if (to->v.octetstring.octets == NULL) 773f06ca4afSHartmut Brandt return (-1); 774f06ca4afSHartmut Brandt (void)memcpy(to->v.octetstring.octets, 775f06ca4afSHartmut Brandt from->v.octetstring.octets, to->v.octetstring.len); 776f06ca4afSHartmut Brandt } 777f06ca4afSHartmut Brandt } else 778f06ca4afSHartmut Brandt to->v = from->v; 779f06ca4afSHartmut Brandt return (0); 780f06ca4afSHartmut Brandt } 781f06ca4afSHartmut Brandt 782f06ca4afSHartmut Brandt void 783f06ca4afSHartmut Brandt snmp_pdu_free(struct snmp_pdu *pdu) 784f06ca4afSHartmut Brandt { 785f06ca4afSHartmut Brandt u_int i; 786f06ca4afSHartmut Brandt 787f06ca4afSHartmut Brandt for (i = 0; i < pdu->nbindings; i++) 788f06ca4afSHartmut Brandt snmp_value_free(&pdu->bindings[i]); 789f06ca4afSHartmut Brandt } 790f06ca4afSHartmut Brandt 791f06ca4afSHartmut Brandt /* 792f06ca4afSHartmut Brandt * Parse an ASCII SNMP value into the binary form 793f06ca4afSHartmut Brandt */ 794f06ca4afSHartmut Brandt int 795f06ca4afSHartmut Brandt snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) 796f06ca4afSHartmut Brandt { 797f06ca4afSHartmut Brandt char *end; 798f06ca4afSHartmut Brandt 799f06ca4afSHartmut Brandt switch (syntax) { 800f06ca4afSHartmut Brandt 801f06ca4afSHartmut Brandt case SNMP_SYNTAX_NULL: 802f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHOBJECT: 803f06ca4afSHartmut Brandt case SNMP_SYNTAX_NOSUCHINSTANCE: 804f06ca4afSHartmut Brandt case SNMP_SYNTAX_ENDOFMIBVIEW: 805f06ca4afSHartmut Brandt if (*str != '\0') 806f06ca4afSHartmut Brandt return (-1); 807f06ca4afSHartmut Brandt return (0); 808f06ca4afSHartmut Brandt 809f06ca4afSHartmut Brandt case SNMP_SYNTAX_INTEGER: 810f06ca4afSHartmut Brandt v->integer = strtoll(str, &end, 0); 811f06ca4afSHartmut Brandt if (*end != '\0') 812f06ca4afSHartmut Brandt return (-1); 813f06ca4afSHartmut Brandt return (0); 814f06ca4afSHartmut Brandt 815f06ca4afSHartmut Brandt case SNMP_SYNTAX_OCTETSTRING: 816f06ca4afSHartmut Brandt { 817f06ca4afSHartmut Brandt u_long len; /* actual length of string */ 818f06ca4afSHartmut Brandt u_long alloc; /* allocate length of string */ 819f06ca4afSHartmut Brandt u_char *octs; /* actual octets */ 820f06ca4afSHartmut Brandt u_long oct; /* actual octet */ 821f06ca4afSHartmut Brandt u_char *nocts; /* to avoid memory leak */ 822f06ca4afSHartmut Brandt u_char c; /* actual character */ 823f06ca4afSHartmut Brandt 824f06ca4afSHartmut Brandt # define STUFFC(C) \ 825f06ca4afSHartmut Brandt if (alloc == len) { \ 826f06ca4afSHartmut Brandt alloc += 100; \ 827f06ca4afSHartmut Brandt if ((nocts = realloc(octs, alloc)) == NULL) { \ 828f06ca4afSHartmut Brandt free(octs); \ 829f06ca4afSHartmut Brandt return (-1); \ 830f06ca4afSHartmut Brandt } \ 831f06ca4afSHartmut Brandt octs = nocts; \ 832f06ca4afSHartmut Brandt } \ 833f06ca4afSHartmut Brandt octs[len++] = (C); 834f06ca4afSHartmut Brandt 835f06ca4afSHartmut Brandt len = alloc = 0; 836f06ca4afSHartmut Brandt octs = NULL; 837f06ca4afSHartmut Brandt 838f06ca4afSHartmut Brandt if (*str == '"') { 839f06ca4afSHartmut Brandt str++; 840f06ca4afSHartmut Brandt while((c = *str++) != '\0') { 841f06ca4afSHartmut Brandt if (c == '"') { 842f06ca4afSHartmut Brandt if (*str != '\0') { 843f06ca4afSHartmut Brandt free(octs); 844f06ca4afSHartmut Brandt return (-1); 845f06ca4afSHartmut Brandt } 846f06ca4afSHartmut Brandt break; 847f06ca4afSHartmut Brandt } 848f06ca4afSHartmut Brandt if (c == '\\') { 849f06ca4afSHartmut Brandt switch (c = *str++) { 850f06ca4afSHartmut Brandt 851f06ca4afSHartmut Brandt case '\\': 852f06ca4afSHartmut Brandt break; 853f06ca4afSHartmut Brandt case 'a': 854f06ca4afSHartmut Brandt c = '\a'; 855f06ca4afSHartmut Brandt break; 856f06ca4afSHartmut Brandt case 'b': 857f06ca4afSHartmut Brandt c = '\b'; 858f06ca4afSHartmut Brandt break; 859f06ca4afSHartmut Brandt case 'f': 860f06ca4afSHartmut Brandt c = '\f'; 861f06ca4afSHartmut Brandt break; 862f06ca4afSHartmut Brandt case 'n': 863f06ca4afSHartmut Brandt c = '\n'; 864f06ca4afSHartmut Brandt break; 865f06ca4afSHartmut Brandt case 'r': 866f06ca4afSHartmut Brandt c = '\r'; 867f06ca4afSHartmut Brandt break; 868f06ca4afSHartmut Brandt case 't': 869f06ca4afSHartmut Brandt c = '\t'; 870f06ca4afSHartmut Brandt break; 871f06ca4afSHartmut Brandt case 'v': 872f06ca4afSHartmut Brandt c = '\v'; 873f06ca4afSHartmut Brandt break; 874f06ca4afSHartmut Brandt case 'x': 875f06ca4afSHartmut Brandt c = 0; 876f06ca4afSHartmut Brandt if (!isxdigit(*str)) 877f06ca4afSHartmut Brandt break; 878f06ca4afSHartmut Brandt if (isdigit(*str)) 879f06ca4afSHartmut Brandt c = *str++ - '0'; 880f06ca4afSHartmut Brandt else if (isupper(*str)) 881f06ca4afSHartmut Brandt c = *str++ - 'A' + 10; 882f06ca4afSHartmut Brandt else 883f06ca4afSHartmut Brandt c = *str++ - 'a' + 10; 884f06ca4afSHartmut Brandt if (!isxdigit(*str)) 885f06ca4afSHartmut Brandt break; 886f06ca4afSHartmut Brandt if (isdigit(*str)) 887f06ca4afSHartmut Brandt c += *str++ - '0'; 888f06ca4afSHartmut Brandt else if (isupper(*str)) 889f06ca4afSHartmut Brandt c += *str++ - 'A' + 10; 890f06ca4afSHartmut Brandt else 891f06ca4afSHartmut Brandt c += *str++ - 'a' + 10; 892f06ca4afSHartmut Brandt break; 893f06ca4afSHartmut Brandt case '0': case '1': case '2': 894f06ca4afSHartmut Brandt case '3': case '4': case '5': 895f06ca4afSHartmut Brandt case '6': case '7': 896f06ca4afSHartmut Brandt c = *str++ - '0'; 897f06ca4afSHartmut Brandt if (*str < '0' || *str > '7') 898f06ca4afSHartmut Brandt break; 899f06ca4afSHartmut Brandt c = *str++ - '0'; 900f06ca4afSHartmut Brandt if (*str < '0' || *str > '7') 901f06ca4afSHartmut Brandt break; 902f06ca4afSHartmut Brandt c = *str++ - '0'; 903f06ca4afSHartmut Brandt break; 904f06ca4afSHartmut Brandt default: 905f06ca4afSHartmut Brandt break; 906f06ca4afSHartmut Brandt } 907f06ca4afSHartmut Brandt } 908f06ca4afSHartmut Brandt STUFFC(c); 909f06ca4afSHartmut Brandt } 910f06ca4afSHartmut Brandt } else { 911f06ca4afSHartmut Brandt while (*str != '\0') { 912f06ca4afSHartmut Brandt oct = strtoul(str, &end, 16); 913f06ca4afSHartmut Brandt str = end; 914f06ca4afSHartmut Brandt if (oct > 0xff) { 915f06ca4afSHartmut Brandt free(octs); 916f06ca4afSHartmut Brandt return (-1); 917f06ca4afSHartmut Brandt } 918f06ca4afSHartmut Brandt STUFFC(oct); 919f06ca4afSHartmut Brandt if (*str == ':') 920f06ca4afSHartmut Brandt str++; 921f06ca4afSHartmut Brandt else if(*str != '\0') { 922f06ca4afSHartmut Brandt free(octs); 923f06ca4afSHartmut Brandt return (-1); 924f06ca4afSHartmut Brandt } 925f06ca4afSHartmut Brandt } 926f06ca4afSHartmut Brandt } 927f06ca4afSHartmut Brandt v->octetstring.octets = octs; 928f06ca4afSHartmut Brandt v->octetstring.len = len; 929f06ca4afSHartmut Brandt return (0); 930f06ca4afSHartmut Brandt # undef STUFFC 931f06ca4afSHartmut Brandt } 932f06ca4afSHartmut Brandt 933f06ca4afSHartmut Brandt case SNMP_SYNTAX_OID: 934f06ca4afSHartmut Brandt { 935f06ca4afSHartmut Brandt u_long subid; 936f06ca4afSHartmut Brandt 937f06ca4afSHartmut Brandt v->oid.len = 0; 938f06ca4afSHartmut Brandt 939f06ca4afSHartmut Brandt for (;;) { 940f06ca4afSHartmut Brandt if (v->oid.len == ASN_MAXOIDLEN) 941f06ca4afSHartmut Brandt return (-1); 942f06ca4afSHartmut Brandt subid = strtoul(str, &end, 10); 943f06ca4afSHartmut Brandt str = end; 944f06ca4afSHartmut Brandt if (subid > ASN_MAXID) 945f06ca4afSHartmut Brandt return (-1); 946f06ca4afSHartmut Brandt v->oid.subs[v->oid.len++] = (asn_subid_t)subid; 947f06ca4afSHartmut Brandt if (*str == '\0') 948f06ca4afSHartmut Brandt break; 949f06ca4afSHartmut Brandt if (*str != '.') 950f06ca4afSHartmut Brandt return (-1); 951f06ca4afSHartmut Brandt str++; 952f06ca4afSHartmut Brandt } 953f06ca4afSHartmut Brandt return (0); 954f06ca4afSHartmut Brandt } 955f06ca4afSHartmut Brandt 956f06ca4afSHartmut Brandt case SNMP_SYNTAX_IPADDRESS: 957f06ca4afSHartmut Brandt { 958f06ca4afSHartmut Brandt struct hostent *he; 959f06ca4afSHartmut Brandt u_long ip[4]; 960f06ca4afSHartmut Brandt int n; 961f06ca4afSHartmut Brandt 962f06ca4afSHartmut Brandt if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], 963f06ca4afSHartmut Brandt &ip[3], &n) == 4 && (size_t)n == strlen(str) && 964f06ca4afSHartmut Brandt ip[0] <= 0xff && ip[1] <= 0xff && 965f06ca4afSHartmut Brandt ip[2] <= 0xff && ip[3] <= 0xff) { 966f06ca4afSHartmut Brandt v->ipaddress[0] = (u_char)ip[0]; 967f06ca4afSHartmut Brandt v->ipaddress[1] = (u_char)ip[1]; 968f06ca4afSHartmut Brandt v->ipaddress[2] = (u_char)ip[2]; 969f06ca4afSHartmut Brandt v->ipaddress[3] = (u_char)ip[3]; 970f06ca4afSHartmut Brandt return (0); 971f06ca4afSHartmut Brandt } 972f06ca4afSHartmut Brandt 973f06ca4afSHartmut Brandt if ((he = gethostbyname(str)) == NULL) 974f06ca4afSHartmut Brandt return (-1); 975f06ca4afSHartmut Brandt if (he->h_addrtype != AF_INET) 976f06ca4afSHartmut Brandt return (-1); 977f06ca4afSHartmut Brandt 978f06ca4afSHartmut Brandt v->ipaddress[0] = he->h_addr[0]; 979f06ca4afSHartmut Brandt v->ipaddress[1] = he->h_addr[1]; 980f06ca4afSHartmut Brandt v->ipaddress[2] = he->h_addr[2]; 981f06ca4afSHartmut Brandt v->ipaddress[3] = he->h_addr[3]; 982f06ca4afSHartmut Brandt return (0); 983f06ca4afSHartmut Brandt } 984f06ca4afSHartmut Brandt 985f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER: 986f06ca4afSHartmut Brandt case SNMP_SYNTAX_GAUGE: 987f06ca4afSHartmut Brandt case SNMP_SYNTAX_TIMETICKS: 988f06ca4afSHartmut Brandt { 989f06ca4afSHartmut Brandt u_int64_t sub; 990f06ca4afSHartmut Brandt 991f06ca4afSHartmut Brandt sub = strtoull(str, &end, 0); 992f06ca4afSHartmut Brandt if (*end != '\0' || sub > 0xffffffff) 993f06ca4afSHartmut Brandt return (-1); 994f06ca4afSHartmut Brandt v->uint32 = (u_int32_t)sub; 995f06ca4afSHartmut Brandt return (0); 996f06ca4afSHartmut Brandt } 997f06ca4afSHartmut Brandt 998f06ca4afSHartmut Brandt case SNMP_SYNTAX_COUNTER64: 999f06ca4afSHartmut Brandt v->counter64 = strtoull(str, &end, 0); 1000f06ca4afSHartmut Brandt if (*end != '\0') 1001f06ca4afSHartmut Brandt return (-1); 1002f06ca4afSHartmut Brandt return (0); 1003f06ca4afSHartmut Brandt } 1004f06ca4afSHartmut Brandt abort(); 1005f06ca4afSHartmut Brandt } 1006f06ca4afSHartmut Brandt 1007f06ca4afSHartmut Brandt static void 1008f06ca4afSHartmut Brandt snmp_error_func(const char *fmt, ...) 1009f06ca4afSHartmut Brandt { 1010f06ca4afSHartmut Brandt va_list ap; 1011f06ca4afSHartmut Brandt 1012f06ca4afSHartmut Brandt va_start(ap, fmt); 1013f06ca4afSHartmut Brandt fprintf(stderr, "SNMP: "); 1014f06ca4afSHartmut Brandt vfprintf(stderr, fmt, ap); 1015f06ca4afSHartmut Brandt fprintf(stderr, "\n"); 1016f06ca4afSHartmut Brandt va_end(ap); 1017f06ca4afSHartmut Brandt } 1018f06ca4afSHartmut Brandt 1019f06ca4afSHartmut Brandt static void 1020f06ca4afSHartmut Brandt snmp_printf_func(const char *fmt, ...) 1021f06ca4afSHartmut Brandt { 1022f06ca4afSHartmut Brandt va_list ap; 1023f06ca4afSHartmut Brandt 1024f06ca4afSHartmut Brandt va_start(ap, fmt); 1025f06ca4afSHartmut Brandt vfprintf(stderr, fmt, ap); 1026f06ca4afSHartmut Brandt va_end(ap); 1027f06ca4afSHartmut Brandt } 1028