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.

1164 lines
38 KiB

  1. /*+
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1997 - 2000.
  5. *
  6. * Name : runas.cxx
  7. * Author:Jeffrey Richter (v-jeffrr)
  8. *
  9. * Abstract:
  10. * This is the RUNAS tool. It uses CreateProcessWithLogon API
  11. * to start processes under different security context than the
  12. * currently logged on user.
  13. *
  14. * Revision History:
  15. * PraeritG 10/8/97 To integrate this in to services.exe
  16. *
  17. -*/
  18. #define STRICT
  19. #define UNICODE 1
  20. #include <Windows.h>
  21. #include <shellapi.h>
  22. #include <stdarg.h>
  23. #include <stdio.h>
  24. #include <winsafer.h>
  25. #include <wincred.h>
  26. #include <lmcons.h>
  27. #include <netlib.h>
  28. #include <strsafe.h>
  29. #ifndef SECURITY_WIN32
  30. #define SECURITY_WIN32
  31. #endif
  32. #include <security.h>
  33. #include "dbgdef.h"
  34. #include "stringid.h"
  35. #include "rmtcred.h"
  36. #include "utils.h"
  37. #include "RunasMsg.h"
  38. // Helper macros:
  39. #define ARRAYSIZE(a) ((sizeof(a))/(sizeof(a[0])))
  40. #define FIELDOFFSET(s,m) (size_t)&(((s *)0)->m)
  41. #define PSAD_NULL_DATA (-1)
  42. #define PSAD_STRING_DATA (-2)
  43. #define PSAD_NO_MORE_DATA (-1)
  44. //
  45. // must move to winbase.h soon!
  46. #define LOGON_WITH_PROFILE 0x00000001
  47. #define LOGON_NETCREDENTIALS_ONLY 0x00000002
  48. // NT Process exit codes:
  49. #define EXIT_CODE_SUCCEEDED 0
  50. #define EXIT_CODE_FAILED 1
  51. // Credential flags:
  52. #define RUNAS_USE_SMARTCARD 0x00000001
  53. #define RUNAS_USE_SAVEDCREDS 0x00000002
  54. #define RUNAS_SAVE_CREDS 0x00000004
  55. // Argument IDs for command line parsing:
  56. enum ArgId {
  57. AI_ENV = 0,
  58. AI_NETONLY,
  59. AI_NOPROFILE,
  60. AI_PROFILE,
  61. AI_TRUSTLEVEL,
  62. AI_USER,
  63. AI_SMARTCARD,
  64. AI_SHOWTRUSTLEVELS,
  65. AI_SAVECRED
  66. } ArgId;
  67. BOOL rgArgCompat[9][9] =
  68. {
  69. // ENV NETONLY NOPROFILE PROFILE TRUSTLEVEL USER SMARTCARD SHOWTRUSTLEVELS SAVECRED
  70. { FALSE, TRUE, TRUE, TRUE, FALSE, TRUE, TRUE, FALSE, TRUE }, // ENV
  71. { TRUE, FALSE, TRUE, FALSE, FALSE, TRUE, FALSE, FALSE, FALSE }, // NETONLY
  72. { TRUE, TRUE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE }, // NOPROFILE
  73. { TRUE, FALSE, FALSE, FALSE, FALSE, TRUE, TRUE, FALSE, TRUE }, // PROFILE
  74. { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // TRUSTLEVEL
  75. { TRUE, TRUE, TRUE, TRUE, FALSE, FALSE, TRUE, FALSE, TRUE }, // USER
  76. { TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE }, // SMARTCARD
  77. { FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE }, // SHOWTRUSTLEVELS
  78. { TRUE, FALSE, TRUE, TRUE, FALSE, TRUE, FALSE, FALSE, FALSE } // SAVECRED
  79. };
  80. #define _CheckArgCompat(args, n, ai) \
  81. { \
  82. for (int _i = 0; _i < (n); _i++) { \
  83. if (FALSE == rgArgCompat[(ai)][(args)[_i]]) { \
  84. RunasPrintHelp(); \
  85. return (EXIT_CODE_FAILED); \
  86. } \
  87. } \
  88. (args)[(n)] = (ai); \
  89. }
  90. HMODULE hMod = NULL;
  91. HANDLE g_hStdout = NULL;
  92. void DbgPrintf( DWORD /*dwSubSysId*/, LPCSTR /*pszFormat*/ , ...)
  93. {
  94. /* We're not currently using the DbgPrintf functionality, and it's breaking compiles with /W4
  95. va_list args;
  96. CHAR pszBuffer[1024];
  97. va_start(args, pszFormat);
  98. _vsnprintf(pszBuffer, 1024, pszFormat, args);
  99. va_end(args);
  100. OutputDebugStringA(pszBuffer);
  101. */
  102. }
  103. typedef BOOLEAN (WINAPI * SetThreadUILanguageFunc)(DWORD dwReserved);
  104. SetThreadUILanguageFunc g_pfnSetThreadUILanguage = NULL;
  105. HRESULT MySetThreadUILanguage(DWORD dwParam)
  106. {
  107. HMODULE hKernel32Dll = NULL;
  108. HRESULT hr;
  109. if (NULL == g_pfnSetThreadUILanguage) {
  110. // We've got the correct system directory now.
  111. hKernel32Dll = LoadLibraryW(L"kernel32.dll");
  112. if (NULL == hKernel32Dll) {
  113. hr = HRESULT_FROM_WIN32(GetLastError());
  114. goto error;
  115. }
  116. g_pfnSetThreadUILanguage = (SetThreadUILanguageFunc)GetProcAddress(hKernel32Dll, "SetThreadUILanguage");
  117. if (NULL == g_pfnSetThreadUILanguage) {
  118. hr = HRESULT_FROM_WIN32(GetLastError());
  119. goto error;
  120. }
  121. }
  122. g_pfnSetThreadUILanguage(dwParam);
  123. hr = S_OK;
  124. error:
  125. if (NULL != hKernel32Dll) {
  126. FreeLibrary(hKernel32Dll);
  127. }
  128. return hr;
  129. }
  130. HRESULT InitializeConsoleOutput() {
  131. g_hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  132. if (INVALID_HANDLE_VALUE == g_hStdout) {
  133. return HRESULT_FROM_WIN32(GetLastError());
  134. }
  135. return S_OK;
  136. }
  137. HRESULT LocalizedWPrintf(UINT nResourceID) {
  138. DWORD ccWritten;
  139. DWORD dwRetval;
  140. WCHAR rgwszString[512];
  141. dwRetval = LoadStringW(hMod, nResourceID, rgwszString, ARRAYSIZE(rgwszString));
  142. if (0 == dwRetval) {
  143. return HRESULT_FROM_WIN32(GetLastError());
  144. }
  145. if (!WriteConsoleW(g_hStdout, rgwszString, (DWORD)wcslen(rgwszString), &ccWritten, NULL)) {
  146. return HRESULT_FROM_WIN32(GetLastError());
  147. }
  148. return S_OK;
  149. }
  150. DWORD MyGetLastError() {
  151. DWORD dwResult = GetLastError();
  152. if (ERROR_SUCCESS == dwResult) {
  153. dwResult = (DWORD)E_FAIL;
  154. }
  155. return dwResult;
  156. }
  157. VOID
  158. DisplayMsg(DWORD dwSource, DWORD dwMsgId, ... )
  159. {
  160. DWORD dwBytesWritten;
  161. DWORD dwLen;
  162. LPWSTR pwszDisplayBuffer = NULL;
  163. va_list ap;
  164. va_start(ap, dwMsgId);
  165. dwLen = FormatMessageW(dwSource | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  166. NULL,
  167. dwMsgId,
  168. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  169. (LPWSTR)&pwszDisplayBuffer,
  170. 0,
  171. &ap);
  172. if (dwLen && pwszDisplayBuffer) {
  173. WriteConsoleW(g_hStdout,
  174. (LPVOID)pwszDisplayBuffer,
  175. dwLen,
  176. &dwBytesWritten,
  177. NULL);
  178. }
  179. if (NULL != pwszDisplayBuffer) { LocalFree(pwszDisplayBuffer); }
  180. va_end(ap);
  181. }
  182. BOOL WriteMsg(DWORD dwSource, DWORD dwMsgId, LPWSTR *ppMsg, ...)
  183. {
  184. DWORD dwLen;
  185. va_list ap;
  186. va_start(ap, ppMsg);
  187. dwLen = FormatMessageW(dwSource | FORMAT_MESSAGE_ALLOCATE_BUFFER,
  188. NULL,
  189. dwMsgId,
  190. MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
  191. (LPWSTR)ppMsg,
  192. 0,
  193. &ap);
  194. va_end(ap);
  195. // 0 is the error return value of FormatMessage.
  196. return (0 != dwLen);
  197. }
  198. DWORD GetCredentials
  199. (IN DWORD dwCredFlags,
  200. IN OUT LPWSTR pwszPassword,
  201. IN DWORD ccPasswordChars,
  202. IN OUT LPWSTR pwszUserName,
  203. IN DWORD ccUserNameChars,
  204. IN OUT LPWSTR pwszUserDisplayName,
  205. IN DWORD ccUserDisplayNameChars,
  206. IN OUT LPWSTR pwszTarget,
  207. IN DWORD ccTarget)
  208. {
  209. BOOL fResult;
  210. DWORD dwCreduiCmdlineFlags = 0;
  211. DWORD dwResult;
  212. HRESULT hr;
  213. LPWSTR pwszAccountDomainName = NULL;
  214. LPWSTR pwszMarshalledCred = NULL;
  215. if (RUNAS_USE_SAVEDCREDS & dwCredFlags) {
  216. if (NULL == wcschr(pwszUserName, L'\\') && NULL == wcschr(pwszUserName, L'@')) {
  217. WCHAR wszUserNameTmp[CREDUI_MAX_USERNAME_LENGTH+1];
  218. memset(&wszUserNameTmp[0], 0, sizeof(wszUserNameTmp));
  219. // We have a username in relative form. Try to prepend the machine name (for workstations) or domain name (for DCs).
  220. // We'll need to use a temporary buffer, because the safe string functions don't have an equivalent for memmove().
  221. pwszAccountDomainName = GetAccountDomainName();
  222. _JumpCondition(NULL == pwszAccountDomainName, GetAccountDomainNameError);
  223. // 1) Copy the relative username to a temporary buffer:
  224. hr = StringCchCopy(wszUserNameTmp, ARRAYSIZE(wszUserNameTmp), pwszUserName);
  225. _JumpCondition(FAILED(hr), StringCchCopyError);
  226. // 2) Copy the domain name into the username buffer
  227. hr = StringCchCopy(pwszUserName, ccUserNameChars, pwszAccountDomainName);
  228. _JumpCondition(FAILED(hr), StringCchCopyError);
  229. // 3) Concatenate the \username
  230. hr = StringCchCat(pwszUserName, ccUserNameChars, L"\\");
  231. _JumpCondition(FAILED(hr), StringCchCatError);
  232. hr = StringCchCat(pwszUserName, ccUserNameChars, wszUserNameTmp);
  233. _JumpCondition(FAILED(hr), StringCchCatError);
  234. }
  235. USERNAME_TARGET_CREDENTIAL_INFO utci = { pwszUserName };
  236. // Get the marshalled credential from credman.
  237. fResult = CredMarshalCredentialW(UsernameTargetCredential, &utci, &pwszMarshalledCred);
  238. _JumpCondition(FALSE == fResult, CredMarshalCredentialWError);
  239. // User the user-supplied name as the display name.
  240. hr = StringCchCopy(pwszUserDisplayName, ccUserDisplayNameChars, pwszUserName);
  241. _JumpCondition(FAILED(hr), StringCchCopyError);
  242. // Copy the marshalled cred to the user name. We use an empty
  243. // passwd with the marshalled cred.
  244. hr = StringCchCopy(pwszUserName, ccUserNameChars, pwszMarshalledCred);
  245. _JumpCondition(FAILED(hr), StringCchCopyError);
  246. }
  247. else {
  248. dwCreduiCmdlineFlags =
  249. CREDUI_FLAGS_USERNAME_TARGET_CREDENTIALS // These are 'runas' credentials
  250. | CREDUI_FLAGS_VALIDATE_USERNAME; // Ensure that the username syntax is correct
  251. if (RUNAS_USE_SMARTCARD & dwCredFlags) {
  252. dwCreduiCmdlineFlags |= CREDUI_FLAGS_REQUIRE_SMARTCARD;
  253. fResult = LoadStringW(hMod, RUNASP_STRING_SMARTCARDUSER, pwszTarget, ccTarget);
  254. _JumpCondition(FALSE == fResult, LoadStringError);
  255. }
  256. else {
  257. dwCreduiCmdlineFlags |= CREDUI_FLAGS_EXCLUDE_CERTIFICATES; // we don't (yet) know how to handle certificates
  258. hr = StringCchCopy(pwszTarget, ccTarget, pwszUserName);
  259. _JumpCondition(FAILED(hr), StringCchCopyError);
  260. }
  261. if (RUNAS_SAVE_CREDS & dwCredFlags) {
  262. dwCreduiCmdlineFlags |=
  263. CREDUI_FLAGS_PERSIST // persist creds automatically
  264. | CREDUI_FLAGS_EXPECT_CONFIRMATION; // Don't store bogus creds into credman.
  265. } else {
  266. dwCreduiCmdlineFlags |=
  267. CREDUI_FLAGS_DO_NOT_PERSIST; // Do not persist the creds
  268. }
  269. dwResult = CredUICmdLinePromptForCredentialsW
  270. (pwszTarget,
  271. NULL,
  272. NO_ERROR,
  273. pwszUserName,
  274. ccUserNameChars,
  275. pwszPassword,
  276. ccPasswordChars,
  277. NULL,
  278. dwCreduiCmdlineFlags);
  279. _JumpCondition(ERROR_SUCCESS != dwResult, CredUICmdLineGetPasswordError);
  280. if (RUNAS_USE_SMARTCARD & dwCredFlags) {
  281. // Smartcard creds are not human-readable. Get a display name:
  282. fResult = CreduiGetCertDisplayNameFromMarshaledName
  283. (pwszUserName,
  284. pwszUserDisplayName,
  285. ccUserDisplayNameChars,
  286. FALSE);
  287. _JumpCondition(FALSE == fResult, CreduiGetCertDisplayNameFromMarshaledNameError);
  288. }
  289. else {
  290. hr = StringCchCopy(pwszUserDisplayName, ccUserDisplayNameChars, pwszUserName);
  291. _JumpCondition(FAILED(hr), StringCchCopyError);
  292. }
  293. }
  294. dwResult = ERROR_SUCCESS;
  295. ErrorReturn:
  296. if (NULL != pwszAccountDomainName) { NetApiBufferFree(pwszAccountDomainName); }
  297. return dwResult;
  298. SET_DWRESULT(CredMarshalCredentialWError, GetLastError());
  299. SET_DWRESULT(CredUICmdLineGetPasswordError, dwResult);
  300. SET_DWRESULT(CreduiGetCertDisplayNameFromMarshaledNameError, GetLastError());
  301. SET_DWRESULT(GetAccountDomainNameError, GetLastError());
  302. SET_DWRESULT(LoadStringError, GetLastError());
  303. SET_DWRESULT(StringCchCatError, (DWORD)hr);
  304. SET_DWRESULT(StringCchCopyError, (DWORD)hr);
  305. }
  306. DWORD SaveCredentials
  307. (IN LPWSTR pwszTarget,
  308. IN BOOL fSave)
  309. {
  310. return CredUIConfirmCredentialsW(pwszTarget, fSave);
  311. }
  312. BOOL GetTitle
  313. (IN LPWSTR pwszAppName,
  314. IN LPWSTR pwszUserName,
  315. IN BOOL fRestricted,
  316. IN LPWSTR pwszAuthzLevel,
  317. OUT LPWSTR *ppwszTitle)
  318. {
  319. DWORD dwMsgId = fRestricted ? RUNASP_STRING_TITLE_WITH_RESTRICTED : RUNASP_STRING_TITLE;
  320. return WriteMsg(FORMAT_MESSAGE_FROM_HMODULE,
  321. dwMsgId,
  322. ppwszTitle,
  323. pwszAppName,
  324. pwszUserName,
  325. pwszAuthzLevel);
  326. }
  327. // Creates the process with a given "privilege level".
  328. //
  329. // dwAuthzLevel -- specifies the authorization level ID to create the
  330. // process with. Can be one of the following values:
  331. //
  332. // SAFER_LEVELID_FULLYTRUSTED
  333. // SAFER_LEVELID_NORMALUSER
  334. // SAFER_LEVELID_CONSTRAINED
  335. // SAFER_LEVELID_UNTRUSTED
  336. //
  337. BOOL CreateProcessRestricted
  338. (IN DWORD dwAuthzLevel,
  339. IN LPCWSTR pwszAppName,
  340. IN LPWSTR pwszCmdLine,
  341. IN LPWSTR pwszCurrentDirectory,
  342. IN LPSTARTUPINFO si,
  343. OUT PROCESS_INFORMATION *pi)
  344. {
  345. BOOL fResult = FALSE;
  346. DWORD dwCreationFlags = 0;
  347. SAFER_LEVEL_HANDLE hAuthzLevel = NULL;
  348. HANDLE hToken = NULL;
  349. // Maintain old runas behavior: console apps run in a new console.
  350. dwCreationFlags |= CREATE_NEW_CONSOLE;
  351. fResult = SaferCreateLevel
  352. (SAFER_SCOPEID_MACHINE,
  353. dwAuthzLevel,
  354. SAFER_LEVEL_OPEN,
  355. &hAuthzLevel,
  356. NULL);
  357. _JumpCondition(FALSE == fResult, error);
  358. // Generate the restricted token that we will use.
  359. fResult = SaferComputeTokenFromLevel
  360. (hAuthzLevel,
  361. NULL, // source token
  362. &hToken, // target token
  363. SAFER_TOKEN_MAKE_INERT, // runas should run with the inert flag
  364. NULL); // reserved
  365. _JumpCondition(FALSE == fResult, error);
  366. // Launch the child process under the context of the restricted token.
  367. fResult = CreateProcessAsUser
  368. (hToken, // token representing the user
  369. pwszAppName, // name of executable module
  370. pwszCmdLine, // command-line string
  371. NULL, // process security attributes
  372. NULL, // thread security attributes
  373. FALSE, // if process inherits handles
  374. dwCreationFlags, // creation flags
  375. NULL, // new environment block
  376. pwszCurrentDirectory, // current directory name
  377. si, // startup information
  378. pi // process information
  379. );
  380. // success.
  381. error:
  382. if (NULL != hAuthzLevel) { SaferCloseLevel(hAuthzLevel); }
  383. if (NULL != hToken) { CloseHandle(hToken); }
  384. return fResult;
  385. }
  386. DWORD FriendlyNameToTrustLevelID(LPWSTR pwszFriendlyName,
  387. DWORD *pdwTrustLevelID)
  388. {
  389. BOOL fResult;
  390. DWORD cbSize;
  391. DWORD dwResult;
  392. DWORD dwNumLevels;
  393. DWORD *pdwLevelIDs = NULL;
  394. SAFER_LEVEL_HANDLE hAuthzLevel = NULL;
  395. WCHAR wszLevelName[1024];
  396. DWORD dwBufferSize = 0;
  397. fResult = SaferGetPolicyInformation
  398. (SAFER_SCOPEID_MACHINE,
  399. SaferPolicyLevelList,
  400. 0,
  401. NULL,
  402. &cbSize,
  403. NULL);
  404. _JumpCondition(FALSE == fResult && ERROR_INSUFFICIENT_BUFFER != GetLastError(), GetInformationCodeAuthzPolicyWError);
  405. dwNumLevels = cbSize / sizeof(DWORD);
  406. pdwLevelIDs = (DWORD *)HeapAlloc(GetProcessHeap(), 0, cbSize);
  407. _JumpCondition(NULL == pdwLevelIDs, MemoryError);
  408. fResult = SaferGetPolicyInformation
  409. (SAFER_SCOPEID_MACHINE,
  410. SaferPolicyLevelList,
  411. cbSize,
  412. pdwLevelIDs,
  413. &cbSize,
  414. NULL);
  415. _JumpCondition(FALSE == fResult, GetInformationCodeAuthzPolicyWError);
  416. // Try each trust level, and return the one that matches the trust level
  417. // passed as a parameter:
  418. for (DWORD dwIndex = 0; dwIndex < dwNumLevels; dwIndex++)
  419. {
  420. if (SaferCreateLevel
  421. (SAFER_SCOPEID_MACHINE,
  422. pdwLevelIDs[dwIndex],
  423. SAFER_LEVEL_OPEN,
  424. &hAuthzLevel,
  425. NULL))
  426. {
  427. if (SaferGetLevelInformation
  428. (hAuthzLevel,
  429. SaferObjectFriendlyName,
  430. wszLevelName,
  431. sizeof(wszLevelName) / sizeof(wszLevelName[0]),
  432. &dwBufferSize))
  433. {
  434. if (0 == _wcsicmp(pwszFriendlyName, wszLevelName))
  435. {
  436. // We've found the specified trust level.
  437. *pdwTrustLevelID = pdwLevelIDs[dwIndex];
  438. SaferCloseLevel(hAuthzLevel);
  439. dwResult = ERROR_SUCCESS;
  440. goto ErrorReturn;
  441. }
  442. }
  443. SaferCloseLevel(hAuthzLevel);
  444. }
  445. }
  446. // The specified level ID is not in the enumeration.
  447. dwResult = ERROR_NOT_FOUND;
  448. ErrorReturn:
  449. if (NULL != pdwLevelIDs) { HeapFree(GetProcessHeap(), 0, pdwLevelIDs); }
  450. return dwResult;
  451. SET_DWRESULT(GetInformationCodeAuthzPolicyWError, GetLastError());
  452. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  453. }
  454. DWORD IntermediateSaferLevelsAreEnabled(BOOL *pfResult)
  455. {
  456. BOOL fResult;
  457. DWORD cbSize;
  458. DWORD dwNumLevels;
  459. DWORD dwResult;
  460. cbSize = 0;
  461. fResult = SaferGetPolicyInformation
  462. (SAFER_SCOPEID_MACHINE,
  463. SaferPolicyLevelList,
  464. 0,
  465. NULL,
  466. &cbSize,
  467. NULL);
  468. _JumpCondition(!fResult && ERROR_INSUFFICIENT_BUFFER != GetLastError(), SaferGetPolicyInformationError);
  469. dwNumLevels = cbSize / sizeof(DWORD);
  470. // If there are more than two levels available, we know that intermediate
  471. // safer levels have been enabled.
  472. fResult = dwNumLevels > 2;
  473. *pfResult = fResult;
  474. dwResult = ERROR_SUCCESS;
  475. ErrorReturn:
  476. return dwResult;
  477. SET_DWRESULT(SaferGetPolicyInformationError, GetLastError());
  478. }
  479. DWORD
  480. ShowTrustLevels(VOID)
  481. {
  482. BOOL fResult;
  483. DWORD cbSize;
  484. DWORD ccWritten;
  485. DWORD dwResult;
  486. DWORD dwNumLevels;
  487. DWORD *pdwLevelIDs = NULL;
  488. SAFER_LEVEL_HANDLE hAuthzLevel = NULL;
  489. WCHAR wszLevelName[1024];
  490. DWORD dwBufferSize = 0;
  491. // Print header:
  492. LocalizedWPrintf(RUNASP_STRING_TRUSTLEVELS);
  493. // Print trust levels:
  494. fResult = SaferGetPolicyInformation
  495. (SAFER_SCOPEID_MACHINE,
  496. SaferPolicyLevelList,
  497. 0,
  498. NULL,
  499. &cbSize,
  500. NULL);
  501. _JumpCondition(FALSE == fResult && ERROR_INSUFFICIENT_BUFFER != GetLastError(), GetInformationCodeAuthzPolicyWError);
  502. dwNumLevels = cbSize / sizeof(DWORD);
  503. pdwLevelIDs = (DWORD *)HeapAlloc(GetProcessHeap(), 0, cbSize);
  504. _JumpCondition(NULL == pdwLevelIDs, MemoryError);
  505. fResult = SaferGetPolicyInformation
  506. (SAFER_SCOPEID_MACHINE,
  507. SaferPolicyLevelList,
  508. cbSize,
  509. pdwLevelIDs,
  510. &cbSize,
  511. NULL);
  512. _JumpCondition(FALSE == fResult, GetInformationCodeAuthzPolicyWError);
  513. for (DWORD dwIndex = 0; dwIndex < dwNumLevels; dwIndex++)
  514. {
  515. // Give our best effort to enumerate each trust level:
  516. if (SaferCreateLevel
  517. (SAFER_SCOPEID_MACHINE,
  518. pdwLevelIDs[dwIndex],
  519. SAFER_LEVEL_OPEN,
  520. &hAuthzLevel,
  521. NULL))
  522. {
  523. if (SaferGetLevelInformation
  524. (hAuthzLevel,
  525. SaferObjectFriendlyName,
  526. wszLevelName,
  527. sizeof(wszLevelName) / sizeof(wszLevelName[0]),
  528. &dwBufferSize))
  529. {
  530. WriteConsoleW(g_hStdout, wszLevelName, (DWORD)wcslen(wszLevelName), &ccWritten, NULL);
  531. WriteConsoleW(g_hStdout, L"\n", 1, &ccWritten, NULL);
  532. }
  533. SaferCloseLevel(hAuthzLevel);
  534. }
  535. }
  536. dwResult = ERROR_SUCCESS;
  537. ErrorReturn:
  538. if (NULL != pdwLevelIDs) { HeapFree(GetProcessHeap(), 0, pdwLevelIDs); }
  539. return dwResult;
  540. SET_DWRESULT(GetInformationCodeAuthzPolicyWError, GetLastError());
  541. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  542. }
  543. VOID
  544. RunasPrintHelp(VOID)
  545. {
  546. UINT rgText[] = {
  547. RUNASP_STRING_HELP_LINE1, RUNASP_STRING_HELP_LINE2,
  548. RUNASP_STRING_HELP_LINE3, RUNASP_STRING_HELP_LINE4,
  549. RUNASP_STRING_HELP_LINE5, RUNASP_STRING_SAFER_HELP_LINE1,
  550. RUNASP_STRING_HELP_LINE7, RUNASP_STRING_HELP_LINE8,
  551. RUNASP_STRING_HELP_LINE9, RUNASP_STRING_HELP_LINE10,
  552. RUNASP_STRING_HELP_LINE11, RUNASP_STRING_HELP_LINE12,
  553. RUNASP_STRING_HELP_LINE13, RUNASP_STRING_HELP_LINE14,
  554. RUNASP_STRING_HELP_LINE15, RUNASP_STRING_HELP_LINE16,
  555. RUNASP_STRING_HELP_LINE17, RUNASP_STRING_HELP_LINE18,
  556. RUNASP_STRING_HELP_LINE19, RUNASP_STRING_HELP_LINE20,
  557. RUNASP_STRING_SAFER_HELP_LINE2, RUNASP_STRING_SAFER_HELP_LINE3,
  558. RUNASP_STRING_SAFER_HELP_LINE4, RUNASP_STRING_SAFER_HELP_LINE5,
  559. RUNASP_STRING_HELP_LINE25, RUNASP_STRING_HELP_LINE26,
  560. RUNASP_STRING_HELP_LINE27, RUNASP_STRING_HELP_LINE28,
  561. RUNASP_STRING_HELP_LINE29, RUNASP_STRING_HELP_LINE30,
  562. RUNASP_STRING_HELP_LINE31, RUNASP_STRING_HELP_LINE32,
  563. RUNASP_STRING_HELP_LINE33
  564. };
  565. BOOL fShowSaferHelp;
  566. if (ERROR_SUCCESS != IntermediateSaferLevelsAreEnabled(&fShowSaferHelp)) {
  567. fShowSaferHelp = FALSE;
  568. }
  569. for (DWORD dwIndex = 0; dwIndex < ARRAYSIZE(rgText); dwIndex++) {
  570. BOOL fPrintLine = TRUE;
  571. switch (rgText[dwIndex])
  572. {
  573. case RUNASP_STRING_SAFER_HELP_LINE1:
  574. case RUNASP_STRING_SAFER_HELP_LINE2:
  575. case RUNASP_STRING_SAFER_HELP_LINE3:
  576. case RUNASP_STRING_SAFER_HELP_LINE4:
  577. case RUNASP_STRING_SAFER_HELP_LINE5:
  578. fPrintLine = fShowSaferHelp;
  579. break;
  580. default:
  581. ;
  582. }
  583. if (fPrintLine)
  584. LocalizedWPrintf(rgText[dwIndex]);
  585. }
  586. }
  587. int WINAPI
  588. WinMain(
  589. HINSTANCE hinstExe,
  590. HINSTANCE /*hinstExePrev*/,
  591. LPSTR /*pszCmdLine*/,
  592. int /*nCmdShow*/)
  593. {
  594. HRESULT hr;
  595. DWORD dwAuthzLevel = 0;
  596. DWORD dwResult = 0;
  597. DWORD dwRetval = EXIT_CODE_FAILED;
  598. DWORD Logonflags = 0;
  599. DWORD flags = 0;
  600. BOOL fOk = FALSE;
  601. BOOL UseCurrentEnvironment = FALSE;
  602. BOOL UseNetOnly = FALSE;
  603. BOOL fCreateProcessRestricted = FALSE;
  604. BOOL fSuppliedAppName = FALSE;
  605. BOOL fSuppliedUserName = FALSE;
  606. BOOL fCredMan = FALSE;
  607. #if DBG
  608. BOOL fSuppliedPassword = FALSE;
  609. #endif // DBG
  610. DWORD dwCredFlags = 0;
  611. LPVOID Environment = NULL;
  612. LPWSTR pwszCurrentDir = NULL;
  613. LPWSTR pwszArgvUserName = NULL;
  614. LPWSTR pwszTitle = NULL;
  615. WCHAR pwszAuthzLevel[MAX_PATH];
  616. WCHAR pwszDomainName[MAX_PATH];
  617. WCHAR pwszUserDisplayName[CREDUI_MAX_USERNAME_LENGTH];
  618. WCHAR pwszUserName[CREDUI_MAX_USERNAME_LENGTH];
  619. WCHAR pwszPassword[CREDUI_MAX_PASSWORD_LENGTH];
  620. WCHAR pwszTarget[CREDUI_MAX_USERNAME_LENGTH];
  621. int i;
  622. DWORD rgdwArgs[ARRAYSIZE(rgArgCompat)];
  623. int nNumArgs;
  624. memset(&pwszAuthzLevel[0], 0, sizeof(pwszAuthzLevel));
  625. memset(&pwszDomainName[0], 0, sizeof(pwszDomainName));
  626. memset(&pwszUserDisplayName[0], 0, sizeof(pwszUserDisplayName));
  627. memset(&pwszUserName[0], 0, sizeof(pwszUserName));
  628. memset((WCHAR *)&pwszPassword[0], 0, sizeof(pwszPassword));
  629. memset((WCHAR *)&pwszTarget[0], 0, sizeof(pwszTarget));
  630. hMod = (HMODULE)hinstExe;
  631. MySetThreadUILanguage(0);
  632. if (S_OK != (dwResult = InitializeConsoleOutput()))
  633. {
  634. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, dwResult);
  635. goto error;
  636. }
  637. LPWSTR* pszArgv = CommandLineToArgvW(GetCommandLineW(), &nNumArgs);
  638. if (pszArgv == NULL) {
  639. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, MyGetLastError());
  640. goto error;
  641. }
  642. // Logging on with profile is now the default:
  643. Logonflags |= LOGON_WITH_PROFILE;
  644. for(i=1;i<nNumArgs;i++)
  645. {
  646. if(pszArgv[i][0] != L'/')
  647. {
  648. if (i == nNumArgs-1)
  649. {
  650. fSuppliedAppName = TRUE;
  651. break;
  652. }
  653. else
  654. {
  655. RunasPrintHelp();
  656. goto error;
  657. }
  658. }
  659. switch(pszArgv[i][1])
  660. {
  661. #if DBG
  662. case L'z':
  663. case L'Z':
  664. {
  665. LPWSTR str = &(pszArgv[i][2]);
  666. while(*str != L':')
  667. {
  668. if(*str == L'\0')
  669. {
  670. RunasPrintHelp();
  671. goto error;
  672. }
  673. str++;
  674. }
  675. str++;
  676. hr = StringCchCopy((WCHAR *)pwszPassword, ARRAYSIZE(pwszPassword), str);
  677. if (FAILED(hr)) {
  678. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  679. goto error;
  680. }
  681. fSuppliedPassword = TRUE;
  682. break;
  683. }
  684. #endif // DBG
  685. case L'p':
  686. case L'P': // "/profile" argument
  687. _CheckArgCompat(rgdwArgs, i-1, AI_PROFILE);
  688. break;
  689. case L'e':
  690. case L'E': // "/env" argument
  691. {
  692. _CheckArgCompat(rgdwArgs, i-1, AI_ENV);
  693. UseCurrentEnvironment = TRUE;
  694. break;
  695. }
  696. case L'n':
  697. case L'N':
  698. {
  699. switch (pszArgv[i][2])
  700. {
  701. case L'e':
  702. case L'E': // "/netonly" argument
  703. _CheckArgCompat(rgdwArgs, i-1, AI_NETONLY);
  704. UseNetOnly = TRUE;
  705. Logonflags |= LOGON_NETCREDENTIALS_ONLY;
  706. Logonflags &= ~LOGON_WITH_PROFILE;
  707. break;
  708. case L'o':
  709. case L'O': // "/noprofile" argument
  710. _CheckArgCompat(rgdwArgs, i-1, AI_NOPROFILE);
  711. Logonflags &= ~LOGON_WITH_PROFILE;
  712. break;
  713. default:
  714. RunasPrintHelp();
  715. goto error;
  716. }
  717. break;
  718. }
  719. case L's':
  720. case L'S': // "/smartcard" argument
  721. {
  722. switch (pszArgv[i][2])
  723. {
  724. case L'a':
  725. case L'A':
  726. _CheckArgCompat(rgdwArgs, i-1, AI_SAVECRED);
  727. dwCredFlags |= RUNAS_USE_SAVEDCREDS;
  728. fCredMan = TRUE;
  729. break;
  730. case L'm':
  731. case L'M':
  732. _CheckArgCompat(rgdwArgs, i-1, AI_SMARTCARD);
  733. dwCredFlags |= RUNAS_USE_SMARTCARD;
  734. break;
  735. case L'h':
  736. case L'H':
  737. _CheckArgCompat(rgdwArgs, i-1, AI_SHOWTRUSTLEVELS);
  738. ShowTrustLevels();
  739. dwRetval = EXIT_CODE_SUCCEEDED;
  740. goto error;
  741. }
  742. break ;
  743. }
  744. case L't':
  745. case L'T': // "/trustlevel" argument
  746. {
  747. _CheckArgCompat(rgdwArgs, i-1, AI_TRUSTLEVEL);
  748. LPWSTR str = &(pszArgv[i][2]);
  749. while (*str != L':')
  750. {
  751. if (*str == L'\0')
  752. {
  753. RunasPrintHelp();
  754. goto error;
  755. }
  756. str++;
  757. }
  758. str++;
  759. if (ERROR_SUCCESS != FriendlyNameToTrustLevelID(str, &dwAuthzLevel))
  760. {
  761. ShowTrustLevels();
  762. goto error;
  763. }
  764. hr = StringCchCopy(pwszAuthzLevel, ARRAYSIZE(pwszAuthzLevel), str);
  765. if (FAILED(hr)) {
  766. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  767. goto error;
  768. }
  769. fCreateProcessRestricted = TRUE;
  770. break;
  771. }
  772. case L'u':
  773. case L'U': // "/user" argument
  774. {
  775. _CheckArgCompat(rgdwArgs, i-1, AI_USER);
  776. LPWSTR str = &(pszArgv[i][2]);
  777. while(*str != L':')
  778. {
  779. if(*str == L'\0')
  780. {
  781. RunasPrintHelp();
  782. goto error;
  783. }
  784. str++;
  785. }
  786. str++;
  787. hr = StringCchCopy(pwszUserName, ARRAYSIZE(pwszUserName), str);
  788. if (FAILED(hr)) {
  789. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  790. goto error;
  791. }
  792. pwszArgvUserName = str; // Save the supplied username in case we need to restore it.
  793. fSuppliedUserName = TRUE;
  794. break;
  795. }
  796. default:
  797. RunasPrintHelp();
  798. goto error;
  799. }
  800. }
  801. // The command line must specify:
  802. // 1) an application to run
  803. // 2) either a username, a trustlevel, or a smartcard option
  804. if(FALSE == fSuppliedAppName ||
  805. (FALSE == fSuppliedUserName && FALSE == fCreateProcessRestricted && 0 == (RUNAS_USE_SMARTCARD & dwCredFlags))
  806. )
  807. {
  808. RunasPrintHelp();
  809. goto error;
  810. }
  811. STARTUPINFO si;
  812. PROCESS_INFORMATION pi;
  813. ZeroMemory(&si, sizeof(si));
  814. ZeroMemory(&pi, sizeof(pi));
  815. si.cb = sizeof(si);
  816. if (TRUE == fCreateProcessRestricted)
  817. {
  818. // Username is not specified with this set of options --
  819. // use the current user.
  820. DWORD dwSize = ARRAYSIZE(pwszUserName);
  821. if (FALSE == GetUserNameEx(NameSamCompatible, &pwszUserName[0], &dwSize))
  822. {
  823. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, MyGetLastError());
  824. goto error;
  825. }
  826. pwszCurrentDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
  827. if (NULL == pwszCurrentDir)
  828. {
  829. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_NOT_ENOUGH_MEMORY);
  830. goto error;
  831. }
  832. if (FALSE == GetCurrentDirectory(MAX_PATH, pwszCurrentDir))
  833. {
  834. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, MyGetLastError());
  835. goto error;
  836. }
  837. if (FALSE == GetTitle(pszArgv[nNumArgs-1],
  838. pwszUserName,
  839. TRUE,
  840. pwszAuthzLevel,
  841. &pwszTitle))
  842. {
  843. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, MyGetLastError());
  844. goto error;
  845. }
  846. si.lpTitle = pwszTitle;
  847. // If we're just doing restricted login, we have enough information to proceed.
  848. fOk = CreateProcessRestricted
  849. (dwAuthzLevel,
  850. NULL,
  851. pszArgv[nNumArgs - 1],
  852. pwszCurrentDir,
  853. &si,
  854. &pi);
  855. }
  856. else
  857. {
  858. for (BOOL fDone = FALSE; !fDone; ) {
  859. #if DBG
  860. // Can only supply password in checked builds.
  861. if (FALSE == fSuppliedPassword) {
  862. #endif // DBG
  863. dwResult = GetCredentials
  864. (dwCredFlags,
  865. (WCHAR *)pwszPassword,
  866. ARRAYSIZE(pwszPassword),
  867. pwszUserName,
  868. ARRAYSIZE(pwszUserName),
  869. pwszUserDisplayName,
  870. ARRAYSIZE(pwszUserDisplayName),
  871. (WCHAR *)pwszTarget,
  872. ARRAYSIZE(pwszTarget));
  873. if (ERROR_SUCCESS != dwResult) {
  874. LocalizedWPrintf(RUNASP_STRING_ERROR_PASSWORD);
  875. goto error;
  876. }
  877. #if DBG
  878. } else {
  879. // If we've supplied a password, don't call GetCredentials.
  880. // Just copy our username to the display name and proceed.
  881. wcsncpy(pwszUserDisplayName, pwszUserName, ARRAYSIZE(pwszUserDisplayName)-1);
  882. }
  883. #endif // DBG
  884. if (FALSE == GetTitle(pszArgv[nNumArgs-1],
  885. pwszUserDisplayName,
  886. FALSE,
  887. NULL,
  888. &pwszTitle))
  889. {
  890. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, MyGetLastError());
  891. goto error;
  892. }
  893. si.lpTitle = pwszTitle;
  894. //
  895. // Now we should take the pwszUserName and parse it
  896. // if it is Domain\User, we want to split it.
  897. //
  898. WCHAR *wstr = pwszUserName;
  899. while(*wstr != L'\0')
  900. {
  901. if(*wstr == L'\\')
  902. {
  903. *wstr = L'\0';
  904. wstr++;
  905. //
  906. // first part is domain
  907. // second is user.
  908. //
  909. hr = StringCchCopy(pwszDomainName, ARRAYSIZE(pwszDomainName), pwszUserName);
  910. if (FAILED(hr)) {
  911. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  912. goto error;
  913. }
  914. hr = StringCchCopy(pwszUserName, ARRAYSIZE(pwszUserName), wstr);
  915. if (FAILED(hr)) {
  916. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  917. goto error;
  918. }
  919. break;
  920. }
  921. wstr++;
  922. }
  923. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_WAIT, pszArgv[nNumArgs-1], pwszUserDisplayName);
  924. if(UseCurrentEnvironment)
  925. {
  926. pwszCurrentDir = (LPWSTR)HeapAlloc(GetProcessHeap(), 0, MAX_PATH * sizeof(WCHAR));
  927. if (NULL == pwszCurrentDir) {
  928. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_NOT_ENOUGH_MEMORY);
  929. goto error;
  930. }
  931. if (!GetCurrentDirectory(MAX_PATH, pwszCurrentDir)) {
  932. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, GetLastError());
  933. goto error;
  934. }
  935. Environment = GetEnvironmentStrings();
  936. flags |= CREATE_UNICODE_ENVIRONMENT;
  937. }
  938. fOk = CreateProcessWithLogonW
  939. (pwszUserName, // Username
  940. pwszDomainName, // Domain
  941. (WCHAR *)pwszPassword, // Password
  942. Logonflags, // logon flags
  943. NULL, // Application name
  944. pszArgv[nNumArgs-1], // Command line
  945. flags, // flags
  946. Environment, // NULL=LoggedOnUserEnv, GetEnvironmentStrings
  947. pwszCurrentDir,// Working Directory
  948. &si, // Startup Info
  949. &pi); // Process Info
  950. // See if we need to try again...
  951. fDone = TRUE;
  952. if (fCredMan) { // The /savecred option was specified.
  953. if (RUNAS_USE_SAVEDCREDS & dwCredFlags) { // We tried to use saved credentials
  954. if (!fOk && CREDUI_IS_AUTHENTICATION_ERROR(GetLastError())) {
  955. // We attempted to use saved creds, and it didn't work.
  956. // Try prompting for a password.
  957. dwCredFlags &= ~RUNAS_USE_SAVEDCREDS;
  958. dwCredFlags |= RUNAS_SAVE_CREDS; // We'll save the new credentials if we can.
  959. fDone = FALSE; // We should try to create the process again.
  960. // Reset the username, it may have been modified by GetCredentials():
  961. hr = StringCchCopy(pwszUserName, ARRAYSIZE(pwszUserName), pwszArgvUserName);
  962. if (FAILED(hr)) {
  963. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, ERROR_INVALID_PARAMETER);
  964. goto error;
  965. }
  966. } else {
  967. // We succeeded, or some other failure occured.
  968. // Don't bother trying again.
  969. }
  970. }
  971. else {
  972. // We attempted to save our credentials to credman. Only save them on success:
  973. dwResult = SaveCredentials((WCHAR *)pwszTarget, fOk);
  974. // ignore errors in SaveCredentials (not much we can do on error).
  975. }
  976. }
  977. }
  978. }
  979. if(!fOk)
  980. {
  981. DWORD dw;
  982. LPWSTR wszErrorText = NULL;
  983. dw = GetLastError();
  984. if (ERROR_SUCCESS == dw)
  985. GetExitCodeProcess(pi.hProcess, &dw);
  986. if (ERROR_SUCCESS == dw)
  987. GetExitCodeThread(pi.hThread, &dw);
  988. if (ERROR_SUCCESS == dw)
  989. dw = (DWORD)E_FAIL;
  990. if (!WriteMsg(FORMAT_MESSAGE_FROM_SYSTEM, dw, &wszErrorText, pszArgv[nNumArgs-1]))
  991. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_INTERNAL, dw);
  992. else
  993. DisplayMsg(FORMAT_MESSAGE_FROM_HMODULE, RUNASP_STRING_ERROR_OCCURED, pszArgv[nNumArgs-1], dw, wszErrorText);
  994. goto error;
  995. }
  996. CloseHandle(pi.hProcess);
  997. CloseHandle(pi.hThread);
  998. dwRetval = EXIT_CODE_SUCCEEDED;
  999. error:
  1000. // Zero out memory which might contain credentials:
  1001. SecureZeroMemory(pwszPassword, sizeof(pwszPassword));
  1002. SecureZeroMemory(pwszTarget, sizeof(pwszTarget));
  1003. return dwRetval;
  1004. }