/*++ Copyright (c) 1992-1997 Microsoft Corporation Module Name: subagnts.c Abstract: Contains definitions for manipulating subagent structures. Environment: User Mode - Win32 Revision History: 10-Feb-1997 DonRyan Rewrote to implement SNMPv2 support. --*/ /////////////////////////////////////////////////////////////////////////////// // // // Include files // // // /////////////////////////////////////////////////////////////////////////////// #include "globals.h" #include "subagnts.h" #include "regions.h" #include "snmpmgmt.h" /////////////////////////////////////////////////////////////////////////////// // // // Private procedures // // // /////////////////////////////////////////////////////////////////////////////// BOOL FindSubagent( PSUBAGENT_LIST_ENTRY * ppSLE, LPSTR pPathname ) /*++ Routine Description: Locates subagent in list. Arguments: ppSLE - pointer to receive pointer to entry. pPathname - pointer to pathname to find. Return Values: Returns true if successful. --*/ { PLIST_ENTRY pLE; PSUBAGENT_LIST_ENTRY pSLE; // initialize *ppSLE = NULL; // obtain pointer to head pLE = g_Subagents.Flink; // process all entries in list while (pLE != &g_Subagents) { // retrieve pointer to trap destination structure pSLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link); // compare pathname string with entry if (!strcmp(pSLE->pPathname, pPathname)) { // transfer *ppSLE = pSLE; // success return TRUE; } // next entry pLE = pLE->Flink; } // failure return FALSE; } BOOL AddSubagentRegion( PSUBAGENT_LIST_ENTRY pSLE, AsnObjectIdentifier * pPrefixOid ) /*++ Routine Description: Adds subagent supported region to structure. Arguments: pSLE - pointer to subagent structure. pPrefixOid - pointer to supported region. Return Values: Returns true if successful. --*/ { BOOL fOk = FALSE; PMIB_REGION_LIST_ENTRY pRLE = NULL; // allocate region if (AllocRLE(&pRLE)) { // copy prefix to structure if (SnmpUtilOidCpy(&pRLE->PrefixOid, pPrefixOid) == 0) { FreeRLE(pRLE); return fOk; } // copy prefix as temporary limit if (SnmpUtilOidCpy(&pRLE->LimitOid, pPrefixOid) == 0) { FreeRLE(pRLE); return fOk; } // save pointer pRLE->pSLE = pSLE; // modify limit oid to be one past the prefix ++pRLE->LimitOid.ids[pRLE->LimitOid.idLength - 1]; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: %s supports %s.\n", pSLE->pPathname, SnmpUtilOidToA(&pRLE->PrefixOid) )); // attach to mib region to subagent structure InsertTailList(&pSLE->SupportedRegions, &pRLE->Link); // success fOk = TRUE; } return fOk; } BOOL OfferInternalMgmtVariables( PSUBAGENT_LIST_ENTRY pSLE ) /*++ Routine Description: if the subagent is willing to monitor the SNMP service this function is offering it a pointer to the internal management variables Arguments: pSLE - pointer to subagent structure. Return Values: Returns true anyway. --*/ { if (pSLE->pfnSnmpExtensionMonitor != NULL) { __try { // attempt to initialize agent (*pSLE->pfnSnmpExtensionMonitor)(&snmpMgmtBase); } __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx offering internals to %s.\n", GetExceptionCode(), pSLE->pPathname )); // failure return FALSE; } } return TRUE; } BOOL LoadSubagentRegions( PSUBAGENT_LIST_ENTRY pSLE ) /*++ Routine Description: Loads subagent supported regions. Arguments: pSLE - pointer to subagent structure. Return Values: Returns true if successful. --*/ { BOOL fOk = FALSE; HANDLE hSubagentTrapEvent = NULL; AsnObjectIdentifier PrefixOid = { 0, NULL }; __try { // attempt to initialize agent if ((*pSLE->pfnSnmpExtensionInit)( g_dwUpTimeReference, &hSubagentTrapEvent, &PrefixOid )) { // store subagent trap event handle pSLE->hSubagentTrapEvent = hSubagentTrapEvent; // add subagent region to list entry fOk = AddSubagentRegion(pSLE, &PrefixOid); // check to see if subagent supports additional regions if (fOk && (pSLE->pfnSnmpExtensionInitEx != NULL)) { BOOL fMoreRegions = TRUE; // get other regions while (fOk && fMoreRegions) { // retrieve next supported region fMoreRegions = (*pSLE->pfnSnmpExtensionInitEx)( &PrefixOid ); // validate if (fMoreRegions) { // add subagent region to list entry fOk = AddSubagentRegion(pSLE, &PrefixOid); } } } } } __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx loading %s.\n", GetExceptionCode(), pSLE->pPathname )); // failure fOk = FALSE; } return fOk; } BOOL LoadSubagent( PSUBAGENT_LIST_ENTRY pSLE ) /*++ Routine Description: Loads subagent dll and initializes. Arguments: pSLE - pointer to subagent structure. Return Values: Returns true if successful. --*/ { BOOL fOk = FALSE; // attempt to load subagent library - we use the altered search path flag so that // the subagent can load DLLs that live in its directory pSLE->hSubagentDll = LoadLibraryExA(pSLE->pPathname, 0, LOAD_WITH_ALTERED_SEARCH_PATH); // validate handle if (pSLE->hSubagentDll != NULL) { // load primary initialization routine pSLE->pfnSnmpExtensionInit = (PFNSNMPEXTENSIONINIT) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_INIT ); // load secondary initialization routine pSLE->pfnSnmpExtensionInitEx = (PFNSNMPEXTENSIONINITEX) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_INIT_EX ); // load secondary initialization routine pSLE->pfnSnmpExtensionClose = (PFNSNMPEXTENSIONCLOSE) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_CLOSE ); // load the extension monitor routine pSLE->pfnSnmpExtensionMonitor = (PFNSNMPEXTENSIONMONITOR) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_MONITOR ); // load snmpv1-based subagent request routine pSLE->pfnSnmpExtensionQuery = (PFNSNMPEXTENSIONQUERY) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_QUERY ); // load snmpv2-based subagent request routine pSLE->pfnSnmpExtensionQueryEx = (PFNSNMPEXTENSIONQUERYEX) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_QUERY_EX ); // load snmpv1-based subagent trap routine pSLE->pfnSnmpExtensionTrap = (PFNSNMPEXTENSIONTRAP) GetProcAddress( pSLE->hSubagentDll, SNMP_EXTENSION_TRAP ); // validate subagent agent entry points if ((pSLE->pfnSnmpExtensionInit != NULL) && ((pSLE->pfnSnmpExtensionQuery != NULL) || (pSLE->pfnSnmpExtensionQueryEx != NULL))) { // load supported regions if (fOk = LoadSubagentRegions(pSLE)) // !!intentional assignement!! { // offering internal management variables; fOk = OfferInternalMgmtVariables(pSLE); } } } else { DWORD errCode = GetLastError(); LPTSTR pPathname; #ifdef UNICODE SnmpUtilUTF8ToUnicode(&pPathname, pSLE->pPathname, TRUE); #else pPathname = pSLE->pPathname; #endif SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error %d loading subagent.\n", errCode )); ReportSnmpEvent( SNMP_EVENT_INVALID_EXTENSION_AGENT_DLL, 1, &pPathname, errCode); #ifdef UNICODE SnmpUtilMemFree(pPathname); #endif } return fOk; } BOOL AddSubagentByDll( LPSTR pPathname, UCHAR uchInitFlags ) /*++ Routine Description: Adds subagent to list. Arguments: pPathname - pointer to subagent's dll path. Return Values: Returns true if successful. --*/ { BOOL fOk = FALSE; PSUBAGENT_LIST_ENTRY pSLE = NULL; // attempt to locate in list if (FindSubagent(&pSLE, pPathname)) { SNMPDBG(( SNMP_LOG_WARNING, "SNMP: SVC: duplicate entry for %s.\n", pPathname )); // success fOk = TRUE; } else { // allocate subagent structure if (AllocSLE(&pSLE, pPathname, uchInitFlags)) { SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: processing subagent %s.\n", pPathname )); // initialize subagent if (LoadSubagent(pSLE)) { // insert into valid communities list InsertTailList(&g_Subagents, &pSLE->Link); // success fOk = TRUE; } // cleanup if (!fOk) { // release FreeSLE(pSLE); } } } return fOk; } BOOL AddSubagentByKey( LPTSTR pKey ) /*++ Routine Description: Adds subagent to list. Arguments: pKey - pointer to subagent's registry key path. Return Values: Returns true if successful. --*/ { HKEY hKey; LONG lStatus; DWORD dwIndex; DWORD dwNameSize; DWORD dwValueSize; DWORD dwValueType; CHAR szName[MAX_PATH]; CHAR szValue[MAX_PATH]; BOOL fOk = FALSE; PSUBAGENT_LIST_ENTRY pSLE = NULL; // open registry subkey lStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pKey, 0, KEY_READ, &hKey ); // validate return code if (lStatus == ERROR_SUCCESS) { // initialize dwIndex = 0; // initialize buffer sizes dwNameSize = sizeof(szName)/sizeof(szName[0]); // size in TCHARs dwValueSize = sizeof(szValue); // size in bytes // loop until error or end of list while (lStatus == ERROR_SUCCESS) { // read next value lStatus = RegEnumValueA( hKey, dwIndex, szName, &dwNameSize, NULL, &dwValueType, szValue, &dwValueSize ); // validate return code if (lStatus == ERROR_SUCCESS) { if (dwValueType == REG_EXPAND_SZ || dwValueType == REG_SZ) { // check to see if value is pathname if (!_stricmp(szName, REG_VALUE_SUBAGENT_PATH)) { DWORD dwRequired; CHAR szExpanded[MAX_PATH]; // expand environment strings in path dwRequired = ExpandEnvironmentStringsA( szValue, szExpanded, sizeof(szExpanded)/sizeof(szExpanded[0]) ); if ((dwRequired != 0) && (dwRequired <= sizeof(szExpanded)/sizeof(szExpanded[0])) ) { // load subagent library - no flags set fOk = AddSubagentByDll(szExpanded, 0); } break; // bail... } } // initialize buffer sizes dwNameSize = sizeof(szName)/sizeof(szName[0]); dwValueSize = sizeof(szValue); // next dwIndex++; } else if (lStatus == ERROR_NO_MORE_ITEMS) { // failure fOk = FALSE; } } // release handle RegCloseKey(hKey); } else { // the registry key for this subagent could not be located. ReportSnmpEvent( SNMP_EVENT_INVALID_EXTENSION_AGENT_KEY, 1, &pKey, lStatus); } return fOk; } /////////////////////////////////////////////////////////////////////////////// // // // Public procedures // // // /////////////////////////////////////////////////////////////////////////////// BOOL AllocSLE( PSUBAGENT_LIST_ENTRY * ppSLE, LPSTR pPathname, UCHAR uchInitFlags ) /*++ Routine Description: Allocates trap destination structure and initializes. Arguments: ppSLE - pointer to receive pointer to entry. pPathname - pointer to subgent's dll path. Return Values: Returns true if successful. --*/ { BOOL fOk = FALSE; PSUBAGENT_LIST_ENTRY pSLE = NULL; // attempt to allocate structure pSLE = AgentMemAlloc(sizeof(SUBAGENT_LIST_ENTRY)); // validate if (pSLE != NULL) { // allocate memory for trap destination string pSLE->pPathname = AgentMemAlloc(strlen(pPathname)+1); // validate if (pSLE->pPathname != NULL) { // transfer trap destination string strcpy(pSLE->pPathname, pPathname); // set the initial flags value pSLE->uchFlags = uchInitFlags; // initialize list of supported regions InitializeListHead(&pSLE->SupportedRegions); // success fOk = TRUE; } // cleanup if (!fOk) { // release FreeSLE(pSLE); // re-init pSLE = NULL; } } // transfer *ppSLE = pSLE; return fOk; } BOOL FreeSLE( PSUBAGENT_LIST_ENTRY pSLE ) /*++ Routine Description: Releases subagent structure. Arguments: pSLE - pointer to list entry to be freed. Return Values: Returns true if successful. --*/ { BOOL fOk = TRUE; // validate pointer if (pSLE != NULL) { SNMPDBG(( SNMP_LOG_VERBOSE, "SNMP: SVC: unloading %s.\n", pSLE->pPathname )); // release manager structures UnloadRegions(&pSLE->SupportedRegions); // validate subagent dll handle if (pSLE->hSubagentDll != NULL) { __try { if (pSLE->pfnSnmpExtensionClose != NULL) (*pSLE->pfnSnmpExtensionClose)(); } __except (EXCEPTION_EXECUTE_HANDLER) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: exception 0x%08lx unloading %s.\n", GetExceptionCode(), pSLE->pPathname )); } // unload subagent FreeLibrary(pSLE->hSubagentDll); pSLE->hSubagentDll = NULL; } // release string AgentMemFree(pSLE->pPathname); // release structure AgentMemFree(pSLE); } return TRUE; } BOOL LoadSubagents( ) /*++ Routine Description: Constructs list of subagents. Arguments: None. Return Values: Returns true if successful. --*/ { HKEY hKey; LONG lStatus; DWORD dwIndex; DWORD dwNameSize; DWORD dwValueSize; DWORD dwValueType; TCHAR szName[MAX_PATH]; TCHAR szValue[MAX_PATH]; LPTSTR pszKey = REG_KEY_EXTENSION_AGENTS; BOOL fOk = FALSE; SNMPDBG(( SNMP_LOG_TRACE, "SNMP: SVC: loading subagents.\n" )); // Open the ..SNMP\Parameters\ExtensionAgents subkey lStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, pszKey, 0, KEY_READ, &hKey ); // validate return code if (lStatus == ERROR_SUCCESS) { // initialize dwIndex = 0; // initialize buffer sizes dwNameSize = sizeof(szName) / sizeof(szName[0]); // size in number of TCHARs dwValueSize = sizeof(szValue); // size in number of bytes // loop until error or end of list while (lStatus == ERROR_SUCCESS) { // read next value lStatus = RegEnumValue( hKey, dwIndex, szName, &dwNameSize, NULL, &dwValueType, (LPBYTE)szValue, &dwValueSize ); // validate return code if (lStatus == ERROR_SUCCESS) { if (dwValueType == REG_SZ) { // add subagent to list AddSubagentByKey(szValue); } // re-initialize buffer sizes dwNameSize = sizeof(szName) / sizeof(szName[0]); // size in number of TCHARs dwValueSize = sizeof(szValue); // size in number of bytes // next dwIndex++; } else if (lStatus == ERROR_NO_MORE_ITEMS) { // success fOk = TRUE; } } } if (!fOk) { SNMPDBG(( SNMP_LOG_ERROR, "SNMP: SVC: error %d processing Subagents subkey.\n", lStatus )); // report event ReportSnmpEvent( SNMP_EVENT_INVALID_REGISTRY_KEY, 1, &pszKey, lStatus ); } return fOk; } BOOL UnloadSubagents( ) /*++ Routine Description: Destroys list of subagents. Arguments: None. Return Values: Returns true if successful. --*/ { PLIST_ENTRY pLE; PSUBAGENT_LIST_ENTRY pSLE; // process entries until list is empty while (!IsListEmpty(&g_Subagents)) { // extract next entry from head of list pLE = RemoveHeadList(&g_Subagents); // retrieve pointer to community structure pSLE = CONTAINING_RECORD(pLE, SUBAGENT_LIST_ENTRY, Link); // release FreeSLE(pSLE); } return TRUE; }