1 /* 2 * PROJECT: ReactOS runas utility 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: base/applications/runas/runas.c 5 * COPYRIGHT: Copyright 2022 Eric Kohl <eric.kohl@reactos.org> 6 */ 7 8 #include <stdio.h> 9 #include <stdlib.h> 10 #include <limits.h> 11 #include <stdarg.h> 12 13 #define WIN32_NO_STATUS 14 #include <windef.h> 15 #include <winbase.h> 16 #include <winnls.h> 17 #include <wincon.h> 18 #include <winsvc.h> 19 #include <conutils.h> 20 21 #include "resource.h" 22 23 #define NDEBUG 24 #include <debug.h> 25 26 #define MAX_PASSWORD_LENGTH 64 27 28 static 29 VOID 30 Usage(VOID) 31 { 32 int i; 33 for (i = IDS_USAGE01; i <= IDS_USAGE_MAX; i++) 34 ConResPuts(StdOut, i); 35 } 36 37 38 static 39 VOID 40 ConInString( 41 _In_ PWSTR pInput, 42 _In_ DWORD dwLength) 43 { 44 DWORD dwOldMode; 45 DWORD dwRead = 0; 46 HANDLE hFile; 47 PWSTR p; 48 PCHAR pBuf; 49 50 pBuf = (PCHAR)HeapAlloc(GetProcessHeap(), 0, dwLength - 1); 51 ZeroMemory(pInput, dwLength * sizeof(WCHAR)); 52 hFile = GetStdHandle(STD_INPUT_HANDLE); 53 GetConsoleMode(hFile, &dwOldMode); 54 55 SetConsoleMode(hFile, ENABLE_LINE_INPUT /*| ENABLE_ECHO_INPUT*/); 56 57 ReadFile(hFile, (PVOID)pBuf, dwLength - 1, &dwRead, NULL); 58 59 MultiByteToWideChar(GetConsoleCP(), 0, pBuf, dwRead, pInput, dwLength - 1); 60 HeapFree(GetProcessHeap(), 0, pBuf); 61 62 for (p = pInput; *p; p++) 63 { 64 if (*p == L'\x0d') 65 { 66 *p = UNICODE_NULL; 67 break; 68 } 69 } 70 71 SetConsoleMode(hFile, dwOldMode); 72 } 73 74 75 int 76 wmain( 77 int argc, 78 LPCWSTR argv[]) 79 { 80 LPCWSTR pszArg; 81 int i, result = 0; 82 BOOL bProfile = FALSE, bNoProfile = FALSE; 83 BOOL bEnv = FALSE, bNetOnly = FALSE; 84 PWSTR pszUserName = NULL; 85 PWSTR pszDomain = NULL; 86 PWSTR pszCommandLine = NULL; 87 PWSTR pszPassword = NULL; 88 PWSTR pszCurrentDirectory = NULL; 89 PWSTR pszEnvironment = NULL; 90 PWSTR ptr; 91 STARTUPINFOW StartupInfo; 92 PROCESS_INFORMATION ProcessInfo; 93 DWORD dwLogonFlags = LOGON_WITH_PROFILE; 94 DWORD dwCreateFlags = 0; 95 BOOL rc; 96 97 /* Initialize the Console Standard Streams */ 98 ConInitStdStreams(); 99 100 if (argc == 1) 101 { 102 Usage(); 103 return 0; 104 } 105 106 ZeroMemory(&StartupInfo, sizeof(StartupInfo)); 107 ZeroMemory(&ProcessInfo, sizeof(ProcessInfo)); 108 109 for (i = 1; i < argc; i++) 110 { 111 pszArg = argv[i]; 112 if (*pszArg == L'-' || *pszArg == L'/') 113 { 114 pszArg++; 115 if (wcscmp(pszArg, L"?") == 0) 116 { 117 Usage(); 118 result = 0; 119 goto done; 120 } 121 else if (wcsicmp(pszArg, L"profile") == 0) 122 { 123 bProfile = TRUE; 124 } 125 else if (wcsicmp(pszArg, L"netonly") == 0) 126 { 127 bNetOnly = TRUE; 128 } 129 else if (wcsicmp(pszArg, L"noprofile") == 0) 130 { 131 bNoProfile = TRUE; 132 } 133 else if (wcsicmp(pszArg, L"env") == 0) 134 { 135 bEnv = TRUE; 136 } 137 else if (_wcsnicmp(pszArg, L"user:", 5) == 0) 138 { 139 pszArg += 5; 140 ptr = wcschr(pszArg, L'@'); 141 if (ptr != NULL) 142 { 143 /* User@Domain */ 144 pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((ptr - pszArg) + 1) * sizeof(WCHAR)); 145 if (pszUserName == NULL) 146 { 147 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 148 result = -1; 149 goto done; 150 } 151 152 wcsncpy(pszUserName, pszArg, (ptr - pszArg)); 153 154 ptr++; 155 pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(ptr) + 1) * sizeof(WCHAR)); 156 if (pszDomain == NULL) 157 { 158 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 159 result = -1; 160 goto done; 161 } 162 163 wcscpy(pszDomain, ptr); 164 } 165 else 166 { 167 ptr = wcschr(pszArg, L'\\'); 168 if (ptr != NULL) 169 { 170 /* Domain\User */ 171 pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(ptr + 1) + 1)* sizeof(WCHAR)); 172 if (pszUserName == NULL) 173 { 174 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 175 result = -1; 176 goto done; 177 } 178 179 wcscpy(pszUserName, (ptr + 1)); 180 181 pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, ((ptr - pszArg) + 1) * sizeof(WCHAR)); 182 if (pszDomain == NULL) 183 { 184 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 185 result = -1; 186 goto done; 187 } 188 189 wcsncpy(pszDomain, pszArg, (ptr - pszArg)); 190 } 191 else 192 { 193 /* User */ 194 pszUserName = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pszArg) + 1) * sizeof(WCHAR)); 195 if (pszUserName == NULL) 196 { 197 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 198 result = -1; 199 goto done; 200 } 201 202 wcscpy(pszUserName, pszArg); 203 } 204 } 205 } 206 else 207 { 208 Usage(); 209 result = -1; 210 goto done; 211 } 212 } 213 else 214 { 215 if (pszCommandLine == NULL) 216 { 217 pszCommandLine = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (wcslen(pszArg) + 1) * sizeof(WCHAR)); 218 if (pszCommandLine == NULL) 219 { 220 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 221 result = -1; 222 goto done; 223 } 224 225 wcscpy(pszCommandLine, pszArg); 226 break; 227 } 228 } 229 } 230 231 /* Check for incompatible options */ 232 if ((bProfile && bNoProfile) || 233 (bProfile && bNetOnly)) 234 { 235 Usage(); 236 result = -1; 237 goto done; 238 } 239 240 /* Check for existing command line and user name */ 241 if (pszCommandLine == NULL || pszUserName == NULL) 242 { 243 Usage(); 244 result = -1; 245 goto done; 246 } 247 248 if (bProfile) 249 dwLogonFlags |= LOGON_WITH_PROFILE; 250 251 if (bNoProfile) 252 dwLogonFlags &= ~LOGON_WITH_PROFILE; 253 254 if (bNetOnly) 255 { 256 dwLogonFlags |= LOGON_NETCREDENTIALS_ONLY; 257 dwLogonFlags &= ~LOGON_WITH_PROFILE; 258 } 259 260 DPRINT("User: %S\n", pszUserName); 261 DPRINT("Domain: %S\n", pszDomain); 262 DPRINT("CommandLine: %S\n", pszCommandLine); 263 264 if (pszDomain == NULL) 265 { 266 DWORD dwLength = MAX_COMPUTERNAME_LENGTH + 1; 267 pszDomain = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, dwLength * sizeof(WCHAR)); 268 if (pszDomain == NULL) 269 { 270 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 271 result = -1; 272 goto done; 273 } 274 275 GetComputerNameW(pszDomain, &dwLength); 276 } 277 278 if (bEnv) 279 { 280 pszEnvironment = GetEnvironmentStringsW(); 281 pszCurrentDirectory = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PATH + 1) * sizeof(WCHAR)); 282 if (pszCurrentDirectory == NULL) 283 { 284 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 285 result = -1; 286 goto done; 287 } 288 289 GetCurrentDirectory(MAX_PATH + 1, pszCurrentDirectory); 290 dwCreateFlags |= CREATE_UNICODE_ENVIRONMENT; 291 } 292 293 pszPassword = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (MAX_PASSWORD_LENGTH + 1) * sizeof(WCHAR)); 294 if (pszPassword == NULL) 295 { 296 ConResPrintf(StdOut, IDS_INTERNAL_ERROR, ERROR_OUTOFMEMORY); 297 result = -1; 298 goto done; 299 } 300 301 /* Query the password */ 302 ConResPrintf(StdOut, IDS_PASSWORD, pszDomain, pszUserName); 303 ConInString(pszPassword, MAX_PASSWORD_LENGTH + 1); 304 ConPuts(StdOut, L"\n"); 305 306 ConResPrintf(StdOut, IDS_START, pszCommandLine, pszDomain, pszUserName); 307 308 rc = CreateProcessWithLogonW(pszUserName, 309 pszDomain, 310 pszPassword, 311 dwLogonFlags, 312 NULL, 313 pszCommandLine, 314 dwCreateFlags, 315 pszEnvironment, 316 pszCurrentDirectory, 317 &StartupInfo, 318 &ProcessInfo); 319 if (rc == FALSE) 320 { 321 ConResPrintf(StdOut, IDS_RUN_ERROR, pszCommandLine); 322 ConPrintf(StdOut, L"%lu\n", GetLastError()); 323 } 324 325 done: 326 if (ProcessInfo.hThread) 327 CloseHandle(ProcessInfo.hThread); 328 329 if (ProcessInfo.hProcess) 330 CloseHandle(ProcessInfo.hProcess); 331 332 if (pszPassword) 333 HeapFree(GetProcessHeap(), 0, pszPassword); 334 335 /* NOTE: Do NOT free pszEnvironment */ 336 337 if (pszCurrentDirectory) 338 HeapFree(GetProcessHeap(), 0, pszCurrentDirectory); 339 340 if (pszCommandLine) 341 HeapFree(GetProcessHeap(), 0, pszCommandLine); 342 343 if (pszUserName) 344 HeapFree(GetProcessHeap(), 0, pszUserName); 345 346 if (pszDomain) 347 HeapFree(GetProcessHeap(), 0, pszDomain); 348 349 return result; 350 } 351