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.

908 lines
28 KiB

  1. /**************************** Module Header ********************************\
  2. * Module Name: security.c
  3. *
  4. * Copyright (c) 1985 - 1999, Microsoft Corporation
  5. *
  6. * Securable Object Routines
  7. *
  8. * History:
  9. * 12-31-90 JimA Created.
  10. * 04-14-92 RichardW Changed ACE_HEADER
  11. \***************************************************************************/
  12. #define _SECURITY 1
  13. #include "precomp.h"
  14. #pragma hdrstop
  15. #pragma alloc_text(INIT, InitSecurity)
  16. /*
  17. * General security stuff
  18. */
  19. PSECURITY_DESCRIPTOR gpsdInitWinSta;
  20. PRIVILEGE_SET psTcb = { 1, PRIVILEGE_SET_ALL_NECESSARY,
  21. { SE_TCB_PRIVILEGE, 0 }
  22. };
  23. /***************************************************************************\
  24. * AllocAce
  25. *
  26. * Allocates and initializes an ACE list.
  27. *
  28. * History:
  29. * 04-25-91 JimA Created.
  30. \***************************************************************************/
  31. PACCESS_ALLOWED_ACE AllocAce(
  32. PACCESS_ALLOWED_ACE pace,
  33. BYTE bType,
  34. BYTE bFlags,
  35. ACCESS_MASK am,
  36. PSID psid,
  37. LPDWORD lpdwLength)
  38. {
  39. PACCESS_ALLOWED_ACE paceNew;
  40. DWORD iEnd;
  41. DWORD dwLength, dwLengthSid;
  42. /*
  43. * Allocate space for the ACE.
  44. */
  45. dwLengthSid = RtlLengthSid(psid);
  46. dwLength = dwLengthSid + sizeof(ACE_HEADER) + sizeof(ACCESS_MASK);
  47. if (pace == NULL) {
  48. iEnd = 0;
  49. pace = UserAllocPoolWithQuota(dwLength, TAG_SECURITY);
  50. if (pace == NULL)
  51. return NULL;
  52. } else {
  53. iEnd = *lpdwLength;
  54. paceNew = UserAllocPoolWithQuota(iEnd + dwLength, TAG_SECURITY);
  55. if (paceNew == NULL)
  56. return NULL;
  57. RtlCopyMemory(paceNew, pace, iEnd);
  58. UserFreePool(pace);
  59. pace = paceNew;
  60. }
  61. *lpdwLength = dwLength + iEnd;
  62. /*
  63. * Insert the new ACE.
  64. */
  65. paceNew = (PACCESS_ALLOWED_ACE)((PBYTE)pace + iEnd);
  66. paceNew->Header.AceType = bType;
  67. paceNew->Header.AceSize = (USHORT)dwLength;
  68. paceNew->Header.AceFlags = bFlags;
  69. paceNew->Mask = am;
  70. RtlCopySid(dwLengthSid, &paceNew->SidStart, psid);
  71. return pace;
  72. }
  73. /***************************************************************************\
  74. * CreateSecurityDescriptor
  75. *
  76. * Allocates and initializes a security descriptor.
  77. *
  78. * History:
  79. * 04-25-91 JimA Created.
  80. \***************************************************************************/
  81. PSECURITY_DESCRIPTOR CreateSecurityDescriptor(
  82. PACCESS_ALLOWED_ACE paceList,
  83. DWORD cbAce,
  84. BOOLEAN fDaclDefaulted)
  85. {
  86. PSECURITY_DESCRIPTOR psd;
  87. PACL pacl;
  88. NTSTATUS Status;
  89. /*
  90. * Allocate the security descriptor
  91. */
  92. psd = (PSECURITY_DESCRIPTOR)UserAllocPoolWithQuota(
  93. cbAce + sizeof(ACL) + SECURITY_DESCRIPTOR_MIN_LENGTH,
  94. TAG_SECURITY);
  95. if (psd == NULL)
  96. return NULL;
  97. RtlCreateSecurityDescriptor(psd, SECURITY_DESCRIPTOR_REVISION);
  98. /*
  99. * Initialize the ACL
  100. */
  101. pacl = (PACL)((PBYTE)psd + SECURITY_DESCRIPTOR_MIN_LENGTH);
  102. Status = RtlCreateAcl(pacl, sizeof(ACL) + cbAce, ACL_REVISION);
  103. if (NT_SUCCESS(Status)) {
  104. /*
  105. * Add the ACEs to the ACL.
  106. */
  107. Status = RtlAddAce(pacl, ACL_REVISION, MAXULONG, paceList, cbAce);
  108. if (NT_SUCCESS(Status)) {
  109. /*
  110. * Initialize the SD
  111. */
  112. Status = RtlSetDaclSecurityDescriptor(psd, (BOOLEAN)TRUE,
  113. pacl, fDaclDefaulted);
  114. RtlSetSaclSecurityDescriptor(psd, (BOOLEAN)FALSE, NULL,
  115. (BOOLEAN)FALSE);
  116. RtlSetOwnerSecurityDescriptor(psd, NULL, (BOOLEAN)FALSE);
  117. RtlSetGroupSecurityDescriptor(psd, NULL, (BOOLEAN)FALSE);
  118. }
  119. }
  120. if (!NT_SUCCESS(Status)) {
  121. UserFreePool(psd);
  122. return NULL;
  123. }
  124. return psd;
  125. }
  126. /***************************************************************************\
  127. * InitSecurity
  128. *
  129. * Initialize global security information.
  130. *
  131. * History:
  132. * 01-29-91 JimA Created.
  133. \***************************************************************************/
  134. BOOL InitSecurity(
  135. VOID)
  136. {
  137. PACCESS_ALLOWED_ACE paceList = NULL, pace;
  138. DWORD dwLength;
  139. /*
  140. * Create ACE list.
  141. */
  142. paceList = AllocAce(NULL,
  143. ACCESS_ALLOWED_ACE_TYPE,
  144. CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE,
  145. WinStaMapping.GenericAll,
  146. SeExports->SeWorldSid,
  147. &dwLength);
  148. if (paceList == NULL)
  149. return FALSE;
  150. pace = AllocAce(paceList,
  151. ACCESS_ALLOWED_ACE_TYPE,
  152. CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | NO_PROPAGATE_INHERIT_ACE,
  153. WinStaMapping.GenericAll,
  154. SeExports->SeRestrictedSid,
  155. &dwLength);
  156. if (pace == NULL) {
  157. UserFreePool(paceList);
  158. return FALSE;
  159. }
  160. paceList = pace;
  161. pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE,
  162. OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE,
  163. GENERIC_ALL, SeExports->SeWorldSid, &dwLength);
  164. if (pace == NULL) {
  165. UserFreePool(paceList);
  166. return FALSE;
  167. }
  168. paceList = pace;
  169. pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE,
  170. OBJECT_INHERIT_ACE | INHERIT_ONLY_ACE,
  171. GENERIC_ALL, SeExports->SeRestrictedSid, &dwLength);
  172. if (pace == NULL) {
  173. UserFreePool(paceList);
  174. return FALSE;
  175. }
  176. paceList = pace;
  177. pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE,
  178. 0, DIRECTORY_QUERY | DIRECTORY_CREATE_OBJECT,
  179. SeExports->SeAliasAdminsSid, &dwLength);
  180. if (pace == NULL) {
  181. UserFreePool(paceList);
  182. return FALSE;
  183. }
  184. paceList = pace;
  185. pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE,
  186. 0, DIRECTORY_TRAVERSE, SeExports->SeWorldSid, &dwLength);
  187. if (pace == NULL) {
  188. UserFreePool(paceList);
  189. return FALSE;
  190. }
  191. paceList = pace;
  192. pace = AllocAce(paceList, ACCESS_ALLOWED_ACE_TYPE,
  193. 0, DIRECTORY_TRAVERSE, SeExports->SeRestrictedSid, &dwLength);
  194. if (pace == NULL) {
  195. UserFreePool(paceList);
  196. return FALSE;
  197. }
  198. paceList = pace;
  199. /*
  200. * Create the SD
  201. */
  202. gpsdInitWinSta = CreateSecurityDescriptor(paceList, dwLength, FALSE);
  203. UserFreePool(paceList);
  204. if (gpsdInitWinSta == NULL) {
  205. RIPMSG0(RIP_WARNING, "Initial windowstation security was not created!");
  206. }
  207. return (BOOL)(gpsdInitWinSta != NULL);
  208. }
  209. /***************************************************************************\
  210. * TestForInteractiveUser
  211. *
  212. * Returns STATUS_SUCCESS if the LUID passed represents an
  213. * interactiveUser user logged on by winlogon, otherwise FALSE
  214. *
  215. * History:
  216. * 03-08-95 JimA Created.
  217. \***************************************************************************/
  218. NTSTATUS
  219. TestForInteractiveUser(
  220. PLUID pluidCaller
  221. )
  222. {
  223. PWINDOWSTATION pwinsta;
  224. UserAssert(grpWinStaList != NULL);
  225. /*
  226. * !!!
  227. *
  228. * This relies on the fact that there is only ONE interactive
  229. * windowstation and that it is the first one in the list.
  230. * If multiple windowstations are ever supported
  231. * a lookup will have to be done here.
  232. */
  233. pwinsta = grpWinStaList;
  234. /*
  235. * Compare it with the id of the logged on user.
  236. */
  237. if (RtlEqualLuid(pluidCaller, &pwinsta->luidUser))
  238. return STATUS_SUCCESS;
  239. else
  240. return STATUS_ACCESS_DENIED;
  241. }
  242. /***************************************************************************\
  243. * _UserTestForWinStaAccess
  244. *
  245. * Returns STATUS_SUCCESS if the current user has GENERIC_EXECUTE access on
  246. * WindowStation pstrWinSta
  247. *
  248. *
  249. * History:
  250. * 06-05-96 Created SalimC
  251. * 01-02-02 Modified Mohamed Changed pstrWinSta to be a kernel mode address
  252. * and later copied to a dynamically allocated
  253. * user mode address.
  254. \***************************************************************************/
  255. NTSTATUS
  256. _UserTestForWinStaAccess(
  257. PUNICODE_STRING pstrWinSta,
  258. BOOL fInherit
  259. )
  260. {
  261. PTOKEN_STATISTICS pStats;
  262. ULONG BytesRequired;
  263. PWINDOWSTATION pwinsta;
  264. HWINSTA hwsta = NULL;
  265. POBJECT_ATTRIBUTES pObjAttr = NULL;
  266. PUNICODE_STRING pstrStatic;
  267. NTSTATUS Status = STATUS_SUCCESS;
  268. SIZE_T cbObjA;
  269. UNICODE_STRING strDefWinSta;
  270. HANDLE htoken;
  271. BOOLEAN fDefWinSta;
  272. CheckCritIn();
  273. /*
  274. * If we are testing against Default WindowStation (WinSta0) retreive
  275. * pwinsta from the top of the grpwinstaList instead of doing an
  276. * _OpenWindowStation.
  277. *
  278. * NOTE: This relies on the fact that there is only ONE interactive
  279. * windowstation and that it is the first one in the list. If multiple
  280. * windowstations are ever supported a lookup will have to be done
  281. * instead.
  282. */
  283. RtlInitUnicodeString(&strDefWinSta, DEFAULT_WINSTA);
  284. fDefWinSta = RtlEqualUnicodeString(pstrWinSta, &strDefWinSta, TRUE);
  285. if (fDefWinSta) {
  286. if (!NT_SUCCESS(Status = OpenEffectiveToken(&htoken))) {
  287. return Status;
  288. }
  289. Status = ZwQueryInformationToken(htoken,
  290. TokenStatistics,
  291. NULL,
  292. 0,
  293. &BytesRequired);
  294. if (Status != STATUS_BUFFER_TOO_SMALL) {
  295. ZwClose(htoken);
  296. return Status;
  297. }
  298. //
  299. // Allocate space for the user info
  300. //
  301. pStats = (PTOKEN_STATISTICS)UserAllocPoolWithQuota(BytesRequired, TAG_SECURITY);
  302. if (pStats == NULL) {
  303. Status = STATUS_NO_MEMORY;
  304. ZwClose(htoken);
  305. return Status;
  306. }
  307. //
  308. // Read in the user info
  309. //
  310. Status = ZwQueryInformationToken(htoken,
  311. TokenStatistics,
  312. pStats,
  313. BytesRequired,
  314. &BytesRequired);
  315. if (!NT_SUCCESS(Status)) {
  316. ZwClose(htoken);
  317. UserFreePool(pStats);
  318. return Status;
  319. }
  320. /*
  321. * Make sure that current process has access to this window station
  322. */
  323. Status = STATUS_ACCESS_DENIED;
  324. if (grpWinStaList != NULL) {
  325. /*
  326. * !!!
  327. *
  328. * This relies on the fact that there is only ONE interactive
  329. * windowstation and that it is the first one in the list.
  330. * If multiple windowstations are ever supported
  331. * a lookup will have to be done here.
  332. */
  333. pwinsta = grpWinStaList;
  334. /*
  335. * For now we will just do the user luid test till we figure out
  336. * what fInherit means for a Multi-User system
  337. */
  338. if (fInherit) {
  339. if ( (RtlEqualLuid(&pStats->AuthenticationId, &pwinsta->luidUser)) ||
  340. (RtlEqualLuid(&pStats->AuthenticationId, &luidSystem)) ||
  341. (AccessCheckObject(pwinsta, GENERIC_EXECUTE, UserMode, &WinStaMapping)) ) {
  342. Status = STATUS_SUCCESS;
  343. }
  344. } else {
  345. /* Bug 42905. Service Controller clears the flag
  346. * ScStartupInfo.dwFlags &= (~STARTF_DESKTOPINHERIT) to make services
  347. * running under the context of system non-interactive. Hence if fInherit
  348. * is false don't do the SystemLuid and AccessCheckObject tests.
  349. */
  350. if (RtlEqualLuid(&pStats->AuthenticationId, &pwinsta->luidUser)) {
  351. Status = STATUS_SUCCESS;
  352. }
  353. }
  354. }
  355. ZwClose(htoken);
  356. UserFreePool(pStats);
  357. return Status;
  358. }
  359. /*
  360. * Since we don't have a pointer to the WindowStation Object we will do
  361. * a _OpenWindowStation() to make sure we have the desired access.
  362. */
  363. cbObjA = sizeof(*pObjAttr) + sizeof(*pstrStatic) + STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  364. Status = ZwAllocateVirtualMemory(NtCurrentProcess(),
  365. &pObjAttr, 0, &cbObjA, MEM_COMMIT, PAGE_READWRITE);
  366. pstrStatic = (PUNICODE_STRING)((PBYTE)pObjAttr + sizeof(*pObjAttr));
  367. if (NT_SUCCESS(Status)) {
  368. /*
  369. * Note -- the string must be in client-space or the address
  370. * validation in _OpenWindowStation will fail.
  371. */
  372. try {
  373. pstrStatic->Length = 0;
  374. pstrStatic->MaximumLength = STATIC_UNICODE_BUFFER_LENGTH * sizeof(WCHAR);
  375. pstrStatic->Buffer = (PWSTR)((PBYTE)pstrStatic + sizeof(*pstrStatic));
  376. RtlCopyUnicodeString(pstrStatic, pstrWinSta);
  377. InitializeObjectAttributes(pObjAttr,
  378. pstrStatic,
  379. OBJ_CASE_INSENSITIVE,
  380. NULL,
  381. NULL);
  382. } except (W32ExceptionHandler(FALSE, RIP_WARNING)) {
  383. Status = GetExceptionCode();
  384. }
  385. if (NT_SUCCESS(Status)) {
  386. /*
  387. * In order to be able to verify access rights, we will pass
  388. * UserMode for KPROCESSOR_MODE. Passing KernelMode would bypass
  389. * all security checks. As a side-effect, hwsta is created
  390. * as a UserMode handle and is not a trusted/protected handle.
  391. */
  392. hwsta = _OpenWindowStation(pObjAttr, GENERIC_EXECUTE, UserMode);
  393. }
  394. } else {
  395. return Status;
  396. }
  397. if (pObjAttr != NULL) {
  398. ZwFreeVirtualMemory(NtCurrentProcess(), &pObjAttr, &cbObjA, MEM_RELEASE);
  399. }
  400. if (!hwsta) {
  401. return STATUS_ACCESS_DENIED;
  402. }
  403. Status = ObCloseHandle(hwsta, UserMode);
  404. UserAssert(NT_SUCCESS(Status));
  405. return Status;
  406. }
  407. /***************************************************************************\
  408. * CheckGrantedAccess
  409. *
  410. * Confirms all requested accesses are granted and sets error status.
  411. *
  412. * History:
  413. * 06-26-95 JimA Created.
  414. \***************************************************************************/
  415. BOOL CheckGrantedAccess(
  416. ACCESS_MASK amGranted,
  417. ACCESS_MASK amRequest)
  418. {
  419. /*
  420. * Check the granted access.
  421. */
  422. if (!RtlAreAllAccessesGranted(amGranted, amRequest)) {
  423. RIPERR0(ERROR_ACCESS_DENIED, RIP_VERBOSE, "");
  424. return FALSE;
  425. }
  426. return TRUE;
  427. }
  428. /***************************************************************************\
  429. * CheckWinstaWriteAttributesAccess
  430. *
  431. * Checks if the current process has WINSTA_WRITEATTRIBUTES access
  432. * to its windowstation, and whether that windowstation is an
  433. * interactive windowstation.
  434. *
  435. * History:
  436. * 06-Jun-1996 adams Created.
  437. \***************************************************************************/
  438. BOOL CheckWinstaWriteAttributesAccess(
  439. VOID)
  440. {
  441. PPROCESSINFO ppiCurrent = PpiCurrent();
  442. /*
  443. * winlogon has rights to all windowstations.
  444. */
  445. if (PsGetCurrentProcessId() == gpidLogon)
  446. return TRUE;
  447. if (!(ppiCurrent->W32PF_Flags & W32PF_IOWINSTA)) {
  448. RIPERR0(ERROR_REQUIRES_INTERACTIVE_WINDOWSTATION,
  449. RIP_WARNING,
  450. "Operation invalid on a non-interactive WindowStation.");
  451. return FALSE;
  452. }
  453. if (!RtlAreAllAccessesGranted(ppiCurrent->amwinsta, WINSTA_WRITEATTRIBUTES)) {
  454. RIPERR0(ERROR_ACCESS_DENIED,
  455. RIP_WARNING,
  456. "WINSTA_WRITEATTRIBUTES access to WindowStation denied.");
  457. return FALSE;
  458. }
  459. return TRUE;
  460. }
  461. /***************************************************************************\
  462. * AccessCheckObject
  463. *
  464. * Performs an access check on an object
  465. *
  466. * History:
  467. * 12-31-90 JimA Created.
  468. \***************************************************************************/
  469. BOOL AccessCheckObject(
  470. PVOID pobj,
  471. ACCESS_MASK amRequest,
  472. KPROCESSOR_MODE AccessMode,
  473. CONST GENERIC_MAPPING *pGenericMapping)
  474. {
  475. NTSTATUS Status;
  476. ACCESS_STATE AccessState;
  477. BOOLEAN fAccessGranted;
  478. AUX_ACCESS_DATA AuxData;
  479. BOOLEAN bMutexLocked = (pGenericMapping == (&KeyMapping));
  480. /*
  481. * Due to a resource problem in the object manager, we must pass in a TRUE
  482. * when checking access for registry keys, even if we do not explicitly have
  483. * the object type mutex. If we do not, we can get into a deadlock situation with this mutex
  484. * and the CmpRegistry lock.
  485. */
  486. SeCreateAccessState(&AccessState, &AuxData, amRequest, (PGENERIC_MAPPING)pGenericMapping);
  487. fAccessGranted = ObCheckObjectAccess(
  488. pobj,
  489. &AccessState,
  490. bMutexLocked,
  491. AccessMode,
  492. &Status);
  493. SeDeleteAccessState(&AccessState);
  494. return (BOOL)(fAccessGranted == TRUE);
  495. }
  496. /***************************************************************************\
  497. * IsPrivileged
  498. *
  499. * Check to see if the client has the specified privileges
  500. *
  501. * History:
  502. * 01-02-91 JimA Created.
  503. \***************************************************************************/
  504. BOOL IsPrivileged(
  505. PPRIVILEGE_SET ppSet)
  506. {
  507. SECURITY_SUBJECT_CONTEXT Context;
  508. BOOLEAN bHeld;
  509. SeCaptureSubjectContext(&Context);
  510. SeLockSubjectContext(&Context);
  511. bHeld = SePrivilegeCheck(ppSet, &Context, UserMode);
  512. SePrivilegeObjectAuditAlarm(NULL, &Context, 0, ppSet, bHeld, UserMode);
  513. SeUnlockSubjectContext(&Context);
  514. SeReleaseSubjectContext(&Context);
  515. if (!bHeld)
  516. RIPERR0(ERROR_PRIVILEGE_NOT_HELD, RIP_VERBOSE, "");
  517. /*
  518. * Return result of privilege check
  519. */
  520. return (BOOL)bHeld;
  521. }
  522. /***************************************************************************\
  523. * _GetUserObjectInformation (API)
  524. *
  525. * Gets information about a secure USER object
  526. *
  527. * History:
  528. * 04-25-94 JimA Created.
  529. \***************************************************************************/
  530. BOOL _GetUserObjectInformation(
  531. HANDLE h,
  532. int nIndex,
  533. PVOID ccxpvInfo,
  534. DWORD nLength,
  535. LPDWORD lpnLengthNeeded)
  536. {
  537. PUSEROBJECTFLAGS puof;
  538. BOOL fSuccess = TRUE;
  539. PVOID pObject;
  540. POBJECT_HEADER pHead;
  541. DWORD dwLengthNeeded = 0;
  542. OBJECT_HANDLE_INFORMATION ohi;
  543. PUNICODE_STRING pstrInfo;
  544. PWINDOWSTATION pwinsta;
  545. NTSTATUS Status;
  546. ACCESS_MASK amDesiredAccess = 0;
  547. /*
  548. * Validate the object and get a pointer with whatever
  549. * access is granted.
  550. */
  551. Status = ObReferenceObjectByHandle(
  552. h,
  553. 0,
  554. NULL,
  555. UserMode,
  556. &pObject,
  557. NULL);
  558. if (!NT_SUCCESS(Status)) {
  559. RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed");
  560. return FALSE;
  561. }
  562. /*
  563. * Determine the correct access mask given the object type.
  564. */
  565. pHead = OBJECT_TO_OBJECT_HEADER(pObject);
  566. if (pHead->Type == *ExWindowStationObjectType) {
  567. amDesiredAccess = WINSTA_READATTRIBUTES;
  568. } else if (pHead->Type == *ExDesktopObjectType) {
  569. amDesiredAccess = DESKTOP_READOBJECTS;
  570. }
  571. ObDereferenceObject(pObject);
  572. if (!amDesiredAccess) {
  573. RIPERR0(ERROR_INVALID_FUNCTION, RIP_WARNING, "Object is not a USER object");
  574. return FALSE;
  575. }
  576. /*
  577. * Re-open the object with the proper access.
  578. */
  579. Status = ObReferenceObjectByHandle(
  580. h,
  581. amDesiredAccess,
  582. NULL,
  583. UserMode,
  584. &pObject,
  585. &ohi);
  586. if (!NT_SUCCESS(Status)) {
  587. RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed");
  588. return FALSE;
  589. }
  590. #ifdef LOGDESKTOPLOCKS
  591. if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) {
  592. LogDesktop(pObject, LD_REF_FN_GETUSEROBJECTINFORMATION, TRUE, (ULONG_PTR)PtiCurrentShared());
  593. }
  594. #endif
  595. try {
  596. switch (nIndex) {
  597. case UOI_FLAGS:
  598. dwLengthNeeded = sizeof(USEROBJECTFLAGS);
  599. if (nLength < sizeof(USEROBJECTFLAGS)) {
  600. RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, "");
  601. fSuccess = FALSE;
  602. break;
  603. }
  604. puof = ccxpvInfo;
  605. puof->fInherit = (ohi.HandleAttributes & OBJ_INHERIT) ? TRUE : FALSE;
  606. puof->fReserved = 0;
  607. puof->dwFlags = 0;
  608. if (pHead->Type == *ExDesktopObjectType) {
  609. if (CheckHandleFlag(NULL, ((PDESKTOP)pObject)->dwSessionId, h, HF_DESKTOPHOOK)) {
  610. puof->dwFlags |= DF_ALLOWOTHERACCOUNTHOOK;
  611. }
  612. } else {
  613. if (!(((PWINDOWSTATION)pObject)->dwWSF_Flags & WSF_NOIO))
  614. puof->dwFlags |= WSF_VISIBLE;
  615. }
  616. break;
  617. case UOI_NAME:
  618. pstrInfo = POBJECT_NAME(pObject);
  619. goto docopy;
  620. case UOI_TYPE:
  621. pstrInfo = &pHead->Type->Name;
  622. docopy:
  623. if (pstrInfo) {
  624. dwLengthNeeded = pstrInfo->Length + sizeof(WCHAR);
  625. if (dwLengthNeeded > nLength) {
  626. RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, "");
  627. fSuccess = FALSE;
  628. break;
  629. }
  630. RtlCopyMemory(ccxpvInfo, pstrInfo->Buffer, pstrInfo->Length);
  631. *(PWCHAR)((PBYTE)ccxpvInfo + pstrInfo->Length) = 0;
  632. } else {
  633. dwLengthNeeded = 0;
  634. }
  635. break;
  636. case UOI_USER_SID:
  637. if (pHead->Type == *ExWindowStationObjectType)
  638. pwinsta = pObject;
  639. else
  640. pwinsta = ((PDESKTOP)pObject)->rpwinstaParent;
  641. if (pwinsta->psidUser == NULL) {
  642. dwLengthNeeded = 0;
  643. } else {
  644. dwLengthNeeded = RtlLengthSid(pwinsta->psidUser);
  645. if (dwLengthNeeded > nLength) {
  646. RIPERR0(ERROR_INSUFFICIENT_BUFFER, RIP_VERBOSE, "");
  647. fSuccess = FALSE;
  648. break;
  649. }
  650. RtlCopyMemory(ccxpvInfo, pwinsta->psidUser, dwLengthNeeded);
  651. }
  652. break;
  653. default:
  654. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  655. fSuccess = FALSE;
  656. break;
  657. }
  658. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  659. fSuccess = FALSE;
  660. }
  661. *lpnLengthNeeded = dwLengthNeeded;
  662. #ifdef LOGDESKTOPLOCKS
  663. if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) {
  664. LogDesktop(pObject, LD_DEREF_FN_GETUSEROBJECTINFORMATION, FALSE, (ULONG_PTR)PtiCurrentShared());
  665. }
  666. #endif
  667. ObDereferenceObject(pObject);
  668. return fSuccess;
  669. }
  670. /***************************************************************************\
  671. * _SetUserObjectInformation (API)
  672. *
  673. * Sets information about a secure USER object
  674. *
  675. * History:
  676. * 04-25-94 JimA Created.
  677. \***************************************************************************/
  678. BOOL _SetUserObjectInformation(
  679. HANDLE h,
  680. int nIndex,
  681. PVOID ccxpvInfo,
  682. DWORD nLength)
  683. {
  684. PUSEROBJECTFLAGS puof;
  685. BOOL fSuccess = TRUE;
  686. PVOID pObject;
  687. POBJECT_HEADER pHead;
  688. DWORD dwLengthNeeded = 0;
  689. OBJECT_HANDLE_INFORMATION ohi;
  690. OBJECT_HANDLE_FLAG_INFORMATION ofi;
  691. NTSTATUS Status;
  692. ACCESS_MASK amDesiredAccess = 0;
  693. /*
  694. * Validate the object and get a pointer with whatever
  695. * access is granted.
  696. */
  697. Status = ObReferenceObjectByHandle(
  698. h,
  699. 0,
  700. NULL,
  701. UserMode,
  702. &pObject,
  703. NULL);
  704. if (!NT_SUCCESS(Status)) {
  705. RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed");
  706. return FALSE;
  707. }
  708. /*
  709. * Determine the correct access mask given the object type.
  710. */
  711. pHead = OBJECT_TO_OBJECT_HEADER(pObject);
  712. if (pHead->Type == *ExWindowStationObjectType) {
  713. amDesiredAccess = WINSTA_WRITEATTRIBUTES;
  714. } else if (pHead->Type == *ExDesktopObjectType) {
  715. amDesiredAccess = DESKTOP_WRITEOBJECTS;
  716. }
  717. ObDereferenceObject(pObject);
  718. if (!amDesiredAccess) {
  719. RIPERR0(ERROR_INVALID_FUNCTION, RIP_WARNING, "Object is not a USER object");
  720. return FALSE;
  721. }
  722. /*
  723. * Re-open the object with the proper access.
  724. */
  725. Status = ObReferenceObjectByHandle(
  726. h,
  727. amDesiredAccess,
  728. NULL,
  729. UserMode,
  730. &pObject,
  731. &ohi);
  732. if (!NT_SUCCESS(Status)) {
  733. RIPNTERR0(Status, RIP_VERBOSE, "ObReferenceObjectByHandle Failed");
  734. return FALSE;
  735. }
  736. #ifdef LOGDESKTOPLOCKS
  737. if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) {
  738. LogDesktop(pObject, LD_REF_FN_SETUSEROBJECTINFORMATION, TRUE, (ULONG_PTR)PtiCurrent());
  739. }
  740. #endif
  741. try {
  742. switch (nIndex) {
  743. case UOI_FLAGS:
  744. if (nLength < sizeof(USEROBJECTFLAGS)) {
  745. RIPERR0(ERROR_INVALID_DATA, RIP_VERBOSE, "");
  746. fSuccess = FALSE;
  747. break;
  748. }
  749. puof = ccxpvInfo;
  750. ofi.Inherit = (puof->fInherit != FALSE);
  751. ofi.ProtectFromClose = (ohi.HandleAttributes & OBJ_PROTECT_CLOSE) ? TRUE : FALSE;
  752. ObSetHandleAttributes(h, &ofi, UserMode);
  753. if (pHead->Type == *ExDesktopObjectType) {
  754. SetHandleFlag(h, HF_DESKTOPHOOK,
  755. puof->dwFlags & DF_ALLOWOTHERACCOUNTHOOK);
  756. }
  757. break;
  758. default:
  759. RIPERR0(ERROR_INVALID_PARAMETER, RIP_VERBOSE, "");
  760. fSuccess = FALSE;
  761. break;
  762. }
  763. } except (W32ExceptionHandler(TRUE, RIP_WARNING)) {
  764. fSuccess = FALSE;
  765. }
  766. #ifdef LOGDESKTOPLOCKS
  767. if (OBJECT_TO_OBJECT_HEADER(pObject)->Type == *ExDesktopObjectType) {
  768. LogDesktop(pObject, LD_DEREF_FN_SETUSEROBJECTINFORMATION, FALSE, (ULONG_PTR)PtiCurrent());
  769. }
  770. #endif
  771. ObDereferenceObject(pObject);
  772. return fSuccess;
  773. }
  774. /***************************************************************************\
  775. * UserScreenAccessCheck
  776. *
  777. * Called from the engine to determine if the thread's desktop is
  778. * active and the process has WINSTA_READSCREEN access.
  779. *
  780. * Note that we may or may not be in USER's critical section when this
  781. * is called. This is OK as long as we don't reference thing belonging
  782. * to other threads. If we did try to enter the critical section here,
  783. * a deadlock may occur between the engine and user.
  784. *
  785. * History:
  786. * 05-20-1993 JimA Created.
  787. * 11-22-1996 BradG Brought back to life.
  788. * 05-07-2001 JasonSch CSRSS threads aren't always attached to a desktop,
  789. * but they need to draw anyway (for console).
  790. \***************************************************************************/
  791. BOOL FASTCALL UserScreenAccessCheck(VOID)
  792. {
  793. PTHREADINFO ptiCurrent = PtiCurrentShared();
  794. UserAssert(ptiCurrent != NULL);
  795. return (ptiCurrent != NULL &&
  796. (ptiCurrent->rpdesk == grpdeskRitInput || (ptiCurrent->TIF_flags & TIF_CSRSSTHREAD) != 0) &&
  797. (W32GetCurrentProcess()->W32PF_Flags & (W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA)) == (W32PF_READSCREENACCESSGRANTED | W32PF_IOWINSTA)
  798. );
  799. }