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

token.c

Go to the documentation of this file.
00001 /*++ 00002 00003 Copyright (c) 1989 Microsoft Corporation 00004 00005 Module Name: 00006 00007 token.c 00008 00009 Abstract: 00010 00011 This module implements the initialization, open, duplicate and other 00012 services of the executive token object. 00013 00014 Author: 00015 00016 Jim Kelly (JimK) 5-April-1990 00017 00018 Environment: 00019 00020 Kernel mode only. 00021 00022 Revision History: 00023 00024 v15: robertre 00025 updated ACL_REVISION 00026 00027 --*/ 00028 00029 00030 #include "sep.h" 00031 #include "sertlp.h" 00032 #include <zwapi.h> 00033 #include "tokenp.h" 00034 00035 #ifdef ALLOC_PRAGMA 00036 #pragma alloc_text(INIT,SepTokenInitialization) 00037 #pragma alloc_text(INIT,SeMakeSystemToken) 00038 #pragma alloc_text(INIT,SeMakeAnonymousToken) 00039 #pragma alloc_text(PAGE,SeTokenType) 00040 #pragma alloc_text(PAGE,SeTokenIsAdmin) 00041 #pragma alloc_text(PAGE,SepCreateToken) 00042 #pragma alloc_text(PAGE,SeTokenImpersonationLevel) 00043 #pragma alloc_text(PAGE,SeAssignPrimaryToken) 00044 #pragma alloc_text(PAGE,SeDeassignPrimaryToken) 00045 #pragma alloc_text(PAGE,SeExchangePrimaryToken) 00046 #pragma alloc_text(PAGE,SeGetTokenControlInformation) 00047 #pragma alloc_text(PAGE,SeSubProcessToken) 00048 #pragma alloc_text(PAGE,NtCreateToken) 00049 #pragma alloc_text(PAGE,SepTokenDeleteMethod) 00050 #pragma alloc_text(PAGE,SepIdAssignableAsOwner) 00051 #pragma alloc_text(PAGE,SeIsChildToken) 00052 #pragma alloc_text(PAGE,SeIsChildTokenByPointer) 00053 #pragma alloc_text(PAGE,NtImpersonateAnonymousToken) 00054 #endif 00055 00056 00058 // // 00059 // Global Variables // 00060 // // 00062 00063 // 00064 // Generic mapping of access types 00065 // 00066 00067 GENERIC_MAPPING SepTokenMapping = { TOKEN_READ, 00068 TOKEN_WRITE, 00069 TOKEN_EXECUTE, 00070 TOKEN_ALL_ACCESS 00071 }; 00072 00073 // 00074 // Address of token object type descriptor. 00075 // 00076 00077 POBJECT_TYPE SepTokenObjectType; 00078 00079 00080 // 00081 // Used to track whether or not a system token has been created or not. 00082 // 00083 00084 #if DBG 00085 BOOLEAN SystemTokenCreated = FALSE; 00086 #endif //DBG 00087 00088 00089 // 00090 // Token lock 00091 // 00092 00093 ERESOURCE SepTokenLock; 00094 00095 00096 00097 00098 // 00099 // Used to control the active token diagnostic support provided 00100 // 00101 00102 #ifdef TOKEN_DIAGNOSTICS_ENABLED 00103 ULONG TokenGlobalFlag = 0; 00104 #endif // TOKEN_DIAGNOSTICS_ENABLED 00105 00106 00107 00109 // // 00110 // Token Object Routines & Methods // 00111 // // 00113 00114 00115 00116 00117 TOKEN_TYPE 00118 SeTokenType( 00119 IN PACCESS_TOKEN Token 00120 ) 00121 00122 /*++ 00123 00124 Routine Description: 00125 00126 This function returns the type of an instance of a token (TokenPrimary, 00127 or TokenImpersonation). 00128 00129 00130 Arguments: 00131 00132 Token - Points to the token whose type is to be returned. 00133 00134 Return Value: 00135 00136 The token's type. 00137 00138 --*/ 00139 00140 { 00141 PAGED_CODE(); 00142 00143 return (((PTOKEN)Token)->TokenType); 00144 } 00145 00146 00147 00148 NTKERNELAPI 00149 BOOLEAN 00150 SeTokenIsAdmin( 00151 IN PACCESS_TOKEN Token 00152 ) 00153 00154 /*++ 00155 00156 Routine Description: 00157 00158 Returns if the token is a member of the local admin group. 00159 00160 Arguments: 00161 00162 Token - Points to the token. 00163 00164 Return Value: 00165 00166 TRUE - Token contains the local admin group 00167 FALSE - no admin. 00168 00169 --*/ 00170 00171 { 00172 PAGED_CODE(); 00173 00174 return ((((PTOKEN)Token)->TokenFlags & TOKEN_HAS_ADMIN_GROUP) != 0 ); 00175 } 00176 00177 00178 00179 NTKERNELAPI 00180 BOOLEAN 00181 SeTokenIsRestricted( 00182 IN PACCESS_TOKEN Token 00183 ) 00184 00185 /*++ 00186 00187 Routine Description: 00188 00189 Returns if the token is a restricted token. 00190 00191 Arguments: 00192 00193 Token - Points to the token. 00194 00195 Return Value: 00196 00197 TRUE - Token contains restricted sids 00198 FALSE - no admin. 00199 00200 --*/ 00201 00202 { 00203 PAGED_CODE(); 00204 00205 return ((((PTOKEN)Token)->TokenFlags & TOKEN_IS_RESTRICTED) != 0 ); 00206 } 00207 00208 00209 00210 SECURITY_IMPERSONATION_LEVEL 00211 SeTokenImpersonationLevel( 00212 IN PACCESS_TOKEN Token 00213 ) 00214 00215 /*++ 00216 00217 Routine Description: 00218 00219 This function returns the impersonation level of a token. The token 00220 is assumed to be a TokenImpersonation type token. 00221 00222 00223 Arguments: 00224 00225 Token - Points to the token whose impersonation level is to be returned. 00226 00227 Return Value: 00228 00229 The token's impersonation level. 00230 00231 --*/ 00232 00233 { 00234 PAGED_CODE(); 00235 00236 return ((PTOKEN)Token)->ImpersonationLevel; 00237 } 00238 00239 00240 VOID 00241 SeAssignPrimaryToken( 00242 IN PEPROCESS Process, 00243 IN PACCESS_TOKEN Token 00244 ) 00245 00246 00247 /*++ 00248 00249 Routine Description: 00250 00251 This function establishes a primary token for a process. 00252 00253 Arguments: 00254 00255 Token - Points to the new primary token. 00256 00257 Return Value: 00258 00259 None. 00260 00261 --*/ 00262 00263 { 00264 00265 NTSTATUS 00266 Status; 00267 00268 PTOKEN 00269 NewToken = (PTOKEN)Token; 00270 00271 PAGED_CODE(); 00272 00273 ASSERT(NewToken->TokenType == TokenPrimary); 00274 ASSERT( !NewToken->TokenInUse ); 00275 00276 00277 // 00278 // Dereference the old token if there is one. 00279 // 00280 // Processes typically already have a token that must be 00281 // dereferenced. There are two cases where this may not 00282 // be the situation. First, during phase 0 system initialization, 00283 // the initial system process starts out without a token. Second, 00284 // if an error occurs during process creation, we may be cleaning 00285 // up a process that hasn't yet had a primary token assigned. 00286 // 00287 00288 if (Process->Token != NULL) { 00289 SeDeassignPrimaryToken( Process ); 00290 } 00291 00292 00293 Process->Token=Token; 00294 NewToken->TokenInUse = TRUE; 00295 ObReferenceObject(NewToken); 00296 return; 00297 } 00298 00299 00300 00301 VOID 00302 SeDeassignPrimaryToken( 00303 IN PEPROCESS Process 00304 ) 00305 00306 00307 /*++ 00308 00309 Routine Description: 00310 00311 This function causes a process reference to a token to be 00312 dropped. 00313 00314 Arguments: 00315 00316 Process - Points to the process whose primary token is no longer needed. 00317 This is probably only the case at process deletion or when 00318 a primary token is being replaced. 00319 00320 Return Value: 00321 00322 None. 00323 00324 --*/ 00325 00326 { 00327 00328 PTOKEN 00329 OldToken = (PTOKEN)(Process->Token); 00330 00331 PAGED_CODE(); 00332 00333 ASSERT(OldToken->TokenType == TokenPrimary); 00334 ASSERT(OldToken->TokenInUse); 00335 00336 OldToken->TokenInUse = FALSE; 00337 ObDereferenceObject( OldToken ); 00338 00339 00340 return; 00341 } 00342 00343 00344 00345 NTSTATUS 00346 SeExchangePrimaryToken( 00347 IN PEPROCESS Process, 00348 IN PACCESS_TOKEN NewAccessToken, 00349 OUT PACCESS_TOKEN *OldAccessToken 00350 ) 00351 00352 00353 /*++ 00354 00355 Routine Description: 00356 00357 This function is used to perform the portions of changing a primary 00358 token that reference the internals of token structures. 00359 00360 The new token is checked to make sure it is not already in use. 00361 00362 The 00363 00364 00365 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00366 !!!!!!!! WARNING WARNING WARNING !!!!!!!! 00367 !!!!!!!! !!!!!!!! 00368 !!!!!!!! THIS ROUTINE MUST BE CALLED WITH THE GOBAL !!!!!!!! 00369 !!!!!!!! PROCESS SECURITY FIELDS LOCK HELD !!!!!!!! 00370 !!!!!!!! !!!!!!!! 00371 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 00372 00373 Arguments: 00374 00375 Process - Points to the process whose primary token is being exchanged. 00376 00377 NewAccessToken - Points to the process's new primary token. 00378 00379 OldAccessToken - Receives a pointer to the process's current token. 00380 The caller is responsible for dereferencing this token when 00381 it is no longer needed. This can't be done while the process 00382 security locks are held. 00383 00384 00385 Return Value: 00386 00387 STATUS_SUCCESS - Everything has been updated. 00388 00389 STATUS_TOKEN_ALREADY_IN_USE - A primary token can only be used by a 00390 single process. That is, each process must have its own primary 00391 token. The token passed to be assigned as the primary token is 00392 already in use as a primary token. 00393 00394 STATUS_BAD_TOKEN_TYPE - The new token is not a primary token. 00395 00396 00397 --*/ 00398 00399 { 00400 NTSTATUS 00401 Status; 00402 00403 PTOKEN 00404 OldToken = (PTOKEN)(Process->Token); 00405 00406 PTOKEN 00407 NewToken = (PTOKEN)NewAccessToken; 00408 00409 PAGED_CODE(); 00410 00411 00412 // 00413 // We need to access the security fields of both tokens. 00414 // Access to these fields is guarded by the global Process Security 00415 // fields lock. 00416 // 00417 00418 ASSERT(OldToken->TokenType == TokenPrimary); 00419 ASSERT(OldToken->TokenInUse); 00420 00421 00422 // 00423 // Make sure the new token is a primary token... 00424 // 00425 00426 if ( NewToken->TokenType != TokenPrimary ) { 00427 return(STATUS_BAD_TOKEN_TYPE); 00428 } 00429 00430 // 00431 // and that it is not already in use... 00432 // 00433 00434 if (NewToken->TokenInUse) { 00435 return(STATUS_TOKEN_ALREADY_IN_USE); 00436 } 00437 00438 // 00439 // Ensure SessionId consistent for hydra 00440 // 00441 00442 NewToken->SessionId = OldToken->SessionId ; 00443 00444 00445 00446 // 00447 // Switch the tokens 00448 // 00449 00450 Process->Token=NewAccessToken; 00451 NewToken->TokenInUse = TRUE; 00452 ObReferenceObject(NewToken); 00453 00454 // 00455 // Mark the token as "NOT USED" 00456 // 00457 00458 OldToken->TokenInUse = FALSE; 00459 00460 // 00461 // Return the pointer to the old token. The caller 00462 // is responsible for dereferencing it if they don't need it. 00463 // 00464 00465 (*OldAccessToken) = OldToken; 00466 00467 return (STATUS_SUCCESS); 00468 } 00469 00470 00471 00472 00473 00474 VOID 00475 SeGetTokenControlInformation ( 00476 IN PACCESS_TOKEN Token, 00477 OUT PTOKEN_CONTROL TokenControl 00478 ) 00479 00480 /*++ 00481 00482 Routine Description: 00483 00484 This routine is provided for communication session layers, or 00485 any other executive component that needs to keep track of 00486 whether a caller's security context has changed between calls. 00487 Communication session layers will need to check this, for some 00488 security quality of service modes, to determine whether or not 00489 a server's security context needs to be updated to reflect 00490 changes in the client's security context. 00491 00492 This routine will also be useful to communications subsystems 00493 that need to retrieve client' authentication information from 00494 the local security authority in order to perform a remote 00495 authentication. 00496 00497 00498 Parameters: 00499 00500 Token - Points to the token whose information is to be retrieved. 00501 00502 TokenControl - Points to the buffer to receive the token control 00503 information. 00504 00505 Return Value: 00506 00507 None. 00508 00509 --*/ 00510 00511 { 00512 PAGED_CODE(); 00513 00514 // 00515 // acquire exclusive access to the token 00516 // 00517 00518 SepAcquireTokenReadLock( (PTOKEN)Token ); 00519 00520 // 00521 // Grab the data and run 00522 // 00523 00524 TokenControl->TokenId = ((TOKEN *)Token)->TokenId; 00525 TokenControl->AuthenticationId = ((TOKEN *)Token)->AuthenticationId; 00526 TokenControl->ModifiedId = ((TOKEN *)Token)->ModifiedId; 00527 TokenControl->TokenSource = ((TOKEN *)Token)->TokenSource; 00528 00529 SepReleaseTokenReadLock( (PTOKEN)Token ); 00530 00531 return; 00532 00533 } 00534 00535 PACCESS_TOKEN 00536 SeMakeSystemToken () 00537 00538 /*++ 00539 00540 Routine Description: 00541 00542 This routine is provided for use by executive components 00543 DURING SYSTEM INITIALIZATION ONLY. It creates a token for 00544 use by system components. 00545 00546 A system token has the following characteristics: 00547 00548 - It has LOCAL_SYSTEM as its user ID 00549 00550 - It has the following groups with the corresponding 00551 attributes: 00552 00553 ADMINS_ALIAS EnabledByDefault | 00554 Enabled | 00555 Owner 00556 00557 WORLD EnabledByDefault | 00558 Enabled | 00559 Mandatory 00560 00561 ADMINISTRATORS (alias) Owner (disabled) 00562 00563 AUTHENTICATED_USER 00564 EnabledByDefault | 00565 Enabled | 00566 Mandatory 00567 00568 00569 - It has LOCAL_SYSTEM as its primary group. 00570 00571 - It has the privileges shown in comments below. 00572 00573 00574 - It has protection that provides TOKEN_ALL_ACCESS to 00575 the LOCAL_SYSTEM ID. 00576 00577 00578 - It has a default ACL that grants GENERIC_ALL access 00579 to LOCAL_SYSTEM and GENERIC_EXECUTE to WORLD. 00580 00581 00582 Parameters: 00583 00584 None. 00585 00586 Return Value: 00587 00588 Pointer to a system token. 00589 00590 --*/ 00591 00592 { 00593 NTSTATUS Status; 00594 00595 PVOID Token; 00596 00597 SID_AND_ATTRIBUTES UserId; 00598 TOKEN_PRIMARY_GROUP PrimaryGroup; 00599 PSID_AND_ATTRIBUTES GroupIds; 00600 ULONG GroupIdsLength; 00601 LUID_AND_ATTRIBUTES Privileges[30]; 00602 PACL TokenAcl; 00603 PSID Owner; 00604 ULONG NormalGroupAttributes; 00605 ULONG OwnerGroupAttributes; 00606 ULONG Length; 00607 OBJECT_ATTRIBUTES TokenObjectAttributes; 00608 PSECURITY_DESCRIPTOR TokenSecurityDescriptor; 00609 ULONG BufferLength; 00610 PVOID Buffer; 00611 00612 ULONG_PTR GroupIdsBuffer[128 * sizeof(ULONG) / sizeof(ULONG_PTR)]; 00613 00614 TIME_FIELDS TimeFields; 00615 LARGE_INTEGER NoExpiration; 00616 00617 PAGED_CODE(); 00618 00619 00620 // 00621 // Make sure only one system token gets created. 00622 // 00623 00624 #if DBG 00625 ASSERT( !SystemTokenCreated ); 00626 SystemTokenCreated = TRUE; 00627 #endif //DBG 00628 00629 00630 // 00631 // Set up expiration times 00632 // 00633 00634 TimeFields.Year = 3000; 00635 TimeFields.Month = 1; 00636 TimeFields.Day = 1; 00637 TimeFields.Hour = 1; 00638 TimeFields.Minute = 1; 00639 TimeFields.Second = 1; 00640 TimeFields.Milliseconds = 1; 00641 TimeFields.Weekday = 1; 00642 00643 RtlTimeFieldsToTime( &TimeFields, &NoExpiration ); 00644 00645 00646 // // 00647 // // The amount of memory used in the following is gross overkill, but 00648 // // it is freed up immediately after creating the token. 00649 // // 00650 // 00651 // GroupIds = (PSID_AND_ATTRIBUTES)ExAllocatePool( NonPagedPool, 512 ); 00652 00653 GroupIds = (PSID_AND_ATTRIBUTES)GroupIdsBuffer; 00654 00655 00656 // 00657 // Set up the attributes to be assigned to groups 00658 // 00659 00660 NormalGroupAttributes = (SE_GROUP_MANDATORY | 00661 SE_GROUP_ENABLED_BY_DEFAULT | 00662 SE_GROUP_ENABLED 00663 ); 00664 00665 OwnerGroupAttributes = (SE_GROUP_ENABLED_BY_DEFAULT | 00666 SE_GROUP_ENABLED | 00667 SE_GROUP_OWNER 00668 ); 00669 00670 // 00671 // Set up the user ID 00672 // 00673 00674 UserId.Sid = SeLocalSystemSid; 00675 UserId.Attributes = 0; 00676 00677 // 00678 // Set up the groups 00679 // 00680 00681 00682 GroupIds->Sid = SeAliasAdminsSid; 00683 (GroupIds+1)->Sid = SeWorldSid; 00684 (GroupIds+2)->Sid = SeAuthenticatedUsersSid; 00685 00686 GroupIds->Attributes = OwnerGroupAttributes; 00687 (GroupIds+1)->Attributes = NormalGroupAttributes; 00688 (GroupIds+2)->Attributes = NormalGroupAttributes; 00689 00690 GroupIdsLength = (ULONG)LongAlignSize(SeLengthSid(GroupIds->Sid)) + 00691 (ULONG)LongAlignSize(SeLengthSid((GroupIds+1)->Sid)) + 00692 (ULONG)LongAlignSize(SeLengthSid((GroupIds+2)->Sid)) + 00693 sizeof(SID_AND_ATTRIBUTES); 00694 00695 ASSERT( GroupIdsLength <= 128 * sizeof(ULONG) ); 00696 00697 00698 // 00699 // Privileges 00700 // 00701 00702 // 00703 // The privileges in the system token are as follows: 00704 // 00705 // Privilege Name Attributes 00706 // -------------- ---------- 00707 // 00708 // SeTcbPrivilege enabled/enabled by default 00709 // SeCreateTokenPrivilege DISabled/NOT enabled by default 00710 // SeTakeOwnershipPrivilege DISabled/NOT enabled by default 00711 // SeCreatePagefilePrivilege enabled/enabled by default 00712 // SeLockMemoryPrivilege enabled/enabled by default 00713 // SeAssignPrimaryTokenPrivilege DISabled/NOT enabled by default 00714 // SeIncreaseQuotaPrivilege DISabled/NOT enabled by default 00715 // SeIncreaseBasePriorityPrivilege enabled/enabled by default 00716 // SeCreatePermanentPrivilege enabled/enabled by default 00717 // SeDebugPrivilege enabled/enabled by default 00718 // SeAuditPrivilege enabled/enabled by default 00719 // SeSecurityPrivilege DISabled/NOT enabled by default 00720 // SeSystemEnvironmentPrivilege DISabled/NOT enabled by default 00721 // SeChangeNotifyPrivilege enabled/enabled by default 00722 // SeBackupPrivilege DISabled/NOT enabled by default 00723 // SeRestorePrivilege DISabled/NOT enabled by default 00724 // SeShutdownPrivilege DISabled/NOT enabled by default 00725 // SeLoadDriverPrivilege DISabled/NOT enabled by default 00726 // SeProfileSingleProcessPrivilege enabled/enabled by default 00727 // SeSystemtimePrivilege DISabled/NOT enabled by default 00728 // SeUndockPrivilege DISabled/NOT enabled by default 00729 // 00730 // The following privileges are not present, and should never be present in 00731 // the local system token: 00732 // 00733 // SeRemoteShutdownPrivilege no one can come in as local system 00734 // SeSyncAgentPrivilege only users specified by the admin can 00735 // be sync agents 00736 // SeEnableDelegationPrivilege only users specified by the admin can 00737 // enable delegation on accounts. 00738 // 00739 00740 Privileges[0].Luid = SeTcbPrivilege; 00741 Privileges[0].Attributes = 00742 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00743 SE_PRIVILEGE_ENABLED); // Enabled 00744 00745 Privileges[1].Luid = SeCreateTokenPrivilege; 00746 Privileges[1].Attributes = 0; // Only the LSA should enable this. 00747 00748 Privileges[2].Luid = SeTakeOwnershipPrivilege; 00749 Privileges[2].Attributes = 0; 00750 00751 Privileges[3].Luid = SeCreatePagefilePrivilege; 00752 Privileges[3].Attributes = 00753 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00754 SE_PRIVILEGE_ENABLED); // Enabled 00755 00756 Privileges[4].Luid = SeLockMemoryPrivilege; 00757 Privileges[4].Attributes = 00758 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00759 SE_PRIVILEGE_ENABLED); // Enabled 00760 00761 Privileges[5].Luid = SeAssignPrimaryTokenPrivilege; 00762 Privileges[5].Attributes = 0; // disabled, not enabled by default 00763 00764 Privileges[6].Luid = SeIncreaseQuotaPrivilege; 00765 Privileges[6].Attributes = 0; // disabled, not enabled by default 00766 00767 Privileges[7].Luid = SeIncreaseBasePriorityPrivilege; 00768 Privileges[7].Attributes = 00769 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00770 SE_PRIVILEGE_ENABLED); // Enabled 00771 00772 Privileges[8].Luid = SeCreatePermanentPrivilege; 00773 Privileges[8].Attributes = 00774 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00775 SE_PRIVILEGE_ENABLED); // Enabled 00776 00777 Privileges[9].Luid = SeDebugPrivilege; 00778 Privileges[9].Attributes = 00779 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00780 SE_PRIVILEGE_ENABLED); // Enabled 00781 00782 Privileges[10].Luid = SeAuditPrivilege; 00783 Privileges[10].Attributes = 00784 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00785 SE_PRIVILEGE_ENABLED); // Enabled 00786 00787 Privileges[11].Luid = SeSecurityPrivilege; 00788 Privileges[11].Attributes = 0; // disabled, not enabled by default 00789 00790 Privileges[12].Luid = SeSystemEnvironmentPrivilege; 00791 Privileges[12].Attributes = 0; // disabled, not enabled by default 00792 00793 Privileges[13].Luid = SeChangeNotifyPrivilege; 00794 Privileges[13].Attributes = 00795 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00796 SE_PRIVILEGE_ENABLED); // Enabled 00797 00798 00799 Privileges[14].Luid = SeBackupPrivilege; 00800 Privileges[14].Attributes = 0; // disabled, not enabled by default 00801 00802 Privileges[15].Luid = SeRestorePrivilege; 00803 Privileges[15].Attributes = 0; // disabled, not enabled by default 00804 00805 Privileges[16].Luid = SeShutdownPrivilege; 00806 Privileges[16].Attributes = 0; // disabled, not enabled by default 00807 00808 Privileges[17].Luid = SeLoadDriverPrivilege; 00809 Privileges[17].Attributes = 0; // disabled, not enabled by default 00810 00811 Privileges[18].Luid = SeProfileSingleProcessPrivilege; 00812 Privileges[18].Attributes = 00813 (SE_PRIVILEGE_ENABLED_BY_DEFAULT | // Enabled by default 00814 SE_PRIVILEGE_ENABLED); // Enabled 00815 00816 Privileges[19].Luid = SeSystemtimePrivilege; 00817 Privileges[19].Attributes = 0; // disabled, not enabled by default 00818 00819 Privileges[20].Luid = SeUndockPrivilege ; 00820 Privileges[20].Attributes = 0 ; // disabled, not enabled by default 00821 00822 //BEFORE ADDING ANOTHER PRIVILEGE ^^ HERE ^^ CHECK THE ARRAY BOUND 00823 //ALSO INCREMENT THE PRIVILEGE COUNT IN THE SepCreateToken() call 00824 00825 00826 // 00827 // Establish the primary group and default owner 00828 // 00829 00830 PrimaryGroup.PrimaryGroup = SeLocalSystemSid; // Primary group 00831 Owner = SeAliasAdminsSid; // Default owner 00832 00833 00834 00835 00836 00837 // 00838 // Set up an ACL to protect token as well ... 00839 // give system full reign of terror. This includes user-mode components 00840 // running as part of the system. 00841 // 00842 00843 Length = (ULONG)sizeof(ACL) + 00844 ((ULONG)sizeof(ACCESS_ALLOWED_ACE) - sizeof(ULONG)) + 00845 SeLengthSid( SeLocalSystemSid ) ; 00846 00847 TokenAcl = (PACL)ExAllocatePoolWithTag(PagedPool, Length, 'cAeS'); 00848 00849 if ( TokenAcl == NULL ) { 00850 00851 return NULL ; 00852 } 00853 00854 Status = RtlCreateAcl( TokenAcl, Length, ACL_REVISION2); 00855 ASSERT( NT_SUCCESS(Status) ); 00856 00857 Status = RtlAddAccessAllowedAce ( 00858 TokenAcl, 00859 ACL_REVISION2, 00860 TOKEN_ALL_ACCESS, 00861 SeLocalSystemSid 00862 ); 00863 ASSERT( NT_SUCCESS(Status) ); 00864 00865 TokenSecurityDescriptor = 00866 (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( 00867 PagedPool, 00868 sizeof(SECURITY_DESCRIPTOR), 00869 'dSeS' 00870 ); 00871 00872 if ( TokenSecurityDescriptor == NULL ) { 00873 00874 ExFreePool( TokenAcl ); 00875 00876 return NULL ; 00877 } 00878 00879 Status = RtlCreateSecurityDescriptor( 00880 TokenSecurityDescriptor, 00881 SECURITY_DESCRIPTOR_REVISION 00882 ); 00883 ASSERT( NT_SUCCESS(Status) ); 00884 00885 Status = RtlSetDaclSecurityDescriptor ( 00886 TokenSecurityDescriptor, 00887 TRUE, 00888 TokenAcl, 00889 FALSE 00890 ); 00891 ASSERT( NT_SUCCESS(Status) ); 00892 00893 00894 Status = RtlSetOwnerSecurityDescriptor ( 00895 TokenSecurityDescriptor, 00896 SeAliasAdminsSid, 00897 FALSE // Owner defaulted 00898 ); 00899 ASSERT( NT_SUCCESS(Status) ); 00900 00901 Status = RtlSetGroupSecurityDescriptor ( 00902 TokenSecurityDescriptor, 00903 SeAliasAdminsSid, 00904 FALSE // Group defaulted 00905 ); 00906 ASSERT( NT_SUCCESS(Status) ); 00907 00908 00909 // 00910 // Create the system token 00911 // 00912 00913 #ifdef TOKEN_DEBUG 00914 00915 // 00916 // Debug 00917 DbgPrint("\n Creating system token...\n"); 00918 // Debug 00919 // 00921 #endif //TOKEN_DEBUG 00922 00923 InitializeObjectAttributes( 00924 &TokenObjectAttributes, 00925 NULL, 00926 0, 00927 NULL, 00928 TokenSecurityDescriptor 00929 ); 00930 00931 00932 00933 ASSERT(SeSystemDefaultDacl != NULL); 00934 Status = SepCreateToken( 00935 (PHANDLE)&Token, 00936 KernelMode, 00937 0, // No handle created for system token 00938 &TokenObjectAttributes, 00939 TokenPrimary, 00940 (SECURITY_IMPERSONATION_LEVEL)0, 00941 &SeSystemAuthenticationId, 00942 &NoExpiration, 00943 &UserId, 00944 3, // GroupCount 00945 GroupIds, 00946 GroupIdsLength, 00947 21, // privileges 00948 Privileges, 00949 sizeof(Privileges), 00950 Owner, 00951 PrimaryGroup.PrimaryGroup, 00952 SeSystemDefaultDacl, 00953 &SeSystemTokenSource, 00954 TRUE, // System token 00955 NULL, 00956 NULL 00957 ); 00958 00959 ASSERT(NT_SUCCESS(Status)); 00960 00961 // 00962 // Assign the security descriptor here, since we don't do it 00963 // in SepCreateToken for the System Token. 00964 // 00965 00966 BufferLength = Length + 00967 sizeof(SECURITY_DESCRIPTOR_RELATIVE) + 00968 2 * SeLengthSid(SeAliasAdminsSid); 00969 00970 Buffer = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( PagedPool, 00971 BufferLength, 00972 'dSeS' 00973 ); 00974 00975 if ( Buffer ) { 00976 00977 Status = RtlAbsoluteToSelfRelativeSD( TokenSecurityDescriptor, 00978 Buffer, 00979 &BufferLength 00980 ); 00981 ASSERT(NT_SUCCESS(Status)); 00982 00983 Status = ObAssignObjectSecurityDescriptor( Token, 00984 Buffer, 00985 PagedPool 00986 ); 00987 ASSERT(NT_SUCCESS(Status)); 00988 00989 } else { 00990 00991 ObDereferenceObject( Token ); 00992 00993 Token = NULL ; 00994 00995 } 00996 00997 // 00998 // We can free the old one now. 00999 // 01000 01001 ExFreePool( TokenAcl ); 01002 ExFreePool( TokenSecurityDescriptor ); 01003 01004 return (PACCESS_TOKEN)Token; 01005 01006 } 01007 01008 01009 PACCESS_TOKEN 01010 SeMakeAnonymousLogonToken ( 01011 VOID 01012 ) 01013 01014 /*++ 01015 01016 Routine Description: 01017 01018 This routine is provided for use by executive components 01019 DURING SYSTEM INITIALIZATION ONLY. It creates a token for 01020 use by system components. 01021 01022 A system token has the following characteristics: 01023 01024 - It has ANONYMOUS_LOGON as its user ID 01025 01026 - It has the following groups with the corresponding 01027 attributes: 01028 01029 01030 WORLD EnabledByDefault | 01031 Enabled | 01032 Mandatory 01033 01034 01035 - It has WORLD as its primary group. 01036 01037 - It has no privileges/ 01038 01039 01040 - It has protection that provides TOKEN_ALL_ACCESS to 01041 the WORLD ID. 01042 01043 01044 - It has a default ACL that grants GENERIC_ALL access 01045 to WORLD. 01046 01047 01048 Parameters: 01049 01050 None. 01051 01052 Return Value: 01053 01054 Pointer to a system token. 01055 01056 --*/ 01057 01058 { 01059 NTSTATUS Status; 01060 01061 PVOID Token; 01062 01063 SID_AND_ATTRIBUTES UserId; 01064 PSID_AND_ATTRIBUTES GroupIds; 01065 TOKEN_PRIMARY_GROUP PrimaryGroup; 01066 ULONG GroupIdsLength; 01067 PACL TokenAcl; 01068 PSID Owner; 01069 ULONG NormalGroupAttributes; 01070 ULONG Length; 01071 OBJECT_ATTRIBUTES TokenObjectAttributes; 01072 PSECURITY_DESCRIPTOR TokenSecurityDescriptor; 01073 ULONG BufferLength; 01074 PVOID Buffer; 01075 01076 ULONG_PTR GroupIdsBuffer[128 * sizeof(ULONG) / sizeof(ULONG_PTR)]; 01077 01078 TIME_FIELDS TimeFields; 01079 LARGE_INTEGER NoExpiration; 01080 01081 PAGED_CODE(); 01082 01083 01084 01085 // 01086 // Set up expiration times 01087 // 01088 01089 TimeFields.Year = 3000; 01090 TimeFields.Month = 1; 01091 TimeFields.Day = 1; 01092 TimeFields.Hour = 1; 01093 TimeFields.Minute = 1; 01094 TimeFields.Second = 1; 01095 TimeFields.Milliseconds = 1; 01096 TimeFields.Weekday = 1; 01097 01098 RtlTimeFieldsToTime( &TimeFields, &NoExpiration ); 01099 01100 01101 01102 GroupIds = (PSID_AND_ATTRIBUTES)GroupIdsBuffer; 01103 01104 01105 // 01106 // Set up the attributes to be assigned to groups 01107 // 01108 01109 NormalGroupAttributes = (SE_GROUP_MANDATORY | 01110 SE_GROUP_ENABLED_BY_DEFAULT | 01111 SE_GROUP_ENABLED 01112 ); 01113 01114 01115 // 01116 // Set up the user ID 01117 // 01118 01119 UserId.Sid = SeAnonymousLogonSid; 01120 UserId.Attributes = 0; 01121 01122 // 01123 // Set up the groups 01124 // 01125 01126 01127 GroupIds->Sid = SeWorldSid; 01128 GroupIds->Attributes = NormalGroupAttributes; 01129 01130 01131 GroupIdsLength = (ULONG)LongAlignSize(SeLengthSid(GroupIds->Sid)) + 01132 sizeof(SID_AND_ATTRIBUTES); 01133 01134 ASSERT( GroupIdsLength <= 128 * sizeof(ULONG) ); 01135 01136 01137 // 01138 // Privileges 01139 // 01140 01141 01142 // 01143 // Establish the primary group and default owner 01144 // 01145 01146 PrimaryGroup.PrimaryGroup = SeAnonymousLogonSid; // Primary group 01147 01148 01149 01150 01151 01152 // 01153 // Set up an ACL to protect token as well ... 01154 // give system full reign of terror. This includes user-mode components 01155 // running as part of the system. 01156 // 01157 01158 Length = (ULONG)sizeof(ACL) + 01159 (ULONG)sizeof(ACCESS_ALLOWED_ACE) + 01160 SeLengthSid( SeWorldSid ) + 01161 8; // The 8 is just for good measure 01162 ASSERT( Length < 200 ); 01163 01164 TokenAcl = (PACL)ExAllocatePoolWithTag(PagedPool, 200, 'cAeS'); 01165 01166 if ( !TokenAcl ) { 01167 01168 return NULL ; 01169 } 01170 01171 Status = RtlCreateAcl( TokenAcl, Length, ACL_REVISION2); 01172 ASSERT( NT_SUCCESS(Status) ); 01173 01174 Status = RtlAddAccessAllowedAce ( 01175 TokenAcl, 01176 ACL_REVISION2, 01177 TOKEN_ALL_ACCESS, 01178 SeWorldSid 01179 ); 01180 ASSERT( NT_SUCCESS(Status) ); 01181 01182 TokenSecurityDescriptor = 01183 (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( 01184 PagedPool, 01185 SECURITY_DESCRIPTOR_MIN_LENGTH, 01186 'dSeS' 01187 ); 01188 01189 if ( !TokenSecurityDescriptor ) { 01190 01191 ExFreePool( TokenAcl ); 01192 01193 return NULL ; 01194 } 01195 01196 01197 Status = RtlCreateSecurityDescriptor( 01198 TokenSecurityDescriptor, 01199 SECURITY_DESCRIPTOR_REVISION 01200 ); 01201 ASSERT( NT_SUCCESS(Status) ); 01202 01203 Status = RtlSetDaclSecurityDescriptor ( 01204 TokenSecurityDescriptor, 01205 TRUE, 01206 TokenAcl, 01207 FALSE 01208 ); 01209 ASSERT( NT_SUCCESS(Status) ); 01210 01211 01212 Status = RtlSetOwnerSecurityDescriptor ( 01213 TokenSecurityDescriptor, 01214 SeWorldSid, 01215 FALSE // Owner defaulted 01216 ); 01217 ASSERT( NT_SUCCESS(Status) ); 01218 01219 Status = RtlSetGroupSecurityDescriptor ( 01220 TokenSecurityDescriptor, 01221 SeWorldSid, 01222 FALSE // Group defaulted 01223 ); 01224 ASSERT( NT_SUCCESS(Status) ); 01225 01226 01227 // 01228 // Create the system token 01229 // 01230 01231 #ifdef TOKEN_DEBUG 01232 01233 // 01234 // Debug 01235 DbgPrint("\n Creating system token...\n"); 01236 // Debug 01237 // 01239 #endif //TOKEN_DEBUG 01240 01241 InitializeObjectAttributes( 01242 &TokenObjectAttributes, 01243 NULL, 01244 0, 01245 NULL, 01246 TokenSecurityDescriptor 01247 ); 01248 01249 01250 01251 Status = SepCreateToken( 01252 (PHANDLE)&Token, 01253 KernelMode, 01254 0, // No handle created for system token 01255 &TokenObjectAttributes, 01256 TokenPrimary, 01257 (SECURITY_IMPERSONATION_LEVEL)0, 01258 &SeAnonymousAuthenticationId, 01259 &NoExpiration, 01260 &UserId, 01261 1, // GroupCount 01262 GroupIds, 01263 GroupIdsLength, 01264 0, // no privileges 01265 NULL, // no Privileges, 01266 0, // no privileges 01267 NULL, 01268 PrimaryGroup.PrimaryGroup, 01269 TokenAcl, 01270 &SeSystemTokenSource, 01271 TRUE, // System token 01272 NULL, 01273 NULL 01274 ); 01275 01276 ASSERT(NT_SUCCESS(Status)); 01277 01278 // 01279 // Assign the security descriptor here, since we don't do it 01280 // in SepCreateToken for the System Token. 01281 // 01282 01283 BufferLength = Length + 01284 sizeof(SECURITY_DESCRIPTOR) + 01285 2 * SeLengthSid(SeAliasAdminsSid); 01286 01287 Buffer = (PSECURITY_DESCRIPTOR)ExAllocatePoolWithTag( PagedPool, 01288 BufferLength, 01289 'dSeS' 01290 ); 01291 01292 if ( Buffer ) { 01293 01294 Status = RtlAbsoluteToSelfRelativeSD( TokenSecurityDescriptor, 01295 Buffer, 01296 &BufferLength 01297 ); 01298 ASSERT(NT_SUCCESS(Status)); 01299 01300 Status = ObAssignObjectSecurityDescriptor( Token, 01301 Buffer, 01302 PagedPool 01303 ); 01304 ASSERT(NT_SUCCESS(Status)); 01305 01306 } else { 01307 01308 ObDereferenceObject( Token ); 01309 01310 Token = NULL ; 01311 } 01312 01313 01314 // 01315 // We can free the old one now. 01316 // 01317 01318 ExFreePool( TokenAcl ); 01319 ExFreePool( TokenSecurityDescriptor ); 01320 01321 return (PACCESS_TOKEN)Token; 01322 01323 } 01324 01325 01326 NTSTATUS 01327 SeSubProcessToken ( 01328 IN PEPROCESS ParentProcess, 01329 OUT PACCESS_TOKEN *ChildToken 01330 ) 01331 01332 /*++ 01333 01334 Routine Description: 01335 01336 This routine makes a token for a sub-process that is a duplicate 01337 of the parent process's token. 01338 01339 01340 01341 Parameters: 01342 01343 ParentProcess - Pointer to the parent process object. This is used 01344 to locate the parent process's primary token, and for logging 01345 purposes. 01346 01347 ChildToken - Receives a pointer to the child process's token. 01348 01349 Return Value: 01350 01351 STATUS_SUCCESS - Indicates the sub-process's token has been created 01352 successfully. 01353 01354 Other status values may be returned from memory allocation or object 01355 creation services used and typically indicate insufficient resources 01356 or quota on the requestor's part. 01357 01358 01359 01360 --*/ 01361 01362 { 01363 01364 // 01365 // NOTE: THIS ROUTINE CAN BE MADE MUCH MORE EFFICIENT. 01366 // IT IS DONE IN A BRUTE FORCE FASHION FOR THE LARGE_INTEGER 01367 // BEING TO GET THINGS UP AND RUNNING. 01368 // 01369 // THE PERFORMANCE OF THIS ROUTINE DIRECTLY IMPACTS 01370 // THE PERFORMANCE OF SUB-PROCESS CREATION. 01371 // 01372 01373 01374 KPROCESSOR_MODE PreviousMode; 01375 PTOKEN ParentToken; 01376 PTOKEN NewToken; 01377 HANDLE NewTokenHandle; 01378 OBJECT_ATTRIBUTES PrimaryTokenAttributes; 01379 01380 PTOKEN InsertedToken; 01381 01382 NTSTATUS Status; 01383 NTSTATUS IgnoreStatus; 01384 01385 PAGED_CODE(); 01386 01387 PreviousMode = KeGetPreviousMode(); 01388 01389 InitializeObjectAttributes( 01390 &PrimaryTokenAttributes, 01391 NULL, 01392 0, 01393 NULL, 01394 NULL 01395 ); 01396 01397 #ifdef TOKEN_DEBUG 01398 DbgPrint("\nCreating sub-process token...\n"); 01399 DbgPrint("Parent token address = 0x%lx\n", ParentProcess->Token); 01400 #endif //TOKEN_DEBUG 01401 01402 ParentToken = (PTOKEN)PsReferencePrimaryToken( ParentProcess ); 01403 01404 Status = SepDuplicateToken( 01405 ParentToken, // ExistingToken 01406 &PrimaryTokenAttributes, // ObjectAttributes 01407 FALSE, // EffectiveOnly 01408 TokenPrimary, // TokenType 01409 (SECURITY_IMPERSONATION_LEVEL)0, // ImpersonationLevel 01410 KernelMode, // RequestorMode 01411 &NewToken // NewToken 01412 ); 01413 01414 PsDereferencePrimaryToken( (PACCESS_TOKEN)ParentToken ); 01415 01416 if (NT_SUCCESS(Status)) { 01417 01418 // 01419 // Insert the new token object, up its ref count, and then 01420 // delete the new handle. 01421 // 01422 01423 Status = ObInsertObject( 01424 NewToken, 01425 NULL, 01426 0, 01427 1, // ObjectPointerBias 01428 (PVOID *)&InsertedToken, 01429 &NewTokenHandle 01430 ); 01431 01432 if (NT_SUCCESS(Status)) { 01433 01434 *ChildToken = InsertedToken; 01435 InsertedToken->TokenInUse = TRUE; 01436 IgnoreStatus = ZwClose( NewTokenHandle ); 01437 01438 // 01439 // At this point, either the token has a reference 01440 // outstanding (and no handles), or the reference 01441 // failed. If the reference failed, the status will 01442 // be returned indicating why. 01443 // 01444 01445 } else { 01446 01447 // 01448 // ObInsertObject dereferences the passed object if it 01449 // fails, so we don't have to do any cleanup on NewToken 01450 // here. 01451 // 01452 } 01453 } 01454 01455 return Status; 01456 } 01457 01458 01459 BOOLEAN 01460 SepTokenInitialization ( VOID ) 01461 01462 /*++ 01463 01464 Routine Description: 01465 01466 This function creates the token object type descriptor at system 01467 initialization and stores the address of the object type descriptor 01468 in global storage. It also created token related global variables. 01469 01470 Furthermore, some number of pseudo tokens are created during system 01471 initialization. These tokens are tracked down and replaced with 01472 real tokens. 01473 01474 Arguments: 01475 01476 None. 01477 01478 Return Value: 01479 01480 A value of TRUE is returned if the object type descriptor is 01481 successfully initialized. Otherwise a value of FALSE is returned. 01482 01483 --*/ 01484 01485 { 01486 01487 OBJECT_TYPE_INITIALIZER ObjectTypeInitializer; 01488 NTSTATUS Status; 01489 UNICODE_STRING TypeName; 01490 01491 PAGED_CODE(); 01492 01493 // 01494 // Initialize string descriptor. 01495 // 01496 01497 RtlInitUnicodeString(&TypeName, L"Token"); 01498 01499 01500 // 01501 // Create the global token lock 01502 // 01503 01504 ExInitializeResource(&SepTokenLock); 01505 01506 01507 #if 0 01508 BUG, BUG Need to get system default ACL to protect token object 01509 #endif 01510 01511 // 01512 // Create object type descriptor. 01513 // 01514 01515 RtlZeroMemory(&ObjectTypeInitializer,sizeof(ObjectTypeInitializer)); 01516 ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer); 01517 ObjectTypeInitializer.InvalidAttributes = OBJ_OPENLINK; 01518 ObjectTypeInitializer.GenericMapping = SepTokenMapping; 01519 ObjectTypeInitializer.SecurityRequired = TRUE; 01520 ObjectTypeInitializer.UseDefaultObject = TRUE; 01521 ObjectTypeInitializer.PoolType = PagedPool; 01522 ObjectTypeInitializer.ValidAccessMask = TOKEN_ALL_ACCESS; 01523 ObjectTypeInitializer.DeleteProcedure = SepTokenDeleteMethod; 01524 01525 Status = ObCreateObjectType(&TypeName, 01526 &ObjectTypeInitializer, 01527 (PSECURITY_DESCRIPTOR)NULL, // BUG, BUG assign real protection 01528 &SepTokenObjectType 01529 ); 01530 01531 01532 #if 0 01533 BUG, BUG Now track down all pseudo tokens used during system initialization 01534 BUG, BUG and replace them with real ones. 01535 #endif 01536 01537 // 01538 // If the object type descriptor was successfully created, then 01539 // return a value of TRUE. Otherwise return a value of FALSE. 01540 // 01541 01542 return (BOOLEAN)NT_SUCCESS(Status); 01543 } 01544 01546 // // 01547 // Temporary, for Debug only // 01548 // // 01550 #ifdef TOKEN_DEBUG 01551 VOID 01552 SepDumpToken( 01553 IN PTOKEN T 01554 ) 01555 01556 { 01557 ULONG Index; 01558 01559 // 01560 // Dump a token 01561 // 01562 01563 DbgPrint("\n"); 01564 01565 DbgPrint(" address: 0x%lx \n", ((ULONG)T) ); 01566 01567 DbgPrint(" TokenId: (0x%lx, 0x%lx) \n", 01568 T->TokenId.HighPart, T->TokenId.LowPart ); 01569 01570 if ( (T->AuthenticationId.Data[0] == SeSystemAuthenticationId.Data[0]) && 01571 (T->AuthenticationId.Data[1] == SeSystemAuthenticationId.Data[1]) && 01572 (T->AuthenticationId.Data[2] == SeSystemAuthenticationId.Data[2]) && 01573 (T->AuthenticationId.Data[3] == SeSystemAuthenticationId.Data[3]) ) { 01574 01575 DbgPrint(" AuthenticationId: SeSystemAuthenticationId \n"); 01576 01577 } else { 01578 01579 DbgPrint(" AuthenticationId: (0x%lx, 0x%lx, 0x%lx, 0x%lx) \n", 01580 T->AuthenticationId.Data[0], 01581 T->AuthenticationId.Data[1], 01582 T->AuthenticationId.Data[2], 01583 T->AuthenticationId.Data[3] ); 01584 } 01585 01586 DbgPrint(" ExpirationTime: 0x%lx, 0x%lx \n", 01587 T->ExpirationTime.HighPart, 01588 T->ExpirationTime.LowPart ); 01589 01590 if (T->TokenType == TokenPrimary) { 01591 DbgPrint(" TokenType: Primary \n"); 01592 } else { 01593 if (T->TokenType == TokenImpersonation) { 01594 DbgPrint(" TokenType: Impersonation \n"); 01595 } else { 01596 DbgPrint(" TokenType: (Unknown type, value = 0x%lx) \n", 01597 ((ULONG)T-TokenType) ); 01598 } 01599 } 01600 01601 DbgPrint(" ImpersonationLevel: 0x%lx \n", 01602 ((ULONG)T->ImpersonationLevel) ); 01603 01604 DbgPrint(" TokenSource: (not yet provided) \n"); 01605 DbgPrint(" DynamicCharged: 0x%lx \n", T->DynamicCharged); 01606 DbgPrint(" UserAndGroupCount: 0x%lx \n", T->UserAndGroupCount); 01607 DbgPrint(" PrivilegeCount: 0x%lx \n", T->PrivilegeCount); 01608 DbgPrint(" VariableLength: 0x%lx \n", T->VariableLength); 01609 01610 01611 DbgPrint(" ModifiedId: (0x%lx, 0x%lx) \n", 01612 T->ModifiedId.HighPart, 01613 T->ModifiedId.LowPart ); 01614 DbgPrint(" DynamicAvailable: 0x%lx \n", T->DynamicAvailable); 01615 DbgPrint(" DefaultOwnerIndex: 0x%lx \n", T->DefaultOwnerIndex); 01616 01617 01618 DbgPrint(" Address of DynamicPart: 0x%lx \n", 01619 (* (PULONG)((PVOID)(&(T->DynamicPart)))) ); 01620 DbgPrint(" Address of Default DACL: 0x%lx \n", 01621 (* (PULONG)((PVOID)(&(T->DefaultDacl)))) ); 01622 01623 DbgPrint(" Address Of Variable Part: 0x%lx \n", 01624 &(T->VariablePart) ); 01625 01626 DbgPrint("\n"); 01627 DbgPrint(" PrimaryGroup:\n"); 01628 DbgPrint(" Address: 0x%lx \n", 01629 (* (PULONG)((PVOID)(&(T->PrimaryGroup)))) ); 01630 DbgPrint(" Length: 0x%lx \n", 01631 SeLengthSid((T->PrimaryGroup)) ); 01632 DbgPrint("\n"); 01633 DbgPrint(" UserAndGroups: 0x%lx \n", 01634 (* (PULONG)((PVOID)(&(T->UserAndGroups)))) ); 01635 DbgPrint(" User ID - \n"); 01636 DbgPrint(" Address: 0x%lx \n", 01637 (* (PULONG)((PVOID)(&(T->UserAndGroups[0].Sid)))) ); 01638 DbgPrint(" Attributes: 0x%lx \n", 01639 (T->UserAndGroups[0].Attributes) ); 01640 DbgPrint(" Length: 0x%lx \n", 01641 SeLengthSid((T->UserAndGroups[0].Sid)) ); 01642 Index = 1; 01643 while (Index < T->UserAndGroupCount) { 01644 DbgPrint(" Group 0x%lx - \n", Index ); 01645 DbgPrint(" Address: 0x%lx \n", 01646 (* (PULONG)((PVOID)(&(T->UserAndGroups[Index].Sid)))) ); 01647 DbgPrint(" Attributes: 0x%lx \n", 01648 (T->UserAndGroups[Index].Attributes) ); 01649 DbgPrint(" Length: 0x%lx \n", 01650 SeLengthSid((T->UserAndGroups[Index].Sid)) ); 01651 Index += 1; 01652 } 01653 01654 Index = 0; 01655 while (Index < T->RestrictedSidCount) { 01656 DbgPrint(" Sid 0x%lx - \n", Index ); 01657 DbgPrint(" Address: 0x%lx \n", 01658 (* (PULONG)((PVOID)(&(T->RestrictedSids[Index].Sid)))) ); 01659 DbgPrint(" Attributes: 0x%lx \n", 01660 (T->RestrictedSids[Index].Attributes) ); 01661 DbgPrint(" Length: 0x%lx \n", 01662 SeLengthSid((T->RestrictedSids[Index].Sid)) ); 01663 Index += 1; 01664 } 01665 01666 01667 DbgPrint("\n"); 01668 DbgPrint(" Privileges: 0x%lx\n", 01669 (* (PULONG)((PVOID)(&(T->Privileges)))) ); 01670 Index = 0; 01671 while (Index < T->PrivilegeCount) { 01672 DbgPrint(" Privilege 0x%lx - \n", Index ); 01673 DbgPrint(" Address: 0x%lx \n", 01674 (&(T->Privileges[Index])) ); 01675 DbgPrint(" LUID: (0x%lx, 0x%lx) \n", 01676 T->Privileges[Index].Luid.HighPart, 01677 T->Privileges[Index].Luid.LowPart ); 01678 DbgPrint(" Attributes: 0x%lx \n", 01679 T->Privileges[Index].Attributes ); 01680 01681 Index += 1; 01682 } 01683 01684 return; 01685 01686 } 01687 #endif //TOKEN_DEBUG 01688 01689 NTSTATUS 01690 NtCreateToken( 01691 OUT PHANDLE TokenHandle, 01692 IN ACCESS_MASK DesiredAccess, 01693 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 01694 IN TOKEN_TYPE TokenType, 01695 IN PLUID AuthenticationId, 01696 IN PLARGE_INTEGER ExpirationTime, 01697 IN PTOKEN_USER User, 01698 IN PTOKEN_GROUPS Groups, 01699 IN PTOKEN_PRIVILEGES Privileges, 01700 IN PTOKEN_OWNER Owner OPTIONAL, 01701 IN PTOKEN_PRIMARY_GROUP PrimaryGroup, 01702 IN PTOKEN_DEFAULT_DACL DefaultDacl OPTIONAL, 01703 IN PTOKEN_SOURCE TokenSource 01704 ) 01705 01706 /*++ 01707 01708 Routine Description: 01709 01710 Create a token object and return a handle opened for access to 01711 that token. This API requires SeCreateTokenPrivilege privilege. 01712 01713 Arguments: 01714 01715 TokenHandle - Receives the handle of the newly created token. 01716 01717 DesiredAccess - Is an access mask indicating which access types 01718 the handle is to provide to the new object. 01719 01720 ObjectAttributes - Points to the standard object attributes data 01721 structure. Refer to the NT Object Management 01722 Specification for a description of this data structure. 01723 01724 If the token type is TokenImpersonation, then this parameter 01725 must specify the impersonation level of the token. 01726 01727 TokenType - Type of token to be created. Privilege is required 01728 to create any type of token. 01729 01730 AuthenticationId - Points to a LUID (or LUID) providing a unique 01731 identifier associated with the authentication. This is used 01732 within security only, for audit purposes. 01733 01734 ExpirationTime - Time at which the token becomes invalid. If this 01735 value is specified as zero, then the token has no expiration 01736 time. 01737 01738 User - Is the user SID to place in the token. 01739 01740 Groups - Are the group SIDs to place in the token. 01741 01742 Privileges - Are the privileges to place in the token. 01743 01744 Owner - (Optionally) identifies an identifier that is to be used 01745 as the default owner for the token. If not provided, the 01746 user ID is made the default owner. 01747 01748 PrimaryGroup - Identifies which of the group IDs is to be the 01749 primary group of the token. 01750 01751 DefaultDacl - (optionally) establishes an ACL to be used as the 01752 default discretionary access protection for the token. 01753 01754 TokenSource - Identifies the token source name string and 01755 identifier to be assigned to the token. 01756 01757 Return Value: 01758 01759 STATUS_SUCCESS - Indicates the operation was successful. 01760 01761 STATUS_INVALID_OWNER - Indicates the ID provided to be assigned 01762 as the default owner of the token does not have an attribute 01763 indicating it may be assigned as an owner. 01764 01765 STATUS_INVALID_PRIMARY_GROUP - Indicates the group ID provided 01766 via the PrimaryGroup parameter was not among those assigned 01767 to the token in the Groups parameter. 01768 01769 STATUS_BAD_IMPERSONATION_LEVEL - Indicates no impersonation level 01770 was provided when attempting to create a token of type 01771 TokenImpersonation. 01772 01773 --*/ 01774 01775 { 01776 01777 KPROCESSOR_MODE PreviousMode; 01778 NTSTATUS Status; 01779 ULONG Ignore; 01780 01781 01782 HANDLE LocalHandle; 01783 01784 BOOLEAN SecurityQosPresent = FALSE; 01785 SECURITY_ADVANCED_QUALITY_OF_SERVICE CapturedSecurityQos; 01786 01787 LUID CapturedAuthenticationId; 01788 LARGE_INTEGER CapturedExpirationTime; 01789 01790 PSID_AND_ATTRIBUTES CapturedUser = NULL; 01791 ULONG CapturedUserLength; 01792 01793 ULONG CapturedGroupCount; 01794 PSID_AND_ATTRIBUTES CapturedGroups = NULL; 01795 ULONG CapturedGroupsLength; 01796 01797 ULONG CapturedPrivilegeCount; 01798 PLUID_AND_ATTRIBUTES CapturedPrivileges = NULL; 01799 ULONG CapturedPrivilegesLength; 01800 01801 PSID CapturedOwner = NULL; 01802 01803 PSID CapturedPrimaryGroup = NULL; 01804 01805 PACL CapturedDefaultDacl = NULL; 01806 01807 TOKEN_SOURCE CapturedTokenSource; 01808 01809 PVOID CapturedAddress; 01810 01811 PAGED_CODE(); 01812 01813 PreviousMode = KeGetPreviousMode(); 01814 01815 if (PreviousMode != KernelMode) { 01816 01817 // 01818 // Probe everything necessary for input to the capture subroutines. 01819 // 01820 01821 try { 01822 01823 ProbeForWriteHandle(TokenHandle); 01824 01825 01826 ProbeForRead( ExpirationTime, sizeof(LARGE_INTEGER), sizeof(ULONG) ); 01827 ProbeForRead( Groups, sizeof(TOKEN_GROUPS), sizeof(ULONG) ); 01828 ProbeForRead( Privileges, sizeof(TOKEN_PRIVILEGES), sizeof(ULONG) ); 01829 ProbeForRead( TokenSource, sizeof(TOKEN_SOURCE), sizeof(ULONG) ); 01830 01831 01832 if ( ARGUMENT_PRESENT(Owner) ) { 01833 ProbeForRead( Owner, sizeof(TOKEN_OWNER), sizeof(ULONG) ); 01834 } 01835 01836 01837 ProbeForRead( 01838 PrimaryGroup, 01839 sizeof(TOKEN_PRIMARY_GROUP), 01840 sizeof(ULONG) 01841 ); 01842 01843 01844 if ( ARGUMENT_PRESENT(DefaultDacl) ) { 01845 ProbeForRead( 01846 DefaultDacl, 01847 sizeof(TOKEN_DEFAULT_DACL), 01848 sizeof(ULONG) 01849 ); 01850 } 01851 01852 ProbeForRead( 01853 AuthenticationId, 01854 sizeof(LUID), 01855 sizeof(ULONG) 01856 ); 01857 01858 } except(EXCEPTION_EXECUTE_HANDLER) { 01859 return GetExceptionCode(); 01860 } // end_try 01861 01862 } //end_if 01863 01864 // 01865 // Capture the security quality of service. 01866 // This capture routine necessarily does some probing of its own. 01867 // 01868 01869 Status = SeCaptureSecurityQos( 01870 ObjectAttributes, 01871 PreviousMode, 01872 &SecurityQosPresent, 01873 &CapturedSecurityQos 01874 ); 01875 01876 if (!NT_SUCCESS(Status)) { 01877 return Status; 01878 } 01879 01880 if (TokenType == TokenImpersonation) { 01881 01882 if (!SecurityQosPresent) { 01883 return STATUS_BAD_IMPERSONATION_LEVEL; 01884 } // endif 01885 01886 } // endif 01887 01888 01889 // 01890 // Capture the rest of the arguments. 01891 // These arguments have already been probed. 01892 // 01893 01894 try { 01895 01896 Status = STATUS_SUCCESS; 01897 01898 // 01899 // Capture and validate AuthenticationID 01900 // 01901 01902 RtlCopyLuid( &CapturedAuthenticationId, AuthenticationId ); 01903 01904 // 01905 // Capture ExpirationTime 01906 // 01907 01908 CapturedExpirationTime = (*ExpirationTime); 01909 01910 // 01911 // Capture User 01912 // 01913 01914 if (NT_SUCCESS(Status)) { 01915 Status = SeCaptureSidAndAttributesArray( 01916 &(User->User), 01917 1, 01918 PreviousMode, 01919 NULL, 0, 01920 PagedPool, 01921 TRUE, 01922 &CapturedUser, 01923 &CapturedUserLength 01924 ); 01925 } 01926 01927 01928 // 01929 // Capture Groups 01930 // 01931 01932 if (NT_SUCCESS(Status)) { 01933 CapturedGroupCount = Groups->GroupCount; 01934 Status = SeCaptureSidAndAttributesArray( 01935 (Groups->Groups), 01936 CapturedGroupCount, 01937 PreviousMode, 01938 NULL, 0, 01939 PagedPool, 01940 TRUE, 01941 &CapturedGroups, 01942 &CapturedGroupsLength 01943 ); 01944 } 01945 01946 01947 // 01948 // Capture Privileges 01949 // 01950 01951 if (NT_SUCCESS(Status)) { 01952 CapturedPrivilegeCount = Privileges->PrivilegeCount; 01953 Status = SeCaptureLuidAndAttributesArray( 01954 (Privileges->Privileges), 01955 CapturedPrivilegeCount, 01956 PreviousMode, 01957 NULL, 0, 01958 PagedPool, 01959 TRUE, 01960 &CapturedPrivileges, 01961 &CapturedPrivilegesLength 01962 ); 01963 } 01964 01965 01966 // 01967 // Capture Owner 01968 // 01969 01970 if ( ARGUMENT_PRESENT(Owner) && NT_SUCCESS(Status)) { 01971 CapturedAddress = Owner->Owner; 01972 Status = SeCaptureSid( 01973 (PSID)CapturedAddress, 01974 PreviousMode, 01975 NULL, 0, 01976 PagedPool, 01977 TRUE, 01978 &CapturedOwner 01979 ); 01980 } 01981 01982 01983 // 01984 // Capture PrimaryGroup 01985 // 01986 if (NT_SUCCESS(Status)) { 01987 CapturedAddress = PrimaryGroup->PrimaryGroup; 01988 Status = SeCaptureSid( 01989 (PSID)CapturedAddress, 01990 PreviousMode, 01991 NULL, 0, 01992 PagedPool, 01993 TRUE, 01994 &CapturedPrimaryGroup 01995 ); 01996 } 01997 01998 01999 // 02000 // Capture DefaultDacl 02001 // 02002 02003 if ( ARGUMENT_PRESENT(DefaultDacl) && NT_SUCCESS(Status) ) { 02004 CapturedAddress = DefaultDacl->DefaultDacl; 02005 if (CapturedAddress != NULL) { 02006 Status = SeCaptureAcl( 02007 (PACL)CapturedAddress, 02008 PreviousMode, 02009 NULL, 0, 02010 NonPagedPool, 02011 TRUE, 02012 &CapturedDefaultDacl, 02013 &Ignore 02014 ); 02015 } 02016 } 02017 02018 // 02019 // Capture TokenSource 02020 // 02021 02022 CapturedTokenSource = (*TokenSource); 02023 02024 02025 } except(EXCEPTION_EXECUTE_HANDLER) { 02026 02027 if (CapturedUser != NULL) { 02028 SeReleaseSidAndAttributesArray( 02029 CapturedUser, 02030 PreviousMode, 02031 TRUE 02032 ); 02033 } 02034 02035 if (CapturedGroups != NULL) { 02036 SeReleaseSidAndAttributesArray( 02037 CapturedGroups, 02038 PreviousMode, 02039 TRUE 02040 ); 02041 } 02042 02043 if (CapturedPrivileges != NULL) { 02044 SeReleaseLuidAndAttributesArray( 02045 CapturedPrivileges, 02046 PreviousMode, 02047 TRUE 02048 ); 02049 } 02050 02051 if (CapturedOwner != NULL) { 02052 SeReleaseSid( CapturedOwner, PreviousMode, TRUE); 02053 } 02054 02055 if (CapturedPrimaryGroup != NULL) { 02056 SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE); 02057 } 02058 02059 if (CapturedDefaultDacl != NULL) { 02060 SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE); 02061 } 02062 02063 if (SecurityQosPresent == TRUE) { 02064 SeFreeCapturedSecurityQos( &CapturedSecurityQos ); 02065 } 02066 02067 return GetExceptionCode(); 02068 02069 } // end_try{} 02070 02071 // 02072 // Create the token 02073 // 02074 02075 if (NT_SUCCESS(Status)) { 02076 Status = SepCreateToken( 02077 &LocalHandle, 02078 PreviousMode, 02079 DesiredAccess, 02080 ObjectAttributes, 02081 TokenType, 02082 CapturedSecurityQos.ImpersonationLevel, 02083 &CapturedAuthenticationId, 02084 &CapturedExpirationTime, 02085 CapturedUser, 02086 CapturedGroupCount, 02087 CapturedGroups, 02088 CapturedGroupsLength, 02089 CapturedPrivilegeCount, 02090 CapturedPrivileges, 02091 CapturedPrivilegesLength, 02092 CapturedOwner, 02093 CapturedPrimaryGroup, 02094 CapturedDefaultDacl, 02095 &CapturedTokenSource, 02096 FALSE, // Not a system token 02097 SecurityQosPresent ? CapturedSecurityQos.ProxyData : NULL, 02098 SecurityQosPresent ? CapturedSecurityQos.AuditData : NULL 02099 ); 02100 } 02101 02102 // 02103 // Clean up the temporary capture buffers 02104 // 02105 02106 if (CapturedUser != NULL) { 02107 SeReleaseSidAndAttributesArray( CapturedUser, PreviousMode, TRUE); 02108 } 02109 if (CapturedGroups != NULL) { 02110 SeReleaseSidAndAttributesArray( CapturedGroups, PreviousMode, TRUE); 02111 } 02112 02113 if (CapturedPrivileges != NULL) { 02114 SeReleaseLuidAndAttributesArray( CapturedPrivileges, PreviousMode, TRUE); 02115 } 02116 02117 if (CapturedOwner != NULL) { 02118 SeReleaseSid( CapturedOwner, PreviousMode, TRUE); 02119 } 02120 02121 if (CapturedPrimaryGroup != NULL) { 02122 SeReleaseSid( CapturedPrimaryGroup, PreviousMode, TRUE); 02123 } 02124 02125 if (CapturedDefaultDacl != NULL) { 02126 SeReleaseAcl( CapturedDefaultDacl, PreviousMode, TRUE); 02127 } 02128 02129 if (SecurityQosPresent == TRUE) { 02130 SeFreeCapturedSecurityQos( &CapturedSecurityQos ); 02131 } 02132 02133 // 02134 // Return the handle to this new token 02135 // 02136 02137 if (NT_SUCCESS(Status)) { 02138 try { *TokenHandle = LocalHandle; } 02139 except(EXCEPTION_EXECUTE_HANDLER) { return GetExceptionCode(); } 02140 } 02141 02142 return Status; 02143 02144 } 02145 02146 02147 02149 // // 02150 // Token Private Routines // 02151 // // 02153 02154 02155 VOID 02156 SepTokenDeleteMethod ( 02157 IN PVOID Token 02158 ) 02159 02160 /*++ 02161 02162 Routine Description: 02163 02164 This function is the token object type-specific delete method. 02165 It is needed to ensure that all memory allocated for the token 02166 gets deallocated. 02167 02168 Arguments: 02169 02170 Token - Points to the token object being deleted. 02171 02172 Return Value: 02173 02174 None. 02175 02176 --*/ 02177 02178 { 02179 PAGED_CODE(); 02180 02181 // 02182 // De-reference the logon session referenced by this token object 02183 // 02184 02185 SepDeReferenceLogonSession( &(((TOKEN *)Token)->AuthenticationId) ); 02186 02187 02188 // 02189 // If the token has an associated Dynamic part, deallocate it. 02190 // 02191 02192 if (ARGUMENT_PRESENT( ((TOKEN *)Token)->DynamicPart)) { 02193 ExFreePool( ((TOKEN *)Token)->DynamicPart ); 02194 } 02195 02196 // 02197 // Free the Proxy and Global audit structures if present. 02198 // 02199 02200 if (ARGUMENT_PRESENT(((TOKEN *) Token)->ProxyData)) { 02201 SepFreeProxyData( ((TOKEN *)Token)->ProxyData ); 02202 } 02203 02204 if (ARGUMENT_PRESENT(((TOKEN *)Token)->AuditData )) { 02205 ExFreePool( (((TOKEN *)Token)->AuditData) ); 02206 } 02207 02208 02209 return; 02210 } 02211 02212 NTSTATUS 02213 SepCreateToken( 02214 OUT PHANDLE TokenHandle, 02215 IN KPROCESSOR_MODE RequestorMode, 02216 IN ACCESS_MASK DesiredAccess, 02217 IN POBJECT_ATTRIBUTES ObjectAttributes OPTIONAL, 02218 IN TOKEN_TYPE TokenType, 02219 IN SECURITY_IMPERSONATION_LEVEL ImpersonationLevel OPTIONAL, 02220 IN PLUID AuthenticationId, 02221 IN PLARGE_INTEGER ExpirationTime, 02222 IN PSID_AND_ATTRIBUTES User, 02223 IN ULONG GroupCount, 02224 IN PSID_AND_ATTRIBUTES Groups, 02225 IN ULONG GroupsLength, 02226 IN ULONG PrivilegeCount, 02227 IN PLUID_AND_ATTRIBUTES Privileges, 02228 IN ULONG PrivilegesLength, 02229 IN PSID Owner OPTIONAL, 02230 IN PSID PrimaryGroup, 02231 IN PACL DefaultDacl OPTIONAL, 02232 IN PTOKEN_SOURCE TokenSource, 02233 IN BOOLEAN SystemToken, 02234 IN PSECURITY_TOKEN_PROXY_DATA ProxyData OPTIONAL, 02235 IN PSECURITY_TOKEN_AUDIT_DATA AuditData OPTIONAL 02236 ) 02237 02238 /*++ 02239 02240 Routine Description: 02241 02242 Create a token object and return a handle opened for access to 02243 that token. This API implements the bulk of the work needed 02244 for NtCreateToken. 02245 02246 All parameters except DesiredAccess and ObjectAttributes are assumed 02247 to have been probed and captured. 02248 02249 The output parameter (TokenHandle) is expected to be returned to a 02250 safe address, rather than to a user mode address that may cause an 02251 exception. 02252 02253 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 02254 NOTE: This routine is also used to create the initial system token. 02255 In that case, the SystemToken parameter is TRUE and no handle 02256 is established to the token. Instead, a pointer to the token 02257 is returned via the TokenHandle parameter. 02258 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 02259 02260 02261 Arguments: 02262 02263 TokenHandle - Receives the handle of the newly created token. If the 02264 SystemToken parameter is specified is true, then this parameter 02265 receives a pointer to the token instead of a handle to the token. 02266 02267 RequestorMode - The mode of the caller on whose behalf the token 02268 is being created. 02269 02270 DesiredAccess - Is an access mask indicating which access types 02271 the handle is to provide to the new object. 02272 02273 ObjectAttributes - Points to the standard object attributes data 02274 structure. Refer to the NT Object Management 02275 Specification for a description of this data structure. 02276 02277 TokenType - Type of token to be created. Privilege is required 02278 to create any type of token. 02279 02280 ImpersonationLevel - If the token type is TokenImpersonation, then 02281 this parameter is used to specify the impersonation level of 02282 the token. 02283 02284 AuthenticationId - Points to a LUID (or LUID) providing a unique 02285 identifier associated with the authentication. This is used 02286 within security only, for audit purposes. 02287 02288 ExpirationTime - Time at which the token becomes invalid. If this 02289 value is specified as zero, then the token has no expiration 02290 time. 02291 02292 User - Is the user SID to place in the token. 02293 02294 GroupCount - Indicates the number of groups in the 'Groups' parameter. 02295 This value may be zero, in which case the 'Groups' parameter is 02296 ignored. 02297 02298 Groups - Are the group SIDs, and their corresponding attributes, 02299 to place in the token. 02300 02301 GroupsLength - Indicates the length, in bytes, of the array of groups 02302 to place in the token. 02303 02304 PrivilegeCount - Indicates the number of privileges in the 'Privileges' 02305 parameter. This value may be zero, in which case the 'Privileges' 02306 parameter is ignored. 02307 02308 Privileges - Are the privilege LUIDs, and their corresponding attributes, 02309 to place in the token. 02310 02311 PrivilegesLength - Indicates the length, in bytes, of the array of 02312 privileges to place in the token. 02313 02314 Owner - (Optionally) identifies an identifier that is to be used 02315 as the default owner for the token. If not provided, the 02316 user ID is made the default owner. 02317 02318 PrimaryGroup - Identifies which of the group IDs is to be the 02319 primary group of the token. 02320 02321 DefaultDacl - (optionally) establishes an ACL to be used as the 02322 default discretionary access protection for the token. 02323 02324 TokenSource - Identifies the token source name string and 02325 identifier to be assigned to the token. 02326 02327 Return Value: 02328 02329 STATUS_SUCCESS - Indicates the operation was successful. 02330 02331 STATUS_INVALID_OWNER - Indicates the ID provided to be assigned 02332 as the default owner of the token does not have an attribute 02333 indicating it may be assigned as an owner. 02334 02335 STATUS_INVALID_PRIMARY_GROUP - Indicates the group ID provided 02336 via the PrimaryGroup parameter was not among those assigned 02337 to the token in the Groups parameter. 02338 02339 STATUS_INVALID_PARAMETER - Indicates that a required parameter, 02340 such as User or PrimaryGroup, was not provided with a legitimate 02341 value. 02342 02343 --*/ 02344 02345 { 02346 02347 PTOKEN Token; 02348 NTSTATUS Status; 02349 02350 ULONG PagedPoolSize; 02351 02352 ULONG PrimaryGroupLength; 02353 02354 ULONG TokenBodyLength; 02355 ULONG VariableLength; 02356 02357 ULONG DefaultOwnerIndex; 02358 PUCHAR Where ; 02359 ULONG ComputedPrivLength ; 02360 02361 //ULONG_PTR NextFree; 02362 PSID NextSidFree; 02363 02364 ULONG DynamicLength = TOKEN_DEFAULT_DYNAMIC_CHARGE; 02365 ULONG DynamicLengthUsed; 02366 02367 ULONG SubAuthorityCount; 02368 ULONG GroupIndex; 02369 ULONG PrivilegeIndex; 02370 BOOLEAN OwnerFound; 02371 02372 UCHAR TokenFlags = 0; 02373 02374 ACCESS_STATE AccessState; 02375 AUX_ACCESS_DATA AuxData; 02376 LUID NewModifiedId; 02377 02378 PAGED_CODE(); 02379 02380 ASSERT( sizeof(SECURITY_IMPERSONATION_LEVEL) <= sizeof(ULONG) ); 02381 02382 // 02383 // Make sure the Enabled and Enabled-by-default bits are set on every 02384 // mandatory group. 02385 // 02386 // Also, check to see if the local administrators alias is present. 02387 // if so, turn on the flag so that we can do restrictions later 02388 // 02389 02390 for (GroupIndex=0; GroupIndex < GroupCount; GroupIndex++) { 02391 if (Groups[GroupIndex].Attributes & SE_GROUP_MANDATORY) { 02392 Groups[GroupIndex].Attributes |= (SE_GROUP_ENABLED | SE_GROUP_ENABLED_BY_DEFAULT); 02393 } 02394 if ( RtlEqualSid( SeAliasAdminsSid, Groups[GroupIndex].Sid ) ) 02395 { 02396 TokenFlags |= TOKEN_HAS_ADMIN_GROUP ; 02397 } 02398 } 02399 02400 // 02401 // Check to see if the token being created is going to be granted 02402 // SeChangeNotifyPrivilege. If so, set a flag in the TokenFlags field 02403 // so we can find this out quickly. 02404 // 02405 02406 for (PrivilegeIndex = 0; PrivilegeIndex < PrivilegeCount; PrivilegeIndex++) { 02407 02408 if (((RtlEqualLuid(&Privileges[PrivilegeIndex].Luid,&SeChangeNotifyPrivilege)) 02409 && 02410 (Privileges[PrivilegeIndex].Attributes & SE_PRIVILEGE_ENABLED))) { 02411 02412 TokenFlags |= TOKEN_HAS_TRAVERSE_PRIVILEGE; 02413 break; 02414 } 02415 } 02416 02417 02418 // 02419 // Get a ModifiedId to use 02420 // 02421 02422 ExAllocateLocallyUniqueId( &NewModifiedId ); 02423 02424 // 02425 // Validate the owner ID, if provided and establish the default 02426 // owner index. 02427 // 02428 02429 if (!ARGUMENT_PRESENT(Owner)) { 02430 02431 DefaultOwnerIndex = 0; 02432 02433 } else { 02434 02435 02436 if ( RtlEqualSid( Owner, User->Sid ) ) { 02437 02438 DefaultOwnerIndex = 0; 02439 02440 } else { 02441 02442 GroupIndex = 0; 02443 OwnerFound = FALSE; 02444 02445 while ((GroupIndex < GroupCount) && (!OwnerFound)) { 02446 02447 if ( RtlEqualSid( Owner, (Groups[GroupIndex].Sid) ) ) { 02448 02449 // 02450 // Found a match - make sure it is assignable as owner. 02451 // 02452 02453 if ( SepArrayGroupAttributes( Groups, GroupIndex ) & 02454 SE_GROUP_OWNER ) { 02455 02456 DefaultOwnerIndex = GroupIndex + 1; 02457 OwnerFound = TRUE; 02458 02459 } else { 02460 02461 return STATUS_INVALID_OWNER; 02462 02463 } // endif Owner attribute set 02464 02465 } // endif owner = group 02466 02467 GroupIndex += 1; 02468 02469 } // endwhile 02470 02471 if (!OwnerFound) { 02472 02473 return STATUS_INVALID_OWNER; 02474 02475 } // endif !OwnerFound 02476 } // endif owner = user 02477 } // endif owner specified 02478 02479 02480 02481 // 02482 // Increment the reference count for this logon session 02483 // (fail if there is no corresponding logon session.) 02484 // 02485 02486 Status = SepReferenceLogonSession( AuthenticationId ); 02487 if ( !NT_SUCCESS(Status) ) { 02488 return Status; 02489 } 02490 02491 02492 02493 02494 // 02495 // Calculate the length needed for the variable portion of the token 02496 // This includes the User ID, Group IDs, and Privileges 02497 // 02498 // 02499 // Align the privilege chunk by pointer alignment so that the SIDs will 02500 // be correctly aligned. Align the Groups Length so that the SID_AND_ATTR 02501 // array (which is 02502 // 02503 02504 ComputedPrivLength = PrivilegeCount * sizeof( LUID_AND_ATTRIBUTES ) ; 02505 02506 ComputedPrivLength = ALIGN_UP( ComputedPrivLength, PVOID ); 02507 02508 GroupsLength = ALIGN_UP( GroupsLength, PVOID ); 02509 02510 02511 VariableLength = GroupsLength + ComputedPrivLength + 02512 ALIGN_UP( (GroupCount * sizeof( SID_AND_ATTRIBUTES )), PVOID ) ; 02513 02514 SubAuthorityCount = ((SID *)(User->Sid))->SubAuthorityCount; 02515 VariableLength += sizeof(SID_AND_ATTRIBUTES) + 02516 (ULONG)LongAlignSize(RtlLengthRequiredSid( SubAuthorityCount )); 02517 02518 02519 02520 // 02521 // Calculate the length needed for the dynamic portion of the token 02522 // This includes the default Dacl and the primary group. 02523 // 02524 02525 SubAuthorityCount = ((SID *)PrimaryGroup)->SubAuthorityCount; 02526 DynamicLengthUsed = (ULONG)LongAlignSize(RtlLengthRequiredSid( SubAuthorityCount )); 02527 02528 if (ARGUMENT_PRESENT(DefaultDacl)) { 02529 DynamicLengthUsed += (ULONG)LongAlignSize(DefaultDacl->AclSize); 02530 } 02531 02532 if (DynamicLengthUsed > DynamicLength) { 02533 DynamicLength = DynamicLengthUsed; 02534 } 02535 02536 // 02537 // Now create the token body 02538 // 02539 02540 TokenBodyLength = sizeof(TOKEN) + VariableLength; 02541 PagedPoolSize = TokenBodyLength + DynamicLength; 02542 02543 02544 Status = ObCreateObject( 02545 RequestorMode, // ProbeMode 02546 SepTokenObjectType, // ObjectType 02547 ObjectAttributes, // ObjectAttributes 02548 UserMode, // OwnershipMode 02549 NULL, // ParseContext 02550 TokenBodyLength, // ObjectBodySize 02551 PagedPoolSize, // PagedPoolCharge 02552 0, // NonPagedPoolCharge 02553 (PVOID *)&Token // Return pointer to object 02554 ); 02555 02556 if (!NT_SUCCESS(Status)) { 02557 SepDeReferenceLogonSession( AuthenticationId ); 02558 return Status; 02559 } 02560 02561 // 02562 // After this point, we rely on token deletion to clean up the referenced 02563 // logon session if the creation fails. 02564 // 02565 02566 02567 // 02568 // Main Body initialization 02569 // 02570 02571 02572 ExAllocateLocallyUniqueId( &(Token->TokenId) ); 02573 Token->ParentTokenId = RtlConvertLongToLuid(0); 02574 Token->AuthenticationId = (*AuthenticationId); 02575 Token->TokenInUse = FALSE; 02576 Token->ModifiedId = NewModifiedId; 02577 Token->ExpirationTime = (*ExpirationTime); 02578 Token->TokenType = TokenType; 02579 Token->ImpersonationLevel = ImpersonationLevel; 02580 Token->TokenSource = (*TokenSource); 02581 02582 Token->TokenFlags = TokenFlags; 02583 Token->SessionId = 0; 02584 02585 Token->DynamicCharged = DynamicLength; 02586 Token->DynamicAvailable = DynamicLength - DynamicLengthUsed; 02587 02588 Token->DefaultOwnerIndex = DefaultOwnerIndex; 02589 Token->DefaultDacl = NULL; 02590 02591 Token->VariableLength = VariableLength; 02592 02593 // Ensure SepTokenDeleteMethod knows the buffers aren't allocated yet. 02594 Token->ProxyData = NULL; 02595 Token->AuditData = NULL; 02596 Token->DynamicPart = NULL; 02597 02598 if (ARGUMENT_PRESENT( ProxyData )) { 02599 02600 Status = SepCopyProxyData( 02601 &Token->ProxyData, 02602 ProxyData 02603 ); 02604 02605 if (!NT_SUCCESS(Status)) { 02606 ObDereferenceObject( Token ); 02607 return( STATUS_NO_MEMORY ); 02608 } 02609 02610 } else { 02611 02612 Token->ProxyData = NULL; 02613 } 02614 02615 if (ARGUMENT_PRESENT( AuditData )) { 02616 02617 Token->AuditData = ExAllocatePool( PagedPool, sizeof( SECURITY_TOKEN_AUDIT_DATA )); 02618 02619 if (Token->AuditData == NULL) { 02620 ObDereferenceObject( Token ); 02621 return( STATUS_NO_MEMORY ); 02622 } 02623 02624 *(Token->AuditData) = *AuditData; 02625 02626 } else { 02627 02628 Token->AuditData = NULL; 02629 } 02630 02631 02632 // 02633 // Variable part initialization 02634 // Data is in the following order: 02635 // 02636 // Privileges array 02637 // User (SID_AND_ATTRIBUTES) 02638 // Groups (SID_AND_ATTRIBUTES) 02639 // Restricted Sids (SID_AND_ATTRIBUTES) 02640 // SIDs 02641 // 02642 02643 Where = (PUCHAR) & Token->VariablePart ; 02644 02645 Token->Privileges = (PLUID_AND_ATTRIBUTES) Where ; 02646 Token->PrivilegeCount = PrivilegeCount ; 02647 02648 RtlCopyMemory( 02649 Where, 02650 Privileges, 02651 PrivilegeCount * sizeof(LUID_AND_ATTRIBUTES) ); 02652 02653 ASSERT( ComputedPrivLength >= PrivilegeCount * sizeof( LUID_AND_ATTRIBUTES ) ); 02654 02655 Where += ComputedPrivLength ; 02656 VariableLength -= ComputedPrivLength ; 02657 02658 ASSERT( (((ULONG_PTR) Where ) & (sizeof(PVOID) - 1)) == 0 ); 02659 02660 // 02661 // Now, copy the sid and attributes arrays. 02662 // 02663 02664 NextSidFree = (PSID) (Where + (sizeof( SID_AND_ATTRIBUTES ) * 02665 (GroupCount + 1) ) ); 02666 02667 Token->UserAndGroups = (PSID_AND_ATTRIBUTES) Where ; 02668 Token->UserAndGroupCount = GroupCount + 1 ; 02669 02670 02671 ASSERT(VariableLength >= ((GroupCount + 1) * (ULONG)sizeof(SID_AND_ATTRIBUTES))); 02672 02673 VariableLength -= ((GroupCount + 1) * (ULONG)sizeof(SID_AND_ATTRIBUTES)); 02674 Status = RtlCopySidAndAttributesArray( 02675 1, 02676 User, 02677 VariableLength, 02678 (PSID_AND_ATTRIBUTES)Where, 02679 NextSidFree, 02680 &NextSidFree, 02681 &VariableLength 02682 ); 02683 02684 Where += sizeof( SID_AND_ATTRIBUTES ); 02685 02686 ASSERT( (((ULONG_PTR) Where ) & (sizeof(PVOID) - 1)) == 0 ); 02687 02688 Status = RtlCopySidAndAttributesArray( 02689 GroupCount, 02690 Groups, 02691 VariableLength, 02692 (PSID_AND_ATTRIBUTES)Where, 02693 NextSidFree, 02694 &NextSidFree, 02695 &VariableLength 02696 ); 02697 02698 02699 ASSERT(NT_SUCCESS(Status)); 02700 02701 02702 Token->RestrictedSids = NULL; 02703 Token->RestrictedSidCount = 0; 02704 02705 02706 // 02707 // Dynamic part initialization 02708 // Data is in the following order: 02709 // 02710 // PrimaryGroup (SID) 02711 // Default Discreationary Acl (ACL) 02712 // 02713 02714 Token->DynamicPart = (PULONG)ExAllocatePoolWithTag( PagedPool, DynamicLength, 'dTeS' ); 02715 02716 // 02717 // The attempt to allocate the DynamicPart of the token may have 02718 // failed. Dereference the created object and exit with an error. 02719 // 02720 02721 if (Token->DynamicPart == NULL) { 02722 ObDereferenceObject( Token ); 02723 return( STATUS_NO_MEMORY ); 02724 } 02725 02726 02727 Where = (PUCHAR) Token->DynamicPart; 02728 02729 Token->PrimaryGroup = (PSID) Where; 02730 PrimaryGroupLength = RtlLengthRequiredSid( ((SID *)PrimaryGroup)->SubAuthorityCount ); 02731 RtlCopySid( PrimaryGroupLength, (PSID)Where, PrimaryGroup ); 02732 Where += (ULONG)LongAlignSize(PrimaryGroupLength); 02733 02734 if (ARGUMENT_PRESENT(DefaultDacl)) { 02735 Token->DefaultDacl = (PACL)Where; 02736 02737 RtlCopyMemory( (PVOID)Where, 02738 (PVOID)DefaultDacl, 02739 DefaultDacl->AclSize 02740 ); 02741 } 02742 02743 #ifdef TOKEN_DEBUG 02744 02745 // 02746 // Debug 02747 SepDumpToken( Token ); 02748 // Debug 02749 // 02751 #endif //TOKEN_DEBUG 02752 02753 02754 // 02755 // Insert the token unless it is a system token. 02756 // 02757 02758 if (!SystemToken) { 02759 02760 Status = SeCreateAccessState( 02761 &AccessState, 02762 &AuxData, 02763 DesiredAccess, 02764 &SepTokenObjectType->TypeInfo.GenericMapping 02765 ); 02766 02767 if ( NT_SUCCESS(Status) ) { 02768 BOOLEAN PrivilegeHeld; 02769 02770 PrivilegeHeld = SeSinglePrivilegeCheck( 02771 SeCreateTokenPrivilege, 02772 KeGetPreviousMode() 02773 ); 02774 02775 if (PrivilegeHeld) { 02776 02777 Status = ObInsertObject( Token, 02778 &AccessState, 02779 0, 02780 0, 02781 (PVOID *)NULL, 02782 TokenHandle 02783 ); 02784 02785 } else { 02786 02787 Status = STATUS_PRIVILEGE_NOT_HELD; 02788 ObDereferenceObject( Token ); 02789 } 02790 02791 SeDeleteAccessState( &AccessState ); 02792 02793 } else { 02794 02795 ObDereferenceObject( Token ); 02796 } 02797 } else { 02798 02799 ASSERT( NT_SUCCESS( Status ) ); 02800 ObDeleteCapturedInsertInfo(Token); 02801 // 02802 // Return pointer instead of handle. 02803 // 02804 02805 (*TokenHandle) = (HANDLE)Token; 02806 } 02807 02808 return Status; 02809 02810 } 02811 02812 BOOLEAN 02813 SepIdAssignableAsOwner( 02814 IN PTOKEN Token, 02815 IN ULONG Index 02816 ) 02817 02818 /*++ 02819 02820 02821 Routine Description: 02822 02823 This routine returns a boolean value indicating whether the user 02824 or group ID in the specified token with the specified index is 02825 assignable as the owner of an object. 02826 02827 If the index is 0, which is always the USER ID, then the ID is 02828 assignable as owner. Otherwise, the ID is that of a group, and 02829 it must have the "Owner" attribute set to be assignable. 02830 02831 02832 02833 Arguments: 02834 02835 Token - Pointer to a locked Token to use. 02836 02837 Index - Index into the Token's UserAndGroupsArray. This value 02838 is assumed to be valid. 02839 02840 Return Value: 02841 02842 TRUE - Indicates the index corresponds to an ID that may be assigned 02843 as the owner of objects. 02844 02845 FALSE - Indicates the index does not correspond to an ID that may be 02846 assigned as the owner of objects. 02847 02848 --*/ 02849 { 02850 PAGED_CODE(); 02851 02852 if (Index == 0) { 02853 02854 return TRUE; 02855 02856 } else { 02857 02858 return (BOOLEAN) 02859 ( (SepTokenGroupAttributes(Token,Index) & SE_GROUP_OWNER) 02860 != 0 02861 ); 02862 } 02863 } 02864 02865 02866 NTSTATUS 02867 SeIsChildToken( 02868 IN HANDLE Token, 02869 OUT PBOOLEAN IsChild 02870 ) 02871 /*++ 02872 02873 Routine Description: 02874 02875 This routine returns TRUE if the supplied token is a child of the caller's 02876 process token. This is done by comparing the ParentTokenId field of the 02877 supplied token to the TokenId field of the token from the current subject 02878 context. 02879 02880 Arguments: 02881 02882 Token - Token to check for childhood 02883 02884 IsChild - Contains results of comparison. 02885 02886 TRUE - The supplied token is a child of the caller's token 02887 FALSE- The supplied token is not a child of the caller's token 02888 02889 Returns: 02890 02891 Status codes from any NT services called. 02892 02893 --*/ 02894 { 02895 PTOKEN CallerToken; 02896 PTOKEN SuppliedToken; 02897 LUID CallerTokenId; 02898 LUID SuppliedParentTokenId; 02899 NTSTATUS Status = STATUS_SUCCESS; 02900 02901 *IsChild = FALSE; 02902 02903 // 02904 // Capture the caller's token and get the token id 02905 // 02906 02907 CallerToken = (PTOKEN) PsReferencePrimaryToken(PsGetCurrentProcess()); 02908 02909 02910 SepAcquireTokenReadLock( CallerToken ); 02911 02912 CallerTokenId = CallerToken->TokenId; 02913 02914 SepReleaseTokenReadLock( CallerToken ); 02915 02916 PsDereferencePrimaryToken(CallerToken); 02917 02918 // 02919 // Reference the supplied token and get the parent token id. 02920 // 02921 02922 Status = ObReferenceObjectByHandle( 02923 Token, // Handle 02924 0, // DesiredAccess 02925 SepTokenObjectType, // ObjectType 02926 KeGetPreviousMode(), // AccessMode 02927 (PVOID *)&SuppliedToken, // Object 02928 NULL // GrantedAccess 02929 ); 02930 02931 if (NT_SUCCESS(Status)) 02932 { 02933 SepAcquireTokenReadLock( SuppliedToken ); 02934 02935 SuppliedParentTokenId = SuppliedToken->ParentTokenId; 02936 02937 SepReleaseTokenReadLock( SuppliedToken ); 02938 02939 ObDereferenceObject(SuppliedToken); 02940 02941 // 02942 // Check to see if the supplied token's parent ID is the ID 02943 // of the caller. 02944 // 02945 02946 if (RtlEqualLuid( 02947 &SuppliedParentTokenId, 02948 &CallerTokenId 02949 )) { 02950 02951 *IsChild = TRUE; 02952 } 02953 02954 } 02955 return(Status); 02956 } 02957 02958 02959 NTSTATUS 02960 SeIsChildTokenByPointer( 02961 IN PACCESS_TOKEN Token, 02962 OUT PBOOLEAN IsChild 02963 ) 02964 /*++ 02965 02966 Routine Description: 02967 02968 This routine returns TRUE if the supplied token is a child of the caller's 02969 token. This is done by comparing the ParentTokenId field of the supplied 02970 token to the TokenId field of the token from the current subject context. 02971 02972 Arguments: 02973 02974 Token - Token to check for childhood 02975 02976 IsChild - Contains results of comparison. 02977 02978 TRUE - The supplied token is a child of the caller's token 02979 FALSE- The supplied token is not a child of the caller's token 02980 02981 Returns: 02982 02983 Status codes from any NT services called. 02984 02985 --*/ 02986 { 02987 SECURITY_SUBJECT_CONTEXT SubjectSecurityContext; 02988 PTOKEN CallerToken; 02989 PTOKEN SuppliedToken; 02990 LUID CallerTokenId; 02991 LUID SuppliedParentTokenId; 02992 NTSTATUS Status = STATUS_SUCCESS; 02993 02994 *IsChild = FALSE; 02995 02996 // 02997 // Capture the caller's token and get the token id 02998 // 02999 03000 CallerToken = (PTOKEN) PsReferencePrimaryToken(PsGetCurrentProcess()); 03001 03002 03003 SepAcquireTokenReadLock( CallerToken ); 03004 03005 CallerTokenId = CallerToken->TokenId; 03006 03007 SepReleaseTokenReadLock( CallerToken ); 03008 03009 PsDereferencePrimaryToken(CallerToken); 03010 03011 SuppliedToken = (PTOKEN) Token ; 03012 03013 SepAcquireTokenReadLock( SuppliedToken ); 03014 03015 SuppliedParentTokenId = SuppliedToken->ParentTokenId; 03016 03017 SepReleaseTokenReadLock( SuppliedToken ); 03018 03019 // 03020 // Check to see if the supplied token's parent ID is the ID 03021 // of the caller. 03022 // 03023 03024 if (RtlEqualLuid( 03025 &SuppliedParentTokenId, 03026 &CallerTokenId 03027 )) { 03028 03029 *IsChild = TRUE; 03030 } 03031 03032 03033 03034 return(Status); 03035 } 03036 03037 NTSTATUS 03038 NtImpersonateAnonymousToken( 03039 IN HANDLE ThreadHandle 03040 ) 03041 03042 /*++ 03043 03044 Routine Description: 03045 03046 Impersonates the system's anonymous logon token on this thread. 03047 03048 Arguments: 03049 03050 ThreadHandle - Handle to the thread to do the impersonation. 03051 03052 Return Value: 03053 03054 STATUS_SUCCESS - Indicates the operation was successful. 03055 03056 STATUS_INVALID_HANDLE - the thread handle is invalid. 03057 03058 STATUS_ACCESS_DENIED - The thread handle is not open for impersonation 03059 access. 03060 --*/ 03061 { 03062 PETHREAD CallerThread = NULL; 03063 NTSTATUS Status = STATUS_SUCCESS; 03064 03065 // 03066 // Reference the caller's thread to make sure we can impersonate 03067 // 03068 03069 Status = ObReferenceObjectByHandle( 03070 ThreadHandle, 03071 THREAD_IMPERSONATE, 03072 PsThreadType, 03073 KeGetPreviousMode(), 03074 (PVOID *)&CallerThread, 03075 NULL 03076 ); 03077 if (!NT_SUCCESS(Status)) { 03078 goto Cleanup; 03079 } 03080 03081 // 03082 // Reference the impersonation token to make sure we are allowed to 03083 // impersonate it. 03084 // 03085 03086 Status = ObReferenceObjectByPointer( 03087 SeAnonymousLogonToken, 03088 TOKEN_IMPERSONATE, 03089 SepTokenObjectType, 03090 KeGetPreviousMode() 03091 ); 03092 if (!NT_SUCCESS(Status)) 03093 { 03094 goto Cleanup; 03095 } 03096 03097 ObDereferenceObject(SeAnonymousLogonToken); 03098 03099 // 03100 // Do the impersonation. We want copy on open so the caller can't 03101 // actually modify this system's copy of this token. 03102 // 03103 03104 Status = PsImpersonateClient( 03105 CallerThread, 03106 SeAnonymousLogonToken, 03107 TRUE, // copy on open 03108 FALSE, // no effective only 03109 SecurityImpersonation 03110 ); 03111 Cleanup: 03112 03113 if (CallerThread != NULL) { 03114 ObDereferenceObject(CallerThread); 03115 } 03116 return(Status); 03117 }

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