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.

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