| #include <net-snmp/net-snmp-config.h> |
| |
| #if HAVE_STRING_H |
| #include <string.h> |
| #else |
| #include <strings.h> |
| #endif |
| |
| #include <net-snmp/net-snmp-includes.h> |
| #include <net-snmp/agent/net-snmp-agent-includes.h> |
| |
| #include <net-snmp/agent/old_api.h> |
| #include <net-snmp/agent/agent_callbacks.h> |
| |
| #define MIB_CLIENTS_ARE_EVIL 1 |
| |
| /* |
| * don't use these! |
| */ |
| void set_current_agent_session(netsnmp_agent_session *asp); |
| netsnmp_agent_session *netsnmp_get_current_agent_session(void); |
| |
| /** @defgroup old_api old_api |
| * Calls mib module code written in the old style of code. |
| * @ingroup handler |
| * This is a backwards compatilibity module that allows code written |
| * in the old API to be run under the new handler based architecture. |
| * Use it by calling netsnmp_register_old_api(). |
| * @{ |
| */ |
| |
| /** returns a old_api handler that should be the final calling |
| * handler. Don't use this function. Use the netsnmp_register_old_api() |
| * function instead. |
| */ |
| netsnmp_mib_handler * |
| get_old_api_handler(void) |
| { |
| return netsnmp_create_handler("old_api", netsnmp_old_api_helper); |
| } |
| |
| |
| /** Registers an old API set into the mib tree. Functionally this |
| * mimics the old register_mib_context() function (and in fact the new |
| * register_mib_context() function merely calls this new old_api one). |
| */ |
| int |
| netsnmp_register_old_api(const char *moduleName, |
| struct variable *var, |
| size_t varsize, |
| size_t numvars, |
| oid * mibloc, |
| size_t mibloclen, |
| int priority, |
| int range_subid, |
| oid range_ubound, |
| netsnmp_session * ss, |
| const char *context, int timeout, int flags) |
| { |
| |
| unsigned int i; |
| |
| /* |
| * register all subtree nodes |
| */ |
| for (i = 0; i < numvars; i++) { |
| struct variable *vp; |
| netsnmp_handler_registration *reginfo = |
| SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration); |
| |
| vp = netsnmp_memdup((const struct variable *) |
| ((const char *) var + varsize * i), |
| varsize); |
| |
| reginfo->handler = get_old_api_handler(); |
| reginfo->handlerName = strdup(moduleName); |
| reginfo->rootoid_len = (mibloclen + vp->namelen); |
| reginfo->rootoid = |
| (oid *) malloc(reginfo->rootoid_len * sizeof(oid)); |
| |
| memcpy(reginfo->rootoid, mibloc, mibloclen * sizeof(oid)); |
| memcpy(reginfo->rootoid + mibloclen, vp->name, vp->namelen |
| * sizeof(oid)); |
| reginfo->handler->myvoid = (void *) vp; |
| |
| reginfo->priority = priority; |
| reginfo->range_subid = range_subid; |
| |
| reginfo->range_ubound = range_ubound; |
| reginfo->timeout = timeout; |
| reginfo->contextName = (context) ? strdup(context) : NULL; |
| reginfo->modes = HANDLER_CAN_RWRITE; |
| |
| /* |
| * register ourselves in the mib tree |
| */ |
| if (netsnmp_register_handler(reginfo) != MIB_REGISTERED_OK) { |
| /** netsnmp_handler_registration_free(reginfo); already freed */ |
| SNMP_FREE(vp); |
| } |
| } |
| return SNMPERR_SUCCESS; |
| } |
| |
| /** registers a row within a mib table */ |
| int |
| netsnmp_register_mib_table_row(const char *moduleName, |
| struct variable *var, |
| size_t varsize, |
| size_t numvars, |
| oid * mibloc, |
| size_t mibloclen, |
| int priority, |
| int var_subid, |
| netsnmp_session * ss, |
| const char *context, int timeout, int flags) |
| { |
| unsigned int i = 0, rc = 0; |
| oid ubound = 0; |
| |
| for (i = 0; i < numvars; i++) { |
| struct variable *vr = |
| (struct variable *) ((char *) var + (i * varsize)); |
| netsnmp_handler_registration *r; |
| if ( var_subid > (int)mibloclen ) { |
| break; /* doesn't make sense */ |
| } |
| r = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration); |
| |
| if (r == NULL) { |
| /* |
| * Unregister whatever we have registered so far, and |
| * return an error. |
| */ |
| rc = MIB_REGISTRATION_FAILED; |
| break; |
| } |
| memset(r, 0, sizeof(netsnmp_handler_registration)); |
| |
| r->handler = get_old_api_handler(); |
| r->handlerName = strdup(moduleName); |
| |
| if (r->handlerName == NULL) { |
| netsnmp_handler_registration_free(r); |
| break; |
| } |
| |
| r->rootoid_len = mibloclen; |
| r->rootoid = (oid *) malloc(r->rootoid_len * sizeof(oid)); |
| |
| if (r->rootoid == NULL) { |
| netsnmp_handler_registration_free(r); |
| rc = MIB_REGISTRATION_FAILED; |
| break; |
| } |
| memcpy(r->rootoid, mibloc, mibloclen * sizeof(oid)); |
| memcpy((u_char *) (r->rootoid + (var_subid - vr->namelen)), vr->name, |
| vr->namelen * sizeof(oid)); |
| DEBUGMSGTL(("netsnmp_register_mib_table_row", "rootoid ")); |
| DEBUGMSGOID(("netsnmp_register_mib_table_row", r->rootoid, |
| r->rootoid_len)); |
| DEBUGMSG(("netsnmp_register_mib_table_row", "(%d)\n", |
| (var_subid - vr->namelen))); |
| r->handler->myvoid = (void *) malloc(varsize); |
| |
| if (r->handler->myvoid == NULL) { |
| netsnmp_handler_registration_free(r); |
| rc = MIB_REGISTRATION_FAILED; |
| break; |
| } |
| memcpy((char *) r->handler->myvoid, vr, varsize); |
| |
| r->contextName = (context) ? strdup(context) : NULL; |
| |
| if (context != NULL && r->contextName == NULL) { |
| netsnmp_handler_registration_free(r); |
| rc = MIB_REGISTRATION_FAILED; |
| break; |
| } |
| |
| r->priority = priority; |
| r->range_subid = 0; /* var_subid; */ |
| r->range_ubound = 0; /* range_ubound; */ |
| r->timeout = timeout; |
| r->modes = HANDLER_CAN_RWRITE; |
| |
| /* |
| * Register this column and row |
| */ |
| if ((rc = |
| netsnmp_register_handler_nocallback(r)) != |
| MIB_REGISTERED_OK) { |
| DEBUGMSGTL(("netsnmp_register_mib_table_row", |
| "register failed %d\n", rc)); |
| netsnmp_handler_registration_free(r); |
| break; |
| } |
| |
| if (vr->namelen > 0) { |
| if (vr->name[vr->namelen - 1] > ubound) { |
| ubound = vr->name[vr->namelen - 1]; |
| } |
| } |
| } |
| |
| if (rc == MIB_REGISTERED_OK) { |
| struct register_parameters reg_parms; |
| |
| reg_parms.name = mibloc; |
| reg_parms.namelen = mibloclen; |
| reg_parms.priority = priority; |
| reg_parms.flags = (u_char) flags; |
| reg_parms.range_subid = var_subid; |
| reg_parms.range_ubound = ubound; |
| reg_parms.timeout = timeout; |
| reg_parms.contextName = context; |
| rc = snmp_call_callbacks(SNMP_CALLBACK_APPLICATION, |
| SNMPD_CALLBACK_REGISTER_OID, ®_parms); |
| } |
| |
| return rc; |
| } |
| |
| /** 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; |
| WriteMethod *write_method = NULL; |
| size_t len; |
| u_char *access = NULL; |
| netsnmp_old_api_cache *cacheptr; |
| netsnmp_agent_session *oldasp = NULL; |
| oid tmp_name[MAX_OID_LEN]; |
| size_t tmp_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: |
| case MODE_SET_RESERVE1: |
| /* |
| * 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 |
| */ |
| if (reqinfo->mode != MODE_SET_RESERVE1) |
| 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) |
| */ |
| if (reqinfo->mode != MODE_SET_RESERVE1) |
| 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)); |
| /* |
| * 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; |
| } |
| |
| /** @} */ |
| |
| /* |
| * don't use this! |
| */ |
| static netsnmp_agent_session *current_agent_session = NULL; |
| netsnmp_agent_session * |
| netsnmp_get_current_agent_session() |
| { |
| return current_agent_session; |
| } |
| |
| /* |
| * don't use this! |
| */ |
| void |
| set_current_agent_session(netsnmp_agent_session *asp) |
| { |
| current_agent_session = asp; |
| } |