windows-nt/Source/XPSP1/NT/net/rras/netsh/shell/reghlp.c
2020-09-26 16:20:57 +08:00

2229 lines
53 KiB
C

/*++
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; i<g_dwNumHelpers; i++)
{
if (!memcmp(pguidHelper, &g_HelperTable[i].nha.guidHelper, sizeof(GUID)))
{
*pdwIndex = i;
return NO_ERROR;
}
}
return ERROR_NOT_FOUND;
}
DWORD
AddHelper(
IN CONST GUID *pguidParent,
IN CONST NS_HELPER_ATTRIBUTES *pAttributes
)
{
PNS_HELPER_TABLE_ENTRY phtTmp;
//
// Need to add entries in the helper table
//
phtTmp = MALLOC((g_dwNumHelpers + 1) * sizeof(NS_HELPER_TABLE_ENTRY));
if (phtTmp is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(phtTmp, g_HelperTable,
g_dwNumHelpers * sizeof(NS_HELPER_TABLE_ENTRY));
CopyMemory(&phtTmp[g_dwNumHelpers],
pAttributes,
sizeof(NS_HELPER_ATTRIBUTES));
CopyMemory(&phtTmp[g_dwNumHelpers].guidParent, pguidParent, sizeof(GUID));
phtTmp[g_dwNumHelpers].dwDllIndex = g_dwDllIndex;
phtTmp[g_dwNumHelpers].bStarted = FALSE;
phtTmp[g_dwNumHelpers].ulSubContextSize = sizeof(NS_CONTEXT_ATTRIBUTES);
phtTmp[g_dwNumHelpers].ulNumSubContexts = 0;
phtTmp[g_dwNumHelpers].pSubContextTable = (UINT_PTR)NULL;
g_dwNumHelpers ++;
FREE(g_HelperTable);
g_HelperTable = phtTmp;
return ERROR_SUCCESS;
}
DWORD
WINAPI
GenericDeregisterAllContexts(
IN CONST GUID *pguidChild
)
/*++
Description:
Remove all contexts registered by a given helper
--*/
{
DWORD j, dwErr;
PNS_HELPER_TABLE_ENTRY pChildHelper, pParentHelper;
PCNS_CONTEXT_ATTRIBUTES pSubContext;
dwErr = GetHelperEntry(pguidChild, &pChildHelper);
if (dwErr)
{
return dwErr;
}
dwErr = GetHelperEntry(&pChildHelper->guidParent, &pParentHelper);
if (dwErr)
{
return dwErr;
}
for (j=0; j<pParentHelper->ulNumSubContexts; 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<g_dwNumHelpers; i++)
{
if (g_HelperTable[i].bStarted)
continue;
dwErr = FindHelper(&g_HelperTable[i].guidParent, &dwParentIndex);
if (dwErr isnot NO_ERROR)
{
continue;
}
if (!g_HelperTable[dwParentIndex].bStarted)
{
continue;
}
dwVersion = NETSH_VERSION_50;
bFound = TRUE;
break;
}
if (bFound)
{
g_HelperTable[i].bStarted = TRUE;
if (g_HelperTable[i].nha.pfnStart)
{
g_HelperTable[i].nha.pfnStart( &g_HelperTable[i].guidParent,
dwVersion );
}
}
} while (bFound);
}
DWORD
AddDllEntry(
LPCWSTR pwszValueName,
LPCWSTR pwszConfigDll
)
{
PNS_DLL_TABLE_ENTRY phtTmp = NULL;
//
// Need to add entry in the dll table
//
phtTmp = MALLOC((g_dwNumDlls + 1) * sizeof(NS_DLL_TABLE_ENTRY));
if (phtTmp is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(phtTmp, g_DllTable,
g_dwNumDlls * sizeof(NS_DLL_TABLE_ENTRY));
ZeroMemory(&phtTmp[g_dwNumDlls], sizeof(NS_DLL_TABLE_ENTRY));
phtTmp[g_dwNumDlls].pwszValueName = MALLOC( (wcslen(pwszValueName) + 1)
* sizeof(WCHAR));
if (!phtTmp[g_dwNumDlls].pwszValueName)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(phtTmp[g_dwNumDlls].pwszValueName, pwszValueName);
phtTmp[g_dwNumDlls].pwszDLLName = MALLOC( (wcslen(pwszConfigDll) + 1)
* sizeof(WCHAR));
if (!phtTmp[g_dwNumDlls].pwszDLLName)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(phtTmp[g_dwNumDlls].pwszDLLName, pwszConfigDll);
_wcsupr(phtTmp[g_dwNumDlls].pwszDLLName);
g_dwNumDlls ++;
FREE(g_DllTable);
g_DllTable = phtTmp;
return LoadDll(g_dwNumDlls - 1);
}
DWORD
InstallDll(
IN LPCWSTR pwszConfigDll
)
/*++
Called by: HandleAddHelper()
--*/
{
DWORD i, dwErr;
HKEY hBaseKey;
DWORD dwResult = ERROR_SUCCESS;
BOOL bFound = FALSE;
WCHAR wcszKeyName[80];
LPWSTR p, q;
LPWSTR pwszConfigDllCopy;
//
// Check to see if the DLL is already present.
//
for (i = 0; i < g_dwNumDlls; i++)
{
if (_wcsicmp(g_DllTable[i].pwszDLLName, pwszConfigDll) == 0)
{
bFound = TRUE;
break;
}
}
do
{
if (bFound)
break;
//
// Add the key to the registry
//
//
// Create Base Key. If it already exists, fine.
//
dwResult = RegCreateKeyExW(HKEY_LOCAL_MACHINE,
REG_KEY_NETSH_HELPER,
0,
L"STRING",
REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS,
NULL,
&hBaseKey,
NULL);
if(dwResult != ERROR_SUCCESS)
{
break;
}
//
// Add key for the Dll
//
pwszConfigDllCopy = _wcsdup(pwszConfigDll);
if (!pwszConfigDllCopy)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
p = pwszConfigDllCopy;
if ((q = wcsrchr(pwszConfigDllCopy, L'/')) isnot NULL)
{
p = q+1;
}
else if ((q = wcsrchr(pwszConfigDllCopy, L'\\')) isnot NULL)
{
p = q+1;
}
wcscpy(wcszKeyName, p);
if ((p = wcsrchr(wcszKeyName, L'.')) isnot NULL)
{
*p = L'\0';
}
dwResult = RegSetValueExW(hBaseKey,
wcszKeyName,
0,
REG_SZ,
(PBYTE) pwszConfigDllCopy,
(wcslen(pwszConfigDllCopy) + 1) * sizeof(WCHAR));
RegCloseKey(hBaseKey);
free(pwszConfigDllCopy);
} while (FALSE);
if (dwResult != ERROR_SUCCESS)
{
//
// Could not install key successfully
//
PrintMessageFromModule(g_hModule, EMSG_INSTALL_KEY_FAILED, pwszConfigDll);
return dwResult;
}
dwErr = AddDllEntry(wcszKeyName, pwszConfigDll);
StartNewHelpers();
return dwErr;
}
DWORD
UninstallDll(
IN LPCWSTR pwszConfigDll,
IN BOOL fDeleteFromRegistry
)
{
DWORD i, j;
HKEY hBaseKey;
DWORD dwResult = ERROR_SUCCESS;
BOOL bFound = FALSE;
PNS_DLL_TABLE_ENTRY phtTmp = NULL;
//
// Check to see if the DLL is present.
//
for (i = 0; i < g_dwNumDlls; i++)
{
if (_wcsicmp(g_DllTable[i].pwszDLLName, pwszConfigDll) == 0)
{
bFound = TRUE;
break;
}
}
if (!bFound)
{
//
// DLL to be uninstalled not found.
//
return ERROR_NOT_FOUND;
}
// Uninstall all helpers for this DLL
for (j=0; j<g_dwNumHelpers; j++)
{
if (g_HelperTable[j].dwDllIndex is i)
{
DeleteHelper(j);
j--;
}
}
do
{
if (fDeleteFromRegistry)
{
//
// Delete the key from registry
//
//
// Open Base Key.
//
dwResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
REG_KEY_NETSH_HELPER,
0,
KEY_ALL_ACCESS,
&hBaseKey);
if(dwResult != ERROR_SUCCESS)
{
break;
}
//
// Delete key for the Dll
//
dwResult = RegDeleteValueW(hBaseKey,
g_DllTable[i].pwszValueName);
RegCloseKey(hBaseKey);
}
} while (FALSE);
if (dwResult != ERROR_SUCCESS)
{
//
// Could not uninstall key successfully
//
PrintMessageFromModule(g_hModule,
EMSG_UNINSTALL_KEY_FAILED,
pwszConfigDll);
return dwResult;
}
//
// Key succesfully deleted from registry. If a DLL table is currently
// available, then reflect changes in it too.
//
FREE( g_DllTable[i].pwszDLLName );
g_DllTable[i].pwszDLLName = NULL;
FREE( g_DllTable[i].pwszValueName );
g_DllTable[i].pwszValueName = NULL;
phtTmp = MALLOC((g_dwNumDlls - 1) * sizeof(NS_DLL_TABLE_ENTRY));
if (phtTmp is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(phtTmp,
g_DllTable,
i * sizeof(NS_DLL_TABLE_ENTRY));
CopyMemory(phtTmp + i,
g_DllTable + i + 1,
(g_dwNumDlls - 1 - i) * sizeof(NS_DLL_TABLE_ENTRY));
g_dwNumDlls --;
// Update the DLL index in all helpers
for (j=0; j<g_dwNumHelpers; j++)
{
if (g_HelperTable[j].dwDllIndex > 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; j<dwLevel; j++)
{
PrintMessageFromModule(g_hModule, MSG_SHOW_HELPER_INFO1);
}
PrintMessageFromModule( g_hModule,
MSG_SHOW_HELPER_INFO2,
pSubContext->pwszContext );
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; i<g_dwNumDlls; i++)
{
if (!g_DllTable[i].bLoaded)
{
if (!bFound)
{
PrintMessageFromModule( g_hModule, MSG_SHOW_HELPER_DLL_HDR );
bFound = TRUE;
}
PrintMessage( L"%1!s!\n", g_DllTable[i].pwszDLLName );
}
}
// Show orphaned helpers
for (bFound=FALSE,i=0; i<g_dwNumHelpers; i++)
{
if (!g_HelperTable[i].bStarted)
{
ConvertGuidToString(&g_HelperTable[i].nha.guidHelper,
rgwcHelperGuid);
ConvertGuidToString(&g_HelperTable[i].guidParent,
rgwcParentGuid);
if (!bFound)
{
PrintMessageFromModule( g_hModule, MSG_SHOW_HELPER_ORPHAN_HDR );
bFound = TRUE;
}
PrintMessageFromModule(g_hModule,
MSG_SHOW_HELPER_ORPHAN_INFO,
rgwcHelperGuid,
g_DllTable[g_HelperTable[i].dwDllIndex].pwszDLLName,
rgwcParentGuid);
}
}
return NO_ERROR;
}
DWORD
HandleAddHelper(
LPCWSTR pwszMachine,
LPWSTR *ppwcArguments,
DWORD dwCurrentIndex,
DWORD dwArgCount,
DWORD dwFlags,
PVOID pvData,
BOOL *pbDone
)
/*++
Routine Description:
Installs a helper under the shell
Arguments:
Return Value:
NO_ERROR
--*/
{
DWORD dwErr;
if (dwArgCount-dwCurrentIndex != 1
|| IsHelpToken(ppwcArguments[dwCurrentIndex]))
{
//
// Install requires only the dll name
//
return ERROR_INVALID_SYNTAX;
}
#if 0
if(IsReservedKeyWord(ppwcArguments[dwCurrentIndex]))
{
PrintMessageFromModule(g_hModule, EMSG_RSVD_KEYWORD,
ppwcArguments[dwCurrentIndex]);
return ERROR_INVALID_PARAMETER;
}
#endif
dwErr = InstallDll(ppwcArguments[dwCurrentIndex]);
if (dwErr is ERROR_NOT_ENOUGH_MEMORY)
{
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
dwErr = ERROR_SUPPRESS_OUTPUT;
}
if (dwErr is ERROR_SUCCESS)
{
dwErr = ERROR_OKAY;
}
return dwErr;
}
DWORD
HandleDelHelper(
LPCWSTR pwszMachine,
LPWSTR *ppwcArguments,
DWORD dwCurrentIndex,
DWORD dwArgCount,
DWORD dwFlags,
PVOID pvData,
BOOL *pbDone
)
/*++
Routine Description:
Removes a helper from under the Shell
Arguments:
Return Value:
NO_ERROR
--*/
{
DWORD dwErr;
if (dwArgCount-dwCurrentIndex != 1)
{
//
// Uninstall requires name of helper
//
return ERROR_INVALID_SYNTAX;
}
dwErr = UninstallDll(ppwcArguments[dwCurrentIndex], TRUE);
if (dwErr is ERROR_NOT_ENOUGH_MEMORY)
{
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
}
if (dwErr is ERROR_SUCCESS)
{
dwErr = ERROR_OKAY;
}
return dwErr;
}
DWORD
GenericDeleteContext(
IN PNS_HELPER_TABLE_ENTRY pParentHelper,
IN DWORD dwContextIdx
)
{
DWORD dwResult = ERROR_SUCCESS;
PBYTE phtTmp = NULL;
phtTmp = MALLOC((pParentHelper->ulNumSubContexts - 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; i<pParentHelper->ulNumSubContexts; 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; i<pParentHelper->ulNumSubContexts; 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; i<g_ulNumUbiqCmds; i++)
{
if (g_UbiqCmds[i].dwFlags & ~dwFlags)
{
continue;
}
if (MatchToken(ppwcArguments[1],
g_UbiqCmds[i].pwszCmdToken))
{
if (!VerifyOsVersion(g_UbiqCmds[i].pOsVersionCheck))
{
continue;
}
dwErr = GetHelperEntry( &g_NetshGuid, &pHelper );
GetDllEntry( pHelper->dwDllIndex, &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; i<pHelper->ulNumSubContexts; 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;
}