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

tokenopn.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 tokenopn.c 00008 00009 Abstract: 00010 00011 This module implements the open thread and process token services. 00012 00013 Author: 00014 00015 Jim Kelly (JimK) 2-Aug-1990 00016 00017 Environment: 00018 00019 Kernel mode only. 00020 00021 Revision History: 00022 00023 --*/ 00024 00025 //#ifndef TOKEN_DEBUG 00026 //#define TOKEN_DEBUG 00027 //#endif 00028 00029 #include "sep.h" 00030 #include "seopaque.h" 00031 #include "tokenp.h" 00032 00033 NTSTATUS 00034 SepCreateImpersonationTokenDacl( 00035 IN PTOKEN Token, 00036 IN PACCESS_TOKEN PrimaryToken, 00037 OUT PACL *Acl 00038 ); 00039 00040 #ifdef ALLOC_PRAGMA 00041 #pragma alloc_text(PAGE,NtOpenProcessToken) 00042 #pragma alloc_text(PAGE,NtOpenThreadToken) 00043 #pragma alloc_text(PAGE,SepCreateImpersonationTokenDacl) 00044 #endif 00045 00046 00047 00048 NTSTATUS 00049 SepCreateImpersonationTokenDacl( 00050 IN PTOKEN Token, 00051 IN PACCESS_TOKEN PrimaryToken, 00052 OUT PACL *Acl 00053 ) 00054 /*++ 00055 00056 Routine Description: 00057 00058 This routine modifies the DACL protecting the passed token to allow 00059 the current user (described by the PrimaryToken parameter) full access. 00060 This permits callers of NtOpenThreadToken to call with OpenAsSelf==TRUE 00061 and succeed. 00062 00063 The new DACL placed on the token is as follows: 00064 00065 ACE 0 - Server gets TOKEN_ALL_ACCESS 00066 00067 ACE 1 - Client gets TOKEN_ALL_ACCESS 00068 00069 ACE 2 - Admins gets TOKEN_ALL_ACCESS 00070 00071 ACE 3 - System gets TOKEN_ALL_ACCESS 00072 00073 ACE 4 - Restricted gets TOKEN_ALL_ACCESS 00074 00075 00076 Arguments: 00077 00078 Token - The token whose protection is to be modified. 00079 00080 PrimaryToken - Token representing the subject to be granted access. 00081 00082 Acl - Returns the modified ACL, allocated out of PagedPool. 00083 00084 00085 Return Value: 00086 00087 00088 --*/ 00089 00090 { 00091 PSID ServerUserSid; 00092 PSID ClientUserSid; 00093 NTSTATUS Status = STATUS_SUCCESS; 00094 ULONG AclLength; 00095 PACL NewDacl; 00096 PSECURITY_DESCRIPTOR OldDescriptor; 00097 BOOLEAN MemoryAllocated; 00098 PACL OldDacl; 00099 BOOLEAN DaclPresent; 00100 BOOLEAN DaclDefaulted; 00101 00102 PAGED_CODE(); 00103 00104 ServerUserSid = ((PTOKEN)PrimaryToken)->UserAndGroups[0].Sid; 00105 00106 ClientUserSid = Token->UserAndGroups[0].Sid; 00107 00108 // 00109 // Compute how much space we'll need for the new DACL. 00110 // 00111 00112 AclLength = 5 * sizeof( ACCESS_ALLOWED_ACE ) - 5 * sizeof( ULONG ) + 00113 SeLengthSid( ServerUserSid ) + SeLengthSid( SeLocalSystemSid ) + 00114 SeLengthSid( ClientUserSid ) + SeLengthSid( SeAliasAdminsSid ) + 00115 SeLengthSid( SeRestrictedSid ) + sizeof( ACL ); 00116 00117 NewDacl = ExAllocatePool( PagedPool, AclLength ); 00118 00119 if (NewDacl == NULL) { 00120 00121 *Acl = NULL; 00122 return STATUS_INSUFFICIENT_RESOURCES; 00123 } 00124 00125 Status = RtlCreateAcl( NewDacl, AclLength, ACL_REVISION2 ); 00126 ASSERT(NT_SUCCESS( Status )); 00127 00128 Status = RtlAddAccessAllowedAce ( 00129 NewDacl, 00130 ACL_REVISION2, 00131 TOKEN_ALL_ACCESS, 00132 ServerUserSid 00133 ); 00134 ASSERT( NT_SUCCESS( Status )); 00135 00136 Status = RtlAddAccessAllowedAce ( 00137 NewDacl, 00138 ACL_REVISION2, 00139 TOKEN_ALL_ACCESS, 00140 ClientUserSid 00141 ); 00142 ASSERT( NT_SUCCESS( Status )); 00143 00144 Status = RtlAddAccessAllowedAce ( 00145 NewDacl, 00146 ACL_REVISION2, 00147 TOKEN_ALL_ACCESS, 00148 SeAliasAdminsSid 00149 ); 00150 ASSERT( NT_SUCCESS( Status )); 00151 00152 Status = RtlAddAccessAllowedAce ( 00153 NewDacl, 00154 ACL_REVISION2, 00155 TOKEN_ALL_ACCESS, 00156 SeLocalSystemSid 00157 ); 00158 ASSERT( NT_SUCCESS( Status )); 00159 00160 if(ARGUMENT_PRESENT(((PTOKEN)PrimaryToken)->RestrictedSids) || 00161 ARGUMENT_PRESENT(Token->RestrictedSids)) { 00162 Status = RtlAddAccessAllowedAce ( 00163 NewDacl, 00164 ACL_REVISION2, 00165 TOKEN_ALL_ACCESS, 00166 SeRestrictedSid 00167 ); 00168 ASSERT( NT_SUCCESS( Status )); 00169 } 00170 00171 *Acl = NewDacl; 00172 return STATUS_SUCCESS; 00173 } 00174 00175 00176 00177 NTSTATUS 00178 NtOpenProcessToken( 00179 IN HANDLE ProcessHandle, 00180 IN ACCESS_MASK DesiredAccess, 00181 OUT PHANDLE TokenHandle 00182 ) 00183 00184 /*++ 00185 00186 Routine Description: 00187 00188 Open a token object associated with a process and return a handle 00189 that may be used to access that token. 00190 00191 Arguments: 00192 00193 ProcessHandle - Specifies the process whose token is to be 00194 opened. 00195 00196 DesiredAccess - Is an access mask indicating which access types 00197 are desired to the token. These access types are reconciled 00198 with the Discretionary Access Control list of the token to 00199 determine whether the accesses will be granted or denied. 00200 00201 TokenHandle - Receives the handle of the newly opened token. 00202 00203 Return Value: 00204 00205 STATUS_SUCCESS - Indicates the operation was successful. 00206 00207 --*/ 00208 { 00209 00210 PVOID Token; 00211 KPROCESSOR_MODE PreviousMode; 00212 NTSTATUS Status; 00213 00214 HANDLE LocalHandle; 00215 00216 PAGED_CODE(); 00217 00218 PreviousMode = KeGetPreviousMode(); 00219 00220 // 00221 // Probe parameters 00222 // 00223 00224 if (PreviousMode != KernelMode) { 00225 00226 try { 00227 00228 ProbeForWriteHandle(TokenHandle); 00229 00230 } except(EXCEPTION_EXECUTE_HANDLER) { 00231 return GetExceptionCode(); 00232 } // end_try 00233 00234 } //end_if 00235 00236 00237 // 00238 // Valdiate access to the process and obtain a pointer to the 00239 // process's token. If successful, this will cause the token's 00240 // reference count to be incremented. 00241 // 00242 00243 Status = PsOpenTokenOfProcess( ProcessHandle, ((PACCESS_TOKEN *)&Token)); 00244 00245 if (!NT_SUCCESS(Status)) { 00246 return Status; 00247 } 00248 00249 // 00250 // Now try to open the token for the specified desired access 00251 // 00252 00253 Status = ObOpenObjectByPointer( 00254 (PVOID)Token, // Object 00255 0, // HandleAttributes 00256 NULL, // AccessState 00257 DesiredAccess, // DesiredAccess 00258 SepTokenObjectType, // ObjectType 00259 PreviousMode, // AccessMode 00260 &LocalHandle // Handle 00261 ); 00262 00263 // 00264 // And decrement the reference count of the token to counter 00265 // the action performed by PsOpenTokenOfProcess(). If the open 00266 // was successful, the handle will have caused the token's 00267 // reference count to have been incremented. 00268 // 00269 00270 ObDereferenceObject( Token ); 00271 00272 // 00273 // Return the new handle 00274 // 00275 00276 if (NT_SUCCESS(Status)) { 00277 00278 try { 00279 00280 *TokenHandle = LocalHandle; 00281 00282 } except(EXCEPTION_EXECUTE_HANDLER) { 00283 00284 return GetExceptionCode(); 00285 00286 } 00287 } 00288 00289 return Status; 00290 00291 } 00292 00293 NTSTATUS 00294 SepOpenTokenOfThread( 00295 IN HANDLE ThreadHandle, 00296 IN BOOLEAN OpenAsSelf, 00297 OUT PACCESS_TOKEN *Token, 00298 OUT PETHREAD *Thread, 00299 OUT PBOOLEAN CopyOnOpen, 00300 OUT PBOOLEAN EffectiveOnly, 00301 OUT PSECURITY_IMPERSONATION_LEVEL ImpersonationLevel 00302 ) 00303 00304 /*++ 00305 00306 Routine Description: 00307 00308 This function does the thread specific processing of 00309 an NtOpenThreadToken() service. 00310 00311 The service validates that the handle has appropriate access 00312 to reference the thread. If so, it goes on to increment 00313 the reference count of the token object to prevent it from 00314 going away while the rest of the NtOpenThreadToken() request 00315 is processed. 00316 00317 NOTE: If this call completes successfully, the caller is responsible 00318 for decrementing the reference count of the target token. 00319 This must be done using PsDereferenceImpersonationToken(). 00320 00321 Arguments: 00322 00323 ThreadHandle - Supplies a handle to a thread object. 00324 00325 OpenAsSelf - Is a boolean value indicating whether the access should 00326 be made using the calling thread's current security context, which 00327 may be that of a client (if impersonating), or using the caller's 00328 process-level security context. A value of FALSE indicates the 00329 caller's current context should be used un-modified. A value of 00330 TRUE indicates the request should be fulfilled using the process 00331 level security context. 00332 00333 Token - If successful, receives a pointer to the thread's token 00334 object. 00335 00336 CopyOnOpen - The current value of the Thread->Client->CopyOnOpen field. 00337 00338 EffectiveOnly - The current value of the Thread->Client->EffectiveOnly field. 00339 00340 ImpersonationLevel - The current value of the Thread->Client->ImpersonationLevel 00341 field. 00342 00343 Return Value: 00344 00345 STATUS_SUCCESS - Indicates the call completed successfully. 00346 00347 STATUS_NO_TOKEN - Indicates the referenced thread is not currently 00348 impersonating a client. 00349 00350 STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous 00351 impersonation level. An anonymous token can not be openned. 00352 00353 status may also be any value returned by an attemp the reference 00354 the thread object for THREAD_QUERY_INFORMATION access. 00355 00356 --*/ 00357 00358 { 00359 00360 NTSTATUS 00361 Status; 00362 00363 KPROCESSOR_MODE 00364 PreviousMode; 00365 00366 SE_IMPERSONATION_STATE 00367 DisabledImpersonationState; 00368 00369 BOOLEAN 00370 RestoreImpersonationState = FALSE; 00371 00372 PreviousMode = KeGetPreviousMode(); 00373 00374 00375 // 00376 // Disable impersonation if necessary 00377 // 00378 00379 if (OpenAsSelf) { 00380 RestoreImpersonationState = PsDisableImpersonation( 00381 PsGetCurrentThread(), 00382 &DisabledImpersonationState 00383 ); 00384 } 00385 00386 // 00387 // Make sure the handle grants the appropriate access to the specified 00388 // thread. 00389 // 00390 00391 Status = ObReferenceObjectByHandle( 00392 ThreadHandle, 00393 THREAD_QUERY_INFORMATION, 00394 PsThreadType, 00395 PreviousMode, 00396 (PVOID *)Thread, 00397 NULL 00398 ); 00399 00400 00401 00402 00403 if (RestoreImpersonationState) { 00404 PsRestoreImpersonation( 00405 PsGetCurrentThread(), 00406 &DisabledImpersonationState 00407 ); 00408 } 00409 00410 if (!NT_SUCCESS(Status)) { 00411 return Status; 00412 } 00413 00414 // 00415 // Reference the impersonation token, if there is one 00416 // 00417 00418 (*Token) = PsReferenceImpersonationToken( *Thread, 00419 CopyOnOpen, 00420 EffectiveOnly, 00421 ImpersonationLevel 00422 ); 00423 00424 00425 00426 00427 // 00428 // Make sure there is a token 00429 // 00430 00431 if ((*Token) == NULL) { 00432 ObDereferenceObject( *Thread ); 00433 (*Thread) = NULL; 00434 return STATUS_NO_TOKEN; 00435 } 00436 00437 00438 // 00439 // Make sure the ImpersonationLevel is high enough to allow 00440 // the token to be openned. 00441 // 00442 00443 if ((*ImpersonationLevel) <= SecurityAnonymous) { 00444 PsDereferenceImpersonationToken( (*Token) ); 00445 ObDereferenceObject( *Thread ); 00446 (*Thread) = NULL; 00447 (*Token) = NULL; 00448 return STATUS_CANT_OPEN_ANONYMOUS; 00449 } 00450 00451 00452 return STATUS_SUCCESS; 00453 00454 } 00455 00456 00457 NTSTATUS 00458 NtOpenThreadToken( 00459 IN HANDLE ThreadHandle, 00460 IN ACCESS_MASK DesiredAccess, 00461 IN BOOLEAN OpenAsSelf, 00462 OUT PHANDLE TokenHandle 00463 ) 00464 00465 /*++ 00466 00467 00468 Routine Description: 00469 00470 Open a token object associated with a thread and return a handle that 00471 may be used to access that token. 00472 00473 Arguments: 00474 00475 ThreadHandle - Specifies the thread whose token is to be opened. 00476 00477 DesiredAccess - Is an access mask indicating which access types 00478 are desired to the token. These access types are reconciled 00479 with the Discretionary Access Control list of the token to 00480 determine whether the accesses will be granted or denied. 00481 00482 OpenAsSelf - Is a boolean value indicating whether the access should 00483 be made using the calling thread's current security context, which 00484 may be that of a client if impersonating, or using the caller's 00485 process-level security context. A value of FALSE indicates the 00486 caller's current context should be used un-modified. A value of 00487 TRUE indicates the request should be fulfilled using the process 00488 level security context. 00489 00490 This parameter is necessary to allow a server process to open 00491 a client's token when the client specified IDENTIFICATION level 00492 impersonation. In this case, the caller would not be able to 00493 open the client's token using the client's context (because you 00494 can't create executive level objects using IDENTIFICATION level 00495 impersonation). 00496 00497 TokenHandle - Receives the handle of the newly opened token. 00498 00499 Return Value: 00500 00501 STATUS_SUCCESS - Indicates the operation was successful. 00502 00503 STATUS_NO_TOKEN - Indicates an attempt has been made to open a 00504 token associated with a thread that is not currently 00505 impersonating a client. 00506 00507 STATUS_CANT_OPEN_ANONYMOUS - Indicates the client requested anonymous 00508 impersonation level. An anonymous token can not be openned. 00509 00510 --*/ 00511 { 00512 00513 KPROCESSOR_MODE PreviousMode; 00514 NTSTATUS Status; 00515 00516 PVOID Token; 00517 PTOKEN NewToken = NULL; 00518 BOOLEAN CopyOnOpen; 00519 BOOLEAN EffectiveOnly; 00520 SECURITY_IMPERSONATION_LEVEL ImpersonationLevel; 00521 SE_IMPERSONATION_STATE DisabledImpersonationState; 00522 BOOLEAN RestoreImpersonationState = FALSE; 00523 00524 HANDLE LocalHandle; 00525 SECURITY_DESCRIPTOR SecurityDescriptor; 00526 OBJECT_ATTRIBUTES ObjectAttributes; 00527 PACL NewAcl = NULL; 00528 PETHREAD Thread; 00529 PETHREAD OriginalThread = NULL; 00530 PACCESS_TOKEN PrimaryToken; 00531 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 00532 00533 PAGED_CODE(); 00534 00535 PreviousMode = KeGetPreviousMode(); 00536 00537 // 00538 // Probe parameters 00539 // 00540 00541 if (PreviousMode != KernelMode) { 00542 00543 try { 00544 00545 ProbeForWriteHandle(TokenHandle); 00546 00547 } except(EXCEPTION_EXECUTE_HANDLER) { 00548 return GetExceptionCode(); 00549 } // end_try 00550 00551 } //end_if 00552 00553 // 00554 // Valdiate access to the thread and obtain a pointer to the 00555 // thread's token (if there is one). If successful, this will 00556 // cause the token's reference count to be incremented. 00557 // 00558 // This routine disabled impersonation as necessary to properly 00559 // honor the OpenAsSelf flag. 00560 // 00561 00562 Status = SepOpenTokenOfThread( ThreadHandle, 00563 OpenAsSelf, 00564 ((PACCESS_TOKEN *)&Token), 00565 &OriginalThread, 00566 &CopyOnOpen, 00567 &EffectiveOnly, 00568 &ImpersonationLevel 00569 ); 00570 00571 if (!NT_SUCCESS(Status)) { 00572 return Status; 00573 } 00574 00575 00576 // 00577 // The token was successfully referenced. 00578 // 00579 00580 // 00581 // We need to create and/or open a token object, so disable impersonation 00582 // if necessary. 00583 // 00584 00585 if (OpenAsSelf) { 00586 RestoreImpersonationState = PsDisableImpersonation( 00587 PsGetCurrentThread(), 00588 &DisabledImpersonationState 00589 ); 00590 } 00591 00592 // 00593 // If the CopyOnOpen flag is not set, then the token can be 00594 // opened directly. Otherwise, the token must be duplicated, 00595 // and a handle to the duplicate returned. 00596 // 00597 00598 if (CopyOnOpen) { 00599 00600 // 00601 // Create the new security descriptor for the token. 00602 // 00603 // We must obtain the correct SID to put into the Dacl. Do this 00604 // by finding the process associated with the passed thread 00605 // and grabbing the User SID out of that process's token. 00606 // If we just use the current SubjectContext, we'll get the 00607 // SID of whoever is calling us, which isn't what we want. 00608 // 00609 00610 Status = ObReferenceObjectByHandle( 00611 ThreadHandle, 00612 THREAD_ALL_ACCESS, 00613 PsThreadType, 00614 KernelMode, 00615 (PVOID)&Thread, 00616 NULL 00617 ); 00618 00619 // 00620 // Verify that the handle is still pointer to the same thread\ 00621 // BUGBUG: wrong error code. 00622 // 00623 00624 if (NT_SUCCESS(Status) && (Thread != OriginalThread)) { 00625 Status = STATUS_OBJECT_TYPE_MISMATCH; 00626 } 00627 00628 if (NT_SUCCESS(Status)) { 00629 00630 PrimaryToken = PsReferencePrimaryToken(Thread->ThreadsProcess); 00631 00632 Status = SepCreateImpersonationTokenDacl( 00633 (PTOKEN)Token, 00634 PrimaryToken, 00635 &NewAcl 00636 ); 00637 00638 PsDereferencePrimaryToken( PrimaryToken ); 00639 00640 if (NT_SUCCESS( Status )) { 00641 00642 if (NewAcl != NULL) { 00643 00644 // 00645 // There exist tokens that either do not have security descriptors at all, 00646 // or have security descriptors, but do not have DACLs. In either case, do 00647 // nothing. 00648 // 00649 00650 Status = RtlCreateSecurityDescriptor ( &SecurityDescriptor, SECURITY_DESCRIPTOR_REVISION ); 00651 ASSERT( NT_SUCCESS( Status )); 00652 00653 Status = RtlSetDaclSecurityDescriptor ( 00654 &SecurityDescriptor, 00655 TRUE, 00656 NewAcl, 00657 FALSE 00658 ); 00659 00660 ASSERT( NT_SUCCESS( Status )); 00661 } 00662 00663 InitializeObjectAttributes( 00664 &ObjectAttributes, 00665 NULL, 00666 0L, 00667 NULL, 00668 NewAcl == NULL ? NULL : &SecurityDescriptor 00669 ); 00670 00671 // 00672 // Open a copy of the token 00673 // 00674 00675 Status = SepDuplicateToken( 00676 (PTOKEN)Token, // ExistingToken 00677 &ObjectAttributes, // ObjectAttributes 00678 EffectiveOnly, // EffectiveOnly 00679 TokenImpersonation, // TokenType 00680 ImpersonationLevel, // ImpersonationLevel 00681 KernelMode, // RequestorMode must be kernel mode 00682 &NewToken 00683 ); 00684 00685 if (NT_SUCCESS( Status )) { 00686 00687 // 00688 // Reference the token so it doesn't go away 00689 // 00690 00691 ObReferenceObject(NewToken); 00692 00693 // 00694 // Insert the new token 00695 // 00696 00697 Status = ObInsertObject( NewToken, 00698 NULL, 00699 DesiredAccess, 00700 0, 00701 (PVOID *)NULL, 00702 &LocalHandle 00703 ); 00704 } 00705 } 00706 } 00707 00708 00709 } else { 00710 00711 // 00712 // We do not have to modify the security on the token in the static case, 00713 // because in all the places in the system where impersonation takes place 00714 // over a secure transport (e.g., LPC), CopyOnOpen is set. The only reason 00715 // we'be be here is if the impersonation is taking place because someone did 00716 // an NtSetInformationThread and passed in a token. 00717 // 00718 // In that case, we absolutely do not want to give the caller guaranteed 00719 // access, because that would allow anyone who has access to a thread to 00720 // impersonate any of that thread's clients for any access. 00721 // 00722 00723 // 00724 // Open the existing token 00725 // 00726 00727 Status = ObOpenObjectByPointer( 00728 (PVOID)Token, // Object 00729 0, // HandleAttributes 00730 NULL, // AccessState 00731 DesiredAccess, // DesiredAccess 00732 SepTokenObjectType, // ObjectType 00733 PreviousMode, // AccessMode 00734 &LocalHandle // Handle 00735 ); 00736 } 00737 00738 if (NewAcl != NULL) { 00739 ExFreePool( NewAcl ); 00740 } 00741 00742 if (RestoreImpersonationState) { 00743 PsRestoreImpersonation( 00744 PsGetCurrentThread(), 00745 &DisabledImpersonationState 00746 ); 00747 } 00748 00749 // 00750 // And decrement the reference count of the existing token to counter 00751 // the action performed by PsOpenTokenOfThread. If the open 00752 // was successful, the handle will have caused the token's 00753 // reference count to have been incremented. 00754 // 00755 00756 ObDereferenceObject( Token ); 00757 00758 if (NT_SUCCESS( Status ) && CopyOnOpen) { 00759 00760 // 00761 // Assign the newly duplicated token to the thread. 00762 // 00763 00764 PsImpersonateClient( Thread, 00765 NewToken, 00766 FALSE, // turn off CopyOnOpen flag 00767 EffectiveOnly, 00768 ImpersonationLevel 00769 ); 00770 00771 } 00772 00773 // 00774 // We've impersonated the token so let go of oure reference 00775 // 00776 00777 if (NewToken != NULL) { 00778 ObDereferenceObject( NewToken ); 00779 } 00780 00781 if (CopyOnOpen && (Thread != NULL)) { 00782 00783 ObDereferenceObject( Thread ); 00784 } 00785 00786 if (OriginalThread != NULL) { 00787 ObDereferenceObject(OriginalThread); 00788 } 00789 00790 // 00791 // Return the new handle 00792 // 00793 00794 if (NT_SUCCESS(Status)) { 00795 try { *TokenHandle = LocalHandle; } 00796 except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } 00797 } 00798 00799 return Status; 00800 00801 } 00802

Generated on Sat May 15 19:42:01 2004 for test by doxygen 1.3.7