/* * Split the subtree into two at the specified point, * returning the new (second) subtree */ struct subtree * split_subtree(struct subtree *current, oid name[], int name_len ) { struct subtree *new_sub, *ptr; int i; char *cp; if ( snmp_oid_compare(name, name_len, current->end, current->end_len) > 0 ) return NULL; /* Split comes after the end of this subtree */ new_sub = (struct subtree *)malloc(sizeof(struct subtree)); if ( new_sub == NULL ) return NULL; memcpy(new_sub, current, sizeof(struct subtree)); /* Set up the point of division */ memcpy(current->end, name, name_len*sizeof(oid)); memcpy(new_sub->start, name, name_len*sizeof(oid)); current->end_len = name_len; new_sub->start_len = name_len; /* * Split the variables between the two new subtrees */ i = current->variables_len; current->variables_len = 0; for ( ; i > 0 ; i-- ) { /* Note that the variable "name" field omits the prefix common to the whole registration, hence the strange comparison here */ if ( snmp_oid_compare( new_sub->variables[0].name, new_sub->variables[0].namelen, name + current->namelen, name_len - current->namelen ) >= 0 ) break; /* All following variables belong to the second subtree */ current->variables_len++; new_sub->variables_len--; cp = (char *)new_sub->variables; new_sub->variables = (struct variable *)(cp + new_sub->variables_width); } /* Delegated trees should retain their variables regardless */ if ( current->variables_len > 0 && IS_DELEGATED((u_char)current->variables[0].type)) { new_sub->variables_len = 1; new_sub->variables = current->variables; } /* Propogate this split down through any children */ if ( current->children ) new_sub->children = split_subtree(current->children, name, name_len); /* Retain the correct linking of the list */ for ( ptr = current ; ptr != NULL ; ptr=ptr->children ) ptr->next = new_sub; for ( ptr = new_sub ; ptr != NULL ; ptr=ptr->children ) ptr->prev = current; for ( ptr = new_sub->next ; ptr != NULL ; ptr=ptr->children ) ptr->prev = new_sub; return new_sub; }
int handle_var_list(struct agent_snmp_session *asp) { struct variable_list *varbind_ptr; u_char statType; u_char *statP; size_t statLen; u_short acl; WriteMethod *write_method; AddVarMethod *add_method; int noSuchObject = TRUE; int count, view; count = 0; varbind_ptr = asp->start; if ( !varbind_ptr ) { return SNMP_ERR_NOERROR; } while (1) { count++; statp_loop: statP = getStatPtr( varbind_ptr->name, &varbind_ptr->name_length, &statType, &statLen, &acl, asp->exact, &write_method, asp->pdu, &noSuchObject); if (statP == NULL && (asp->rw != WRITE || write_method == NULL)) { /* Careful -- if the varbind was lengthy, it will have allocated some memory. */ snmp_set_var_value(varbind_ptr, NULL, 0); varbind_ptr->val.integer = NULL; varbind_ptr->val_len = 0; if ( asp->exact ) { if ( noSuchObject == TRUE ){ statType = SNMP_NOSUCHOBJECT; } else { statType = SNMP_NOSUCHINSTANCE; } } else { statType = SNMP_ENDOFMIBVIEW; } if (asp->pdu->version == SNMP_VERSION_1) { asp->pdu->errstat = SNMP_ERR_NOSUCHNAME; asp->pdu->errindex = count; return SNMP_ERR_NOSUCHNAME; } else if (asp->rw == WRITE) { asp->pdu->errstat = ( noSuchObject ? SNMP_ERR_NOTWRITABLE : SNMP_ERR_NOCREATION ); asp->pdu->errindex = count; return asp->pdu->errstat; } else varbind_ptr->type = statType; } /* Delegated variables should be added to the relevant outgoing request */ else if ( IS_DELEGATED(statType)) { add_method = (AddVarMethod*)statP; statType = (*add_method)( asp, varbind_ptr ); } /* GETNEXT/GETBULK should just skip inaccessible entries */ else if ((view = in_a_view(varbind_ptr->name, &varbind_ptr->name_length, asp->pdu, varbind_ptr->type)) && !asp->exact) { if (view != 5) send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); goto statp_loop; } /* Other access problems are permanent */ else if (( asp->rw == WRITE && !(acl & 2)) || view) { if (asp->pdu->version == SNMP_VERSION_1 || asp->rw != WRITE) { if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)) DEBUGMSGTL(("snmp_agent", " >> noSuchName (read-only)\n")); ERROR_MSG("read-only"); statType = SNMP_ERR_NOSUCHNAME; } else { if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE)) DEBUGMSGTL(("snmp_agent", " >> notWritable\n")); ERROR_MSG("Not Writable"); statType = SNMP_ERR_NOTWRITABLE; } asp->pdu->errstat = statType; asp->pdu->errindex = count; send_easy_trap(SNMP_TRAP_AUTHFAIL, 0); return statType; } else { /* dump verbose info */ if (ds_get_boolean(DS_APPLICATION_ID, DS_AGENT_VERBOSE) && statP) dump_var(varbind_ptr->name, varbind_ptr->name_length, statType, statP, statLen); /* FINALLY we can act on SET requests ....*/ if ( asp->rw == WRITE ) { if ( write_method != NULL ) { statType = (*write_method)(asp->mode, varbind_ptr->val.string, varbind_ptr->type, varbind_ptr->val_len, statP, varbind_ptr->name, varbind_ptr->name_length); if (statType != SNMP_ERR_NOERROR) { asp->pdu->errstat = statType; asp->pdu->errindex = count; return statType; } } else { if (!goodValue(varbind_ptr->type, varbind_ptr->val_len, statType, statLen)){ if (asp->pdu->version == SNMP_VERSION_1) statType = SNMP_ERR_BADVALUE; else statType = SNMP_ERR_WRONGTYPE; /* poor approximation */ asp->pdu->errstat = statType; asp->pdu->errindex = count; return statType; } /* actually do the set if necessary */ if (asp->mode == COMMIT) setVariable(varbind_ptr->val.string, varbind_ptr->type, varbind_ptr->val_len, statP, statLen); } } /* ... or save the results from assorted GETs */ else { snmp_set_var_value(varbind_ptr, statP, statLen); varbind_ptr->type = statType; } } if ( varbind_ptr == asp->end ) return SNMP_ERR_NOERROR; varbind_ptr = varbind_ptr->next_variable; if ( asp->mode == RESERVE1 ) snmp_vars_inc++; } }
/** implements the old_api handler */ int netsnmp_old_api_helper(netsnmp_mib_handler *handler, netsnmp_handler_registration *reginfo, netsnmp_agent_request_info *reqinfo, netsnmp_request_info *requests) { #if MIB_CLIENTS_ARE_EVIL oid save[MAX_OID_LEN]; size_t savelen = 0; #endif struct variable compat_var, *cvp = &compat_var; int exact = 1; int status; struct variable *vp; netsnmp_old_api_cache *cacheptr; netsnmp_agent_session *oldasp = NULL; u_char *access = NULL; WriteMethod *write_method = NULL; size_t len; size_t tmp_len; oid tmp_name[MAX_OID_LEN]; vp = (struct variable *) handler->myvoid; /* * create old variable structure with right information */ memcpy(cvp->name, reginfo->rootoid, reginfo->rootoid_len * sizeof(oid)); cvp->namelen = reginfo->rootoid_len; cvp->type = vp->type; cvp->magic = vp->magic; cvp->acl = vp->acl; cvp->findVar = vp->findVar; switch (reqinfo->mode) { case MODE_GETNEXT: case MODE_GETBULK: exact = 0; } for (; requests; requests = requests->next) { #if MIB_CLIENTS_ARE_EVIL savelen = requests->requestvb->name_length; memcpy(save, requests->requestvb->name, savelen * sizeof(oid)); #endif switch (reqinfo->mode) { case MODE_GET: case MODE_GETNEXT: #ifndef NETSNMP_NO_WRITE_SUPPORT case MODE_SET_RESERVE1: #endif /* !NETSNMP_NO_WRITE_SUPPORT */ /* * Actually call the old mib-module function */ if (vp && vp->findVar) { memcpy(tmp_name, requests->requestvb->name, requests->requestvb->name_length*sizeof(oid)); tmp_len = requests->requestvb->name_length; access = (*(vp->findVar)) (cvp, tmp_name, &tmp_len, exact, &len, &write_method); snmp_set_var_objid( requests->requestvb, tmp_name, tmp_len ); } else access = NULL; #ifdef WWW_FIX if (IS_DELEGATED(cvp->type)) { add_method = (AddVarMethod *) statP; requests->delayed = 1; have_delegated = 1; continue; /* WWW: This may not get to the right place */ } #endif /* * WWW: end range checking */ if (access) { /* * result returned */ #ifndef NETSNMP_NO_WRITE_SUPPORT if (reqinfo->mode != MODE_SET_RESERVE1) #endif /* !NETSNMP_NO_WRITE_SUPPORT */ snmp_set_var_typed_value(requests->requestvb, cvp->type, access, len); } else { /* * no result returned */ #if MIB_CLIENTS_ARE_EVIL if (access == NULL) { if (netsnmp_oid_equals(requests->requestvb->name, requests->requestvb->name_length, save, savelen) != 0) { DEBUGMSGTL(("old_api", "evil_client: %s\n", reginfo->handlerName)); memcpy(requests->requestvb->name, save, savelen * sizeof(oid)); requests->requestvb->name_length = savelen; } } #endif } /* * AAA: fall through for everything that is a set (see BBB) */ #ifndef NETSNMP_NO_WRITE_SUPPORT if (reqinfo->mode != MODE_SET_RESERVE1) #endif /* !NETSNMP_NO_WRITE_SUPPORT */ break; cacheptr = SNMP_MALLOC_TYPEDEF(netsnmp_old_api_cache); if (!cacheptr) return netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_RESOURCEUNAVAILABLE); cacheptr->data = access; cacheptr->write_method = write_method; write_method = NULL; netsnmp_request_add_list_data(requests, netsnmp_create_data_list (OLD_API_NAME, cacheptr, &free_wrapper)); /* * BBB: fall through for everything that is a set (see AAA) */ default: /* * WWW: explicitly list the SET conditions */ /* * (the rest of the) SET contions */ cacheptr = (netsnmp_old_api_cache *) netsnmp_request_get_list_data(requests, OLD_API_NAME); if (cacheptr == NULL || cacheptr->write_method == NULL) { /* * WWW: try to set ourselves if possible? */ return netsnmp_set_request_error(reqinfo, requests, SNMP_ERR_NOTWRITABLE); } oldasp = netsnmp_get_current_agent_session(); set_current_agent_session(reqinfo->asp); status = (*(cacheptr->write_method)) (reqinfo->mode, requests->requestvb->val. string, requests->requestvb->type, requests->requestvb->val_len, cacheptr->data, requests->requestvb->name, requests->requestvb-> name_length); set_current_agent_session(oldasp); if (status != SNMP_ERR_NOERROR) { netsnmp_set_request_error(reqinfo, requests, status); } /* * clean up is done by the automatic freeing of the * cache stored in the request. */ break; } } return SNMP_ERR_NOERROR; }