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.

608 lines
14 KiB

  1. /*++
  2. Module Name:
  3. SeAstate.c
  4. Abstract:
  5. This Module implements the privilege check procedures.
  6. Author:
  7. Robert Reichel (robertre) 20-March-90
  8. Environment:
  9. Kernel Mode
  10. Revision History:
  11. v1: robertre
  12. new file, move Access State related routines here
  13. --*/
  14. #include "pch.h"
  15. #pragma hdrstop
  16. #ifdef ALLOC_PRAGMA
  17. #pragma alloc_text(PAGE,SeCreateAccessState)
  18. #pragma alloc_text(PAGE,SeDeleteAccessState)
  19. #pragma alloc_text(PAGE,SeSetAccessStateGenericMapping)
  20. #pragma alloc_text(PAGE,SeAppendPrivileges)
  21. #pragma alloc_text(PAGE,SepConcatenatePrivileges)
  22. #endif
  23. //
  24. // Define logical sum of all generic accesses.
  25. //
  26. #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | GENERIC_EXECUTE | GENERIC_ALL)
  27. //
  28. // The PRIVILEGE_SET data structure includes an array including ANYSIZE_ARRAY
  29. // elements. This definition provides the size of an empty PRIVILEGE_SET
  30. // (i.e., one with no privileges in it).
  31. //
  32. #define SEP_PRIVILEGE_SET_HEADER_SIZE \
  33. ((ULONG)sizeof(PRIVILEGE_SET) - \
  34. (ANYSIZE_ARRAY * (ULONG)sizeof(LUID_AND_ATTRIBUTES)))
  35. #if 0
  36. NTSTATUS
  37. SeCreateAccessState(
  38. IN PACCESS_STATE AccessState,
  39. IN ACCESS_MASK DesiredAccess,
  40. IN PGENERIC_MAPPING GenericMapping OPTIONAL
  41. )
  42. /*++
  43. Routine Description:
  44. This routine initializes an ACCESS_STATE structure. This consists
  45. of:
  46. - zeroing the entire structure
  47. - mapping generic access types in the passed DesiredAccess
  48. and putting it into the structure
  49. - "capturing" the Subject Context, which must be held for the
  50. duration of the access attempt (at least until auditing is performed).
  51. - Allocating an Operation ID, which is an LUID that will be used
  52. to associate different parts of the access attempt in the audit
  53. log.
  54. Arguments:
  55. AccessState - a pointer to the structure to be initialized.
  56. DesiredAccess - Access mask containing the desired access
  57. GenericMapping - Optionally supplies a pointer to a generic mapping
  58. that may be used to map any generic access requests that may
  59. have been passed in the DesiredAccess parameter.
  60. Note that if this parameter is not supplied, it must be filled
  61. in at some later point. The IO system does this in IopParseDevice.
  62. Return Value:
  63. Error if the attempt to allocate an LUID fails.
  64. Note that this error may be safely ignored if it is known that all
  65. security checks will be performed with PreviousMode == KernelMode.
  66. Know what you're doing if you choose to ignore this.
  67. --*/
  68. {
  69. ACCESS_MASK MappedAccessMask;
  70. PSECURITY_DESCRIPTOR InputSecurityDescriptor = NULL;
  71. PAUX_ACCESS_DATA AuxData;
  72. PAGED_CODE();
  73. //
  74. // Don't modify what he passed in
  75. //
  76. MappedAccessMask = DesiredAccess;
  77. //
  78. // Map generic access to object specific access iff generic access types
  79. // are specified and a generic access mapping table is provided.
  80. //
  81. if ( ((DesiredAccess & GENERIC_ACCESS) != 0) &&
  82. ARGUMENT_PRESENT(GenericMapping) ) {
  83. RtlMapGenericMask(
  84. &MappedAccessMask,
  85. GenericMapping
  86. );
  87. }
  88. RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
  89. //
  90. // Assume RtlZeroMemory has initialized these fields properly
  91. //
  92. ASSERT( AccessState->SecurityDescriptor == NULL );
  93. ASSERT( AccessState->PrivilegesAllocated == FALSE );
  94. AccessState->AuxData = ExAllocatePool( PagedPool, sizeof( AUX_ACCESS_DATA ));
  95. if (AccessState->AuxData == NULL) {
  96. return( STATUS_NO_MEMORY );
  97. }
  98. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  99. SeCaptureSubjectContext(&AccessState->SubjectSecurityContext);
  100. if (((PTOKEN)EffectiveToken( &AccessState->SubjectSecurityContext ))->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE ) {
  101. AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
  102. }
  103. if (SeTokenIsRestricted(EffectiveToken( &AccessState-SubjectSecurityContext))) {
  104. AccessState->Flags |= TOKEN_IS_RESTRICTED;
  105. }
  106. AccessState->RemainingDesiredAccess = MappedAccessMask;
  107. AccessState->OriginalDesiredAccess = DesiredAccess;
  108. AuxData->PrivilegesUsed = (PPRIVILEGE_SET)((PUCHAR)AccessState +
  109. (FIELD_OFFSET(ACCESS_STATE, Privileges)));
  110. ExAllocateLocallyUniqueId(&AccessState->OperationID);
  111. if (ARGUMENT_PRESENT(GenericMapping)) {
  112. AuxData->GenericMapping = *GenericMapping;
  113. }
  114. return( STATUS_SUCCESS );
  115. }
  116. #endif
  117. NTSTATUS
  118. SeCreateAccessState(
  119. IN PACCESS_STATE AccessState,
  120. IN PAUX_ACCESS_DATA AuxData,
  121. IN ACCESS_MASK DesiredAccess,
  122. IN PGENERIC_MAPPING GenericMapping OPTIONAL
  123. )
  124. /*++
  125. Routine Description:
  126. This routine initializes an ACCESS_STATE structure. This consists
  127. of:
  128. - zeroing the entire structure
  129. - mapping generic access types in the passed DesiredAccess
  130. and putting it into the structure
  131. - "capturing" the Subject Context, which must be held for the
  132. duration of the access attempt (at least until auditing is performed).
  133. - Allocating an Operation ID, which is an LUID that will be used
  134. to associate different parts of the access attempt in the audit
  135. log.
  136. Arguments:
  137. AccessState - a pointer to the structure to be initialized.
  138. AuxData - Supplies a buffer big enough for an AuxData structure
  139. so we don't have to allocate one.
  140. DesiredAccess - Access mask containing the desired access
  141. GenericMapping - Optionally supplies a pointer to a generic mapping
  142. that may be used to map any generic access requests that may
  143. have been passed in the DesiredAccess parameter.
  144. Note that if this parameter is not supplied, it must be filled
  145. in at some later point. The IO system does this in IopParseDevice.
  146. Return Value:
  147. Error if the attempt to allocate an LUID fails.
  148. Note that this error may be safely ignored if it is known that all
  149. security checks will be performed with PreviousMode == KernelMode.
  150. Know what you're doing if you choose to ignore this.
  151. --*/
  152. {
  153. ACCESS_MASK MappedAccessMask;
  154. PSECURITY_DESCRIPTOR InputSecurityDescriptor = NULL;
  155. PAGED_CODE();
  156. //
  157. // Don't modify what he passed in
  158. //
  159. MappedAccessMask = DesiredAccess;
  160. //
  161. // Map generic access to object specific access iff generic access types
  162. // are specified and a generic access mapping table is provided.
  163. //
  164. if ( ((DesiredAccess & GENERIC_ACCESS) != 0) &&
  165. ARGUMENT_PRESENT(GenericMapping) ) {
  166. RtlMapGenericMask(
  167. &MappedAccessMask,
  168. GenericMapping
  169. );
  170. }
  171. RtlZeroMemory(AccessState, sizeof(ACCESS_STATE));
  172. RtlZeroMemory(AuxData, sizeof(AUX_ACCESS_DATA));
  173. //
  174. // Assume RtlZeroMemory has initialized these fields properly
  175. //
  176. ASSERT( AccessState->SecurityDescriptor == NULL );
  177. ASSERT( AccessState->PrivilegesAllocated == FALSE );
  178. AccessState->AuxData = AuxData;
  179. SeCaptureSubjectContext(&AccessState->SubjectSecurityContext);
  180. if (((PTOKEN)EffectiveToken( &AccessState->SubjectSecurityContext ))->TokenFlags & TOKEN_HAS_TRAVERSE_PRIVILEGE ) {
  181. AccessState->Flags = TOKEN_HAS_TRAVERSE_PRIVILEGE;
  182. }
  183. AccessState->RemainingDesiredAccess = MappedAccessMask;
  184. AccessState->OriginalDesiredAccess = MappedAccessMask;
  185. AuxData->PrivilegesUsed = (PPRIVILEGE_SET)((ULONG_PTR)AccessState +
  186. (FIELD_OFFSET(ACCESS_STATE, Privileges)));
  187. ExAllocateLocallyUniqueId(&AccessState->OperationID);
  188. if (ARGUMENT_PRESENT(GenericMapping)) {
  189. AuxData->GenericMapping = *GenericMapping;
  190. }
  191. return( STATUS_SUCCESS );
  192. }
  193. #if 0
  194. VOID
  195. SeDeleteAccessState(
  196. PACCESS_STATE AccessState
  197. )
  198. /*++
  199. Routine Description:
  200. This routine deallocates any memory that may have been allocated as
  201. part of constructing the access state (normally only for an excessive
  202. number of privileges), and frees the Subject Context.
  203. Arguments:
  204. AccessState - a pointer to the ACCESS_STATE structure to be
  205. deallocated.
  206. Return Value:
  207. None.
  208. --*/
  209. {
  210. PAUX_ACCESS_DATA AuxData;
  211. PAGED_CODE();
  212. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  213. if (AccessState->PrivilegesAllocated) {
  214. ExFreePool( (PVOID)AuxData->PrivilegesUsed );
  215. }
  216. if (AccessState->ObjectName.Buffer != NULL) {
  217. ExFreePool(AccessState->ObjectName.Buffer);
  218. }
  219. if (AccessState->ObjectTypeName.Buffer != NULL) {
  220. ExFreePool(AccessState->ObjectTypeName.Buffer);
  221. }
  222. ExFreePool( AuxData );
  223. SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
  224. return;
  225. }
  226. #endif
  227. VOID
  228. SeDeleteAccessState(
  229. PACCESS_STATE AccessState
  230. )
  231. /*++
  232. Routine Description:
  233. This routine deallocates any memory that may have been allocated as
  234. part of constructing the access state (normally only for an excessive
  235. number of privileges), and frees the Subject Context.
  236. Arguments:
  237. AccessState - a pointer to the ACCESS_STATE structure to be
  238. deallocated.
  239. Return Value:
  240. None.
  241. --*/
  242. {
  243. PAUX_ACCESS_DATA AuxData;
  244. PAGED_CODE();
  245. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  246. if (AccessState->PrivilegesAllocated) {
  247. ExFreePool( (PVOID)AuxData->PrivilegesUsed );
  248. }
  249. if (AccessState->ObjectName.Buffer != NULL) {
  250. ExFreePool(AccessState->ObjectName.Buffer);
  251. }
  252. if (AccessState->ObjectTypeName.Buffer != NULL) {
  253. ExFreePool(AccessState->ObjectTypeName.Buffer);
  254. }
  255. SeReleaseSubjectContext(&AccessState->SubjectSecurityContext);
  256. return;
  257. }
  258. VOID
  259. SeSetAccessStateGenericMapping (
  260. PACCESS_STATE AccessState,
  261. PGENERIC_MAPPING GenericMapping
  262. )
  263. /*++
  264. Routine Description:
  265. This routine sets the GenericMapping field in an AccessState structure.
  266. It must be called before access validation is performed if the GenericMapping
  267. is not passed in when the AccessState structure is created.
  268. Arguments:
  269. AccessState - a pointer to the ACCESS_STATE structure to be modified.
  270. GenericMapping - a pointer to the GenericMapping to be copied into the AccessState.
  271. Return Value:
  272. --*/
  273. {
  274. PAUX_ACCESS_DATA AuxData;
  275. PAGED_CODE();
  276. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  277. AuxData->GenericMapping = *GenericMapping;
  278. return;
  279. }
  280. NTSTATUS
  281. SeAppendPrivileges(
  282. PACCESS_STATE AccessState,
  283. PPRIVILEGE_SET Privileges
  284. )
  285. /*++
  286. Routine Description:
  287. This routine takes a privilege set and adds it to the privilege set
  288. imbedded in an ACCESS_STATE structure.
  289. An AccessState may contain up to three imbedded privileges. To
  290. add more, this routine will allocate a block of memory, copy
  291. the current privileges into it, and append the new privilege
  292. to that block. A bit is set in the AccessState indicating that
  293. the pointer to the privilge set in the structure points to pool
  294. memory and must be deallocated.
  295. Arguments:
  296. AccessState - The AccessState structure representing the current
  297. access attempt.
  298. Privileges - A pointer to a privilege set to be added.
  299. Return Value:
  300. STATUS_INSUFFICIENT_RESOURCES - an attempt to allocate pool memory
  301. failed.
  302. --*/
  303. {
  304. ULONG NewPrivilegeSetSize;
  305. PPRIVILEGE_SET NewPrivilegeSet;
  306. PAUX_ACCESS_DATA AuxData;
  307. PAGED_CODE();
  308. AuxData = (PAUX_ACCESS_DATA)AccessState->AuxData;
  309. if (Privileges->PrivilegeCount + AuxData->PrivilegesUsed->PrivilegeCount >
  310. INITIAL_PRIVILEGE_COUNT) {
  311. //
  312. // Compute the total size of the two privilege sets
  313. //
  314. NewPrivilegeSetSize = SepPrivilegeSetSize( Privileges ) +
  315. SepPrivilegeSetSize( AuxData->PrivilegesUsed );
  316. NewPrivilegeSet = ExAllocatePoolWithTag( PagedPool, NewPrivilegeSetSize, 'rPeS' );
  317. if (NewPrivilegeSet == NULL) {
  318. return( STATUS_INSUFFICIENT_RESOURCES );
  319. }
  320. RtlCopyMemory(
  321. NewPrivilegeSet,
  322. AuxData->PrivilegesUsed,
  323. SepPrivilegeSetSize( AuxData->PrivilegesUsed )
  324. );
  325. //
  326. // Note that this will adjust the privilege count in the
  327. // structure for us.
  328. //
  329. SepConcatenatePrivileges(
  330. NewPrivilegeSet,
  331. NewPrivilegeSetSize,
  332. Privileges
  333. );
  334. if (AccessState->PrivilegesAllocated) {
  335. ExFreePool( AuxData->PrivilegesUsed );
  336. }
  337. AuxData->PrivilegesUsed = NewPrivilegeSet;
  338. //
  339. // Mark that we've allocated memory for the privilege set,
  340. // so we know to free it when we're cleaning up.
  341. //
  342. AccessState->PrivilegesAllocated = TRUE;
  343. } else {
  344. //
  345. // Note that this will adjust the privilege count in the
  346. // structure for us.
  347. //
  348. SepConcatenatePrivileges(
  349. AuxData->PrivilegesUsed,
  350. sizeof(INITIAL_PRIVILEGE_SET),
  351. Privileges
  352. );
  353. }
  354. return( STATUS_SUCCESS );
  355. }
  356. VOID
  357. SepConcatenatePrivileges(
  358. IN PPRIVILEGE_SET TargetPrivilegeSet,
  359. IN ULONG TargetBufferSize,
  360. IN PPRIVILEGE_SET SourcePrivilegeSet
  361. )
  362. /*++
  363. Routine Description:
  364. Takes two privilege sets and appends the second to the end of the
  365. first.
  366. There must be enough space left at the end of the first privilege
  367. set to contain the second.
  368. Arguments:
  369. TargetPrivilegeSet - Supplies a buffer containing a privilege set.
  370. The buffer must be large enough to contain the second privilege
  371. set.
  372. TargetBufferSize - Supplies the size of the target buffer.
  373. SourcePrivilegeSet - Supplies the privilege set to be copied
  374. into the target buffer.
  375. Return Value:
  376. None
  377. --*/
  378. {
  379. PVOID Base;
  380. PVOID Source;
  381. ULONG Length;
  382. PAGED_CODE();
  383. ASSERT( ((ULONG)SepPrivilegeSetSize( TargetPrivilegeSet ) +
  384. (ULONG)SepPrivilegeSetSize( SourcePrivilegeSet ) -
  385. SEP_PRIVILEGE_SET_HEADER_SIZE ) <=
  386. TargetBufferSize
  387. );
  388. Base = (PVOID)((ULONG_PTR)TargetPrivilegeSet + SepPrivilegeSetSize( TargetPrivilegeSet ));
  389. Source = (PVOID) ((ULONG_PTR)SourcePrivilegeSet + SEP_PRIVILEGE_SET_HEADER_SIZE);
  390. Length = SourcePrivilegeSet->PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES);
  391. RtlMoveMemory(
  392. Base,
  393. Source,
  394. Length
  395. );
  396. TargetPrivilegeSet->PrivilegeCount += SourcePrivilegeSet->PrivilegeCount;
  397. }