int snmp_msg_read(pool *p, unsigned char **buf, size_t *buflen, char **community, unsigned int *community_len, long *snmp_version, struct snmp_pdu **pdu) { unsigned char asn1_type; unsigned int asn1_len; int res; res = snmp_asn1_read_header(p, buf, buflen, &asn1_type, &asn1_len, 0); if (res < 0) { return -1; } if (asn1_type != (SNMP_ASN1_TYPE_SEQUENCE|SNMP_ASN1_CONSTRUCT)) { pr_trace_msg(trace_channel, 3, "unable to read SNMP message (tag '%s')", snmp_asn1_get_tagstr(p, asn1_type)); errno = EINVAL; return -1; } res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, snmp_version, 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 17, "read SNMP message for %s", snmp_msg_get_versionstr(*snmp_version)); /* XXX Don't support SNMPv3 yet. */ if (*snmp_version != SNMP_PROTOCOL_VERSION_1 && *snmp_version != SNMP_PROTOCOL_VERSION_2) { (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "%s messages not currently supported, dropping packet", snmp_msg_get_versionstr(*snmp_version)); res = snmp_db_incr_value(p, SNMP_DB_SNMP_F_PKTS_DROPPED_TOTAL, 1); if (res < 0) { (void) pr_log_writefile(snmp_logfd, MOD_SNMP_VERSION, "error incrementing snmp.packetsDroppedTotal: %s", strerror(errno)); } errno = ENOSYS; return -1; } res = snmp_asn1_read_string(p, buf, buflen, &asn1_type, community, community_len); if (res < 0) { return -1; } /* Check that asn1_type is a UNIVERSTAL/PRIMITIVE/OCTETSTRING. */ if (!(asn1_type == (SNMP_ASN1_CLASS_UNIVERSAL|SNMP_ASN1_PRIMITIVE|SNMP_ASN1_TYPE_OCTETSTRING))) { pr_trace_msg(trace_channel, 3, "unable to read OCTET_STRING (received type '%s')", snmp_asn1_get_tagstr(p, asn1_type)); errno = EINVAL; return -1; } pr_trace_msg(trace_channel, 17, "read %s message: community = '%s'", snmp_msg_get_versionstr(*snmp_version), *community); res = snmp_pdu_read(p, buf, buflen, pdu, *snmp_version); if (res < 0) { return -1; } return 0; }
int snmp_pdu_read(pool *p, unsigned char **buf, size_t *buflen, struct snmp_pdu **pdu, long snmp_version) { unsigned char asn1_type; unsigned int asn1_len; int flags, res; /* Since the "type" in this header is the PDU request type, the trace logging * of the ASN.1 type will be wrong. That being the case, simply tell the * readers to not trace log that wrong invalid ASN.1 type. Makes the * trace logging confusing and incorrect. */ flags = SNMP_ASN1_FL_NO_TRACE_TYPESTR; res = snmp_asn1_read_header(p, buf, buflen, &asn1_type, &asn1_len, flags); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read in PDU (0x%02x), length %u bytes", asn1_type, asn1_len); *pdu = snmp_pdu_create(p, asn1_type); switch (asn1_type) { case SNMP_PDU_RESPONSE: case SNMP_PDU_TRAP_V1: case SNMP_PDU_TRAP_V2: case SNMP_PDU_INFORM: case SNMP_PDU_REPORT: pr_trace_msg(trace_channel, 1, "handling '%s' PDU not currently supported", snmp_pdu_get_request_type_desc((*pdu)->request_type)); errno = ENOSYS; return -1; case SNMP_PDU_GETBULK: /* Request ID */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->request_id), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU request ID: %ld", (*pdu)->request_id); /* Non-repeaters */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->non_repeaters), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU non-repeaters: %ld", (*pdu)->non_repeaters); /* As per RFC1905, if non_repeaters is negative, it is set to zero. */ if ((*pdu)->non_repeaters < 0) { (*pdu)->non_repeaters = 0; } /* Max-repetitions */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->max_repetitions), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU max-repetitions: %ld", (*pdu)->max_repetitions); /* As per RFC1905, if max_repetitions is negative, it is set to zero. */ if ((*pdu)->max_repetitions < 0) { (*pdu)->max_repetitions = 0; } break; default: /* Request ID */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->request_id), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU request ID: %ld", (*pdu)->request_id); /* Error Status/Code */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->err_code), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU error status/code: %ld", (*pdu)->err_code); /* XXX What if err_code is non-zero? */ /* Error Index */ res = snmp_asn1_read_int(p, buf, buflen, &asn1_type, &((*pdu)->err_idx), 0); if (res < 0) { return -1; } pr_trace_msg(trace_channel, 19, "read PDU error index: %ld", (*pdu)->err_idx); /* XXX What if err_idx is non-zero? */ break; } res = snmp_smi_read_vars(p, buf, buflen, &((*pdu)->varlist), snmp_version); if (res < 0) { return -1; } (*pdu)->varlistlen = res; pr_trace_msg(trace_channel, 17, "read %d %s from %s message", res, res != 1 ? "variables" : "variable", snmp_msg_get_versionstr(snmp_version)); return 0; }