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.

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