int decode_MechType(const unsigned char *p, size_t len, MechType *data, size_t *size) { size_t ret = 0; size_t l; int e; memset(data, 0, sizeof(*data)); e = decode_oid(p, len, data, &l); FORW; if(size) *size = ret; return 0; fail: free_MechType(data); return e; }
static int decode_snmp_request(request_t *request, client_t *client) { int type; size_t pos = 0, len = 0; const char *header_msg = "Unexpected SNMP header"; const char *error_msg = "Unexpected SNMP error"; const char *request_msg = "Unexpected SNMP request"; const char *varbind_msg = "Unexpected SNMP varbindings"; const char *commun_msg = "SNMP community"; const char *version_msg = "SNMP version"; /* The SNMP message is enclosed in a sequence */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_SEQUENCE || len != (client->size - pos)) { lprintf(LOG_DEBUG, "%s type %02X length %zu\n", header_msg, type, len); errno = EINVAL; return -1; } /* The first element of the sequence is the version */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_INTEGER || len != 1) { lprintf(LOG_DEBUG, "Unexpected %s type %02X length %zu\n", version_msg, type, len); errno = EINVAL; return -1; } if (decode_int(client->packet, client->size, &pos, len, &request->version) == -1) return -1; if (request->version != SNMP_VERSION_1 && request->version != SNMP_VERSION_2C) { lprintf(LOG_DEBUG, "Unsupported %s %d\n", version_msg, request->version); errno = EINVAL; return -1; } /* The second element of the sequence is the community string */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_OCTET_STRING || len >= sizeof(request->community)) { lprintf(LOG_DEBUG, "Unexpected %s type %02X length %zu\n", commun_msg, type, len); errno = EINVAL; return -1; } if (decode_str(client->packet, client->size, &pos, len, request->community, sizeof(request->community)) == -1) return -1; if (strlen(request->community) < 1) { lprintf(LOG_DEBUG, "unsupported %s '%s'\n", commun_msg, request->community); errno = EINVAL; return -1; } /* The third element of the sequence is the SNMP request */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (len != (client->size - pos)) { lprintf(LOG_DEBUG, "%s type type %02X length %zu\n", request_msg, type, len); errno = EINVAL; return -1; } request->type = type; /* The first element of the SNMP request is the request ID */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_INTEGER || len < 1) { lprintf(LOG_DEBUG, "%s id type %02X length %zu\n", request_msg, type, len); errno = EINVAL; return -1; } if (decode_int(client->packet, client->size, &pos, len, &request->id) == -1) return -1; /* The second element of the SNMP request is the error state / non repeaters (0..2147483647) */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_INTEGER || len < 1) { lprintf(LOG_DEBUG, "%s state type %02X length %zu\n", error_msg, type, len); errno = EINVAL; return -1; } if (decode_cnt(client->packet, client->size, &pos, len, &request->non_repeaters) == -1) return -1; /* The third element of the SNMP request is the error index / max repetitions (0..2147483647) */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_INTEGER || len < 1) { lprintf(LOG_DEBUG, "%s index type %02X length %zu\n", error_msg, type, len); errno = EINVAL; return -1; } if (decode_cnt(client->packet, client->size, &pos, len, &request->max_repetitions) == -1) return -1; /* The fourth element of the SNMP request are the variable bindings */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_SEQUENCE || len != (client->size - pos)) { lprintf(LOG_DEBUG, "%s type %02X length %zu\n", varbind_msg, type, len); errno = EINVAL; return -1; } /* Loop through the variable bindings */ request->oid_list_length = 0; while (pos < client->size) { /* If there is not enough room in the OID list, bail out now */ if (request->oid_list_length >= MAX_NR_OIDS) { lprintf(LOG_DEBUG, "Overflow in OID list\n"); errno = EFAULT; return -1; } /* Each variable binding is a sequence describing the variable */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_SEQUENCE || len < 1) { lprintf(LOG_DEBUG, "%s type %02X length %zu\n", varbind_msg, type, len); errno = EINVAL; return -1; } /* The first element of the variable binding is the OID */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if (type != BER_TYPE_OID || len < 1) { lprintf(LOG_DEBUG, "%s OID type %02X length %zu\n", varbind_msg, type, len); errno = EINVAL; return -1; } if (decode_oid(client->packet, client->size, &pos, len, &request->oid_list[request->oid_list_length]) == -1) return -1; /* The second element of the variable binding is the new type and value */ if (decode_len(client->packet, client->size, &pos, &type, &len) == -1) return -1; if ((type == BER_TYPE_NULL && len) || (type != BER_TYPE_NULL && !len)) { lprintf(LOG_DEBUG, "%s value type %02X length %zu\n", varbind_msg, type, len); errno = EINVAL; return -1; } if (decode_ptr(client->packet, client->size, &pos, len) == -1) return -1; /* Now the OID list has one more entry */ request->oid_list_length++; } return 0; }