int agentx_unregister_index(netsnmp_session * ss, netsnmp_variable_list * varbind) { netsnmp_pdu *pdu, *response; netsnmp_variable_list *varbind2; if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { return -1; } /* * Make a copy of the index request varbind * for the AgentX request PDU * (since the pdu structure will be freed) */ varbind2 = (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); if (varbind2 == NULL) return -1; if (snmp_clone_var(varbind, varbind2)) { snmp_free_varbind(varbind2); return -1; } pdu = snmp_pdu_create(AGENTX_MSG_INDEX_DEALLOCATE); if (pdu == NULL) { snmp_free_varbind(varbind2); return -1; } pdu->time = 0; pdu->sessid = ss->sessid; /* * Just send a single index release varbind. * (as above) */ pdu->variables = varbind2; if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) return -1; if (response->errstat != SNMP_ERR_NOERROR) { snmp_free_pdu(response); return -1; /* XXX - say why */ } snmp_free_pdu(response); return SNMP_ERR_NOERROR; }
int allocate_idx_list(netsnmp_session * session, netsnmp_pdu *pdu) { netsnmp_session *sp; netsnmp_variable_list *vp, *vp2, *next, *res; int flags = 0; sp = find_agentx_session(session, pdu->sessid); if (sp == NULL) return AGENTX_ERR_NOT_OPEN; if (pdu->flags & AGENTX_MSG_FLAG_ANY_INSTANCE) flags |= ALLOCATE_ANY_INDEX; if (pdu->flags & AGENTX_MSG_FLAG_NEW_INSTANCE) flags |= ALLOCATE_NEW_INDEX; /* * XXX - what about errors? * * If any allocations fail, then we need to * *fully* release the earlier ones. * (i.e. remove them completely from the index registry, * not simply mark them as available for re-use) * * For now - assume they all succeed. */ for (vp = pdu->variables; vp != NULL; vp = next) { next = vp->next_variable; res = register_index(vp, flags, session); if (res == NULL) { /* * If any allocations fail, we need to *fully* release * all previous ones (i.e. remove them completely * from the index registry) */ for (vp2 = pdu->variables; vp2 != vp; vp2 = vp2->next_variable) { remove_index(vp2, session); } return AGENTX_ERR_INDEX_NONE_AVAILABLE; /* XXX */ } else { (void) snmp_clone_var(res, vp); free(res); } vp->next_variable = next; } return AGENTX_ERR_NOERROR; }
static netsnmp_variable_list * _copy_varlist(netsnmp_variable_list * var, /* source varList */ int errindex, /* index of variable to drop (if any) */ int copy_count) { /* !=0 number variables to copy */ netsnmp_variable_list *newhead, *newvar, *oldvar; int ii = 0; newhead = NULL; oldvar = NULL; while (var && (copy_count-- > 0)) { /* * Drop the specified variable (if applicable) */ if (++ii == errindex) { var = var->next_variable; continue; } /* * clone the next variable. Cleanup if alloc fails */ newvar = (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); if (snmp_clone_var(var, newvar)) { if (newvar) free((char *) newvar); snmp_free_varbind(newhead); return 0; } /* * add cloned variable to new list */ if (0 == newhead) newhead = newvar; if (oldvar) oldvar->next_variable = newvar; oldvar = newvar; var = var->next_variable; } return newhead; }
netsnmp_variable_list * agentx_register_index(netsnmp_session * ss, netsnmp_variable_list * varbind, int flags) { netsnmp_pdu *pdu, *response; netsnmp_variable_list *varbind2; if (ss == NULL || !IS_AGENTX_VERSION(ss->version)) { return NULL; } /* * Make a copy of the index request varbind * for the AgentX request PDU * (since the pdu structure will be freed) */ varbind2 = (netsnmp_variable_list *) malloc(sizeof(netsnmp_variable_list)); if (varbind2 == NULL) return NULL; if (snmp_clone_var(varbind, varbind2)) { snmp_free_varbind(varbind2); return NULL; } if (varbind2->val.string == NULL) varbind2->val.string = varbind2->buf; /* ensure it points somewhere */ pdu = snmp_pdu_create(AGENTX_MSG_INDEX_ALLOCATE); if (pdu == NULL) { snmp_free_varbind(varbind2); return NULL; } pdu->time = 0; pdu->sessid = ss->sessid; if (flags == ALLOCATE_ANY_INDEX) pdu->flags |= AGENTX_MSG_FLAG_ANY_INSTANCE; if (flags == ALLOCATE_NEW_INDEX) pdu->flags |= AGENTX_MSG_FLAG_NEW_INSTANCE; /* * Just send a single index request varbind. * Although the AgentX protocol supports * multiple index allocations in a single * request, the model used in the net-snmp agent * doesn't currently take advantage of this. * I believe this is our prerogative - just as * long as the master side Index request handler * can cope with multiple index requests. */ pdu->variables = varbind2; if (agentx_synch_response(ss, pdu, &response) != STAT_SUCCESS) return NULL; if (response->errstat != SNMP_ERR_NOERROR) { snmp_free_pdu(response); return NULL; } /* * Unlink the (single) response varbind to return * to the main driving index request routine. * * This is a memory leak, as nothing will ever * release this varbind. If this becomes a problem, * we'll need to keep a list of these here, and * free the memory in the "index release" routine. * But the master side never frees these either (by * design, since it still needs them), so expecting * the subagent to is discrimination, pure & simple :-) */ varbind2 = response->variables; response->variables = NULL; snmp_free_pdu(response); return varbind2; }
int mp_snmp_subtree_query(netsnmp_session *ss, const oid *subtree_oid, const size_t subtree_len, mp_snmp_subtree *subtree) { oid last_oid[MAX_OID_LEN]; size_t last_len; netsnmp_pdu *request = NULL; netsnmp_pdu *response = NULL; netsnmp_variable_list *var; size_t alloc_size = 0; int rc; /* prepare result */ memset(subtree, '\0', sizeof(*subtree)); subtree->vars = NULL; memcpy(last_oid, subtree_oid, subtree_len * sizeof(oid)); last_len = subtree_len; for (;;) { /* * setup request */ if (ss->version == SNMP_VERSION_1) { request = snmp_pdu_create(SNMP_MSG_GETNEXT); } else { request = snmp_pdu_create(SNMP_MSG_GETBULK); request->non_repeaters = 0; request->max_repetitions = 16; } snmp_add_null_var(request, last_oid, last_len); /* * commence request */ if (response) { snmp_free_pdu(response); response = NULL; } if (mp_verbose > 2) { char buf[128]; snprint_objid((char *) &buf, sizeof(buf), last_oid, last_len); printf("Fetching next from OID %s\n", buf); } rc = snmp_synch_response(ss, request, &response); if (mp_verbose > 3) printf("snmp_synch_response(): rc=%d, errstat=%ld\n", rc, response->errstat); if ((rc == STAT_SUCCESS) && response) { if (response->errstat == SNMP_ERR_NOERROR) { /* * loop over results (may only be one result in case of SNMP v1) */ for (var = response->variables; var; var = var->next_variable) { /* * check, if OIDs are incresing to prevent infinite * loop with broken SNMP agents */ if (snmp_oidtree_compare(var->name, var->name_length, last_oid, last_len) < 0) { if (response) snmp_free_pdu(response); mp_snmp_deinit(); critical("SNMP error: OIDs are not incresing"); } /* * terminate, if oid does not belong to subtree anymore */ if ((var->type == SNMP_ENDOFMIBVIEW) || (snmp_oidtree_compare(subtree_oid, subtree_len, var->name, var->name_length) != 0)) { snmp_free_pdu(response); return rc; } if (mp_verbose > 2) print_variable(var->name, var->name_length, var); if (var->type != SNMP_NOSUCHOBJECT || var->type != SNMP_NOSUCHINSTANCE) { if (alloc_size <= subtree->size) { alloc_size += 16; subtree->vars = mp_realloc(subtree->vars, alloc_size * sizeof(netsnmp_variable_list*)); } subtree->vars[subtree->size] = mp_malloc(sizeof(netsnmp_variable_list)); snmp_clone_var(var, subtree->vars[subtree->size]); subtree->size++; } /* * save last fetched oid */ memcpy(last_oid, var->name, var->name_length * sizeof(oid)); last_len = var->name_length; } /* for */ } else if ((ss->version == SNMP_VERSION_1) && (response->errstat == SNMP_ERR_NOSUCHNAME)) { if (mp_verbose > 3) printf("SNMP-V1: end of tree\n"); } else { /* * some other error occured */ if (mp_verbose > 0) printf("SNMP error: respose->errstat = %ld", response->errstat); rc = STAT_ERROR; //goto done; break; } } else { /* no response, assume an error */ rc = STAT_ERROR; break; } } if (response) snmp_free_pdu(response); return rc; }
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; }