Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

2612 lines
66 KiB

/*++
Copyright (c) 1998-1999 Microsoft Corporation
Module Name:
routing\netsh\shell\shell.c
Abstract:
The command shell.
Revision History:
Anand Mahalingam 7/6/98 Created
Dave Thaler 99 Updated
--*/
#include "precomp.h"
#undef EXTRA_DEBUG
//
// Define this when we allow a -r option to do remote config
//
#define ALLOW_REMOTES
#define DEFAULT_STARTUP_CONTEXT L"netsh"
WCHAR RtmonPrompt[MAX_CMD_LEN];
WCHAR g_pwszContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
WCHAR g_pwszNewContext[MAX_CMD_LEN] = DEFAULT_STARTUP_CONTEXT;
LPWSTR g_pwszRouterName = NULL;
LPWSTR g_pwszRememberedConnection = NULL;
HANDLE g_hModule;
BOOL g_bVerbose = FALSE;
BOOL g_bInteractive = FALSE;
DWORD g_dwContextArgCount;
DWORD g_dwTotalArgCount;
BOOL g_bDone = FALSE;
HANDLE g_hLogFile = NULL;
BOOL
WINAPI
HandlerRoutine(
DWORD dwCtrlType // control signal type
);
//
// If quiet, "Ok" and other informational messages will be suppressed.
//
BOOL g_bQuiet = TRUE;
CMD_ENTRY g_UbiqCmds[] =
{
CREATE_CMD_ENTRY( DUMP, HandleUbiqDump),
CREATE_CMD_ENTRY( HELP1, HandleUbiqHelp),
CREATE_CMD_ENTRY( HELP2, HandleUbiqHelp),
};
ULONG g_ulNumUbiqCmds = sizeof(g_UbiqCmds)/sizeof(CMD_ENTRY);
CMD_ENTRY g_ShellCmds[] =
{
// CREATE_CMD_ENTRY( DUMP, HandleShellDump),
// CREATE_CMD_ENTRY( HELP1, HandleShellHelp),
// CREATE_CMD_ENTRY( HELP2, HandleShellHelp),
CREATE_CMD_ENTRY( LOAD, HandleShellLoad),
CREATE_CMD_ENTRY_EX(QUIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(BYE, HandleShellExit, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(EXIT, HandleShellExit, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(FLUSH, HandleShellFlush, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(SAVE, HandleShellSave, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(COMMIT, HandleShellCommit, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(UNCOMMIT, HandleShellUncommit,CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(ALIAS, HandleShellAlias, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(UNALIAS, HandleShellUnalias, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(UPLEVEL, HandleShellUplevel, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(PUSHD, HandleShellPushd, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(POPD, HandleShellPopd, CMD_FLAG_INTERACTIVE),
};
ULONG g_ulNumShellCmds = sizeof(g_ShellCmds)/sizeof(CMD_ENTRY);
CMD_ENTRY g_ShellAddCmdTable[] = {
CREATE_CMD_ENTRY_EX(ADD_HELPER, HandleAddHelper, CMD_FLAG_LOCAL),
};
CMD_ENTRY g_ShellSetCmdTable[] = {
CREATE_CMD_ENTRY_EX(SET_MACHINE, HandleSetMachine,CMD_FLAG_ONLINE),
CREATE_CMD_ENTRY_EX(SET_MODE, HandleSetMode, CMD_FLAG_INTERACTIVE),
CREATE_CMD_ENTRY_EX(SET_FILE, HandleSetFile, CMD_FLAG_INTERACTIVE),
};
CMD_ENTRY g_ShellDelCmdTable[] = {
CREATE_CMD_ENTRY_EX(DEL_HELPER, HandleDelHelper, CMD_FLAG_LOCAL),
};
CMD_ENTRY g_ShellShowCmdTable[] = {
CREATE_CMD_ENTRY_EX(SHOW_ALIAS, HandleShowAlias, 0),
CREATE_CMD_ENTRY_EX(SHOW_HELPER, HandleShowHelper, 0),
CREATE_CMD_ENTRY_EX(SHOW_MODE, HandleShowMode, CMD_FLAG_INTERACTIVE),
};
CMD_GROUP_ENTRY g_ShellCmdGroups[] =
{
CREATE_CMD_GROUP_ENTRY(GROUP_ADD, g_ShellAddCmdTable),
CREATE_CMD_GROUP_ENTRY(GROUP_DELETE, g_ShellDelCmdTable),
CREATE_CMD_GROUP_ENTRY(GROUP_SET, g_ShellSetCmdTable),
CREATE_CMD_GROUP_ENTRY(GROUP_SHOW, g_ShellShowCmdTable),
};
ULONG g_ulNumGroups = sizeof(g_ShellCmdGroups)/sizeof(CMD_GROUP_ENTRY);
DWORD
ParseCommand(
IN PLIST_ENTRY pleEntry,
IN BOOL bAlias
)
/*++
Routine Description:
This converts any multi-token arguments into separate arg entries.
If bAlias is set, it also expands any args which are aliases.
Arguments:
ple - Pointer to the argument.
bAlias - To look for alias or not.
Called by: ConvertBufferToArgList(), ProcessCommand()
Return Value:
ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
--*/
{
DWORD dwErr = NO_ERROR, dwLen , i;
LPWSTR pw1, pw2, pwszAlias;
PLIST_ENTRY ple, ple1, pleTmp, plePrev, pleAlias;
PARG_ENTRY pae, paeArg;
WCHAR wcTmp;
paeArg = CONTAINING_RECORD(pleEntry, ARG_ENTRY, le);
if (! paeArg->pwszArg)
{
return NO_ERROR;
}
pw1 = paeArg->pwszArg;
//
// Get each argument in the command. Argument within " must
// be retained as is. The token delimiters are ' ' and '='
//
for (plePrev = pleEntry ; ; )
{
// Skip leading whitespace
for(; *pw1 && *pw1 != L'#' && (*pw1 == L' ' || *pw1 == L'\t'); pw1++);
// If it starts with a #, it's the same as an empty string
if (*pw1 == L'#')
*pw1 = L'\0';
// If it's an empty string, we're done
if (!(*pw1))
{
break;
}
if (*pw1 is L'"')
{
for (pw2 = pw1 + 1; *pw2 && *pw2 != L'"'; pw2++);
if (*pw2)
{
pw2++;
}
}
else if (*pw1 is L'=')
{
pw2 = pw1 + 1;
}
else
{
for(pw2 = pw1 + 1; *pw2 && *pw2 != L' ' && *pw2 != L'=' ; pw2++);
}
//
// Add the new argument to the list.
//
pae = MALLOC(sizeof(ARG_ENTRY));
if (pae is NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
ple = &(pae->le);
ple->Flink = plePrev->Flink;
ple->Blink = plePrev;
plePrev->Flink = ple;
ple->Flink->Blink = ple;
plePrev = ple;
wcTmp = *pw2;
*pw2 = L'\0';
//
// The argument could be an alias. If so replace it by
// the original string.
//
if (bAlias)
{
ATLookupAliasTable(pw1, &pwszAlias);
}
else
{
pwszAlias = NULL;
}
if (pwszAlias)
{
pw1 = pwszAlias;
dwLen = wcslen(pwszAlias) + 1;
}
else
{
dwLen = (DWORD)(pw2 - pw1 + 1);
}
pae->pwszArg = MALLOC(dwLen * sizeof(WCHAR));
if (pae->pwszArg is NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
// Convert /? and -? to just ?
if (!wcscmp(pw1, L"/?") or !wcscmp(pw1, L"-?"))
{
pw1++;
}
wcscpy(pae->pwszArg, pw1);
*pw2 = wcTmp;
pw1 = pw2;
}
if (dwErr is NO_ERROR)
{
// Free the argument
FREE(paeArg->pwszArg);
pleEntry->Blink->Flink = pleEntry->Flink;
pleEntry->Flink->Blink = pleEntry->Blink;
FREE(paeArg);
}
return dwErr;
}
DWORD
WINAPI
UpdateNewContext(
IN OUT LPWSTR pwszBuffer,
IN LPCWSTR pwszNewToken,
IN DWORD dwArgs
)
/*++
pwszBuffer - a static buffer (should be g_pwszNewContext)
currently this can't be dynamic since the context buffer
would have to be an IN/OUT parameter to this function
and hence to all monitor Entry points.
--*/
{
DWORD dwErr;
PLIST_ENTRY pleHead, pleNode;
PARG_ENTRY pae;
// Convert buffer to list
dwErr = ConvertBufferToArgList( &pleHead, pwszBuffer );
if (dwErr)
{
return dwErr;
}
// Locate in list
for (pleNode = pleHead->Blink; dwArgs>1; pleNode=pleNode->Blink)
{
if (pleNode->Blink isnot pleHead)
{
pae = CONTAINING_RECORD(pleNode->Blink, ARG_ENTRY, le);
if (!wcscmp(pae->pwszArg,L"="))
{
pleNode=pleNode->Blink; // back up over =
if (pleNode->Blink isnot pleHead)
{
pleNode=pleNode->Blink; // back up over tag too
}
}
}
dwArgs--;
}
// Update in list
pae = CONTAINING_RECORD(pleNode, ARG_ENTRY, le);
if (pae->pwszArg)
{
FREE(pae->pwszArg);
}
pae->pwszArg = MALLOC((wcslen(pwszNewToken)+1) * sizeof(WCHAR));
if (pae->pwszArg is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(pae->pwszArg, pwszNewToken);
// Convert list to buffer
dwErr = ConvertArgListToBuffer( pleHead, pwszBuffer );
return dwErr;
}
DWORD
GetNewContext(
IN LPCWSTR pwszArgument,
OUT LPWSTR *ppwszNewContext,
OUT BOOL *pbContext
)
/*++
Routine Description:
Based on the first command argument and the current context,
determines the context for the new command.
Arguments:
pwszArgument - First argument in the command line.
ppwszNewContext - Pointer to the new context.
pbContext - Is it a new context ?
Return Value:
ERROR_NOT_ENOUGH_MEMORY, NO_ERROR
--*/
{
LPWSTR pwszNewContext, pwcToken, pw1, pwszArgumentCopy, pwszArgumentPtr;
DWORD dwSize;
pwszArgumentCopy = _wcsdup(pwszArgument);
if ( pwszArgumentCopy is NULL )
{
*pbContext = FALSE;
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
pwszArgumentPtr = pwszArgumentCopy;
//
// New Context cannot be longer than the combined lengths
// of pwszArgument and g_pwszContext.
//
dwSize = wcslen(pwszArgumentCopy) + wcslen(g_pwszContext) + 2;
pwszNewContext = MALLOC(dwSize * sizeof(WCHAR));
if (pwszNewContext is NULL)
{
*pbContext = FALSE;
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
free(pwszArgumentPtr);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (pwszArgumentCopy[0] is L'\\')
{
//
// The context is an absolute one.
//
pwszNewContext[0] = L'\0';
pwszArgumentCopy++;
*pbContext = TRUE;
}
else
{
//
// Context is relative to current.
//
wcscpy(pwszNewContext,g_pwszContext);
}
if ((pwcToken = wcstok(pwszArgumentCopy, L"\\" )) is NULL)
{
*ppwszNewContext = pwszNewContext;
free(pwszArgumentPtr);
return NO_ERROR;
}
do
{
if (_wcsicmp(pwcToken, L"..") == 0)
{
//
// Go back one level. If already at root, ignore.
//
if (_wcsicmp(pwszNewContext,L"\\") == 0)
{
}
else
{
pw1 = wcsrchr(pwszNewContext,L'\\');
if (pw1)
{
*pw1 = L'\0';
}
}
*pbContext = TRUE;
}
else
{
//
// add this level to context
//
wcscat(pwszNewContext,L"\\");
wcscat(pwszNewContext,pwcToken);
*pbContext = TRUE;
}
} while ((pwcToken = wcstok((LPWSTR)NULL, L"\\" )) != NULL);
*ppwszNewContext = pwszNewContext;
free(pwszArgumentPtr);
return NO_ERROR;
}
DWORD
AppendString(
IN OUT LPWSTR *ppwszBuffer,
IN LPCWSTR pwszString
)
{
LPWSTR pwszNewBuffer;
DWORD dwLen;
if (*ppwszBuffer is NULL) {
dwLen = wcslen(pwszString) + 1;
pwszNewBuffer = MALLOC( dwLen * sizeof(WCHAR));
if (pwszNewBuffer) {
pwszNewBuffer[0] = 0;
}
} else {
dwLen = wcslen(*ppwszBuffer) + wcslen(pwszString) + 1;
pwszNewBuffer = REALLOC( *ppwszBuffer, dwLen * sizeof(WCHAR));
}
if (!pwszNewBuffer)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
*ppwszBuffer = pwszNewBuffer;
wcscat(pwszNewBuffer, pwszString);
return NO_ERROR;
}
VOID
ConvertArgArrayToBuffer(
IN DWORD dwArgCount,
IN LPCWSTR *argv,
OUT LPWSTR *ppwszBuffer
)
{
DWORD i;
#ifdef EXTRA_DEBUG
PRINT1("In ConvertArgArrayToBuffer:");
for( i = 0; i < dwArgCount; i++)
{
PRINT(argv[i]);
}
#endif
// Initial string to empty
*ppwszBuffer = NULL;
for (i=0; i<dwArgCount; i++)
{
if (i)
{
AppendString(ppwszBuffer, L" ");
}
if (wcschr(argv[i], L' '))
{
AppendString(ppwszBuffer, L"\"");
AppendString(ppwszBuffer, argv[i]);
AppendString(ppwszBuffer, L"\"");
}
else
{
AppendString(ppwszBuffer, argv[i]);
}
}
#ifdef EXTRA_DEBUG
PRINT1("At end of ConvertArgArrayToBuffer:");
PRINT(*ppwszBuffer);
#endif
}
VOID
SetContext(
IN LPCWSTR wszNewContext
)
{
wcscpy(g_pwszContext, wszNewContext);
_wcslwr(g_pwszContext);
}
BOOL
IsImmediate(
IN DWORD dwCmdFlags,
IN DWORD dwRemainingArgs
)
/*++
Description:
Determines whether a command was "immediate". A command is immediate
if the context in which it exists was the current context in the
shell.
Returns:
TRUE if command is "immediate", FALSE if not
--*/
{
if (!(dwCmdFlags & CMD_FLAG_PRIVATE))
{
return FALSE;
}
// One way to tell is to get the current context arg count,
// the total arg count, and the remaining arg count.
return (g_dwContextArgCount + dwRemainingArgs is g_dwTotalArgCount);
}
DWORD
ProcessHelperCommand2(
IN PCNS_CONTEXT_ATTRIBUTES pContext,
IN DWORD dwArgCount,
IN OUT LPWSTR *argv,
IN DWORD dwDisplayFlags,
OUT BOOL *pbDone
)
{
PNS_CONTEXT_ENTRY_FN pfnEntryPt;
DWORD dwRes, dwIdx;
LPWSTR pwszNewContext = NULL;
LPWSTR pwszOrigContext = NULL;
if (pContext->dwFlags & ~dwDisplayFlags)
{
return ERROR_CMD_NOT_FOUND;
}
pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
// If arg was abbreviated, replace argv[0] with expanded name
if (wcscmp(argv[0], pContext->pwszContext))
{
pwszOrigContext = argv[0];
argv[0] = pContext->pwszContext;
}
ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
if (pwszNewContext)
{
wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
//
// this is something of a hack - we put the NULL 100 chars before the end of the buffer to prevent a buffer overrun later
// in UpdateNewContext: 190933 netsh hit an AV on netsh!._wcsnicmp
//
g_pwszNewContext[ MAX_CMD_LEN - 100 ] = 0;
FREE(pwszNewContext);
pwszNewContext = NULL;
}
//
// Call the entry point of helper.
//
if (pfnEntryPt)
{
dwRes = (*pfnEntryPt)(g_pwszRouterName,
argv, // + 1,
dwArgCount, // - 1,
dwDisplayFlags,
NULL,
g_pwszNewContext);
}
else
{
dwRes = GenericMonitor(pContext,
g_pwszRouterName,
argv, // + 1,
dwArgCount, // - 1,
dwDisplayFlags,
NULL,
g_pwszNewContext);
}
if (pwszOrigContext)
{
argv[0] = pwszOrigContext;
}
if (dwRes isnot NO_ERROR)
{
if (dwRes is ERROR_CONTEXT_SWITCH)
{
if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
{
LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
if (argv2 is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
if (argv2[dwArgCount] is NULL)
{
dwRes = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
wcscpy(argv2[dwArgCount], CMD_HELP2);
g_dwTotalArgCount = dwArgCount+1;
dwRes = ProcessHelperCommand2(pContext,
dwArgCount+1,
argv2,
dwDisplayFlags,
pbDone);
FREE(argv2[dwArgCount]);
}
FREE(argv2);
return dwRes;
}
//
// A context switch.
//
SetContext(g_pwszNewContext);
dwRes = NO_ERROR;
}
else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
{
PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
g_pwszRouterName);
*pbDone = TRUE;
}
}
return dwRes;
}
DWORD
WINAPI
ProcessHelperCommand(
IN DWORD dwArgCount,
IN OUT LPWSTR *argv,
IN DWORD dwDisplayFlags,
// OUT LPWSTR *ppwszNewContext,
OUT BOOL *pbDone
)
{
PCNS_CONTEXT_ATTRIBUTES pContext;
PNS_CONTEXT_ENTRY_FN pfnEntryPt;
DWORD dwRes, dwIdx;
LPWSTR pwszNewContext = NULL;
LPWSTR pwszOrigContext = NULL;
PNS_HELPER_TABLE_ENTRY pHelper;
dwRes = GetRootContext( &pContext, &pHelper);
if (dwRes)
{
return dwRes;
}
dwRes = GetContextEntry(pHelper, argv[0], &pContext);
if (dwRes isnot NO_ERROR)
{
return ERROR_CMD_NOT_FOUND;
}
if (pContext->dwFlags & ~dwDisplayFlags)
{
return ERROR_CMD_NOT_FOUND;
}
#if 1
pfnEntryPt = (!pContext->pReserved) ? NULL : ((PNS_PRIV_CONTEXT_ATTRIBUTES)pContext->pReserved)->pfnEntryFn;
#else
dwRes = GetHelperAttributes(dwIdx, &pfnEntryPt);
if (dwRes != NO_ERROR)
{
//
// Could not find helper or could not load the DLL
//
return dwRes;
}
#endif
// If arg was abbreviated, replace argv[0] with expanded name
if (wcscmp(argv[0], pContext->pwszContext))
{
pwszOrigContext = argv[0];
argv[0] = pContext->pwszContext;
}
ConvertArgArrayToBuffer(dwArgCount, argv, &pwszNewContext);
if (pwszNewContext)
{
wcsncpy(g_pwszNewContext, pwszNewContext, MAX_CMD_LEN);
g_pwszNewContext[ MAX_CMD_LEN - 1 ] = '\0';
FREE(pwszNewContext);
pwszNewContext = NULL;
}
//
// Call the entry point of helper.
//
if (pfnEntryPt)
{
dwRes = (*pfnEntryPt)(g_pwszRouterName,
argv + 1,
dwArgCount - 1,
dwDisplayFlags,
NULL,
g_pwszNewContext);
}
else
{
dwRes = GenericMonitor(pContext,
g_pwszRouterName,
argv + 1,
dwArgCount - 1,
dwDisplayFlags,
NULL,
g_pwszNewContext);
}
if (pwszOrigContext)
{
argv[0] = pwszOrigContext;
}
if (dwRes isnot NO_ERROR)
{
if (dwRes is ERROR_CONTEXT_SWITCH)
{
if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
{
LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
if (argv2 is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
if (argv2[dwArgCount] is NULL)
{
dwRes = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
wcscpy(argv2[dwArgCount], CMD_HELP2);
g_dwTotalArgCount = dwArgCount+1;
dwRes = ProcessHelperCommand(dwArgCount+1,
argv2,
dwDisplayFlags,
pbDone);
FREE(argv2[dwArgCount]);
}
FREE(argv2);
return dwRes;
}
//
// A context switch.
//
SetContext(g_pwszNewContext);
dwRes = NO_ERROR;
}
else if (dwRes is ERROR_CONNECT_REMOTE_CONFIG)
{
PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
g_pwszRouterName);
*pbDone = TRUE;
}
}
return dwRes;
}
DWORD
WINAPI
ExecuteHandler(
IN HANDLE hModule,
IN CMD_ENTRY *pCmdEntry,
IN OUT LPWSTR *argv,
IN DWORD dwNumMatched,
IN DWORD dwArgCount,
IN DWORD dwFlags,
IN LPCVOID pvData,
IN LPCWSTR pwszGroupName,
OUT BOOL *pbDone)
{
DWORD dwErr = NO_ERROR;
if (((dwArgCount - dwNumMatched) == 1)
&& IsHelpToken(argv[dwNumMatched]))
{
dwErr = ERROR_SHOW_USAGE;
}
else
{
//
// Call the parsing routine for the command
//
dwErr = pCmdEntry->pfnCmdHandler( g_pwszRouterName,
argv,
dwNumMatched,
dwArgCount,
dwFlags,
pvData,
pbDone );
}
if (dwErr is ERROR_INVALID_SYNTAX)
{
PrintError(NULL, dwErr);
dwErr = ERROR_SHOW_USAGE;
}
switch (dwErr) {
case ERROR_SHOW_USAGE:
//
// If the only argument is a help token, just
// display the help.
//
if (NULL != pwszGroupName)
{
LPWSTR pwszGroupFullCmd = (LPWSTR)
MALLOC( ( wcslen(pwszGroupName) +
wcslen(pCmdEntry->pwszCmdToken) +
2 // for blank and NULL characters
) * sizeof(WCHAR)
);
if (NULL == pwszGroupFullCmd)
{
// we still try to print without group name
PrintMessageFromModule( hModule,
pCmdEntry->dwCmdHlpToken,
pCmdEntry->pwszCmdToken );
}
else
{
wcscpy(pwszGroupFullCmd, pwszGroupName);
wcscat(pwszGroupFullCmd, L" ");
wcscat(pwszGroupFullCmd, pCmdEntry->pwszCmdToken);
PrintMessageFromModule( hModule,
pCmdEntry->dwCmdHlpToken,
pwszGroupFullCmd );
FREE(pwszGroupFullCmd);
}
}
else
{
PrintMessageFromModule( hModule,
pCmdEntry->dwCmdHlpToken,
pCmdEntry->pwszCmdToken );
}
dwErr = NO_ERROR;
break;
case NO_ERROR:
case ERROR_SUPPRESS_OUTPUT:
break;
case ERROR_OKAY:
if (!g_bQuiet)
{
PrintMessageFromModule( NULL, MSG_OKAY);
}
dwErr = NO_ERROR;
break;
default:
PrintError(NULL, dwErr);
break;
}
if (!g_bQuiet)
{
PrintMessage( MSG_NEWLINE );
}
return dwErr;
}
BOOL
ProcessGroupCommand(
IN DWORD dwArgCount,
IN PTCHAR *argv,
IN DWORD dwDisplayFlags,
OUT BOOL *pbDone
)
{
BOOL bFound = FALSE;
DWORD i, j, dwNumMatched, dwErr;
for(i = 0; i < g_ulNumGroups; i++)
{
if (g_ShellCmdGroups[i].dwFlags & ~dwDisplayFlags)
{
continue;
}
if (MatchToken(argv[0],
g_ShellCmdGroups[i].pwszCmdGroupToken))
{
// See if it's a request for help
if ((dwArgCount < 2) || IsHelpToken(argv[1]))
{
PCNS_CONTEXT_ATTRIBUTES pContext;
dwErr = GetRootContext(&pContext, NULL);
if (dwErr is NO_ERROR)
{
dwErr = DisplayContextHelp(
pContext,
CMD_FLAG_PRIVATE,
dwDisplayFlags,
dwArgCount-2+1,
g_ShellCmdGroups[i].pwszCmdGroupToken );
}
return TRUE;
}
//
// Command matched entry i, so look at the table of sub commands
// for this command
//
for (j = 0; j < g_ShellCmdGroups[i].ulCmdGroupSize; j++)
{
if (g_ShellCmdGroups[i].pCmdGroup[j].dwFlags
& ~dwDisplayFlags)
{
continue;
}
if (MatchCmdLine(argv,
dwArgCount,
g_ShellCmdGroups[i].pCmdGroup[j].pwszCmdToken,
&dwNumMatched))
{
bFound = TRUE;
dwErr = ExecuteHandler(g_hModule,
&g_ShellCmdGroups[i].pCmdGroup[j],
argv, dwNumMatched, dwArgCount,
dwDisplayFlags,
NULL,
g_ShellCmdGroups[i].pwszCmdGroupToken,
pbDone);
//
// quit the for(j)
//
break;
}
}
break;
}
}
return bFound;
}
DWORD
LookupCommandHandler(
IN LPCWSTR pwszCmd
)
{
// Eventually, we want to look up commands in sub-contexts first,
// and end up with the global context. For now, we'll just do global.
DWORD i;
for (i = 0; i < g_ulNumShellCmds; i++)
{
if (MatchToken(pwszCmd, g_ShellCmds[i].pwszCmdToken))
{
return i;
}
}
return -1;
}
VOID
FreeArgArray(
DWORD argc,
LPWSTR *argv
)
{
DWORD i;
for (i = 0; i < argc; i++)
{
FREE(argv[i]);
}
FREE(argv);
}
DWORD
ConvertArgListToBuffer(
IN PLIST_ENTRY pleHead,
OUT LPWSTR pwszBuffer
)
{
PLIST_ENTRY ple;
PARG_ENTRY pae;
LPWSTR p = pwszBuffer;
*p = '\0';
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
if (p isnot pwszBuffer)
{
*p++ = ' ';
}
wcscpy(p, pae->pwszArg);
p += wcslen(p);
}
return NO_ERROR;
}
DWORD
AppendArgument(
IN OUT LPWSTR **pargv,
IN DWORD i,
IN LPCWSTR pwszString
)
{
DWORD dwErr;
dwErr = AppendString( &(*pargv)[i], pwszString );
if ((*pargv)[i] is NULL) {
FreeArgArray(i, *pargv);
*pargv = NULL;
return ERROR_NOT_ENOUGH_MEMORY;
}
return NO_ERROR;
}
DWORD
ConvertArgListToArray(
IN PLIST_ENTRY pleContextHead,
IN PLIST_ENTRY pleHead,
OUT PDWORD pargc,
OUT LPWSTR **pargv,
OUT PDWORD pdwContextArgc
)
{
DWORD dwErr = NO_ERROR;
DWORD argc = 0, i = 0;
LPWSTR *argv = NULL, p;
BOOL bEqualTo;
PLIST_ENTRY ple;
PARG_ENTRY pae;
#ifdef EXTRA_DEBUG
if (pleHead)
{
PLIST_ENTRY ple;
PRINT1("In ConvertArgListToArray:");
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
PRINT(pae->pwszArg);
}
}
#endif
// Count tokens
if (pleContextHead)
{
for (ple = pleContextHead->Flink; ple != pleContextHead; ple = ple->Flink)
argc++;
}
*pdwContextArgc = argc;
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
argc++;
do {
if (!argc)
break;
//
// Allocate space for arguments
//
argv = MALLOC(argc * sizeof(LPCWSTR));
if (argv is NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
memset(argv, 0, argc * sizeof(LPCWSTR));
bEqualTo = FALSE;
//
// Copy the arguments from the list into an argv kind of
// structure. At this point, the arguments tag, '=' and
// the value are made into one argument tag=value.
//
//
// Copy context
//
i = 0;
if (pleContextHead)
{
for (ple = pleContextHead->Flink;
ple != pleContextHead;
ple = ple->Flink)
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
dwErr = AppendArgument( &argv, i++, pae->pwszArg );
if ( dwErr isnot NO_ERROR ) {
break;
}
}
}
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink )
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
//
// Remove any " from the string name
//
if (pae->pwszArg[0] == L'"')
{
if (bEqualTo)
{
dwErr=AppendArgument(&argv, i-1, pae->pwszArg+1);
if ( dwErr isnot NO_ERROR ) {
break;
}
bEqualTo = FALSE;
}
else
{
dwErr=AppendArgument(&argv, i++, pae->pwszArg+1);
if (dwErr isnot NO_ERROR ) {
break;
}
}
p = argv[i-1];
if (p[wcslen(p) - 1] == L'"')
{
p[wcslen(p) - 1] = L'\0';
}
continue;
}
//
// combine arguments of the form tag = value
//
if ((wcscmp(pae->pwszArg,L"=") == 0) || bEqualTo)
{
bEqualTo = (bEqualTo) ? FALSE : TRUE;
if (i > 0)
{
i--;
}
dwErr = AppendArgument( &argv, i++, pae->pwszArg);
if (dwErr isnot NO_ERROR ) {
break;
}
}
else
{
dwErr = AppendArgument( &argv, i++, pae->pwszArg);
if (dwErr isnot NO_ERROR ) {
break;
}
}
}
} while (FALSE);
#ifdef EXTRA_DEBUG
PRINT1("At end of ConvertArgListToArray:");
for( i = 0; i < argc; i++)
{
PRINT(argv[i]);
}
#endif
*pargc = i;
*pargv = argv;
return dwErr;
}
DWORD
ConvertBufferToArgList(
PLIST_ENTRY *ppleHead,
LPCWSTR pwszBuffer
)
{
PLIST_ENTRY pleHead = NULL;
DWORD dwErr = NO_ERROR;
PARG_ENTRY pae;
#ifdef EXTRA_DEBUG
PRINT1("In ConvertBufferToArgList:");
PRINT(pwszBuffer);
#endif
do {
//
// First convert the command line to a list of tokens
//
pleHead = MALLOC(sizeof(ARG_ENTRY));
if (pleHead is NULL)
{
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
ZeroMemory(pleHead, sizeof(ARG_ENTRY));
InitializeListHead(pleHead);
pae = MALLOC(sizeof(ARG_ENTRY));
if (pae is NULL)
{
FREE(pleHead);
pleHead = NULL;
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
pae->pwszArg = MALLOC((wcslen(pwszBuffer)+1) * sizeof(WCHAR));
if (pae->pwszArg is NULL)
{
FREE(pleHead);
FREE(pae);
pleHead = NULL;
dwErr = ERROR_NOT_ENOUGH_MEMORY;
break;
}
wcscpy(pae->pwszArg, pwszBuffer);
InsertHeadList(pleHead, &(pae->le));
dwErr = ParseCommand(pleHead->Flink, FALSE);
if (dwErr isnot NO_ERROR)
{
FREE_ARG_LIST(pleHead);
pleHead = NULL;
break;
}
} while (FALSE);
#ifdef EXTRA_DEBUG
if (pleHead)
{
PLIST_ENTRY ple;
PRINT1("At end of ConvertBufferToArgList:");
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
PRINT(pae->pwszArg);
}
}
#endif
*ppleHead = pleHead;
if (dwErr is ERROR_NOT_ENOUGH_MEMORY)
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
return dwErr;
}
DWORD
ProcessShellCommand(
IN DWORD dwArgCount,
IN OUT LPWSTR *argv,
IN DWORD dwDisplayFlags,
// OUT LPWSTR *ppwszNewContext,
OUT BOOL *pbDone
)
{
DWORD i;
for (i = 0; i < g_ulNumShellCmds; i++)
{
if (g_ShellCmds[i].dwFlags & ~dwDisplayFlags)
{
continue;
}
if (MatchToken( argv[0],
g_ShellCmds[i].pwszCmdToken ))
{
return ExecuteHandler( g_hModule,
&g_ShellCmds[i],
argv,
1,
dwArgCount,
dwDisplayFlags,
NULL,
NULL,
pbDone );
}
}
return ERROR_CMD_NOT_FOUND;
}
DWORD
ProcessCommand(
IN LPCWSTR pwszCmdLine,
OUT BOOL *pbDone
)
/*++
Routine Description:
Executes command if it is for the shell or else calls the
corresponding helper routine.
Arguments:
pwszCmdLine - The command line to be executed.
Return Value:
TRUE, FALSE - (Whether to quit the program or not)
--*/
{
LPCWSTR pwszAliasString = NULL;
DWORD dwRes = NO_ERROR, i, dwLen, j;
WCHAR wszAliasString[MAX_CMD_LEN],
pwszContext[MAX_CMD_LEN];
WCHAR pwszCommandLine[MAX_CMD_LEN],*pwszNewContext;
LPCWSTR pwcAliasString, pw1,pw2,pw3;
BOOL bContext, bEqualTo, bTmp;
LPCWSTR pwszArg0, pwszArg1, pwszArg2;
PLIST_ENTRY ple, ple1, ple2, pleHead, pleTmp, pleNext;
PLIST_ENTRY pleContextHead;
PARG_ENTRY pae;
DWORD dwArgCount = 0, dwContextArgCount = 0;
LPWSTR *argv, pwcNewContext = NULL;
BOOL bShellCmd, bAlias, bFound = FALSE, dwDisplayFlags;
PCNS_CONTEXT_ATTRIBUTES pContext;
*pbDone = FALSE;
dwDisplayFlags = (g_bInteractive)? CMD_FLAG_INTERACTIVE : 0;
dwDisplayFlags |= ~CMD_FLAG_LIMIT_MASK;
// Command is executed on the local machine if router name is null
if (!g_pwszRouterName)
{
dwDisplayFlags |= CMD_FLAG_LOCAL;
}
if (g_bCommit)
{
dwDisplayFlags |= CMD_FLAG_ONLINE;
}
if (g_bVerbose)
{
PrintMessage(L"> %1!s!\n", pwszCmdLine);
}
dwRes = ConvertBufferToArgList(&pleContextHead, g_pwszContext);
if (dwRes isnot NO_ERROR)
{
*pbDone = TRUE;
return dwRes;
}
dwRes = ConvertBufferToArgList(&pleHead, pwszCmdLine);
if (dwRes isnot NO_ERROR)
{
FREE_ARG_LIST(pleContextHead);
*pbDone = TRUE;
return dwRes;
}
if (IsListEmpty(pleHead))
{
FREE_ARG_LIST(pleHead);
FREE_ARG_LIST(pleContextHead);
return NO_ERROR;
}
// Expand alias (not recursive)
dwRes = ParseCommand(pleHead->Flink, TRUE);
if (dwRes isnot NO_ERROR)
{
FREE_ARG_LIST(pleHead);
FREE_ARG_LIST(pleContextHead);
*pbDone = TRUE;
return dwRes;
}
#ifdef EXTRA_DEBUG
PRINT1("In ProcessCommand 2:");
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
PRINT(pae->pwszArg);
}
#endif
// Go through and expand any multi-tokens args into separate args
for (ple = (pleHead->Flink); ple != pleHead; ple = pleNext)
{
pleNext = ple->Flink;
dwRes = ParseCommand(ple, FALSE);
if (dwRes isnot NO_ERROR)
{
break;
}
}
if (dwRes isnot NO_ERROR)
{
FREE_ARG_LIST(pleHead);
FREE_ARG_LIST(pleContextHead);
*pbDone = TRUE;
return dwRes;
}
#ifdef EXTRA_DEBUG
PRINT1("In ProcessCommand 3:");
for (ple = pleHead->Flink; ple != pleHead; ple = ple->Flink)
{
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
PRINT(pae->pwszArg);
}
#endif
//
// At this point, we should have a fully formed command,
// hopefully operable within the current context.
// The first token may be a command. If so, then the args
// will be the context followed by the rest of the tokens.
// If the first token is not a command, then the args will
// be the context followed by all the tokens.
//
if (IsListEmpty(pleHead))
{
FREE_ARG_LIST(pleHead);
FREE_ARG_LIST(pleContextHead);
return NO_ERROR;
}
pae = CONTAINING_RECORD(pleHead->Flink, ARG_ENTRY, le);
pwszArg0 = pae->pwszArg;
GetRootContext( &g_CurrentContext, &g_CurrentHelper );
do
{
// In the first context (only) we try, private commands are valid.
dwDisplayFlags |= CMD_FLAG_PRIVATE;
pContext = g_CurrentContext;
for(;;)
{
dwRes = ConvertArgListToArray( pleContextHead,
pleHead,
&dwArgCount,
&argv,
&dwContextArgCount );
g_dwTotalArgCount = dwArgCount;
g_dwContextArgCount = dwContextArgCount;
#if 1
# if 1
dwRes = ProcessHelperCommand2( pContext,
dwArgCount,
argv,
dwDisplayFlags,
pbDone );
# else
dwRes = GenericMonitor( pContext,
g_pwszRouterName,
argv,
dwArgCount,
dwDisplayFlags,
NULL,
g_pwszNewContext );
# endif
#else
{
if (!ProcessGroupCommand(dwArgCount, argv, dwDisplayFlags, pbDone))
{
//
// Having got the context and the command, see if there
// is a helper for it.
//
dwRes = ProcessHelperCommand( dwArgCount,
argv,
dwDisplayFlags,
// &pwszNewContext,
pbDone );
if (dwRes is ERROR_CMD_NOT_FOUND)
{
dwRes = ProcessShellCommand( dwArgCount,
argv,
dwDisplayFlags,
// &pwszNewContext,
pbDone );
}
}
}
#endif
FreeArgArray(dwArgCount, argv);
if (*pbDone or ((dwRes isnot ERROR_CMD_NOT_FOUND)
&& (dwRes isnot ERROR_CONTINUE_IN_PARENT_CONTEXT)))
{
break;
}
// Make sure we don't look above "netsh"
if (pleContextHead->Flink->Flink == pleContextHead)
{
break;
}
// Delete the last element of the context list
// (Try inheriting a command from one level up)
ple = pleContextHead->Blink;
pae = CONTAINING_RECORD(ple, ARG_ENTRY, le);
if (pae->pwszArg)
FREE(pae->pwszArg);
RemoveEntryList(ple);
FREE(pae);
GetParentContext(pContext, &pContext);
dwDisplayFlags &= ~CMD_FLAG_PRIVATE;
}
#if 0
if (pwszNewContext)
{
FREE(pwszNewContext);
pwszNewContext = NULL;
}
#endif
} while (FALSE);
switch(dwRes)
{
case ERROR_OKAY:
if (!g_bQuiet)
{
PrintMessageFromModule(g_hModule, MSG_OKAY);
}
break;
case ERROR_NOT_ENOUGH_MEMORY:
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
*pbDone = TRUE;
break;
case ERROR_CMD_NOT_FOUND:
{
LPWSTR pwszCmdLineDup = _wcsdup(pwszCmdLine);
if (!pwszCmdLineDup)
{
PrintMessageFromModule(g_hModule, MSG_NOT_ENOUGH_MEMORY);
return ERROR_NOT_ENOUGH_MEMORY;
}
if (wcslen(pwszCmdLineDup) > 256)
{
wcscpy(pwszCmdLineDup + 250, L"...");
}
PrintMessageFromModule(NULL, ERROR_CMD_NOT_FOUND, pwszCmdLineDup);
free(pwszCmdLineDup);
}
break;
case ERROR_CONTEXT_SWITCH:
{
if (!(dwDisplayFlags & CMD_FLAG_INTERACTIVE))
{
LPWSTR *argv2 = MALLOC((dwArgCount+1) * sizeof(LPWSTR));
if (argv2 is NULL)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
CopyMemory(argv2, argv, dwArgCount * sizeof(LPWSTR));
argv2[dwArgCount] = MALLOC((wcslen(CMD_HELP2)+1) * sizeof(WCHAR));
if (argv2[dwArgCount] is NULL)
{
dwRes = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
wcscpy(argv2[dwArgCount], CMD_HELP2);
g_dwTotalArgCount = dwArgCount+1;
dwRes = ProcessHelperCommand(dwArgCount+1,
argv2,
dwDisplayFlags,
pbDone);
FREE(argv2[dwArgCount]);
}
FREE(argv2);
return dwRes;
}
//
// A context switch.
//
SetContext(g_pwszNewContext);
dwRes = NO_ERROR;
break;
}
case ERROR_CONNECT_REMOTE_CONFIG:
PrintMessageFromModule(g_hModule, EMSG_REMOTE_CONNECT_FAILED,
g_pwszRouterName);
g_bDone = TRUE;
break;
default:
// We don't want to print out an error in the default case here since one would have
// printed by ExecuteHandler already. Doing this will cause a duplicate message to
// be displayed.
break;
}
FREE_ARG_LIST(pleHead);
FREE_ARG_LIST(pleContextHead);
return dwRes;
}
// Append line to the full command
DWORD
AppendLineToCommand(
LPCWSTR pwszCmdLine,
DWORD dwCmdLineLen,
LPWSTR *ppwszFullCommand,
DWORD *dwFullCommandLen
)
{
LPWSTR pwszNewCommand;
DWORD dwErr = NO_ERROR;
DWORD dwLen;
// Allocate enough space to hold the full command
dwLen = *dwFullCommandLen + dwCmdLineLen;
if (*ppwszFullCommand is NULL)
{
pwszNewCommand = MALLOC( (dwLen+1) * sizeof(WCHAR) );
}
else
{
pwszNewCommand = REALLOC(*ppwszFullCommand, (dwLen+1) * sizeof(WCHAR) );
}
if (!pwszNewCommand)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
// Append cmd
wcscpy(pwszNewCommand + *dwFullCommandLen, pwszCmdLine);
// Update the pointer
*ppwszFullCommand = pwszNewCommand;
*dwFullCommandLen = dwLen;
return dwErr;
}
DWORD
MainCommandLoop(
FILE *fp,
BOOL bDisplayPrompt
)
{
LPWSTR pwszFullCommand, p, pwszCmdLine;
DWORD dwFullCommandLen, dwCmdLineLen, dwErr = NO_ERROR;
DWORD dwAnyErr = NO_ERROR;
BOOL bEof, bDone;
for ( ; ; )
{
pwszFullCommand = NULL;
dwFullCommandLen = 0;
bEof = FALSE;
if (bDisplayPrompt)
{
if (g_pwszRouterName)
{
PrintMessage(L"[%1!s!] ", g_pwszRouterName);
}
if (g_pwszContext[0] is L'\0')
{
PrintMessage(RtmonPrompt);
}
else
{
PrintMessage(L"%1!s!>",g_pwszContext);
}
}
// Get an entire command
for (;;)
{
// Get a single line, which may be \ terminated
pwszCmdLine = OEMfgets(&dwCmdLineLen, fp);
if (pwszCmdLine is NULL)
{
bEof = TRUE;
break;
}
p = pwszCmdLine + (dwCmdLineLen-1);
// Trim trailing whitespace
while ((p > pwszCmdLine) && iswspace(p[-1]))
{
*(--p) = 0;
}
if ((p > pwszCmdLine) && (p[-1] is '\\'))
{
// Strip '\\' from the end of the line
*(--p) = 0;
// Append line to the full command
AppendLineToCommand( pwszCmdLine,
(DWORD)(p-pwszCmdLine),
&pwszFullCommand,
&dwFullCommandLen );
FREE(pwszCmdLine);
continue; // Get more input
}
// Append line to the full command
AppendLineToCommand( pwszCmdLine,
(DWORD)(p-pwszCmdLine),
&pwszFullCommand,
&dwFullCommandLen );
// We're done
FREE(pwszCmdLine);
break;
}
if (bEof)
{
break;
}
dwErr = ProcessCommand(pwszFullCommand, &bDone);
if (bDone || g_bDone)
{
FREE(pwszFullCommand);
break;
}
if (dwErr)
{
dwAnyErr = dwErr;
}
FREE(pwszFullCommand);
}
return dwAnyErr;
}
DWORD
LoadScriptFile(
IN LPCWSTR pwszFileName
)
/*++
Routine Description:
Reads in commands from the file and processes them.
Arguments:
pwszFileName - Name of script file.
Return Value:
TRUE, FALSE
--*/
{
FILE* fp;
DWORD i, dwErr = NO_ERROR;
BOOL bOldInteractive = g_bInteractive;
BOOL bOldQuiet = g_bQuiet;
if ((fp = _wfopen(pwszFileName,L"r")) is NULL)
{
PrintMessageFromModule(g_hModule, MSG_OPEN_FAILED, pwszFileName);
return GetLastError();
}
g_bInteractive = TRUE;
g_bQuiet = TRUE;
dwErr = MainCommandLoop(fp, FALSE);
g_bInteractive = bOldInteractive;
g_bQuiet = bOldQuiet;
fclose(fp);
if (dwErr)
{
dwErr = ERROR_SUPPRESS_OUTPUT;
}
return dwErr;
}
// This drops the IPC$ connection to the remote machine (if any).
// This function is called when we switch to a new machine, or netsh finally exits.
//
// deonb 7 Dec 2001
DWORD DisconnectFromCurrentRouter()
{
DWORD dwErr = NO_ERROR;
if (g_pwszRememberedConnection)
{
dwErr = WNetCancelConnection2(g_pwszRememberedConnection, 0, TRUE);
if (dwErr)
{
PrintError(NULL, dwErr);
}
FREE(g_pwszRememberedConnection);
g_pwszRememberedConnection = NULL;
}
return dwErr;
}
DWORD
SetMachine(
IN LPCWSTR pwszNewRouter,
IN LPCWSTR pwszUserName,
IN LPCWSTR pwszPassword
)
{
HRESULT hr;
if (g_pwszRouterName)
{
FREE(g_pwszRouterName);
}
DisconnectFromCurrentRouter();
if (pwszNewRouter)
{
g_pwszRouterName = MALLOC((wcslen(pwszNewRouter) + 1) * sizeof(WCHAR));
if (!g_pwszRouterName)
{
return ERROR_NOT_ENOUGH_MEMORY;
}
wcscpy(g_pwszRouterName, pwszNewRouter);
}
else
{
g_pwszRouterName = NULL;
}
// Change back to root context
SetContext(DEFAULT_STARTUP_CONTEXT);
hr = UpdateVersionInfoGlobals(g_pwszRouterName, pwszUserName, pwszPassword);
if (FAILED(hr))
{
if (g_pwszRouterName)
{
PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
}
else
{
TCHAR szComputerName[MAX_PATH];
DWORD dwComputerNameLen = MAX_PATH;
GetComputerName(szComputerName, &dwComputerNameLen);
PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
}
PrintError(NULL, hr);
}
// Also create a connection to that machine on IPC$. This eliminates the need
// to do a net use before netsh, and then specify the username & password AGAIN to the
// netsh command line.
if (g_pwszRouterName && (pwszUserName || pwszPassword) )
{
WCHAR szIPC[MAX_PATH];
NETRESOURCE NetResource;
wsprintf(szIPC, L"\\\\%s\\ipc$", g_pwszRouterName);
ZeroMemory(&NetResource, sizeof(NETRESOURCE));
NetResource.dwType = RESOURCETYPE_ANY;
NetResource.lpLocalName = NULL;
NetResource.lpProvider = NULL;
NetResource.lpRemoteName= szIPC; // OS Selects a provider
hr = WNetAddConnection2(&NetResource, pwszPassword, pwszUserName, CONNECT_COMMANDLINE | CONNECT_INTERACTIVE);
if (S_OK == hr)
{
g_pwszRememberedConnection = MALLOC(sizeof(WCHAR) * MAX_PATH);
if (!g_pwszRememberedConnection)
{
PrintMessageFromModule(NULL, ERROR_OUTOFMEMORY);
return NO_ERROR; // don't fail the set machine since it did actually work if we're at this point.
}
wcsncpy(g_pwszRememberedConnection, szIPC, MAX_PATH);
}
else
{
PrintError(NULL, hr);
}
}
return NO_ERROR;
}
void SetThreadCodePage()
{
LANGID (WINAPI *pSetThreadUILanguage)() = NULL;
HMODULE hKernel32 = NULL;
hKernel32 = LoadLibrary(L"kernel32.dll");
if (hKernel32)
{
pSetThreadUILanguage = (PVOID) GetProcAddress( hKernel32, "SetThreadUILanguage" );
// OS Platforms before WinXP doesn't support MUI command line utilities so
// we don't need to worry about it if the O/S doesn't support this API.
if (pSetThreadUILanguage)
{
(*pSetThreadUILanguage)( 0 );
}
FreeLibrary(hKernel32);
}
}
int
MainFunction(
int argc,
WCHAR *argv[]
)
{
WCHAR pwszCmdLine[MAX_CMD_LEN] = L"\0";
WCHAR pwszArgContext[MAX_CMD_LEN] = L"\0";
BOOL bOnce = FALSE, bDone = FALSE;
LPCWSTR pwszArgAlias = NULL;
LPCWSTR pwszArgScript = NULL;
DWORD dwErr = NO_ERROR, i;
LPCWSTR p;
HRESULT hr;
LPCWSTR pwszMachineName = NULL;
LPCWSTR pwszUserName = NULL;
LPCWSTR pwszPassword = NULL;
WCHAR szPasswordPrompt[MAX_PATH];
if ((g_hModule = GetModuleHandle(NULL)) is NULL)
{
PRINT1("GetModuleHandle failed");
return 1;
}
swprintf(RtmonPrompt, L"%s>", STRING_NETSH);
//
// Initialize the Alias Table
//
dwErr = ATInitTable();
if (dwErr isnot NO_ERROR)
{
return 0;
}
// Initialize the root helper
AddDllEntry(L"", L"netsh.exe");
//
// Load information about the helpers from the registry.
//
LoadDllInfoFromRegistry();
// Need to set the Ctrl Handler so it can catch the Ctrl C and close window events.
// This is done so the helper dlls can properly be unloaded.
//
SetConsoleCtrlHandler(HandlerRoutine,
TRUE);
//
// Set TEB's language ID to correspond to the console output code page. This
// will ensure the correct language message is displayed when FormatMessage is
// called.
//
SetThreadCodePage();
for ( i = 1; i < (DWORD) argc; i++ )
{
if (_wcsicmp(argv[i], L"-?")==0 ||
_wcsicmp(argv[i], L"-h")==0 ||
_wcsicmp(argv[i], L"?" )==0 ||
_wcsicmp(argv[i], L"/?")==0)
{
(VOID) UpdateVersionInfoGlobals(NULL, NULL, NULL);
// deonb: If this fails we want to restrict the helper from showing up in the context - ignoring
// the return value will accomplish this.
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
ProcessCommand(L"?", &bDone);
// Need to free the helper DLLs before we exit
//
FreeHelpers();
FreeDlls();
return 1;
}
if (_wcsicmp(argv[i], L"-v") == 0)
{
g_bVerbose = TRUE;
continue;
}
if (_wcsicmp(argv[i], L"-a") == 0)
{
//
// alias file
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
pwszArgAlias = argv[i+1];
i++;
continue;
}
}
if (_wcsicmp(argv[i], L"-c") == 0)
{
//
// starting context
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
wcscpy(pwszArgContext, argv[i+1]);
i++;
continue;
}
}
if (_wcsicmp(argv[i], L"-f") == 0)
{
//
// command to run
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
pwszArgScript = argv[i+1];
i++;
bOnce = TRUE;
continue;
}
}
#ifdef ALLOW_REMOTES
if (_wcsicmp(argv[i], L"-r") == 0)
{
//
// router name
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
if (wcslen(argv[i+1]))
{
pwszMachineName = argv[i+1];
}
i++;
continue;
}
}
if (_wcsicmp(argv[i], L"-u") == 0)
{
//
// user name
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
if (wcslen(argv[i+1]))
{
pwszUserName = argv[i+1];
}
i++;
continue;
}
}
if (_wcsicmp(argv[i], L"-p") == 0)
{
//
// password
//
if (i + 1 >= (DWORD)argc)
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
if (wcslen(argv[i+1]))
{
pwszPassword = argv[i+1];
}
i++;
continue;
}
}
#endif
if (!bOnce)
{
while (i < (DWORD)argc)
{
if (pwszCmdLine[0])
{
wcscat(pwszCmdLine, L" ");
}
p = argv[i];
if (!p[0] || wcschr(argv[i], L' '))
{
wcscat(pwszCmdLine, L"\"");
wcscat(pwszCmdLine, p);
wcscat(pwszCmdLine, L"\"");
}
else
{
wcscat(pwszCmdLine, p);
}
i++;
}
}
else
{
PrintMessageFromModule(g_hModule, MSG_NETSH_USAGE, argv[0]);
dwErr = ERROR_INVALID_SYNTAX;
}
break;
}
do
{
if (dwErr isnot NO_ERROR)
{
break;
}
if (pwszMachineName)
{
if (pwszPassword && _wcsicmp(pwszPassword, L"*") == 0)
{
DWORD dwLen = 0;
PrintMessageFromModule(g_hModule, MSG_NETSH_LOGIN_PASSWORD, pwszMachineName);
if (0 != GetPasswdStr(szPasswordPrompt, MAX_PATH, &dwLen))
{
dwErr = ERROR_INVALID_SYNTAX;
break;
}
else
{
pwszPassword = szPasswordPrompt;
}
}
dwErr = SetMachine( pwszMachineName, pwszUserName, pwszPassword );
if (dwErr isnot NO_ERROR)
{
PrintMessageFromModule(g_hModule, dwErr);
break;
}
}
if (!g_pwszRouterName)
{
hr = UpdateVersionInfoGlobals(NULL, NULL, NULL); // Update the info for the local machine
if (FAILED(hr))
{
if (g_pwszRouterName)
{
PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, g_pwszRouterName);
}
else
{
TCHAR szComputerName[MAX_PATH];
DWORD dwComputerNameLen = MAX_PATH;
GetComputerName(szComputerName, &dwComputerNameLen);
PrintMessageFromModule(g_hModule, MSG_WARN_COULDNOTVERCHECKHOST, szComputerName);
}
PrintError(NULL, hr);
}
}
if (pwszArgAlias)
{
dwErr = LoadScriptFile(pwszArgAlias);
if (dwErr)
{
break;
}
}
if (pwszArgContext[0] != L'\0')
{
// The context switch command should be processed in
// interactive mode (which is the only time a context
// switch is legal).
g_bInteractive = TRUE;
dwErr = ProcessCommand(pwszArgContext, &bDone);
g_bInteractive = FALSE;
if (dwErr)
{
break;
}
}
if (pwszCmdLine[0] != L'\0')
{
g_bQuiet = FALSE; // Bug# 262183
dwErr = ProcessCommand(pwszCmdLine, &bDone);
break;
}
if (pwszArgScript)
{
g_bInteractive = TRUE;
dwErr = LoadScriptFile(pwszArgScript);
break;
}
g_bInteractive = TRUE;
g_bQuiet = FALSE;
// Main command loop
dwErr = MainCommandLoop(stdin, TRUE);
} while (FALSE);
//
// Clean up
//
DisconnectFromCurrentRouter();
FreeHelpers();
FreeDlls();
FreeAliasTable();
if(g_pwszRouterName)
{
FREE(g_pwszRouterName);
g_pwszRouterName = NULL;
}
// Return 1 on error, 0 if not
return (dwErr isnot NO_ERROR);
}
int _cdecl
wmain(
int argc,
WCHAR *argv[]
)
/*++
Routine Description:
The main function.
Arguments:
Return Value:
--*/
{
HANDLE hStdOut;
DWORD dwRet;
CONSOLE_SCREEN_BUFFER_INFO csbi;
WORD oldXSize;
char buff[256];
WSADATA wsaData;
HRESULT hr;
#if 0
hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
if (hStdOut is INVALID_HANDLE_VALUE)
{
PRINT1("Standard output could not be opened.");
return 0;
}
GetConsoleScreenBufferInfo(hStdOut, &csbi);
oldXSize = csbi.dwSize.X;
csbi.dwSize.X = 120;
SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
#endif
#if 0
WSAStartup(MAKEWORD(2,0), &wsaData);
if (!gethostname(buff, sizeof(buff)))
{
g_pwszRouterName = MALLOC( (strlen(buff)+1) * sizeof(WCHAR) );
swprintf(g_pwszRouterName, L"%hs", buff);
}
#endif
dwRet = MainFunction(argc, argv);
#if 0
GetConsoleScreenBufferInfo(hStdOut, &csbi);
csbi.dwSize.X = oldXSize;
SetConsoleScreenBufferSize(hStdOut, csbi.dwSize);
CloseHandle(hStdOut);
#endif
return dwRet;
}
BOOL
IsLocalCommand(
IN LPCWSTR pwszCmd,
IN DWORD dwSkipFlags
)
/*++
Arguments:
pwszCmd - string to see if it matches a command
dwSkipFlags - any commands with these flags will be ignored.
This is the opposite semantics of the "dwDisplayFlags"
parameter used elsewhere (dwSkipFlags = ~dwDisplayFlags)
--*/
{
DWORD i, dwErr;
PCNS_CONTEXT_ATTRIBUTES pContext, pSubContext;
PNS_HELPER_TABLE_ENTRY pHelper;
dwErr = GetRootContext( &pContext, &pHelper );
if (dwErr)
{
return FALSE;
}
for (i=0; i<g_ulNumShellCmds; i++)
{
if (!(g_ShellCmds[i].dwFlags & dwSkipFlags)
&& !_wcsicmp( pwszCmd,
g_ShellCmds[i].pwszCmdToken ))
{
return TRUE;
}
}
for (i=0; i<g_ulNumGroups; i++)
{
if (!(g_ShellCmdGroups[i].dwFlags & dwSkipFlags)
&& !_wcsicmp( pwszCmd,
g_ShellCmdGroups[i].pwszCmdGroupToken ))
{
return TRUE;
}
}
for (i=0; i<pHelper->ulNumSubContexts; i++)
{
pSubContext = (PCNS_CONTEXT_ATTRIBUTES)
(pHelper->pSubContextTable + i*pHelper->ulSubContextSize);
if (!(pSubContext->dwFlags & dwSkipFlags)
&& !_wcsicmp( pwszCmd,
pSubContext->pwszContext))
{
return TRUE;
}
}
return FALSE;
}