/* * Portions of this file are subject to the following copyright(s). See * the Net-SNMP's COPYING file for more details and other copyrights * that may apply: * * Portions of this file are copyrighted by: * Copyright (c) 2016 VMware, Inc. All rights reserved. * Use is subject to license terms specified in the COPYING file * distributed with the Net-SNMP package. */ #include #include #include #include #if HAVE_STRING_H #include #else #include #endif #include #include #define MIB_CLIENTS_ARE_EVIL 1 #ifdef HAVE_DMALLOC_H static void free_wrapper(void * p) { free(p); } #else #define free_wrapper free #endif /* * don't use these! */ void set_current_agent_session(netsnmp_agent_session *asp); /** @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); } struct variable * netsnmp_duplicate_variable(const struct variable *var) { struct variable *var2 = NULL; if (var) { const int varsize = offsetof(struct variable, name) + var->namelen * sizeof(var->name[0]); var2 = malloc(varsize); if (var2) memcpy(var2, var, varsize); } return var2; } /** 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, const struct variable *var, size_t varsize, size_t numvars, const 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; int res; /* * register all subtree nodes */ for (i = 0; i < numvars; i++) { struct variable *vp; netsnmp_handler_registration *reginfo = SNMP_MALLOC_TYPEDEF(netsnmp_handler_registration); if (reginfo == NULL) return SNMP_ERR_GENERR; vp = netsnmp_duplicate_variable((const struct variable *) ((const char *) var + varsize * i)); 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)); if (NULL == reginfo->handler || NULL == reginfo->handlerName || NULL == reginfo->rootoid) { netsnmp_handler_free(reginfo->handler); SNMP_FREE(vp); SNMP_FREE(reginfo->handlerName); SNMP_FREE(reginfo->rootoid); SNMP_FREE(reginfo); return SNMP_ERR_GENERR; } memcpy(reginfo->rootoid, mibloc, mibloclen * sizeof(oid)); memcpy(reginfo->rootoid + mibloclen, vp->name, vp->namelen * sizeof(oid)); reginfo->handler->myvoid = (void *) vp; reginfo->handler->data_clone = (void *(*)(void *))netsnmp_duplicate_variable; reginfo->handler->data_free = free; reginfo->priority = priority; reginfo->range_subid = range_subid; reginfo->range_ubound = range_ubound; reginfo->timeout = timeout; reginfo->contextName = (context) ? strdup(context) : NULL; reginfo->modes = vp->acl == NETSNMP_OLDAPI_RONLY ? HANDLER_CAN_RONLY : HANDLER_CAN_RWRITE; /* * register ourselves in the mib tree */ res = netsnmp_register_handler(reginfo); if (MIB_REGISTERED_OK != res) { /** reginfo already freed on error. */ snmp_log(LOG_WARNING, "old_api handler registration failed\n"); return res; } } return SNMPERR_SUCCESS; } /** registers a row within a mib table */ int netsnmp_register_mib_table_row(const char *moduleName, const 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++) { const struct variable *vr = (const struct variable *) ((const 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. */ snmp_log(LOG_ERR, "mib table row registration failed\n"); rc = MIB_REGISTRATION_FAILED; break; } r->handler = get_old_api_handler(); r->handlerName = strdup(moduleName); r->rootoid_len = mibloclen; r->rootoid = (oid *) malloc(r->rootoid_len * sizeof(oid)); if (r->handler == NULL || r->handlerName == NULL || 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 = netsnmp_duplicate_variable(vr); r->handler->data_clone = (void *(*)(void *))netsnmp_duplicate_variable; r->handler->data_free = free; r->contextName = (context) ? strdup(context) : NULL; if (r->handler->myvoid == NULL || (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) { snmp_log(LOG_ERR, "mib table row registration failed\n"); DEBUGMSGTL(("netsnmp_register_mib_table_row", "register failed %d\n", rc)); /** reginfo already freed */ 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; 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) { tmp_len = requests->requestvb->name_length*sizeof(oid); memcpy(tmp_name, requests->requestvb->name, tmp_len); /** clear the rest of tmp_name to keep valgrind happy */ memset(&tmp_name[requests->requestvb->name_length], 0x0, sizeof(tmp_name)-tmp_len); 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) */ /* FALL THROUGH */ 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(void) { return current_agent_session; } /* * don't use this! */ void set_current_agent_session(netsnmp_agent_session *asp) { current_agent_session = asp; }