/*++ Copyright (c) 1998-1999 Microsoft Corporation Module Name: routing\netsh\shell\reghlp.c Abstract: To get information about helper DLLs from registry. Revision History: Anand Mahalingam 7/06/98 Created Dave Thaler 11/13/98 Revised --*/ #include "precomp.h" #define MALLOC(x) HeapAlloc(GetProcessHeap(), 0, (x)) #define FREE(x) HeapFree(GetProcessHeap(), 0, (x)) #define DLL_INIT_FN "InitHelperDll" #define DLL_INIT_FN_NAME L"InitHelperDll" #define REG_KEY_NETSH_HELPER L"SOFTWARE\\Microsoft\\NetSh" PNS_HELPER_TABLE_ENTRY g_CurrentHelper = NULL; PCNS_CONTEXT_ATTRIBUTES g_CurrentContext = NULL; /* fa85c48a-68d7-4a8c-891c-2360edc4d78 */ #define NETSH_NULL_GUID \ { 0xfa85c48a, 0x68d7, 0x4a8c, {0x89, 0x1c, 0x23, 0x60, 0xed, 0xc4, 0xd7, 0x8} }; static const GUID g_NetshGuid = NETSH_ROOT_GUID; static const GUID g_NullGuid = NETSH_NULL_GUID; // // Initialize helper Table // PNS_HELPER_TABLE_ENTRY g_HelperTable; DWORD g_dwNumHelpers = 0; PNS_DLL_TABLE_ENTRY g_DllTable; DWORD g_dwNumDlls = 0; // This variable maintains the index of the Dll currently being called out to. DWORD g_dwDllIndex; DWORD WINAPI RegisterContext( IN CONST NS_CONTEXT_ATTRIBUTES *pChildContext ); DWORD FindHelper( IN CONST GUID *pguidHelper, OUT PDWORD pdwIndex ); DWORD GenericDeleteContext( IN PNS_HELPER_TABLE_ENTRY pParentHelper, IN DWORD dwContextIdx ); DWORD CommitSubContexts( IN PNS_HELPER_TABLE_ENTRY pHelper, IN DWORD dwAction ); DWORD WINAPI InitHelperDll( IN DWORD dwNetshVersion, OUT PVOID pReserved ); DWORD UninstallDll( IN LPCWSTR pwszConfigDll, IN BOOL fDeleteFromRegistry ); // // Local copy of the commit state. // BOOL g_bCommit = TRUE; int __cdecl ContextCmp( const void *a, const void *b ) { PCNS_CONTEXT_ATTRIBUTES pCA = (PCNS_CONTEXT_ATTRIBUTES)a; PCNS_CONTEXT_ATTRIBUTES pCB = (PCNS_CONTEXT_ATTRIBUTES)b; ULONG ulPriA = (pCA->dwFlags & CMD_FLAG_PRIORITY)? pCA->ulPriority : DEFAULT_CONTEXT_PRIORITY; ULONG ulPriB = (pCB->dwFlags & CMD_FLAG_PRIORITY)? pCB->ulPriority : DEFAULT_CONTEXT_PRIORITY; return ulPriA - ulPriB; } DWORD DumpContext( IN PCNS_CONTEXT_ATTRIBUTES pContext, IN LPWSTR *ppwcArguments, IN DWORD dwArgCount, IN LPCVOID pvData ) { DWORD dwErr = NO_ERROR; PNS_HELPER_TABLE_ENTRY pChildHelper; do { if (pContext->pfnDumpFn) { dwErr = pContext->pfnDumpFn( g_pwszRouterName, ppwcArguments, dwArgCount, pvData ); if (dwErr) { break; } } // Dump child contexts (even if parent didn't have a dump function) dwErr = GetHelperEntry(&pContext->guidHelper, &pChildHelper); if (dwErr) { break; } dwErr = DumpSubContexts(pChildHelper, ppwcArguments, dwArgCount, pvData); if (dwErr) { break; } } while (FALSE); return NO_ERROR; } DWORD DumpSubContexts( IN PNS_HELPER_TABLE_ENTRY pHelper, IN LPWSTR *ppwcArguments, IN DWORD dwArgCount, IN LPCVOID pvData ) { DWORD i, dwSize, dwErr = NO_ERROR; PCNS_CONTEXT_ATTRIBUTES pSubContext; PBYTE pSubContextTable; // Copy contexts for sorting dwSize =pHelper->ulNumSubContexts * pHelper->ulSubContextSize; pSubContextTable = MALLOC( dwSize ); if (!pSubContextTable) { return ERROR_NOT_ENOUGH_MEMORY; } memcpy(pSubContextTable, pHelper->pSubContextTable, dwSize ); // Sort copy of contexts by priority qsort(pSubContextTable, pHelper->ulNumSubContexts, pHelper->ulSubContextSize, ContextCmp); for (i = 0; i < pHelper->ulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pSubContextTable + i*pHelper->ulSubContextSize); dwErr = DumpContext( pSubContext, ppwcArguments, dwArgCount, pvData ); if (dwErr) { break; } } // Free contexts for sorting FREE(pSubContextTable); return dwErr; } DWORD CommitContext( IN PCNS_CONTEXT_ATTRIBUTES pContext, IN DWORD dwAction ) { DWORD dwErr = NO_ERROR; PNS_HELPER_TABLE_ENTRY pChildHelper; do { if (pContext->pfnCommitFn) { // No need to call connect since you cannot change machines in // offline mode dwErr = pContext->pfnCommitFn(dwAction); if (dwErr) { break; } } // Commit child contexts (even if parent didn't have a commit function) dwErr = GetHelperEntry(&pContext->guidHelper, &pChildHelper); if (dwErr) { break; } dwErr = CommitSubContexts(pChildHelper, dwAction); if (dwErr) { break; } } while (FALSE); return NO_ERROR; } DWORD CommitSubContexts( IN PNS_HELPER_TABLE_ENTRY pHelper, IN DWORD dwAction ) { DWORD i, dwSize, dwErr = NO_ERROR; PCNS_CONTEXT_ATTRIBUTES pSubContext; PBYTE pSubContextTable; // Copy contexts for sorting dwSize =pHelper->ulNumSubContexts * pHelper->ulSubContextSize; pSubContextTable = MALLOC( dwSize ); if (!pSubContextTable) { return ERROR_NOT_ENOUGH_MEMORY; } memcpy(pSubContextTable, pHelper->pSubContextTable, dwSize ); // Sort copy of contexts by priority qsort(pSubContextTable, pHelper->ulNumSubContexts, pHelper->ulSubContextSize, ContextCmp); for (i = 0; i < pHelper->ulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pSubContextTable + i*pHelper->ulSubContextSize); dwErr = CommitContext(pSubContext, dwAction); if (dwErr) { break; } } // Free contexts for sorting FREE(pSubContextTable); return dwErr; } DWORD CallCommit( IN DWORD dwAction, OUT BOOL *pbCommit ) /*++ Routine Description: Calls commit for all the transports. Arguments: dwAction - What to do. Could be one of COMMIT, UNCOMMIT, FLUSH, COMMIT_STATE pbCommit - The current commit state. Return Value: NO_ERROR --*/ { DWORD i, dwErr; PHELPER_ENTRY_FN pfnEntry; PCNS_CONTEXT_ATTRIBUTES pContext, pSubContext; PNS_HELPER_TABLE_ENTRY pHelper; switch (dwAction) { case NETSH_COMMIT_STATE : *pbCommit = g_bCommit; return NO_ERROR; case NETSH_COMMIT : g_bCommit = TRUE; break; case NETSH_UNCOMMIT : g_bCommit = FALSE; default : break; } // // Call commit for each sub context // dwErr = GetRootContext( &pContext, &pHelper ); if (dwErr) { return dwErr; } dwErr = CommitContext( pContext, dwAction ); if (dwErr isnot NO_ERROR) { PrintMessageFromModule(g_hModule, MSG_COMMIT_ERROR, pContext->pwszContext); dwErr = ERROR_SUPPRESS_OUTPUT; } return dwErr; } DWORD FindHelper( IN CONST GUID *pguidHelper, OUT PDWORD pdwIndex ) { DWORD i; for (i=0; iguidParent, &pParentHelper); if (dwErr) { return dwErr; } for (j=0; julNumSubContexts; j++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pParentHelper->pSubContextTable + j*pParentHelper->ulSubContextSize); if (!memcmp( &pSubContext->guidHelper, pguidChild, sizeof(GUID) )) { GenericDeleteContext(pParentHelper, j); j--; } } return dwErr; } DWORD DeleteHelper( IN DWORD dwHelperIdx ) { DWORD j, dwErr, dwParentIndex; PNS_HELPER_TABLE_ENTRY phtTmp = NULL; // Tell parent helper to // uninstall all contexts for this helper dwErr = FindHelper(&g_HelperTable[dwHelperIdx].guidParent, &dwParentIndex); if (dwErr is NO_ERROR) { GenericDeregisterAllContexts(&g_HelperTable[dwHelperIdx].nha.guidHelper); } phtTmp = MALLOC((g_dwNumHelpers - 1) * sizeof(NS_HELPER_TABLE_ENTRY)); if (phtTmp is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } CopyMemory(phtTmp, g_HelperTable, dwHelperIdx * sizeof(NS_HELPER_TABLE_ENTRY)); CopyMemory(phtTmp + dwHelperIdx, g_HelperTable + dwHelperIdx + 1, (g_dwNumHelpers - 1 - dwHelperIdx) * sizeof(NS_HELPER_TABLE_ENTRY)); g_dwNumHelpers --; FREE(g_HelperTable); g_HelperTable = phtTmp; return ERROR_SUCCESS; } DWORD GetHelperEntry( IN CONST GUID *pGuid, OUT PNS_HELPER_TABLE_ENTRY *ppHelper ) { DWORD i, dwErr; dwErr = FindHelper(pGuid, &i); if (dwErr is NO_ERROR) { *ppHelper = &g_HelperTable[i]; } return dwErr; } DWORD GetDllEntry( IN DWORD dwDllIndex, OUT PNS_DLL_TABLE_ENTRY *ppDll ) { *ppDll = &g_DllTable[ dwDllIndex ]; return NO_ERROR; } DWORD RegisterHelper( IN CONST GUID *pguidParent, IN CONST NS_HELPER_ATTRIBUTES *pAttributes ) { DWORD i, dwErr; dwErr = FindHelper(&pAttributes->guidHelper, &i); if (dwErr is NO_ERROR) { return ERROR_HELPER_ALREADY_REGISTERED; } //if pguidParent is NULL, the caller means the parent is netsh (g_NetshGuid) if (!pguidParent) { pguidParent = &g_NetshGuid; } // Make sure we don't cause a recursive registration. if (IsEqualGUID(&pAttributes->guidHelper, pguidParent)) { if (! (IsEqualGUID(&pAttributes->guidHelper, &g_NullGuid) && IsEqualGUID(pguidParent, &g_NullGuid) ) ) { ASSERT(FALSE); return ERROR_INVALID_PARAMETER; } } return AddHelper(pguidParent, pAttributes); } VOID ConvertGuidToString( IN CONST GUID *pGuid, OUT LPWSTR pwszBuffer ) { wsprintf(pwszBuffer, L"{%08X-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X}", pGuid->Data1, pGuid->Data2, pGuid->Data3, pGuid->Data4[0], pGuid->Data4[1], pGuid->Data4[2], pGuid->Data4[3], pGuid->Data4[4], pGuid->Data4[5], pGuid->Data4[6], pGuid->Data4[7]); } DWORD ConvertStringToGuid( IN LPCWSTR pwszGuid, IN USHORT usStringLen, OUT GUID *pGuid ) { UNICODE_STRING Temp; Temp.Length = Temp.MaximumLength = usStringLen; Temp.Buffer = (LPWSTR)pwszGuid; if(RtlGUIDFromString(&Temp, pGuid) isnot STATUS_SUCCESS) { return ERROR_INVALID_PARAMETER; } return NO_ERROR; } DWORD LoadDll( DWORD dwIdx ) { HANDLE hDll; DWORD dwErr; PNS_DLL_INIT_FN pfnLoadFn; NS_DLL_ATTRIBUTES DllTable; g_dwDllIndex = dwIdx; // // Try to load DLL into memory. // if (dwIdx is 0) { // Netsh internal helper hDll = g_hModule; pfnLoadFn = InitHelperDll; } else { hDll = LoadLibraryW(g_DllTable[dwIdx].pwszDLLName); if (hDll is NULL) { PrintMessageFromModule( g_hModule, MSG_DLL_LOAD_FAILED, g_DllTable[dwIdx].pwszDLLName ); return ERROR_SUPPRESS_OUTPUT; } pfnLoadFn = (PNS_DLL_INIT_FN) GetProcAddress(hDll, DLL_INIT_FN); } if (!pfnLoadFn) { PrintMessageFromModule( g_hModule, EMSG_DLL_FN_NOT_FOUND, DLL_INIT_FN_NAME, g_DllTable[dwIdx].pwszDLLName ); FreeLibrary(hDll); g_DllTable[dwIdx].hDll = NULL; return ERROR_SUPPRESS_OUTPUT; } g_DllTable[dwIdx].hDll = hDll; memset(&DllTable, 0, sizeof(DllTable)); dwErr = (pfnLoadFn)( NETSH_VERSION_50, &DllTable ); if (dwErr == NO_ERROR) { g_DllTable[dwIdx].bLoaded = TRUE; g_DllTable[dwIdx].pfnStopFn = DllTable.pfnStopFn; } else { PrintMessageFromModule( g_hModule, MSG_DLL_START_FAILED, DLL_INIT_FN_NAME, g_DllTable[dwIdx].pwszDLLName, dwErr ); UninstallDll(g_DllTable[dwIdx].pwszDLLName, FALSE); } return NO_ERROR; } VOID StartNewHelpers() /*++ Description: Recursively start all unstarted helpers whose parent (if any) is started. --*/ { BOOL bFound = FALSE; DWORD i, dwParentIndex, dwErr, dwVersion; // Mark root as started g_HelperTable[0].bStarted = TRUE; // Repeat until we couldn't find any helper to start do { bFound = FALSE; // Look for a startable helper for (i=0; i i) { g_HelperTable[j].dwDllIndex--; } } // // Unload the dll if it was loaded // if (g_DllTable[i].bLoaded) { #if 0 if (pHelperTable[i].pfnUnInitFn) (pHelperTable[i].pfnUnInitFn)(0); #endif FreeLibrary(g_DllTable[i].hDll); } FREE(g_DllTable); g_DllTable = phtTmp; return ERROR_SUCCESS; } VOID LoadDllInfoFromRegistry( VOID ) /*++ Routine Description: Loads information about the helper DLLs from the registry. Arguments: Return Value: --*/ { DWORD dwResult, i, dwMaxValueLen, dwValueLen; DWORD dwMaxValueNameLen, dwValueNameLen; DWORD dwSize,dwType,dwNumDlls; FILETIME ftLastTime; HKEY hkeyDlls = NULL; LPWSTR pwValue = NULL; LPWSTR pwValueName = NULL; do { // // Open Base Key // dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, REG_KEY_NETSH_HELPER, 0, KEY_READ, &hkeyDlls); if(dwResult != NO_ERROR) { break; } // // Get Number of DLLs // dwResult = RegQueryInfoKey(hkeyDlls, NULL, NULL, NULL, NULL, NULL, NULL, &dwNumDlls, &dwMaxValueNameLen, &dwMaxValueLen, NULL, NULL); if(dwResult != NO_ERROR) { break; } if(dwNumDlls == 0) { // // Nothing registered // break; } // // Key len is in WCHARS // dwSize = dwMaxValueNameLen + 1; pwValueName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize * sizeof(WCHAR)); if(pwValueName is NULL) { PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY); break; } dwSize = dwMaxValueLen + 1; pwValue = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwSize); if(pwValue is NULL) { FREE(pwValueName); PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY); break; } for(i = 0; i < dwNumDlls; i++) { dwValueLen = dwMaxValueLen + 1; dwValueNameLen = dwMaxValueNameLen + 1; dwResult = RegEnumValueW(hkeyDlls, i, pwValueName, &dwValueNameLen, NULL, NULL, (PBYTE)pwValue, &dwValueLen); if(dwResult isnot NO_ERROR) { if(dwResult is ERROR_NO_MORE_ITEMS) { // // Done // break; } continue; } dwResult = AddDllEntry(pwValueName, pwValue); } } while (FALSE); if (hkeyDlls) { RegCloseKey(hkeyDlls); } if (pwValueName) { FREE(pwValueName); } if (pwValue) { FREE(pwValue); } StartNewHelpers(); return; } DWORD GetContextEntry( IN PNS_HELPER_TABLE_ENTRY pHelper, IN LPCWSTR pwszContext, OUT PCNS_CONTEXT_ATTRIBUTES *ppContext ) { DWORD k; PCNS_CONTEXT_ATTRIBUTES pSubContext; for ( k = 0 ; k < pHelper->ulNumSubContexts ; k++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pHelper->pSubContextTable + k*pHelper->ulSubContextSize); if (MatchToken(pwszContext, pSubContext->pwszContext)) { *ppContext = (PCNS_CONTEXT_ATTRIBUTES)pSubContext; return NO_ERROR; } } return ERROR_NOT_FOUND; } DWORD FreeHelpers( VOID ) { DWORD i; for (i = 0; i < g_dwNumHelpers; i++) { if (g_HelperTable[i].nha.pfnStop) (g_HelperTable[i].nha.pfnStop)(0); } FREE(g_HelperTable); return NO_ERROR; } DWORD FreeDlls( VOID ) { DWORD i; for (i = 0; i < g_dwNumDlls; i++) { if (g_DllTable[i].bLoaded) { FreeLibrary(g_DllTable[i].hDll); } } FREE(g_DllTable); return NO_ERROR; } DWORD ShowHelpers( PNS_HELPER_TABLE_ENTRY pHelper, DWORD dwLevel ) { DWORD i, dwDllIndex, dwErr = NO_ERROR, j; WCHAR rgwcHelperGuid[MAX_NAME_LEN]; PCNS_CONTEXT_ATTRIBUTES pSubContext; PNS_HELPER_TABLE_ENTRY pChildHelper; for (i = 0; i < pHelper->ulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pHelper->pSubContextTable + i*pHelper->ulSubContextSize); dwErr = GetHelperEntry( &pSubContext->guidHelper, &pChildHelper ); if (dwErr) { return dwErr; } ConvertGuidToString(&pSubContext->guidHelper, rgwcHelperGuid); dwDllIndex = pChildHelper->dwDllIndex; PrintMessageFromModule( g_hModule, MSG_SHOW_HELPER_INFO, rgwcHelperGuid, g_DllTable[dwDllIndex].pwszDLLName ); for (j=0; jpwszContext ); dwErr = ShowHelpers( pChildHelper, dwLevel+1 ); } return dwErr; } DWORD HandleShowHelper( LPCWSTR pwszMachine, LPWSTR *ppwcArguments, DWORD dwCurrentIndex, DWORD dwArgCount, DWORD dwFlags, PVOID pvData, BOOL *pbDone ) /*++ Routine Description: Arguments: None Return Value: None --*/ { DWORD i, dwHelperIdx, dwDllIndex, dwErr = NO_ERROR; WCHAR rgwcHelperGuid[MAX_NAME_LEN]; PNS_HELPER_TABLE_ENTRY pHelper = g_CurrentHelper; PCNS_CONTEXT_ATTRIBUTES pContext; WCHAR rgwcParentGuid[MAX_NAME_LEN]; BOOL bFound; dwErr = GetRootContext(&pContext, &pHelper); if (dwErr isnot NO_ERROR) { return dwErr; } PrintMessageFromModule(g_hModule, MSG_SHOW_HELPER_HDR); ShowHelpers(pHelper, 0); // Show orphaned DLLs for (bFound=FALSE,i=0; iulNumSubContexts - 1) * pParentHelper->ulSubContextSize); if (phtTmp is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } CopyMemory(phtTmp, pParentHelper->pSubContextTable, dwContextIdx * pParentHelper->ulSubContextSize); CopyMemory(phtTmp + dwContextIdx * pParentHelper->ulSubContextSize, pParentHelper->pSubContextTable + (dwContextIdx + 1) * pParentHelper->ulSubContextSize, (pParentHelper->ulNumSubContexts - 1 - dwContextIdx) * pParentHelper->ulSubContextSize); pParentHelper->ulNumSubContexts --; FREE(pParentHelper->pSubContextTable); pParentHelper->pSubContextTable = phtTmp; return ERROR_SUCCESS; } DWORD GenericFindContext( IN PNS_HELPER_TABLE_ENTRY pParentHelper, IN LPCWSTR pwszContext, OUT PDWORD pdwIndex ) { DWORD i; PCNS_CONTEXT_ATTRIBUTES pSubContext; for (i=0; iulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pParentHelper->pSubContextTable + i*pParentHelper->ulSubContextSize); if (!_wcsicmp(pwszContext, pSubContext->pwszContext)) { *pdwIndex = i; return NO_ERROR; } } return ERROR_NOT_FOUND; } DWORD GenericAddContext( IN PNS_HELPER_TABLE_ENTRY pParentHelper, IN PCNS_CONTEXT_ATTRIBUTES pChildContext ) { PBYTE phtTmp; DWORD i; PCNS_CONTEXT_ATTRIBUTES pSubContext; // Find where in the table the new entry should go for (i=0; iulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pParentHelper->pSubContextTable + i*pParentHelper->ulSubContextSize); if (_wcsicmp(pChildContext->pwszContext, pSubContext->pwszContext) < 0) { break; } } // // Need to add entries in the context table // phtTmp = MALLOC((pParentHelper->ulNumSubContexts + 1) * pParentHelper->ulSubContextSize ); if (phtTmp is NULL) { return ERROR_NOT_ENOUGH_MEMORY; } // Copy all contexts which come before the new one if (i > 0) { CopyMemory(phtTmp, pParentHelper->pSubContextTable, i * pParentHelper->ulSubContextSize); } CopyMemory(phtTmp + i*pParentHelper->ulSubContextSize, pChildContext, pParentHelper->ulSubContextSize); // Copy any contexts which come after the new one if (i < pParentHelper->ulNumSubContexts) { CopyMemory(phtTmp + (i+1)*pParentHelper->ulSubContextSize, pParentHelper->pSubContextTable + i*pParentHelper->ulSubContextSize, (pParentHelper->ulNumSubContexts - i) * pParentHelper->ulSubContextSize); } (pParentHelper->ulNumSubContexts) ++; FREE(pParentHelper->pSubContextTable); pParentHelper->pSubContextTable = phtTmp; return ERROR_SUCCESS; } DWORD WINAPI RegisterContext( IN CONST NS_CONTEXT_ATTRIBUTES *pChildContext ) { DWORD dwErr, i; PNS_HELPER_TABLE_ENTRY pParentHelper; CONST GUID *pguidParent; ULONG nGroups, nSubGroups; if (!pChildContext) { return ERROR_INVALID_PARAMETER; } if ( (!pChildContext->pwszContext) || (wcslen(pChildContext->pwszContext) == 0) || (wcschr(pChildContext->pwszContext, L' ') != 0) || (wcschr(pChildContext->pwszContext, L'=') != 0) ) { return ERROR_INVALID_PARAMETER; } for (nGroups = 0; nGroups < pChildContext->ulNumTopCmds; nGroups++) { CMD_ENTRY *cmd = &((*pChildContext->pTopCmds)[nGroups]); if ( (!cmd->pwszCmdToken) || (wcslen(cmd->pwszCmdToken) == 0) || (wcschr(cmd->pwszCmdToken, L' ') != 0) || (wcschr(cmd->pwszCmdToken, L'=') != 0) ) { PrintMessageFromModule(g_hModule, MSG_INVALID_TOPLEVEL_CMD, cmd->pwszCmdToken); ASSERT(FALSE); } } for (nGroups = 0; nGroups < pChildContext->ulNumGroups; nGroups++) { CMD_GROUP_ENTRY *grpCmd = &((*pChildContext->pCmdGroups)[nGroups]); if ( (!grpCmd->pwszCmdGroupToken) || (wcslen(grpCmd->pwszCmdGroupToken) == 0) || (wcschr(grpCmd->pwszCmdGroupToken, L' ') != 0) || (wcschr(grpCmd->pwszCmdGroupToken, L'=') != 0) ) { PrintMessageFromModule(g_hModule, MSG_INVALID_CMD_GROUP, grpCmd->pwszCmdGroupToken); ASSERT(FALSE); } for (nSubGroups = 0; nSubGroups < grpCmd->ulCmdGroupSize; nSubGroups++) { CMD_ENTRY *cmd = &((grpCmd->pCmdGroup)[nSubGroups]); if ( (!cmd->pwszCmdToken) || (wcslen(cmd->pwszCmdToken) == 0) || (wcschr(cmd->pwszCmdToken, L' ') != 0) || (wcschr(cmd->pwszCmdToken, L'=') != 0) ) { PrintMessageFromModule(g_hModule, MSG_INVALID_CMD, cmd->pwszCmdToken); ASSERT(FALSE); } } } // Get parent guid from child guid dwErr = FindHelper( &pChildContext->guidHelper, &i ); if (dwErr) { return dwErr; } pguidParent = &g_HelperTable[i].guidParent; dwErr = GetHelperEntry( pguidParent, &pParentHelper ); if (dwErr) { return dwErr; } dwErr = GenericFindContext(pParentHelper, pChildContext->pwszContext, &i); if (dwErr is NO_ERROR) { CopyMemory( pParentHelper->pSubContextTable + i*pParentHelper->ulSubContextSize, pChildContext, pParentHelper->ulSubContextSize ); return NO_ERROR; } return GenericAddContext( pParentHelper, pChildContext ); } DWORD WINAPI GetHostMachineInfo( IN OUT UINT *puiCIMOSType, // WMI: Win32_OperatingSystem OSType IN OUT UINT *puiCIMOSProductSuite, // WMI: Win32_OperatingSystem OSProductSuite IN OUT LPWSTR pszCIMOSVersion, // WMI: Win32_OperatingSystem Version IN OUT LPWSTR pszCIMOSBuildNumber, // WMI: Win32_OperatingSystem BuildNumber IN OUT LPWSTR pszCIMServicePackMajorVersion, // WMI: Win32_OperatingSystem ServicePackMajorVersion IN OUT LPWSTR pszCIMServicePackMinorVersion, // WMI: Win32_OperatingSystem ServicePackMinorVersion IN OUT UINT *puiCIMProcessorArchitecture) // WMI: Win32_Processor Architecture { if (!g_CIMSucceeded) return ERROR_HOST_UNREACHABLE; if (puiCIMOSType) *puiCIMOSType = g_CIMOSType; if (puiCIMOSProductSuite) *puiCIMOSProductSuite = g_CIMOSProductSuite; if (puiCIMProcessorArchitecture) *puiCIMProcessorArchitecture = g_CIMProcessorArchitecture; if (pszCIMOSVersion) wcsncpy(pszCIMOSVersion, g_CIMOSVersion, MAX_PATH); if (pszCIMOSBuildNumber) wcsncpy(pszCIMOSBuildNumber, g_CIMOSBuildNumber, MAX_PATH); if (pszCIMServicePackMajorVersion) wcsncpy(pszCIMServicePackMajorVersion, g_CIMServicePackMajorVersion, MAX_PATH); if (pszCIMServicePackMinorVersion) wcsncpy(pszCIMServicePackMinorVersion, g_CIMServicePackMinorVersion, MAX_PATH); return NO_ERROR; } BOOL VerifyOsVersion(IN PNS_OSVERSIONCHECK pfnVersionCheck) { DWORD dwRetVal; if (!pfnVersionCheck) { return TRUE; } else { if (g_CIMSucceeded) { dwRetVal = pfnVersionCheck( g_CIMOSType, g_CIMOSProductSuite, g_CIMOSVersion, g_CIMOSBuildNumber, g_CIMServicePackMajorVersion, g_CIMServicePackMinorVersion, g_CIMProcessorArchitecture, 0); return dwRetVal; } else { return FALSE; } } } DWORD WINAPI GenericMonitor( IN const NS_CONTEXT_ATTRIBUTES *pGenericContext, IN LPCWSTR pwszMachine, IN OUT LPWSTR *ppwcArguments, IN DWORD dwArgCount, IN DWORD dwFlags, IN LPCVOID pvData, OUT LPWSTR pwcNewContext ) { DWORD dwErr = NO_ERROR, dwIndex, i, j; BOOL bFound = FALSE; DWORD dwNumMatched; DWORD dwCmdHelpToken; LPCWSTR pwszCmdToken; PNS_DLL_TABLE_ENTRY pDll; PNS_HELPER_TABLE_ENTRY pHelper; PCNS_CONTEXT_ATTRIBUTES pSubContext; PCNS_CONTEXT_ATTRIBUTES pContext = pGenericContext; GetHelperEntry( &pContext->guidHelper, &pHelper); GetDllEntry( pHelper->dwDllIndex, &pDll); g_CurrentContext = pContext; g_CurrentHelper = pHelper; if (pContext->pfnConnectFn) { dwErr = pContext->pfnConnectFn(pwszMachine); if (dwErr) { return dwErr; } } // // See if command is a context switch. // if (dwArgCount is 1) { UpdateNewContext(pwcNewContext, pContext->pwszContext, dwArgCount); return ERROR_CONTEXT_SWITCH; } // // See if the command is a ubiquitous command // for (i=0; idwDllIndex, &pDll); return ExecuteHandler( pDll->hDll, &g_UbiqCmds[i], ppwcArguments, 2, dwArgCount, dwFlags, pvData, NULL, &g_bDone ); } } // // See if the command is a top level (non group) command // for(i = 0; i < pContext->ulNumTopCmds; i++) { if ((*pContext->pTopCmds)[i].dwFlags & ~dwFlags) { continue; } if (MatchToken(ppwcArguments[1], (*pContext->pTopCmds)[i].pwszCmdToken)) { if (!VerifyOsVersion( (*pContext->pTopCmds)[i].pOsVersionCheck) ) { continue; } return ExecuteHandler( pDll->hDll, &(*pContext->pTopCmds)[i], ppwcArguments, 2, dwArgCount, dwFlags, pvData, NULL, &g_bDone ); } } // // Check to see if it is meant for one of the // helpers under it. // for (i=0; iulNumSubContexts; i++) { pSubContext = (PCNS_CONTEXT_ATTRIBUTES) (pHelper->pSubContextTable + i*pHelper->ulSubContextSize); if (pSubContext->dwFlags & ~dwFlags) { continue; } if (!VerifyOsVersion(pSubContext->pfnOsVersionCheck)) { continue; } if (MatchToken( ppwcArguments[1], pSubContext->pwszContext)) { dwIndex = i; bFound = TRUE; break; } } if (bFound) { PNS_PRIV_CONTEXT_ATTRIBUTES pNsPrivContextAttributes; PNS_PRIV_CONTEXT_ATTRIBUTES pNsPrivSubContextAttributes; // // Intended for one of the helpers under this one // Pass on the command to the helper // UpdateNewContext(pwcNewContext, pSubContext->pwszContext, dwArgCount - 1); // // Call entry point of the helper. // pNsPrivContextAttributes = pContext->pReserved; pNsPrivSubContextAttributes = pSubContext->pReserved; if ( (pNsPrivContextAttributes) && (pNsPrivContextAttributes->pfnSubEntryFn) ) { dwErr = (*pNsPrivContextAttributes->pfnSubEntryFn)( pSubContext, pwszMachine, ppwcArguments + 1, dwArgCount - 1, dwFlags, NULL, pwcNewContext); } else { if ( (!pNsPrivSubContextAttributes) || (!pNsPrivSubContextAttributes->pfnEntryFn) ) { dwErr = GenericMonitor( pSubContext, pwszMachine, ppwcArguments + 1, dwArgCount - 1, dwFlags, NULL, pwcNewContext); } else { dwErr = (pNsPrivSubContextAttributes->pfnEntryFn)( pwszMachine, ppwcArguments + 1, dwArgCount - 1, dwFlags, NULL, pwcNewContext); } } return dwErr; } // // It is a command group // bFound = FALSE; for(i = 0; i < pContext->ulNumGroups; i++) { if ((*pContext->pCmdGroups)[i].dwFlags & ~dwFlags) { continue; } if (MatchToken(ppwcArguments[1], (*pContext->pCmdGroups)[i].pwszCmdGroupToken)) { LPCWSTR pwszCmdGroupToken = (*pContext->pCmdGroups)[i].pwszCmdGroupToken; if (!VerifyOsVersion((*pContext->pCmdGroups)[i].pOsVersionCheck)) { continue; } // See if it's a request for help if ((dwArgCount<3) || IsHelpToken(ppwcArguments[2])) { return DisplayContextHelp( pContext, CMD_FLAG_PRIVATE, dwFlags, dwArgCount-2+1, (*pContext->pCmdGroups)[i].pwszCmdGroupToken ); } // // Command matched entry i, so look at the table of sub commands // for this command // for (j = 0; j < (*pContext->pCmdGroups)[i].ulCmdGroupSize; j++) { if ((*pContext->pCmdGroups)[i].pCmdGroup[j].dwFlags & ~dwFlags) { continue; } if (MatchCmdLine(ppwcArguments + 2, dwArgCount - 1, (*pContext->pCmdGroups)[i].pCmdGroup[j].pwszCmdToken, &dwNumMatched)) { if (!VerifyOsVersion((*pContext->pCmdGroups)[i].pCmdGroup[j].pOsVersionCheck)) { continue; } return ExecuteHandler( pDll->hDll, &(*pContext->pCmdGroups)[i].pCmdGroup[j], ppwcArguments, dwNumMatched + 2, dwArgCount, dwFlags, pvData, pwszCmdGroupToken, // the command group name &g_bDone ); } } return ERROR_CMD_NOT_FOUND; } } return ERROR_CMD_NOT_FOUND; } DWORD WINAPI NetshStartHelper( IN CONST GUID *pguidParent, IN DWORD dwVersion ) { DWORD dwErr; NS_CONTEXT_ATTRIBUTES attMyAttributes; // ParentVersion = dwVersion; ZeroMemory(&attMyAttributes, sizeof(attMyAttributes)); attMyAttributes.pwszContext = L"netsh"; attMyAttributes.guidHelper = g_NetshGuid; attMyAttributes.dwVersion = 1; attMyAttributes.dwFlags = 0; attMyAttributes.ulNumTopCmds = g_ulNumShellCmds; attMyAttributes.pTopCmds = (CMD_ENTRY (*)[])&g_ShellCmds; attMyAttributes.ulNumGroups = g_ulNumGroups; attMyAttributes.pCmdGroups = (CMD_GROUP_ENTRY (*)[])&g_ShellCmdGroups; dwErr = RegisterContext( &attMyAttributes ); return dwErr; } DWORD WINAPI InitHelperDll( IN DWORD dwNetshVersion, OUT PVOID pReserved ) { NS_HELPER_ATTRIBUTES attMyAttributes; ZeroMemory( &attMyAttributes, sizeof(attMyAttributes) ); attMyAttributes.guidHelper = g_NullGuid; attMyAttributes.dwVersion = 1; RegisterHelper( &g_NullGuid, &attMyAttributes ); attMyAttributes.guidHelper = g_NetshGuid; attMyAttributes.dwVersion = 1; attMyAttributes.pfnStart = NetshStartHelper; RegisterHelper( &g_NullGuid, &attMyAttributes ); return NO_ERROR; } DWORD GetRootContext( OUT PCNS_CONTEXT_ATTRIBUTES *ppContext, OUT PNS_HELPER_TABLE_ENTRY *ppHelper ) { PCNS_CONTEXT_ATTRIBUTES pContext; DWORD dwErr, k; PNS_HELPER_TABLE_ENTRY pNull; dwErr = GetHelperEntry( &g_NetshGuid, ppHelper ); dwErr = GetHelperEntry( &g_NullGuid, &pNull ); for ( k = 0 ; k < pNull->ulNumSubContexts ; k++) { pContext = (PCNS_CONTEXT_ATTRIBUTES) (pNull->pSubContextTable + k*pNull->ulSubContextSize); if (memcmp( &g_NetshGuid, &pContext->guidHelper, sizeof(GUID) )) { continue; } *ppContext = pContext; return NO_ERROR; } return dwErr; } DWORD GetParentContext( IN PCNS_CONTEXT_ATTRIBUTES pChildContext, OUT PCNS_CONTEXT_ATTRIBUTES *ppParentContext ) { DWORD dwErr, k; PNS_HELPER_TABLE_ENTRY pChild, pParent, pGrandParent; PCNS_CONTEXT_ATTRIBUTES pParentContext; // For now, just pick the first context in the parent helper // To do this, we need to look through the grandparent's subcontexts dwErr = GetHelperEntry( &pChildContext->guidHelper, &pChild ); if (dwErr) { return dwErr; } dwErr = GetHelperEntry( &pChild->guidParent, &pParent ); if (dwErr) { return dwErr; } dwErr = GetHelperEntry( &pParent->guidParent, &pGrandParent ); if (dwErr) { return dwErr; } for ( k = 0 ; k < pGrandParent->ulNumSubContexts ; k++) { pParentContext = (PCNS_CONTEXT_ATTRIBUTES) (pGrandParent->pSubContextTable + k*pGrandParent->ulSubContextSize); if (memcmp( &pChild->guidParent, &pParentContext->guidHelper, sizeof(GUID) )) { continue; } *ppParentContext = pParentContext; return NO_ERROR; } return ERROR_NOT_FOUND; } DWORD AppendFullContextName( IN PCNS_CONTEXT_ATTRIBUTES pContext, OUT LPWSTR *ppwszContextName ) { DWORD dwErr; PCNS_CONTEXT_ATTRIBUTES pParent; dwErr = GetParentContext(pContext, &pParent); if (dwErr is NO_ERROR) { dwErr = AppendFullContextName(pParent, ppwszContextName); if (dwErr) { return dwErr; } } if (*ppwszContextName) { AppendString(ppwszContextName, L" "); } dwErr = AppendString(ppwszContextName, pContext->pwszContext); return dwErr; }