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

security.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 security.c 00008 00009 Abstract: 00010 00011 This module implements the security related portions of the process 00012 structure. 00013 00014 00015 Author: 00016 00017 Mark Lucovsky (markl) 25-Apr-1989 00018 Jim Kelly (JimK) 2-August-1990 00019 00020 Revision History: 00021 00022 --*/ 00023 00024 #include "psp.h" 00025 00026 00027 PACCESS_TOKEN 00028 PsReferencePrimaryToken( 00029 IN PEPROCESS Process 00030 ) 00031 00032 /*++ 00033 00034 Routine Description: 00035 00036 This function returns a pointer to the primary token of a process. 00037 The reference count of that primary token is incremented to protect 00038 the pointer returned. 00039 00040 When the pointer is no longer needed, it should be freed using 00041 PsDereferencePrimaryToken(). 00042 00043 00044 Arguments: 00045 00046 Process - Supplies the address of the process whose primary token 00047 is to be referenced. 00048 00049 Return Value: 00050 00051 A pointer to the specified process's primary token. 00052 00053 --*/ 00054 00055 { 00056 PACCESS_TOKEN 00057 Token; 00058 00059 ASSERT( Process->Pcb.Header.Type == ProcessObject ); 00060 00061 // 00062 // For performance sake, we may want to change this to use 00063 // an executive interlocked add routine in the future. 00064 // 00065 00066 00067 // 00068 // Lock the process security fields. 00069 // 00070 00071 PsLockProcessSecurityFields(); 00072 00073 // 00074 // Grab the current token pointer value 00075 // 00076 00077 Token = Process->Token; 00078 00079 // 00080 // Increment the reference count of the primary token to protect our 00081 // pointer. 00082 // 00083 00084 ObReferenceObject(Token); 00085 00086 // 00087 // Release the process security fields 00088 // 00089 00090 PsFreeProcessSecurityFields(); 00091 00092 return Token; 00093 00094 } 00095 00096 PACCESS_TOKEN 00097 PsReferenceImpersonationToken( 00098 IN PETHREAD Thread, 00099 OUT PBOOLEAN CopyOnOpen, 00100 OUT PBOOLEAN EffectiveOnly, 00101 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel 00102 ) 00103 00104 /*++ 00105 00106 Routine Description: 00107 00108 This function returns a pointer to the impersonation token of a thread. 00109 The reference count of that impersonation token is incremented to protect 00110 the pointer returned. 00111 00112 If the thread is not currently impersonating a client, then a null pointer 00113 is returned. 00114 00115 If the thread is impersonating a client, then information about the 00116 means of impersonation are also returned (ImpersonationLevel). 00117 00118 If a non-null value is returned, then PsDereferenceImpersonationToken() 00119 must be called to decrement the token's reference count when the pointer 00120 is no longer needed. 00121 00122 00123 Arguments: 00124 00125 Thread - Supplies the address of the thread whose impersonation token 00126 is to be referenced. 00127 00128 CopyOnOpen - The current value of the Thread->ImpersonationInfo->CopyOnOpen field. 00129 00130 EffectiveOnly - The current value of the Thread->ImpersonationInfo->EffectiveOnly field. 00131 00132 ImpersonationLevel - The current value of the Thread->ImpersonationInfo->ImpersonationLevel 00133 field. 00134 00135 Return Value: 00136 00137 A pointer to the specified thread's impersonation token. 00138 00139 If the thread is not currently impersonating a client, then NULL is 00140 returned. 00141 00142 --*/ 00143 00144 { 00145 PACCESS_TOKEN 00146 Token; 00147 00148 ASSERT( Thread->Tcb.Header.Type == ThreadObject ); 00149 // 00150 // before going through the lock overhead just look to see if it is 00151 // null. There is no race. Grabbing the lock is not needed until 00152 // we decide to use the token at which point we re check to see it 00153 // it is null. 00154 // This check saves about 300 instructions. 00155 // 00156 00157 if ( !Thread->ActiveImpersonationInfo ) { 00158 return NULL; 00159 } 00160 00161 00162 // 00163 // Lock the process security fields. 00164 // 00165 00166 PsLockProcessSecurityFields(); 00167 00168 // 00169 // Grab the current token pointer value 00170 // 00171 00172 00173 if ( Thread->ActiveImpersonationInfo ) { 00174 00175 // 00176 // Return the thread's impersonation level, etc. 00177 // 00178 00179 Token = Thread->ImpersonationInfo->Token; 00180 (*ImpersonationLevel) = Thread->ImpersonationInfo->ImpersonationLevel; 00181 (*CopyOnOpen) = Thread->ImpersonationInfo->CopyOnOpen; 00182 (*EffectiveOnly) = Thread->ImpersonationInfo->EffectiveOnly; 00183 00184 00185 // 00186 // Increment the reference count of the token to protect our 00187 // pointer. 00188 // 00189 00190 ObReferenceObject(Token); 00191 00192 } else { 00193 Token = NULL; 00194 } 00195 00196 00197 // 00198 // Release the security fields. 00199 // 00200 00201 PsFreeProcessSecurityFields(); 00202 00203 return Token; 00204 00205 } 00206 00207 PACCESS_TOKEN 00208 PsReferenceEffectiveToken( 00209 IN PETHREAD Thread, 00210 OUT PTOKEN_TYPE TokenType, 00211 OUT PBOOLEAN EffectiveOnly, 00212 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel 00213 ) 00214 00215 /*++ 00216 00217 Routine Description: 00218 00219 This function returns a pointer to the effective token of a thread. The 00220 effective token of a thread is the thread's impersonation token if it has 00221 one. Otherwise, it is the primary token of the thread's process. 00222 00223 The reference count of the effective token is incremented to protect 00224 the pointer returned. 00225 00226 If the thread is impersonating a client, then the impersonation level 00227 is also returned. 00228 00229 Either PsDereferenceImpersonationToken() (for an impersonation token) or 00230 PsDereferencePrimaryToken() (for a primary token) must be called to 00231 decrement the token's reference count when the pointer is no longer 00232 needed. 00233 00234 00235 Arguments: 00236 00237 Thread - Supplies the address of the thread whose effective token 00238 is to be referenced. 00239 00240 TokenType - Receives the type of the effective token. If the thread 00241 is currently impersonating a client, then this will be 00242 TokenImpersonation. Othwerwise, it will be TokenPrimary. 00243 00244 EffectiveOnly - If the token type is TokenImpersonation, then this 00245 receives the value of the client thread's Thread->Client->EffectiveOnly field. 00246 Otherwise, it is set to FALSE. 00247 00248 ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel 00249 field for an impersonation token and is not set for a primary token. 00250 00251 Return Value: 00252 00253 A pointer to the specified thread's effective token. 00254 00255 --*/ 00256 00257 { 00258 PACCESS_TOKEN 00259 Token; 00260 00261 ASSERT( Thread->Tcb.Header.Type == ThreadObject ); 00262 00263 // 00264 // Lock the process security fields. 00265 // 00266 00267 PsLockProcessSecurityFields(); 00268 00269 // 00270 // Grab the current impersonation token pointer value 00271 // 00272 00273 00274 if ( Thread->ActiveImpersonationInfo ) { 00275 00276 Token = Thread->ImpersonationInfo->Token; 00277 00278 // 00279 // Return the thread's impersonation level, etc. 00280 // 00281 00282 (*TokenType) = TokenImpersonation; 00283 (*EffectiveOnly) = Thread->ImpersonationInfo->EffectiveOnly; 00284 (*ImpersonationLevel) = Thread->ImpersonationInfo->ImpersonationLevel; 00285 00286 00287 00288 } else { 00289 00290 // 00291 // Get the thread's primary token if it wasn't impersonating a client. 00292 // 00293 00294 Token = THREAD_TO_PROCESS(Thread)->Token; 00295 00296 00297 // 00298 // Only the TokenType and CopyOnOpen OUT parameters are 00299 // returned for a primary token. 00300 // 00301 00302 (*TokenType) = TokenPrimary; 00303 (*EffectiveOnly) = FALSE; 00304 00305 } 00306 00307 // 00308 // Increment the reference count of the token to protect our 00309 // pointer. 00310 // 00311 00312 ObReferenceObject(Token); 00313 00314 // 00315 // Release the security fields. 00316 // 00317 00318 PsFreeProcessSecurityFields(); 00319 00320 00321 return Token; 00322 00323 } 00324 00325 NTSTATUS 00326 PsOpenTokenOfThread( 00327 IN HANDLE ThreadHandle, 00328 IN BOOLEAN OpenAsSelf, 00329 OUT PACCESS_TOKEN *Token, 00330 OUT PBOOLEAN CopyOnOpen, 00331 OUT PBOOLEAN EffectiveOnly, 00332 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel 00333 ) 00334 00335 /*++ 00336 00337 Routine Description: 00338 00339 This function does the thread specific processing of 00340 an NtOpenThreadToken() service. 00341 00342 The service validates that the handle has appropriate access 00343 to reference the thread. If so, it goes on to increment 00344 the reference count of the token object to prevent it from 00345 going away while the rest of the NtOpenThreadToken() request 00346 is processed. 00347 00348 NOTE: If this call completes successfully, the caller is responsible 00349 for decrementing the reference count of the target token. 00350 This must be done using PsDereferenceImpersonationToken(). 00351 00352 Arguments: 00353 00354 ThreadHandle - Supplies a handle to a thread object. 00355 00356 OpenAsSelf - Is a boolean value indicating whether the access should 00357 be made using the calling thread's current security context, which 00358 may be that of a client (if impersonating), or using the caller's 00359 process-level security context. A value of FALSE indicates the 00360 caller's current context should be used un-modified. A value of 00361 TRUE indicates the request should be fulfilled using the process 00362 level security context. 00363 00364 Token - If successful, receives a pointer to the thread's token 00365 object. 00366 00367 CopyOnOpen - The current value of the Thread->Client->CopyOnOpen field. 00368 00369 EffectiveOnly - The current value of the Thread->Client->EffectiveOnly field. 00370 00371 ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel 00372 field. 00373 00374 Return Value: 00375 00376 STATUS_SUCCESS - Indicates the call completed successfully. 00377 00378 STATUS_NO_TOKEN - Indicates the referenced thread is not currently 00379 impersonating a client. 00380 00381 STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous 00382 impersonation level. An anonymous token can not be openned. 00383 00384 status may also be any value returned by an attemp the reference 00385 the thread object for THREAD_QUERY_INFORMATION access. 00386 00387 --*/ 00388 00389 { 00390 00391 NTSTATUS 00392 Status; 00393 00394 PETHREAD 00395 Thread; 00396 00397 KPROCESSOR_MODE 00398 PreviousMode; 00399 00400 SE_IMPERSONATION_STATE 00401 DisabledImpersonationState; 00402 00403 BOOLEAN 00404 RestoreImpersonationState = FALSE; 00405 00406 PreviousMode = KeGetPreviousMode(); 00407 00408 00409 00410 // 00411 // Disable impersonation if necessary 00412 // 00413 00414 if (OpenAsSelf) { 00415 RestoreImpersonationState = PsDisableImpersonation( 00416 PsGetCurrentThread(), 00417 &DisabledImpersonationState 00418 ); 00419 } 00420 00421 // 00422 // Make sure the handle grants the appropriate access to the specified 00423 // thread. 00424 // 00425 00426 Status = ObReferenceObjectByHandle( 00427 ThreadHandle, 00428 THREAD_QUERY_INFORMATION, 00429 PsThreadType, 00430 PreviousMode, 00431 (PVOID *)&Thread, 00432 NULL 00433 ); 00434 00435 00436 00437 00438 if (RestoreImpersonationState) { 00439 PsRestoreImpersonation( 00440 PsGetCurrentThread(), 00441 &DisabledImpersonationState 00442 ); 00443 } 00444 00445 if (!NT_SUCCESS(Status)) { 00446 return Status; 00447 } 00448 00449 // 00450 // Reference the impersonation token, if there is one 00451 // 00452 00453 (*Token) = PsReferenceImpersonationToken( Thread, 00454 CopyOnOpen, 00455 EffectiveOnly, 00456 ImpersonationLevel 00457 ); 00458 00459 00460 // 00461 // dereference the target thread. 00462 // 00463 00464 ObDereferenceObject( Thread ); 00465 00466 // 00467 // Make sure there is a token 00468 // 00469 00470 if ((*Token) == NULL) { 00471 return STATUS_NO_TOKEN; 00472 } 00473 00474 // 00475 // Make sure the ImpersonationLevel is high enough to allow 00476 // the token to be openned. 00477 // 00478 00479 if ((*ImpersonationLevel) <= SecurityAnonymous) { 00480 PsDereferenceImpersonationToken( (*Token) ); 00481 (*Token) = NULL; 00482 return STATUS_CANT_OPEN_ANONYMOUS; 00483 } 00484 00485 00486 return STATUS_SUCCESS; 00487 00488 } 00489 00490 00491 NTSTATUS 00492 PsOpenTokenOfProcess( 00493 IN HANDLE ProcessHandle, 00494 OUT PACCESS_TOKEN *Token 00495 ) 00496 00497 /*++ 00498 00499 Routine Description: 00500 00501 This function does the process specific processing of 00502 an NtOpenProcessToken() service. 00503 00504 The service validates that the handle has appropriate access 00505 to referenced process. If so, it goes on to reference the 00506 primary token object to prevent it from going away while the 00507 rest of the NtOpenProcessToken() request is processed. 00508 00509 NOTE: If this call completes successfully, the caller is responsible 00510 for decrementing the reference count of the target token. 00511 This must be done using the PsDereferencePrimaryToken() API. 00512 00513 Arguments: 00514 00515 ProcessHandle - Supplies a handle to a process object whose primary 00516 token is to be opened. 00517 00518 Token - If successful, receives a pointer to the process's token 00519 object. 00520 00521 Return Value: 00522 00523 STATUS_SUCCESS - Indicates the call completed successfully. 00524 00525 status may also be any value returned by an attemp the reference 00526 the process object for PROCESS_QUERY_INFORMATION access. 00527 00528 --*/ 00529 00530 { 00531 00532 NTSTATUS 00533 Status; 00534 00535 PEPROCESS 00536 Process; 00537 00538 KPROCESSOR_MODE 00539 PreviousMode; 00540 00541 00542 PreviousMode = KeGetPreviousMode(); 00543 00544 // 00545 // Make sure the handle grants the appropriate access to the specified 00546 // process. 00547 // 00548 00549 Status = ObReferenceObjectByHandle( 00550 ProcessHandle, 00551 PROCESS_QUERY_INFORMATION, 00552 PsProcessType, 00553 PreviousMode, 00554 (PVOID *)&Process, 00555 NULL 00556 ); 00557 00558 if (!NT_SUCCESS(Status)) { 00559 00560 return Status; 00561 00562 } 00563 00564 // 00565 // Reference the primary token 00566 // (This takes care of gaining exlusive access to the process 00567 // security fields for us) 00568 // 00569 00570 (*Token) = PsReferencePrimaryToken( Process ); 00571 00572 00573 00574 // 00575 // Done with the process object 00576 // 00577 00578 ObDereferenceObject( Process ); 00579 00580 return STATUS_SUCCESS; 00581 00582 00583 } 00584 00585 NTSTATUS 00586 PsOpenTokenOfJobObject( 00587 IN HANDLE JobObject, 00588 OUT PACCESS_TOKEN * Token 00589 ) 00590 00591 /*++ 00592 00593 Routine Description: 00594 00595 This function does the ps/job specific work for NtOpenJobObjectToken. 00596 00597 00598 Arguments: 00599 00600 JobObject - Supplies a handle to a job object whose limit token 00601 token is to be opened. 00602 00603 Token - If successful, receives a pointer to the process's token 00604 object. 00605 00606 Return Value: 00607 00608 STATUS_SUCCESS - Indicates the call completed successfully. 00609 00610 STATUS_NO_TOKEN - indicates the job object does not have a token 00611 00612 00613 --*/ 00614 { 00615 NTSTATUS Status ; 00616 PEJOB Job ; 00617 KPROCESSOR_MODE PreviousMode ; 00618 00619 PreviousMode = KeGetPreviousMode(); 00620 00621 Status = ObReferenceObjectByHandle( 00622 JobObject, 00623 JOB_OBJECT_QUERY, 00624 PsJobType, 00625 PreviousMode, 00626 &Job, 00627 NULL ); 00628 00629 if ( NT_SUCCESS( Status ) ) 00630 { 00631 if ( Job->Token ) 00632 { 00633 ObReferenceObject( Job->Token ); 00634 00635 *Token = Job->Token ; 00636 00637 } 00638 else 00639 { 00640 Status = STATUS_NO_TOKEN ; 00641 } 00642 00643 } 00644 00645 return Status ; 00646 } 00647 00648 00649 NTSTATUS 00650 PsImpersonateClient( 00651 IN PETHREAD Thread, 00652 IN PACCESS_TOKEN Token, 00653 IN BOOLEAN CopyOnOpen, 00654 IN BOOLEAN EffectiveOnly, 00655 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel 00656 ) 00657 00658 /*++ 00659 00660 Routine Description: 00661 00662 This routine sets up the specified thread so that it is impersonating 00663 the specified client. This will result in the reference count of the 00664 token representing the client being incremented to reflect the new 00665 reference. 00666 00667 If the thread is currently impersonating a client, that token will be 00668 dereferenced. 00669 00670 00671 00672 Arguments: 00673 00674 Thread - points to the thread which is going to impersonate a client. 00675 00676 Token - Points to the token to be assigned as the impersonation token. 00677 This does NOT have to be a TokenImpersonation type token. This 00678 allows direct reference of client process's primary tokens. 00679 00680 CopyOnOpen - If TRUE, indicates the token is considered to be private 00681 by the assigner and should be copied if opened. For example, a 00682 session layer may be using a token to represent a client's context. 00683 If the session is trying to synchronize the context of the client, 00684 then user mode code should not be given direct access to the session 00685 layer's token. 00686 00687 Basically, session layers should always specify TRUE for this, while 00688 tokens assigned by the server itself (handle based) should specify 00689 FALSE. 00690 00691 00692 EffectiveOnly - Is a boolean value to be assigned as the 00693 Thread->ImpersonationInfo->EffectiveOnly field value for the 00694 impersonation. A value of FALSE indicates the server is allowed 00695 to enable currently disabled groups and privileges. 00696 00697 ImpersonationLevel - Is the impersonation level that the server is allowed 00698 to access the token with. 00699 00700 00701 Return Value: 00702 00703 STATUS_SUCCESS - Indicates the call completed successfully. 00704 00705 00706 --*/ 00707 00708 { 00709 00710 PPS_IMPERSONATION_INFORMATION 00711 NewClient; 00712 00713 PACCESS_TOKEN 00714 OldToken; 00715 00716 PACCESS_TOKEN NewerToken ; 00717 NTSTATUS Status ; 00718 PPS_JOB_TOKEN_FILTER Filter ; 00719 BOOLEAN DontRefToken = FALSE ; 00720 00721 ASSERT( Thread->Tcb.Header.Type == ThreadObject ); 00722 00723 00724 // 00725 // Lock the process security fields 00726 // 00727 00728 PsLockProcessSecurityFields(); 00729 00730 00731 if (!ARGUMENT_PRESENT(Token)) { 00732 00733 // 00734 // This is a request to revert to self. 00735 // Clean up any client information. 00736 // 00737 00738 if ( Thread->ActiveImpersonationInfo ) { 00739 00740 OldToken = Thread->ImpersonationInfo->Token; 00741 Thread->ActiveImpersonationInfo = FALSE; 00742 } else { 00743 OldToken = NULL; 00744 } 00745 00746 } else { 00747 00748 // 00749 // Check if we're allowed to impersonate based on the job 00750 // restrictions: 00751 // 00752 00753 Status = STATUS_SUCCESS ; 00754 00755 if ( Thread->ThreadsProcess->Job ) { 00756 00757 if ( ( Thread->ThreadsProcess->Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN ) && 00758 ( SeTokenIsAdmin( Token ) ) ) { 00759 00760 Status = STATUS_ACCESS_DENIED ; 00761 00762 } 00763 00764 if ( ( Thread->ThreadsProcess->Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ) && 00765 ( !SeTokenIsRestricted( Token ) ) ) 00766 { 00767 Status = STATUS_ACCESS_DENIED ; 00768 } 00769 00770 if ( Thread->ThreadsProcess->Job->Filter ) 00771 { 00772 // 00773 // Filter installed. Need to create a restricted token 00774 // dynamically. 00775 // 00776 Filter = Thread->ThreadsProcess->Job->Filter ; 00777 00778 Status = SeFastFilterToken( 00779 Token, 00780 KernelMode, 00781 0, 00782 Filter->CapturedGroupCount, 00783 Filter->CapturedGroups, 00784 Filter->CapturedPrivilegeCount, 00785 Filter->CapturedPrivileges, 00786 Filter->CapturedSidCount, 00787 Filter->CapturedSids, 00788 Filter->CapturedSidsLength, 00789 &NewerToken ); 00790 00791 if ( NT_SUCCESS( Status ) ) 00792 { 00793 DontRefToken = TRUE ; 00794 00795 Token = NewerToken ; 00796 } 00797 00798 } 00799 } 00800 00801 if ( !NT_SUCCESS( Status ) ) 00802 { 00803 PsFreeProcessSecurityFields(); 00804 00805 return Status ; 00806 } 00807 00808 // 00809 // If we are already impersonating someone, 00810 // use the already allocated block. This avoids 00811 // an alloc and a free. 00812 // 00813 00814 if ( Thread->ActiveImpersonationInfo ) { 00815 00816 // 00817 // capture the old token pointer. 00818 // We'll dereference it after unlocking the security fields. 00819 // 00820 00821 OldToken = Thread->ImpersonationInfo->Token; 00822 NewClient = Thread->ImpersonationInfo; 00823 00824 } else { 00825 00826 OldToken = NULL; 00827 00828 if ( Thread->ImpersonationInfo ) { 00829 NewClient = Thread->ImpersonationInfo; 00830 } else { 00831 00832 // 00833 // Allocate and set up the Client block 00834 // 00835 00836 NewClient = (PPS_IMPERSONATION_INFORMATION)ExAllocatePoolWithTag( 00837 PagedPool, 00838 sizeof(PS_IMPERSONATION_INFORMATION), 00839 'mIsP'); 00840 00841 if (NewClient == NULL) { 00842 00843 PsFreeProcessSecurityFields(); 00844 00845 return STATUS_NO_MEMORY ; 00846 00847 } 00848 00849 Thread->ImpersonationInfo = NewClient; 00850 } 00851 } 00852 00853 NewClient->ImpersonationLevel = ImpersonationLevel; 00854 NewClient->EffectiveOnly = EffectiveOnly; 00855 NewClient->CopyOnOpen = CopyOnOpen; 00856 NewClient->Token = Token; 00857 Thread->ActiveImpersonationInfo = TRUE; 00858 00859 if ( !DontRefToken ) 00860 { 00861 ObReferenceObject(NewClient->Token); 00862 } 00863 } 00864 00865 // 00866 // Release the security fields 00867 // 00868 00869 PsFreeProcessSecurityFields(); 00870 00871 00872 // 00873 // Free the old client token, if necessary. 00874 // 00875 00876 if (ARGUMENT_PRESENT( OldToken )) { 00877 00878 PsDereferenceImpersonationToken( OldToken ); 00879 } 00880 00881 00882 return STATUS_SUCCESS ; 00883 00884 } 00885 00886 00887 BOOLEAN 00888 PsDisableImpersonation( 00889 IN PETHREAD Thread, 00890 IN PSE_IMPERSONATION_STATE ImpersonationState 00891 ) 00892 00893 /*++ 00894 00895 Routine Description: 00896 00897 This routine temporarily disables the impersonation of a thread. 00898 The impersonation state is saved for quick replacement later. The 00899 impersonation token is left referenced and a pointer to it is held 00900 in the IMPERSONATION_STATE data structure. 00901 00902 PsRestoreImpersonation() must be used after this routine is called. 00903 00904 00905 00906 Arguments: 00907 00908 Thread - points to the thread whose impersonation (if any) is to 00909 be temporarily disabled. 00910 00911 ImpersonationState - receives the current impersonation information, 00912 including a pointer to the impersonation token. 00913 00914 00915 Return Value: 00916 00917 TRUE - Indicates the impersonation state has been saved and the 00918 impersonation has been temporarily disabled. 00919 00920 FALSE - Indicates the specified thread was not impersonating a client. 00921 No action has been taken. 00922 00923 --*/ 00924 00925 { 00926 00927 00928 PPS_IMPERSONATION_INFORMATION 00929 OldClient; 00930 00931 ASSERT( Thread->Tcb.Header.Type == ThreadObject ); 00932 00933 // 00934 // Lock the process security fields 00935 // 00936 00937 PsLockProcessSecurityFields(); 00938 00939 // 00940 // Capture the impersonation information (if there is any). 00941 // 00942 00943 if ( Thread->ActiveImpersonationInfo ) { 00944 00945 OldClient = Thread->ImpersonationInfo; 00946 ImpersonationState->Level = OldClient->ImpersonationLevel; 00947 ImpersonationState->EffectiveOnly = OldClient->EffectiveOnly; 00948 ImpersonationState->CopyOnOpen = OldClient->CopyOnOpen; 00949 ImpersonationState->Token = OldClient->Token; 00950 } else { 00951 00952 // 00953 // Not impersonating. Just make up some values. 00954 // The NULL for the token indicates we aren't impersonating. 00955 // 00956 00957 OldClient = NULL; 00958 ImpersonationState->Level = SecurityAnonymous; 00959 ImpersonationState->EffectiveOnly = FALSE; 00960 ImpersonationState->CopyOnOpen = FALSE; 00961 ImpersonationState->Token = NULL; 00962 } 00963 00964 // 00965 // Clear the Client field to indicate the thread is not impersonating. 00966 // 00967 00968 Thread->ActiveImpersonationInfo = FALSE; 00969 00970 00971 // 00972 // Release the security fields 00973 // 00974 00975 PsFreeProcessSecurityFields(); 00976 00977 00978 if ( OldClient ) { 00979 00980 return TRUE; 00981 00982 } else { 00983 return FALSE; 00984 } 00985 00986 } 00987 00988 00989 VOID 00990 PsRestoreImpersonation( 00991 IN PETHREAD Thread, 00992 IN PSE_IMPERSONATION_STATE ImpersonationState 00993 ) 00994 00995 /*++ 00996 00997 Routine Description: 00998 00999 This routine restores an impersonation that has been temporarily disabled 01000 using PsDisableImpersonation(). 01001 01002 Notice that if this routine finds the thread is already impersonating 01003 (again), then restoring the temporarily disabled impersonation will cause 01004 the current impersonation to be abandoned. 01005 01006 01007 01008 Arguments: 01009 01010 Thread - points to the thread whose impersonation is to be restored. 01011 01012 ImpersontionState - receives the current impersontion information, 01013 including a pointer ot the impersonation token. 01014 01015 01016 Return Value: 01017 01018 TRUE - Indicates the impersonation state has been saved and the 01019 impersonation has been temporarily disabled. 01020 01021 FALSE - Indicates the specified thread was not impersonating a client. 01022 No action has been taken. 01023 01024 --*/ 01025 01026 { 01027 01028 01029 // 01030 // The processing for restore is identical to that for Impersonation, 01031 // except that the token's reference count will be incremented (and 01032 // so we need to do one dereference). 01033 01034 PsImpersonateClient( 01035 Thread, 01036 ImpersonationState->Token, 01037 ImpersonationState->CopyOnOpen, 01038 ImpersonationState->EffectiveOnly, 01039 ImpersonationState->Level 01040 ); 01041 01042 01043 ObDereferenceObject( ImpersonationState->Token ); 01044 01045 return; 01046 01047 } 01048 01049 01050 VOID 01051 PsRevertToSelf( ) 01052 01053 /*++ 01054 01055 Routine Description: 01056 01057 This routine causes the calling thread to discontinue 01058 impersonating a client. If the thread is not currently 01059 impersonating a client, no action is taken. 01060 01061 Arguments: 01062 01063 None. 01064 01065 Return Value: 01066 01067 None. 01068 01069 --*/ 01070 01071 { 01072 PETHREAD 01073 Thread = PsGetCurrentThread(); 01074 01075 PACCESS_TOKEN OldToken; 01076 01077 // 01078 // Lock the process security fields 01079 // 01080 01081 PsLockProcessSecurityFields(); 01082 01083 // 01084 // See if the thread is impersonating a client 01085 // and dereference that token if so. 01086 // 01087 01088 if ( Thread->ActiveImpersonationInfo ) { 01089 01090 Thread->ActiveImpersonationInfo = FALSE; 01091 OldToken = Thread->ImpersonationInfo->Token; 01092 } else { 01093 OldToken = NULL; 01094 } 01095 01096 01097 // 01098 // Release the security fields 01099 // 01100 01101 PsFreeProcessSecurityFields(); 01102 01103 01104 // 01105 // Free the old client info... 01106 // 01107 01108 if ( OldToken ) { 01109 ObDereferenceObject( OldToken ); 01110 } 01111 01112 return; 01113 } 01114 01115 01116 NTSTATUS 01117 PspInitializeProcessSecurity( 01118 IN PEPROCESS Parent OPTIONAL, 01119 IN PEPROCESS Child 01120 ) 01121 01122 /*++ 01123 01124 Routine Description: 01125 01126 This function initializes a new process's security fields, including 01127 the assignment of a new primary token. 01128 01129 The child process is assumed to not yet have been inserted into 01130 an object table. 01131 01132 NOTE: IT IS EXPECTED THAT THIS SERVICE WILL BE CALLED WITH A NULL 01133 PARENT PROCESS POINTER EXACTLY ONCE - FOR THE INITIAL SYSTEM 01134 PROCESS. 01135 01136 01137 Arguments: 01138 01139 Parent - An optional pointer to the process being used as the parent 01140 of the new process. If this value is NULL, then the process is 01141 assumed to be the initial system process, and the boot token is 01142 assigned rather than a duplicate of the parent process's primary 01143 token. 01144 01145 Child - Supplies the address of the process being initialized. This 01146 process does not yet require security field contention protection. 01147 In particular, the security fields may be accessed without first 01148 acquiring the process security fields lock. 01149 01150 01151 01152 Return Value: 01153 01154 01155 --*/ 01156 01157 { 01158 NTSTATUS 01159 Status; 01160 01161 01162 // 01163 // Assign the primary token 01164 // 01165 01166 if (ARGUMENT_PRESENT(Parent)) { 01167 01168 // 01169 // create the primary token 01170 // This is a duplicate of the parent's token. 01171 // 01172 01173 Status = SeSubProcessToken( 01174 Parent, 01175 &Child->Token 01176 ); 01177 01178 if (!NT_SUCCESS(Status)) { 01179 Child->Token = NULL; // Needed to ensure proper deletion 01180 } 01181 01182 } else { 01183 01184 // 01185 // Reference and assign the boot token 01186 // 01187 // The use of a single boot access token assumes there is 01188 // exactly one parentless process in the system - the initial 01189 // process. If this ever changes, this code will need to change 01190 // to match the new condition (so that a token doesn't end up 01191 // being shared by multiple processes. 01192 // 01193 01194 Child->Token = NULL; 01195 SeAssignPrimaryToken( Child, PspBootAccessToken ); 01196 Status = STATUS_SUCCESS; 01197 01198 01199 } 01200 01201 return Status; 01202 01203 } 01204 01205 VOID 01206 PspDeleteProcessSecurity( 01207 IN PEPROCESS Process 01208 ) 01209 01210 /*++ 01211 01212 Routine Description: 01213 01214 This function cleans up a process's security fields as part of process 01215 deletion. It is assumed no other references to the process can occur 01216 during or after a call to this routine. This enables us to reference 01217 the process security fields without acquiring the lock protecting those 01218 fields. 01219 01220 NOTE: It may be desirable to add auditing capability to this routine 01221 at some point. 01222 01223 01224 Arguments: 01225 01226 Process - A pointer to the process being deleted. 01227 01228 01229 Return Value: 01230 01231 None. 01232 01233 --*/ 01234 01235 { 01236 01237 01238 01239 01240 // 01241 // If we are deleting a process that didn't successfully complete 01242 // process initialization, then there may be no token associated 01243 // with it yet. 01244 // 01245 01246 if (ARGUMENT_PRESENT(Process->Token)) { 01247 SeDeassignPrimaryToken( Process ); 01248 Process->Token = NULL; 01249 } 01250 01251 return; 01252 } 01253 01254 01255 NTSTATUS 01256 PspAssignPrimaryToken( 01257 IN PEPROCESS Process, 01258 IN HANDLE Token OPTIONAL, 01259 IN PACCESS_TOKEN TokenPointer OPTIONAL 01260 ) 01261 01262 /*++ 01263 01264 Routine Description: 01265 01266 This function performs the security portions of primary token assignment. 01267 It is expected that the proper access to the process and thread objects, 01268 as well as necessary privilege, has already been established. 01269 01270 A primary token can only be replaced if the process has no threads, or 01271 has one thread. This is because the thread objects point to the primary 01272 token and must have those pointers updated when the primary token is 01273 changed. This is only expected to be necessary at logon time, when 01274 the process is in its infancy and either has zero threads or maybe one 01275 inactive thread. 01276 01277 If the assignment is successful, the old token is dereferenced and the 01278 new one is referenced. 01279 01280 01281 01282 Arguments: 01283 01284 Process - A pointer to the process whose primary token is being 01285 replaced. 01286 01287 Token - The handle value of the token to be assigned as the primary 01288 token. 01289 01290 01291 Return Value: 01292 01293 STATUS_SUCCESS - Indicates the primary token has been successfully 01294 replaced. 01295 01296 STATUS_BAD_TOKEN_TYPE - Indicates the token is not of type TokenPrimary. 01297 01298 STATUS_TOKEN_IN_USE - Indicates the token is already in use by 01299 another process. 01300 01301 Other status may be returned when attempting to reference the token 01302 object. 01303 01304 --*/ 01305 01306 { 01307 NTSTATUS 01308 Status; 01309 01310 PACCESS_TOKEN 01311 NewToken, 01312 OldToken; 01313 01314 KPROCESSOR_MODE 01315 PreviousMode; 01316 01317 01318 if ( TokenPointer == NULL ) 01319 { 01320 PreviousMode = KeGetPreviousMode(); 01321 01322 // 01323 // Reference the specified token, and make sure it can be assigned 01324 // as a primary token. 01325 // 01326 01327 Status = ObReferenceObjectByHandle ( 01328 Token, 01329 TOKEN_ASSIGN_PRIMARY, 01330 SeTokenObjectType(), 01331 PreviousMode, 01332 (PVOID *)&NewToken, 01333 NULL 01334 ); 01335 01336 if ( !NT_SUCCESS(Status) ) { 01337 return Status; 01338 } 01339 } 01340 else 01341 { 01342 NewToken = TokenPointer ; 01343 } 01344 01345 01346 // 01347 // Lock the process security fields. 01348 // 01349 01350 PsLockProcessSecurityFields(); 01351 01352 01353 01354 01355 01356 // 01357 // This routine makes sure the NewToken is suitable for assignment 01358 // as a primary token. 01359 // 01360 01361 Status = SeExchangePrimaryToken( Process, NewToken, &OldToken ); 01362 01363 01364 // 01365 // Release the process security fields 01366 // 01367 01368 PsFreeProcessSecurityFields(); 01369 01370 // 01371 // Free the old token (we don't need it). 01372 // This can't be done while the security fields are locked. 01373 // 01374 01375 if (NT_SUCCESS( Status )) { 01376 01377 ObDereferenceObject( OldToken ); 01378 } 01379 01380 // 01381 // Undo the handle reference 01382 // 01383 01384 if ( TokenPointer == NULL ) 01385 { 01386 ObDereferenceObject( NewToken ); 01387 } 01388 01389 01390 return Status; 01391 } 01392 01393 01394 VOID 01395 PspInitializeThreadSecurity( 01396 IN PEPROCESS Process, 01397 IN PETHREAD Thread 01398 ) 01399 01400 /*++ 01401 01402 Routine Description: 01403 01404 This function initializes a new thread's security fields. 01405 01406 01407 Arguments: 01408 01409 Process - Points to the process the thread belongs to. 01410 01411 Thread - Points to the thread object being initialized. 01412 01413 01414 Return Value: 01415 01416 None. 01417 01418 --*/ 01419 01420 { 01421 01422 01423 // 01424 // Initially not impersonating anyone. 01425 // 01426 01427 Thread->ImpersonationInfo = NULL; 01428 Thread->ActiveImpersonationInfo = FALSE; 01429 01430 return; 01431 01432 } 01433 01434 01435 VOID 01436 PspDeleteThreadSecurity( 01437 IN PETHREAD Thread 01438 ) 01439 01440 /*++ 01441 01442 Routine Description: 01443 01444 This function cleans up a thread's security fields as part of thread 01445 deletion. It is assumed no other references to the thread can occur 01446 during or after a call to this routine, so no locking is necessary 01447 to access the thread security fields. 01448 01449 01450 Arguments: 01451 01452 Thread - A pointer to the thread being deleted. 01453 01454 01455 Return Value: 01456 01457 None. 01458 01459 --*/ 01460 01461 { 01462 01463 // 01464 // clean-up client information, if there is any. 01465 // 01466 01467 if ( Thread->ActiveImpersonationInfo ) { 01468 ObDereferenceObject( Thread->ImpersonationInfo->Token ); 01469 } 01470 01471 if ( Thread->ImpersonationInfo ) { 01472 ExFreePool( Thread->ImpersonationInfo ); 01473 Thread->ActiveImpersonationInfo = FALSE; 01474 Thread->ImpersonationInfo = NULL; 01475 } 01476 01477 return; 01478 01479 } 01480 01481 01482 NTSTATUS 01483 PsAssignImpersonationToken( 01484 IN PETHREAD Thread, 01485 IN HANDLE Token 01486 ) 01487 01488 /*++ 01489 01490 Routine Description: 01491 01492 This function performs the security portions of establishing an 01493 impersonation token. This routine is expected to be used only in 01494 the case where the subject has asked for impersonation explicitly 01495 providing an impersonation token. Other services are provided for 01496 use by communication session layers that need to establish an 01497 impersonation on a server's behalf. 01498 01499 It is expected that the proper access to the thread object has already 01500 been established. 01501 01502 The following rules apply: 01503 01504 1) The caller must have TOKEN_IMPERSONATE access to the token 01505 for any action to be taken. 01506 01507 2) If the token may NOT be used for impersonation (e.g., not an 01508 impersonation token) no action is taken. 01509 01510 3) Otherwise, any existing impersonation token is dereferenced and 01511 the new token is established as the impersonation token. 01512 01513 01514 01515 Arguments: 01516 01517 Thread - A pointer to the thread whose impersonation token is being 01518 set. 01519 01520 Token - The handle value of the token to be assigned as the impersonation 01521 token. If this value is NULL, then current impersonation (if any) 01522 is terminated and no new impersonation is established. 01523 01524 01525 Return Value: 01526 01527 STATUS_SUCCESS - Indicates the primary token has been successfully 01528 replaced. 01529 01530 STATUS_BAD_TOKEN_TYPE - Indicates the token is not of type 01531 TokenImpersonation. 01532 01533 Other status may be returned when attempting to reference the token 01534 object. 01535 01536 --*/ 01537 01538 { 01539 NTSTATUS 01540 Status; 01541 01542 PACCESS_TOKEN 01543 NewToken, NewerToken ; 01544 01545 KPROCESSOR_MODE 01546 PreviousMode; 01547 01548 SECURITY_IMPERSONATION_LEVEL 01549 ImpersonationLevel; 01550 01551 PPS_JOB_TOKEN_FILTER Filter ; 01552 01553 PEPROCESS ThreadProcess; 01554 BOOLEAN AttachedToProcess = FALSE; 01555 01556 PreviousMode = KeGetPreviousMode(); 01557 01558 if (!ARGUMENT_PRESENT(Token)) { 01559 01560 NewToken = NULL; 01561 01562 // 01563 // Don't care what value ImpersonationLevel has, it won't 01564 // be used. 01565 // 01566 01567 } else { 01568 01569 // 01570 // Reference the specified token for TOKEN_IMPERSONATE access 01571 // 01572 01573 Status = ObReferenceObjectByHandle ( 01574 Token, 01575 TOKEN_IMPERSONATE, 01576 SeTokenObjectType(), 01577 PreviousMode, 01578 (PVOID *)&NewToken, 01579 NULL 01580 ); 01581 01582 if ( !NT_SUCCESS(Status) ) { 01583 return Status; 01584 } 01585 01586 // 01587 // Make sure the token is an impersonation token. 01588 // 01589 01590 if (SeTokenType( NewToken ) != TokenImpersonation ) { 01591 ObDereferenceObject( NewToken ); 01592 return STATUS_BAD_TOKEN_TYPE; 01593 } 01594 01595 if ( Thread->ThreadsProcess->Job ) { 01596 01597 if ( ( Thread->ThreadsProcess->Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_NO_ADMIN ) && 01598 ( SeTokenIsAdmin( NewToken ) ) ) { 01599 01600 ObDereferenceObject( NewToken ); 01601 01602 return STATUS_ACCESS_DENIED ; 01603 01604 } 01605 01606 if ( ( Thread->ThreadsProcess->Job->SecurityLimitFlags & JOB_OBJECT_SECURITY_RESTRICTED_TOKEN ) && 01607 ( !SeTokenIsRestricted( NewToken ) ) ) 01608 { 01609 ObDereferenceObject( NewToken ); 01610 01611 return STATUS_ACCESS_DENIED ; 01612 } 01613 01614 if ( Thread->ThreadsProcess->Job->Filter ) 01615 { 01616 // 01617 // Filter installed. Need to create a restricted token 01618 // dynamically. 01619 // 01620 Filter = Thread->ThreadsProcess->Job->Filter ; 01621 01622 Status = SeFastFilterToken( 01623 NewToken, 01624 PreviousMode, 01625 0, 01626 Filter->CapturedGroupCount, 01627 Filter->CapturedGroups, 01628 Filter->CapturedPrivilegeCount, 01629 Filter->CapturedPrivileges, 01630 Filter->CapturedSidCount, 01631 Filter->CapturedSids, 01632 Filter->CapturedSidsLength, 01633 &NewerToken ); 01634 01635 ObDereferenceObject( NewToken ); 01636 01637 if ( NT_SUCCESS( Status ) ) 01638 { 01639 NewToken = NewerToken ; 01640 } 01641 else 01642 { 01643 return Status ; 01644 } 01645 01646 01647 } 01648 } 01649 01650 ImpersonationLevel = SeTokenImpersonationLevel( NewToken ); 01651 } 01652 01653 // 01654 // The rest can be done by PsImpersonateClient. 01655 // 01656 // PsImpersonateClient will reference the passed token 01657 // on success. 01658 // 01659 01660 Status = PsImpersonateClient( 01661 Thread, 01662 NewToken, 01663 FALSE, // CopyOnOpen 01664 FALSE, //EffectiveOnly 01665 ImpersonationLevel 01666 ); 01667 01668 01669 // 01670 // dereference the passed token, if there is one. 01671 // 01672 // Note that if PsImpersonateClient failed, this will 01673 // be the final dereference of NewToken/NewerToken, 01674 // and it will be freed. 01675 // 01676 01677 if (ARGUMENT_PRESENT(NewToken)) { 01678 ObDereferenceObject( NewToken ); 01679 } 01680 01681 if (NT_SUCCESS( Status )) { 01682 01683 // 01684 // Indicate that 'Thread' has started to do impersonation. 01685 // This info is useful for GetUserDefaultLCID() 01686 // 01687 01688 if (!IS_SYSTEM_THREAD(Thread)) { 01689 01690 ThreadProcess = THREAD_TO_PROCESS(Thread); 01691 01692 if ( PsGetCurrentProcess() != ThreadProcess ) { 01693 KeAttachProcess( &ThreadProcess->Pcb ); 01694 AttachedToProcess = TRUE; 01695 } 01696 01697 if (ARGUMENT_PRESENT(NewToken)) { 01698 ((PTEB)(Thread->Tcb.Teb))->ImpersonationLocale = (LCID)-1; 01699 ((PTEB)(Thread->Tcb.Teb))->IsImpersonating = 1; 01700 } else { 01701 ((PTEB)(Thread->Tcb.Teb))->ImpersonationLocale = (LCID) 0; 01702 ((PTEB)(Thread->Tcb.Teb))->IsImpersonating = 0; 01703 } 01704 01705 if (AttachedToProcess) { 01706 KeDetachProcess(); 01707 } 01708 } 01709 } 01710 01711 return Status; 01712 }

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