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.

1042 lines
30 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. All rights reserved
  4. Module Name:
  5. utils.cxx
  6. Abstract:
  7. utils
  8. Author:
  9. Larry Zhu (LZhu) December 1, 2001 Created
  10. Environment:
  11. User Mode -Win32
  12. Revision History:
  13. --*/
  14. #include "precomp.hxx"
  15. #pragma hdrstop
  16. #include "utils.hxx"
  17. #include <Sddl.h>
  18. #define MAXDWORD 0xffffffff
  19. NTSTATUS
  20. CreateUnicodeStringFromAsciiz(
  21. IN PCSZ pszSourceString,
  22. OUT UNICODE_STRING* pDestinationString
  23. )
  24. {
  25. TNtStatus Status;
  26. ANSI_STRING AnsiString;
  27. RtlInitAnsiString( &AnsiString, pszSourceString );
  28. Status DBGCHK = RtlAnsiStringToUnicodeString(
  29. pDestinationString,
  30. &AnsiString,
  31. TRUE
  32. );
  33. return Status;
  34. }
  35. VOID
  36. PackStringAsString32(
  37. IN VOID* pvBufferBase,
  38. IN OUT STRING* pString
  39. )
  40. {
  41. pString->Buffer = (CHAR*) (pString->Buffer - (CHAR*) pvBufferBase);
  42. }
  43. NTSTATUS
  44. CreateString32FromAsciiz(
  45. IN VOID* pvBufferBase,
  46. IN PCSZ pszSourceString,
  47. OUT UNICODE_STRING* pDestinationString
  48. )
  49. {
  50. TNtStatus Status;
  51. Status DBGCHK = CreateUnicodeStringFromAsciiz(pszSourceString, pDestinationString);
  52. if (NT_SUCCESS(Status))
  53. {
  54. PackStringAsString32(pvBufferBase, (STRING*) pDestinationString);
  55. }
  56. return Status;
  57. }
  58. VOID
  59. RelocatePackString(
  60. IN OUT STRING* pString,
  61. IN OUT CHAR** ppWhere
  62. )
  63. {
  64. RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
  65. pString->Buffer = *ppWhere;
  66. *ppWhere += pString->Length;
  67. }
  68. VOID
  69. RelocatePackUnicodeString(
  70. IN UNICODE_STRING* pString,
  71. IN OUT CHAR** ppWhere
  72. )
  73. {
  74. RelocatePackString((STRING*) pString, ppWhere);
  75. }
  76. VOID
  77. PackUnicodeStringAsUnicodeStringZ(
  78. IN UNICODE_STRING* pString,
  79. IN OUT WCHAR** ppWhere,
  80. OUT UNICODE_STRING* pDestString
  81. )
  82. {
  83. RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
  84. pDestString->Buffer = *ppWhere;
  85. pDestString->Length = pString->Length;
  86. pDestString->MaximumLength = pString->Length + sizeof(WCHAR);
  87. *ppWhere += pDestString->MaximumLength / sizeof(WCHAR);
  88. //
  89. // add unicode NULL
  90. //
  91. pDestString->Buffer[(pDestString->MaximumLength / sizeof(WCHAR)) - 1] = UNICODE_NULL;
  92. }
  93. VOID
  94. PackString(
  95. IN STRING* pString,
  96. IN OUT CHAR** ppWhere,
  97. OUT STRING* pDestString
  98. )
  99. {
  100. RtlCopyMemory(*ppWhere, pString->Buffer, pString->Length);
  101. pDestString->Buffer = *ppWhere;
  102. *ppWhere += pString->Length;
  103. pDestString->Length = pString->Length;
  104. pDestString->MaximumLength = pString->Length;
  105. }
  106. VOID
  107. DebugPrintSysTimeAsLocalTime(
  108. IN ULONG ulLevel,
  109. IN PCSTR pszBanner,
  110. IN LARGE_INTEGER* pSysTime
  111. )
  112. {
  113. TNtStatus NtStatus = STATUS_UNSUCCESSFUL;
  114. TIME_FIELDS TimeFields = {0};
  115. LARGE_INTEGER LocalTime = {0};
  116. NtStatus DBGCHK = RtlSystemTimeToLocalTime(pSysTime, &LocalTime);
  117. if (NT_SUCCESS(NtStatus))
  118. {
  119. RtlTimeToTimeFields(&LocalTime, &TimeFields);
  120. DebugPrintf(ulLevel, "%s LocalTime(%ld/%ld/%ld %ld:%2.2ld:%2.2ld) SystemTime(H%8.8lx L%8.8lx)\n",
  121. pszBanner,
  122. TimeFields.Month,
  123. TimeFields.Day,
  124. TimeFields.Year,
  125. TimeFields.Hour,
  126. TimeFields.Minute,
  127. TimeFields.Second,
  128. pSysTime->HighPart,
  129. pSysTime->LowPart);
  130. }
  131. }
  132. VOID
  133. DebugPrintLocalTime(
  134. IN ULONG ulLevel,
  135. IN PCSTR pszBanner,
  136. IN LARGE_INTEGER* pLocalTime
  137. )
  138. {
  139. TIME_FIELDS TimeFields = {0};
  140. RtlTimeToTimeFields(pLocalTime, &TimeFields);
  141. DebugPrintf(ulLevel, "%s LocalTime(%ld/%ld/%ld %ld:%2.2ld:%2.2ld) H%8.8lx L%8.8lx\n",
  142. pszBanner,
  143. TimeFields.Month,
  144. TimeFields.Day,
  145. TimeFields.Year,
  146. TimeFields.Hour,
  147. TimeFields.Minute,
  148. TimeFields.Second,
  149. pLocalTime->HighPart,
  150. pLocalTime->LowPart);
  151. }
  152. #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
  153. #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | STANDARD_RIGHTS_REQUIRED)
  154. #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
  155. HRESULT
  156. StartInteractiveClientProcessAsUser(
  157. IN HANDLE hToken,
  158. IN PTSTR pszCommandLine // command line to execute
  159. )
  160. {
  161. THResult hRetval = E_FAIL;
  162. HANDLE hDup = NULL;
  163. HDESK hdesk = NULL;
  164. HWINSTA hwinsta = NULL;
  165. HWINSTA hwinstaSave = NULL;
  166. PROCESS_INFORMATION pi = {INVALID_HANDLE_VALUE, INVALID_HANDLE_VALUE, 0, 0};
  167. PSID pSid = NULL;
  168. STARTUPINFO si = {0};
  169. HANDLE hSystemToken = NULL;
  170. CHAR TokenUserInfoBuffer[MAX_PATH + sizeof(TOKEN_USER)] = {0}; // MAX_SID_SIZE is 256
  171. TOKEN_USER* pTokenUserInfo = (TOKEN_USER*) TokenUserInfoBuffer;
  172. ULONG cbReturn = 0;
  173. // Save a handle to the caller's current window station.
  174. hwinstaSave = GetProcessWindowStation();
  175. hRetval DBGCHK = hwinstaSave ? S_OK : GetLastErrorAsHResult();
  176. // Get the SID for the client's logon session.
  177. if (SUCCEEDED(hRetval))
  178. {
  179. hRetval DBGCHK = GetLogonSIDOrUserSid(hToken, &pSid) ? S_OK : GetLastErrorAsHResult();
  180. }
  181. // Get a handle to the interactive window station.
  182. if (SUCCEEDED(hRetval))
  183. {
  184. hwinsta = OpenWindowStation(
  185. TEXT("winsta0"), // the interactive window station
  186. FALSE, // handle is not inheritable
  187. MAXIMUM_ALLOWED // rights to read/write the DACL
  188. );
  189. hRetval DBGCHK = hwinsta ? S_OK : GetLastErrorAsHResult();
  190. }
  191. // Allow logon SID full access to interactive window station.
  192. if (SUCCEEDED(hRetval))
  193. {
  194. hRetval DBGCHK = AddAceToWindowStation(hwinsta, pSid) ? S_OK : GetLastErrorAsHResult();
  195. }
  196. // To get the correct default desktop, set the caller's
  197. // window station to the interactive window station.
  198. if (SUCCEEDED(hRetval))
  199. {
  200. hRetval DBGCHK = SetProcessWindowStation(hwinsta) ? S_OK : GetLastErrorAsHResult();
  201. }
  202. // Get a handle to the interactive desktop.
  203. if (SUCCEEDED(hRetval))
  204. {
  205. TImpersonation imper(NULL);
  206. hRetval DBGCHK = imper.Validate();
  207. if (SUCCEEDED(hRetval))
  208. {
  209. hdesk = OpenDesktop(
  210. TEXT("default"), // the interactive window station
  211. 0, // no interaction with other desktop processes
  212. FALSE, // handle is not inheritable
  213. MAXIMUM_ALLOWED
  214. );
  215. hRetval DBGCHK = hdesk ? S_OK : GetLastErrorAsHResult();
  216. }
  217. // Allow logon SID full access to interactive desktop.
  218. if (SUCCEEDED(hRetval))
  219. {
  220. hRetval DBGCHK = AddAceToDesktop(hdesk, pSid) ? S_OK : GetLastErrorAsHResult();
  221. }
  222. }
  223. //
  224. // get the necessary privileges enabled
  225. //
  226. if (SUCCEEDED(hRetval))
  227. {
  228. hRetval DBGCHK = GetSystemToken(&hSystemToken);
  229. }
  230. if (SUCCEEDED(hRetval))
  231. {
  232. TImpersonation imper(hSystemToken);
  233. hRetval DBGCHK = imper.Validate();
  234. // Allow logon SID full access to interactive desktop.
  235. if (SUCCEEDED(hRetval))
  236. {
  237. hRetval DBGCHK = SetThreadDesktop(hdesk) ? S_OK : GetLastErrorAsHResult();
  238. }
  239. if (SUCCEEDED(hRetval))
  240. {
  241. hRetval DBGCHK = GetTokenInformation(
  242. hToken,
  243. TokenUser,
  244. TokenUserInfoBuffer,
  245. sizeof(TokenUserInfoBuffer),
  246. &cbReturn
  247. ) ? S_OK : GetLastErrorAsHResult();
  248. }
  249. // Initialize the STARTUPINFO structure.
  250. // Specify that the process runs in the interactive desktop.
  251. if (SUCCEEDED(hRetval))
  252. {
  253. si.cb = sizeof(STARTUPINFO);
  254. si.lpDesktop = TEXT("winsta0\\default");
  255. hRetval DBGCHK = ConvertSidToStringSid(pTokenUserInfo->User.Sid, &si.lpTitle) ? S_OK : GetLastErrorAsHResult();
  256. }
  257. // Launch the process in the client's logon session.
  258. if (SUCCEEDED(hRetval))
  259. {
  260. DBGCFG1(hRetval, HRESULT_FROM_WIN32(ERROR_BAD_TOKEN_TYPE));
  261. hRetval DBGCHK = CreateProcessAsUser(
  262. hToken, // client's access token
  263. NULL, // file to execute
  264. pszCommandLine, // command line
  265. NULL, // pointer to process SECURITY_ATTRIBUTES
  266. NULL, // pointer to thread SECURITY_ATTRIBUTES
  267. FALSE, // handles are not inheritable
  268. NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags
  269. NULL, // pointer to new environment block
  270. NULL, // name of current directory
  271. &si, // pointer to STARTUPINFO structure
  272. &pi // receives information about new process
  273. ) ? S_OK : GetLastErrorAsHResult();
  274. if (FAILED(hRetval) && (ERROR_BAD_TOKEN_TYPE == HRESULT_CODE(hRetval)))
  275. {
  276. DebugPrintf(SSPI_WARN, "CreateProcessAsUser failed with ERROR_BAD_TOKEN_TYPE\n");
  277. hRetval DBGCHK = DuplicateTokenEx(
  278. hToken,
  279. TOKEN_QUERY | TOKEN_DUPLICATE | TOKEN_ASSIGN_PRIMARY,
  280. NULL,
  281. SecurityImpersonation,
  282. TokenPrimary,
  283. &hDup
  284. ) ? S_OK : GetLastErrorAsHResult();
  285. if (SUCCEEDED(hRetval))
  286. {
  287. hRetval DBGCHK = CreateProcessAsUser(
  288. hDup, // client's access token
  289. NULL, // file to execute
  290. pszCommandLine, // command line
  291. NULL, // pointer to process SECURITY_ATTRIBUTES
  292. NULL, // pointer to thread SECURITY_ATTRIBUTES
  293. FALSE, // handles are not inheritable
  294. NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags
  295. NULL, // pointer to new environment block
  296. NULL, // name of current directory
  297. &si, // pointer to STARTUPINFO structure
  298. &pi // receives information about new process
  299. ) ? S_OK : GetLastErrorAsHResult();
  300. }
  301. }
  302. }
  303. if (SUCCEEDED(hRetval))
  304. {
  305. SspiPrint(SSPI_LOG, TEXT("StartInteractiveClientProcessAsUser succeeded: process id %d(%#x), user is %s, pszCommandLine \"%s\"\n"), pi.dwProcessId, pi.dwProcessId, si.lpTitle, pszCommandLine);
  306. }
  307. if (si.lpTitle)
  308. {
  309. LocalFree(si.lpTitle);
  310. }
  311. }
  312. THResult hr;
  313. // Restore the caller's window station.
  314. if (hwinstaSave)
  315. {
  316. hr DBGCHK = SetProcessWindowStation(hwinstaSave) ? S_OK : GetLastErrorAsHResult();
  317. hr DBGCHK = CloseWindowStation(hwinstaSave) ? S_OK : GetLastErrorAsHResult();
  318. }
  319. if (hDup)
  320. {
  321. hr DBGCHK = CloseHandle(hDup) ? S_OK : GetLastErrorAsHResult();
  322. }
  323. if (hSystemToken)
  324. {
  325. hr DBGCHK = CloseHandle(hSystemToken) ? S_OK : GetLastErrorAsHResult();
  326. }
  327. if (pi.hProcess != INVALID_HANDLE_VALUE)
  328. {
  329. // WaitForSingleObject(pi.hProcess, INFINITE);
  330. hr DBGCHK = CloseHandle(pi.hProcess) ? S_OK : GetLastErrorAsHResult();
  331. }
  332. if (pi.hThread != INVALID_HANDLE_VALUE)
  333. {
  334. hr DBGCHK = CloseHandle(pi.hThread) ? S_OK : GetLastErrorAsHResult();
  335. }
  336. // Close the handles to the interactive window station and desktop.
  337. if (hwinsta)
  338. {
  339. hr DBGCHK = CloseWindowStation(hwinsta) ? S_OK : GetLastErrorAsHResult();
  340. }
  341. if (hdesk)
  342. {
  343. DBGCFG1(hr, HRESULT_FROM_WIN32(ERROR_BUSY));
  344. hr DBGCHK = CloseDesktop(hdesk) ? S_OK : GetLastErrorAsHResult();
  345. }
  346. // Free the buffer for the logon SID.
  347. if (pSid)
  348. {
  349. FreeLogonSID(&pSid);
  350. }
  351. return hRetval;
  352. }
  353. BOOL AddAceToWindowStation(IN HWINSTA hwinsta, IN PSID psid)
  354. {
  355. ACCESS_ALLOWED_ACE *pace;
  356. ACL_SIZE_INFORMATION aclSizeInfo;
  357. BOOL bDaclExist;
  358. BOOL bDaclPresent;
  359. BOOL bSuccess = FALSE;
  360. DWORD dwNewAclSize;
  361. DWORD dwSidSize = 0;
  362. DWORD dwSdSizeNeeded;
  363. PACL pacl;
  364. PACL pNewAcl;
  365. PSECURITY_DESCRIPTOR psd = NULL;
  366. PSECURITY_DESCRIPTOR psdNew = NULL;
  367. PVOID pTempAce;
  368. SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
  369. unsigned int i;
  370. __try
  371. {
  372. // Obtain the DACL for the window station.
  373. if (!GetUserObjectSecurity(
  374. hwinsta,
  375. &si,
  376. psd,
  377. dwSidSize,
  378. &dwSdSizeNeeded))
  379. {
  380. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  381. {
  382. psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
  383. GetProcessHeap(),
  384. HEAP_ZERO_MEMORY,
  385. dwSdSizeNeeded);
  386. if (psd == NULL)
  387. __leave;
  388. psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
  389. GetProcessHeap(),
  390. HEAP_ZERO_MEMORY,
  391. dwSdSizeNeeded);
  392. if (psdNew == NULL)
  393. __leave;
  394. dwSidSize = dwSdSizeNeeded;
  395. if (!GetUserObjectSecurity(
  396. hwinsta,
  397. &si,
  398. psd,
  399. dwSidSize,
  400. &dwSdSizeNeeded))
  401. __leave;
  402. }
  403. else
  404. __leave;
  405. }
  406. // Create a new DACL.
  407. if (!InitializeSecurityDescriptor(
  408. psdNew,
  409. SECURITY_DESCRIPTOR_REVISION))
  410. __leave;
  411. // Get the DACL from the security descriptor.
  412. if (!GetSecurityDescriptorDacl(
  413. psd,
  414. &bDaclPresent,
  415. &pacl,
  416. &bDaclExist))
  417. __leave;
  418. // Initialize the ACL.
  419. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
  420. aclSizeInfo.AclBytesInUse = sizeof(ACL);
  421. // Call only if the DACL is not NULL.
  422. if (pacl != NULL)
  423. {
  424. // get the file ACL size info
  425. if (!GetAclInformation(
  426. pacl,
  427. (PVOID)&aclSizeInfo,
  428. sizeof(ACL_SIZE_INFORMATION),
  429. AclSizeInformation))
  430. __leave;
  431. }
  432. // Compute the size of the new ACL.
  433. dwNewAclSize = aclSizeInfo.AclBytesInUse + (2 * sizeof(ACCESS_ALLOWED_ACE))
  434. + (2 * GetLengthSid(psid)) - (2 * sizeof(DWORD));
  435. // Allocate memory for the new ACL.
  436. pNewAcl = (PACL)HeapAlloc(
  437. GetProcessHeap(),
  438. HEAP_ZERO_MEMORY,
  439. dwNewAclSize);
  440. if (pNewAcl == NULL)
  441. __leave;
  442. // Initialize the new DACL.
  443. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
  444. __leave;
  445. // If DACL is present, copy it to a new DACL.
  446. if (bDaclPresent)
  447. {
  448. // Copy the ACEs to the new ACL.
  449. if (aclSizeInfo.AceCount)
  450. {
  451. for (i=0; i < aclSizeInfo.AceCount; i++)
  452. {
  453. // Get an ACE.
  454. if (!GetAce(pacl, i, &pTempAce))
  455. __leave;
  456. // Add the ACE to the new ACL.
  457. if (!AddAce(
  458. pNewAcl,
  459. ACL_REVISION,
  460. MAXDWORD,
  461. pTempAce,
  462. ((PACE_HEADER)pTempAce)->AceSize))
  463. __leave;
  464. }
  465. }
  466. }
  467. // Add the first ACE to the window station.
  468. pace = (ACCESS_ALLOWED_ACE *)HeapAlloc(
  469. GetProcessHeap(),
  470. HEAP_ZERO_MEMORY,
  471. sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(psid) -
  472. sizeof(DWORD));
  473. if (pace == NULL)
  474. __leave;
  475. pace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
  476. pace->Header.AceFlags = CONTAINER_INHERIT_ACE |
  477. INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
  478. pace->Header.AceSize = (USHORT) (sizeof(ACCESS_ALLOWED_ACE) +
  479. GetLengthSid(psid) - sizeof(DWORD));
  480. pace->Mask = GENERIC_ACCESS;
  481. if (!CopySid(GetLengthSid(psid), &pace->SidStart, psid))
  482. __leave;
  483. if (!AddAce(
  484. pNewAcl,
  485. ACL_REVISION,
  486. MAXDWORD,
  487. (PVOID)pace,
  488. pace->Header.AceSize))
  489. __leave;
  490. // Add the second ACE to the window station.
  491. pace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
  492. pace->Mask = WINSTA_ALL;
  493. if (!AddAce(
  494. pNewAcl,
  495. ACL_REVISION,
  496. MAXDWORD,
  497. (PVOID)pace,
  498. pace->Header.AceSize))
  499. __leave;
  500. // Set a new DACL for the security descriptor.
  501. if (!SetSecurityDescriptorDacl(
  502. psdNew,
  503. TRUE,
  504. pNewAcl,
  505. FALSE))
  506. __leave;
  507. // Set the new security descriptor for the window station.
  508. if (!SetUserObjectSecurity(hwinsta, &si, psdNew))
  509. __leave;
  510. // Indicate success.
  511. bSuccess = TRUE;
  512. }
  513. __finally
  514. {
  515. // Free the allocated buffers.
  516. if (pace != NULL)
  517. HeapFree(GetProcessHeap(), 0, (PVOID)pace);
  518. if (pNewAcl != NULL)
  519. HeapFree(GetProcessHeap(), 0, (PVOID)pNewAcl);
  520. if (psd != NULL)
  521. HeapFree(GetProcessHeap(), 0, (PVOID)psd);
  522. if (psdNew != NULL)
  523. HeapFree(GetProcessHeap(), 0, (PVOID)psdNew);
  524. }
  525. return bSuccess;
  526. }
  527. BOOL AddAceToDesktop(IN HDESK hdesk, IN PSID psid)
  528. {
  529. ACL_SIZE_INFORMATION aclSizeInfo;
  530. BOOL bDaclExist;
  531. BOOL bDaclPresent;
  532. BOOL bSuccess = FALSE;
  533. DWORD dwNewAclSize;
  534. DWORD dwSidSize = 0;
  535. DWORD dwSdSizeNeeded;
  536. PACL pacl;
  537. PACL pNewAcl;
  538. PSECURITY_DESCRIPTOR psd = NULL;
  539. PSECURITY_DESCRIPTOR psdNew = NULL;
  540. PVOID pTempAce;
  541. SECURITY_INFORMATION si = DACL_SECURITY_INFORMATION;
  542. unsigned int i;
  543. __try
  544. {
  545. // Obtain the security descriptor for the desktop object.
  546. if (!GetUserObjectSecurity(
  547. hdesk,
  548. &si,
  549. psd,
  550. dwSidSize,
  551. &dwSdSizeNeeded))
  552. {
  553. if (GetLastError() == ERROR_INSUFFICIENT_BUFFER)
  554. {
  555. psd = (PSECURITY_DESCRIPTOR)HeapAlloc(
  556. GetProcessHeap(),
  557. HEAP_ZERO_MEMORY,
  558. dwSdSizeNeeded );
  559. if (psd == NULL)
  560. __leave;
  561. psdNew = (PSECURITY_DESCRIPTOR)HeapAlloc(
  562. GetProcessHeap(),
  563. HEAP_ZERO_MEMORY,
  564. dwSdSizeNeeded);
  565. if (psdNew == NULL)
  566. __leave;
  567. dwSidSize = dwSdSizeNeeded;
  568. if (!GetUserObjectSecurity(
  569. hdesk,
  570. &si,
  571. psd,
  572. dwSidSize,
  573. &dwSdSizeNeeded))
  574. __leave;
  575. }
  576. else
  577. __leave;
  578. }
  579. // Create a new security descriptor.
  580. if (!InitializeSecurityDescriptor(
  581. psdNew,
  582. SECURITY_DESCRIPTOR_REVISION))
  583. __leave;
  584. // Obtain the DACL from the security descriptor.
  585. if (!GetSecurityDescriptorDacl(
  586. psd,
  587. &bDaclPresent,
  588. &pacl,
  589. &bDaclExist))
  590. __leave;
  591. // Initialize.
  592. ZeroMemory(&aclSizeInfo, sizeof(ACL_SIZE_INFORMATION));
  593. aclSizeInfo.AclBytesInUse = sizeof(ACL);
  594. // Call only if NULL DACL.
  595. if (pacl != NULL)
  596. {
  597. // Determine the size of the ACL information.
  598. if (!GetAclInformation(
  599. pacl,
  600. (PVOID)&aclSizeInfo,
  601. sizeof(ACL_SIZE_INFORMATION),
  602. AclSizeInformation))
  603. __leave;
  604. }
  605. // Compute the size of the new ACL.
  606. dwNewAclSize = aclSizeInfo.AclBytesInUse +
  607. sizeof(ACCESS_ALLOWED_ACE) +
  608. GetLengthSid(psid) - sizeof(DWORD);
  609. // Allocate buffer for the new ACL.
  610. pNewAcl = (PACL)HeapAlloc(
  611. GetProcessHeap(),
  612. HEAP_ZERO_MEMORY,
  613. dwNewAclSize);
  614. if (pNewAcl == NULL)
  615. __leave;
  616. // Initialize the new ACL.
  617. if (!InitializeAcl(pNewAcl, dwNewAclSize, ACL_REVISION))
  618. __leave;
  619. // If DACL is present, copy it to a new DACL.
  620. if (bDaclPresent)
  621. {
  622. // Copy the ACEs to the new ACL.
  623. if (aclSizeInfo.AceCount)
  624. {
  625. for (i=0; i < aclSizeInfo.AceCount; i++)
  626. {
  627. // Get an ACE.
  628. if (!GetAce(pacl, i, &pTempAce))
  629. __leave;
  630. // Add the ACE to the new ACL.
  631. if (!AddAce(
  632. pNewAcl,
  633. ACL_REVISION,
  634. MAXDWORD,
  635. pTempAce,
  636. ((PACE_HEADER)pTempAce)->AceSize))
  637. __leave;
  638. }
  639. }
  640. }
  641. // Add ACE to the DACL.
  642. if (!AddAccessAllowedAce(
  643. pNewAcl,
  644. ACL_REVISION,
  645. DESKTOP_ALL,
  646. psid))
  647. __leave;
  648. // Set new DACL to the new security descriptor.
  649. if (!SetSecurityDescriptorDacl(
  650. psdNew,
  651. TRUE,
  652. pNewAcl,
  653. FALSE))
  654. __leave;
  655. // Set the new security descriptor for the desktop object.
  656. if (!SetUserObjectSecurity(hdesk, &si, psdNew))
  657. __leave;
  658. // Indicate success.
  659. bSuccess = TRUE;
  660. }
  661. __finally
  662. {
  663. // Free buffers.
  664. if (pNewAcl != NULL)
  665. HeapFree(GetProcessHeap(), 0, (PVOID)pNewAcl);
  666. if (psd != NULL)
  667. HeapFree(GetProcessHeap(), 0, (PVOID)psd);
  668. if (psdNew != NULL)
  669. HeapFree(GetProcessHeap(), 0, (PVOID)psdNew);
  670. }
  671. return bSuccess;
  672. }
  673. BOOL GetLogonSIDOrUserSid(IN HANDLE hToken, OUT PSID *ppsid)
  674. {
  675. BOOL bSuccess = FALSE;
  676. DWORD dwIndex;
  677. DWORD dwLength = 0;
  678. PTOKEN_GROUPS ptg = NULL;
  679. *ppsid = NULL;
  680. // Get required buffer size and allocate the TOKEN_GROUPS buffer.
  681. if (!GetTokenInformation(
  682. hToken, // handle to the access token
  683. TokenGroups, // get information about the token's groups
  684. (PVOID) ptg, // pointer to TOKEN_GROUPS buffer
  685. 0, // size of buffer
  686. &dwLength // receives required buffer size
  687. ))
  688. {
  689. if (GetLastError() != ERROR_INSUFFICIENT_BUFFER)
  690. goto Cleanup;
  691. ptg = (PTOKEN_GROUPS)HeapAlloc(GetProcessHeap(),
  692. HEAP_ZERO_MEMORY, dwLength);
  693. if (ptg == NULL)
  694. goto Cleanup;
  695. }
  696. // Get the token group information from the access token.
  697. if (!GetTokenInformation(
  698. hToken, // handle to the access token
  699. TokenGroups, // get information about the token's groups
  700. (PVOID) ptg, // pointer to TOKEN_GROUPS buffer
  701. dwLength, // size of buffer
  702. &dwLength // receives required buffer size
  703. ))
  704. {
  705. goto Cleanup;
  706. }
  707. // Loop through the groups to find the logon SID.
  708. for (dwIndex = 0; dwIndex < ptg->GroupCount; dwIndex++)
  709. if (0 != (ptg->Groups[dwIndex].Attributes & SE_GROUP_LOGON_ID))
  710. {
  711. // Found the logon SID; make a copy of it.
  712. dwLength = GetLengthSid(ptg->Groups[dwIndex].Sid);
  713. *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
  714. HEAP_ZERO_MEMORY, dwLength);
  715. if (*ppsid == NULL)
  716. goto Cleanup;
  717. if (!CopySid(dwLength, *ppsid, ptg->Groups[dwIndex].Sid))
  718. {
  719. HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
  720. goto Cleanup;
  721. }
  722. break;
  723. }
  724. if (NULL == *ppsid)
  725. {
  726. ULONG cbUserInfo;
  727. PUCHAR pnSubAuthorityCount = 0;
  728. CHAR UserInfoBuffer[4096] = {0};
  729. PTOKEN_USER pUserInfo = (PTOKEN_USER) UserInfoBuffer;
  730. SspiPrint(SSPI_WARN, TEXT("GetLogonSIDOrUserSid failed to find logon id, trying user sid\n"));
  731. if (!GetTokenInformation(
  732. hToken,
  733. TokenUser,
  734. UserInfoBuffer,
  735. sizeof(UserInfoBuffer),
  736. &cbUserInfo
  737. ))
  738. {
  739. goto Cleanup;
  740. }
  741. if (!IsValidSid(pUserInfo->User.Sid)) goto Cleanup;
  742. pnSubAuthorityCount = GetSidSubAuthorityCount(pUserInfo->User.Sid);
  743. dwLength = GetSidLengthRequired(*pnSubAuthorityCount);
  744. *ppsid = (PSID) HeapAlloc(GetProcessHeap(),
  745. HEAP_ZERO_MEMORY, dwLength);
  746. if (*ppsid == NULL)
  747. goto Cleanup;
  748. if (!CopySid(dwLength, *ppsid, pUserInfo->User.Sid))
  749. {
  750. HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
  751. goto Cleanup;
  752. }
  753. }
  754. bSuccess = TRUE;
  755. Cleanup:
  756. // Free the buffer for the token groups.
  757. if (ptg != NULL)
  758. HeapFree(GetProcessHeap(), 0, (PVOID)ptg);
  759. return bSuccess;
  760. }
  761. VOID FreeLogonSID(IN PSID *ppsid)
  762. {
  763. HeapFree(GetProcessHeap(), 0, (PVOID)*ppsid);
  764. }
  765. /**
  766. This function builds a Dacl which grants the creator of the objects
  767. FILE_ALL_ACCESS and Everyone FILE_GENERIC_READ and FILE_GENERIC_WRITE
  768. access to the object.
  769. This Dacl allows for higher security than a NULL Dacl, which is common for
  770. named-pipes, as this only grants the creator/owner write access to the
  771. security descriptor, and grants Everyone the ability to "use" the named-pipe.
  772. This scenario prevents a malevolent user from disrupting service by preventing
  773. arbitrary access manipulation.
  774. **/
  775. BOOL
  776. BuildNamedPipeAcl(
  777. IN OUT PACL pAcl,
  778. OUT PDWORD pcbAclSize
  779. )
  780. {
  781. DWORD cbAclSize = 0;
  782. SID_IDENTIFIER_AUTHORITY siaWorld = SECURITY_WORLD_SID_AUTHORITY;
  783. SID_IDENTIFIER_AUTHORITY siaCreator = SECURITY_CREATOR_SID_AUTHORITY;
  784. BYTE BufEveryoneSid[32] = {0};
  785. BYTE BufOwnerSid[32] = {0};
  786. PSID pEveryoneSid = (PSID)BufEveryoneSid;
  787. PSID pOwnerSid = (PSID)BufOwnerSid;
  788. //
  789. // compute size of acl
  790. //
  791. cbAclSize = sizeof(ACL) + 2 * ( sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD) )
  792. + GetSidLengthRequired( 1 ) // well-known Everyone Sid
  793. + GetSidLengthRequired( 1 ) ; // well-known Creator Owner Sid
  794. if (*pcbAclSize < cbAclSize)
  795. {
  796. *pcbAclSize = cbAclSize;
  797. return FALSE;
  798. }
  799. *pcbAclSize = cbAclSize;
  800. //
  801. // intialize well known sids
  802. //
  803. if (!InitializeSid(pEveryoneSid, &siaWorld, 1)) return FALSE;
  804. *GetSidSubAuthority(pEveryoneSid, 0) = SECURITY_WORLD_RID;
  805. if (!InitializeSid(pOwnerSid, &siaCreator, 1)) return FALSE;
  806. *GetSidSubAuthority(pOwnerSid, 0) = SECURITY_CREATOR_OWNER_RID;
  807. if (!InitializeAcl(pAcl, cbAclSize, ACL_REVISION))
  808. return FALSE;
  809. if (!AddAccessAllowedAce(
  810. pAcl,
  811. ACL_REVISION,
  812. FILE_GENERIC_READ | FILE_GENERIC_WRITE,
  813. pEveryoneSid
  814. ))
  815. return FALSE;
  816. return AddAccessAllowedAce(
  817. pAcl,
  818. ACL_REVISION,
  819. FILE_ALL_ACCESS,
  820. pOwnerSid
  821. );
  822. }