From 0698344859516a56ccc2d1577416f36b429b05be Mon Sep 17 00:00:00 2001 From: Shteryana Shopova Date: Thu, 17 Oct 2013 11:49:46 +0000 Subject: [PATCH] Fix SNMP Error response PDUs and properly encode them when using v3 auth/encryption. Reported by: harti@ --- contrib/bsnmp/lib/snmp.c | 8 +++--- contrib/bsnmp/lib/snmp.h | 2 +- contrib/bsnmp/lib/snmpagent.c | 47 ++++++++++++++++++++++++++++++++--- 3 files changed, 49 insertions(+), 8 deletions(-) diff --git a/contrib/bsnmp/lib/snmp.c b/contrib/bsnmp/lib/snmp.c index 744510c6301f..6b9e3e87aaaa 100644 --- a/contrib/bsnmp/lib/snmp.c +++ b/contrib/bsnmp/lib/snmp.c @@ -288,11 +288,13 @@ parse_secparams(struct asn_buf *b, struct snmp_pdu *pdu) memset(buf, 0, 256); tb.asn_ptr = buf; tb.asn_len = 256; + u_int len; - if (asn_get_octetstring(b, buf, &tb.asn_len) != ASN_ERR_OK) { + if (asn_get_octetstring(b, buf, &len) != ASN_ERR_OK) { snmp_error("cannot parse usm header"); return (ASN_ERR_FAILED); } + tb.asn_len = len; if (asn_get_sequence(&tb, &octs_len) != ASN_ERR_OK) { snmp_error("cannot decode usm header"); @@ -864,7 +866,7 @@ snmp_fix_encoding(struct asn_buf *b, struct snmp_pdu *pdu) return (SNMP_CODE_FAILED); pdu->scoped_len = b->asn_ptr - pdu->scoped_ptr; - if ((code = snmp_pdu_fix_padd(b, pdu))!= ASN_ERR_OK) + if (snmp_pdu_fix_padd(b, pdu) != ASN_ERR_OK) return (SNMP_CODE_FAILED); if (pdu->security_model != SNMP_SECMODEL_USM) @@ -997,7 +999,7 @@ snmp_pdu_encode(struct snmp_pdu *pdu, struct asn_buf *resp_b) 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])) + if (snmp_binding_encode(resp_b, &pdu->bindings[idx]) != ASN_ERR_OK) return (SNMP_CODE_FAILED); diff --git a/contrib/bsnmp/lib/snmp.h b/contrib/bsnmp/lib/snmp.h index 631d2f2e71c8..4657336316ea 100644 --- a/contrib/bsnmp/lib/snmp.h +++ b/contrib/bsnmp/lib/snmp.h @@ -182,7 +182,7 @@ struct snmp_pdu { /* fixes for encoding */ size_t outer_len; - size_t scoped_len; + asn_len_t scoped_len; u_char *outer_ptr; u_char *digest_ptr; u_char *encrypted_ptr; diff --git a/contrib/bsnmp/lib/snmpagent.c b/contrib/bsnmp/lib/snmpagent.c index 888d622514f5..ee9242021ea9 100644 --- a/contrib/bsnmp/lib/snmpagent.c +++ b/contrib/bsnmp/lib/snmpagent.c @@ -166,7 +166,7 @@ find_subnode(const struct snmp_value *value) } static void -snmp_pdu_create_response(struct snmp_pdu *pdu, struct snmp_pdu *resp) +snmp_pdu_create_response(const struct snmp_pdu *pdu, struct snmp_pdu *resp) { memset(resp, 0, sizeof(*resp)); strcpy(resp->community, pdu->community); @@ -952,18 +952,57 @@ enum snmp_ret snmp_make_errresp(const struct snmp_pdu *pdu, struct asn_buf *pdu_b, struct asn_buf *resp_b) { + u_char type; asn_len_t len; struct snmp_pdu resp; enum asn_err err; enum snmp_code code; - memset(&resp, 0, sizeof(resp)); + snmp_pdu_create_response(pdu, &resp); + if ((code = snmp_pdu_decode_header(pdu_b, &resp)) != SNMP_CODE_OK) return (SNMP_RET_IGN); - if (pdu_b->asn_len < len) + if (pdu->version == SNMP_V3) { + if (resp.user.priv_proto != SNMP_PRIV_NOPRIV && + (asn_get_header(pdu_b, &type, &resp.scoped_len) != ASN_ERR_OK + || type != ASN_TYPE_OCTETSTRING)) { + snmp_error("cannot decode encrypted pdu"); + return (SNMP_RET_IGN); + } + + if (asn_get_sequence(pdu_b, &len) != ASN_ERR_OK) { + snmp_error("cannot decode scoped pdu header"); + return (SNMP_RET_IGN); + } + + len = SNMP_ENGINE_ID_SIZ; + if (asn_get_octetstring(pdu_b, (u_char *)resp.context_engine, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context engine"); + return (SNMP_RET_IGN); + } + resp.context_engine_len = len; + len = SNMP_CONTEXT_NAME_SIZ; + if (asn_get_octetstring(pdu_b, (u_char *)resp.context_name, + &len) != ASN_ERR_OK) { + snmp_error("cannot decode msg context name"); + return (SNMP_RET_IGN); + } + resp.context_name[len] = '\0'; + } + + + if (asn_get_header(pdu_b, &type, &len) != ASN_ERR_OK) { + snmp_error("cannot get pdu header"); return (SNMP_RET_IGN); - pdu_b->asn_len = len; + } + + if ((type & ~ASN_TYPE_MASK) != + (ASN_TYPE_CONSTRUCTED | ASN_CLASS_CONTEXT)) { + snmp_error("bad pdu header tag"); + return (SNMP_RET_IGN); + } err = snmp_parse_pdus_hdr(pdu_b, &resp, &len); if (ASN_ERR_STOPPED(err))