Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

376 lines
10 KiB

  1. /*++
  2. Copyright (c) 1989-2000 Microsoft Corporation
  3. Module Name:
  4. AcChkSup.c
  5. Abstract:
  6. This module implements the FAT access checking routine
  7. // @@BEGIN_DDKSPLIT
  8. Author:
  9. Gary Kimura [GaryKi] 12-Jun-1989
  10. Revision History:
  11. // @@END_DDKSPLIT
  12. --*/
  13. #include "FatProcs.h"
  14. //
  15. // Our debug trace level
  16. //
  17. #define Dbg (DEBUG_TRACE_ACCHKSUP)
  18. NTSTATUS
  19. FatCreateRestrictEveryoneToken(
  20. IN PACCESS_TOKEN Token,
  21. OUT PACCESS_TOKEN *RestrictedToken
  22. );
  23. #ifdef ALLOC_PRAGMA
  24. #pragma alloc_text(PAGE, FatCheckFileAccess)
  25. #pragma alloc_text(PAGE, FatCreateRestrictEveryoneToken)
  26. #pragma alloc_text(PAGE, FatExplicitDeviceAccessGranted)
  27. #endif
  28. BOOLEAN
  29. FatCheckFileAccess (
  30. PIRP_CONTEXT IrpContext,
  31. IN UCHAR DirentAttributes,
  32. IN PACCESS_MASK DesiredAccess
  33. )
  34. /*++
  35. Routine Description:
  36. This routine checks if a desired access is allowed to a file represented
  37. by the specified DirentAttriubutes.
  38. Arguments:
  39. DirentAttributes - Supplies the Dirent attributes to check access for
  40. DesiredAccess - Supplies the desired access mask that we are checking for
  41. Return Value:
  42. BOOLEAN - TRUE if access is allowed and FALSE otherwise
  43. --*/
  44. {
  45. BOOLEAN Result;
  46. DebugTrace(+1, Dbg, "FatCheckFileAccess\n", 0);
  47. DebugTrace( 0, Dbg, "DirentAttributes = %8lx\n", DirentAttributes);
  48. DebugTrace( 0, Dbg, "DesiredAccess = %8lx\n", *DesiredAccess);
  49. //
  50. // This procedures is programmed like a string of filters each
  51. // filter checks to see if some access is allowed, if it is not allowed
  52. // the filter return FALSE to the user without further checks otherwise
  53. // it moves on to the next filter. The filter check is to check for
  54. // desired access flags that are not allowed for a particular dirent
  55. //
  56. Result = TRUE;
  57. try {
  58. //
  59. // Check for Volume ID or Device Dirents, these are not allowed user
  60. // access at all
  61. //
  62. if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_VOLUME_ID) ||
  63. FlagOn(DirentAttributes, FAT_DIRENT_ATTR_DEVICE)) {
  64. DebugTrace(0, Dbg, "Cannot access volume id or device\n", 0);
  65. try_return( Result = FALSE );
  66. }
  67. //
  68. // Check the desired access for the object - we only blackball that
  69. // we do not understand. The model of filesystems using ACLs is that
  70. // they do not type the ACL to the object the ACL is on. Permissions
  71. // are not checked for consistency vs. the object type - dir/file.
  72. //
  73. if (FlagOn(*DesiredAccess, ~(DELETE |
  74. READ_CONTROL |
  75. WRITE_OWNER |
  76. WRITE_DAC |
  77. SYNCHRONIZE |
  78. ACCESS_SYSTEM_SECURITY |
  79. FILE_WRITE_DATA |
  80. FILE_READ_EA |
  81. FILE_WRITE_EA |
  82. FILE_READ_ATTRIBUTES |
  83. FILE_WRITE_ATTRIBUTES |
  84. FILE_LIST_DIRECTORY |
  85. FILE_TRAVERSE |
  86. FILE_DELETE_CHILD |
  87. FILE_APPEND_DATA))) {
  88. DebugTrace(0, Dbg, "Cannot open object\n", 0);
  89. try_return( Result = FALSE );
  90. }
  91. //
  92. // Check for a read-only Dirent
  93. //
  94. if (FlagOn(DirentAttributes, FAT_DIRENT_ATTR_READ_ONLY)) {
  95. //
  96. // Check the desired access for a read-only dirent, we blackball
  97. // WRITE, FILE_APPEND_DATA, FILE_ADD_FILE,
  98. // FILE_ADD_SUBDIRECTORY, and FILE_DELETE_CHILD
  99. //
  100. if (FlagOn(*DesiredAccess, ~(DELETE |
  101. READ_CONTROL |
  102. WRITE_OWNER |
  103. WRITE_DAC |
  104. SYNCHRONIZE |
  105. ACCESS_SYSTEM_SECURITY |
  106. FILE_READ_DATA |
  107. FILE_READ_EA |
  108. FILE_WRITE_EA |
  109. FILE_READ_ATTRIBUTES |
  110. FILE_WRITE_ATTRIBUTES |
  111. FILE_EXECUTE |
  112. FILE_LIST_DIRECTORY |
  113. FILE_TRAVERSE))) {
  114. DebugTrace(0, Dbg, "Cannot open readonly\n", 0);
  115. try_return( Result = FALSE );
  116. }
  117. }
  118. try_exit: NOTHING;
  119. } finally {
  120. DebugUnwind( FatCheckFileAccess );
  121. DebugTrace(-1, Dbg, "FatCheckFileAccess -> %08lx\n", Result);
  122. }
  123. UNREFERENCED_PARAMETER( IrpContext );
  124. return Result;
  125. }
  126. NTSTATUS
  127. FatExplicitDeviceAccessGranted (
  128. IN PIRP_CONTEXT IrpContext,
  129. IN PDEVICE_OBJECT DeviceObject,
  130. IN PACCESS_STATE AccessState,
  131. IN KPROCESSOR_MODE ProcessorMode
  132. )
  133. /*++
  134. Routine Description:
  135. This function asks whether the SID described in the input access state has
  136. been granted any explicit access to the given device object. It does this
  137. by acquiring a token stripped of its ability to acquire access via the
  138. Everyone SID and re-doing the access check.
  139. Arguments:
  140. DeviceObject - the device whose ACL will be checked
  141. AccessState - the access state describing the security context to be checked
  142. ProcessorMode - the mode this check should occur against
  143. Return Value:
  144. NTSTATUS - Indicating whether explicit access was granted.
  145. --*/
  146. {
  147. NTSTATUS Status;
  148. BOOLEAN Result;
  149. PACCESS_TOKEN OriginalAccessToken;
  150. PACCESS_TOKEN RestrictedAccessToken;
  151. PACCESS_TOKEN *EffectiveToken;
  152. PRIVILEGE_SET PrivilegeSet;
  153. ACCESS_MASK GrantedAccess;
  154. //
  155. // If the access state indicates that specific access other
  156. // than traverse was acquired, either Everyone does have such
  157. // access or explicit access was granted. In both cases, we're
  158. // happy to let this proceed.
  159. //
  160. if (AccessState->PreviouslyGrantedAccess & (SPECIFIC_RIGHTS_ALL ^
  161. FILE_TRAVERSE)) {
  162. return STATUS_SUCCESS;
  163. }
  164. //
  165. // If the manage volume privilege is held, this also permits access.
  166. //
  167. PrivilegeSet.PrivilegeCount = 1;
  168. PrivilegeSet.Control = PRIVILEGE_SET_ALL_NECESSARY;
  169. PrivilegeSet.Privilege[0].Luid = RtlConvertLongToLuid( SE_MANAGE_VOLUME_PRIVILEGE );
  170. PrivilegeSet.Privilege[0].Attributes = 0;
  171. if (SePrivilegeCheck( &PrivilegeSet,
  172. &AccessState->SubjectSecurityContext,
  173. ProcessorMode )) {
  174. return STATUS_SUCCESS;
  175. }
  176. //
  177. // Capture the subject context as a prelude to everything below.
  178. //
  179. SeLockSubjectContext( &AccessState->SubjectSecurityContext );
  180. //
  181. // Convert the token in the subject context into one which does not
  182. // acquire access through the Everyone SID.
  183. //
  184. // The logic for deciding which token is effective comes from
  185. // SeQuerySubjectContextToken; since there is no natural way
  186. // of getting a pointer to it, do it by hand.
  187. //
  188. if (ARGUMENT_PRESENT( AccessState->SubjectSecurityContext.ClientToken )) {
  189. EffectiveToken = &AccessState->SubjectSecurityContext.ClientToken;
  190. } else {
  191. EffectiveToken = &AccessState->SubjectSecurityContext.PrimaryToken;
  192. }
  193. OriginalAccessToken = *EffectiveToken;
  194. Status = FatCreateRestrictEveryoneToken( OriginalAccessToken, &RestrictedAccessToken );
  195. if (!NT_SUCCESS(Status)) {
  196. SeReleaseSubjectContext( &AccessState->SubjectSecurityContext );
  197. return Status;
  198. }
  199. //
  200. // Now see if the resulting context has access to the device through
  201. // its explicitly granted access. We swap in our restricted token
  202. // for this check as the effective client token.
  203. //
  204. *EffectiveToken = RestrictedAccessToken;
  205. Result = SeAccessCheck( DeviceObject->SecurityDescriptor,
  206. &AccessState->SubjectSecurityContext,
  207. FALSE,
  208. AccessState->OriginalDesiredAccess,
  209. 0,
  210. NULL,
  211. IoGetFileObjectGenericMapping(),
  212. ProcessorMode,
  213. &GrantedAccess,
  214. &Status );
  215. *EffectiveToken = OriginalAccessToken;
  216. //
  217. // Cleanup and return.
  218. //
  219. SeUnlockSubjectContext( &AccessState->SubjectSecurityContext );
  220. ObDereferenceObject( RestrictedAccessToken );
  221. return Status;
  222. }
  223. NTSTATUS
  224. FatCreateRestrictEveryoneToken (
  225. IN PACCESS_TOKEN Token,
  226. OUT PACCESS_TOKEN *RestrictedToken
  227. )
  228. /*++
  229. Routine Description:
  230. This function takes a token as the input and returns a new restricted token
  231. from which Everyone sid has been disabled. The resulting token may be used
  232. to find out if access is available to a user-sid by explicit means.
  233. Arguments:
  234. Token - Input token from which Everyone sid needs to be deactivated.
  235. RestrictedToken - Receives the the new restricted token.
  236. This must be released using ObDereferenceObject(*RestrictedToken);
  237. Return Value:
  238. NTSTATUS - Returned by SeFilterToken.
  239. --*/
  240. {
  241. //
  242. // Array of sids to disable.
  243. //
  244. TOKEN_GROUPS SidsToDisable;
  245. NTSTATUS Status = STATUS_SUCCESS;
  246. //
  247. // Restricted token will contain the original sids with one change:
  248. // If Everyone sid is present in the token, it will be marked for DenyOnly.
  249. //
  250. *RestrictedToken = NULL;
  251. //
  252. // Put Everyone sid in the array of sids to disable. This will mark it
  253. // for SE_GROUP_USE_FOR_DENY_ONLY and it'll only be applicable for Deny aces.
  254. //
  255. SidsToDisable.GroupCount = 1;
  256. SidsToDisable.Groups[0].Attributes = 0;
  257. SidsToDisable.Groups[0].Sid = SeExports->SeWorldSid;
  258. Status = SeFilterToken(
  259. Token, // Token that needs to be restricted.
  260. 0, // No flags
  261. &SidsToDisable, // Disable everyone sid
  262. NULL, // Do not create any restricted sids
  263. NULL, // Do not delete any privileges
  264. RestrictedToken // Restricted token
  265. );
  266. return Status;
  267. }