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.

854 lines
24 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. seclient.c
  5. Abstract:
  6. This module implements routines providing client impersonation to
  7. communication session layers (such as LPC Ports).
  8. WARNING: The following notes apply to the use of these services:
  9. (1) No synchronization of operations to a security context block are
  10. performed by these services. The caller of these services must
  11. ensure that use of an individual security context block is
  12. serialized to prevent simultaneous, incompatible updates.
  13. (2) Any or all of these services may create, open, or operate on a
  14. token object. This may result in a mutex being acquired at
  15. MUTEXT_LEVEL_SE_TOKEN level. The caller must ensure that no
  16. mutexes are held at levels that conflict with this action.
  17. Author:
  18. Jim Kelly (JimK) 1-August-1990
  19. Environment:
  20. Kernel mode only.
  21. Revision History:
  22. --*/
  23. #include "pch.h"
  24. #pragma hdrstop
  25. #ifdef ALLOC_PRAGMA
  26. NTSTATUS
  27. SepCreateClientSecurity(
  28. IN PACCESS_TOKEN Token,
  29. IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
  30. IN BOOLEAN ServerIsRemote,
  31. TOKEN_TYPE TokenType,
  32. BOOLEAN ThreadEffectiveOnly,
  33. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  34. OUT PSECURITY_CLIENT_CONTEXT ClientContext
  35. );
  36. #pragma alloc_text(PAGE,SepCreateClientSecurity)
  37. #pragma alloc_text(PAGE,SeCreateClientSecurity)
  38. #pragma alloc_text(PAGE,SeUpdateClientSecurity)
  39. #pragma alloc_text(PAGE,SeImpersonateClient)
  40. #pragma alloc_text(PAGE,SeImpersonateClientEx)
  41. #pragma alloc_text(PAGE,SeCreateClientSecurityFromSubjectContext)
  42. #endif
  43. ////////////////////////////////////////////////////////////////////////
  44. // //
  45. // Routines //
  46. // //
  47. ////////////////////////////////////////////////////////////////////////
  48. NTSTATUS
  49. SepCreateClientSecurity(
  50. IN PACCESS_TOKEN Token,
  51. IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
  52. IN BOOLEAN ServerIsRemote,
  53. TOKEN_TYPE TokenType,
  54. BOOLEAN ThreadEffectiveOnly,
  55. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel,
  56. OUT PSECURITY_CLIENT_CONTEXT ClientContext
  57. )
  58. /*++
  59. Routine Description
  60. This routine creates a context block to represent the passed token. The token
  61. is expected to be properly referenced when passed to the function. If the call
  62. is unsuccessful, the caller is responsible to dereference the token. Also, if the
  63. call succeeds but the caller requested SECURITY_STATIC_TRACKING, then we have duplicated
  64. the token and the caller is again responsible to dereference the passed token.
  65. Arguments
  66. Token - The effective token for which the context is constructed.
  67. ClientSecurityQos - Points to the security quality of service
  68. parameters specified by the client for this communication
  69. session.
  70. ServerIsRemote - Provides an indication as to whether the session
  71. this context block is being used for is an inter-system
  72. session or intra-system session. This is reconciled with the
  73. impersonation level of the client thread's token (in case the
  74. client has a client of his own that didn't specify delegation).
  75. TokenType - specifies the type of the passed token.
  76. ThreadEffectiveOnly - if the token is an impersonation token, then this
  77. is the thread's ImpersonationInfo->EffectiveOnly field value.
  78. ImpersonationLevel - the impersonation level of the token.
  79. ClientContext - Points to the client security context block to be
  80. initialized.
  81. Return Value
  82. --*/
  83. {
  84. NTSTATUS Status = STATUS_SUCCESS;
  85. PACCESS_TOKEN DuplicateToken;
  86. PAGED_CODE();
  87. if ( !VALID_IMPERSONATION_LEVEL(ClientSecurityQos->ImpersonationLevel) ) {
  88. return STATUS_INVALID_PARAMETER;
  89. }
  90. //
  91. // Make sure the client is not trying to abuse use of a
  92. // client of its own by attempting an invalid impersonation.
  93. // Also set the ClientContext->DirectAccessEffectiveOnly flag
  94. // appropriately if the impersonation is legitimate. The
  95. // DirectAccessEffectiveOnly flag value will end up being ignored
  96. // if STATIC mode is requested, but this is the most efficient
  97. // place to calculate it, and we are optimizing for DYNAMIC mode.
  98. //
  99. if (TokenType == TokenImpersonation) {
  100. if ( ClientSecurityQos->ImpersonationLevel > ImpersonationLevel) {
  101. return STATUS_BAD_IMPERSONATION_LEVEL;
  102. }
  103. if ( SepBadImpersonationLevel(ImpersonationLevel,ServerIsRemote)) {
  104. return STATUS_BAD_IMPERSONATION_LEVEL;
  105. } else {
  106. //
  107. // TokenType is TokenImpersonation and the impersonation is legit.
  108. // Set the DirectAccessEffectiveOnly flag to be the minimum of
  109. // the current thread value and the caller specified value.
  110. //
  111. ClientContext->DirectAccessEffectiveOnly =
  112. ( (ThreadEffectiveOnly || (ClientSecurityQos->EffectiveOnly)) ?
  113. TRUE : FALSE );
  114. }
  115. } else {
  116. //
  117. // TokenType is TokenPrimary. In this case, the client specified
  118. // EffectiveOnly value is always used.
  119. //
  120. ClientContext->DirectAccessEffectiveOnly =
  121. ClientSecurityQos->EffectiveOnly;
  122. }
  123. //
  124. // Copy the token if necessary (i.e., static tracking requested)
  125. //
  126. if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING) {
  127. ClientContext->DirectlyAccessClientToken = FALSE;
  128. Status = SeCopyClientToken(
  129. Token,
  130. ClientSecurityQos->ImpersonationLevel,
  131. KernelMode,
  132. &DuplicateToken
  133. );
  134. Token = DuplicateToken;
  135. //
  136. // If there was an error, we're done.
  137. //
  138. if (!NT_SUCCESS(Status)) {
  139. return Status;
  140. }
  141. } else {
  142. ClientContext->DirectlyAccessClientToken = TRUE;
  143. if (ServerIsRemote) {
  144. //
  145. // Get a copy of the client token's control information
  146. // so that we can tell if it changes in the future.
  147. //
  148. SeGetTokenControlInformation( Token,
  149. &ClientContext->ClientTokenControl
  150. );
  151. }
  152. }
  153. ClientContext->SecurityQos.Length =
  154. (ULONG)sizeof(SECURITY_QUALITY_OF_SERVICE);
  155. ClientContext->SecurityQos.ImpersonationLevel =
  156. ClientSecurityQos->ImpersonationLevel;
  157. ClientContext->SecurityQos.ContextTrackingMode =
  158. ClientSecurityQos->ContextTrackingMode;
  159. ClientContext->SecurityQos.EffectiveOnly =
  160. ClientSecurityQos->EffectiveOnly;
  161. ClientContext->ServerIsRemote = ServerIsRemote;
  162. ClientContext->ClientToken = Token;
  163. return STATUS_SUCCESS;
  164. }
  165. NTSTATUS
  166. SeCreateClientSecurity (
  167. IN PETHREAD ClientThread,
  168. IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
  169. IN BOOLEAN ServerIsRemote,
  170. OUT PSECURITY_CLIENT_CONTEXT ClientContext
  171. )
  172. /*++
  173. Routine Description:
  174. This service initializes a context block to represent a client's
  175. security context. This may simply result in a reference to the
  176. client's token, or may cause the client's token to be duplicated,
  177. depending upon the security quality of service information specified.
  178. NOTE
  179. The code in this routine is optimized for DYNAMIC context
  180. tracking. This is only mode in which direct access to a
  181. caller's token is allowed, and the mode expected to be used
  182. most often. STATIC context tracking always requires the
  183. caller's token to be copied.
  184. Arguments:
  185. ClientThread - Points to the client's thread. This is used to
  186. locate the client's security context (token).
  187. ClientSecurityQos - Points to the security quality of service
  188. parameters specified by the client for this communication
  189. session.
  190. ServerIsRemote - Provides an indication as to whether the session
  191. this context block is being used for is an inter-system
  192. session or intra-system session. This is reconciled with the
  193. impersonation level of the client thread's token (in case the
  194. client has a client of his own that didn't specify delegation).
  195. ClientContext - Points to the client security context block to be
  196. initialized.
  197. Return Value:
  198. STATUS_SUCCESS - The service completed successfully.
  199. STATUS_BAD_IMPERSONATION_LEVEL - The client is currently
  200. impersonating either an Anonymous or Identification level
  201. token, which can not be passed on for use by another server.
  202. This status may also be returned if the security context
  203. block is for an inter-system communication session and the
  204. client thread is impersonating a client of its own using
  205. other than delegation impersonation level.
  206. --*/
  207. {
  208. NTSTATUS Status = STATUS_SUCCESS;
  209. PACCESS_TOKEN Token;
  210. TOKEN_TYPE TokenType;
  211. BOOLEAN ThreadEffectiveOnly;
  212. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  213. PACCESS_TOKEN DuplicateToken;
  214. PAGED_CODE();
  215. //
  216. // Gain access to the client thread's effective token
  217. //
  218. Token = PsReferenceEffectiveToken(
  219. ClientThread,
  220. &TokenType,
  221. &ThreadEffectiveOnly,
  222. &ImpersonationLevel
  223. );
  224. Status = SepCreateClientSecurity(
  225. Token,
  226. ClientSecurityQos,
  227. ServerIsRemote,
  228. TokenType,
  229. ThreadEffectiveOnly,
  230. ImpersonationLevel,
  231. ClientContext );
  232. //
  233. // If failed, or if a token was copied internally, then deref our token.
  234. //
  235. if ((!NT_SUCCESS( Status )) || (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)) {
  236. ObDereferenceObject( Token );
  237. }
  238. return Status;
  239. }
  240. #if SAVE_FOR_PRODUCT_2
  241. NTSTATUS
  242. SeUpdateClientSecurity(
  243. IN PETHREAD ClientThread,
  244. IN OUT PSECURITY_CLIENT_CONTEXT ClientContext,
  245. OUT PBOOLEAN ChangesMade,
  246. OUT PBOOLEAN NewToken
  247. )
  248. /*++
  249. Routine Description:
  250. This service is used to update a client security context block
  251. based upon the client's current security context and the security
  252. quality of service parameters specified when the security block
  253. was created. If the SecurityContextTracking specified when the
  254. context block was created indicated static tracking, then no
  255. change will be made to the context block. Otherwise, a change may
  256. be made.
  257. An indication of whether any changes were made is returned to the
  258. caller. This may be used by communication session layers
  259. providing remote communications to decide whether or not to send
  260. an updated security context to the remote server's node. It may
  261. also be used by a server session layer to decide whether or not to
  262. inform a server that a previously obtained handle to a token no
  263. longer represents the current security context.
  264. Arguments:
  265. ClientThread - Points to the client's thread. This is used to
  266. locate the security context to synchronize with.
  267. ClientContext - Points to client security context block to be
  268. updated.
  269. ChangesMade - Receives an indication as to whether any changes to
  270. the client's security context had been made since the last
  271. time the security context block was synchronized. This will
  272. always be FALSE if static security tracking is in effect.
  273. NewToken - Receives an indication as to whether the same token
  274. is used to represent the client's current context, or whether
  275. the context now points to a new token. If the client's token
  276. is directly referenced, then this indicates the client changed
  277. tokens (and the new one is now referenced). If the client's token
  278. isn't directly referenced, then this indicates it was necessary
  279. to delete one token and create another one. This will always be
  280. FALSE if static security tracking is in effect.
  281. Return Value:
  282. STATUS_SUCCESS - The service completed successfully.
  283. STATUS_BAD_IMPERSONATION_LEVEL - The client is currently
  284. impersonating either an Anonymous or Identification level
  285. token, which can not be passed on for use by another server.
  286. This status may also be returned if the security context
  287. block is for an inter-system communication session and the
  288. client thread is impersonating a client of its own using
  289. other than delegation impersonation level.
  290. --*/
  291. {
  292. NTSTATUS Status;
  293. PACCESS_TOKEN Token;
  294. TOKEN_TYPE TokenType;
  295. BOOLEAN ThreadEffectiveOnly;
  296. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  297. PACCESS_TOKEN DuplicateToken;
  298. TOKEN_CONTROL TokenControl;
  299. PAGED_CODE();
  300. if (ClientContext->SecurityQos.ContextTrackingMode ==
  301. SECURITY_STATIC_TRACKING) {
  302. (*NewToken) = FALSE;
  303. (*ChangesMade) = FALSE;
  304. return STATUS_SUCCESS;
  305. }
  306. //////////////////////////////////////////////
  307. // //
  308. // Optimize for the directly accessed token //
  309. // //
  310. //////////////////////////////////////////////
  311. //
  312. // Gain access to the client thread's effective token
  313. //
  314. Token = PsReferenceEffectiveToken(
  315. ClientThread,
  316. &TokenType,
  317. &ThreadEffectiveOnly,
  318. &ImpersonationLevel
  319. );
  320. //
  321. // See if the token is the same.
  322. //
  323. SeGetTokenControlInformation( Token, &TokenControl );
  324. if ( SeSameToken( &TokenControl,
  325. &ClientContext->ClientTokenControl) ) {
  326. (*NewToken = FALSE);
  327. //
  328. // Same token.
  329. // Is it unmodified?
  330. //
  331. if ( (TokenControl.ModifiedId.HighPart ==
  332. ClientContext->ClientTokenControl.ModifiedId.HighPart) &&
  333. (TokenControl.ModifiedId.LowPart ==
  334. ClientContext->ClientTokenControl.ModifiedId.LowPart) ) {
  335. //
  336. // Yup. No changes necessary.
  337. //
  338. if (TokenType == TokenPrimary) {
  339. PsDereferencePrimaryTokenEx(THREAD_TO_PROCESS(ClientThread), Token );
  340. } else {
  341. PsDereferenceImpersonationToken( Token );
  342. }
  343. (*ChangesMade) = FALSE;
  344. return STATUS_SUCCESS;
  345. } else {
  346. //
  347. // Same token, but it has been modified.
  348. // If we are directly accessing the token, then we can
  349. // just indicate it has changed and return. Otherwise
  350. // we have to actually update our copy of the token.
  351. //
  352. (*ChangesMade) = TRUE;
  353. if (ClientContext->DirectlyAccessClientToken) {
  354. if (TokenType == TokenPrimary) {
  355. PsDereferencePrimaryTokenEx(THREAD_TO_PROCESS(ClientThread), Token);
  356. } else {
  357. PsDereferenceImpersonationToken (Token);
  358. }
  359. //
  360. // Save the new modified count and whether or not
  361. // the token is for effective use only
  362. //
  363. ClientContext->ClientTokenControl.ModifiedId =
  364. TokenControl.ModifiedId;
  365. ClientContext->DirectAccessEffectiveOnly =
  366. ( (ThreadEffectiveOnly || (ClientContext->SecurityQos.EffectiveOnly)) ?
  367. TRUE : FALSE );
  368. return STATUS_SUCCESS;
  369. } else {
  370. //
  371. // There is a possibility for a fair performance gain here
  372. // by just updating the existing token to match its origin.
  373. // However, it isn't clear that this case is ever really
  374. // used, so the effort and complexity is avoided at this time.
  375. // If it is found that this case is used, then this code
  376. // can be added.
  377. //
  378. // Instead, we just fall through to the case of completely
  379. // different tokens below.
  380. //
  381. }
  382. }
  383. }
  384. //
  385. // Not the same token, or the same token has changed.
  386. // In either case, we're going to create a new copy of the token
  387. // and dump the old copy.
  388. //
  389. // Make sure the current impersonation situation is legitimate.
  390. //
  391. (*NewToken) = TRUE;
  392. (*ChangesMade) = TRUE;
  393. if (TokenType == TokenImpersonation) {
  394. if ( SepBadImpersonationLevel(ImpersonationLevel,
  395. ClientContext->ServerIsRemote)) {
  396. PsDereferenceImpersonationToken(Token );
  397. return STATUS_BAD_IMPERSONATION_LEVEL;
  398. }
  399. }
  400. //
  401. // Copy the token
  402. //
  403. Status = SeCopyClientToken(
  404. Token,
  405. ClientContext->SecurityQos.ImpersonationLevel,
  406. KernelMode,
  407. &DuplicateToken
  408. );
  409. //
  410. // No longer need the pointer to the client's effective token
  411. //
  412. if (TokenType == TokenPrimary) {
  413. PsDereferencePrimaryToken( Token );
  414. } else {
  415. PsDereferenceImpersonationToken(Token );
  416. }
  417. //
  418. // If there was an error, we're done.
  419. //
  420. if (!NT_SUCCESS(Status)) {
  421. return Status;
  422. }
  423. //
  424. // Otherwise, replace the current token with the new one.
  425. //
  426. Token = ClientContext->ClientToken;
  427. ClientContext->ClientToken = DuplicateToken;
  428. ClientContext->DirectlyAccessClientToken = FALSE;
  429. if (SeTokenType( Token ) == TokenPrimary) {
  430. PsDereferencePrimaryToken( Token );
  431. } else {
  432. PsDereferenceImpersonationToken( Token );
  433. }
  434. //
  435. // Get a copy of the current token's control information
  436. // so that we can tell if it changes in the future.
  437. //
  438. SeGetTokenControlInformation( DuplicateToken,
  439. &ClientContext->ClientTokenControl
  440. );
  441. return STATUS_SUCCESS;
  442. }
  443. #endif
  444. VOID
  445. SeImpersonateClient(
  446. IN PSECURITY_CLIENT_CONTEXT ClientContext,
  447. IN PETHREAD ServerThread OPTIONAL
  448. )
  449. /*++
  450. Routine Description:
  451. This service is used to cause the calling thread to impersonate a
  452. client. The client security context in ClientContext is assumed to
  453. be up to date.
  454. Arguments:
  455. ClientContext - Points to client security context block.
  456. ServerThread - (Optional) Specifies the thread which is to be made to
  457. impersonate the client. If not specified, the calling thread is
  458. used.
  459. Return Value:
  460. None.
  461. --*/
  462. {
  463. PAGED_CODE();
  464. #if DBG
  465. DbgPrint("SE: Obsolete call: SeImpersonateClient\n");
  466. #endif
  467. (VOID) SeImpersonateClientEx( ClientContext, ServerThread );
  468. }
  469. NTSTATUS
  470. SeImpersonateClientEx(
  471. IN PSECURITY_CLIENT_CONTEXT ClientContext,
  472. IN PETHREAD ServerThread OPTIONAL
  473. )
  474. /*++
  475. Routine Description:
  476. This service is used to cause the calling thread to impersonate a
  477. client. The client security context in ClientContext is assumed to
  478. be up to date.
  479. Arguments:
  480. ClientContext - Points to client security context block.
  481. ServerThread - (Optional) Specifies the thread which is to be made to
  482. impersonate the client. If not specified, the calling thread is
  483. used.
  484. Return Value:
  485. None.
  486. --*/
  487. {
  488. BOOLEAN EffectiveValueToUse;
  489. PETHREAD Thread;
  490. NTSTATUS Status ;
  491. PAGED_CODE();
  492. if (ClientContext->DirectlyAccessClientToken) {
  493. EffectiveValueToUse = ClientContext->DirectAccessEffectiveOnly;
  494. } else {
  495. EffectiveValueToUse = ClientContext->SecurityQos.EffectiveOnly;
  496. }
  497. //
  498. // if a ServerThread wasn't specified, then default to the current
  499. // thread.
  500. //
  501. if (!ARGUMENT_PRESENT(ServerThread)) {
  502. Thread = PsGetCurrentThread();
  503. } else {
  504. Thread = ServerThread;
  505. }
  506. //
  507. // Assign the context to the calling thread
  508. //
  509. Status = PsImpersonateClient( Thread,
  510. ClientContext->ClientToken,
  511. TRUE,
  512. EffectiveValueToUse,
  513. ClientContext->SecurityQos.ImpersonationLevel
  514. );
  515. return Status ;
  516. }
  517. NTSTATUS
  518. SeCreateClientSecurityFromSubjectContext (
  519. IN PSECURITY_SUBJECT_CONTEXT SubjectContext,
  520. IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos,
  521. IN BOOLEAN ServerIsRemote,
  522. OUT PSECURITY_CLIENT_CONTEXT ClientContext
  523. )
  524. /*++
  525. Routine Description:
  526. This service initializes a context block to represent a client's
  527. security context. This may simply result in a reference to the
  528. client's token, or may cause the client's token to be duplicated,
  529. depending upon the security quality of service information specified.
  530. NOTE
  531. The code in this routine is optimized for DYNAMIC context
  532. tracking. This is only mode in which direct access to a
  533. caller's token is allowed, and the mode expected to be used
  534. most often. STATIC context tracking always requires the
  535. caller's token to be copied.
  536. Arguments:
  537. SubjectContext - Points to the SubjectContext that should serve
  538. as the basis for this client context.
  539. ClientSecurityQos - Points to the security quality of service
  540. parameters specified by the client for this communication
  541. session.
  542. ServerIsRemote - Provides an indication as to whether the session
  543. this context block is being used for is an inter-system
  544. session or intra-system session. This is reconciled with the
  545. impersonation level of the client thread's token (in case the
  546. client has a client of his own that didn't specify delegation).
  547. ClientContext - Points to the client security context block to be
  548. initialized.
  549. Return Value:
  550. STATUS_SUCCESS - The service completed successfully.
  551. STATUS_BAD_IMPERSONATION_LEVEL - The client is currently
  552. impersonating either an Anonymous or Identification level
  553. token, which can not be passed on for use by another server.
  554. This status may also be returned if the security context
  555. block is for an inter-system communication session and the
  556. client thread is impersonating a client of its own using
  557. other than delegation impersonation level.
  558. --*/
  559. {
  560. NTSTATUS Status = STATUS_SUCCESS;
  561. PACCESS_TOKEN Token;
  562. TOKEN_TYPE Type;
  563. BOOLEAN ThreadEffectiveOnly;
  564. SECURITY_IMPERSONATION_LEVEL ImpersonationLevel;
  565. PACCESS_TOKEN DuplicateToken;
  566. PAGED_CODE();
  567. Token = SeQuerySubjectContextToken(
  568. SubjectContext
  569. );
  570. ObReferenceObject( Token );
  571. if ( SubjectContext->ClientToken )
  572. {
  573. Type = TokenImpersonation ;
  574. }
  575. else
  576. {
  577. Type = TokenPrimary ;
  578. }
  579. Status = SepCreateClientSecurity(
  580. Token,
  581. ClientSecurityQos,
  582. ServerIsRemote,
  583. Type,
  584. FALSE,
  585. SubjectContext->ImpersonationLevel,
  586. ClientContext
  587. );
  588. //
  589. // If failed, or if a token was copied internally, then deref our token.
  590. //
  591. if ((!NT_SUCCESS( Status )) || (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING)) {
  592. ObDereferenceObject( Token );
  593. }
  594. return Status ;
  595. }