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.

1238 lines
26 KiB

  1. /*++
  2. Copyright (c) 1999-2001 Microsoft Corporation
  3. Module Name:
  4. utils.cpp
  5. Abstract:
  6. utility routines
  7. Author:
  8. Brian Guarraci (briangu) 2001.
  9. Revision History:
  10. --*/
  11. #include <TChar.h>
  12. #include <stdlib.h>
  13. #include "cmnhdr.h"
  14. #include <utils.h>
  15. #include <Sddl.h>
  16. #include <Shlwapi.h>
  17. #define SECURITY_WIN32
  18. #include <security.h>
  19. #include <secext.h>
  20. #define DESKTOP_ALL (DESKTOP_READOBJECTS | \
  21. DESKTOP_CREATEWINDOW | \
  22. DESKTOP_CREATEMENU | \
  23. DESKTOP_HOOKCONTROL | \
  24. DESKTOP_JOURNALRECORD | \
  25. DESKTOP_JOURNALPLAYBACK | \
  26. DESKTOP_ENUMERATE | \
  27. DESKTOP_WRITEOBJECTS | \
  28. DESKTOP_SWITCHDESKTOP | \
  29. STANDARD_RIGHTS_REQUIRED \
  30. )
  31. #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | \
  32. WINSTA_READATTRIBUTES | \
  33. WINSTA_ACCESSCLIPBOARD | \
  34. WINSTA_CREATEDESKTOP | \
  35. WINSTA_WRITEATTRIBUTES | \
  36. WINSTA_ACCESSGLOBALATOMS | \
  37. WINSTA_EXITWINDOWS | \
  38. WINSTA_ENUMERATE | \
  39. WINSTA_READSCREEN | \
  40. STANDARD_RIGHTS_REQUIRED \
  41. )
  42. #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
  43. #define MAXDWORD (~(DWORD)0)
  44. void
  45. FillProcessStartupInfo(
  46. IN OUT STARTUPINFO *si,
  47. IN PWCHAR desktopName,
  48. IN HANDLE hStdinPipe,
  49. IN HANDLE hStdoutPipe,
  50. IN HANDLE hStdError
  51. )
  52. /*++
  53. Routine Description:
  54. This routine populates the process startup info
  55. with the std I/O/error handles and other necessary
  56. elements for creating a cmd process to run under
  57. the session.
  58. Arguments:
  59. si - the STARTUPINFO structure
  60. hStdinPipe - the standard input handle
  61. hStdoutPipe - the standard output handle
  62. hStdError - the standard error handle
  63. Return Value:
  64. None
  65. --*/
  66. {
  67. ASSERT( si != NULL );
  68. //
  69. // Initialize the SI
  70. //
  71. ZeroMemory(si, sizeof(STARTUPINFO));
  72. si->cb = sizeof(STARTUPINFO);
  73. //
  74. // Populate the I/O Handles
  75. //
  76. si->dwFlags = STARTF_USESTDHANDLES;
  77. si->hStdInput = hStdinPipe;
  78. si->hStdOutput = hStdoutPipe;
  79. si->hStdError = hStdError;
  80. //
  81. // We need this when we create a process as a user
  82. // so that console i/o works.
  83. //
  84. si->lpDesktop = desktopName;
  85. return;
  86. }
  87. bool
  88. NeedCredentials(
  89. VOID
  90. )
  91. /*++
  92. Routine Description:
  93. This routine will detect if the user must give us credentials.
  94. If so, we return TRUE, if not, we'll return FALSE.
  95. Arguments:
  96. None.
  97. Return Value:
  98. TRUE - The user must provide us some credentials.
  99. FALSE - The user doesn't need to give us any credentials.
  100. Security:
  101. interface: registry
  102. --*/
  103. {
  104. DWORD rc;
  105. HKEY hKey;
  106. DWORD DWord;
  107. DWORD dwsize;
  108. DWORD DataType;
  109. //
  110. // See if we're in Setup. If so, then there's no need to ask
  111. // for any credentials.
  112. //
  113. rc = RegOpenKeyEx( HKEY_LOCAL_MACHINE,
  114. L"System\\Setup",
  115. 0,
  116. KEY_READ,
  117. &hKey );
  118. if( rc == NO_ERROR ) {
  119. dwsize = sizeof(DWORD);
  120. rc = RegQueryValueEx(
  121. hKey,
  122. TEXT("SystemSetupInProgress"),
  123. NULL,
  124. &DataType,
  125. (LPBYTE)&DWord,
  126. &dwsize );
  127. RegCloseKey( hKey );
  128. if ((rc == NO_ERROR) &&
  129. (DataType == REG_DWORD) &&
  130. (dwsize == sizeof(DWORD))
  131. ) {
  132. if (DWord == 1) {
  133. return FALSE;
  134. }
  135. }
  136. }
  137. //
  138. // Default to returning that login credentials are required.
  139. //
  140. return TRUE;
  141. }
  142. BOOL
  143. GetLogonSID (
  144. IN HANDLE hToken,
  145. OUT PSID *ppsid
  146. )
  147. /*++
  148. Routine Description:
  149. This routine retrieves the SID of a given access token.
  150. Arguments:
  151. hToken - access token
  152. ppsid - on success, contains the SID
  153. Return Value:
  154. Status
  155. --*/
  156. {
  157. BOOL bSuccess = FALSE;
  158. DWORD dwIndex;
  159. DWORD dwLength = 0;
  160. PTOKEN_GROUPS ptg = NULL;
  161. //
  162. // Get required buffer size and allocate the TOKEN_GROUPS buffer.
  163. //
  164. if (!GetTokenInformation(
  165. hToken, // handle to the access token
  166. TokenGroups, // get information about the token's groups
  167. (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
  168. 0, // size of buffer
  169. &dwLength // receives required buffer size
  170. )) {
  171. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
  172. goto Cleanup;
  173. }
  174. ptg = (PTOKEN_GROUPS)HeapAlloc(
  175. GetProcessHeap(),
  176. HEAP_ZERO_MEMORY,
  177. dwLength);
  178. if (ptg == NULL) {
  179. goto Cleanup;
  180. }
  181. }
  182. //
  183. // Get the token group information from the access token.
  184. //
  185. if (!GetTokenInformation(
  186. hToken, // handle to the access token
  187. TokenGroups, // get information about the token's groups
  188. (LPVOID) ptg, // pointer to TOKEN_GROUPS buffer
  189. dwLength, // size of buffer
  190. &dwLength // receives required buffer size
  191. )) {
  192. goto Cleanup;
  193. }
  194. //
  195. // Loop through the groups to find the logon SID.
  196. //
  197. for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
  198. if ((ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID) == SE_GROUP_LOGON_ID) {
  199. // Found the logon SID; make a copy of it.
  200. dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
  201. *ppsid = (PSID) HeapAlloc(
  202. GetProcessHeap(),
  203. HEAP_ZERO_MEMORY,
  204. dwLength
  205. );
  206. if (*ppsid == NULL) {
  207. goto Cleanup;
  208. }
  209. if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid)) {
  210. HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
  211. goto Cleanup;
  212. }
  213. break;
  214. }
  215. bSuccess = TRUE;
  216. Cleanup:
  217. // Free the buffer for the token groups.
  218. if (ptg != NULL) {
  219. HeapFree(GetProcessHeap(), 0, (LPVOID)ptg);
  220. }
  221. return bSuccess;
  222. }
  223. VOID
  224. FreeLogonSID (
  225. IN OUT PSID *ppsid
  226. )
  227. /*++
  228. Routine Description:
  229. Counterpart to GetLogonSID (Release the logon SID)
  230. Arguments:
  231. ppsid - the sid to release
  232. Return Value:
  233. None
  234. --*/
  235. {
  236. HeapFree(GetProcessHeap(), 0, (LPVOID)*ppsid);
  237. }
  238. DWORD
  239. GetAndComputeTickCountDeltaT(
  240. IN DWORD StartTick
  241. )
  242. /*++
  243. Routine Description:
  244. Determine how long it has been since the esc-ctrl-a sequence
  245. Arguments:
  246. StartTick - the timer tick at the beginning of the time-span
  247. Return Value:
  248. The deltaT
  249. --*/
  250. {
  251. DWORD TickCount;
  252. DWORD DeltaT;
  253. //
  254. // get the current tick count to compare against the start tick cnt
  255. //
  256. TickCount = GetTickCount();
  257. //
  258. // Account for the tick count rollover every 49.7 days of system up time
  259. //
  260. if (TickCount < StartTick) {
  261. DeltaT = (~((DWORD)0) - StartTick) + TickCount;
  262. } else {
  263. DeltaT = TickCount - StartTick;
  264. }
  265. return DeltaT;
  266. }
  267. BOOL
  268. NtGetUserName (
  269. OUT LPTSTR *pUserName
  270. )
  271. /*+++
  272. Description:
  273. This routine calls the GetUserNameEx WIN32 call to get the
  274. SAM compatible user id of the user under which this process is running. The
  275. user id is returned through a static buffer pUserName and must be freed by
  276. the caller.
  277. Arguments:
  278. None
  279. Return Values:
  280. None
  281. Security:
  282. interface: system info
  283. ---*/
  284. {
  285. BOOL bSuccess;
  286. DWORD dwError = 0;
  287. LPTSTR wcUserIdBuffer;
  288. ULONG ulUserIdBuffSize;
  289. //
  290. // default: the username pointer is NULL until success
  291. //
  292. *pUserName = NULL;
  293. //
  294. // default: reasonable initial size
  295. //
  296. ulUserIdBuffSize = 256;
  297. //
  298. // attempt to load the username
  299. // grow the username buffer if necessary
  300. //
  301. do {
  302. //
  303. // allocate the username buffer according
  304. // to the current attempt size
  305. //
  306. wcUserIdBuffer = new TCHAR[ulUserIdBuffSize];
  307. //
  308. // attempt to get the username
  309. //
  310. bSuccess = GetUserNameEx(
  311. NameSamCompatible,
  312. wcUserIdBuffer,
  313. &ulUserIdBuffSize
  314. );
  315. if ( !bSuccess ) {
  316. dwError = GetLastError();
  317. if ( dwError != STATUS_BUFFER_TOO_SMALL ) {
  318. delete [] wcUserIdBuffer;
  319. break;
  320. }
  321. } else {
  322. //
  323. // the username buffer is valid
  324. //
  325. *pUserName = wcUserIdBuffer;
  326. break;
  327. }
  328. } while ( dwError == STATUS_BUFFER_TOO_SMALL );
  329. return bSuccess;
  330. }
  331. BOOL
  332. UtilLoadProfile(
  333. IN HANDLE hToken,
  334. OUT HANDLE *hProfile
  335. )
  336. /*++
  337. Routine Description:
  338. This routine loads the profile and environment block for the specified
  339. user (hToken). These operations are combined becuase we will always need
  340. to do both here.
  341. Note: the caller must call UtilUnloadProfile when done.
  342. Arguments:
  343. hToken - the specified user's authenticated token
  344. hProfile - on success, contains the user's profile handle
  345. Return Value:
  346. TRUE - success
  347. FALSE - otherwise
  348. Security:
  349. interface: user profile api & DS
  350. --*/
  351. {
  352. LPTSTR pwszUserName;
  353. BOOL bSuccess;
  354. PROFILEINFO ProfileInfo;
  355. if (hToken == INVALID_HANDLE_VALUE) {
  356. return FALSE;
  357. }
  358. if (hProfile == NULL) {
  359. ASSERT(0);
  360. return FALSE;
  361. }
  362. //
  363. //
  364. //
  365. *hProfile = INVALID_HANDLE_VALUE;
  366. //
  367. // default: unsuccussful
  368. //
  369. bSuccess = FALSE;
  370. __try {
  371. //
  372. // clear the profile handle
  373. //
  374. RtlZeroMemory(&ProfileInfo, sizeof(PROFILEINFO));
  375. do {
  376. //
  377. // Become the specified user so we can get the username
  378. //
  379. bSuccess = ImpersonateLoggedOnUser(hToken);
  380. if (!bSuccess) {
  381. break;
  382. }
  383. //
  384. // get the username for the profile
  385. //
  386. bSuccess = NtGetUserName(
  387. &pwszUserName
  388. );
  389. ASSERT(bSuccess);
  390. //
  391. // return to the previous state
  392. //
  393. if (!RevertToSelf() || !bSuccess || pwszUserName == NULL) {
  394. bSuccess = FALSE;
  395. break;
  396. }
  397. //
  398. // Populate the profile structure so that we can
  399. // attempt to load the profile for the specified user
  400. //
  401. ProfileInfo.dwSize = sizeof ( PROFILEINFO );
  402. ProfileInfo.dwFlags = PI_NOUI;
  403. ProfileInfo.lpUserName = pwszUserName;
  404. //
  405. // Load the profile
  406. //
  407. bSuccess = LoadUserProfile (
  408. hToken,
  409. &ProfileInfo
  410. );
  411. //
  412. // we are done with the username
  413. //
  414. delete[] pwszUserName;
  415. if (!bSuccess) {
  416. break;
  417. }
  418. //
  419. // return the registry key handle
  420. //
  421. *hProfile = ProfileInfo.hProfile;
  422. } while ( FALSE );
  423. }
  424. __except(EXCEPTION_EXECUTE_HANDLER) {
  425. bSuccess = FALSE;
  426. }
  427. return bSuccess;
  428. }
  429. BOOL
  430. UtilLoadEnvironment(
  431. IN HANDLE hToken,
  432. OUT PVOID *pchEnvBlock
  433. )
  434. /*++
  435. Routine Description:
  436. This routine loads the environment block for the specified user (hToken).
  437. Note: the caller must call UtilUnloadEnvironment when done.
  438. Arguments:
  439. hToken - the specified user's authenticated token
  440. pchEnvBlock - on success, points to the env. block
  441. Return Value:
  442. TRUE - success
  443. FALSE - otherwise
  444. --*/
  445. {
  446. BOOL bSuccess;
  447. if (hToken == INVALID_HANDLE_VALUE) {
  448. return FALSE;
  449. }
  450. if (pchEnvBlock == NULL) {
  451. ASSERT(0);
  452. return FALSE;
  453. }
  454. //
  455. // default: unsuccussful
  456. //
  457. bSuccess = FALSE;
  458. __try {
  459. //
  460. // Load the user's environment block
  461. //
  462. bSuccess = CreateEnvironmentBlock(
  463. (void**)pchEnvBlock,
  464. hToken,
  465. FALSE
  466. );
  467. if (!bSuccess) {
  468. //
  469. // Ensure that the env. block ptr is NULL
  470. //
  471. *pchEnvBlock = NULL;
  472. }
  473. }
  474. __except(EXCEPTION_EXECUTE_HANDLER) {
  475. bSuccess = FALSE;
  476. }
  477. return bSuccess;
  478. }
  479. BOOL
  480. UtilUnloadProfile(
  481. IN HANDLE hToken,
  482. IN HANDLE hProfile
  483. )
  484. /*++
  485. Routine Description:
  486. This routine unloads the profile the specified user (hToken).
  487. Arguments:
  488. hToken - the specified user's authenticated token
  489. hProfile - the profile handle to unload
  490. Return Value:
  491. TRUE - success
  492. FALSE - otherwise
  493. --*/
  494. {
  495. BOOL bSuccess;
  496. if (hToken == INVALID_HANDLE_VALUE) {
  497. return FALSE;
  498. }
  499. if (hProfile == INVALID_HANDLE_VALUE) {
  500. ASSERT(0);
  501. return FALSE;
  502. }
  503. //
  504. // default: unsuccussful
  505. //
  506. bSuccess = FALSE;
  507. __try {
  508. bSuccess = UnloadUserProfile(
  509. hToken,
  510. hProfile
  511. );
  512. }
  513. __except(EXCEPTION_EXECUTE_HANDLER) {
  514. bSuccess = FALSE;
  515. }
  516. return bSuccess;
  517. }
  518. BOOL
  519. UtilUnloadEnvironment(
  520. IN PVOID pchEnvBlock
  521. )
  522. /*++
  523. Routine Description:
  524. This routine unloads the environment block for the specified user.
  525. Arguments:
  526. pchEnvBlock - the env. block
  527. Return Value:
  528. TRUE - success
  529. FALSE - otherwise
  530. --*/
  531. {
  532. BOOL bSuccess;
  533. if (pchEnvBlock == NULL) {
  534. ASSERT(0);
  535. return FALSE;
  536. }
  537. //
  538. // default: unsuccussful
  539. //
  540. bSuccess = FALSE;
  541. __try {
  542. bSuccess = DestroyEnvironmentBlock(pchEnvBlock);
  543. }
  544. __except(EXCEPTION_EXECUTE_HANDLER) {
  545. bSuccess = FALSE;
  546. }
  547. return bSuccess;
  548. }
  549. BOOL
  550. BuildSACWinStaDesktopName(
  551. IN PWCHAR winStaName,
  552. OUT PWCHAR *desktopName
  553. )
  554. /*++
  555. Routine Description:
  556. Arguments:
  557. Return Value:
  558. Status
  559. Security:
  560. --*/
  561. {
  562. ULONG l;
  563. PWSTR postfix = L"Default";
  564. //
  565. //
  566. //
  567. *desktopName = NULL;
  568. do {
  569. l = lstrlen(winStaName);
  570. l += 1; // for backslash
  571. l += lstrlen(postfix);
  572. *desktopName = new WCHAR[l+1];
  573. wnsprintf(
  574. *desktopName,
  575. l+1,
  576. L"%s\\%s",
  577. winStaName,
  578. postfix
  579. );
  580. } while(FALSE);
  581. return TRUE;
  582. }
  583. BOOL
  584. BuildSACWinStaName(
  585. OUT PWCHAR *winStaName
  586. )
  587. /*++
  588. Routine Description:
  589. Creates a winStaName. This string is the concatenation of "SACWinSta"
  590. with the string version of a GUID generated in this function.
  591. Arguments:
  592. winStaName - pointer to the address the windows station name will be
  593. written.
  594. Return Value:
  595. TRUE on success, FALSE otherwise.
  596. Security:
  597. --*/
  598. {
  599. BOOL bSuccess = TRUE;
  600. RPC_STATUS rpcStatus;
  601. ULONG l;
  602. PWSTR prefix = L"SACWinSta";
  603. UUID Uuid;
  604. LPWSTR UuidString = NULL;
  605. //
  606. //
  607. //
  608. *winStaName = NULL;
  609. do {
  610. //
  611. // Create a Uuid.
  612. //
  613. rpcStatus = UuidCreate(&Uuid);
  614. if (rpcStatus != RPC_S_OK) {
  615. bSuccess = FALSE;
  616. break;
  617. }
  618. //
  619. // Create a string for the Uuid
  620. //
  621. rpcStatus = UuidToString(&Uuid, &UuidString);
  622. if (rpcStatus != RPC_S_OK) {
  623. bSuccess = FALSE;
  624. break;
  625. }
  626. //
  627. // Calculate the required length for the windows station name.
  628. //
  629. l = lstrlen(prefix);
  630. l += lstrlen(UuidString);
  631. //
  632. // Create the windows station name buffer
  633. //
  634. *winStaName = new WCHAR[l+1];
  635. //
  636. // "SACWinSta"UUID
  637. //
  638. wnsprintf(
  639. *winStaName,
  640. l+1,
  641. L"%s%s",
  642. prefix,
  643. UuidString
  644. );
  645. //
  646. // Convert the '-'s from the Uuid to alphanumeric characters.
  647. //
  648. for(ULONG i = 0; i < wcslen(*winStaName); i++) {
  649. if ((*winStaName)[i] == L'-') {
  650. (*winStaName)[i] = L'0';
  651. }
  652. }
  653. //
  654. // Free memory allocated by UuidToString
  655. //
  656. RpcStringFree(&UuidString);
  657. } while(FALSE);
  658. return bSuccess;
  659. }
  660. bool
  661. CreateSACSessionWinStaAndDesktop(
  662. IN HANDLE hToken,
  663. OUT HWINSTA *hOldWinSta,
  664. OUT HWINSTA *hWinSta,
  665. OUT HDESK *hDesktop,
  666. OUT PWCHAR *winStaName
  667. )
  668. /*++
  669. Routine Description:
  670. This routine creates a window station and desktop pair for
  671. the user logging in. The name of the winsta\desktop pair
  672. is of the form:
  673. SACWinSta<Uuid>\Default
  674. The net result of this behavior is to have a unique window
  675. station for each sacsess. Doing so mitigates any spoofing
  676. security risks.
  677. NOTE: Only Admins (and higher) can create named window
  678. stations, so name squatting is mitigated.
  679. We close the handles to the the window station and desktop
  680. after we are done with them so that when the last session
  681. exits, the winsta and desktop objects get automatically
  682. cleaned up. This prevents us from having to garbage collect.
  683. Arguments:
  684. hToken - the user to grant access to
  685. Return Value:
  686. Status
  687. Security:
  688. interface: console
  689. --*/
  690. {
  691. bool bStatus = FALSE;
  692. BOOL bRetVal = FALSE;
  693. DWORD dwErrCode = 0;
  694. PSID pSidAdministrators = NULL;
  695. PSID pSidUser = NULL;
  696. PSID pSidLocalSystem = NULL;
  697. int aclSize = 0;
  698. ULONG i;
  699. PACL newACL = NULL;
  700. SECURITY_DESCRIPTOR sd;
  701. SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
  702. ACCESS_ALLOWED_ACE *pace = NULL;
  703. SID_IDENTIFIER_AUTHORITY local_system_authority = SECURITY_NT_AUTHORITY;
  704. //
  705. //
  706. //
  707. *hOldWinSta = NULL;
  708. *hWinSta = NULL;
  709. *hDesktop = NULL;
  710. *winStaName = NULL;
  711. //
  712. //
  713. //
  714. *hOldWinSta = GetProcessWindowStation();
  715. if ( !*hOldWinSta )
  716. {
  717. goto ExitOnError;
  718. }
  719. //
  720. // Build administrators alias sid
  721. //
  722. if (! AllocateAndInitializeSid(
  723. &local_system_authority,
  724. 2, /* there are only two sub-authorities */
  725. SECURITY_BUILTIN_DOMAIN_RID,
  726. DOMAIN_ALIAS_RID_ADMINS,
  727. 0,0,0,0,0,0, /* Don't care about the rest */
  728. &pSidAdministrators
  729. ))
  730. {
  731. goto ExitOnError;
  732. }
  733. //Build LocalSystem sid
  734. if (! AllocateAndInitializeSid(
  735. &local_system_authority,
  736. 1, /* there is only two sub-authority */
  737. SECURITY_LOCAL_SYSTEM_RID,
  738. 0,0,0,0,0,0,0, /* Don't care about the rest */
  739. &pSidLocalSystem
  740. ))
  741. {
  742. goto ExitOnError;
  743. }
  744. //
  745. // Get the SID for the client's logon session.
  746. //
  747. if (!GetLogonSID(hToken, &pSidUser)) {
  748. goto ExitOnError;
  749. }
  750. //
  751. // Allocate size for 4 ACEs.
  752. // We need to add one more InheritOnly ACE for the objects that
  753. // get created under the WindowStation.
  754. //
  755. aclSize = sizeof(ACL) +
  756. (4*sizeof(ACCESS_ALLOWED_ACE) - 4*sizeof(DWORD)) +
  757. GetLengthSid(pSidAdministrators) +
  758. 2*GetLengthSid(pSidUser) +
  759. GetLengthSid(pSidLocalSystem);
  760. newACL = (PACL) new BYTE[aclSize];
  761. if (newACL == NULL)
  762. {
  763. goto ExitOnError;
  764. }
  765. //
  766. //
  767. //
  768. if (!InitializeAcl(newACL, aclSize, ACL_REVISION))
  769. {
  770. goto ExitOnError;
  771. }
  772. //
  773. //
  774. //
  775. pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(
  776. GetProcessHeap(),
  777. HEAP_ZERO_MEMORY,
  778. sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(pSidUser) - sizeof(DWORD)
  779. );
  780. if (pace == NULL)
  781. {
  782. goto ExitOnError;
  783. }
  784. //
  785. // Create InheritOnly ACE. The objects ( like Desktop ) that get created
  786. // under the WindowStation, will inherit these security Attributes.
  787. // This is done because we should not allow WRITE_DAC and few other permissions to all users.
  788. //
  789. pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  790. pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
  791. INHERIT_ONLY_ACE |
  792. OBJECT_INHERIT_ACE;
  793. pace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) +
  794. (WORD)GetLengthSid(pSidUser) -
  795. sizeof(DWORD);
  796. pace->Mask = DESKTOP_ALL & ~(WRITE_DAC | WRITE_OWNER | DELETE);
  797. if (!CopySid(GetLengthSid(pSidUser), &pace->SidStart, pSidUser))
  798. {
  799. goto ExitOnError;
  800. }
  801. if (!AddAce(
  802. newACL,
  803. ACL_REVISION,
  804. MAXDWORD,
  805. (LPVOID)pace,
  806. pace->Header.AceSize
  807. ))
  808. {
  809. goto ExitOnError;
  810. }
  811. if (!AddAccessAllowedAce(newACL, ACL_REVISION, WINSTA_ALL | GENERIC_ALL , pSidAdministrators))
  812. {
  813. goto ExitOnError;
  814. }
  815. if (!AddAccessAllowedAce(newACL, ACL_REVISION, WINSTA_ALL | GENERIC_ALL, pSidLocalSystem))
  816. {
  817. goto ExitOnError;
  818. }
  819. if (!AddAccessAllowedAce(newACL,
  820. ACL_REVISION,
  821. WINSTA_ALL & ~(WRITE_DAC | WRITE_OWNER | WINSTA_CREATEDESKTOP | DELETE),
  822. pSidUser
  823. ))
  824. {
  825. goto ExitOnError;
  826. }
  827. if ( !InitializeSecurityDescriptor(&sd, SECURITY_DESCRIPTOR_REVISION ) )
  828. {
  829. goto ExitOnError;
  830. }
  831. if ( !SetSecurityDescriptorDacl(&sd, TRUE, newACL, FALSE) )
  832. {
  833. goto ExitOnError;
  834. }
  835. //
  836. // Each sacsess will have it's own windows station. Overwise there is a
  837. // spoofing security risk. Each windows station has a unique name that
  838. // is generated below. Using this name, we will attempt to create the
  839. // windows station. The first time we successfully create a windowss
  840. // station, break out of the loop. Loop for more then the max
  841. // number of channels to mitigate denial of service because there was
  842. // a windows station opened by service other than us with a name we
  843. // requested.
  844. //
  845. for (i = 0;
  846. (*hWinSta == NULL) && (i < MAX_CHANNEL_COUNT * MAX_CHANNEL_COUNT);
  847. i++) {
  848. //
  849. // Create the windows station name
  850. //
  851. if (BuildSACWinStaName(winStaName))
  852. {
  853. //
  854. // Attempt to create windows station.
  855. //
  856. *hWinSta = CreateWindowStation(
  857. *winStaName,
  858. CWF_CREATE_ONLY,
  859. MAXIMUM_ALLOWED,
  860. NULL
  861. );
  862. }
  863. }
  864. if ( !*hWinSta )
  865. {
  866. goto ExitOnError;
  867. }
  868. if (!SetUserObjectSecurity(*hWinSta,&si,&sd))
  869. {
  870. goto ExitOnError;
  871. }
  872. bRetVal = SetProcessWindowStation( *hWinSta );
  873. if ( !bRetVal )
  874. {
  875. goto ExitOnError;
  876. }
  877. *hDesktop = CreateDesktop(
  878. L"Default",
  879. NULL,
  880. NULL,
  881. 0,
  882. MAXIMUM_ALLOWED,
  883. NULL
  884. );
  885. if ( *hDesktop == NULL )
  886. {
  887. goto ExitOnError;
  888. }
  889. {
  890. PWCHAR temp;
  891. if (!BuildSACWinStaDesktopName(*winStaName,&temp))
  892. {
  893. goto ExitOnError;
  894. }
  895. delete [] *winStaName;
  896. *winStaName = temp;
  897. #if 0
  898. OutputDebugString(L"\n");
  899. OutputDebugString(*winStaName);
  900. OutputDebugString(L"\n");
  901. #endif
  902. }
  903. bStatus = TRUE;
  904. goto Done;
  905. ExitOnError:
  906. dwErrCode = GetLastError();
  907. if (*hOldWinSta)
  908. {
  909. SetProcessWindowStation( *hOldWinSta );
  910. }
  911. if (*hWinSta)
  912. {
  913. CloseWindowStation(*hWinSta);
  914. }
  915. if (*hDesktop)
  916. {
  917. CloseDesktop(*hDesktop);
  918. }
  919. Done:
  920. if ( pSidAdministrators != NULL )
  921. {
  922. FreeSid (pSidAdministrators );
  923. }
  924. if ( pSidLocalSystem!= NULL )
  925. {
  926. FreeSid (pSidLocalSystem);
  927. }
  928. if ( pSidUser!= NULL )
  929. {
  930. FreeLogonSID (&pSidUser);
  931. }
  932. if (newACL)
  933. {
  934. delete [] newACL;
  935. }
  936. if (pace)
  937. {
  938. HeapFree(GetProcessHeap(), 0, (LPVOID)pace);
  939. }
  940. return( bStatus );
  941. }