Main Page | Class Hierarchy | Class List | File List | Class Members | File Members

seclient.c

Go to the documentation of this file.
00001 00002 /*++ 00003 00004 Copyright (c) 1989 Microsoft Corporation 00005 00006 Module Name: 00007 00008 seclient.c 00009 00010 Abstract: 00011 00012 This module implements routines providing client impersonation to 00013 communication session layers (such as LPC Ports). 00014 00015 WARNING: The following notes apply to the use of these services: 00016 00017 (1) No synchronization of operations to a security context block are 00018 performed by these services. The caller of these services must 00019 ensure that use of an individual security context block is 00020 serialized to prevent simultaneous, incompatible updates. 00021 00022 (2) Any or all of these services may create, open, or operate on a 00023 token object. This may result in a mutex being acquired at 00024 MUTEXT_LEVEL_SE_TOKEN level. The caller must ensure that no 00025 mutexes are held at levels that conflict with this action. 00026 00027 00028 Author: 00029 00030 Jim Kelly (JimK) 1-August-1990 00031 00032 Environment: 00033 00034 Kernel mode only. 00035 00036 Revision History: 00037 00038 --*/ 00039 00040 00041 #include "sep.h" 00042 #include "seopaque.h" 00043 00044 00045 #ifdef ALLOC_PRAGMA 00046 #pragma alloc_text(PAGE,SeCreateClientSecurity) 00047 #pragma alloc_text(PAGE,SeUpdateClientSecurity) 00048 #pragma alloc_text(PAGE,SeImpersonateClient) 00049 #pragma alloc_text(PAGE,SeImpersonateClientEx) 00050 #pragma alloc_text(PAGE,SeCreateClientSecurityFromSubjectContext) 00051 #endif 00052 00053 00055 // // 00056 // Routines // 00057 // // 00059 00060 00061 NTSTATUS 00062 SepCreateClientSecurity( 00063 IN PACCESS_TOKEN Token, 00064 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, 00065 IN BOOLEAN ServerIsRemote, 00066 TOKEN_TYPE TokenType, 00067 BOOLEAN ThreadEffectiveOnly, 00068 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel, 00069 OUT PSECURITY_CLIENT_CONTEXT ClientContext 00070 ) 00071 { 00072 NTSTATUS Status = STATUS_SUCCESS; 00073 PACCESS_TOKEN DuplicateToken; 00074 00075 PAGED_CODE(); 00076 00077 00078 // 00079 // Make sure the client is not trying to abuse use of a 00080 // client of its own by attempting an invalid impersonation. 00081 // Also set the ClientContext->DirectAccessEffectiveOnly flag 00082 // appropriately if the impersonation is legitimate. The 00083 // DirectAccessEffectiveOnly flag value will end up being ignored 00084 // if STATIC mode is requested, but this is the most efficient 00085 // place to calculate it, and we are optimizing for DYNAMIC mode. 00086 // 00087 00088 if (TokenType == TokenImpersonation) { 00089 00090 if ( ClientSecurityQos->ImpersonationLevel > ImpersonationLevel) { 00091 00092 PsDereferenceImpersonationToken( Token ); 00093 return STATUS_BAD_IMPERSONATION_LEVEL; 00094 00095 } 00096 00097 00098 if ( SepBadImpersonationLevel(ImpersonationLevel,ServerIsRemote)) { 00099 00100 PsDereferenceImpersonationToken( Token ); 00101 return STATUS_BAD_IMPERSONATION_LEVEL; 00102 00103 } else { 00104 00105 // 00106 // TokenType is TokenImpersonation and the impersonation is legit. 00107 // Set the DirectAccessEffectiveOnly flag to be the minimum of 00108 // the current thread value and the caller specified value. 00109 // 00110 00111 ClientContext->DirectAccessEffectiveOnly = 00112 ( (ThreadEffectiveOnly || (ClientSecurityQos->EffectiveOnly)) ? 00113 TRUE : FALSE ); 00114 } 00115 00116 } else { 00117 00118 // 00119 // TokenType is TokenPrimary. In this case, the client specified 00120 // EffectiveOnly value is always used. 00121 // 00122 00123 ClientContext->DirectAccessEffectiveOnly = 00124 ClientSecurityQos->EffectiveOnly; 00125 } 00126 00127 00128 00129 // 00130 // Copy the token if necessary (i.e., static tracking requested) 00131 // 00132 00133 if (ClientSecurityQos->ContextTrackingMode == SECURITY_STATIC_TRACKING) { 00134 00135 ClientContext->DirectlyAccessClientToken = FALSE; 00136 00137 Status = SeCopyClientToken( 00138 Token, 00139 ClientSecurityQos->ImpersonationLevel, 00140 KernelMode, 00141 &DuplicateToken 00142 ); 00143 00144 00145 if ( NT_SUCCESS(Status) ) { 00146 ObDeleteCapturedInsertInfo(DuplicateToken); 00147 } 00148 // 00149 // No longer need the pointer to the client's token 00150 // 00151 00152 if (TokenType == TokenPrimary) { 00153 PsDereferencePrimaryToken( Token ); 00154 } else { 00155 PsDereferenceImpersonationToken( Token ); 00156 } 00157 00158 Token = DuplicateToken; 00159 00160 00161 // 00162 // If there was an error, we're done. 00163 // 00164 if (!NT_SUCCESS(Status)) { 00165 return Status; 00166 } 00167 00168 } else { 00169 00170 ClientContext->DirectlyAccessClientToken = TRUE; 00171 00172 if (ServerIsRemote) { 00173 // 00174 // Get a copy of the client token's control information 00175 // so that we can tell if it changes in the future. 00176 // 00177 00178 SeGetTokenControlInformation( Token, 00179 &ClientContext->ClientTokenControl 00180 ); 00181 00182 } 00183 00184 } 00185 00186 00187 00188 ClientContext->SecurityQos.Length = 00189 (ULONG)sizeof(SECURITY_QUALITY_OF_SERVICE); 00190 00191 ClientContext->SecurityQos.ImpersonationLevel = 00192 ClientSecurityQos->ImpersonationLevel; 00193 00194 ClientContext->SecurityQos.ContextTrackingMode = 00195 ClientSecurityQos->ContextTrackingMode; 00196 00197 ClientContext->SecurityQos.EffectiveOnly = 00198 ClientSecurityQos->EffectiveOnly; 00199 00200 ClientContext->ServerIsRemote = ServerIsRemote; 00201 00202 ClientContext->ClientToken = Token; 00203 00204 return STATUS_SUCCESS; 00205 00206 } 00207 00208 NTSTATUS 00209 SeCreateClientSecurity ( 00210 IN PETHREAD ClientThread, 00211 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, 00212 IN BOOLEAN ServerIsRemote, 00213 OUT PSECURITY_CLIENT_CONTEXT ClientContext 00214 ) 00215 00216 /*++ 00217 00218 Routine Description: 00219 00220 This service initializes a context block to represent a client's 00221 security context. This may simply result in a reference to the 00222 client's token, or may cause the client's token to be duplicated, 00223 depending upon the security quality of service information specified. 00224 00225 NOTE 00226 00227 The code in this routine is optimized for DYNAMIC context 00228 tracking. This is only mode in which direct access to a 00229 caller's token is allowed, and the mode expected to be used 00230 most often. STATIC context tracking always requires the 00231 caller's token to be copied. 00232 00233 00234 Arguments: 00235 00236 ClientThread - Points to the client's thread. This is used to 00237 locate the client's security context (token). 00238 00239 ClientSecurityQos - Points to the security quality of service 00240 parameters specified by the client for this communication 00241 session. 00242 00243 ServerIsRemote - Provides an indication as to whether the session 00244 this context block is being used for is an inter-system 00245 session or intra-system session. This is reconciled with the 00246 impersonation level of the client thread's token (in case the 00247 client has a client of his own that didn't specify delegation). 00248 00249 ClientContext - Points to the client security context block to be 00250 initialized. 00251 00252 00253 Return Value: 00254 00255 STATUS_SUCCESS - The service completed successfully. 00256 00257 STATUS_BAD_IMPERSONATION_LEVEL - The client is currently 00258 impersonating either an Anonymous or Identification level 00259 token, which can not be passed on for use by another server. 00260 This status may also be returned if the security context 00261 block is for an inter-system communication session and the 00262 client thread is impersonating a client of its own using 00263 other than delegation impersonation level. 00264 00265 00266 --*/ 00267 00268 { 00269 NTSTATUS Status = STATUS_SUCCESS; 00270 PACCESS_TOKEN Token; 00271 TOKEN_TYPE TokenType; 00272 BOOLEAN ThreadEffectiveOnly; 00273 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 00274 PACCESS_TOKEN DuplicateToken; 00275 00276 PAGED_CODE(); 00277 00278 // 00279 // Gain access to the client thread's effective token 00280 // 00281 00282 Token = PsReferenceEffectiveToken( 00283 ClientThread, 00284 &TokenType, 00285 &ThreadEffectiveOnly, 00286 &ImpersonationLevel 00287 ); 00288 00289 00290 Status = SepCreateClientSecurity( 00291 Token, 00292 ClientSecurityQos, 00293 ServerIsRemote, 00294 TokenType, 00295 ThreadEffectiveOnly, 00296 ImpersonationLevel, 00297 ClientContext ); 00298 00299 return Status ; 00300 } 00301 00302 00303 00304 #if SAVE_FOR_PRODUCT_2 00305 00306 00307 00308 00309 NTSTATUS 00310 SeUpdateClientSecurity( 00311 IN PETHREAD ClientThread, 00312 IN OUT PSECURITY_CLIENT_CONTEXT ClientContext, 00313 OUT PBOOLEAN ChangesMade, 00314 OUT PBOOLEAN NewToken 00315 ) 00316 00317 /*++ 00318 00319 Routine Description: 00320 00321 This service is used to update a client security context block 00322 based upon the client's current security context and the security 00323 quality of service parameters specified when the security block 00324 was created. If the SecurityContextTracking specified when the 00325 context block was created indicated static tracking, then no 00326 change will be made to the context block. Otherwise, a change may 00327 be made. 00328 00329 00330 An indication of whether any changes were made is returned to the 00331 caller. This may be used by communication session layers 00332 providing remote communications to decide whether or not to send 00333 an updated security context to the remote server's node. It may 00334 also be used by a server session layer to decide whether or not to 00335 inform a server that a previously obtained handle to a token no 00336 longer represents the current security context. 00337 00338 00339 Arguments: 00340 00341 ClientThread - Points to the client's thread. This is used to 00342 locate the security context to synchronize with. 00343 00344 ClientContext - Points to client security context block to be 00345 updated. 00346 00347 ChangesMade - Receives an indication as to whether any changes to 00348 the client's security context had been made since the last 00349 time the security context block was synchronized. This will 00350 always be FALSE if static security tracking is in effect. 00351 00352 NewToken - Receives an indication as to whether the same token 00353 is used to represent the client's current context, or whether 00354 the context now points to a new token. If the client's token 00355 is directly referenced, then this indicates the client changed 00356 tokens (and the new one is now referenced). If the client's token 00357 isn't directly referenced, then this indicates it was necessary 00358 to delete one token and create another one. This will always be 00359 FALSE if static security tracking is in effect. 00360 00361 00362 Return Value: 00363 00364 STATUS_SUCCESS - The service completed successfully. 00365 00366 STATUS_BAD_IMPERSONATION_LEVEL - The client is currently 00367 impersonating either an Anonymous or Identification level 00368 token, which can not be passed on for use by another server. 00369 This status may also be returned if the security context 00370 block is for an inter-system communication session and the 00371 client thread is impersonating a client of its own using 00372 other than delegation impersonation level. 00373 00374 00375 --*/ 00376 00377 { 00378 NTSTATUS Status; 00379 PACCESS_TOKEN Token; 00380 TOKEN_TYPE TokenType; 00381 BOOLEAN ThreadEffectiveOnly; 00382 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 00383 PACCESS_TOKEN DuplicateToken; 00384 TOKEN_CONTROL TokenControl; 00385 00386 PAGED_CODE(); 00387 00388 if (ClientContext->SecurityQos.ContextTrackingMode == 00389 SECURITY_STATIC_TRACKING) { 00390 00391 (*NewToken) = FALSE; 00392 (*ChangesMade) = FALSE; 00393 return STATUS_SUCCESS; 00394 00395 } 00396 00397 00399 // // 00400 // Optimize for the directly accessed token // 00401 // // 00403 00404 00405 00406 // 00407 // Gain access to the client thread's effective token 00408 // 00409 00410 Token = PsReferenceEffectiveToken( 00411 ClientThread, 00412 &TokenType, 00413 &ThreadEffectiveOnly, 00414 &ImpersonationLevel 00415 ); 00416 00417 00418 00419 // 00420 // See if the token is the same. 00421 // 00422 00423 00424 SeGetTokenControlInformation( Token, &TokenControl ); 00425 00426 if ( SeSameToken( &TokenControl, 00427 &ClientContext->ClientTokenControl) ) { 00428 00429 (*NewToken = FALSE); 00430 00431 00432 // 00433 // Same token. 00434 // Is it unmodified? 00435 // 00436 00437 if ( (TokenControl.ModifiedId.HighPart == 00438 ClientContext->ClientTokenControl.ModifiedId.HighPart) && 00439 (TokenControl.ModifiedId.LowPart == 00440 ClientContext->ClientTokenControl.ModifiedId.LowPart) ) { 00441 00442 // 00443 // Yup. No changes necessary. 00444 // 00445 00446 if (TokenType == TokenPrimary) { 00447 PsDereferencePrimaryToken( Token ); 00448 } else { 00449 PsDereferenceImpersonationToken( Token ); 00450 } 00451 00452 (*ChangesMade) = FALSE; 00453 return STATUS_SUCCESS; 00454 00455 } else { 00456 00457 // 00458 // Same token, but it has been modified. 00459 // If we are directly accessing the token, then we can 00460 // just indicate it has changed and return. Otherwise 00461 // we have to actually update our copy of the token. 00462 // 00463 00464 (*ChangesMade) = TRUE; 00465 if (ClientContext->DirectlyAccessClientToken) { 00466 00467 if (TokenType == TokenPrimary) { 00468 PsDereferencePrimaryToken( Token ); 00469 } else { 00470 PsDereferenceImpersonationToken( Token ); 00471 } 00472 00473 // 00474 // Save the new modified count and whether or not 00475 // the token is for effective use only 00476 // 00477 00478 ClientContext->ClientTokenControl.ModifiedId = 00479 TokenControl.ModifiedId; 00480 ClientContext->DirectAccessEffectiveOnly = 00481 ( (ThreadEffectiveOnly || (ClientContext->SecurityQos.EffectiveOnly)) ? 00482 TRUE : FALSE ); 00483 00484 return STATUS_SUCCESS; 00485 } else { 00486 00487 // 00488 // There is a possibility for a fair performance gain here 00489 // by just updating the existing token to match its origin. 00490 // However, it isn't clear that this case is ever really 00491 // used, so the effort and complexity is avoided at this time. 00492 // If it is found that this case is used, then this code 00493 // can be added. 00494 // 00495 // Instead, we just fall through to the case of completely 00496 // different tokens below. 00497 // 00498 } 00499 } 00500 } 00501 00502 00503 // 00504 // Not the same token, or the same token has changed. 00505 // In either case, we're going to create a new copy of the token 00506 // and dump the old copy. 00507 // 00508 // Make sure the current impersonation situation is legitimate. 00509 // 00510 00511 (*NewToken) = TRUE; 00512 (*ChangesMade) = TRUE; 00513 if (TokenType == TokenImpersonation) { 00514 if ( SepBadImpersonationLevel(ImpersonationLevel, 00515 ClientContext->ServerIsRemote)) { 00516 00517 PsDereferenceImpersonationToken( Token ); 00518 return STATUS_BAD_IMPERSONATION_LEVEL; 00519 } 00520 } 00521 00522 00523 // 00524 // Copy the token 00525 // 00526 00527 00528 00529 Status = SeCopyClientToken( 00530 Token, 00531 ClientContext->SecurityQos.ImpersonationLevel, 00532 KernelMode, 00533 &DuplicateToken 00534 ); 00535 00536 00537 // 00538 // No longer need the pointer to the client's effective token 00539 // 00540 00541 if (TokenType == TokenPrimary) { 00542 PsDereferencePrimaryToken( Token ); 00543 } else { 00544 PsDereferenceImpersonationToken( Token ); 00545 } 00546 00547 00548 00549 // 00550 // If there was an error, we're done. 00551 // 00552 if (!NT_SUCCESS(Status)) { 00553 return Status; 00554 } 00555 00556 00557 // 00558 // Otherwise, replace the current token with the new one. 00559 // 00560 00561 Token = ClientContext->ClientToken; 00562 ClientContext->ClientToken = DuplicateToken; 00563 ClientContext->DirectlyAccessClientToken = FALSE; 00564 00565 if (SeTokenType( Token ) == TokenPrimary) { 00566 PsDereferencePrimaryToken( Token ); 00567 } else { 00568 PsDereferenceImpersonationToken( Token ); 00569 } 00570 00571 00572 // 00573 // Get a copy of the current token's control information 00574 // so that we can tell if it changes in the future. 00575 // 00576 00577 SeGetTokenControlInformation( DuplicateToken, 00578 &ClientContext->ClientTokenControl 00579 ); 00580 00581 00582 return STATUS_SUCCESS; 00583 00584 } 00585 00586 00587 #endif 00588 00589 00590 00591 00592 VOID 00593 SeImpersonateClient( 00594 IN PSECURITY_CLIENT_CONTEXT ClientContext, 00595 IN PETHREAD ServerThread OPTIONAL 00596 ) 00597 /*++ 00598 00599 Routine Description: 00600 00601 This service is used to cause the calling thread to impersonate a 00602 client. The client security context in ClientContext is assumed to 00603 be up to date. 00604 00605 00606 Arguments: 00607 00608 ClientContext - Points to client security context block. 00609 00610 ServerThread - (Optional) Specifies the thread which is to be made to 00611 impersonate the client. If not specified, the calling thread is 00612 used. 00613 00614 00615 Return Value: 00616 00617 None. 00618 00619 00620 --*/ 00621 00622 00623 { 00624 00625 PAGED_CODE(); 00626 00627 #if DBG 00628 DbgPrint("SE: Obsolete call: SeImpersonateClient\n"); 00629 #endif 00630 00631 (VOID) SeImpersonateClientEx( ClientContext, ServerThread ); 00632 } 00633 00634 00635 NTSTATUS 00636 SeImpersonateClientEx( 00637 IN PSECURITY_CLIENT_CONTEXT ClientContext, 00638 IN PETHREAD ServerThread OPTIONAL 00639 ) 00640 /*++ 00641 00642 Routine Description: 00643 00644 This service is used to cause the calling thread to impersonate a 00645 client. The client security context in ClientContext is assumed to 00646 be up to date. 00647 00648 00649 Arguments: 00650 00651 ClientContext - Points to client security context block. 00652 00653 ServerThread - (Optional) Specifies the thread which is to be made to 00654 impersonate the client. If not specified, the calling thread is 00655 used. 00656 00657 00658 Return Value: 00659 00660 None. 00661 00662 00663 --*/ 00664 00665 00666 { 00667 00668 BOOLEAN EffectiveValueToUse; 00669 PETHREAD Thread; 00670 NTSTATUS Status ; 00671 00672 PAGED_CODE(); 00673 00674 if (ClientContext->DirectlyAccessClientToken) { 00675 EffectiveValueToUse = ClientContext->DirectAccessEffectiveOnly; 00676 } else { 00677 EffectiveValueToUse = ClientContext->SecurityQos.EffectiveOnly; 00678 } 00679 00680 00681 00682 // 00683 // if a ServerThread wasn't specified, then default to the current 00684 // thread. 00685 // 00686 00687 if (!ARGUMENT_PRESENT(ServerThread)) { 00688 Thread = PsGetCurrentThread(); 00689 } else { 00690 Thread = ServerThread; 00691 } 00692 00693 00694 00695 // 00696 // Assign the context to the calling thread 00697 // 00698 00699 Status = PsImpersonateClient( Thread, 00700 ClientContext->ClientToken, 00701 TRUE, 00702 EffectiveValueToUse, 00703 ClientContext->SecurityQos.ImpersonationLevel 00704 ); 00705 00706 return Status ; 00707 00708 } 00709 00710 00711 NTSTATUS 00712 SeCreateClientSecurityFromSubjectContext ( 00713 IN PSECURITY_SUBJECT_CONTEXT SubjectContext, 00714 IN PSECURITY_QUALITY_OF_SERVICE ClientSecurityQos, 00715 IN BOOLEAN ServerIsRemote, 00716 OUT PSECURITY_CLIENT_CONTEXT ClientContext 00717 ) 00718 /*++ 00719 00720 Routine Description: 00721 00722 This service initializes a context block to represent a client's 00723 security context. This may simply result in a reference to the 00724 client's token, or may cause the client's token to be duplicated, 00725 depending upon the security quality of service information specified. 00726 00727 NOTE 00728 00729 The code in this routine is optimized for DYNAMIC context 00730 tracking. This is only mode in which direct access to a 00731 caller's token is allowed, and the mode expected to be used 00732 most often. STATIC context tracking always requires the 00733 caller's token to be copied. 00734 00735 00736 Arguments: 00737 00738 SubjectContext - Points to the SubjectContext that should serve 00739 as the basis for this client context. 00740 00741 ClientSecurityQos - Points to the security quality of service 00742 parameters specified by the client for this communication 00743 session. 00744 00745 ServerIsRemote - Provides an indication as to whether the session 00746 this context block is being used for is an inter-system 00747 session or intra-system session. This is reconciled with the 00748 impersonation level of the client thread's token (in case the 00749 client has a client of his own that didn't specify delegation). 00750 00751 ClientContext - Points to the client security context block to be 00752 initialized. 00753 00754 00755 Return Value: 00756 00757 STATUS_SUCCESS - The service completed successfully. 00758 00759 STATUS_BAD_IMPERSONATION_LEVEL - The client is currently 00760 impersonating either an Anonymous or Identification level 00761 token, which can not be passed on for use by another server. 00762 This status may also be returned if the security context 00763 block is for an inter-system communication session and the 00764 client thread is impersonating a client of its own using 00765 other than delegation impersonation level. 00766 00767 00768 --*/ 00769 00770 { 00771 NTSTATUS Status = STATUS_SUCCESS; 00772 PACCESS_TOKEN Token; 00773 TOKEN_TYPE Type; 00774 BOOLEAN ThreadEffectiveOnly; 00775 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 00776 PACCESS_TOKEN DuplicateToken; 00777 00778 PAGED_CODE(); 00779 00780 Token = SeQuerySubjectContextToken( 00781 SubjectContext 00782 ); 00783 00784 ObReferenceObject( Token ); 00785 00786 if ( SubjectContext->ClientToken ) 00787 { 00788 Type = TokenImpersonation ; 00789 } 00790 else 00791 { 00792 Type = TokenPrimary ; 00793 } 00794 00795 Status = SepCreateClientSecurity( 00796 Token, 00797 ClientSecurityQos, 00798 ServerIsRemote, 00799 Type, 00800 FALSE, 00801 SubjectContext->ImpersonationLevel, 00802 ClientContext 00803 ); 00804 00805 00806 return Status ; 00807 } 00808

Generated on Sat May 15 19:41:44 2004 for test by doxygen 1.3.7