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.

573 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Subject.c
  5. Abstract:
  6. This Module implements services related to subject security context.
  7. These services are part of the services provided by the Reference Monitor
  8. component.
  9. FOR PERFORMANCE SAKE, THIS MODULE IS AWARE OF INTERNAL TOKEN OBJECT
  10. FORMATS.
  11. Author:
  12. Jim Kelly (JimK) 2-Aug-1990
  13. Environment:
  14. Kernel Mode
  15. Revision History:
  16. --*/
  17. #include "pch.h"
  18. #pragma hdrstop
  19. #ifdef ALLOC_PRAGMA
  20. #pragma alloc_text(PAGE,SeCaptureSubjectContext)
  21. #pragma alloc_text(PAGE,SeLockSubjectContext)
  22. #pragma alloc_text(PAGE,SeUnlockSubjectContext)
  23. #pragma alloc_text(PAGE,SeReleaseSubjectContext)
  24. #pragma alloc_text(PAGE,SepGetDefaultsSubjectContext)
  25. #pragma alloc_text(PAGE,SepIdAssignableAsGroup)
  26. #pragma alloc_text(PAGE,SepValidOwnerSubjectContext)
  27. //#pragma alloc_text(PAGE,SeQueryAuthenticationIdSubjectContext)
  28. #endif
  29. VOID
  30. SeCaptureSubjectContext (
  31. OUT PSECURITY_SUBJECT_CONTEXT SubjectContext
  32. )
  33. /*++
  34. Routine Description:
  35. This routine takes a snapshot of the calling thread's security
  36. context (locking tokens as necessary to do so). This function
  37. is intended to support the object manager and other components
  38. that utilize the reference monitor's access validation,
  39. privilege test, and audit generation services.
  40. A subject's security context should be captured before initiating
  41. access validation and should be released after audit messages
  42. are generated. This is necessary to provide a consistent security
  43. context to all those services.
  44. After calling access validation, privilege test, and audit generation
  45. services, the captured context should be released as soon as possible
  46. using the SeReleaseSubjectContext() service.
  47. Arguments:
  48. SubjectContext - Points to a SECURITY_SUBJECT_CONTEXT data structure
  49. to be filled in with a snapshot of the calling thread's security
  50. profile.
  51. Return Value:
  52. none.
  53. --*/
  54. {
  55. PEPROCESS CurrentProcess;
  56. //PVOID Objects[2];
  57. BOOLEAN IgnoreCopyOnOpen;
  58. BOOLEAN IgnoreEffectiveOnly;
  59. PAGED_CODE();
  60. CurrentProcess = PsGetCurrentProcess();
  61. SubjectContext->ProcessAuditId = PsProcessAuditId( CurrentProcess );
  62. //
  63. // Get pointers to primary and impersonation tokens
  64. //
  65. SubjectContext->ClientToken = PsReferenceImpersonationToken(
  66. PsGetCurrentThread(),
  67. &IgnoreCopyOnOpen,
  68. &IgnoreEffectiveOnly,
  69. &(SubjectContext->ImpersonationLevel)
  70. );
  71. SubjectContext->PrimaryToken = PsReferencePrimaryToken(CurrentProcess);
  72. return;
  73. }
  74. VOID
  75. SeLockSubjectContext(
  76. IN PSECURITY_SUBJECT_CONTEXT SubjectContext
  77. )
  78. /*++
  79. Routine Description:
  80. Acquires READ LOCKS on the primary and impersonation tokens
  81. in the passed SubjectContext.
  82. This call must be undone by a call to SeUnlockSubjectContext().
  83. No one outside of the SE component should need to acquire a
  84. write lock to a token. Therefore there is no public interface
  85. to do this.
  86. Arguments:
  87. SubjectContext - Points to a SECURITY_SUBJECT_CONTEXT data structure
  88. which points to a primary token and an optional impersonation token.
  89. Return Value:
  90. None
  91. --*/
  92. {
  93. PAGED_CODE();
  94. SepAcquireTokenReadLock((PTOKEN)(SubjectContext->PrimaryToken));
  95. if (ARGUMENT_PRESENT(SubjectContext->ClientToken)) {
  96. SepAcquireTokenReadLock((PTOKEN)(SubjectContext->ClientToken));
  97. }
  98. return;
  99. }
  100. VOID
  101. SeUnlockSubjectContext(
  102. IN PSECURITY_SUBJECT_CONTEXT SubjectContext
  103. )
  104. /*++
  105. Routine Description:
  106. Releases the read locks on the token(s) in the passed SubjectContext.
  107. Arguments:
  108. SubjectContext - Points to a SECURITY_SUBJECT_CONTEXT data structure
  109. which points to a primary token and an optional impersonation token.
  110. Return Value:
  111. None
  112. --*/
  113. {
  114. PAGED_CODE();
  115. SepReleaseTokenReadLock((PTOKEN)(SubjectContext->PrimaryToken));
  116. if (ARGUMENT_PRESENT(SubjectContext->ClientToken)) {
  117. SepReleaseTokenReadLock((PTOKEN)(SubjectContext->ClientToken));
  118. }
  119. }
  120. VOID
  121. SeReleaseSubjectContext (
  122. IN PSECURITY_SUBJECT_CONTEXT SubjectContext
  123. )
  124. /*++
  125. Routine Description:
  126. This routine releases a subject security context previously captured by
  127. SeCaptureSubjectContext().
  128. Arguments:
  129. SubjectContext - Points to a SECURITY_SUBJECT_CONTEXT data structure
  130. containing a subject's previously captured security context.
  131. Return Value:
  132. none.
  133. --*/
  134. {
  135. PAGED_CODE();
  136. PsDereferencePrimaryToken( SubjectContext->PrimaryToken );
  137. SubjectContext->PrimaryToken = NULL;
  138. PsDereferenceImpersonationToken( SubjectContext->ClientToken );
  139. SubjectContext->ClientToken = NULL;
  140. return;
  141. }
  142. VOID
  143. SepGetDefaultsSubjectContext(
  144. IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
  145. OUT PSID *Owner,
  146. OUT PSID *Group,
  147. OUT PSID *ServerOwner,
  148. OUT PSID *ServerGroup,
  149. OUT PACL *Dacl
  150. )
  151. /*++
  152. Routine Description:
  153. This routine retrieves pointers to the default owner, primary group,
  154. and, if present, discretionary ACL of the provided subject security
  155. context.
  156. Arguments:
  157. SubjectContext - Points to the subject security context whose default
  158. values are to be retrieved.
  159. Owner - Receives a pointer to the subject's default owner SID. This
  160. value will always be returned as a non-zero pointer. That is,
  161. a subject's security context must contain a owner SID.
  162. Group - Receives a pointer to the subject's default primary group SID.
  163. This value will always be returned as a non-zero pointer. That is,
  164. a subject's security context must contain a primary group.
  165. Dacl - Receives a pointer to the subject's default discretionary ACL,
  166. if one is define for the subject. Note that a subject security context
  167. does not have to include a default discretionary ACL. In this case,
  168. this value will be returned as NULL.
  169. Return Value:
  170. none.
  171. --*/
  172. {
  173. PTOKEN EffectiveToken;
  174. PTOKEN PrimaryToken;
  175. PAGED_CODE();
  176. if (ARGUMENT_PRESENT(SubjectContext->ClientToken)) {
  177. EffectiveToken = (PTOKEN)SubjectContext->ClientToken;
  178. } else {
  179. EffectiveToken = (PTOKEN)SubjectContext->PrimaryToken;
  180. }
  181. (*Owner) = EffectiveToken->UserAndGroups[EffectiveToken->DefaultOwnerIndex].Sid;
  182. (*Group) = EffectiveToken->PrimaryGroup;
  183. (*Dacl) = EffectiveToken->DefaultDacl;
  184. PrimaryToken = (PTOKEN)SubjectContext->PrimaryToken;
  185. *ServerOwner = PrimaryToken->UserAndGroups[PrimaryToken->DefaultOwnerIndex].Sid;
  186. *ServerGroup = PrimaryToken->PrimaryGroup;
  187. return;
  188. }
  189. BOOLEAN
  190. SepIdAssignableAsGroup(
  191. IN PACCESS_TOKEN AToken,
  192. IN PSID Group
  193. )
  194. /*++
  195. Routine Description:
  196. This routine checks to see whether the provided SID is one that
  197. may be assigned to be the default primary group in a token.
  198. The current criteria is that the passed SID be a group in the
  199. token, with no other restrictions.
  200. Arguments:
  201. Token - Points to the token to be examined.
  202. Group - Points to the SID to be checked.
  203. Return Value:
  204. TRUE - SID passed by be assigned as the default primary group in a token.
  205. FALSE - Passed SID may not be so assigned.
  206. --*/
  207. {
  208. ULONG Index;
  209. BOOLEAN Found = FALSE;
  210. PTOKEN Token;
  211. PAGED_CODE();
  212. Token = (PTOKEN)AToken;
  213. //
  214. // Let's make it invalid to assign a NULL primary group,
  215. // but we may need to revisit this.
  216. //
  217. if (Group == NULL) {
  218. return( FALSE );
  219. }
  220. Index = 0;
  221. SepAcquireTokenReadLock( Token );
  222. //
  223. // Walk through the list of user and group IDs looking
  224. // for a match to the specified SID.
  225. //
  226. while (Index < Token->UserAndGroupCount) {
  227. Found = RtlEqualSid(
  228. Group,
  229. Token->UserAndGroups[Index].Sid
  230. );
  231. if ( Found ) {
  232. break;
  233. }
  234. Index += 1;
  235. }
  236. SepReleaseTokenReadLock( Token );
  237. return Found;
  238. }
  239. BOOLEAN
  240. SepValidOwnerSubjectContext(
  241. IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
  242. IN PSID Owner,
  243. IN BOOLEAN ServerObject
  244. )
  245. /*++
  246. Routine Description:
  247. This routine checks to see whether the provided SID is one the subject
  248. is authorized to assign as the owner of objects. It will also check to
  249. see if the caller has SeRestorePrivilege, if so, the request is granted.
  250. Arguments:
  251. SubjectContext - Points to the subject's security context.
  252. Owner - Points to the SID to be checked.
  253. Return Value:
  254. none.
  255. --*/
  256. {
  257. ULONG Index;
  258. BOOLEAN Found;
  259. PTOKEN EffectiveToken;
  260. BOOLEAN Rc = FALSE;
  261. PAGED_CODE();
  262. //
  263. // It is invalid to assign a NULL owner, regardless of
  264. // whether you have SeRestorePrivilege or not.
  265. //
  266. if (Owner == NULL) {
  267. return( FALSE );
  268. }
  269. //
  270. // Allowable owners come from the primary if it's a server object.
  271. //
  272. if (!ServerObject && ARGUMENT_PRESENT(SubjectContext->ClientToken)) {
  273. EffectiveToken = (PTOKEN)SubjectContext->ClientToken;
  274. } else {
  275. EffectiveToken = (PTOKEN)SubjectContext->PrimaryToken;
  276. }
  277. //
  278. // If we're impersonating, make sure we're at TokenImpersonation
  279. // or above. This prevents someone from setting the owner of an
  280. // object when impersonating at less Identify or Anonymous.
  281. //
  282. if (EffectiveToken->TokenType == TokenImpersonation) {
  283. if (EffectiveToken->ImpersonationLevel < SecurityImpersonation) {
  284. return( FALSE );
  285. }
  286. }
  287. Index = 0;
  288. SepAcquireTokenReadLock( EffectiveToken );
  289. //
  290. // Walk through the list of user and group IDs looking
  291. // for a match to the specified SID. If one is found,
  292. // make sure it may be assigned as an owner.
  293. //
  294. // This code is similar to that performed to set the default
  295. // owner of a token (NtSetInformationToken).
  296. //
  297. while (Index < EffectiveToken->UserAndGroupCount) {
  298. Found = RtlEqualSid(
  299. Owner,
  300. EffectiveToken->UserAndGroups[Index].Sid
  301. );
  302. if ( Found ) {
  303. //
  304. // We may return success if the Sid is one that may be assigned
  305. // as an owner, or if the caller has SeRestorePrivilege
  306. //
  307. if ( SepIdAssignableAsOwner(EffectiveToken,Index) ) {
  308. SepReleaseTokenReadLock( EffectiveToken );
  309. Rc = TRUE;
  310. goto exit;
  311. } else {
  312. //
  313. // Rc is already set to FALSE, just exit.
  314. //
  315. SepReleaseTokenReadLock( EffectiveToken );
  316. goto exit;
  317. } //endif assignable
  318. } //endif Found
  319. Index += 1;
  320. } //endwhile
  321. SepReleaseTokenReadLock( EffectiveToken );
  322. exit:
  323. //
  324. // If we are going to fail this call, check for Restore privilege,
  325. // and succeed if he has it.
  326. //
  327. //
  328. // We should really have gotten PreviousMode from the caller, but we
  329. // didn't, so hard wire it to be user-mode here.
  330. //
  331. if ( Rc == FALSE ) {
  332. Rc = SeSinglePrivilegeCheck( SeRestorePrivilege, UserMode );
  333. }
  334. return Rc;
  335. }
  336. #if 0
  337. NTSTATUS
  338. SeQueryAuthenticationIdSubjectContext(
  339. IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
  340. OUT PLUID AuthenticationId
  341. )
  342. /*++
  343. Routine Description:
  344. This routine returns the authentication ID for the effective token
  345. in a subject context
  346. Parameters:
  347. SubjectContext - The subject context to get the ID from
  348. AuthenticationId - Receives the authentication ID from the token
  349. Return Value:
  350. Errors from SeQueryAuthenticationidToken.
  351. --*/
  352. {
  353. NTSTATUS Status;
  354. PAGED_CODE();
  355. SeLockSubjectContext( SubjectContext );
  356. Status = SeQueryAuthenticationIdToken(
  357. EffectiveToken(SubjectContext),
  358. AuthenticationId
  359. );
  360. SeUnlockSubjectContext( SubjectContext );
  361. return( Status );
  362. }
  363. #endif