diff options
Diffstat (limited to 'daemon/bsnmp/snmp.c')
-rw-r--r-- | daemon/bsnmp/snmp.c | 1081 |
1 files changed, 0 insertions, 1081 deletions
diff --git a/daemon/bsnmp/snmp.c b/daemon/bsnmp/snmp.c deleted file mode 100644 index f758262..0000000 --- a/daemon/bsnmp/snmp.c +++ /dev/null @@ -1,1081 +0,0 @@ -/* - * Copyright (c) 2001-2003 - * Fraunhofer Institute for Open Communication Systems (FhG Fokus). - * All rights reserved. - * - * Author: Harti Brandt <harti@freebsd.org> - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``AS IS'' AND - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL AUTHOR OR CONTRIBUTORS BE LIABLE - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF - * SUCH DAMAGE. - * - * $Begemot: bsnmp/lib/snmp.c,v 1.38 2004/08/06 08:46:53 brandt Exp $ - * - * SNMP - */ -#include <sys/types.h> -#include <sys/socket.h> -#include <stdio.h> -#include <stdlib.h> -#include <stddef.h> -#include <stdarg.h> -#include <stdint.h> -#include <string.h> -#include <ctype.h> -#include <netdb.h> -#include <errno.h> - -#include "asn1.h" -#include "snmp.h" -#include "snmppriv.h" - -static void snmp_error_func(const char *, ...); -static void snmp_printf_func(const char *, ...); - -void (*snmp_error)(const char *, ...) = snmp_error_func; -void (*snmp_printf)(const char *, ...) = snmp_printf_func; - -/* - * Get the next variable binding from the list. - * ASN errors on the sequence or the OID are always fatal. - */ -static enum asn_err -get_var_binding(struct asn_buf *b, struct snmp_value *binding) -{ - u_char type; - asn_len_t len, trailer; - enum asn_err err; - - if (asn_get_sequence(b, &len) != ASN_ERR_OK) { - snmp_error("cannot parse varbind header"); - return (ASN_ERR_FAILED); - } - - /* temporary truncate the length so that the parser does not - * eat up bytes behind the sequence in the case the encoding is - * wrong of inner elements. */ - trailer = b->asn_len - len; - b->asn_len = len; - - if (asn_get_objid(b, &binding->var) != ASN_ERR_OK) { - snmp_error("cannot parse binding objid"); - return (ASN_ERR_FAILED); - } - if (asn_get_header(b, &type, &len) != ASN_ERR_OK) { - snmp_error("cannot parse binding value header"); - return (ASN_ERR_FAILED); - } - - switch (type) { - - case ASN_TYPE_NULL: - binding->syntax = SNMP_SYNTAX_NULL; - err = asn_get_null_raw(b, len); - break; - - case ASN_TYPE_INTEGER: - binding->syntax = SNMP_SYNTAX_INTEGER; - err = asn_get_integer_raw(b, len, &binding->v.integer); - break; - - case ASN_TYPE_OCTETSTRING: - binding->syntax = SNMP_SYNTAX_OCTETSTRING; - binding->v.octetstring.octets = malloc(len); - if (binding->v.octetstring.octets == NULL) { - snmp_error("%s", strerror(errno)); - return (ASN_ERR_FAILED); - } - binding->v.octetstring.len = len; - err = asn_get_octetstring_raw(b, len, - binding->v.octetstring.octets, - &binding->v.octetstring.len); - if (ASN_ERR_STOPPED(err)) { - free(binding->v.octetstring.octets); - binding->v.octetstring.octets = NULL; - } - break; - - case ASN_TYPE_OBJID: - binding->syntax = SNMP_SYNTAX_OID; - err = asn_get_objid_raw(b, len, &binding->v.oid); - break; - - case ASN_CLASS_APPLICATION|ASN_APP_IPADDRESS: - binding->syntax = SNMP_SYNTAX_IPADDRESS; - err = asn_get_ipaddress_raw(b, len, binding->v.ipaddress); - break; - - case ASN_CLASS_APPLICATION|ASN_APP_TIMETICKS: - binding->syntax = SNMP_SYNTAX_TIMETICKS; - err = asn_get_uint32_raw(b, len, &binding->v.uint32); - break; - - case ASN_CLASS_APPLICATION|ASN_APP_COUNTER: - binding->syntax = SNMP_SYNTAX_COUNTER; - err = asn_get_uint32_raw(b, len, &binding->v.uint32); - break; - - case ASN_CLASS_APPLICATION|ASN_APP_GAUGE: - binding->syntax = SNMP_SYNTAX_GAUGE; - err = asn_get_uint32_raw(b, len, &binding->v.uint32); - break; - - case ASN_CLASS_APPLICATION|ASN_APP_COUNTER64: - binding->syntax = SNMP_SYNTAX_COUNTER64; - err = asn_get_counter64_raw(b, len, &binding->v.counter64); - break; - - case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHOBJECT: - binding->syntax = SNMP_SYNTAX_NOSUCHOBJECT; - err = asn_get_null_raw(b, len); - break; - - case ASN_CLASS_CONTEXT | ASN_EXCEPT_NOSUCHINSTANCE: - binding->syntax = SNMP_SYNTAX_NOSUCHINSTANCE; - err = asn_get_null_raw(b, len); - break; - - case ASN_CLASS_CONTEXT | ASN_EXCEPT_ENDOFMIBVIEW: - binding->syntax = SNMP_SYNTAX_ENDOFMIBVIEW; - err = asn_get_null_raw(b, len); - break; - - default: - if ((err = asn_skip(b, len)) == ASN_ERR_OK) - err = ASN_ERR_TAG; - snmp_error("bad binding value type 0x%x", type); - break; - } - - if (ASN_ERR_STOPPED(err)) { - snmp_error("cannot parse binding value"); - return (err); - } - - if (b->asn_len != 0) - snmp_error("ignoring junk at end of binding"); - - b->asn_len = trailer; - - return (err); -} - -/* - * Parse the different PDUs contents. Any ASN error in the outer components - * are fatal. Only errors in variable values may be tolerated. If all - * components can be parsed it returns either ASN_ERR_OK or the first - * error that was found. - */ -enum asn_err -snmp_parse_pdus_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) -{ - if (pdu->type == SNMP_PDU_TRAP) { - if (asn_get_objid(b, &pdu->enterprise) != ASN_ERR_OK) { - snmp_error("cannot parse trap enterprise"); - return (ASN_ERR_FAILED); - } - if (asn_get_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK) { - snmp_error("cannot parse trap agent address"); - return (ASN_ERR_FAILED); - } - if (asn_get_integer(b, &pdu->generic_trap) != ASN_ERR_OK) { - snmp_error("cannot parse 'generic-trap'"); - return (ASN_ERR_FAILED); - } - if (asn_get_integer(b, &pdu->specific_trap) != ASN_ERR_OK) { - snmp_error("cannot parse 'specific-trap'"); - return (ASN_ERR_FAILED); - } - if (asn_get_timeticks(b, &pdu->time_stamp) != ASN_ERR_OK) { - snmp_error("cannot parse trap 'time-stamp'"); - return (ASN_ERR_FAILED); - } - } else { - if (asn_get_integer(b, &pdu->request_id) != ASN_ERR_OK) { - snmp_error("cannot parse 'request-id'"); - return (ASN_ERR_FAILED); - } - if (asn_get_integer(b, &pdu->error_status) != ASN_ERR_OK) { - snmp_error("cannot parse 'error_status'"); - return (ASN_ERR_FAILED); - } - if (asn_get_integer(b, &pdu->error_index) != ASN_ERR_OK) { - snmp_error("cannot parse 'error_index'"); - return (ASN_ERR_FAILED); - } - } - - if (asn_get_sequence(b, lenp) != ASN_ERR_OK) { - snmp_error("cannot get varlist header"); - return (ASN_ERR_FAILED); - } - - return (ASN_ERR_OK); -} - -static enum asn_err -parse_pdus(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) -{ - asn_len_t len, trailer; - struct snmp_value *v; - enum asn_err err, err1; - - err = snmp_parse_pdus_hdr(b, pdu, &len); - if (ASN_ERR_STOPPED(err)) - return (err); - - trailer = b->asn_len - len; - - v = pdu->bindings; - err = ASN_ERR_OK; - while (b->asn_len != 0) { - if (pdu->nbindings == SNMP_MAX_BINDINGS) { - snmp_error("too many bindings (> %u) in PDU", - SNMP_MAX_BINDINGS); - return (ASN_ERR_FAILED); - } - err1 = get_var_binding(b, v); - if (ASN_ERR_STOPPED(err1)) - return (ASN_ERR_FAILED); - if (err1 != ASN_ERR_OK && err == ASN_ERR_OK) { - err = err1; - *ip = pdu->nbindings + 1; - } - pdu->nbindings++; - v++; - } - - b->asn_len = trailer; - - return (err); -} - -/* - * Parse the outer SEQUENCE value. ASN_ERR_TAG means 'bad version'. - */ -enum asn_err -snmp_parse_message_hdr(struct asn_buf *b, struct snmp_pdu *pdu, asn_len_t *lenp) -{ - int32_t version; - u_char type; - u_int comm_len; - - if (asn_get_integer(b, &version) != ASN_ERR_OK) { - snmp_error("cannot decode version"); - return (ASN_ERR_FAILED); - } - - if (version == 0) { - pdu->version = SNMP_V1; - } else if (version == 1) { - pdu->version = SNMP_V2c; - } else { - pdu->version = SNMP_Verr; - snmp_error("unsupported SNMP version"); - return (ASN_ERR_TAG); - } - - comm_len = SNMP_COMMUNITY_MAXLEN; - if (asn_get_octetstring(b, (u_char *)pdu->community, - &comm_len) != ASN_ERR_OK) { - snmp_error("cannot decode community"); - return (ASN_ERR_FAILED); - } - pdu->community[comm_len] = '\0'; - - if (asn_get_header(b, &type, lenp) != ASN_ERR_OK) { - snmp_error("cannot get pdu header"); - return (ASN_ERR_FAILED); - } - if ((type & ~ASN_TYPE_MASK) != - (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { - snmp_error("bad pdu header tag"); - return (ASN_ERR_FAILED); - } - pdu->type = type & ASN_TYPE_MASK; - - switch (pdu->type) { - - case SNMP_PDU_GET: - case SNMP_PDU_GETNEXT: - case SNMP_PDU_RESPONSE: - case SNMP_PDU_SET: - break; - - case SNMP_PDU_TRAP: - if (pdu->version != SNMP_V1) { - snmp_error("bad pdu type %u", pdu->type); - return (ASN_ERR_FAILED); - } - break; - - case SNMP_PDU_GETBULK: - case SNMP_PDU_INFORM: - case SNMP_PDU_TRAP2: - case SNMP_PDU_REPORT: - if (pdu->version == SNMP_V1) { - snmp_error("bad pdu type %u", pdu->type); - return (ASN_ERR_FAILED); - } - break; - - default: - snmp_error("bad pdu type %u", pdu->type); - return (ASN_ERR_FAILED); - } - - - if (*lenp > b->asn_len) { - snmp_error("pdu length too long"); - return (ASN_ERR_FAILED); - } - - return (ASN_ERR_OK); -} - -static enum asn_err -parse_message(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) -{ - enum asn_err err; - asn_len_t len, trailer; - - err = snmp_parse_message_hdr(b, pdu, &len); - if (ASN_ERR_STOPPED(err)) - return (err); - - trailer = b->asn_len - len; - b->asn_len = len; - - err = parse_pdus(b, pdu, ip); - if (ASN_ERR_STOPPED(err)) - return (ASN_ERR_FAILED); - - if (b->asn_len != 0) - snmp_error("ignoring trailing junk after pdu"); - - b->asn_len = trailer; - - return (err); -} - -/* - * Decode the PDU except for the variable bindings itself. - * If decoding fails because of a bad binding, but the rest can be - * decoded, ip points to the index of the failed variable (errors - * OORANGE, BADLEN or BADVERS). - */ -enum snmp_code -snmp_pdu_decode(struct asn_buf *b, struct snmp_pdu *pdu, int32_t *ip) -{ - asn_len_t len; - - memset(pdu, 0, sizeof(*pdu)); - - if (asn_get_sequence(b, &len) != ASN_ERR_OK) { - snmp_error("cannot decode pdu header"); - return (SNMP_CODE_FAILED); - } - if (b->asn_len < len) { - snmp_error("outer sequence value too short"); - return (SNMP_CODE_FAILED); - } - if (b->asn_len != len) { - snmp_error("ignoring trailing junk in message"); - b->asn_len = len; - } - - switch (parse_message(b, pdu, ip)) { - - case ASN_ERR_OK: - return (SNMP_CODE_OK); - - case ASN_ERR_FAILED: - case ASN_ERR_EOBUF: - snmp_pdu_free(pdu); - return (SNMP_CODE_FAILED); - - case ASN_ERR_BADLEN: - return (SNMP_CODE_BADLEN); - - case ASN_ERR_RANGE: - return (SNMP_CODE_OORANGE); - - case ASN_ERR_TAG: - if (pdu->version == SNMP_Verr) - return (SNMP_CODE_BADVERS); - else - return (SNMP_CODE_BADENC); - } - - return (SNMP_CODE_OK); -} - -/* - * Check whether what we have is the complete PDU by snooping at the - * enclosing structure header. This returns: - * -1 if there are ASN.1 errors - * 0 if we need more data - * > 0 the length of this PDU - */ -int -snmp_pdu_snoop(const struct asn_buf *b0) -{ - u_int length; - asn_len_t len; - struct asn_buf b = *b0; - - /* <0x10|0x20> <len> <data...> */ - - if (b.asn_len == 0) - return (0); - if (b.asn_cptr[0] != (ASN_TYPE_SEQUENCE | ASN_TYPE_CONSTRUCTED)) { - asn_error(&b, "bad sequence type %u", b.asn_cptr[0]); - return (-1); - } - b.asn_len--; - b.asn_cptr++; - - if (b.asn_len == 0) - return (0); - - if (*b.asn_cptr & 0x80) { - /* long length */ - length = *b.asn_cptr++ & 0x7f; - b.asn_len--; - if (length == 0) { - asn_error(&b, "indefinite length not supported"); - return (-1); - } - if (length > ASN_MAXLENLEN) { - asn_error(&b, "long length too long (%u)", length); - return (-1); - } - if (length > b.asn_len) - return (0); - len = 0; - while (length--) { - len = (len << 8) | *b.asn_cptr++; - b.asn_len--; - } - } else { - len = *b.asn_cptr++; - b.asn_len--; - } - - if (len > b.asn_len) - return (0); - - return (len + b.asn_cptr - b0->asn_cptr); -} - -/* - * Encode the SNMP PDU without the variable bindings field. - * We do this the rather uneffective way by - * moving things around and assuming that the length field will never - * use more than 2 bytes. - * We need a number of pointers to apply the fixes afterwards. - */ -enum snmp_code -snmp_pdu_encode_header(struct asn_buf *b, struct snmp_pdu *pdu) -{ - enum asn_err err; - - if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), - &pdu->outer_ptr) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - if (pdu->version == SNMP_V1) - err = asn_put_integer(b, 0); - else if (pdu->version == SNMP_V2c) - err = asn_put_integer(b, 1); - else - return (SNMP_CODE_BADVERS); - if (err != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - if (asn_put_octetstring(b, (u_char *)pdu->community, - strlen(pdu->community)) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - if (asn_put_temp_header(b, (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT | - pdu->type), &pdu->pdu_ptr) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - if (pdu->type == SNMP_PDU_TRAP) { - if (pdu->version != SNMP_V1 || - asn_put_objid(b, &pdu->enterprise) != ASN_ERR_OK || - asn_put_ipaddress(b, pdu->agent_addr) != ASN_ERR_OK || - asn_put_integer(b, pdu->generic_trap) != ASN_ERR_OK || - asn_put_integer(b, pdu->specific_trap) != ASN_ERR_OK || - asn_put_timeticks(b, pdu->time_stamp) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - } else { - if (pdu->version == SNMP_V1 && (pdu->type == SNMP_PDU_GETBULK || - pdu->type == SNMP_PDU_INFORM || - pdu->type == SNMP_PDU_TRAP2 || - pdu->type == SNMP_PDU_REPORT)) - return (SNMP_CODE_FAILED); - - if (asn_put_integer(b, pdu->request_id) != ASN_ERR_OK || - asn_put_integer(b, pdu->error_status) != ASN_ERR_OK || - asn_put_integer(b, pdu->error_index) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - } - - if (asn_put_temp_header(b, (ASN_TYPE_SEQUENCE|ASN_TYPE_CONSTRUCTED), - &pdu->vars_ptr) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - return (SNMP_CODE_OK); -} - -enum snmp_code -snmp_fix_encoding(struct asn_buf *b, const struct snmp_pdu *pdu) -{ - if (asn_commit_header(b, pdu->vars_ptr) != ASN_ERR_OK || - asn_commit_header(b, pdu->pdu_ptr) != ASN_ERR_OK || - asn_commit_header(b, pdu->outer_ptr) != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - return (SNMP_CODE_OK); -} - -/* - * Encode a binding. Caller must ensure, that the syntax is ok for that version. - * Be sure not to cobber b, when something fails. - */ -enum asn_err -snmp_binding_encode(struct asn_buf *b, const struct snmp_value *binding) -{ - u_char *ptr; - enum asn_err err; - struct asn_buf save = *b; - - if ((err = asn_put_temp_header(b, (ASN_TYPE_SEQUENCE | - ASN_TYPE_CONSTRUCTED), &ptr)) != ASN_ERR_OK) { - *b = save; - return (err); - } - - if ((err = asn_put_objid(b, &binding->var)) != ASN_ERR_OK) { - *b = save; - return (err); - } - - switch (binding->syntax) { - - case SNMP_SYNTAX_NULL: - err = asn_put_null(b); - break; - - case SNMP_SYNTAX_INTEGER: - err = asn_put_integer(b, binding->v.integer); - break; - - case SNMP_SYNTAX_OCTETSTRING: - err = asn_put_octetstring(b, binding->v.octetstring.octets, - binding->v.octetstring.len); - break; - - case SNMP_SYNTAX_OID: - err = asn_put_objid(b, &binding->v.oid); - break; - - case SNMP_SYNTAX_IPADDRESS: - err = asn_put_ipaddress(b, binding->v.ipaddress); - break; - - case SNMP_SYNTAX_TIMETICKS: - err = asn_put_uint32(b, ASN_APP_TIMETICKS, binding->v.uint32); - break; - - case SNMP_SYNTAX_COUNTER: - err = asn_put_uint32(b, ASN_APP_COUNTER, binding->v.uint32); - break; - - case SNMP_SYNTAX_GAUGE: - err = asn_put_uint32(b, ASN_APP_GAUGE, binding->v.uint32); - break; - - case SNMP_SYNTAX_COUNTER64: - err = asn_put_counter64(b, binding->v.counter64); - break; - - case SNMP_SYNTAX_NOSUCHOBJECT: - err = asn_put_exception(b, ASN_EXCEPT_NOSUCHOBJECT); - break; - - case SNMP_SYNTAX_NOSUCHINSTANCE: - err = asn_put_exception(b, ASN_EXCEPT_NOSUCHINSTANCE); - break; - - case SNMP_SYNTAX_ENDOFMIBVIEW: - err = asn_put_exception(b, ASN_EXCEPT_ENDOFMIBVIEW); - break; - } - - if (err != ASN_ERR_OK) { - *b = save; - return (err); - } - - err = asn_commit_header(b, ptr); - if (err != ASN_ERR_OK) { - *b = save; - return (err); - } - - return (ASN_ERR_OK); -} - -/* - * Encode an PDU. - */ -enum snmp_code -snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) -{ - u_int idx; - enum snmp_code err; - - if ((err = snmp_pdu_encode_header(resp_b, pdu)) != SNMP_CODE_OK) - return (err); - for (idx = 0; idx < pdu->nbindings; idx++) - if ((err = snmp_binding_encode(resp_b, &pdu->bindings[idx])) - != ASN_ERR_OK) - return (SNMP_CODE_FAILED); - - return (snmp_fix_encoding(resp_b, pdu)); -} - -static void -dump_binding(const struct snmp_value *b) -{ - u_int i; - char buf[ASN_OIDSTRLEN]; - - snmp_printf("%s=", asn_oid2str_r(&b->var, buf)); - switch (b->syntax) { - - case SNMP_SYNTAX_NULL: - snmp_printf("NULL"); - break; - - case SNMP_SYNTAX_INTEGER: - snmp_printf("INTEGER %d", b->v.integer); - break; - - case SNMP_SYNTAX_OCTETSTRING: - snmp_printf("OCTET STRING %lu:", b->v.octetstring.len); - for (i = 0; i < b->v.octetstring.len; i++) - snmp_printf(" %02x", b->v.octetstring.octets[i]); - break; - - case SNMP_SYNTAX_OID: - snmp_printf("OID %s", asn_oid2str_r(&b->v.oid, buf)); - break; - - case SNMP_SYNTAX_IPADDRESS: - snmp_printf("IPADDRESS %u.%u.%u.%u", b->v.ipaddress[0], - b->v.ipaddress[1], b->v.ipaddress[2], b->v.ipaddress[3]); - break; - - case SNMP_SYNTAX_COUNTER: - snmp_printf("COUNTER %u", b->v.uint32); - break; - - case SNMP_SYNTAX_GAUGE: - snmp_printf("GAUGE %u", b->v.uint32); - break; - - case SNMP_SYNTAX_TIMETICKS: - snmp_printf("TIMETICKS %u", b->v.uint32); - break; - - case SNMP_SYNTAX_COUNTER64: - snmp_printf("COUNTER64 %lld", b->v.counter64); - break; - - case SNMP_SYNTAX_NOSUCHOBJECT: - snmp_printf("NoSuchObject"); - break; - - case SNMP_SYNTAX_NOSUCHINSTANCE: - snmp_printf("NoSuchInstance"); - break; - - case SNMP_SYNTAX_ENDOFMIBVIEW: - snmp_printf("EndOfMibView"); - break; - - default: - snmp_printf("UNKNOWN SYNTAX %u", b->syntax); - break; - } -} - -static __inline void -dump_bindings(const struct snmp_pdu *pdu) -{ - u_int i; - - for (i = 0; i < pdu->nbindings; i++) { - snmp_printf(" [%u]: ", i); - dump_binding(&pdu->bindings[i]); - snmp_printf("\n"); - } -} - -static __inline void -dump_notrap(const struct snmp_pdu *pdu) -{ - snmp_printf(" request_id=%d", pdu->request_id); - snmp_printf(" error_status=%d", pdu->error_status); - snmp_printf(" error_index=%d\n", pdu->error_index); - dump_bindings(pdu); -} - -void -snmp_pdu_dump(const struct snmp_pdu *pdu) -{ - char buf[ASN_OIDSTRLEN]; - const char *vers; - static const char *types[] = { - [SNMP_PDU_GET] = "GET", - [SNMP_PDU_GETNEXT] = "GETNEXT", - [SNMP_PDU_RESPONSE] = "RESPONSE", - [SNMP_PDU_SET] = "SET", - [SNMP_PDU_TRAP] = "TRAPv1", - [SNMP_PDU_GETBULK] = "GETBULK", - [SNMP_PDU_INFORM] = "INFORM", - [SNMP_PDU_TRAP2] = "TRAPv2", - [SNMP_PDU_REPORT] = "REPORT", - }; - - if (pdu->version == SNMP_V1) - vers = "SNMPv1"; - else if (pdu->version == SNMP_V2c) - vers = "SNMPv2c"; - else - vers = "v?"; - - switch (pdu->type) { - case SNMP_PDU_TRAP: - snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); - snmp_printf(" enterprise=%s", asn_oid2str_r(&pdu->enterprise, buf)); - snmp_printf(" agent_addr=%u.%u.%u.%u", pdu->agent_addr[0], - pdu->agent_addr[1], pdu->agent_addr[2], pdu->agent_addr[3]); - snmp_printf(" generic_trap=%d", pdu->generic_trap); - snmp_printf(" specific_trap=%d", pdu->specific_trap); - snmp_printf(" time-stamp=%u\n", pdu->time_stamp); - dump_bindings(pdu); - break; - - case SNMP_PDU_GET: - case SNMP_PDU_GETNEXT: - case SNMP_PDU_RESPONSE: - case SNMP_PDU_SET: - case SNMP_PDU_GETBULK: - case SNMP_PDU_INFORM: - case SNMP_PDU_TRAP2: - case SNMP_PDU_REPORT: - snmp_printf("%s %s '%s'", types[pdu->type], vers, pdu->community); - dump_notrap(pdu); - break; - - default: - snmp_printf("bad pdu type %u\n", pdu->type); - break; - } -} - -void -snmp_value_free(struct snmp_value *value) -{ - if (value->syntax == SNMP_SYNTAX_OCTETSTRING) - free(value->v.octetstring.octets); - value->syntax = SNMP_SYNTAX_NULL; -} - -int -snmp_value_copy(struct snmp_value *to, const struct snmp_value *from) -{ - to->var = from->var; - to->syntax = from->syntax; - - if (from->syntax == SNMP_SYNTAX_OCTETSTRING) { - if ((to->v.octetstring.len = from->v.octetstring.len) == 0) - to->v.octetstring.octets = NULL; - else { - to->v.octetstring.octets = malloc(to->v.octetstring.len); - if (to->v.octetstring.octets == NULL) - return (-1); - (void)memcpy(to->v.octetstring.octets, - from->v.octetstring.octets, to->v.octetstring.len); - } - } else - to->v = from->v; - return (0); -} - -void -snmp_pdu_free(struct snmp_pdu *pdu) -{ - u_int i; - - for (i = 0; i < pdu->nbindings; i++) - snmp_value_free(&pdu->bindings[i]); -} - -/* - * Parse an ASCII SNMP value into the binary form - */ -int -snmp_value_parse(const char *str, enum snmp_syntax syntax, union snmp_values *v) -{ - char *end; - - switch (syntax) { - - case SNMP_SYNTAX_NULL: - case SNMP_SYNTAX_NOSUCHOBJECT: - case SNMP_SYNTAX_NOSUCHINSTANCE: - case SNMP_SYNTAX_ENDOFMIBVIEW: - if (*str != '\0') - return (-1); - return (0); - - case SNMP_SYNTAX_INTEGER: - v->integer = strtoll(str, &end, 0); - if (*end != '\0') - return (-1); - return (0); - - case SNMP_SYNTAX_OCTETSTRING: - { - u_long len; /* actual length of string */ - u_long alloc; /* allocate length of string */ - u_char *octs; /* actual octets */ - u_long oct; /* actual octet */ - u_char *nocts; /* to avoid memory leak */ - u_char c; /* actual character */ - -# define STUFFC(C) \ - if (alloc == len) { \ - alloc += 100; \ - if ((nocts = realloc(octs, alloc)) == NULL) { \ - free(octs); \ - return (-1); \ - } \ - octs = nocts; \ - } \ - octs[len++] = (C); - - len = alloc = 0; - octs = NULL; - - if (*str == '"') { - str++; - while((c = *str++) != '\0') { - if (c == '"') { - if (*str != '\0') { - free(octs); - return (-1); - } - break; - } - if (c == '\\') { - switch (c = *str++) { - - case '\\': - break; - case 'a': - c = '\a'; - break; - case 'b': - c = '\b'; - break; - case 'f': - c = '\f'; - break; - case 'n': - c = '\n'; - break; - case 'r': - c = '\r'; - break; - case 't': - c = '\t'; - break; - case 'v': - c = '\v'; - break; - case 'x': - c = 0; - if (!isxdigit(*str)) - break; - if (isdigit(*str)) - c = *str++ - '0'; - else if (isupper(*str)) - c = *str++ - 'A' + 10; - else - c = *str++ - 'a' + 10; - if (!isxdigit(*str)) - break; - if (isdigit(*str)) - c += *str++ - '0'; - else if (isupper(*str)) - c += *str++ - 'A' + 10; - else - c += *str++ - 'a' + 10; - break; - case '0': case '1': case '2': - case '3': case '4': case '5': - case '6': case '7': - c = *str++ - '0'; - if (*str < '0' || *str > '7') - break; - c = *str++ - '0'; - if (*str < '0' || *str > '7') - break; - c = *str++ - '0'; - break; - default: - break; - } - } - STUFFC(c); - } - } else { - while (*str != '\0') { - oct = strtoul(str, &end, 16); - str = end; - if (oct > 0xff) { - free(octs); - return (-1); - } - STUFFC(oct); - if (*str == ':') - str++; - else if(*str != '\0') { - free(octs); - return (-1); - } - } - } - v->octetstring.octets = octs; - v->octetstring.len = len; - return (0); -# undef STUFFC - } - - case SNMP_SYNTAX_OID: - { - u_long subid; - - v->oid.len = 0; - - for (;;) { - if (v->oid.len == ASN_MAXOIDLEN) - return (-1); - subid = strtoul(str, &end, 10); - str = end; - if (subid > ASN_MAXID) - return (-1); - v->oid.subs[v->oid.len++] = (asn_subid_t)subid; - if (*str == '\0') - break; - if (*str != '.') - return (-1); - str++; - } - return (0); - } - - case SNMP_SYNTAX_IPADDRESS: - { - struct hostent *he; - u_long ip[4]; - int n; - - if (sscanf(str, "%lu.%lu.%lu.%lu%n", &ip[0], &ip[1], &ip[2], - &ip[3], &n) == 4 && (size_t)n == strlen(str) && - ip[0] <= 0xff && ip[1] <= 0xff && - ip[2] <= 0xff && ip[3] <= 0xff) { - v->ipaddress[0] = (u_char)ip[0]; - v->ipaddress[1] = (u_char)ip[1]; - v->ipaddress[2] = (u_char)ip[2]; - v->ipaddress[3] = (u_char)ip[3]; - return (0); - } - - if ((he = gethostbyname(str)) == NULL) - return (-1); - if (he->h_addrtype != AF_INET) - return (-1); - - v->ipaddress[0] = he->h_addr[0]; - v->ipaddress[1] = he->h_addr[1]; - v->ipaddress[2] = he->h_addr[2]; - v->ipaddress[3] = he->h_addr[3]; - return (0); - } - - case SNMP_SYNTAX_COUNTER: - case SNMP_SYNTAX_GAUGE: - case SNMP_SYNTAX_TIMETICKS: - { - uint64_t sub; - - sub = strtoull(str, &end, 0); - if (*end != '\0' || sub > 0xffffffff) - return (-1); - v->uint32 = (uint32_t)sub; - return (0); - } - - case SNMP_SYNTAX_COUNTER64: - v->counter64 = strtoull(str, &end, 0); - if (*end != '\0') - return (-1); - return (0); - } - abort(); -} - -static void -snmp_error_func(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - fprintf(stderr, "SNMP: "); - vfprintf(stderr, fmt, ap); - fprintf(stderr, "\n"); - va_end(ap); -} - -static void -snmp_printf_func(const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vfprintf(stderr, fmt, ap); - va_end(ap); -} |