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.

993 lines
33 KiB

  1. /*+
  2. *
  3. * Microsoft Windows
  4. * Copyright (C) Microsoft Corporation, 1997 - 1998.
  5. *
  6. * Name : cseclogn.cxx
  7. * Author:Jeffrey Richter (v-jeffrr)
  8. *
  9. * Abstract:
  10. * This is the client side for Secondary Logon Service
  11. * implemented as CreateProcessWithLogon API
  12. * in advapi32.dll
  13. *
  14. * Revision History:
  15. * PraeritG 10/8/97 To integrate this in to services.exe
  16. *
  17. -*/
  18. #define UNICODE
  19. #define SECURITY_WIN32
  20. #include <nt.h>
  21. #include <ntrtl.h>
  22. #include <nturtl.h>
  23. #include <Windows.h>
  24. #include <wincred.h>
  25. #include <rpc.h>
  26. #include <crypt.h>
  27. #include <strsafe.h>
  28. #include <assert.h>
  29. #include "seclogon.h"
  30. #include "security.h"
  31. #include "dbgdef.h"
  32. //
  33. // must move to winbase.h soon!
  34. #define LOGON_WITH_PROFILE 0x00000001
  35. #define LOGON_NETCREDENTIALS_ONLY 0x00000002
  36. ////////////////////////////////////////////////////////////////////////
  37. //
  38. // Function prototypes:
  39. //
  40. ////////////////////////////////////////////////////////////////////////
  41. BOOL
  42. CreateProcessWithLogonCommonW(
  43. HANDLE hToken,
  44. LPCWSTR lpUsername,
  45. LPCWSTR lpDomain,
  46. LPCWSTR lpPassword,
  47. DWORD dwLogonFlags,
  48. LPCWSTR lpApplicationName,
  49. LPWSTR lpCommandLine,
  50. DWORD dwCreationFlags,
  51. LPVOID lpEnvironment,
  52. LPCWSTR lpCurrentDirectory,
  53. LPSTARTUPINFOW lpStartupInfo,
  54. LPPROCESS_INFORMATION lpProcessInformation);
  55. DWORD c_SeclCreateProcessWithLogonW(IN SECL_SLI *psli,
  56. OUT SECL_SLRI *pslri);
  57. DWORD To_SECL_BLOB_A(IN LPVOID lpEnvironment,
  58. OUT SECL_BLOB *psb);
  59. DWORD To_SECL_BLOB_W(IN LPVOID lpEnvironment,
  60. OUT SECL_BLOB *psb);
  61. /////////////////////////////////////////////////////////////////////////
  62. //
  63. // Useful macros:
  64. //
  65. /////////////////////////////////////////////////////////////////////////
  66. #define ARRAYSIZE(array) ((sizeof(array)) / (sizeof(array[0])))
  67. //
  68. // Fill out a string structure to send to the seclogon RPC server.
  69. // We'll use the convention that the client must allocate an extra byte
  70. // which the server can use to NULL-terminate the input string
  71. //
  72. #define ASSIGN_SECL_STRING(ss, wsz) \
  73. { \
  74. ss.pwsz = wsz; \
  75. if (NULL != wsz) { \
  76. size_t len; \
  77. LastError = StringCchLength(wsz, 0xFFFF-1, &len); \
  78. if (FAILED(LastError)) { \
  79. __leave; \
  80. } \
  81. ss.ccLength = (WORD)len; \
  82. ss.ccSize = (WORD)len+1; \
  83. } \
  84. else { \
  85. ss.ccLength = ss.ccSize = 0; \
  86. } \
  87. }
  88. #define GET_RTL_ENCRYPT_PADDING_LENGTH(dwLen, dwUnits) \
  89. ((RTL_ENCRYPT_MEMORY_SIZE - (((dwLen)*(dwUnits)) % RTL_ENCRYPT_MEMORY_SIZE)) / (dwUnits))
  90. #define IS_RTL_MEMORY_BLOCK_MULTIPLE(dwLen, dwUnits) \
  91. ((((dwLen)*(dwUnits)) % RTL_ENCRYPT_MEMORY_SIZE) == 0)
  92. #define GET_RTL_ENCRYPT_BLOCK_LENGTH(dwLen, dwUnits) \
  93. ((IS_RTL_MEMORY_BLOCK_MULTIPLE((dwLen), (dwUnits))) ? (dwLen) : ((dwLen) + (GET_RTL_ENCRYPT_PADDING_LENGTH((dwLen), (dwUnits)))))
  94. ////////////////////////////////////////////////////////////////////////
  95. //
  96. // Module implementation:
  97. //
  98. //////////////////////////////////////////////////////////////////////////
  99. extern "C" void *__cdecl _alloca(size_t);
  100. BOOL
  101. WINAPI
  102. CreateProcessWithLogonW(
  103. LPCWSTR lpUsername,
  104. LPCWSTR lpDomain,
  105. LPCWSTR lpPassword,
  106. DWORD dwLogonFlags,
  107. LPCWSTR lpApplicationName,
  108. LPWSTR lpCommandLine,
  109. DWORD dwCreationFlags,
  110. LPVOID lpEnvironment,
  111. LPCWSTR lpCurrentDirectory,
  112. LPSTARTUPINFOW lpStartupInfo,
  113. LPPROCESS_INFORMATION lpProcessInformation
  114. )
  115. {
  116. return CreateProcessWithLogonCommonW(
  117. NULL,
  118. lpUsername,
  119. lpDomain,
  120. lpPassword,
  121. dwLogonFlags,
  122. lpApplicationName,
  123. lpCommandLine,
  124. dwCreationFlags,
  125. lpEnvironment,
  126. lpCurrentDirectory,
  127. lpStartupInfo,
  128. lpProcessInformation
  129. );
  130. }
  131. BOOL
  132. WINAPI
  133. CreateProcessWithTokenW(
  134. HANDLE hToken,
  135. DWORD dwLogonFlags,
  136. LPCWSTR lpApplicationName,
  137. LPWSTR lpCommandLine,
  138. DWORD dwCreationFlags,
  139. LPVOID lpEnvironment,
  140. LPCWSTR lpCurrentDirectory,
  141. LPSTARTUPINFOW lpStartupInfo,
  142. LPPROCESS_INFORMATION lpProcessInformation
  143. )
  144. {
  145. LPWSTR szEmpty = L"";
  146. return CreateProcessWithLogonCommonW(
  147. hToken,
  148. szEmpty,
  149. szEmpty,
  150. szEmpty,
  151. dwLogonFlags,
  152. lpApplicationName,
  153. lpCommandLine,
  154. dwCreationFlags,
  155. lpEnvironment,
  156. lpCurrentDirectory,
  157. lpStartupInfo,
  158. lpProcessInformation
  159. );
  160. }
  161. BOOL
  162. CreateProcessWithLogonCommonW(
  163. HANDLE hToken,
  164. LPCWSTR lpUsername,
  165. LPCWSTR lpDomain,
  166. LPCWSTR lpPassword,
  167. DWORD dwLogonFlags,
  168. LPCWSTR lpApplicationName,
  169. LPWSTR lpCommandLine,
  170. DWORD dwCreationFlags,
  171. LPVOID lpEnvironment,
  172. LPCWSTR lpCurrentDirectory,
  173. LPSTARTUPINFOW lpStartupInfo,
  174. LPPROCESS_INFORMATION lpProcessInformation)
  175. /*++
  176. Routine Description:
  177. Arguments:
  178. Return Value:
  179. --*/
  180. {
  181. BOOL fOk = FALSE;
  182. BOOL fRevertWinsta = FALSE;
  183. DWORD ccCmdLine;
  184. DWORD ccPszApplName;
  185. DWORD ccEncryptedPassword;
  186. DWORD LastError = ERROR_SUCCESS;
  187. HANDLE hheap = GetProcessHeap();
  188. HDESK hDesk = NULL;
  189. HRESULT hr;
  190. HWINSTA hWinsta = NULL;
  191. HWINSTA hWinstaSave = NULL;
  192. LPWSTR pszApplName = NULL;
  193. LPWSTR pszCmdLine = NULL;
  194. LPWSTR pwszEmptyString = L"";
  195. NTSTATUS ntStatus;
  196. SECL_SLI sli;
  197. SECL_SLRI slri;
  198. UNICODE_STRING uszEncryptedPassword;
  199. WCHAR wszDesktopName[2*MAX_PATH + 2];
  200. WCHAR wszEncryptedPassword[GET_RTL_ENCRYPT_BLOCK_LENGTH(CREDUI_MAX_PASSWORD_LENGTH, sizeof(WCHAR)) + 1];
  201. ZeroMemory(&sli, sizeof(sli));
  202. ZeroMemory(&slri, sizeof(slri));
  203. ZeroMemory(&uszEncryptedPassword, sizeof(uszEncryptedPassword));
  204. ZeroMemory(&wszDesktopName, sizeof(wszDesktopName));
  205. ZeroMemory(&wszEncryptedPassword[0], sizeof(wszEncryptedPassword));
  206. __try {
  207. sli.hToken = (unsigned __int64)hToken;
  208. if (NULL != lpPassword && L'\0' != lpPassword[0])
  209. {
  210. // BUG 547683: we need to encrypt the password across the LPC boundary to prevent
  211. // password theft. NOTE: we won't actually touch the user's passwd buffer --
  212. // this behavior would be confusing, and would have minimal gain.
  213. //
  214. // The RtlEncryptMemory() routine requires that the
  215. // memory buffer's size be a multiple of the encryption block length.
  216. // Copy the password over and pad it with some zeros:
  217. //
  218. hr = StringCchCopy(wszEncryptedPassword, ARRAYSIZE(wszEncryptedPassword), lpPassword);
  219. if (FAILED(hr))
  220. {
  221. LastError = (DWORD)hr;
  222. __leave;
  223. }
  224. // Calculate the size of the encrypted password
  225. ccEncryptedPassword = wcslen(wszEncryptedPassword);
  226. ccEncryptedPassword = GET_RTL_ENCRYPT_BLOCK_LENGTH(ccEncryptedPassword, sizeof(WCHAR));
  227. assert(ccEncryptedPassword < ARRAYSIZE(wszEncryptedPassword));
  228. // perform the encryption
  229. ntStatus = RtlEncryptMemory((PVOID)wszEncryptedPassword, sizeof(WCHAR)*ccEncryptedPassword, RTL_ENCRYPT_OPTION_SAME_LOGON);
  230. if (!NT_SUCCESS(ntStatus))
  231. {
  232. LastError = RtlNtStatusToDosError(ntStatus);
  233. __leave;
  234. }
  235. // assign the encrypted password to a SECL_STRING.
  236. // NOTE: we can't use ASSIGN_SECL_STRING, as the encrypted password may have
  237. // '\0' characters in the middle
  238. sli.ssPassword.ccLength = (WORD)(ccEncryptedPassword);
  239. sli.ssPassword.ccSize = (WORD)(ccEncryptedPassword+1);
  240. sli.ssPassword.pwsz = wszEncryptedPassword;
  241. }
  242. else
  243. {
  244. lpPassword = L"";
  245. ASSIGN_SECL_STRING(sli.ssPassword, (LPWSTR)lpPassword);
  246. }
  247. //
  248. // JMR: Do these flags work: CREATE_SEPARATE_WOW_VDM,
  249. // CREATE_SHARED_WOW_VDM
  250. // Valid flags: CREATE_SUSPENDED, CREATE_UNICODE_ENVIRONMENT,
  251. // *_PRIORITY_CLASS
  252. //
  253. // The following flags are illegal. Fail the call if any are specified.
  254. //
  255. if ((dwCreationFlags & (DEBUG_PROCESS | DEBUG_ONLY_THIS_PROCESS
  256. | DETACHED_PROCESS)) != 0) {
  257. LastError = ERROR_INVALID_PARAMETER;
  258. __leave;
  259. }
  260. if(dwLogonFlags & ~(LOGON_WITH_PROFILE | LOGON_NETCREDENTIALS_ONLY))
  261. {
  262. LastError = ERROR_INVALID_PARAMETER;
  263. __leave;
  264. }
  265. //
  266. // Turn on the flags that MUST be turned on
  267. //
  268. // We are overloading CREATE_NEW_CONSOLE to
  269. // CREATE_WITH_NETWORK_LOGON
  270. //
  271. dwCreationFlags |= CREATE_DEFAULT_ERROR_MODE | CREATE_NEW_CONSOLE
  272. | CREATE_NEW_PROCESS_GROUP;
  273. //
  274. // If no priority class explicitly specified and this process is IDLE, force IDLE (See CreateProcess documentation)
  275. //
  276. if ((dwCreationFlags & (NORMAL_PRIORITY_CLASS | IDLE_PRIORITY_CLASS
  277. | HIGH_PRIORITY_CLASS
  278. | REALTIME_PRIORITY_CLASS)) == 0) {
  279. if (GetPriorityClass(GetCurrentProcess()) == IDLE_PRIORITY_CLASS)
  280. dwCreationFlags |= IDLE_PRIORITY_CLASS;
  281. }
  282. ccPszApplName = MAX_PATH;
  283. pszApplName = (LPWSTR) HeapAlloc(hheap, 0, sizeof(WCHAR) * ccPszApplName);
  284. //
  285. // Lookup the fullpathname of the specified executable
  286. //
  287. ccCmdLine = MAX_PATH + lstrlenW(lpCommandLine);
  288. pszCmdLine = (LPWSTR) HeapAlloc(hheap, 0, sizeof(WCHAR) * ccCmdLine);
  289. if(pszApplName == NULL || pszCmdLine == NULL)
  290. {
  291. LastError = ERROR_INVALID_PARAMETER;
  292. __leave;
  293. }
  294. if(lpApplicationName == NULL)
  295. {
  296. if(lpCommandLine != NULL)
  297. {
  298. //
  299. // Commandline contains the name, we should parse it out and get
  300. // the full path so that correct executable is invoked.
  301. //
  302. DWORD Length;
  303. DWORD fileattr;
  304. WCHAR TempChar = L'\0';
  305. LPWSTR TempApplName = NULL;
  306. LPWSTR TempRemainderString = NULL;
  307. LPWSTR WhiteScan = NULL;
  308. BOOL SearchRetry = TRUE;
  309. DWORD ccApplName = lstrlenW(lpCommandLine)+1;
  310. LPWSTR ApplName = (LPWSTR) HeapAlloc(
  311. hheap, 0,
  312. sizeof(WCHAR) * ccApplName);
  313. DWORD ccNameBuffer = MAX_PATH+1;
  314. LPWSTR NameBuffer = (LPWSTR) HeapAlloc(
  315. hheap, 0,
  316. sizeof(WCHAR) * ccNameBuffer);
  317. if (ApplName == NULL || NameBuffer == NULL)
  318. {
  319. LastError = ERROR_NOT_ENOUGH_MEMORY;
  320. __leave;
  321. }
  322. hr = StringCchCopy(ApplName, ccApplName, lpCommandLine);
  323. if (FAILED(hr)) {
  324. LastError = (DWORD)hr;
  325. __leave;
  326. }
  327. WhiteScan = ApplName;
  328. //
  329. // if there is a leading quote
  330. //
  331. if(*WhiteScan == L'\"')
  332. {
  333. // we will NOT retry search, as app name is quoted.
  334. SearchRetry = FALSE;
  335. WhiteScan++;
  336. TempApplName = WhiteScan;
  337. while(*WhiteScan) {
  338. if( *WhiteScan == L'\"')
  339. {
  340. TempChar = *WhiteScan;
  341. *WhiteScan = L'\0';
  342. TempRemainderString = WhiteScan;
  343. break;
  344. }
  345. WhiteScan++;
  346. }
  347. }
  348. else
  349. {
  350. // skip to the first non-white char
  351. while(*WhiteScan) {
  352. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  353. {
  354. WhiteScan++;
  355. }
  356. else
  357. break;
  358. }
  359. TempApplName = WhiteScan;
  360. while(*WhiteScan) {
  361. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  362. {
  363. TempChar = *WhiteScan;
  364. *WhiteScan = L'\0';
  365. TempRemainderString = WhiteScan;
  366. break;
  367. }
  368. WhiteScan++;
  369. }
  370. }
  371. RetrySearch:
  372. Length = SearchPathW(
  373. NULL,
  374. TempApplName,
  375. (PWSTR)L".exe",
  376. MAX_PATH,
  377. NameBuffer,
  378. NULL
  379. );
  380. if(!Length || Length > MAX_PATH)
  381. {
  382. if(LastError)
  383. SetLastError(LastError);
  384. else
  385. LastError = GetLastError();
  386. CoverForDirectoryCase:
  387. //
  388. // If we still have command line left, then keep going
  389. // the point is to march through the command line looking
  390. // for whitespace so we can try to find an image name
  391. // launches of things like:
  392. // c:\word 95\winword.exe /embedding -automation
  393. // require this. Our first iteration will
  394. // stop at c:\word, our next
  395. // will stop at c:\word 95\winword.exe
  396. //
  397. if(TempRemainderString)
  398. {
  399. *TempRemainderString = TempChar;
  400. WhiteScan++;
  401. }
  402. if(*WhiteScan & SearchRetry)
  403. {
  404. // again skip to the first non-white char
  405. while(*WhiteScan) {
  406. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  407. {
  408. WhiteScan++;
  409. }
  410. else
  411. break;
  412. }
  413. while(*WhiteScan) {
  414. if( *WhiteScan == L' ' || *WhiteScan == L'\t')
  415. {
  416. TempChar = *WhiteScan;
  417. *WhiteScan = L'\0';
  418. TempRemainderString = WhiteScan;
  419. break;
  420. }
  421. WhiteScan++;
  422. }
  423. // we'll do one last try of the whole string.
  424. if(!WhiteScan) SearchRetry = FALSE;
  425. goto RetrySearch;
  426. }
  427. //
  428. // otherwise we have failed.
  429. //
  430. if(NameBuffer) HeapFree(hheap, 0, NameBuffer);
  431. if(ApplName) HeapFree(hheap, 0, ApplName);
  432. // we should let CreateProcess do its job.
  433. if (pszApplName)
  434. {
  435. HeapFree(hheap, 0, pszApplName);
  436. pszApplName = NULL;
  437. }
  438. hr = StringCchCopy(pszCmdLine, ccCmdLine, lpCommandLine);
  439. if (FAILED(hr)) {
  440. LastError = (DWORD)hr;
  441. __leave;
  442. }
  443. }
  444. else
  445. {
  446. // searchpath succeeded.
  447. // but it can find a directory!
  448. fileattr = GetFileAttributesW(NameBuffer);
  449. if ( fileattr != 0xffffffff &&
  450. (fileattr & FILE_ATTRIBUTE_DIRECTORY) ) {
  451. Length = 0;
  452. goto CoverForDirectoryCase;
  453. }
  454. //
  455. // so it is not a directory.. it must be the real thing!
  456. //
  457. hr = StringCchCopy(pszApplName, ccPszApplName, NameBuffer);
  458. if (FAILED(hr)) {
  459. LastError = (DWORD)hr;
  460. __leave;
  461. }
  462. hr = StringCchCopy(pszCmdLine, ccCmdLine, lpCommandLine);
  463. if (FAILED(hr)) {
  464. LastError = (DWORD)hr;
  465. __leave;
  466. }
  467. HeapFree(hheap, 0, ApplName);
  468. HeapFree(hheap, 0, NameBuffer);
  469. }
  470. }
  471. else
  472. {
  473. LastError = ERROR_INVALID_PARAMETER;
  474. __leave;
  475. }
  476. }
  477. else
  478. {
  479. //
  480. // If ApplicationName is not null, we need to handle
  481. // one case here -- the application name is present in
  482. // current directory. All other cases will be handled by
  483. // CreateProcess in the server side anyway.
  484. //
  485. //
  486. // let us get a FullPath relative to current directory
  487. // and try to open it. If it succeeds, then the full path
  488. // is what we'll give as app name.. otherwise will just
  489. // pass what we got from caller and let CreateProcess deal with it.
  490. LPWSTR lpFilePart;
  491. DWORD cchFullPath = GetFullPathName(
  492. lpApplicationName,
  493. MAX_PATH,
  494. pszApplName,
  495. &lpFilePart
  496. );
  497. if(cchFullPath)
  498. {
  499. HANDLE hFile;
  500. //
  501. // let us try to open it.
  502. // if it works, pszApplName is already setup correctly.
  503. // just close the handle.
  504. hFile = CreateFile(lpApplicationName, GENERIC_READ,
  505. FILE_SHARE_READ | FILE_SHARE_WRITE,
  506. NULL,
  507. OPEN_EXISTING,
  508. 0,
  509. NULL
  510. );
  511. if(hFile == INVALID_HANDLE_VALUE)
  512. {
  513. // otherwise, keep what the caller gave us.
  514. hr = StringCchCopy(pszApplName, ccPszApplName, lpApplicationName);
  515. if (FAILED(hr)) {
  516. LastError = (DWORD)hr;
  517. __leave;
  518. }
  519. }
  520. else
  521. CloseHandle(hFile);
  522. }
  523. else {
  524. // lets keep what the caller gave us.
  525. hr = StringCchCopy(pszApplName, ccPszApplName, lpApplicationName);
  526. if (FAILED(hr)) {
  527. LastError = (DWORD)hr;
  528. __leave;
  529. }
  530. }
  531. //
  532. // Commandline should be kept as is.
  533. //
  534. if(lpCommandLine != NULL) {
  535. hr = StringCchCopy(pszCmdLine, ccCmdLine, lpCommandLine);
  536. if (FAILED(hr)) {
  537. LastError = (DWORD)hr;
  538. __leave;
  539. }
  540. }
  541. else
  542. {
  543. HeapFree(hheap, 0, pszCmdLine);
  544. pszCmdLine = NULL;
  545. }
  546. }
  547. #if 0
  548. if(lpApplicationName != NULL) lstrcpy(pszApplName,lpApplicationName);
  549. else {
  550. HeapFree(hheap, 0, pszApplName);
  551. pszApplName = NULL;
  552. }
  553. if(lpCommandLine != NULL) lstrcpy(pszCmdLine, lpCommandLine);
  554. else {
  555. HeapFree(hheap, 0, pszCmdLine);
  556. pszCmdLine = NULL;
  557. }
  558. #endif
  559. // Construct a memory block will all the info that needs to go to the server
  560. sli.lLogonIdHighPart = 0;
  561. sli.ulLogonIdLowPart = 0;
  562. sli.ulLogonFlags = dwLogonFlags;
  563. sli.ulProcessId = GetCurrentProcessId();
  564. sli.ulCreationFlags = dwCreationFlags;
  565. sli.hWinsta = 0; // no longer used
  566. sli.hDesk = 0; // no longer used
  567. ASSIGN_SECL_STRING(sli.ssUsername, (LPWSTR) lpUsername);
  568. ASSIGN_SECL_STRING(sli.ssDomain, (LPWSTR) lpDomain);
  569. ASSIGN_SECL_STRING(sli.ssApplicationName, pszApplName);
  570. ASSIGN_SECL_STRING(sli.ssCommandLine, pszCmdLine);
  571. ASSIGN_SECL_STRING(sli.ssCurrentDirectory, (LPWSTR)lpCurrentDirectory);
  572. ASSIGN_SECL_STRING(sli.ssDesktop, lpStartupInfo->lpDesktop);
  573. ASSIGN_SECL_STRING(sli.ssTitle, lpStartupInfo->lpTitle);
  574. if (0 != (sli.ulCreationFlags & CREATE_UNICODE_ENVIRONMENT)) {
  575. LastError = To_SECL_BLOB_W(lpEnvironment, &(sli.sbEnvironment));
  576. }
  577. else {
  578. LastError = To_SECL_BLOB_A(lpEnvironment, &(sli.sbEnvironment));
  579. }
  580. if (ERROR_SUCCESS != LastError) { __leave; }
  581. // If the caller hasn't specified their own desktop, we'll do it for
  582. // them (the seclogon service will take care of granting access
  583. // to the desktop).
  584. if (sli.ssDesktop.pwsz == NULL || sli.ssDesktop.pwsz[0] == L'\0')
  585. {
  586. DWORD Length;
  587. HWINSTA Winsta = GetProcessWindowStation();
  588. HDESK Desk = GetThreadDesktop(GetCurrentThreadId());
  589. // Send seclogon the name of the current windowstation and desktop.
  590. // Default to empty string if we can't get the name:
  591. ASSIGN_SECL_STRING(sli.ssDesktop, pwszEmptyString);
  592. if (GetUserObjectInformation(Winsta, UOI_NAME, wszDesktopName, (MAX_PATH*sizeof(WCHAR)), &Length))
  593. {
  594. Length = (DWORD)wcslen(wszDesktopName);
  595. wszDesktopName[Length++] = L'\\';
  596. if(GetUserObjectInformation(Desk, UOI_NAME, &wszDesktopName[Length], (MAX_PATH*sizeof(WCHAR)), &Length))
  597. {
  598. // sli.ssDesktop now contains "windowstation\desktop"
  599. ASSIGN_SECL_STRING(sli.ssDesktop, wszDesktopName);
  600. }
  601. }
  602. }
  603. else
  604. {
  605. // The caller specified their own desktop
  606. sli.ulSeclogonFlags |= SECLOGON_CALLER_SPECIFIED_DESKTOP;
  607. }
  608. // Perform the RPC call to the seclogon service:
  609. LastError = c_SeclCreateProcessWithLogonW(&sli, &slri);
  610. if (ERROR_SUCCESS != LastError) __leave;
  611. fOk = (slri.ulErrorCode == NO_ERROR); // This function succeeds if the server's function succeeds
  612. if (!fOk) {
  613. //
  614. // If the server function failed, set the server's
  615. // returned eror code as this thread's error code
  616. //
  617. LastError = slri.ulErrorCode;
  618. SetLastError(slri.ulErrorCode);
  619. } else {
  620. //
  621. // The server function succeeded, return the
  622. // PROCESS_INFORMATION info
  623. //
  624. lpProcessInformation->hProcess = (HANDLE)slri.hProcess;
  625. lpProcessInformation->hThread = (HANDLE)slri.hThread;
  626. lpProcessInformation->dwProcessId = slri.ulProcessId;
  627. lpProcessInformation->dwThreadId = slri.ulThreadId;
  628. LastError = ERROR_SUCCESS;
  629. }
  630. }
  631. __finally {
  632. if (NULL != pszCmdLine) HeapFree(hheap, 0, pszCmdLine);
  633. if (NULL != pszApplName) HeapFree(hheap, 0, pszApplName);
  634. if (fRevertWinsta) SetProcessWindowStation(hWinstaSave);
  635. if (NULL != hWinsta) CloseWindowStation(hWinsta);
  636. if (NULL != hDesk) CloseDesktop(hDesk);
  637. SetLastError(LastError);
  638. }
  639. return(fOk);
  640. }
  641. ////////////////////////////////////////////////////////////////////////
  642. //
  643. // RPC Utility methods:
  644. //
  645. ////////////////////////////////////////////////////////////////////////
  646. DWORD To_SECL_BLOB_W(IN LPVOID lpEnvironment,
  647. OUT SECL_BLOB *psb) {
  648. DWORD cb = 0;
  649. DWORD dwResult = NULL;
  650. HANDLE hHeap = NULL;
  651. HRESULT hr;
  652. LPBYTE pb = NULL;
  653. LPWSTR pwsz = NULL;
  654. size_t totalLen = 0;
  655. size_t nextLen;
  656. hHeap = GetProcessHeap();
  657. _JumpCondition(NULL == hHeap, GetProcessHeapError);
  658. if (NULL != lpEnvironment) {
  659. for (pwsz = (LPWSTR)lpEnvironment; pwsz[0] != L'\0'; pwsz += nextLen + 1) {
  660. // 10K chars is the most we allow for the environment block:
  661. hr = StringCchLengthW(pwsz, (10*1024)-totalLen, &nextLen);
  662. if (FAILED(hr))
  663. goto StringCchLengthWError;
  664. totalLen += nextLen + 1;
  665. }
  666. cb = sizeof(WCHAR) * ((DWORD)(1 + totalLen));
  667. pb = (LPBYTE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cb);
  668. _JumpCondition(NULL == pb, MemoryError);
  669. CopyMemory(pb, (LPBYTE)lpEnvironment, cb);
  670. }
  671. psb->cb = cb;
  672. psb->pb = pb;
  673. dwResult = ERROR_SUCCESS;
  674. CommonReturn:
  675. return dwResult;
  676. ErrorReturn:
  677. if (NULL != pb) { HeapFree(hHeap, 0, pb); }
  678. goto CommonReturn;
  679. SET_DWRESULT(GetProcessHeapError, GetLastError());
  680. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  681. SET_DWRESULT(StringCchLengthWError, (DWORD)hr);
  682. }
  683. DWORD To_SECL_BLOB_A(IN LPVOID lpEnvironment,
  684. OUT SECL_BLOB *psb) {
  685. DWORD cb = 0;
  686. DWORD dwResult;
  687. HANDLE hHeap = NULL;
  688. HRESULT hr;
  689. LPBYTE pb = NULL;
  690. LPSTR psz = NULL;
  691. size_t totalLen = 0;
  692. size_t nextLen;
  693. hHeap = GetProcessHeap();
  694. _JumpCondition(NULL == hHeap, GetProcessHeapError);
  695. if (NULL != lpEnvironment) {
  696. for (psz = (LPSTR)lpEnvironment; psz[0] != '\0'; psz += nextLen + 1) {
  697. // 10K chars is the most we allow for the environment block:
  698. hr = StringCchLengthA(psz, (10*1024)-totalLen, &nextLen);
  699. if (FAILED(hr))
  700. goto StringCchLengthAError;
  701. totalLen += nextLen + 1;
  702. }
  703. cb = (DWORD)(1 + totalLen);
  704. pb = (LPBYTE)HeapAlloc(hHeap, HEAP_ZERO_MEMORY, cb);
  705. _JumpCondition(NULL == pb, MemoryError);
  706. CopyMemory(pb, (LPBYTE)lpEnvironment, cb);
  707. }
  708. psb->cb = cb;
  709. psb->pb = pb;
  710. dwResult = ERROR_SUCCESS;
  711. CommonReturn:
  712. return dwResult;
  713. ErrorReturn:
  714. if (NULL != pb) { HeapFree(hHeap, 0, pb); }
  715. goto CommonReturn;
  716. SET_DWRESULT(GetProcessHeapError, GetLastError());
  717. SET_DWRESULT(MemoryError, ERROR_NOT_ENOUGH_MEMORY);
  718. SET_DWRESULT(StringCchLengthAError, (DWORD)hr);
  719. }
  720. DWORD StartSeclogonService() {
  721. BOOL fResult;
  722. DWORD dwInitialCount;
  723. DWORD dwResult;
  724. SC_HANDLE hSCM = NULL;
  725. SC_HANDLE hService = NULL;
  726. SERVICE_STATUS sSvcStatus;
  727. hSCM = OpenSCManager(NULL, NULL, SC_MANAGER_CONNECT);
  728. _JumpCondition(hSCM == NULL, OpenSCManagerError);
  729. hService = OpenService(hSCM, wszSvcName, SERVICE_START | SERVICE_QUERY_STATUS);
  730. _JumpCondition(NULL == hService, OpenServiceError);
  731. fResult = StartService(hService, NULL, NULL);
  732. _JumpCondition(FALSE == fResult, StartServiceError);
  733. // Wait until the service has actually started.
  734. // Set timeout to 20 seconds.
  735. dwInitialCount = GetTickCount();
  736. // Keep polling to see if the service has started ...
  737. for (;;)
  738. {
  739. fResult = QueryServiceStatus(hService, &sSvcStatus);
  740. _JumpCondition(FALSE == fResult, QueryServiceStatusError);
  741. // The service is running. We can stop waiting for it.
  742. if (sSvcStatus.dwCurrentState == SERVICE_RUNNING)
  743. break;
  744. // Check to see if we've timed out. If GetTickCount() rolls over,
  745. // then at worst we time out early.
  746. _JumpCondition((GetTickCount() - dwInitialCount) > 20000, ServiceTimeoutError);
  747. // Don't hose the service.
  748. SleepEx(100, FALSE);
  749. }
  750. // Ok, the service has successfully started.
  751. dwResult = ERROR_SUCCESS;
  752. CommonReturn:
  753. if (NULL != hSCM) { CloseServiceHandle(hSCM); }
  754. if (NULL != hService) { CloseServiceHandle(hService); }
  755. return dwResult;
  756. ErrorReturn:
  757. goto CommonReturn;
  758. SET_DWRESULT(OpenSCManagerError, GetLastError());
  759. SET_DWRESULT(OpenServiceError, GetLastError());
  760. SET_DWRESULT(QueryServiceStatusError, GetLastError());
  761. SET_DWRESULT(StartServiceError, GetLastError());
  762. SET_DWRESULT(ServiceTimeoutError, ERROR_SERVICE_REQUEST_TIMEOUT);
  763. }
  764. DWORD SetupLocalRPCSecurity(handle_t hRPCBinding)
  765. {
  766. CHAR szDomainName[128];
  767. CHAR szName[128];
  768. DWORD cbDomainName;
  769. DWORD cbName;
  770. DWORD dwResult;
  771. PSID pSid = NULL;
  772. RPC_SECURITY_QOS SecurityQOS;
  773. SID_IDENTIFIER_AUTHORITY SidAuthority = SECURITY_NT_AUTHORITY;
  774. SID_NAME_USE SidNameUse;
  775. // We're doing LRPC -- we need to get the account name of the service to do mutual auth
  776. if (!AllocateAndInitializeSid(&SidAuthority, 1, SECURITY_LOCAL_SYSTEM_RID, 0, 0, 0, 0, 0, 0, 0, &pSid))
  777. goto AllocateAndInitializeSidError;
  778. cbName = sizeof(szName);
  779. cbDomainName = sizeof(szDomainName);
  780. if (!LookupAccountSidA(NULL, pSid, szName, &cbName, szDomainName, &cbDomainName, &SidNameUse))
  781. goto LookupAccountSidAError;
  782. // Specify quality of service parameters.
  783. SecurityQOS.ImpersonationType = RPC_C_IMP_LEVEL_IMPERSONATE; // the server will need to impersonate us
  784. SecurityQOS.Version = RPC_C_SECURITY_QOS_VERSION;
  785. SecurityQOS.Capabilities = RPC_C_QOS_CAPABILITIES_MUTUAL_AUTH; // we need mutual auth
  786. SecurityQOS.IdentityTracking = RPC_C_QOS_IDENTITY_STATIC; // calls go to the server under the identity that created the binding handle
  787. dwResult = RpcBindingSetAuthInfoExA(hRPCBinding, (unsigned char *)szName, RPC_C_AUTHN_LEVEL_PKT_PRIVACY, RPC_C_AUTHN_WINNT, NULL, 0, &SecurityQOS);
  788. if (RPC_S_OK != dwResult)
  789. goto RpcBindingSetAuthInfoExAError;
  790. dwResult = ERROR_SUCCESS;
  791. ErrorReturn:
  792. if (NULL != pSid) {
  793. FreeSid(pSid);
  794. }
  795. return dwResult;
  796. SET_DWRESULT(AllocateAndInitializeSidError, GetLastError());
  797. SET_DWRESULT(LookupAccountSidAError, GetLastError());
  798. SET_DWRESULT(RpcBindingSetAuthInfoExAError, dwResult);
  799. }
  800. DWORD c_SeclCreateProcessWithLogonW
  801. (IN SECL_SLI *psli,
  802. OUT SECL_SLRI *pslri)
  803. {
  804. DWORD dwResult;
  805. LPWSTR pwszBinding = NULL;
  806. RPC_BINDING_HANDLE hRPCBinding = NULL;
  807. dwResult = RpcStringBindingCompose
  808. (NULL,
  809. (USHORT *)L"ncalrpc",
  810. NULL,
  811. (USHORT *)wszSeclogonSharedProcEndpointName,
  812. (USHORT *)L"Security=impersonation static false",
  813. (USHORT **)&pwszBinding);
  814. _JumpCondition(RPC_S_OK != dwResult, RpcStringBindingComposeError);
  815. dwResult = RpcBindingFromStringBinding((USHORT *)pwszBinding, &hRPCBinding);
  816. _JumpCondition(0 != dwResult, RpcBindingFromStringBindingError);
  817. dwResult = SetupLocalRPCSecurity(hRPCBinding);
  818. _JumpCondition(ERROR_SUCCESS != dwResult, SetupLocalRpcSecurityError);
  819. // Perform the RPC call to the seclogon service. If the call fails because the
  820. // service was not started, try again. If the call still fails, give up.
  821. for (BOOL fFirstTry = TRUE; /*TRUE*/; fFirstTry = FALSE) {
  822. __try {
  823. SeclCreateProcessWithLogonW(hRPCBinding, psli, pslri);
  824. break;
  825. }
  826. __except(EXCEPTION_EXECUTE_HANDLER) {
  827. dwResult = RpcExceptionCode();
  828. if ((RPC_S_SERVER_UNAVAILABLE == dwResult || RPC_S_UNKNOWN_IF == dwResult) &&
  829. (TRUE == fFirstTry)) {
  830. // Ok, the seclogon service is probably just not started.
  831. // Attempt to start it up and try again.
  832. dwResult = StartSeclogonService();
  833. _JumpCondition(ERROR_SUCCESS != dwResult, SeclCreateProcessWithLogonWError);
  834. }
  835. else {
  836. goto SeclCreateProcessWithLogonWError;
  837. }
  838. }
  839. }
  840. dwResult = ERROR_SUCCESS;
  841. CommonReturn:
  842. if (NULL != pwszBinding) { RpcStringFree((USHORT **)&pwszBinding); }
  843. if (NULL != hRPCBinding) { RpcBindingFree(&hRPCBinding); }
  844. return dwResult;
  845. ErrorReturn:
  846. goto CommonReturn;
  847. SET_DWRESULT(RpcBindingFromStringBindingError, dwResult);
  848. SET_DWRESULT(RpcStringBindingComposeError, dwResult);
  849. SET_DWRESULT(SeclCreateProcessWithLogonWError, dwResult);
  850. SET_DWRESULT(SetupLocalRpcSecurityError, dwResult);
  851. }
  852. void DbgPrintf( DWORD /*dwSubSysId*/, LPCSTR /*pszFormat*/ , ...)
  853. {
  854. }
  855. //////////////////////////////// End Of File /////////////////////////////////