xref: /reactos/base/applications/runas/runas.c (revision e4930be4)
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