/** create a new row in the table */ static void register_foreach(const struct sysORTable* data, void* dummy) { sysORTable_entry *entry; sysORLastChange = data->OR_uptime; entry = SNMP_MALLOC_TYPEDEF(sysORTable_entry); if (!entry) { snmp_log(LOG_ERR, "could not allocate storage, sysORTable is inconsistent\n"); } else { const oid firstNext = sysORNextIndex; netsnmp_iterator* it = CONTAINER_ITERATOR(table); do { const sysORTable_entry* value; const oid cur = sysORNextIndex; if (sysORNextIndex == SNMP_MIN(MAX_SUBID, 2147483647UL)) sysORNextIndex = 1; else ++sysORNextIndex; for (value = (sysORTable_entry*)it->curr(it); value && value->sysORIndex < cur; value = (sysORTable_entry*)ITERATOR_NEXT(it)) { } if (value && value->sysORIndex == cur) { if (sysORNextIndex < cur) it->reset(it); } else { entry->sysORIndex = cur; break; } } while (firstNext != sysORNextIndex); ITERATOR_RELEASE(it); if(firstNext == sysORNextIndex) { snmp_log(LOG_ERR, "Failed to locate a free index in sysORTable\n"); free(entry); } else { entry->data = data; entry->oid_index.len = 1; entry->oid_index.oids = &entry->sysORIndex; CONTAINER_INSERT(table, entry); } } }
netsnmp_variable_list * collect(netsnmp_session * ss, netsnmp_pdu *pdu, oid * base, size_t base_length) { netsnmp_pdu *response; int running = 1; netsnmp_variable_list *saved = NULL, **vlpp = &saved; int status; while (running) { /* * gotta catch em all, gotta catch em all! */ status = snmp_synch_response(ss, pdu, &response); if (status != STAT_SUCCESS || !response) { snmp_sess_perror("snmpdf", ss); exit(1); } if (response->errstat != SNMP_ERR_NOERROR) { fprintf(stderr, "snmpdf: Error in packet: %s\n", snmp_errstring(response->errstat)); exit(1); } if (response && snmp_oid_compare(response->variables->name, SNMP_MIN(base_length, response->variables-> name_length), base, base_length) != 0) running = 0; else { /* * get response */ *vlpp = response->variables; (*vlpp)->next_variable = NULL; /* shouldn't be any, but just in case */ /* * create the next request */ pdu = snmp_pdu_create(SNMP_MSG_GETNEXT); snmp_add_null_var(pdu, (*vlpp)->name, (*vlpp)->name_length); /* * finish loop setup */ vlpp = &((*vlpp)->next_variable); response->variables = NULL; /* ahh, forget about it */ } snmp_free_pdu(response); } return saved; }
/** register a given data_set at a given oid (specified in the netsnmp_handler_registration pointer). The reginfo->handler->access_method *may* be null if the call doesn't ever want to be called for SNMP operations. */ int netsnmp_register_table_data_set(netsnmp_handler_registration *reginfo, netsnmp_table_data_set *data_set, netsnmp_table_registration_info *table_info) { int ret; if (NULL == table_info) { /* * allocate the table if one wasn't allocated */ table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info); if (table_info == NULL) return SNMP_ERR_GENERR; } if (NULL == table_info->indexes && data_set->table->indexes_template) { /* * copy the indexes in */ table_info->indexes = snmp_clone_varbind(data_set->table->indexes_template); } if ((!table_info->min_column || !table_info->max_column) && (data_set->default_row)) { /* * determine min/max columns */ unsigned int mincol = 0xffffffff, maxcol = 0; netsnmp_table_data_set_storage *row; for (row = data_set->default_row; row; row = row->next) { mincol = SNMP_MIN(mincol, row->column); maxcol = SNMP_MAX(maxcol, row->column); } if (!table_info->min_column) table_info->min_column = mincol; if (!table_info->max_column) table_info->max_column = maxcol; } netsnmp_inject_handler(reginfo, netsnmp_get_table_data_set_handler(data_set)); ret = netsnmp_register_table_data(reginfo, data_set->table, table_info); if (reginfo->handler) netsnmp_handler_owns_table_info(reginfo->handler->next); return ret; }
/*******************************************************************-o-****** * snmp_comstr_parse * * Parameters: * *data (I) Message. * *length (I/O) Bytes left in message. * *psid (O) Community string. * *slen (O) Length of community string. * *version (O) Message version. * * Returns: * Pointer to the remainder of data. * * * Parse the header of a community string-based message such as that found * in SNMPv1 and SNMPv2c. */ u_char * snmp_comstr_parse(u_char * data, size_t * length, u_char * psid, size_t * slen, long *version) { u_char type; long ver; size_t origlen = *slen; /* * Message is an ASN.1 SEQUENCE. */ data = asn_parse_sequence(data, length, &type, (ASN_SEQUENCE | ASN_CONSTRUCTOR), "auth message"); if (data == NULL) { return NULL; } /* * First field is the version. */ DEBUGDUMPHEADER("recv", "SNMP version"); data = asn_parse_int(data, length, &type, &ver, sizeof(ver)); DEBUGINDENTLESS(); *version = ver; if (data == NULL) { ERROR_MSG("bad parse of version"); return NULL; } /* * second field is the community string for SNMPv1 & SNMPv2c */ DEBUGDUMPHEADER("recv", "community string"); data = asn_parse_string(data, length, &type, psid, slen); DEBUGINDENTLESS(); if (data == NULL) { ERROR_MSG("bad parse of community"); return NULL; } psid[SNMP_MIN(*slen, origlen - 1)] = '\0'; return (u_char *) data; } /* end snmp_comstr_parse() */
_KEYTOOLS_NOT_AVAILABLE #endif /* internal or openssl */ /*******************************************************************-o-****** * encode_keychange * * Parameters: * *hashtype MIB OID for the hash transform type. * hashtype_len Length of the MIB OID hash transform type. * *oldkey Old key that is used to encodes the new key. * oldkey_len Length of oldkey in bytes. * *newkey New key that is encoded using the old key. * newkey_len Length of new key in bytes. * *kcstring Buffer to contain the KeyChange TC string. * *kcstring_len Length of kcstring buffer. * * Returns: * SNMPERR_SUCCESS Success. * SNMPERR_GENERR All errors. * * * Uses oldkey and acquired random bytes to encode newkey into kcstring * according to the rules of the KeyChange TC described in RFC 2274, Section 5. * * Upon successful return, *kcstring_len contains the length of the * encoded string. * * ASSUMES Old and new key are always equal to each other, although * this may be less than the transform type hash output * output length (eg, using KeyChange for a DESPriv key when * the user also uses SHA1Auth). This also implies that the * hash placed in the second 1/2 of the key change string * will be truncated before the XOR'ing when the hash output is * larger than that 1/2 of the key change string. * * *kcstring_len will be returned as exactly twice that same * length though the input buffer may be larger. * * XXX FIX: Does not handle varibable length keys. * XXX FIX: Does not handle keys larger than the hash algorithm used. */ int encode_keychange( oid *hashtype, u_int hashtype_len, u_char *oldkey, size_t oldkey_len, u_char *newkey, size_t newkey_len, u_char *kcstring, size_t *kcstring_len) #if defined(USE_OPENSSL) || defined(USE_INTERNAL_MD5) { int rval = SNMPERR_SUCCESS; size_t properlength; size_t nbytes = 0; u_char *tmpbuf = NULL; void *context = NULL; /* * Sanity check. */ if ( !hashtype || !oldkey || !newkey || !kcstring || !kcstring_len || (oldkey_len<=0) || (newkey_len<=0) || (*kcstring_len<=0) || (hashtype_len != USM_LENGTH_OID_TRANSFORM) ) { QUITFUN(SNMPERR_GENERR, encode_keychange_quit); } /* * Setup for the transform type. */ properlength = sc_get_properlength(hashtype, hashtype_len); if (properlength == SNMPERR_GENERR) QUITFUN(SNMPERR_GENERR, encode_keychange_quit); if ( (oldkey_len != newkey_len) || (*kcstring_len < (2*oldkey_len)) ) { QUITFUN(SNMPERR_GENERR, encode_keychange_quit); } properlength = SNMP_MIN((int)oldkey_len, properlength); /* * Use the old key and some random bytes to encode the new key * in the KeyChange TC format: * . Get random bytes (store in first half of kcstring), * . Hash (oldkey | random_bytes) (into second half of kcstring), * . XOR hash and newkey (into second half of kcstring). * * Getting the wrong number of random bytes is considered an error. */ nbytes = properlength; #if defined(SNMP_TESTING_CODE) && defined(RANDOMZEROS) memset(kcstring, 0, nbytes); DEBUGMSG(("encode_keychange", "** Using all zero bits for \"random\" delta of )" "the keychange string! **\n")); #else /* !SNMP_TESTING_CODE */ rval = sc_random(kcstring, &nbytes); QUITFUN(rval, encode_keychange_quit); if ((int)nbytes != properlength) { QUITFUN(SNMPERR_GENERR, encode_keychange_quit); } #endif /* !SNMP_TESTING_CODE */ tmpbuf = (u_char *)malloc(properlength*2); if (tmpbuf) { memcpy(tmpbuf, oldkey, properlength); memcpy(tmpbuf+properlength, kcstring, properlength); *kcstring_len -= properlength; rval = sc_hash(hashtype, hashtype_len, tmpbuf, properlength*2, kcstring+properlength, kcstring_len); QUITFUN(rval, encode_keychange_quit); *kcstring_len = (properlength*2); kcstring += properlength; nbytes = 0; while ((int)(nbytes++) < properlength) { *kcstring++ = *kcstring ^ *newkey++; } } encode_keychange_quit: if (rval != SNMPERR_SUCCESS) memset(kcstring, 0, *kcstring_len); SNMP_FREE(tmpbuf); SNMP_FREE(context); return rval; } /* end encode_keychange() */
int unregister_index(netsnmp_variable_list * varbind, int remember, netsnmp_session * ss) { struct snmp_index *idxptr, *idxptr2; struct snmp_index *prev_oid_ptr, *prev_idx_ptr; int res, res2, i; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING) if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) { return (agentx_unregister_index(ss, varbind)); } #endif /* * Look for the requested OID entry */ prev_oid_ptr = NULL; prev_idx_ptr = NULL; res = 1; res2 = 1; for (idxptr = snmp_index_head; idxptr != NULL; prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) { if ((res = snmp_oid_compare(varbind->name, varbind->name_length, idxptr->varbind->name, idxptr->varbind->name_length)) <= 0) break; } if (res != 0) return INDEX_ERR_NOT_ALLOCATED; if (varbind->type != idxptr->varbind->type) return INDEX_ERR_WRONG_TYPE; for (idxptr2 = idxptr; idxptr2 != NULL; prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) { switch (varbind->type) { case ASN_INTEGER: res2 = (*varbind->val.integer - *idxptr2->varbind->val.integer); break; case ASN_OCTET_STR: i = SNMP_MIN(varbind->val_len, idxptr2->varbind->val_len); res2 = memcmp(varbind->val.string, idxptr2->varbind->val.string, i); break; case ASN_OBJECT_ID: res2 = snmp_oid_compare(varbind->val.objid, varbind->val_len / sizeof(oid), idxptr2->varbind->val.objid, idxptr2->varbind->val_len / sizeof(oid)); break; default: return INDEX_ERR_WRONG_TYPE; /* wrong type */ } if (res2 <= 0) break; } if (res2 != 0 || (res2 == 0 && !idxptr2->allocated)) { return INDEX_ERR_NOT_ALLOCATED; } if (ss != idxptr2->session) return INDEX_ERR_WRONG_SESSION; /* * If this is a "normal" index unregistration, * mark the index entry as unused, but leave * it in situ. This allows differentiation * between ANY_INDEX and NEW_INDEX */ if (remember) { idxptr2->allocated = 0; /* Unused index */ idxptr2->session = NULL; return SNMP_ERR_NOERROR; } /* * If this is a failed attempt to register a * number of indexes, the successful ones * must be removed completely. */ if (prev_idx_ptr) { prev_idx_ptr->next_idx = idxptr2->next_idx; } else if (prev_oid_ptr) { if (idxptr2->next_idx) /* Use p_idx_ptr as a temp variable */ prev_idx_ptr = idxptr2->next_idx; else prev_idx_ptr = idxptr2->next_oid; while (prev_oid_ptr) { prev_oid_ptr->next_oid = prev_idx_ptr; prev_oid_ptr = prev_oid_ptr->next_idx; } } else { if (idxptr2->next_idx) snmp_index_head = idxptr2->next_idx; else snmp_index_head = idxptr2->next_oid; } snmp_free_var(idxptr2->varbind); free(idxptr2); return SNMP_ERR_NOERROR; }
netsnmp_variable_list * register_index(netsnmp_variable_list * varbind, int flags, netsnmp_session * ss) { netsnmp_variable_list *rv = NULL; struct snmp_index *new_index, *idxptr, *idxptr2; struct snmp_index *prev_oid_ptr, *prev_idx_ptr; int res, res2, i; DEBUGMSGTL(("register_index", "register ")); DEBUGMSGVAR(("register_index", varbind)); DEBUGMSG(("register_index", "for session %8p\n", ss)); #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING) if (netsnmp_ds_get_boolean(NETSNMP_DS_APPLICATION_ID, NETSNMP_DS_AGENT_ROLE) == SUB_AGENT) { return (agentx_register_index(ss, varbind, flags)); } #endif /* * Look for the requested OID entry */ prev_oid_ptr = NULL; prev_idx_ptr = NULL; res = 1; res2 = 1; for (idxptr = snmp_index_head; idxptr != NULL; prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) { if ((res = snmp_oid_compare(varbind->name, varbind->name_length, idxptr->varbind->name, idxptr->varbind->name_length)) <= 0) break; } /* * Found the OID - now look at the registered indices */ if (res == 0 && idxptr) { if (varbind->type != idxptr->varbind->type) return NULL; /* wrong type */ /* * If we've been asked for an arbitrary new value, * then find the end of the list. * If we've been asked for any arbitrary value, * then look for an unused entry, and use that. * If there aren't any, continue as for new. * Otherwise, locate the given value in the (sorted) * list of already allocated values */ if (flags & ALLOCATE_ANY_INDEX) { for (idxptr2 = idxptr; idxptr2 != NULL; prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) { if (flags == ALLOCATE_ANY_INDEX && !(idxptr2->allocated)) { if ((rv = snmp_clone_varbind(idxptr2->varbind)) != NULL) { idxptr2->session = ss; idxptr2->allocated = 1; } return rv; } } } else { for (idxptr2 = idxptr; idxptr2 != NULL; prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) { switch (varbind->type) { case ASN_INTEGER: res2 = (*varbind->val.integer - *idxptr2->varbind->val.integer); break; case ASN_OCTET_STR: i = SNMP_MIN(varbind->val_len, idxptr2->varbind->val_len); res2 = memcmp(varbind->val.string, idxptr2->varbind->val.string, i); break; case ASN_OBJECT_ID: res2 = snmp_oid_compare(varbind->val.objid, varbind->val_len / sizeof(oid), idxptr2->varbind->val.objid, idxptr2->varbind->val_len / sizeof(oid)); break; default: return NULL; /* wrong type */ } if (res2 <= 0) break; } if (res2 == 0) { if (idxptr2->allocated) { /* * No good: the index is in use. */ return NULL; } else { /* * Okay, it's unallocated, we can just claim ownership * here. */ if ((rv = snmp_clone_varbind(idxptr2->varbind)) != NULL) { idxptr2->session = ss; idxptr2->allocated = 1; } return rv; } } } } /* * OK - we've now located where the new entry needs to * be fitted into the index registry tree * To recap: * 'prev_oid_ptr' points to the head of the OID index * list prior to this one. If this is null, then * it means that this is the first OID in the list. * 'idxptr' points either to the head of this OID list, * or the next OID (if this is a new OID request) * These can be distinguished by the value of 'res'. * * 'prev_idx_ptr' points to the index entry that sorts * immediately prior to the requested value (if any). * If an arbitrary value is required, then this will * point to the last allocated index. * If this pointer is null, then either this is a new * OID request, or the requested value is the first * in the list. * 'idxptr2' points to the next sorted index (if any) * but is not actually needed any more. * * Clear? Good! * I hope you've been paying attention. * There'll be a test later :-) */ /* * We proceed by creating the new entry * (by copying the entry provided) */ new_index = (struct snmp_index *) calloc(1, sizeof(struct snmp_index)); if (new_index == NULL) return NULL; if (NULL == snmp_varlist_add_variable(&new_index->varbind, varbind->name, varbind->name_length, varbind->type, varbind->val.string, varbind->val_len)) { /* * if (snmp_clone_var( varbind, new_index->varbind ) != 0 ) */ free(new_index); return NULL; } new_index->session = ss; new_index->allocated = 1; if (varbind->type == ASN_OCTET_STR && flags == ALLOCATE_THIS_INDEX) new_index->varbind->val.string[new_index->varbind->val_len] = 0; /* * If we've been given a value, then we can use that, but * otherwise, we need to create a new value for this entry. * Note that ANY_INDEX and NEW_INDEX are both covered by this * test (since NEW_INDEX & ANY_INDEX = ANY_INDEX, remember?) */ if (flags & ALLOCATE_ANY_INDEX) { if (prev_idx_ptr) { if (snmp_clone_var(prev_idx_ptr->varbind, new_index->varbind) != 0) { free(new_index); return NULL; } } else new_index->varbind->val.string = new_index->varbind->buf; switch (varbind->type) { case ASN_INTEGER: if (prev_idx_ptr) { (*new_index->varbind->val.integer)++; } else *(new_index->varbind->val.integer) = 1; new_index->varbind->val_len = sizeof(long); break; case ASN_OCTET_STR: if (prev_idx_ptr) { i = new_index->varbind->val_len - 1; while (new_index->varbind->buf[i] == 'z') { new_index->varbind->buf[i] = 'a'; i--; if (i < 0) { i = new_index->varbind->val_len; new_index->varbind->buf[i] = 'a'; new_index->varbind->buf[i + 1] = 0; } } new_index->varbind->buf[i]++; } else strcpy((char *) new_index->varbind->buf, "aaaa"); new_index->varbind->val_len = strlen((char *) new_index->varbind->buf); break; case ASN_OBJECT_ID: if (prev_idx_ptr) { i = prev_idx_ptr->varbind->val_len / sizeof(oid) - 1; while (new_index->varbind->val.objid[i] == 255) { new_index->varbind->val.objid[i] = 1; i--; if (i == 0 && new_index->varbind->val.objid[0] == 2) { new_index->varbind->val.objid[0] = 1; i = new_index->varbind->val_len / sizeof(oid); new_index->varbind->val.objid[i] = 0; new_index->varbind->val_len += sizeof(oid); } } new_index->varbind->val.objid[i]++; } else { /* * If the requested OID name is small enough, * * append another OID (1) and use this as the * * default starting value for new indexes. */ if ((varbind->name_length + 1) * sizeof(oid) <= 40) { for (i = 0; i < (int) varbind->name_length; i++) new_index->varbind->val.objid[i] = varbind->name[i]; new_index->varbind->val.objid[varbind->name_length] = 1; new_index->varbind->val_len = (varbind->name_length + 1) * sizeof(oid); } else { /* * Otherwise use '.1.1.1.1...' */ i = 40 / sizeof(oid); if (i > 4) i = 4; new_index->varbind->val_len = i * (sizeof(oid)); for (i--; i >= 0; i--) new_index->varbind->val.objid[i] = 1; } } break; default: snmp_free_var(new_index->varbind); free(new_index); return NULL; /* Index type not supported */ } } /* * Try to duplicate the new varbind for return. */ if ((rv = snmp_clone_varbind(new_index->varbind)) == NULL) { snmp_free_var(new_index->varbind); free(new_index); return NULL; } /* * Right - we've set up the new entry. * All that remains is to link it into the tree. * There are a number of possible cases here, * so watch carefully. */ if (prev_idx_ptr) { new_index->next_idx = prev_idx_ptr->next_idx; new_index->next_oid = prev_idx_ptr->next_oid; prev_idx_ptr->next_idx = new_index; } else { if (res == 0 && idxptr) { new_index->next_idx = idxptr; new_index->next_oid = idxptr->next_oid; } else { new_index->next_idx = NULL; new_index->next_oid = idxptr; } if (prev_oid_ptr) { while (prev_oid_ptr) { prev_oid_ptr->next_oid = new_index; prev_oid_ptr = prev_oid_ptr->next_idx; } } else snmp_index_head = new_index; } return rv; }
int unregister_index(struct variable_list *varbind, int remember, struct snmp_session *ss) { struct snmp_index *idxptr, *idxptr2; struct snmp_index *prev_oid_ptr, *prev_idx_ptr; int res, res2, i; #if defined(USING_AGENTX_SUBAGENT_MODULE) && !defined(TESTING) if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_ROLE) == SUB_AGENT ) return( agentx_unregister_index( ss, varbind )); #endif /* Look for the requested OID entry */ prev_oid_ptr = NULL; prev_idx_ptr = NULL; res = 1; res2 = 1; for( idxptr = snmp_index_head ; idxptr != NULL; prev_oid_ptr = idxptr, idxptr = idxptr->next_oid) { if ((res = snmp_oid_compare(varbind->name, varbind->name_length, idxptr->varbind.name, idxptr->varbind.name_length)) <= 0 ) break; } if ( res != 0 ) return INDEX_ERR_NOT_ALLOCATED; if ( varbind->type != idxptr->varbind.type ) return INDEX_ERR_WRONG_TYPE; for(idxptr2 = idxptr ; idxptr2 != NULL; prev_idx_ptr = idxptr2, idxptr2 = idxptr2->next_idx) { i = SNMP_MIN(varbind->val_len, idxptr2->varbind.val_len); res2 = memcmp(varbind->val.string, idxptr2->varbind.val.string, i); if ( res2 <= 0 ) break; } if ( res2 != 0 ) return INDEX_ERR_NOT_ALLOCATED; if ( ss != idxptr2->session ) return INDEX_ERR_WRONG_SESSION; /* * If this is a "normal" index unregistration, * mark the index entry as unused, but leave * it in situ. This allows differentiation * between ANY_INDEX and NEW_INDEX */ if ( remember ) { idxptr2->session = NULL; /* Unused index */ return SNMP_ERR_NOERROR; } /* * If this is a failed attempt to register a * number of indexes, the successful ones * must be removed completely. */ if ( prev_idx_ptr ) { prev_idx_ptr->next_idx = idxptr2->next_idx; } else if ( prev_oid_ptr ) { if ( idxptr2->next_idx ) /* Use p_idx_ptr as a temp variable */ prev_idx_ptr = idxptr2->next_idx; else prev_idx_ptr = idxptr2->next_oid; while ( prev_oid_ptr ) { prev_oid_ptr->next_oid = prev_idx_ptr; prev_oid_ptr = prev_oid_ptr->next_idx; } } else { if ( idxptr2->next_idx ) snmp_index_head = idxptr2->next_idx; else snmp_index_head = idxptr2->next_oid; } snmp_free_var( (struct variable_list *)idxptr2 ); return SNMP_ERR_NOERROR; }
/** @internal */ void netsnmp_config_parse_table_set(const char *token, char *line) { oid name[MAX_OID_LEN], table_name[MAX_OID_LEN]; size_t name_length = MAX_OID_LEN, table_name_length = MAX_OID_LEN; struct tree *tp, *indexnode; netsnmp_table_data_set *table_set; data_set_tables *tables; struct index_list *index; unsigned int mincol = 0xffffff, maxcol = 0; u_char type; char *pos; /* * instatiate a fake table based on MIB information */ DEBUGMSGTL(("9:table_set_add_table", "processing '%s'\n", line)); if (NULL != (pos = strchr(line,' '))) { config_pwarn("ignoring extra tokens on line"); snmp_log(LOG_WARNING," ignoring '%s'\n", pos); *pos = '\0'; } /* * check for duplicate table */ tables = (data_set_tables *) netsnmp_get_list_data(auto_tables, line); if (NULL != tables) { config_pwarn("duplicate table definition"); return; } /* * parse oid and find tree structure */ if (!snmp_parse_oid(line, table_name, &table_name_length)) { config_pwarn ("can't instatiate table since I can't parse the table name"); return; } if(NULL == (tp = get_tree(table_name, table_name_length, get_tree_head()))) { config_pwarn("can't instatiate table since " "I can't find mib information about it"); return; } if (NULL == (tp = tp->child_list) || NULL == tp->child_list) { config_pwarn("can't instatiate table since it doesn't appear to be " "a proper table (no children)"); return; } /* * check for augments indexes */ if (NULL != tp->augments) { if (!snmp_parse_oid(tp->augments, table_name, &table_name_length)) { config_pwarn("I can't parse the augment tabel name"); snmp_log(LOG_WARNING, " can't parse %s\n", tp->augments); return; } if(NULL == (tp = get_tree(table_name, table_name_length, get_tree_head()))) { config_pwarn("can't instatiate table since " "I can't find mib information about augment table"); snmp_log(LOG_WARNING, " table %s not found in tree\n", tp->augments); return; } table_set = netsnmp_create_table_data_set(line); /* * loop through indexes and add types */ for (index = tp->indexes; index; index = index->next) { if (!snmp_parse_oid(index->ilabel, name, &name_length) || (NULL == (indexnode = get_tree(name, name_length, get_tree_head())))) { config_pwarn("can't instatiate table since " "I don't know anything about one index"); snmp_log(LOG_WARNING, " index %s not found in tree\n", index->ilabel); return; /* xxx mem leak */ } type = mib_to_asn_type(indexnode->type); if (type == (u_char) - 1) { config_pwarn("unknown index type"); return; /* xxx mem leak */ } if (index->isimplied) /* if implied, mark it as such */ type |= ASN_PRIVATE; DEBUGMSGTL(("table_set_add_row", "adding default index of type %d\n", type)); netsnmp_table_dataset_add_index(table_set, type); } } else table_set = netsnmp_create_table_data_set(line); /* * loop through indexes and add types */ for (index = tp->indexes; index; index = index->next) { if (!snmp_parse_oid(index->ilabel, name, &name_length) || (NULL == (indexnode = get_tree(name, name_length, get_tree_head())))) { config_pwarn("can't instatiate table since " "I don't know anything about one index"); snmp_log(LOG_WARNING, " index %s not found in tree\n", index->ilabel); return; /* xxx mem leak */ } type = mib_to_asn_type(indexnode->type); if (type == (u_char) - 1) { config_pwarn("unknown index type"); return; /* xxx mem leak */ } if (index->isimplied) /* if implied, mark it as such */ type |= ASN_PRIVATE; DEBUGMSGTL(("table_set_add_row", "adding default index of type %d\n", type)); netsnmp_table_dataset_add_index(table_set, type); } /* * loop through children and add each column info */ for (tp = tp->child_list; tp; tp = tp->next_peer) { int canwrite = 0; type = mib_to_asn_type(tp->type); if (type == (u_char) - 1) { config_pwarn("unknown column type"); return; /* xxx mem leak */ } DEBUGMSGTL(("table_set_add_row", "adding column %s(%d) of type %d (access %d)\n", tp->label, tp->subid, type, tp->access)); switch (tp->access) { case MIB_ACCESS_CREATE: table_set->allow_creation = 1; case MIB_ACCESS_READWRITE: case MIB_ACCESS_WRITEONLY: canwrite = 1; case MIB_ACCESS_READONLY: DEBUGMSGTL(("table_set_add_row", "adding column %d of type %d\n", tp->subid, type)); netsnmp_table_set_add_default_row(table_set, tp->subid, type, canwrite, NULL, 0); mincol = SNMP_MIN(mincol, tp->subid); maxcol = SNMP_MAX(maxcol, tp->subid); break; case MIB_ACCESS_NOACCESS: case MIB_ACCESS_NOTIFY: break; default: config_pwarn("unknown column access type"); break; } } /* * register the table */ netsnmp_register_table_data_set(netsnmp_create_handler_registration (line, NULL, table_name, table_name_length, HANDLER_CAN_RWRITE), table_set, NULL); netsnmp_register_auto_data_table(table_set, NULL); }
/* * The helper handler that takes care of passing a specific row of * data down to the lower handler(s). It sets request->processed if * the request should not be handled. */ int netsnmp_table_data_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_data *table = (netsnmp_table_data *) handler->myvoid; netsnmp_request_info *request; int valid_request = 0; netsnmp_table_row *row; netsnmp_table_request_info *table_info; netsnmp_table_registration_info *table_reg_info = netsnmp_find_table_registration_info(reginfo); int result, regresult; int oldmode; for (request = requests; request; request = request->next) { if (request->processed) continue; table_info = netsnmp_extract_table_info(request); if (!table_info) continue; /* ack */ switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: case MODE_SET_RESERVE1: netsnmp_request_add_list_data(request, netsnmp_create_data_list( TABLE_DATA_TABLE, table, NULL)); } /* * find the row in question */ switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ if (request->requestvb->type != ASN_NULL) continue; /* * loop through data till we find the next row */ result = snmp_oid_compare(request->requestvb->name, request->requestvb->name_length, reginfo->rootoid, reginfo->rootoid_len); regresult = snmp_oid_compare(request->requestvb->name, SNMP_MIN(request->requestvb-> name_length, reginfo->rootoid_len), reginfo->rootoid, reginfo->rootoid_len); if (regresult == 0 && request->requestvb->name_length < reginfo->rootoid_len) regresult = -1; if (result < 0 || 0 == result) { /* * before us entirely, return the first */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 1 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the entry */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 2 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the column */ row = table->first_row; } else { /* * loop through all rows looking for the first one * that is equal to the request or greater than it */ for (row = table->first_row; row; row = row->next) { /* * compare the index of the request to the row */ result = snmp_oid_compare(row->index_oid, row->index_oid_len, request->requestvb->name + 2 + reginfo->rootoid_len, request->requestvb->name_length - 2 - reginfo->rootoid_len); if (result == 0) { /* * equal match, return the next row */ if (row) { row = row->next; } break; } else if (result > 0) { /* * the current row is greater than the * request, use it */ break; } } } if (!row) { table_info->colnum++; if (table_info->colnum <= table_reg_info->max_column) { row = table->first_row; } } if (row) { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); /* * Set the name appropriately, so we can pass this * request on as a simple GET request */ netsnmp_table_data_build_result(reginfo, reqinfo, request, row, table_info->colnum, ASN_NULL, NULL, 0); } else { /* no decent result found. Give up. It's beyond us. */ request->processed = 1; } break; case MODE_GET: if (request->requestvb->type != ASN_NULL) continue; /* * find the row in question */ if (request->requestvb->name_length < (reginfo->rootoid_len + 3)) { /* table.entry.column... */ /* * request too short */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else if (NULL == (row = netsnmp_table_data_get_from_oid(table, request-> requestvb->name + reginfo-> rootoid_len + 2, request-> requestvb-> name_length - reginfo-> rootoid_len - 2))) { /* * no such row */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); } break; case MODE_SET_RESERVE1: valid_request = 1; if (NULL != (row = netsnmp_table_data_get_from_oid(table, request->requestvb->name + reginfo->rootoid_len + 2, request->requestvb-> name_length - reginfo->rootoid_len - 2))) { netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_ROW, row, NULL)); } break; case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_FREE: case MODE_SET_UNDO: valid_request = 1; } } if (valid_request && (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK)) { /* * If this is a GetNext or GetBulk request, then we've identified * the row that ought to include the appropriate next instance. * Convert the request into a Get request, so that the lower-level * handlers don't need to worry about skipping on, and call these * handlers ourselves (so we can undo this again afterwards). */ oldmode = reqinfo->mode; reqinfo->mode = MODE_GET; result = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reqinfo->mode = oldmode; handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; return result; } else /* next handler called automatically - 'AUTO_NEXT' */ return SNMP_ERR_NOERROR; }
/** @internal Implements the stash_to_next handler */ int netsnmp_stash_to_next_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { int ret = SNMP_ERR_NOERROR; int namelen; int finished = 0; netsnmp_oid_stash_node **cinfo; netsnmp_variable_list *vb; netsnmp_request_info *reqtmp; /* * this code depends on AUTO_NEXT being set */ netsnmp_assert(handler->flags & MIB_HANDLER_AUTO_NEXT); /* * Don't do anything for any modes except GET_STASH. Just return, * and the agent will call the next handler (AUTO_NEXT). * * If the handler chain already supports GET_STASH, we don't * need to do anything here either. Once again, we just return * and the agent will call the next handler (AUTO_NEXT). * * Otherwise, we munge the mode to GET_NEXT, and call the * next handler ourselves, repeatedly until we've retrieved the * full contents of the table or subtree. * Then restore the mode and return to the calling handler * (setting AUTO_NEXT_OVERRRIDE so the agent knows what we did). */ if (MODE_GET_STASH == reqinfo->mode) { if ( reginfo->modes & HANDLER_CAN_STASH ) { return ret; } cinfo = netsnmp_extract_stash_cache( reqinfo ); reqtmp = SNMP_MALLOC_TYPEDEF(netsnmp_request_info); vb = reqtmp->requestvb = SNMP_MALLOC_TYPEDEF( netsnmp_variable_list ); vb->type = ASN_NULL; snmp_set_var_objid( vb, reginfo->rootoid, reginfo->rootoid_len ); reqinfo->mode = MODE_GETNEXT; while (!finished) { ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, reqtmp); namelen = SNMP_MIN(vb->name_length, reginfo->rootoid_len); if ( !snmp_oid_compare( reginfo->rootoid, reginfo->rootoid_len, vb->name, namelen) && vb->type != ASN_NULL && vb->type != SNMP_ENDOFMIBVIEW ) { /* * This result is relevant so save it, and prepare * the request varbind for the next query. */ netsnmp_oid_stash_add_data( cinfo, vb->name, vb->name_length, snmp_clone_varbind( vb )); /* * Tidy up the response structure, * ready for retrieving the next entry */ netsnmp_free_all_list_data(reqtmp->parent_data); reqtmp->parent_data = NULL; reqtmp->processed = 0; vb->type = ASN_NULL; } else { finished = 1; } } reqinfo->mode = MODE_GET_STASH; /* * let the handler chain processing know that we've already * called the next handler */ handler->flags |= MIB_HANDLER_AUTO_NEXT_OVERRIDE_ONCE; } return ret; }
/*******************************************************************-o-****** * test_keychange * * Returns: * Number of failures. * * * Test of KeyChange TC implementation. * * ASSUME newkey and oldkey begin as NULL terminated strings. */ int test_keychange(void) { int rval = SNMPERR_SUCCESS, failcount = 0, properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACMD5), oldkey_len, newkey_len, keychange_len, temp_len, isdefault_new = FALSE, isdefault_old = FALSE; char *hashname = "usmHMACMD5AuthProtocol.", *s; u_char oldkey_buf[LOCAL_MAXBUF], newkey_buf[LOCAL_MAXBUF], temp_buf[LOCAL_MAXBUF], keychange_buf[LOCAL_MAXBUF]; oid *hashtype = usmHMACMD5AuthProtocol; OUTPUT("Test of KeyChange TC --"); /* * Set newkey and oldkey. */ if (!newkey) { /* newkey */ newkey = NEWKEY_DEFAULT; isdefault_new = TRUE; } newkey_len = strlen(newkey); if (tolower(*(newkey + 1)) == 'x') { newkey_len = hex_to_binary2(newkey + 2, newkey_len - 2, &s); if (newkey_len < 0) { FAILED((rval = SNMPERR_GENERR), "Could not resolve hex newkey."); } newkey = s; binary_to_hex(newkey, newkey_len, &s); } if (!oldkey) { /* oldkey */ oldkey = OLDKEY_DEFAULT; isdefault_old = TRUE; } oldkey_len = strlen(oldkey); if (tolower(*(oldkey + 1)) == 'x') { oldkey_len = hex_to_binary2(oldkey + 2, oldkey_len - 2, &s); if (oldkey_len < 0) { FAILED((rval = SNMPERR_GENERR), "Could not resolve hex oldkey."); } oldkey = s; binary_to_hex(oldkey, oldkey_len, &s); } test_keychange_again: memset(oldkey_buf, 0, LOCAL_MAXBUF); memset(newkey_buf, 0, LOCAL_MAXBUF); memset(keychange_buf, 0, LOCAL_MAXBUF); memset(temp_buf, 0, LOCAL_MAXBUF); memcpy(oldkey_buf, oldkey, SNMP_MIN(oldkey_len, properlength)); memcpy(newkey_buf, newkey, SNMP_MIN(newkey_len, properlength)); keychange_len = LOCAL_MAXBUF; binary_to_hex(oldkey_buf, properlength, &s); fprintf(stdout, "\noldkey%s (len=%d): %s\n", (isdefault_old) ? " (default)" : "", properlength, s); SNMP_FREE(s); binary_to_hex(newkey_buf, properlength, &s); fprintf(stdout, "newkey%s (len=%d): %s\n\n", (isdefault_new) ? " (default)" : "", properlength, s); SNMP_FREE(s); rval = encode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM, oldkey_buf, properlength, newkey_buf, properlength, keychange_buf, &keychange_len); FAILED(rval, "encode_keychange()."); if (keychange_len != (properlength * 2)) { FAILED(SNMPERR_GENERR, "KeyChange string (encoded) is not proper length " "for this hash transform."); } binary_to_hex(keychange_buf, keychange_len, &s); fprintf(stdout, "(%s) KeyChange string: %s\n\n", ((hashtype == usmHMACMD5AuthProtocol) ? "MD5" : "SHA"), s); SNMP_FREE(s); temp_len = properlength; rval = decode_keychange(hashtype, USM_LENGTH_OID_TRANSFORM, oldkey_buf, properlength, keychange_buf, properlength * 2, temp_buf, &temp_len); FAILED(rval, "decode_keychange()."); if (temp_len != properlength) { FAILED(SNMPERR_GENERR, "decoded newkey is not proper length for " "this hash transform."); } binary_to_hex(temp_buf, temp_len, &s); fprintf(stdout, "decoded newkey: %s\n\n", s); SNMP_FREE(s); if (memcmp(newkey_buf, temp_buf, temp_len)) { FAILED(SNMPERR_GENERR, "newkey did not decode properly."); } SUCCESS(hashname); fprintf(stdout, "\n"); /* * Multiplex different test combinations. * * First clause is for Test #2, second clause is for (last) Test #3. */ if (hashtype == usmHMACMD5AuthProtocol) { hashtype = usmHMACSHA1AuthProtocol; hashname = "usmHMACSHA1AuthProtocol (w/DES length kul's)."; properlength = BYTESIZE(SNMP_TRANS_PRIVLEN_1DES) + BYTESIZE(SNMP_TRANS_PRIVLEN_1DES_IV); goto test_keychange_again; } else if (properlength < BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1)) { hashtype = usmHMACSHA1AuthProtocol; hashname = "usmHMACSHA1AuthProtocol."; properlength = BYTESIZE(SNMP_TRANS_AUTHLEN_HMACSHA1); goto test_keychange_again; } return failcount; } /* end test_keychange() */
int netsnmp_scalar_group_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_variable_list *var = requests->requestvb; netsnmp_scalar_group *sgroup = (netsnmp_scalar_group *)handler->myvoid; int ret, cmp; int namelen; oid subid, root_tmp[MAX_OID_LEN], *root_save; DEBUGMSGTL(("helper:scalar_group", "Got request:\n")); namelen = SNMP_MIN(requests->requestvb->name_length, reginfo->rootoid_len); cmp = snmp_oid_compare(requests->requestvb->name, namelen, reginfo->rootoid, reginfo->rootoid_len); DEBUGMSGTL(( "helper:scalar_group", " cmp=%d, oid:", cmp)); DEBUGMSGOID(("helper:scalar_group", var->name, var->name_length)); DEBUGMSG(( "helper:scalar_group", "\n")); /* * copy root oid to root_tmp, set instance to 0. (subid set later on) * save rootoid, since we'll replace it before calling next handler, * and need to restore it afterwards. */ memcpy(root_tmp, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); root_tmp[reginfo->rootoid_len + 1] = 0; root_save = reginfo->rootoid; ret = SNMP_ERR_NOCREATION; switch (reqinfo->mode) { /* * The handling of "exact" requests is basically the same. * The only difference between GET and SET requests is the * error/exception to return on failure. */ case MODE_GET: ret = SNMP_NOSUCHOBJECT; /* Fallthrough */ #ifndef NETSNMP_NO_WRITE_SUPPORT case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: #endif /* NETSNMP_NO_WRITE_SUPPORT */ if (cmp != 0 || requests->requestvb->name_length <= reginfo->rootoid_len) { /* * Common prefix doesn't match, or only *just* matches * the registered root (so can't possibly match a scalar) */ netsnmp_set_request_error(reqinfo, requests, ret); return SNMP_ERR_NOERROR; } else { /* * Otherwise, * extract the object subidentifier from the request, * check this is (probably) valid, and then fudge the * registered 'rootoid' to match, before passing the * request off to the next handler ('scalar'). * * Note that we don't bother checking instance subidentifiers * here. That's left to the scalar helper. */ subid = requests->requestvb->name[reginfo->rootoid_len]; if (subid < sgroup->lbound || subid > sgroup->ubound) { netsnmp_set_request_error(reqinfo, requests, ret); return SNMP_ERR_NOERROR; } root_tmp[reginfo->rootoid_len] = subid; reginfo->rootoid_len += 2; reginfo->rootoid = root_tmp; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid = root_save; reginfo->rootoid_len -= 2; return ret; } break; case MODE_GETNEXT: /* * If we're being asked for something before (or exactly matches) * the registered root OID, then start with the first object. * If we're being asked for something that exactly matches an object * OID, then that's what we pass down. * Otherwise, we pass down the OID of the *next* object.... */ if (cmp < 0 || requests->requestvb->name_length <= reginfo->rootoid_len) { subid = sgroup->lbound; } else if (requests->requestvb->name_length == reginfo->rootoid_len+1) subid = requests->requestvb->name[reginfo->rootoid_len]; else subid = requests->requestvb->name[reginfo->rootoid_len]+1; /* * ... always assuming this is (potentially) valid, of course. */ if (subid < sgroup->lbound) subid = sgroup->lbound; else if (subid > sgroup->ubound) return SNMP_ERR_NOERROR; root_tmp[reginfo->rootoid_len] = subid; reginfo->rootoid_len += 2; reginfo->rootoid = root_tmp; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); /* * If we didn't get an answer (due to holes in the group) * set things up to retry again. */ if (!requests->delegated && (requests->requestvb->type == ASN_NULL || requests->requestvb->type == SNMP_NOSUCHOBJECT || requests->requestvb->type == SNMP_NOSUCHINSTANCE)) { snmp_set_var_objid(requests->requestvb, reginfo->rootoid, reginfo->rootoid_len - 1); requests->requestvb->name[reginfo->rootoid_len - 2] = ++subid; requests->requestvb->type = ASN_PRIV_RETRY; } reginfo->rootoid = root_save; reginfo->rootoid_len -= 2; return ret; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; }
/** * The helper handler that takes care of passing a specific row of * data down to the lower handler(s). It sets request->processed if * the request should not be handled. */ int netsnmp_table_data_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_table_data *table = (netsnmp_table_data *) handler->myvoid; netsnmp_request_info *request; int valid_request = 0; netsnmp_table_row *row; netsnmp_table_request_info *table_info; netsnmp_table_registration_info *table_reg_info = netsnmp_find_table_registration_info(reginfo); int result, regresult; int oldmode; for (request = requests; request; request = request->next) { if (request->processed) continue; table_info = netsnmp_extract_table_info(request); if (!table_info) continue; /* ack */ /* * find the row in question */ switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: /* XXXWWW */ if (request->requestvb->type != ASN_NULL) continue; /* * loop through data till we find the next row */ result = snmp_oid_compare(request->requestvb->name, request->requestvb->name_length, reginfo->rootoid, reginfo->rootoid_len); regresult = snmp_oid_compare(request->requestvb->name, SNMP_MIN(request->requestvb-> name_length, reginfo->rootoid_len), reginfo->rootoid, reginfo->rootoid_len); if (regresult == 0 && request->requestvb->name_length < reginfo->rootoid_len) regresult = -1; if (result < 0 || 0 == result) { /* * before us entirely, return the first */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 1 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the entry */ row = table->first_row; table_info->colnum = table_reg_info->min_column; } else if (regresult == 0 && request->requestvb->name_length == reginfo->rootoid_len + 2 && /* entry node must be 1, but any column is ok */ request->requestvb->name[reginfo->rootoid_len] == 1) { /* * exactly to the column */ row = table->first_row; } else { /* * loop through all rows looking for the first one * that is equal to the request or greater than it */ for (row = table->first_row; row; row = row->next) { /* * compare the index of the request to the row */ result = snmp_oid_compare(row->index_oid, row->index_oid_len, request->requestvb->name + 2 + reginfo->rootoid_len, request->requestvb->name_length - 2 - reginfo->rootoid_len); if (result == 0) { /* * equal match, return the next row */ if (row) { row = row->next; } break; } else if (result > 0) { /* * the current row is greater than the * request, use it */ break; } } } if (!row) { table_info->colnum++; if (table_info->colnum <= table_reg_info->max_column) { row = table->first_row; } } if (row) { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); /* * Set the name appropriately, so we can pass this * request on as a simple GET request */ netsnmp_table_data_build_result(reginfo, reqinfo, request, row, table_info->colnum, ASN_NULL, NULL, 0); } else { /* no decent result found. Give up. It's beyond us. */ request->processed = 1; } break; case MODE_GET: if (request->requestvb->type != ASN_NULL) continue; /* * find the row in question */ if (request->requestvb->name_length < (reginfo->rootoid_len + 3)) { /* table.entry.column... */ /* * request too short */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else if (NULL == (row = netsnmp_table_data_get_from_oid(table, request-> requestvb->name + reginfo-> rootoid_len + 2, request-> requestvb-> name_length - reginfo-> rootoid_len - 2))) { /* * no such row */ netsnmp_set_request_error(reqinfo, request, SNMP_NOSUCHINSTANCE); break; } else { valid_request = 1; netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); } break; case MODE_SET_RESERVE1: valid_request = 1; if (NULL != (row = netsnmp_table_data_get_from_oid(table, request->requestvb->name + reginfo->rootoid_len + 2, request->requestvb-> name_length - reginfo->rootoid_len - 2))) { netsnmp_request_add_list_data(request, netsnmp_create_data_list (TABLE_DATA_NAME, row, NULL)); } break; case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_FREE: case MODE_SET_UNDO: valid_request = 1; } } if (valid_request) { /* * If this is a GetNext or GetBulk request, then we've identified * the row that ought to include the appropriate next instance. * Convert the request into a Get request, so that the lower-level * handlers don't need to worry about skipping on.... */ oldmode = reqinfo->mode; if (reqinfo->mode == MODE_GETNEXT || reqinfo->mode == MODE_GETBULK) { reqinfo->mode = MODE_GET; } result = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); if (oldmode == MODE_GETNEXT || oldmode == MODE_GETBULK) { /* XXX */ for (request = requests; request; request = request->next) { /* * ... but if the lower-level handlers aren't dealing with * skipping on to the next instance, then we must handle * this situation here. * Mark 'holes' in the table as needing to be retried. * * This approach is less efficient than handling such * holes directly in the table_dataset handler, but allows * user-provided handlers to override the dataset handler * if this proves necessary. */ if (request->requestvb->type == ASN_NULL || request->requestvb->type == SNMP_NOSUCHINSTANCE) { request->requestvb->type = ASN_PRIV_RETRY; } /* XXX - Move on to the next object */ if (request->requestvb->type == SNMP_NOSUCHOBJECT) { request->requestvb->type = ASN_PRIV_RETRY; } } reqinfo->mode = oldmode; } return result; } else return SNMP_ERR_NOERROR; }
int netsnmp_scalar_helper_handler(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { netsnmp_variable_list *var = requests->requestvb; int ret, cmp; int namelen; DEBUGMSGTL(("helper:scalar", "Got request:\n")); namelen = SNMP_MIN(requests->requestvb->name_length, reginfo->rootoid_len); cmp = snmp_oid_compare(requests->requestvb->name, namelen, reginfo->rootoid, reginfo->rootoid_len); DEBUGMSGTL(("helper:scalar", " oid:", cmp)); DEBUGMSGOID(("helper:scalar", var->name, var->name_length)); DEBUGMSG(("helper:scalar", "\n")); switch (reqinfo->mode) { case MODE_GET: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_NOSUCHOBJECT); return SNMP_ERR_NOERROR; } else { reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } break; case MODE_SET_RESERVE1: case MODE_SET_RESERVE2: case MODE_SET_ACTION: case MODE_SET_COMMIT: case MODE_SET_UNDO: case MODE_SET_FREE: if (cmp != 0) { netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOCREATION); return SNMP_ERR_NOERROR; } else { reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } break; case MODE_GETNEXT: reginfo->rootoid[reginfo->rootoid_len++] = 0; ret = netsnmp_call_next_handler(handler, reginfo, reqinfo, requests); reginfo->rootoid_len--; return ret; } /* * got here only if illegal mode found */ return SNMP_ERR_GENERR; }