diff --git a/base/applications/network/netsh/CMakeLists.txt b/base/applications/network/netsh/CMakeLists.txt index 5e4005282da..0c838e60c7c 100644 --- a/base/applications/network/netsh/CMakeLists.txt +++ b/base/applications/network/netsh/CMakeLists.txt @@ -1,8 +1,25 @@ -add_definitions(-D__WINESRC__) -include_directories(${REACTOS_SOURCE_DIR}/sdk/include/wine) -add_executable(netsh netsh.c) -target_link_libraries(netsh wine) +include_directories(${REACTOS_SOURCE_DIR}/sdk/lib/conutils) +spec2def(netsh.exe netsh.spec ADD_IMPORTLIB) + +list(APPEND SOURCE + context.c + help.c + helper.c + interpreter.c + netsh.c + precomp.h) + +add_executable(netsh ${SOURCE} netsh.rc ${CMAKE_CURRENT_BINARY_DIR}/netsh.def) + +set_target_properties(netsh + PROPERTIES + ENABLE_EXPORTS TRUE + DEFINE_SYMBOL "") + set_module_type(netsh win32cui UNICODE) -add_importlibs(netsh msvcrt kernel32 ntdll) +target_link_libraries(netsh conutils ${PSEH_LIB}) +add_importlibs(netsh advapi32 msvcrt user32 kernel32 ntdll) + +add_pch(netsh precomp.h SOURCE) add_cd_file(TARGET netsh DESTINATION reactos/system32 FOR all) diff --git a/base/applications/network/netsh/context.c b/base/applications/network/netsh/context.c new file mode 100644 index 00000000000..dded888c879 --- /dev/null +++ b/base/applications/network/netsh/context.c @@ -0,0 +1,374 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell context management functions + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +/* INCLUDES *******************************************************************/ + +#include "precomp.h" + +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +PCONTEXT_ENTRY pRootContext = NULL; +PCONTEXT_ENTRY pCurrentContext = NULL; + +/* FUNCTIONS ******************************************************************/ + +PCONTEXT_ENTRY +AddContext( + PCONTEXT_ENTRY pParentContext, + PWSTR pszName, + GUID *pGuid) +{ + PCONTEXT_ENTRY pEntry; + + if (pParentContext != NULL && pszName == NULL) + return NULL; + + /* Allocate the entry */ + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(CONTEXT_ENTRY)); + if (pEntry == NULL) + return NULL; + + /* Allocate the name buffer */ + if (pszName != NULL) + { + pEntry->pszContextName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pszName) + 1) * sizeof(WCHAR)); + if (pEntry->pszContextName == NULL) + { + HeapFree(GetProcessHeap(), 0, pEntry); + return NULL; + } + + /* Fill the entry */ + wcscpy(pEntry->pszContextName, pszName); + } + + pEntry->pParentContext = pParentContext; + if (pGuid != NULL) + CopyMemory(&pEntry->Guid, pGuid, sizeof(pEntry->Guid)); + + /* Insert it */ + if (pParentContext != NULL) + { + if (pParentContext->pSubContextHead == NULL && pParentContext->pSubContextTail == NULL) + { + pParentContext->pSubContextHead = pEntry; + pParentContext->pSubContextTail = pEntry; + } + else + { + pEntry->pPrev = pParentContext->pSubContextTail; + pParentContext->pSubContextTail->pNext = pEntry; + pParentContext->pSubContextTail = pEntry; + } + } + + return pEntry; +} + + +PCOMMAND_ENTRY +AddContextCommand( + PCONTEXT_ENTRY pContext, + LPCWSTR pwszCmdToken, + PFN_HANDLE_CMD pfnCmdHandler, + DWORD dwShortCmdHelpToken, + DWORD dwCmdHlpToken, + DWORD dwFlags) +{ + PCOMMAND_ENTRY pEntry; + + if (pfnCmdHandler == NULL) + return NULL; + + /* Allocate the entry */ + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY)); + if (pEntry == NULL) + return NULL; + + pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR)); + if (pEntry->pwszCmdToken == NULL) + { + HeapFree(GetProcessHeap(), 0, pEntry); + return NULL; + } + + wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken); + + pEntry->pfnCmdHandler = pfnCmdHandler; + pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; + pEntry->dwCmdHlpToken = dwCmdHlpToken; + pEntry->dwFlags = dwFlags; + + if (pContext->pCommandListHead == NULL && pContext->pCommandListTail == NULL) + { + pContext->pCommandListHead = pEntry; + pContext->pCommandListTail = pEntry; + } + else + { + pEntry->pPrev = pContext->pCommandListTail; + pContext->pCommandListTail->pNext = pEntry; + pContext->pCommandListTail = pEntry; + } + + return pEntry; +} + + +PCOMMAND_GROUP +AddCommandGroup( + PCONTEXT_ENTRY pContext, + LPCWSTR pwszCmdGroupToken, + DWORD dwShortCmdHelpToken, + DWORD dwFlags) +{ + PCOMMAND_GROUP pEntry; + + /* Allocate the entry */ + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_GROUP)); + if (pEntry == NULL) + return NULL; + + pEntry->pwszCmdGroupToken = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pwszCmdGroupToken) + 1) * sizeof(WCHAR)); + if (pEntry->pwszCmdGroupToken == NULL) + { + HeapFree(GetProcessHeap(), 0, pEntry); + return NULL; + } + + wcscpy((LPWSTR)pEntry->pwszCmdGroupToken, pwszCmdGroupToken); + pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; + pEntry->dwFlags = dwFlags; + + if (pContext->pGroupListHead == NULL && pContext->pGroupListTail == NULL) + { + pContext->pGroupListHead = pEntry; + pContext->pGroupListTail = pEntry; + } + else + { + pEntry->pPrev = pContext->pGroupListTail; + pContext->pGroupListTail->pNext = pEntry; + pContext->pGroupListTail = pEntry; + } + + return pEntry; +} + + +PCOMMAND_ENTRY +AddGroupCommand( + PCOMMAND_GROUP pGroup, + LPCWSTR pwszCmdToken, + PFN_HANDLE_CMD pfnCmdHandler, + DWORD dwShortCmdHelpToken, + DWORD dwCmdHlpToken, + DWORD dwFlags) +{ + PCOMMAND_ENTRY pEntry; + + if (pfnCmdHandler == NULL) + return NULL; + + /* Allocate the entry */ + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(COMMAND_ENTRY)); + if (pEntry == NULL) + return NULL; + + pEntry->pwszCmdToken = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pwszCmdToken) + 1) * sizeof(WCHAR)); + if (pEntry->pwszCmdToken == NULL) + { + HeapFree(GetProcessHeap(), 0, pEntry); + return NULL; + } + + wcscpy((LPWSTR)pEntry->pwszCmdToken, pwszCmdToken); + + pEntry->pfnCmdHandler = pfnCmdHandler; + pEntry->dwShortCmdHelpToken = dwShortCmdHelpToken; + pEntry->dwCmdHlpToken = dwCmdHlpToken; + pEntry->dwFlags = dwFlags; + + if (pGroup->pCommandListHead == NULL && pGroup->pCommandListTail == NULL) + { + pGroup->pCommandListHead = pEntry; + pGroup->pCommandListTail = pEntry; + } + else + { + pEntry->pPrev = pGroup->pCommandListTail; + pGroup->pCommandListTail->pNext = pEntry; + pGroup->pCommandListTail = pEntry; + } + + return pEntry; +} + + +VOID +DeleteContext( + PWSTR pszName) +{ + /* Delete all commands */ + /* Delete the context */ +} + + +DWORD +WINAPI +UpCommand( + LPCWSTR pwszMachine, + LPWSTR *argv, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + if (pCurrentContext != pRootContext) + pCurrentContext = pCurrentContext->pParentContext; + + return 0; +} + + +DWORD +WINAPI +ExitCommand( + LPCWSTR pwszMachine, + LPWSTR *argv, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + *pbDone = TRUE; + return 0; +} + + +DWORD +WINAPI +RemCommand( + LPCWSTR pwszMachine, + LPWSTR *argv, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + return 0; +} + + +BOOL +CreateRootContext(VOID) +{ + PCOMMAND_GROUP pGroup; + + pRootContext = AddContext(NULL, NULL, NULL); + DPRINT1("pRootContext: %p\n", pRootContext); + if (pRootContext == NULL) + return FALSE; + + pRootContext->hModule = GetModuleHandle(NULL); + + AddContextCommand(pRootContext, L"..", UpCommand, IDS_HLP_UP, IDS_HLP_UP_EX, 0); + AddContextCommand(pRootContext, L"?", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); + AddContextCommand(pRootContext, L"bye", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + AddContextCommand(pRootContext, L"exit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + AddContextCommand(pRootContext, L"help", HelpCommand, IDS_HLP_HELP, IDS_HLP_HELP_EX, 0); + AddContextCommand(pRootContext, L"quit", ExitCommand, IDS_HLP_EXIT, IDS_HLP_EXIT_EX, 0); + + pGroup = AddCommandGroup(pRootContext, L"add", IDS_HLP_GROUP_ADD, 0); + if (pGroup) + { + AddGroupCommand(pGroup, L"helper", AddHelperCommand, IDS_HLP_ADD_HELPER, IDS_HLP_ADD_HELPER_EX, 0); + } + + pGroup = AddCommandGroup(pRootContext, L"delete", IDS_HLP_GROUP_DELETE, 0); + if (pGroup) + { + AddGroupCommand(pGroup, L"helper", DeleteHelperCommand, IDS_HLP_DEL_HELPER, IDS_HLP_DEL_HELPER_EX, 0); + } + + pGroup = AddCommandGroup(pRootContext, L"show", IDS_HLP_GROUP_SHOW, 0); + if (pGroup) + { + AddGroupCommand(pGroup, L"helper", ShowHelperCommand, IDS_HLP_SHOW_HELPER, IDS_HLP_SHOW_HELPER_EX, 0); + } + + pCurrentContext = pRootContext; + + return TRUE; +} + + +DWORD +WINAPI +RegisterContext( + _In_ const NS_CONTEXT_ATTRIBUTES *pChildContext) +{ + PCONTEXT_ENTRY pContext; + DWORD i; + + DPRINT1("RegisterContext(%p)\n", pChildContext); + if (pChildContext == NULL) + { + DPRINT1("Invalid child context!\n"); + return ERROR_INVALID_PARAMETER; + } + + if ((pChildContext->pwszContext == NULL) || + (wcslen(pChildContext->pwszContext) == 0) || + (wcschr(pChildContext->pwszContext, L' ') != 0) || + (wcschr(pChildContext->pwszContext, L'=') != 0)) + { + DPRINT1("Invalid context name!\n"); + return ERROR_INVALID_PARAMETER; + } + + DPRINT1("Name: %S\n", pChildContext->pwszContext); + + pContext = AddContext(pRootContext, pChildContext->pwszContext, (GUID*)&pChildContext->guidHelper); + if (pContext != NULL) + { + for (i = 0; i < pChildContext->ulNumTopCmds; i++) + { + AddContextCommand(pContext, + pChildContext->pTopCmds[i].pwszCmdToken, + pChildContext->pTopCmds[i].pfnCmdHandler, + pChildContext->pTopCmds[i].dwShortCmdHelpToken, + pChildContext->pTopCmds[i].dwCmdHlpToken, + pChildContext->pTopCmds[i].dwFlags); + } + + /* Add command groups */ + for (i = 0; i < pChildContext->ulNumGroups; i++) + { + AddCommandGroup(pContext, + pChildContext->pCmdGroups[i].pwszCmdGroupToken, + pChildContext->pCmdGroups[i].dwShortCmdHelpToken, + pChildContext->pCmdGroups[i].dwFlags); + } + } + + return ERROR_SUCCESS; +} diff --git a/base/applications/network/netsh/help.c b/base/applications/network/netsh/help.c new file mode 100644 index 00000000000..a446e1ec10c --- /dev/null +++ b/base/applications/network/netsh/help.c @@ -0,0 +1,152 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell builtin help command and support functions + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +/* INCLUDES *******************************************************************/ + +#include "precomp.h" + +#define NDEBUG +#include + +/* FUNCTIONS ******************************************************************/ + +static +VOID +GetContextFullName( + _In_ PCONTEXT_ENTRY pContext, + _Inout_ LPWSTR pszBuffer, + _In_ DWORD cchLength) +{ + if (pContext->pParentContext != NULL) + { + GetContextFullName(pContext->pParentContext, pszBuffer, cchLength); + wcscat(pszBuffer, L" "); + wcscat(pszBuffer, pContext->pszContextName); + } + else + { + wcscpy(pszBuffer, L"netsh"); + } +} + + +static +VOID +HelpContext( + PCONTEXT_ENTRY pContext) +{ + PCONTEXT_ENTRY pSubContext; + PCOMMAND_ENTRY pCommand; + PCOMMAND_GROUP pGroup; + WCHAR szBuffer[80]; + + if (pContext != pRootContext) + HelpContext(pContext->pParentContext); + + if (pContext == pCurrentContext) + { + ConPrintf(StdOut, L"\nCommands in this context:\n"); + } + else if (pContext == pRootContext) + { + ConPrintf(StdOut, L"\nCommands in the netsh-context:\n"); + } + else + { + GetContextFullName(pContext, szBuffer, 80); + ConPrintf(StdOut, L"\nCommands in the %s-context:\n", szBuffer); + } + + pCommand = pContext->pCommandListHead; + while (pCommand != NULL) + { + if (LoadStringW(pContext->hModule, pCommand->dwShortCmdHelpToken, szBuffer, 80) == 0) + szBuffer[0] = UNICODE_NULL; + ConPrintf(StdOut, L"%-15s - %s\n", pCommand->pwszCmdToken, szBuffer); + pCommand = pCommand->pNext; + } + + pGroup = pContext->pGroupListHead; + while (pGroup != NULL) + { + if (LoadStringW(pContext->hModule, pGroup->dwShortCmdHelpToken, szBuffer, 80) == 0) + szBuffer[0] = UNICODE_NULL; + ConPrintf(StdOut, L"%-15s - %s\n", pGroup->pwszCmdGroupToken, szBuffer); + pGroup = pGroup->pNext; + } + + pSubContext = pContext->pSubContextHead; + while (pSubContext != NULL) + { + GetContextFullName(pSubContext, szBuffer, 80); + ConPrintf(StdOut, L"%-15s - Changes to the \"%s\" context.\n", pSubContext->pszContextName, szBuffer); + pSubContext = pSubContext->pNext; + } +} + + +VOID +HelpGroup( + PCOMMAND_GROUP pGroup) +{ + PCOMMAND_ENTRY pCommand; + WCHAR szBuffer[64]; + + ConResPrintf(StdOut, IDS_HELP_HEADER); + + ConPrintf(StdOut, L"\nCommands in this context:\n"); + + pCommand = pGroup->pCommandListHead; + while (pCommand != NULL) + { + swprintf(szBuffer, L"%s %s", pGroup->pwszCmdGroupToken, pCommand->pwszCmdToken); + ConPrintf(StdOut, L"%-15s - ", szBuffer); + ConResPuts(StdOut, pCommand->dwShortCmdHelpToken); + pCommand = pCommand->pNext; + } +} + + +DWORD +WINAPI +HelpCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + PCONTEXT_ENTRY pContext; + + ConResPrintf(StdOut, IDS_HELP_HEADER); + + pContext = pCurrentContext; + if (pContext == NULL) + { + DPRINT1("HelpCommand: invalid context %p\n", pContext); + return 1; + } + + HelpContext(pContext); + + if (pCurrentContext->pSubContextHead != NULL) + { + ConResPrintf(StdOut, IDS_SUBCONTEXT_HEADER); + pContext = pCurrentContext->pSubContextHead; + while (pContext != NULL) + { + ConPrintf(StdOut, L" %s", pContext->pszContextName); + pContext = pContext->pNext; + } + ConPuts(StdOut, L"\n"); + } + ConPuts(StdOut, L"\n"); + + return ERROR_SUCCESS; +} diff --git a/base/applications/network/netsh/helper.c b/base/applications/network/netsh/helper.c new file mode 100644 index 00000000000..2054a647019 --- /dev/null +++ b/base/applications/network/netsh/helper.c @@ -0,0 +1,593 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell helper dll management and support functions + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +/* INCLUDES *******************************************************************/ + +#include "precomp.h" + +#define NDEBUG +#include + +/* GLOBALS ********************************************************************/ + +PDLL_LIST_ENTRY pDllListHead = NULL; +PDLL_LIST_ENTRY pDllListTail = NULL; + +PHELPER_ENTRY pHelperListHead = NULL; +PHELPER_ENTRY pHelperListTail = NULL; + +PDLL_LIST_ENTRY pCurrentDll = NULL; + +/* FUNCTIONS ******************************************************************/ + +static +VOID +StartHelpers(VOID) +{ + PHELPER_ENTRY pHelper; + DWORD dwError; + + pHelper = pHelperListHead; + while (pHelper != NULL) + { + if (pHelper->bStarted == FALSE) + { + if (pHelper->Attributes.pfnStart) + { + dwError = pHelper->Attributes.pfnStart(NULL, 0); + if (dwError == ERROR_SUCCESS) + pHelper->bStarted = TRUE; + } + } + + pHelper = pHelper->pNext; + } +} + + +static +VOID +RegisterHelperDll( + _In_ PDLL_LIST_ENTRY pEntry) +{ + PWSTR pszValueName = NULL; + HKEY hKey; + DWORD dwError; + + dwError = RegCreateKeyExW(HKEY_LOCAL_MACHINE, + REG_NETSH_PATH, + 0, + NULL, + REG_OPTION_NON_VOLATILE, + KEY_WRITE, + NULL, + &hKey, + NULL); + if (dwError == ERROR_SUCCESS) + { + RegSetValueExW(hKey, + pEntry->pszValueName, + 0, + REG_SZ, + (PBYTE)pEntry->pszDllName, + (wcslen(pEntry->pszDllName) + 1) * sizeof(WCHAR)); + + RegCloseKey(hKey); + } + + HeapFree(GetProcessHeap(), 0, pszValueName); +} + + +static +VOID +FreeHelperDll( + _In_ PDLL_LIST_ENTRY pEntry) +{ + if (pEntry->hModule) + FreeLibrary(pEntry->hModule); + + if (pEntry->pszValueName) + HeapFree(GetProcessHeap(), 0, pEntry->pszValueName); + + if (pEntry->pszShortName) + HeapFree(GetProcessHeap(), 0, pEntry->pszShortName); + + if (pEntry->pszDllName) + HeapFree(GetProcessHeap(), 0, pEntry->pszDllName); + + HeapFree(GetProcessHeap(), 0, pEntry); +} + + +static +DWORD +LoadHelperDll( + _In_ PWSTR pszDllName, + _In_ BOOL bRegister) +{ + PNS_DLL_INIT_FN pInitHelperDll; + PDLL_LIST_ENTRY pEntry; + PWSTR pszStart, pszEnd; + BOOL bInserted = FALSE; + DWORD dwError; + + pEntry = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DLL_LIST_ENTRY)); + if (pEntry == NULL) + { + return ERROR_OUTOFMEMORY; + } + + pEntry->pszDllName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pszDllName) + 1) * sizeof(WCHAR)); + if (pEntry->pszDllName == NULL) + { + dwError = ERROR_OUTOFMEMORY; + goto done; + } + + wcscpy(pEntry->pszDllName, pszDllName); + + pszStart = wcsrchr(pszDllName, L'\\'); + if (pszStart == NULL) + pszStart = pszDllName; + + pEntry->pszShortName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pszStart) + 1) * sizeof(WCHAR)); + if (pEntry->pszShortName == NULL) + { + dwError = ERROR_OUTOFMEMORY; + goto done; + } + + wcscpy(pEntry->pszShortName, pszStart); + + pEntry->pszValueName = HeapAlloc(GetProcessHeap(), + HEAP_ZERO_MEMORY, + (wcslen(pEntry->pszShortName) + 1) * sizeof(WCHAR)); + if (pEntry->pszValueName == NULL) + { + dwError = ERROR_OUTOFMEMORY; + goto done; + } + + wcscpy(pEntry->pszValueName, pEntry->pszShortName); + + pszEnd = wcsrchr(pEntry->pszValueName, L'.'); + if (pszEnd != NULL) + *pszEnd = UNICODE_NULL; + + if (pDllListTail == NULL) + { + pEntry->pPrev = NULL; + pEntry->pNext = NULL; + pDllListHead = pEntry; + pDllListTail = pEntry; + } + else + { + pEntry->pPrev = NULL; + pEntry->pNext = pDllListHead; + pDllListHead->pPrev = pEntry; + pDllListHead = pEntry; + } + + bInserted = TRUE; + + pEntry->hModule = LoadLibraryW(pEntry->pszDllName); + if (pEntry->hModule == NULL) + { + dwError = GetLastError(); + DPRINT1("Could not load the helper dll %S (Error: %lu)\n", pEntry->pszDllName, dwError); + goto done; + } + + pInitHelperDll = (PNS_DLL_INIT_FN)GetProcAddress(pEntry->hModule, "InitHelperDll"); + if (pInitHelperDll == NULL) + { + dwError = GetLastError(); + DPRINT1("Could not find 'InitHelperDll' (Error: %lu)\n", dwError); + goto done; + } + + pCurrentDll = pEntry; + dwError = pInitHelperDll(5, NULL); + pCurrentDll = NULL; + + DPRINT1("InitHelperDll returned %lu\n", dwError); + if (dwError != ERROR_SUCCESS) + { + DPRINT1("Call to InitHelperDll failed (Error: %lu)\n", dwError); + goto done; + } + +// if (pEntry->Attributes.pfnStart) +// pEntry->Attributes.pfnStart(NULL, 0); + + if (bRegister) + RegisterHelperDll(pEntry); + +done: + if (dwError != ERROR_SUCCESS) + { + if (bInserted) + { + if (pEntry->pPrev != NULL) + pEntry->pPrev->pNext = pEntry->pNext; + if (pEntry->pNext != NULL) + pEntry->pNext->pPrev = pEntry->pPrev; + if (pDllListTail == pEntry) + pDllListTail = pEntry->pPrev; + if (pDllListHead == pEntry) + pDllListHead = pEntry->pNext; + pEntry->pPrev = NULL; + pEntry->pNext = NULL; + } + + FreeHelperDll(pEntry); + } + + return dwError; +} + + +VOID +LoadHelpers(VOID) +{ + PWSTR pszNameBuffer = NULL; + PWSTR pszValueBuffer = NULL; + HKEY hKey; + DWORD dwValueCount, dwMaxNameLength, dwMaxValueLength; + DWORD dwNameLength, dwValueLength, dwType; + DWORD dwIndex, dwError; + + DPRINT1("LoadHelpers()\n"); + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + REG_NETSH_PATH, + 0, + KEY_READ, + &hKey); + if (dwError != ERROR_SUCCESS) + return; + + dwError = RegQueryInfoKeyW(hKey, + NULL, + NULL, + NULL, + NULL, + NULL, + NULL, + &dwValueCount, + &dwMaxNameLength, + &dwMaxValueLength, + NULL, + NULL); + if (dwError != ERROR_SUCCESS) + goto done; + + pszNameBuffer = HeapAlloc(GetProcessHeap(), 0, + (dwMaxNameLength + 1) * sizeof(WCHAR)); + if (pszNameBuffer == NULL) + goto done; + + pszValueBuffer = HeapAlloc(GetProcessHeap(), 0, + dwMaxValueLength + sizeof(WCHAR)); + if (pszValueBuffer == NULL) + goto done; + + for (dwIndex = 0; dwIndex < dwValueCount; dwIndex++) + { + dwNameLength = dwMaxNameLength + 1; + dwValueLength = dwMaxValueLength + sizeof(WCHAR); + dwError = RegEnumValueW(hKey, + dwIndex, + pszNameBuffer, + &dwNameLength, + NULL, + &dwType, + (PBYTE)pszValueBuffer, + &dwValueLength); + if (dwError != ERROR_SUCCESS) + break; + + DPRINT1("Dll: %S --> %S %lu\n", pszNameBuffer, pszValueBuffer, dwError); + LoadHelperDll(pszValueBuffer, FALSE); + } + +done: + if (pszValueBuffer) + HeapFree(GetProcessHeap(), 0, pszValueBuffer); + + if (pszNameBuffer) + HeapFree(GetProcessHeap(), 0, pszNameBuffer); + + RegCloseKey(hKey); + + StartHelpers(); +} + + +VOID +UnloadHelpers(VOID) +{ + PDLL_LIST_ENTRY pEntry; + + while (pDllListHead != NULL) + { + pEntry = pDllListHead; + pDllListHead = pEntry->pNext; + +// if (pEntry->Attributes.pfnStop) +// pEntry->Attributes.pfnStop(0); + + FreeHelperDll(pEntry); + } + + pDllListTail = NULL; +} + + +PHELPER_ENTRY +FindHelper( + _In_ const GUID *pguidHelper) +{ + PHELPER_ENTRY pHelper; + + pHelper = pHelperListHead; + while (pHelper != NULL) + { + if (IsEqualGUID(pguidHelper, &pHelper->Attributes.guidHelper)) + return pHelper; + + pHelper = pHelper->pNext; + } + + return NULL; +} + + +DWORD +WINAPI +RegisterHelper( + _In_ const GUID *pguidParentHelper, + _In_ const NS_HELPER_ATTRIBUTES *pHelperAttributes) +{ + PHELPER_ENTRY pHelper = NULL, pParentHelper; + DWORD dwError = ERROR_SUCCESS; + + DPRINT("RegisterHelper(%p %p)\n", pguidParentHelper, pHelperAttributes); + + if (FindHelper(&pHelperAttributes->guidHelper) != NULL) + { + DPRINT1("The Helper has already been registered!\n"); + return 1; + } + + pHelper = (PHELPER_ENTRY)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(HELPER_ENTRY)); + if (pHelper == NULL) + { + dwError = ERROR_OUTOFMEMORY; + goto done; + } + + CopyMemory(&pHelper->Attributes, pHelperAttributes, sizeof(NS_HELPER_ATTRIBUTES)); + pHelper->pDllEntry = pCurrentDll; + DPRINT("pHelper->pDllEntry: %p\n", pHelper->pDllEntry); + + if (pguidParentHelper == NULL) + { + if (pHelperListTail == NULL) + { + pHelperListHead = pHelper; + pHelperListTail = pHelper; + } + else + { + pHelper->pNext = pHelperListHead; + pHelperListHead->pPrev = pHelper; + pHelperListHead = pHelper; + } + } + else + { + pParentHelper = FindHelper(&pHelperAttributes->guidHelper); + if (pParentHelper == NULL) + return ERROR_INVALID_PARAMETER; + + if (pParentHelper->pSubHelperHead == NULL && pParentHelper->pSubHelperTail == NULL) + { + pParentHelper->pSubHelperHead = pHelper; + pParentHelper->pSubHelperTail = pHelper; + } + else + { + pHelper->pPrev = pParentHelper->pSubHelperTail; + pParentHelper->pSubHelperTail->pNext = pHelper; + pParentHelper->pSubHelperTail = pHelper; + } + } + +done: + + return dwError; +} + + +DWORD +WINAPI +AddHelperCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + DWORD dwError = ERROR_SUCCESS; + + DPRINT("AddHelperCommand()\n"); + + if (dwArgCount == 2) + { +// ConResPrintf(StdErr, IDS_INVALID_SYNTAX); +// ConResPrintf(StdErr, IDS_HLP_ADD_HELPER_EX); + return 1; + } + + dwError = LoadHelperDll(ppwcArguments[2], TRUE); + if (dwError != ERROR_SUCCESS) + return dwError; + + StartHelpers(); + + return ERROR_SUCCESS; +} + + +DWORD +WINAPI +DeleteHelperCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + PDLL_LIST_ENTRY pEntry; + HKEY hKey; + DWORD dwError; + + DPRINT("DeleteHelper()\n"); + + if (dwArgCount == 2) + { +// ConResPrintf(StdErr, IDS_INVALID_SYNTAX); +// ConResPrintf(StdErr, IDS_HLP_DEL_HELPER_EX); + return 1; + } + + pEntry = pDllListHead; + while (pEntry != NULL) + { + if (wcscmp(pEntry->pszShortName, ppwcArguments[2]) == 0) + { + DPRINT1("remove %S\n", pEntry->pszShortName); + + if (pEntry->pPrev != NULL) + pEntry->pPrev->pNext = pEntry->pNext; + if (pEntry->pNext != NULL) + pEntry->pNext->pPrev = pEntry->pPrev; + if (pDllListTail == pEntry) + pDllListTail = pEntry->pPrev; + if (pDllListHead == pEntry) + pDllListHead = pEntry->pNext; + pEntry->pPrev = NULL; + pEntry->pNext = NULL; + + dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, + REG_NETSH_PATH, + 0, + KEY_WRITE, + &hKey); + if (dwError == ERROR_SUCCESS) + { + RegDeleteValue(hKey, pEntry->pszValueName); + RegCloseKey(hKey); + } + + FreeHelperDll(pEntry); + + return 1; + } + + pEntry = pEntry->pNext; + } + + return ERROR_SUCCESS; +} + + +static +VOID +PrintSubContext( + _In_ PCONTEXT_ENTRY pParentContext, + _In_ DWORD dwLevel) +{ + PCONTEXT_ENTRY pContext; + PHELPER_ENTRY pHelper; + WCHAR szPrefix[22]; + DWORD i; + + if (pParentContext == NULL) + return; + + pContext = pParentContext->pSubContextHead; + while (pContext != NULL) + { + pHelper = FindHelper(&pContext->Guid); + if (pHelper != NULL) + { + if (dwLevel > 10) + dwLevel = 10; + + for (i = 0; i < dwLevel * 2; i++) + szPrefix[i] = L' '; + szPrefix[i] = UNICODE_NULL; + + ConPrintf(StdOut, L"{%08lX-%04X-%04X-%02X%02X-%02X%02X%02X%02X%02X%02X} %-16s %s%s\n", + pHelper->Attributes.guidHelper.Data1, + pHelper->Attributes.guidHelper.Data2, + pHelper->Attributes.guidHelper.Data3, + pHelper->Attributes.guidHelper.Data4[0], + pHelper->Attributes.guidHelper.Data4[1], + pHelper->Attributes.guidHelper.Data4[2], + pHelper->Attributes.guidHelper.Data4[3], + pHelper->Attributes.guidHelper.Data4[4], + pHelper->Attributes.guidHelper.Data4[5], + pHelper->Attributes.guidHelper.Data4[6], + pHelper->Attributes.guidHelper.Data4[7], + pHelper->pDllEntry->pszShortName, + szPrefix, + pContext->pszContextName); + } + + PrintSubContext(pContext, dwLevel + 1); + + pContext = pContext->pNext; + } +} + + +DWORD +WINAPI +ShowHelperCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone) +{ + DPRINT("ShowHelperCommand()\n"); + + ConPrintf(StdOut, L"Helper GUID DLL Name Command\n"); + ConPrintf(StdOut, L"-------------------------------------- ---------------- --------\n"); + + if (pRootContext == NULL) + return ERROR_SUCCESS; + + PrintSubContext(pRootContext, 0); + + return ERROR_SUCCESS; +} diff --git a/base/applications/network/netsh/interpreter.c b/base/applications/network/netsh/interpreter.c new file mode 100644 index 00000000000..87c5c2fc2fe --- /dev/null +++ b/base/applications/network/netsh/interpreter.c @@ -0,0 +1,238 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell command interpreter + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +/* INCLUDES *******************************************************************/ + +#include "precomp.h" + +#define NDEBUG +#include + +/* FUNCTIONS *****************************************************************/ + +BOOL +InterpretCommand( + _In_ LPWSTR *argv, + _In_ DWORD dwArgCount) +{ + PCONTEXT_ENTRY pContext, pSubContext; + PCOMMAND_ENTRY pCommand; + PCOMMAND_GROUP pGroup; + BOOL bDone = FALSE; + DWORD dwHelpLevel = 0; + DWORD dwError = ERROR_SUCCESS; + + /* If no args provided */ + if (dwArgCount == 0) + return TRUE; + + if (pCurrentContext == NULL) + { + DPRINT1("InterpretCmd: invalid context %p\n", pCurrentContext); + return FALSE; + } + + if ((wcsicmp(argv[dwArgCount - 1], L"?") == 0) || + (wcsicmp(argv[dwArgCount - 1], L"help") == 0)) + { + dwHelpLevel = dwArgCount - 1; + } + + pContext = pCurrentContext; + + while (TRUE) + { + pCommand = pContext->pCommandListHead; + while (pCommand != NULL) + { + if (wcsicmp(argv[0], pCommand->pwszCmdToken) == 0) + { + if (dwHelpLevel == 1) + { + ConResPrintf(StdOut, pCommand->dwCmdHlpToken); + return TRUE; + } + else + { + dwError = pCommand->pfnCmdHandler(NULL, argv, 0, dwArgCount, 0, NULL, &bDone); + if (dwError != ERROR_SUCCESS) + { + ConPrintf(StdOut, L"Error: %lu\n\n"); + ConResPrintf(StdOut, pCommand->dwCmdHlpToken); + } + return !bDone; + } + } + + pCommand = pCommand->pNext; + } + + pGroup = pContext->pGroupListHead; + while (pGroup != NULL) + { + if (wcsicmp(argv[0], pGroup->pwszCmdGroupToken) == 0) + { + if (dwHelpLevel == 1) + { + HelpGroup(pGroup); + return TRUE; + } + + pCommand = pGroup->pCommandListHead; + while (pCommand != NULL) + { + if ((dwArgCount > 1) && (wcsicmp(argv[1], pCommand->pwszCmdToken) == 0)) + { + if (dwHelpLevel == 2) + { + ConResPrintf(StdOut, pCommand->dwCmdHlpToken); + return TRUE; + } + else + { + dwError = pCommand->pfnCmdHandler(NULL, argv, 1, dwArgCount, 0, NULL, &bDone); + if (dwError != ERROR_SUCCESS) + { + ConPrintf(StdOut, L"Error: %lu\n\n"); + ConResPrintf(StdOut, pCommand->dwCmdHlpToken); + return TRUE; + } + return !bDone; + } + } + + pCommand = pCommand->pNext; + } + + HelpGroup(pGroup); + return TRUE; + } + + pGroup = pGroup->pNext; + } + + if (pContext == pCurrentContext) + { + pSubContext = pContext->pSubContextHead; + while (pSubContext != NULL) + { + if (wcsicmp(argv[0], pSubContext->pszContextName) == 0) + { + pCurrentContext = pSubContext; + return TRUE; + } + + pSubContext = pSubContext->pNext; + } + } + + if (pContext == pRootContext) + break; + + pContext = pContext->pParentContext; + } + + ConResPrintf(StdErr, IDS_INVALID_COMMAND, argv[0]); + + return TRUE; +} + + +/* + * InterpretScript(char *line): + * The main function used for when reading commands from scripts. + */ +BOOL +InterpretScript( + _In_ LPWSTR pszInputLine) +{ + LPWSTR args_vector[MAX_ARGS_COUNT]; + DWORD dwArgCount = 0; + BOOL bWhiteSpace = TRUE; + LPWSTR ptr; + + memset(args_vector, 0, sizeof(args_vector)); + + ptr = pszInputLine; + while (*ptr != 0) + { + if (iswspace(*ptr) || *ptr == L'\n') + { + *ptr = 0; + bWhiteSpace = TRUE; + } + else + { + if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT)) + { + args_vector[dwArgCount] = ptr; + dwArgCount++; + } + + bWhiteSpace = FALSE; + } + + ptr++; + } + + /* sends the string to find the command */ + return InterpretCommand(args_vector, dwArgCount); +} + + +VOID +InterpretInteractive(VOID) +{ + WCHAR input_line[MAX_STRING_SIZE]; + LPWSTR args_vector[MAX_ARGS_COUNT]; + DWORD dwArgCount = 0; + BOOL bWhiteSpace = TRUE; + BOOL bRun = TRUE; + LPWSTR ptr; + + while (bRun != FALSE) + { + dwArgCount = 0; + memset(args_vector, 0, sizeof(args_vector)); + + /* Shown just before the input where the user places commands */ +// ConResPuts(StdOut, IDS_APP_PROMPT); + ConPuts(StdOut, L"netsh"); + if (pCurrentContext != pRootContext) + { + ConPuts(StdOut, L" "); + ConPuts(StdOut, pCurrentContext->pszContextName); + } + ConPuts(StdOut, L">"); + + /* Get input from the user. */ + fgetws(input_line, MAX_STRING_SIZE, stdin); + + ptr = input_line; + while (*ptr != 0) + { + if (iswspace(*ptr) || *ptr == L'\n') + { + *ptr = 0; + bWhiteSpace = TRUE; + } + else + { + if ((bWhiteSpace != FALSE) && (dwArgCount < MAX_ARGS_COUNT)) + { + args_vector[dwArgCount] = ptr; + dwArgCount++; + } + bWhiteSpace = FALSE; + } + ptr++; + } + + /* Send the string to find the command */ + bRun = InterpretCommand(args_vector, dwArgCount); + } +} diff --git a/base/applications/network/netsh/lang/en-US.rc b/base/applications/network/netsh/lang/en-US.rc new file mode 100644 index 00000000000..1fd6654e247 --- /dev/null +++ b/base/applications/network/netsh/lang/en-US.rc @@ -0,0 +1,36 @@ +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US + +/* Basic application information */ +STRINGTABLE +BEGIN + IDS_APP_USAGE "\nUsage: netsh [-a AliasFile] [-c Context] [-r RemoteMachine] \ +\n [Command | -f ScriptFile]\n" + IDS_INVALID_COMMAND "The following command was not found: %ls.\n" + IDS_OPEN_FAILED "The file %ls could not be openend.\n" + IDS_INVALID_SYNTAX "The syntax supplied for this command is not valid. Check help for the correct syntax.\n\n" +END + +STRINGTABLE +BEGIN + IDS_HELP_HEADER "\nThe following commands are available:\n" + IDS_SUBCONTEXT_HEADER "\nThe following sub-contexts are available:\n" + IDS_HLP_UP "Goes up one context level." + IDS_HLP_UP_EX "Syntax: ..\n\n Goes up one context level.\n\n" + IDS_HLP_EXIT "Exits the program." + IDS_HLP_EXIT_EX "Syntax: exit\n\n Exits the program.\n\n" + IDS_HLP_HELP "Displays a list of commands." + IDS_HLP_HELP_EX "Syntax: help\n\n Displays a list of commands.\n\n" + + IDS_HLP_ADD_HELPER "Installs a helper DLL." + IDS_HLP_ADD_HELPER_EX "Syntax: add helper \n\n Installs the specified helper DLL in netsh.\n\n" + + IDS_HLP_DEL_HELPER "Removes a helper DLL." + IDS_HLP_DEL_HELPER_EX "Syntax: delete helper \n\n Removes the specified helper DLL from netsh.\n\n" + + IDS_HLP_SHOW_HELPER "Lists all the top-level helpers." + IDS_HLP_SHOW_HELPER_EX "Syntax: show helper\n\n Lists all the top-level helpers.\n\n" + + IDS_HLP_GROUP_ADD "Adds a configuration entry to a list of entries." + IDS_HLP_GROUP_DELETE "Deletes a configuration entry from a list of entries." + IDS_HLP_GROUP_SHOW "Displays information." +END diff --git a/base/applications/network/netsh/netsh.c b/base/applications/network/netsh/netsh.c index bf938698d3c..7c0a33b669b 100644 --- a/base/applications/network/netsh/netsh.c +++ b/base/applications/network/netsh/netsh.c @@ -1,33 +1,254 @@ /* - * Copyright 2010 Hans Leidekker for CodeWeavers - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell main file + * COPYRIGHT: Copyright 2023 Eric Kohl */ -#include +/* INCLUDES *******************************************************************/ -WINE_DEFAULT_DEBUG_CHANNEL(netsh); +#include "precomp.h" -int wmain(int argc, WCHAR *argv[]) +#define NDEBUG +#include + +/* FUNCTIONS ******************************************************************/ + +BOOL +RunScript( + _In_ LPCWSTR filename) { - int i; + FILE *script; + WCHAR tmp_string[MAX_STRING_SIZE]; - WINE_FIXME("stub:"); - for (i = 0; i < argc; i++) - WINE_FIXME(" %s", wine_dbgstr_w(argv[i])); - WINE_FIXME("\n"); + /* Open the file for processing */ + script = _wfopen(filename, L"r"); + if (script == NULL) + { + ConResPrintf(StdErr, IDS_OPEN_FAILED, filename); + return FALSE; + } + /* Read and process the script */ + while (fgetws(tmp_string, MAX_STRING_SIZE, script) != NULL) + { + if (InterpretScript(tmp_string) == FALSE) + { + fclose(script); + return FALSE; + } + } + + /* Close the file */ + fclose(script); + + return TRUE; +} + +/* + * wmain(): + * Main entry point of the application. + */ +int +wmain( + _In_ int argc, + _In_ const LPWSTR argv[]) +{ + LPCWSTR tmpBuffer = NULL; + LPCWSTR pszFileName = NULL; + int index; + int result = EXIT_SUCCESS; + + DPRINT("main()\n"); + + /* Initialize the Console Standard Streams */ + ConInitStdStreams(); + + /* FIXME: Init code goes here */ + CreateRootContext(); + LoadHelpers(); + + if (argc < 2) + { + /* If there are no command arguments, then go straight to the interpreter */ + InterpretInteractive(); + } + else + { + /* If there are command arguments, then process them */ + for (index = 1; index < argc; index++) + { + if ((argv[index][0] == '/')|| + (argv[index][0] == '-')) + { + tmpBuffer = argv[index] + 1; + } + else + { + if (pszFileName != NULL) + { + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_FAILURE; + goto done; + } + + /* Run a command from the command line */ + if (InterpretCommand((LPWSTR*)&argv[index], argc - index) == FALSE) + result = EXIT_FAILURE; + goto done; + } + + if (_wcsicmp(tmpBuffer, L"?") == 0) + { + /* Help option */ + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_SUCCESS; + goto done; + } + else if (_wcsicmp(tmpBuffer, L"a") == 0) + { + /* Aliasfile option */ + if ((index + 1) < argc) + { + index++; + ConPuts(StdOut, L"\nThe -a option is not implemented yet\n"); +// aliasfile = argv[index]; + } + else + { + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_FAILURE; + } + } + else if (_wcsicmp(tmpBuffer, L"c") == 0) + { + /* Context option */ + if ((index + 1) < argc) + { + index++; + ConPuts(StdOut, L"\nThe -c option is not implemented yet\n"); +// context = argv[index]; + } + else + { + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_FAILURE; + } + } + else if (_wcsicmp(tmpBuffer, L"f") == 0) + { + /* File option */ + if ((index + 1) < argc) + { + index++; + pszFileName = argv[index]; + } + else + { + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_FAILURE; + } + } + else if (_wcsicmp(tmpBuffer, L"r") == 0) + { + /* Remote option */ + if ((index + 1) < argc) + { + index++; + ConPuts(StdOut, L"\nThe -r option is not implemented yet\n"); +// remote = argv[index]; + } + else + { + ConResPuts(StdOut, IDS_APP_USAGE); + result = EXIT_FAILURE; + } + } + else + { + /* Invalid command */ + ConResPrintf(StdOut, IDS_INVALID_COMMAND, argv[index]); + result = EXIT_FAILURE; + goto done; + } + } + + /* Now we process the filename if it exists */ + if (pszFileName != NULL) + { + if (RunScript(pszFileName) == FALSE) + { + result = EXIT_FAILURE; + goto done; + } + } + } + +done: + /* FIXME: Cleanup code goes here */ + UnloadHelpers(); + + return result; +} + + +DWORD +WINAPI +MatchEnumTag( + _In_ HANDLE hModule, + _In_ LPCWSTR pwcArg, + _In_ DWORD dwNumArg, + _In_ const TOKEN_VALUE *pEnumTable, + _Out_ PDWORD pdwValue) +{ + DPRINT1("MatchEnumTag()\n"); return 0; } + +BOOL +WINAPI +MatchToken( + _In_ LPCWSTR pwszUserToken, + _In_ LPCWSTR pwszCmdToken) +{ + DPRINT1("MatchToken %S %S\n", pwszUserToken, pwszCmdToken); + return (wcsicmp(pwszUserToken, pwszCmdToken) == 0) ? TRUE : FALSE; +} + +DWORD +CDECL +PrintError( + _In_opt_ HANDLE hModule, + _In_ DWORD dwErrId, + ...) +{ + DPRINT1("PrintError()\n"); + return 1; +} + +DWORD +CDECL +PrintMessageFromModule( + _In_ HANDLE hModule, + _In_ DWORD dwMsgId, + ...) +{ + DPRINT1("PrintMessageFromModule()\n"); + return 1; +} + +DWORD +CDECL +PrintMessage( + _In_ LPCWSTR pwszFormat, + ...) +{ + INT Length; + va_list ap; + + va_start(ap, pwszFormat); + Length = ConPrintf(StdOut, pwszFormat); + va_end(ap); + + return Length; +} diff --git a/base/applications/network/netsh/netsh.rc b/base/applications/network/netsh/netsh.rc new file mode 100644 index 00000000000..448c3239e04 --- /dev/null +++ b/base/applications/network/netsh/netsh.rc @@ -0,0 +1,15 @@ +#include + +#include "resource.h" + +#define REACTOS_STR_FILE_DESCRIPTION "Net Shell" +#define REACTOS_STR_INTERNAL_NAME "netsh" +#define REACTOS_STR_ORIGINAL_FILENAME "netsh.exe" +#include + +/* UTF-8 */ +#pragma code_page(65001) + +#ifdef LANGUAGE_EN_US + #include "lang/en-US.rc" +#endif diff --git a/base/applications/network/netsh/netsh.spec b/base/applications/network/netsh/netsh.spec new file mode 100644 index 00000000000..4d82c1e7f36 --- /dev/null +++ b/base/applications/network/netsh/netsh.spec @@ -0,0 +1,7 @@ +@ stdcall MatchEnumTag(ptr wstr long ptr ptr) +@ stdcall MatchToken(wstr wstr) +@ varargs PrintError(ptr long) +@ varargs PrintMessage(wstr) +@ varargs PrintMessageFromModule(ptr long) +@ stdcall RegisterContext(ptr) +@ stdcall RegisterHelper(ptr ptr) diff --git a/base/applications/network/netsh/precomp.h b/base/applications/network/netsh/precomp.h new file mode 100644 index 00000000000..031b03cc767 --- /dev/null +++ b/base/applications/network/netsh/precomp.h @@ -0,0 +1,205 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell main header file + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +#ifndef PRECOMP_H +#define PRECOMP_H + +/* INCLUDES ******************************************************************/ + +#include +#include +#include + +#define WIN32_NO_STATUS +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include "resource.h" + + +/* DEFINES *******************************************************************/ + +#define MAX_STRING_SIZE 1024 +#define MAX_ARGS_COUNT 256 + +#define REG_NETSH_PATH L"Software\\Microsoft\\NetSh" + + +/* TYPEDEFS ******************************************************************/ + +typedef struct _DLL_LIST_ENTRY +{ + struct _DLL_LIST_ENTRY *pPrev; + struct _DLL_LIST_ENTRY *pNext; + + PWSTR pszDllName; + PWSTR pszShortName; + PWSTR pszValueName; + + HMODULE hModule; + +} DLL_LIST_ENTRY, *PDLL_LIST_ENTRY; + +typedef struct _HELPER_ENTRY +{ + struct _HELPER_ENTRY *pPrev; + struct _HELPER_ENTRY *pNext; + + NS_HELPER_ATTRIBUTES Attributes; + + PDLL_LIST_ENTRY pDllEntry; + BOOL bStarted; + + struct _HELPER_ENTRY *pSubHelperHead; + struct _HELPER_ENTRY *pSubHelperTail; + +} HELPER_ENTRY, *PHELPER_ENTRY; + + + +typedef struct _COMMAND_ENTRY +{ + struct _COMMAND_ENTRY *pPrev; + struct _COMMAND_ENTRY *pNext; + + LPCWSTR pwszCmdToken; + PFN_HANDLE_CMD pfnCmdHandler; + DWORD dwShortCmdHelpToken; + DWORD dwCmdHlpToken; + DWORD dwFlags; +} COMMAND_ENTRY, *PCOMMAND_ENTRY; + +typedef struct _COMMAND_GROUP +{ + struct _COMMAND_GROUP *pPrev; + struct _COMMAND_GROUP *pNext; + + LPCWSTR pwszCmdGroupToken; + DWORD dwShortCmdHelpToken; + DWORD dwFlags; + + PCOMMAND_ENTRY pCommandListHead; + PCOMMAND_ENTRY pCommandListTail; +} COMMAND_GROUP, *PCOMMAND_GROUP; + +typedef struct _CONTEXT_ENTRY +{ + struct _CONTEXT_ENTRY *pPrev; + struct _CONTEXT_ENTRY *pNext; + + struct _CONTEXT_ENTRY *pParentContext; + + PWSTR pszContextName; + GUID Guid; + HMODULE hModule; + + PCOMMAND_ENTRY pCommandListHead; + PCOMMAND_ENTRY pCommandListTail; + + PCOMMAND_GROUP pGroupListHead; + PCOMMAND_GROUP pGroupListTail; + + struct _CONTEXT_ENTRY *pSubContextHead; + struct _CONTEXT_ENTRY *pSubContextTail; +} CONTEXT_ENTRY, *PCONTEXT_ENTRY; + + +/* GLOBAL VARIABLES ***********************************************************/ + +extern PCONTEXT_ENTRY pRootContext; +extern PCONTEXT_ENTRY pCurrentContext; + + +/* PROTOTYPES *****************************************************************/ + +/* context.c */ + +BOOL +CreateRootContext(VOID); + + +/* help.c */ +DWORD +WINAPI +HelpCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone); + +VOID +HelpGroup( + PCOMMAND_GROUP pGroup); + + +/* helper.c */ +VOID +LoadHelpers(VOID); + +VOID +UnloadHelpers(VOID); + + +DWORD +WINAPI +AddHelperCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone); + +DWORD +WINAPI +DeleteHelperCommand( + LPCWSTR pwszMachine, + LPWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone); + +DWORD +WINAPI +ShowHelperCommand( + LPCWSTR pwszMachine, + PWSTR *ppwcArguments, + DWORD dwCurrentIndex, + DWORD dwArgCount, + DWORD dwFlags, + LPCVOID pvData, + BOOL *pbDone); + + +/* interpreter.c */ +BOOL +InterpretScript( + LPWSTR pszFileName); + +BOOL +InterpretCommand( + LPWSTR *argv, + DWORD dwArgCount); + +VOID +InterpretInteractive(VOID); + +#endif /* PRECOMP_H */ diff --git a/base/applications/network/netsh/resource.h b/base/applications/network/netsh/resource.h new file mode 100644 index 00000000000..e3875fd655c --- /dev/null +++ b/base/applications/network/netsh/resource.h @@ -0,0 +1,37 @@ +/* + * PROJECT: ReactOS NetSh + * LICENSE: GPL-2.0-or-later (https://spdx.org/licenses/GPL-2.0-or-later) + * PURPOSE: Network Shell resource id header file + * COPYRIGHT: Copyright 2023 Eric Kohl + */ + +#pragma once + +#define IDS_NONE -1 + +#define IDS_APP_USAGE 100 +#define IDS_APP_PROMPT 101 +#define IDS_INVALID_COMMAND 102 +#define IDS_OPEN_FAILED 103 +#define IDS_INVALID_SYNTAX 104 + +#define IDS_HELP_HEADER 200 +#define IDS_SUBCONTEXT_HEADER 201 + +#define IDS_HLP_EXIT 300 +#define IDS_HLP_EXIT_EX 301 +#define IDS_HLP_HELP 302 +#define IDS_HLP_HELP_EX 303 +#define IDS_HLP_UP 304 +#define IDS_HLP_UP_EX 305 + +#define IDS_HLP_ADD_HELPER 310 +#define IDS_HLP_ADD_HELPER_EX 311 +#define IDS_HLP_DEL_HELPER 312 +#define IDS_HLP_DEL_HELPER_EX 313 +#define IDS_HLP_SHOW_HELPER 314 +#define IDS_HLP_SHOW_HELPER_EX 315 + +#define IDS_HLP_GROUP_ADD 320 +#define IDS_HLP_GROUP_DELETE 321 +#define IDS_HLP_GROUP_SHOW 322 \ No newline at end of file