Microsoft KB Archive/264316

= Changes in RPC Cause Impersonation to Behave Differently =

Article ID: 264316

Article Last Modified on 2/21/2007

-

APPLIES TO


 * Microsoft Windows 2000 Server
 * Microsoft Windows 2000 Advanced Server
 * Microsoft Windows 2000 Professional Edition
 * Microsoft Windows 2000 Datacenter Server

-



This article was previously published under Q264316



SUMMARY
Changes in Remote Procedure Call (RPC) between Microsoft Windows NT 4.0 and Windows 2000 have changed the way that impersonation works in Windows 2000. This may cause problems with any program that uses impersonation and RPC calls. This includes RPC calls that are called either directly or indirectly through operating system library calls. Windows 2000 performs extra security checks when it implements RPC calls that cause impersonation credentials to be checked.

If you have created a program that uses a User Logon token created in another thread's context running under a different user's logon, you may not be able to make calls that require RPC. In Windows 2000, these RPC calls verify that the impersonated token has the appropriate rights to make the RPC call.



MORE INFORMATION
To have the same functionality as in Windows NT 4.0, you must add security Access Control Lists (ACLs) to the Created User token. Typically, you create the token by using LogonUser and then duplicating the token and returning it to the caller. Adding these ACLs does not make your program vulnerable because you cannot add these permissions if you do not have the rights to do so in the first place. To add the appropriate ACLs to the token, use the following sample code as a guide: // First obtain the Logon token.

if(!LogonUser(argv[2], argv[1], argv[3], LOGON32_LOGON_NETWORK, LOGON32_PROVIDER_DEFAULT, &hToken)) DisplayLastError(&quot;LogonUser&quot;); // Get the SIDs for the Local System and Domain Admins AllocateAndInitializeSid(               &Auth, 1,            SECURITY_LOCAL_SYSTEM_RID,            0, 0, 0, 0, 0, 0, 0,            &LocalSystemSid ); AllocateAndInitializeSid(           &Auth, 2,            SECURITY_BUILTIN_DOMAIN_RID,            DOMAIN_ALIAS_RID_ADMINS,            0, 0, 0, 0, 0, 0,            &AliasAdminsSid ); // Validate that the TokenUser and TokenOwner exist and are valid if ( OpenProcessToken( hClientProc, TOKEN_QUERY, &ProcessToken ) ) {       ProcessUser = (PTOKEN_USER) UserBuffer ; Status = GetTokenInformation( ProcessToken,               TokenUser,                ProcessUser,                sizeof( UserBuffer ),                &Size ); if ( NO_ERROR == Status) {       ProcessUser = NULL ; }   ProcessOwner = (PTOKEN_OWNER) OwnerBuffer ; Status = GetTokenInformation( ProcessToken,               TokenOwner,                ProcessOwner,                sizeof( OwnerBuffer ),                &Size ); if ( NO_ERROR ==  Status ) {       ProcessOwner = NULL ; }   if ( ProcessOwner && ProcessUser ) {       if ( EqualSid( ProcessOwner->Owner, ProcessUser->User.Sid ) ) {               ProcessOwner = NULL ; }   }    CloseHandle( ProcessToken ); } else { printf(&quot;Open token failed with %d\n&quot;, GetLastError); exit(0); }   //     // If this is a local system create, // the default object DACL is acceptable. Skip // all this. Otherwise, create the ACL //    // If ProcessUser is null, assume that this is    // not SYSTEM (because the SYSTEM caller should work) //    if ( (ProcessUser == NULL) ||                      !EqualSid( ProcessUser->User.Sid, LocalSystemSid ) ) {       // Calculate the ACL length based on which tokens will be         // added

AclLength = sizeof( ACL ) + sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( LocalSystemSid ) - sizeof( ULONG ) + sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( AliasAdminsSid ) - sizeof( ULONG ) ; if ( ProcessOwner ) {           AclLength += sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( ProcessOwner->Owner ) - sizeof( ULONG ) ; }       if ( ProcessUser ) {           AclLength += sizeof( ACCESS_ALLOWED_ACE ) + GetLengthSid( ProcessUser->User.Sid ) - sizeof( ULONG ); }

Acl = malloc( AclLength );

// Now add the various ACEs to the ACL if ( Acl ) {           InitializeAcl( Acl, AclLength, ACL_REVISION2 ); AddAccessAllowedAce( Acl,           ACL_REVISION2,            TOKEN_ALL_ACCESS,            LocalSystemSid ); AddAccessAllowedAce( Acl,           ACL_REVISION2,

TOKEN_READ, AliasAdminsSid );           if ( ProcessOwner )        {        AddAccessAllowedAce( Acl, ACL_REVISION2, TOKEN_ALL_ACCESS, ProcessOwner->Owner );           }            if ( ProcessUser )        {        AddAccessAllowedAce( Acl, ACL_REVISION2, TOKEN_ALL_ACCESS, ProcessUser->User.Sid );           }    }       }

// Create the Security attribute for the call to DuplicateHandle SecAttr.nLength = sizeof(SECURITY_ATTRIBUTES); SecAttr.bInheritHandle = TRUE; SecAttr.lpSecurityDescriptor = &SecDesc; //    // Duplicate the handle for impersonation //    if(!DuplicateHandle( GetCurrentProcess, hToken, (HANDLE)hClientProc, &hDestToken, 0, // access desired - ignored TRUE, // allow inheritance DUPLICATE_SAME_ACCESS ))   DisplayLastError(&quot;DuplicateHandle&quot;); You can then pass hDestToken back to the caller.

Keywords: kbinfo kbprogramming kbrpc KB264316

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.