/* * header complex: More complex storage and data sorting for mib modules */ #include #include #if HAVE_STDLIB_H #include #endif #if HAVE_STRING_H #include #else #include #endif #include #include #include "header_complex.h" #include netsnmp_feature_child_of(header_complex_all, libnetsnmpmibs); netsnmp_feature_child_of(header_complex_free_all, header_complex_all); netsnmp_feature_child_of(header_complex_find_entry, header_complex_all); int header_complex_generate_varoid(netsnmp_variable_list * var) { int i; if (var->name == NULL) { /* * assume cached value is correct */ switch (var->type) { case ASN_INTEGER: case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: var->name_length = 1; var->name = (oid *) malloc(sizeof(oid)); if (var->name == NULL) return SNMPERR_GENERR; var->name[0] = *(var->val.integer); break; case ASN_PRIV_IMPLIED_OBJECT_ID: var->name_length = var->val_len / sizeof(oid); var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); if (var->name == NULL) return SNMPERR_GENERR; for (i = 0; i < (int) var->name_length; i++) var->name[i] = var->val.objid[i]; break; case ASN_OBJECT_ID: var->name_length = var->val_len / sizeof(oid) + 1; var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); if (var->name == NULL) return SNMPERR_GENERR; var->name[0] = var->name_length - 1; for (i = 0; i < (int) var->name_length - 1; i++) var->name[i + 1] = var->val.objid[i]; break; case ASN_PRIV_IMPLIED_OCTET_STR: var->name_length = var->val_len; var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); if (var->name == NULL) return SNMPERR_GENERR; for (i = 0; i < (int) var->val_len; i++) var->name[i] = (oid) var->val.string[i]; break; case ASN_OPAQUE: case ASN_OCTET_STR: var->name_length = var->val_len + 1; var->name = (oid *) malloc(sizeof(oid) * (var->name_length)); if (var->name == NULL) return SNMPERR_GENERR; var->name[0] = (oid) var->val_len; for (i = 0; i < (int) var->val_len; i++) var->name[i + 1] = (oid) var->val.string[i]; break; default: DEBUGMSGTL(("header_complex_generate_varoid", "invalid asn type: %d\n", var->type)); return SNMPERR_GENERR; } } if (var->name_length > MAX_OID_LEN) { DEBUGMSGTL(("header_complex_generate_varoid", "Something terribly wrong, namelen = %d\n", (int)var->name_length)); return SNMPERR_GENERR; } return SNMPERR_SUCCESS; } /* * header_complex_parse_oid(): parses an index to the usmTable to * break it down into a engineID component and a name component. * The results are stored in the data pointer, as a varbindlist: * * * returns 1 if an error is encountered, or 0 if successful. */ int header_complex_parse_oid(oid * oidIndex, size_t oidLen, netsnmp_variable_list * data) { netsnmp_variable_list *var = data; int i, itmp; while (var && oidLen > 0) { switch (var->type) { case ASN_INTEGER: case ASN_COUNTER: case ASN_GAUGE: case ASN_TIMETICKS: var->val.integer = (long *) calloc(1, sizeof(long)); if (var->val.string == NULL) return SNMPERR_GENERR; *var->val.integer = (long) *oidIndex++; var->val_len = sizeof(long); oidLen--; DEBUGMSGTL(("header_complex_parse_oid", "Parsed int(%d): %ld\n", var->type, *var->val.integer)); break; case ASN_OBJECT_ID: case ASN_PRIV_IMPLIED_OBJECT_ID: if (var->type == ASN_PRIV_IMPLIED_OBJECT_ID) { itmp = oidLen; } else { itmp = (long) *oidIndex++; oidLen--; if (itmp > (int) oidLen) return SNMPERR_GENERR; } if (itmp == 0) break; /* zero length strings shouldn't malloc */ var->val_len = itmp * sizeof(oid); var->val.objid = (oid *) calloc(1, var->val_len); if (var->val.objid == NULL) return SNMPERR_GENERR; for (i = 0; i < itmp; i++) var->val.objid[i] = (u_char) * oidIndex++; oidLen -= itmp; DEBUGMSGTL(("header_complex_parse_oid", "Parsed oid: ")); DEBUGMSGOID(("header_complex_parse_oid", var->val.objid, var->val_len / sizeof(oid))); DEBUGMSG(("header_complex_parse_oid", "\n")); break; case ASN_OPAQUE: case ASN_OCTET_STR: case ASN_PRIV_IMPLIED_OCTET_STR: if (var->type == ASN_PRIV_IMPLIED_OCTET_STR) { itmp = oidLen; } else { itmp = (long) *oidIndex++; oidLen--; if (itmp > (int) oidLen) return SNMPERR_GENERR; } if (itmp == 0) break; /* zero length strings shouldn't malloc */ /* * malloc by size+1 to allow a null to be appended. */ var->val_len = itmp; var->val.string = (u_char *) calloc(1, itmp + 1); if (var->val.string == NULL) return SNMPERR_GENERR; for (i = 0; i < itmp; i++) var->val.string[i] = (u_char) * oidIndex++; var->val.string[itmp] = '\0'; oidLen -= itmp; DEBUGMSGTL(("header_complex_parse_oid", "Parsed str(%d): %s\n", var->type, var->val.string)); break; default: DEBUGMSGTL(("header_complex_parse_oid", "invalid asn type: %d\n", var->type)); return SNMPERR_GENERR; } var = var->next_variable; } if (var != NULL || oidLen > 0) return SNMPERR_GENERR; return SNMPERR_SUCCESS; } void header_complex_generate_oid(oid * name, /* out */ size_t * length, /* out */ oid * prefix, size_t prefix_len, netsnmp_variable_list * data) { oid *oidptr; netsnmp_variable_list *var; if (prefix) { memcpy(name, prefix, prefix_len * sizeof(oid)); oidptr = (name + (prefix_len)); *length = prefix_len; } else { oidptr = name; *length = 0; } for (var = data; var != NULL; var = var->next_variable) { header_complex_generate_varoid(var); memcpy(oidptr, var->name, sizeof(oid) * var->name_length); oidptr = oidptr + var->name_length; *length += var->name_length; } DEBUGMSGTL(("header_complex_generate_oid", "generated: ")); DEBUGMSGOID(("header_complex_generate_oid", name, *length)); DEBUGMSG(("header_complex_generate_oid", "\n")); } /* * finds the data in "datalist" stored at "index" */ void * header_complex_get(struct header_complex_index *datalist, netsnmp_variable_list * index) { oid searchfor[MAX_OID_LEN]; size_t searchfor_len; header_complex_generate_oid(searchfor, /* out */ &searchfor_len, /* out */ NULL, 0, index); return header_complex_get_from_oid(datalist, searchfor, searchfor_len); } void * header_complex_get_from_oid(struct header_complex_index *datalist, oid * searchfor, size_t searchfor_len) { struct header_complex_index *nptr; for (nptr = datalist; nptr != NULL; nptr = nptr->next) { if (netsnmp_oid_equals(searchfor, searchfor_len, nptr->name, nptr->namelen) == 0) return nptr->data; } return NULL; } void * header_complex(struct header_complex_index *datalist, struct variable *vp, oid * name, size_t * length, int exact, size_t * var_len, WriteMethod ** write_method) { struct header_complex_index *nptr, *found = NULL; oid indexOid[MAX_OID_LEN]; size_t len; int result; /* * set up some nice defaults for the user */ if (write_method) *write_method = NULL; if (var_len) *var_len = sizeof(long); for (nptr = datalist; nptr != NULL && found == NULL; nptr = nptr->next) { if (vp) { memcpy(indexOid, vp->name, vp->namelen * sizeof(oid)); memcpy(indexOid + vp->namelen, nptr->name, nptr->namelen * sizeof(oid)); len = vp->namelen + nptr->namelen; } else { memcpy(indexOid, nptr->name, nptr->namelen * sizeof(oid)); len = nptr->namelen; } result = snmp_oid_compare(name, *length, indexOid, len); DEBUGMSGTL(("header_complex", "Checking: ")); DEBUGMSGOID(("header_complex", indexOid, len)); DEBUGMSG(("header_complex", "\n")); if (exact) { if (result == 0) { found = nptr; } } else { if (result == 0) { /* * found an exact match. Need the next one for !exact */ if (nptr->next) found = nptr->next; } else if (result == -1) { found = nptr; } } } if (found) { if (vp) { memcpy(name, vp->name, vp->namelen * sizeof(oid)); memcpy(name + vp->namelen, found->name, found->namelen * sizeof(oid)); *length = vp->namelen + found->namelen; } else { memcpy(name, found->name, found->namelen * sizeof(oid)); *length = found->namelen; } return found->data; } return NULL; } struct header_complex_index * header_complex_maybe_add_data(struct header_complex_index **thedata, netsnmp_variable_list * var, void *data, int dont_allow_duplicates) { oid newoid[MAX_OID_LEN]; size_t newoid_len; struct header_complex_index *ret; if (thedata == NULL || var == NULL || data == NULL) return NULL; header_complex_generate_oid(newoid, &newoid_len, NULL, 0, var); ret = header_complex_maybe_add_data_by_oid(thedata, newoid, newoid_len, data, dont_allow_duplicates); /* * free the variable list, but not the enclosed data! it's not ours! */ snmp_free_varbind(var); return (ret); } struct header_complex_index * header_complex_add_data(struct header_complex_index **thedata, netsnmp_variable_list * var, void *data) { return header_complex_maybe_add_data(thedata, var, data, 0); } struct header_complex_index * _header_complex_add_between(struct header_complex_index **thedata, struct header_complex_index *hciptrp, struct header_complex_index *hciptrn, oid * newoid, size_t newoid_len, void *data) { struct header_complex_index *ourself; /* * nptr should now point to the spot that we need to add ourselves * in front of, and pptr should be our new 'prev'. */ /* * create ourselves */ ourself = (struct header_complex_index *) SNMP_MALLOC_STRUCT(header_complex_index); if (ourself == NULL) return NULL; /* * change our pointers */ ourself->prev = hciptrp; ourself->next = hciptrn; if (ourself->next) ourself->next->prev = ourself; if (ourself->prev) ourself->prev->next = ourself; ourself->data = data; ourself->name = snmp_duplicate_objid(newoid, newoid_len); ourself->namelen = newoid_len; /* * rewind to the head of the list and return it (since the new head * could be us, we need to notify the above routine who the head now is. */ for (hciptrp = ourself; hciptrp->prev != NULL; hciptrp = hciptrp->prev); *thedata = hciptrp; DEBUGMSGTL(("header_complex_add_data", "adding something...\n")); return hciptrp; } struct header_complex_index * header_complex_maybe_add_data_by_oid(struct header_complex_index **thedata, oid * newoid, size_t newoid_len, void *data, int dont_allow_duplicates) { struct header_complex_index *hciptrn, *hciptrp; int rc; if (thedata == NULL || newoid == NULL || data == NULL) return NULL; for (hciptrn = *thedata, hciptrp = NULL; hciptrn != NULL; hciptrp = hciptrn, hciptrn = hciptrn->next) { /* * XXX: check for == and error (overlapping table entries) * 8/2005 rks Ok, I added duplicate entry check, but only log * warning and continue, because it seems that nobody * that calls this fucntion does error checking!. */ rc = snmp_oid_compare(hciptrn->name, hciptrn->namelen, newoid, newoid_len); if (rc > 0) break; else if (0 == rc) { snmp_log(LOG_WARNING, "header_complex_add_data_by_oid with " "duplicate index.\n"); if (dont_allow_duplicates) return NULL; } } return _header_complex_add_between(thedata, hciptrp, hciptrn, newoid, newoid_len, data); } struct header_complex_index * header_complex_add_data_by_oid(struct header_complex_index **thedata, oid * newoid, size_t newoid_len, void *data) { return header_complex_maybe_add_data_by_oid(thedata, newoid, newoid_len, data, 0); } /* * extracts an entry from the storage space (removing it from future * accesses) and returns the data stored there * * Modifies "thetop" pointer as needed (and if present) if were * extracting the first node. */ void * header_complex_extract_entry(struct header_complex_index **thetop, struct header_complex_index *thespot) { struct header_complex_index *hciptrp, *hciptrn; void *retdata; if (thespot == NULL) { DEBUGMSGTL(("header_complex_extract_entry", "Null pointer asked to be extracted\n")); return NULL; } retdata = thespot->data; hciptrp = thespot->prev; hciptrn = thespot->next; if (hciptrp) hciptrp->next = hciptrn; else if (thetop) *thetop = hciptrn; if (hciptrn) hciptrn->prev = hciptrp; if (thespot->name) free(thespot->name); free(thespot); return retdata; } /* * wipe out a single entry */ void header_complex_free_entry(struct header_complex_index *theentry, HeaderComplexCleaner * cleaner) { void *data; data = header_complex_extract_entry(NULL, theentry); (*cleaner) (data); } /* * completely wipe out all entries in our data store */ #ifndef NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FREE_ALL void header_complex_free_all(struct header_complex_index *thestuff, HeaderComplexCleaner * cleaner) { struct header_complex_index *hciptr, *hciptrn; for (hciptr = thestuff; hciptr != NULL; hciptr = hciptrn) { hciptrn = hciptr->next; /* need to extract this before deleting it */ header_complex_free_entry(hciptr, cleaner); } } #endif /* NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FREE_ALL */ #ifndef NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FIND_ENTRY struct header_complex_index * header_complex_find_entry(struct header_complex_index *thestuff, void *theentry) { struct header_complex_index *hciptr; for (hciptr = thestuff; hciptr != NULL && hciptr->data != theentry; hciptr = hciptr->next); return hciptr; } #endif /* NETSNMP_FEATURE_REMOVE_HEADER_COMPLEX_FIND_ENTRY */ #ifdef TESTING void header_complex_dump(struct header_complex_index *thestuff) { struct header_complex_index *hciptr; oid oidsave[MAX_OID_LEN]; size_t len; for (hciptr = thestuff; hciptr != NULL; hciptr = hciptr->next) { DEBUGMSGTL(("header_complex_dump", "var: ")); header_complex_generate_oid(oidsave, &len, NULL, 0, hciptr->); DEBUGMSGOID(("header_complex_dump", oidsave, len)); DEBUGMSG(("header_complex_dump", "\n")); } } main() { oid oidsave[MAX_OID_LEN]; int len = MAX_OID_LEN, len2; netsnmp_variable_list *vars; long ltmp = 4242, ltmp2 = 88, ltmp3 = 1, ltmp4 = 4200; oid ourprefix[] = { 1, 2, 3, 4 }; oid testparse[] = { 4, 116, 101, 115, 116, 4200 }; int ret; char *string = "wes", *string2 = "dawn", *string3 = "test"; struct header_complex_index *thestorage = NULL; debug_register_tokens("header_complex"); snmp_set_do_debugging(1); vars = NULL; len2 = sizeof(ltmp); snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp, len2); header_complex_add_data(&thestorage, vars, ourprefix); vars = NULL; len2 = strlen(string); snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string, len2); header_complex_add_data(&thestorage, vars, ourprefix); vars = NULL; len2 = sizeof(ltmp2); snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp2, len2); header_complex_add_data(&thestorage, vars, ourprefix); vars = NULL; len2 = strlen(string2); snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string2, len2); header_complex_add_data(&thestorage, vars, ourprefix); vars = NULL; len2 = sizeof(ltmp3); snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp3, len2); header_complex_add_data(&thestorage, vars, ourprefix); vars = NULL; len2 = strlen(string3); snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, string3, len2); len2 = sizeof(ltmp4); snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, (char *) <mp4, len2); header_complex_add_data(&thestorage, vars, ourprefix); header_complex_dump(thestorage); vars = NULL; snmp_varlist_add_variable(&vars, NULL, 0, ASN_OCTET_STR, NULL, 0); snmp_varlist_add_variable(&vars, NULL, 0, ASN_INTEGER, NULL, 0); ret = header_complex_parse_oid(testparse, sizeof(testparse) / sizeof(oid), vars); DEBUGMSGTL(("header_complex_test", "parse returned %d...\n", ret)); } #endif