15811da1eSEric Kohl /*
25811da1eSEric Kohl * PROJECT: ReactOS runas utility
35811da1eSEric Kohl * LICENSE: GPL - See COPYING in the top level directory
45811da1eSEric Kohl * FILE: base/applications/runas/runas.c
55811da1eSEric Kohl * COPYRIGHT: Copyright 2022 Eric Kohl <eric.kohl@reactos.org>
65811da1eSEric Kohl */
75811da1eSEric Kohl
85811da1eSEric Kohl #include <stdio.h>
95811da1eSEric Kohl #include <stdlib.h>
105811da1eSEric Kohl #include <limits.h>
115811da1eSEric Kohl #include <stdarg.h>
125811da1eSEric Kohl
135811da1eSEric Kohl #define WIN32_NO_STATUS
145811da1eSEric Kohl #include <windef.h>
155811da1eSEric Kohl #include <winbase.h>
165811da1eSEric Kohl #include <winnls.h>
175811da1eSEric Kohl #include <wincon.h>
185811da1eSEric Kohl #include <winsvc.h>
195811da1eSEric Kohl #include <conutils.h>
205811da1eSEric Kohl
215811da1eSEric Kohl #include "resource.h"
225811da1eSEric Kohl
235811da1eSEric Kohl #define NDEBUG
245811da1eSEric Kohl #include <debug.h>
255811da1eSEric Kohl
26c14440eeSEric Kohl #define MAX_PASSWORD_LENGTH 64
27c14440eeSEric Kohl
285811da1eSEric Kohl static
29c14440eeSEric Kohl VOID
Usage(VOID)30c14440eeSEric Kohl Usage(VOID)
315811da1eSEric Kohl {
32c14440eeSEric Kohl int i;
33c14440eeSEric Kohl for (i = IDS_USAGE01; i <= IDS_USAGE_MAX; i++)
34c14440eeSEric Kohl ConResPuts(StdOut, i);
35c14440eeSEric Kohl }
36c14440eeSEric Kohl
37c14440eeSEric Kohl
38c14440eeSEric Kohl static
39c14440eeSEric Kohl VOID
ConInString(_In_ PWSTR pInput,_In_ DWORD dwLength)40c14440eeSEric Kohl ConInString(
41c14440eeSEric Kohl _In_ PWSTR pInput,
42c14440eeSEric Kohl _In_ DWORD dwLength)
43c14440eeSEric Kohl {
44c14440eeSEric Kohl DWORD dwOldMode;
45c14440eeSEric Kohl DWORD dwRead = 0;
46c14440eeSEric Kohl HANDLE hFile;
47c14440eeSEric Kohl PWSTR p;
48c14440eeSEric Kohl PCHAR pBuf;
49c14440eeSEric Kohl
50c14440eeSEric Kohl pBuf = (PCHAR)HeapAlloc(GetProcessHeap(), 0, dwLength - 1);
51c14440eeSEric Kohl ZeroMemory(pInput, dwLength * sizeof(WCHAR));
52c14440eeSEric Kohl hFile = GetStdHandle(STD_INPUT_HANDLE);
53c14440eeSEric Kohl GetConsoleMode(hFile, &dwOldMode);
54c14440eeSEric Kohl
55c14440eeSEric Kohl SetConsoleMode(hFile, ENABLE_LINE_INPUT /*| ENABLE_ECHO_INPUT*/);
56c14440eeSEric Kohl
57c14440eeSEric Kohl ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL);
58c14440eeSEric Kohl
59c14440eeSEric Kohl MultiByteToWideChar(GetConsoleCP(), 0, pBuf, dwRead, pInput, dwLength - 1);
60c14440eeSEric Kohl HeapFree(GetProcessHeap(), 0, pBuf);
61c14440eeSEric Kohl
62c14440eeSEric Kohl for (p = pInput; *p; p++)
63c14440eeSEric Kohl {
64c14440eeSEric Kohl if (*p == L'\x0d')
65c14440eeSEric Kohl {
66c14440eeSEric Kohl *p = UNICODE_NULL;
67c14440eeSEric Kohl break;
68c14440eeSEric Kohl }
69c14440eeSEric Kohl }
70c14440eeSEric Kohl
71c14440eeSEric Kohl SetConsoleMode(hFile, dwOldMode);
725811da1eSEric Kohl }
735811da1eSEric Kohl
745811da1eSEric Kohl
755811da1eSEric Kohl int
wmain(int argc,LPCWSTR argv[])765811da1eSEric Kohl wmain(
775811da1eSEric Kohl int argc,
785811da1eSEric Kohl LPCWSTR argv[])
795811da1eSEric Kohl {
805811da1eSEric Kohl LPCWSTR pszArg;
815811da1eSEric Kohl int i, result = 0;
825811da1eSEric Kohl BOOL bProfile = FALSE, bNoProfile = FALSE;
834109072bSEric Kohl BOOL bEnv = FALSE, bNetOnly = FALSE;
845811da1eSEric Kohl PWSTR pszUserName = NULL;
855811da1eSEric Kohl PWSTR pszDomain = NULL;
865811da1eSEric Kohl PWSTR pszCommandLine = NULL;
875811da1eSEric Kohl PWSTR pszPassword = NULL;
88d4b947aaSEric Kohl PWSTR pszCurrentDirectory = NULL;
89d4b947aaSEric Kohl PWSTR pszEnvironment = NULL;
905811da1eSEric Kohl PWSTR ptr;
915811da1eSEric Kohl STARTUPINFOW StartupInfo;
925811da1eSEric Kohl PROCESS_INFORMATION ProcessInfo;
93eb0830a1SEric Kohl DWORD dwLogonFlags = LOGON_WITH_PROFILE;
94d4b947aaSEric Kohl DWORD dwCreateFlags = 0;
955811da1eSEric Kohl BOOL rc;
965811da1eSEric Kohl
975811da1eSEric Kohl /* Initialize the Console Standard Streams */
985811da1eSEric Kohl ConInitStdStreams();
995811da1eSEric Kohl
1005811da1eSEric Kohl if (argc == 1)
1015811da1eSEric Kohl {
1025811da1eSEric Kohl Usage();
1035811da1eSEric Kohl return 0;
1045811da1eSEric Kohl }
1055811da1eSEric Kohl
1065811da1eSEric Kohl ZeroMemory(&StartupInfo, sizeof(StartupInfo));
1075811da1eSEric Kohl ZeroMemory(&ProcessInfo, sizeof(ProcessInfo));
1085811da1eSEric Kohl
1095811da1eSEric Kohl for (i = 1; i < argc; i++)
1105811da1eSEric Kohl {
1115811da1eSEric Kohl pszArg = argv[i];
1125811da1eSEric Kohl if (*pszArg == L'-' || *pszArg == L'/')
1135811da1eSEric Kohl {
1145811da1eSEric Kohl pszArg++;
1155811da1eSEric Kohl if (wcscmp(pszArg, L"?") == 0)
1165811da1eSEric Kohl {
1175811da1eSEric Kohl Usage();
118d4b947aaSEric Kohl result = 0;
119d4b947aaSEric Kohl goto done;
1205811da1eSEric Kohl }
121*e4930be4STimo Kreuzer else if (_wcsicmp(pszArg, L"profile") == 0)
1225811da1eSEric Kohl {
1235811da1eSEric Kohl bProfile = TRUE;
1245811da1eSEric Kohl }
125*e4930be4STimo Kreuzer else if (_wcsicmp(pszArg, L"netonly") == 0)
1264109072bSEric Kohl {
1274109072bSEric Kohl bNetOnly = TRUE;
1284109072bSEric Kohl }
129*e4930be4STimo Kreuzer else if (_wcsicmp(pszArg, L"noprofile") == 0)
1305811da1eSEric Kohl {
1315811da1eSEric Kohl bNoProfile = TRUE;
1325811da1eSEric Kohl }
133*e4930be4STimo Kreuzer else if (_wcsicmp(pszArg, L"env") == 0)
1345811da1eSEric Kohl {
1355811da1eSEric Kohl bEnv = TRUE;
1365811da1eSEric Kohl }
1375811da1eSEric Kohl else if (_wcsnicmp(pszArg, L"user:", 5) == 0)
1385811da1eSEric Kohl {
1395811da1eSEric Kohl pszArg += 5;
1405811da1eSEric Kohl ptr = wcschr(pszArg, L'@');
1415811da1eSEric Kohl if (ptr != NULL)
1425811da1eSEric Kohl {
1435811da1eSEric Kohl /* User@Domain */
1445811da1eSEric Kohl pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((ptr - pszArg) + 1) * sizeof(WCHAR));
145d4b947aaSEric Kohl if (pszUserName == NULL)
146d4b947aaSEric Kohl {
147d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
148d4b947aaSEric Kohl result = -1;
149d4b947aaSEric Kohl goto done;
150d4b947aaSEric Kohl }
151d4b947aaSEric Kohl
1525811da1eSEric Kohl wcsncpy(pszUserName, pszArg, (ptr - pszArg));
1535811da1eSEric Kohl
1545811da1eSEric Kohl ptr++;
1555811da1eSEric Kohl pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(ptr) + 1) * sizeof(WCHAR));
156d4b947aaSEric Kohl if (pszDomain == NULL)
157d4b947aaSEric Kohl {
158d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
159d4b947aaSEric Kohl result = -1;
160d4b947aaSEric Kohl goto done;
161d4b947aaSEric Kohl }
162d4b947aaSEric Kohl
1635811da1eSEric Kohl wcscpy(pszDomain, ptr);
1645811da1eSEric Kohl }
1655811da1eSEric Kohl else
1665811da1eSEric Kohl {
1675811da1eSEric Kohl ptr = wcschr(pszArg, L'\\');
1685811da1eSEric Kohl if (ptr != NULL)
1695811da1eSEric Kohl {
1705811da1eSEric Kohl /* Domain\User */
1715811da1eSEric Kohl pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(ptr + 1) + 1)* sizeof(WCHAR));
172d4b947aaSEric Kohl if (pszUserName == NULL)
173d4b947aaSEric Kohl {
174d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
175d4b947aaSEric Kohl result = -1;
176d4b947aaSEric Kohl goto done;
177d4b947aaSEric Kohl }
178d4b947aaSEric Kohl
1795811da1eSEric Kohl wcscpy(pszUserName, (ptr + 1));
1805811da1eSEric Kohl
1815811da1eSEric Kohl pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((ptr - pszArg) + 1) * sizeof(WCHAR));
182d4b947aaSEric Kohl if (pszDomain == NULL)
183d4b947aaSEric Kohl {
184d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
185d4b947aaSEric Kohl result = -1;
186d4b947aaSEric Kohl goto done;
187d4b947aaSEric Kohl }
188d4b947aaSEric Kohl
1895811da1eSEric Kohl wcsncpy(pszDomain, pszArg, (ptr - pszArg));
1905811da1eSEric Kohl }
1915811da1eSEric Kohl else
1925811da1eSEric Kohl {
1935811da1eSEric Kohl /* User */
1945811da1eSEric Kohl pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pszArg) + 1) * sizeof(WCHAR));
195d4b947aaSEric Kohl if (pszUserName == NULL)
196d4b947aaSEric Kohl {
197d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
198d4b947aaSEric Kohl result = -1;
199d4b947aaSEric Kohl goto done;
200d4b947aaSEric Kohl }
201d4b947aaSEric Kohl
2025811da1eSEric Kohl wcscpy(pszUserName, pszArg);
2035811da1eSEric Kohl }
2045811da1eSEric Kohl }
2055811da1eSEric Kohl }
2065811da1eSEric Kohl else
2075811da1eSEric Kohl {
2085811da1eSEric Kohl Usage();
2095811da1eSEric Kohl result = -1;
210d4b947aaSEric Kohl goto done;
2115811da1eSEric Kohl }
2125811da1eSEric Kohl }
2135811da1eSEric Kohl else
2145811da1eSEric Kohl {
2155811da1eSEric Kohl if (pszCommandLine == NULL)
2165811da1eSEric Kohl {
2175811da1eSEric Kohl pszCommandLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pszArg) + 1) * sizeof(WCHAR));
218d4b947aaSEric Kohl if (pszCommandLine == NULL)
219d4b947aaSEric Kohl {
220d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
221d4b947aaSEric Kohl result = -1;
222d4b947aaSEric Kohl goto done;
223d4b947aaSEric Kohl }
224d4b947aaSEric Kohl
2255811da1eSEric Kohl wcscpy(pszCommandLine, pszArg);
2265811da1eSEric Kohl break;
2275811da1eSEric Kohl }
2285811da1eSEric Kohl }
2295811da1eSEric Kohl }
2305811da1eSEric Kohl
2314109072bSEric Kohl /* Check for incompatible options */
2324109072bSEric Kohl if ((bProfile && bNoProfile) ||
2334109072bSEric Kohl (bProfile && bNetOnly))
2344109072bSEric Kohl {
2354109072bSEric Kohl Usage();
2364109072bSEric Kohl result = -1;
2374109072bSEric Kohl goto done;
2384109072bSEric Kohl }
2394109072bSEric Kohl
2404109072bSEric Kohl /* Check for existing command line and user name */
2414109072bSEric Kohl if (pszCommandLine == NULL || pszUserName == NULL)
2425811da1eSEric Kohl {
2435811da1eSEric Kohl Usage();
2445811da1eSEric Kohl result = -1;
2455811da1eSEric Kohl goto done;
2465811da1eSEric Kohl }
2475811da1eSEric Kohl
2485811da1eSEric Kohl if (bProfile)
2495811da1eSEric Kohl dwLogonFlags |= LOGON_WITH_PROFILE;
2505811da1eSEric Kohl
2515811da1eSEric Kohl if (bNoProfile)
2525811da1eSEric Kohl dwLogonFlags &= ~LOGON_WITH_PROFILE;
2535811da1eSEric Kohl
2544109072bSEric Kohl if (bNetOnly)
2554109072bSEric Kohl {
2564109072bSEric Kohl dwLogonFlags |= LOGON_NETCREDENTIALS_ONLY;
2574109072bSEric Kohl dwLogonFlags &= ~LOGON_WITH_PROFILE;
2584109072bSEric Kohl }
2594109072bSEric Kohl
2605811da1eSEric Kohl DPRINT("User: %S\n", pszUserName);
2615811da1eSEric Kohl DPRINT("Domain: %S\n", pszDomain);
2625811da1eSEric Kohl DPRINT("CommandLine: %S\n", pszCommandLine);
2635811da1eSEric Kohl
264c14440eeSEric Kohl if (pszDomain == NULL)
265c14440eeSEric Kohl {
266c14440eeSEric Kohl DWORD dwLength = MAX_COMPUTERNAME_LENGTH + 1;
267c14440eeSEric Kohl pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength * sizeof(WCHAR));
268d4b947aaSEric Kohl if (pszDomain == NULL)
269d4b947aaSEric Kohl {
270d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
271d4b947aaSEric Kohl result = -1;
272d4b947aaSEric Kohl goto done;
273d4b947aaSEric Kohl }
274d4b947aaSEric Kohl
275c14440eeSEric Kohl GetComputerNameW(pszDomain, &dwLength);
276c14440eeSEric Kohl }
277c14440eeSEric Kohl
278d4b947aaSEric Kohl if (bEnv)
279d4b947aaSEric Kohl {
280d4b947aaSEric Kohl pszEnvironment = GetEnvironmentStringsW();
281d4b947aaSEric Kohl pszCurrentDirectory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH + 1) * sizeof(WCHAR));
282d4b947aaSEric Kohl if (pszCurrentDirectory == NULL)
283d4b947aaSEric Kohl {
284d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
285d4b947aaSEric Kohl result = -1;
286d4b947aaSEric Kohl goto done;
287d4b947aaSEric Kohl }
288d4b947aaSEric Kohl
289d4b947aaSEric Kohl GetCurrentDirectory(MAX_PATH + 1, pszCurrentDirectory);
290d4b947aaSEric Kohl dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT;
291d4b947aaSEric Kohl }
292d4b947aaSEric Kohl
293c14440eeSEric Kohl pszPassword = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PASSWORD_LENGTH + 1) * sizeof(WCHAR));
294d4b947aaSEric Kohl if (pszPassword == NULL)
295d4b947aaSEric Kohl {
296d4b947aaSEric Kohl ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY);
297d4b947aaSEric Kohl result = -1;
298d4b947aaSEric Kohl goto done;
299d4b947aaSEric Kohl }
300c14440eeSEric Kohl
301c14440eeSEric Kohl /* Query the password */
302c14440eeSEric Kohl ConResPrintf(StdOut, IDS_PASSWORD, pszDomain, pszUserName);
303c14440eeSEric Kohl ConInString(pszPassword, MAX_PASSWORD_LENGTH + 1);
304c14440eeSEric Kohl ConPuts(StdOut, L"\n");
305c14440eeSEric Kohl
306c14440eeSEric Kohl ConResPrintf(StdOut, IDS_START, pszCommandLine, pszDomain, pszUserName);
3075811da1eSEric Kohl
3085811da1eSEric Kohl rc = CreateProcessWithLogonW(pszUserName,
3095811da1eSEric Kohl pszDomain,
3105811da1eSEric Kohl pszPassword,
3115811da1eSEric Kohl dwLogonFlags,
312d4b947aaSEric Kohl NULL,
3135811da1eSEric Kohl pszCommandLine,
314d4b947aaSEric Kohl dwCreateFlags,
315d4b947aaSEric Kohl pszEnvironment,
316d4b947aaSEric Kohl pszCurrentDirectory,
3175811da1eSEric Kohl &StartupInfo,
3185811da1eSEric Kohl &ProcessInfo);
3195811da1eSEric Kohl if (rc == FALSE)
3205811da1eSEric Kohl {
321c14440eeSEric Kohl ConResPrintf(StdOut, IDS_RUN_ERROR, pszCommandLine);
322d4b947aaSEric Kohl ConPrintf(StdOut, L"%lu\n", GetLastError());
3235811da1eSEric Kohl }
3245811da1eSEric Kohl
3255811da1eSEric Kohl done:
3265811da1eSEric Kohl if (ProcessInfo.hThread)
3275811da1eSEric Kohl CloseHandle(ProcessInfo.hThread);
3285811da1eSEric Kohl
3295811da1eSEric Kohl if (ProcessInfo.hProcess)
3305811da1eSEric Kohl CloseHandle(ProcessInfo.hProcess);
3315811da1eSEric Kohl
3325811da1eSEric Kohl if (pszPassword)
3335811da1eSEric Kohl HeapFree(GetProcessHeap(), 0, pszPassword);
3345811da1eSEric Kohl
335d4b947aaSEric Kohl /* NOTE: Do NOT free pszEnvironment */
336d4b947aaSEric Kohl
337d4b947aaSEric Kohl if (pszCurrentDirectory)
338d4b947aaSEric Kohl HeapFree(GetProcessHeap(), 0, pszCurrentDirectory);
339d4b947aaSEric Kohl
3405811da1eSEric Kohl if (pszCommandLine)
3415811da1eSEric Kohl HeapFree(GetProcessHeap(), 0, pszCommandLine);
3425811da1eSEric Kohl
3435811da1eSEric Kohl if (pszUserName)
3445811da1eSEric Kohl HeapFree(GetProcessHeap(), 0, pszUserName);
3455811da1eSEric Kohl
3465811da1eSEric Kohl if (pszDomain)
3475811da1eSEric Kohl HeapFree(GetProcessHeap(), 0, pszDomain);
3485811da1eSEric Kohl
3495811da1eSEric Kohl return result;
3505811da1eSEric Kohl }
351