Source code of Windows XP (NT5)
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.

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