locked
Create process as another user with full token RRS feed

  • Question

  • My application (an installer) needs to do some steps as another user. LogonUser /CreateProcessAsUser as described here http://msdn2.microsoft.com/en-us/library/aa379608.aspx and it basically works , except that token returned from LogonUser is filtered, and I like to have full token.

     Also , I  found that passing LOGON32_BATCH_LOGON to LogonUser (instead of LOGON32_INTERACTIVE_LOGON) would give me the full token. 

    The question is - what to do if user does only has the right to logon interactively? I did some experiments with GetTokenInformation to get the linked token as passed linked token to CreateProcessAsUser(), without much success - got ERROR_BAD_TOKEN_TYPE.  I can get around by temporarily allowing batch logon for my user , but isn't there a more direct and more elegant way to accomplish the task?

     

    Thursday, February 22, 2007 7:14 PM

All replies

  •  wva wrote:

    The question is - what to do if user does only has the right to logon interactively? I did some experiments with GetTokenInformation to get the linked token as passed linked token to CreateProcessAsUser(), without much success - got ERROR_BAD_TOKEN_TYPE.  I can get around by temporarily allowing batch logon for my user , but isn't there a more direct and more elegant way to accomplish the task?

     

    From my experimenting, the token returned by GetTokenInformation() for TokenLinkedToken is not a primary token.  If I use DuplicateTokenEx() to create a primary token using that linked token, I can successfully use that primary token in a call to CreateProcessAsUser().

    Thursday, February 22, 2007 9:09 PM
  • I tried DuplicateTokenEx as suggested, but it did not work either - got error 1346 ( ERROR_BAD_IMPERSONATION_LEVEL, Either a required impersonation level was not provided, or the provided impersonation level is invalid).  The relevant code fragment is here

    if (!LogonUser(lpszUsername,lpszDomain, lpszPassword, dwLogonType, dwLogonProvider, &hToken))

    goto Cleanup;

    // get handle to linked token (will have one if we are lua)

    if( !GetTokenInformation(hToken,TokenLinkedToken,(VOID*) &hLinkedToken,sizeof(HANDLE),&dwLength))

    goto Cleanup;

     

    if(hLinkedToken)

    {

    if(!DuplicateTokenEx(hLinkedToken, MAXIMUM_ALLOWED, NULL, SecurityIdentification , TokenPrimary, &newToken)) 

    goto Cleanup;

    }

     

    Friday, February 23, 2007 11:26 AM
  • Without TCB, TokenLinkedToken returns an identify level token.

    Thursday, March 1, 2007 10:12 PM
  • What you mean by TCB?  How can manage to get it?  Do we need it even in Vista? (I think I don't need it since Windows 2003.)

    I copied ntrights.exe & showpriv.exe from WINDOWS XP RESOURCE KITS to Vista. Although I succeeded to run "ntrights +r SeTcbPrivilege -u <USERNAME>" to grant the SeTcbPrivilege right (I can confirm the granting succeeded by running  "showpriv.exe SeTcbPrivilege"), I got the same error (1346) when calling DuplicateTokenEx. BTW what I have tried was an application which ran in the local administrators group.

    P.S.

    I confused "granting a privilege" and "enabling a privilege".

    But even after I enabled the SeTcbPrivilege privilege using AdjustTokenPrivileges (I can confirm the enabled privilege using Sysinternals' Process Explorer), I got the same error (1346) when calling DuplicateTokenEx.  Why?

    Monday, March 19, 2007 4:28 AM
  • Any news ?

    I'm exactly in the same situation and I'm quite desperate to see that this solution I was starting to test is not working.

    Did you find a solution ?
    Friday, July 6, 2007 11:32 AM
  •  

    On Vista , I try LogonUser with non-interactive logons first ( i.e LOGON32_LOGON_BATCH or LOGON32_LOGON_SERVICE). If this types of logon are granted, I can use the returned token , as it is not restricted. Otherwise, if only LOGON32_LOGON_INTERACTIVE is granted, I'm trying to Enable TCB Privilege and retrieve the linked token with GetTokenInformation.

     

    It works mostly for me (Administrators have "logon as batch" by default) and I cannot think of any better solution for now.

     

     

    Well, here s the function I'm using get user's primary token I later pass to CreateProcessAsUser(). If bRestrictedToken is TRUE after the call, we had no luck (user only has interactive logon right and we could not enable the TCB privilege)  

    Code Snippet

    Code Snippet

    static BOOL GetPrimaryToken(LPTSTR lpszUsername,

    LPTSTR lpszDomain,

    LPTSTR lpszPassword,

    PHANDLE phToken,

    BOOL *bRestrictedToken)

    {

    HANDLE hToken = NULL;

    HANDLE hLinkedToken = NULL;

    DWORD dwLength;

    *bRestrictedToken = FALSE;

    BOOL bIsWindowsVistaOrLater;

    OSVERSIONINFO osvi;

    osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);

    GetVersionEx (&osvi);

    bIsWindowsVistaOrLater = (osvi.dwMajorVersion >= 6);

     

     

    if(!bIsWindowsVistaOrLater)

    {

    return

    LogonUser(lpszUsername,lpszDomain, lpszPassword, LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, phToken);

    }

    else

    {

    /*

    * Assume activated User Account Control.

    * To retrieve user primary token, it is better to avoid LOGON32_LOGON_INTERACTIVE logon type,

    * for LogonUser, otherwise we'll get the filtered token with missing privileges.

    *

    * Thus I'll try first to logon as batch or service.

    * If it works, I've got user token with his highest privileges,

    * done.

    *

    * Otherwise,

    * - logon with interactive logon type and get possibly filtered token.

    * - Try to enable TCB privilege.

    * - Retrieve linked token via GetTokenInformation().

    * If an error or linked token is NULL, then either UAC is not active or we

    * got a standard user, return logon token, done.

    * If linked token is not NULL and TCB privilege was enabled,

    * return linked token (it is primary due to TCB held).

    *

    * If linked token is not NULL and TCB was NOT enabled,

    * returned token is restricted (filtered). This should not happen often

    * , because there is a fair number of conditions that must hold true,

    * 1) User is an Admin

    * 2) User has no batch neither service logon privileges

    * 3) Caller has no TCB privilege

    * 4) UAC is enabled.

    */

    int i;

    HANDLE hMyToken;

    HANDLE hLinkedToken;

    DWORD logonType;

    BOOL bSuccess;

    DWORD dwLastError;

    BOOL bGotTcbPriv;

    TOKEN_PRIVILEGES TcbPrevState;

    DWORD allLogonTypes [] = {

    LOGON32_LOGON_BATCH,

    LOGON32_LOGON_SERVICE,

    LOGON32_LOGON_INTERACTIVE /*intentionally put last, as most restrictive logon*/

    };

    /* Try all logon types */

    for( i=0; i< sizeof(allLogonTypes)/sizeof(allLogonTypes[0]);i++)

    {

    logonType = allLogonTypes[i];

    bSuccess = LogonUser(lpszUsername,lpszDomain, lpszPassword, logonType,

    LOGON32_PROVIDER_DEFAULT, phToken);

    if(bSuccess)

    break;

    dwLastError = GetLastError();

    if(dwLastError != ERROR_LOGON_TYPE_NOT_GRANTED &&

    dwLastError != ERROR_LOGON_NOT_GRANTED)

    {

    return FALSE;

    }

    }

    if(!bSuccess)

    {

    /*User could not logon with any logon type?*/

    return FALSE;

    }

    if(logonType != LOGON32_LOGON_INTERACTIVE)

    {

    /*Non-interactive logon , no UAC, no token restrictions*/

    return TRUE;

    }

     

    /* Try to get the highest privileged token*/

    if (! OpenProcessToken(GetCurrentProcess(),TOKEN_ALL_ACCESS,&hMyToken))

    {

    return FALSE;

    }

    /* Enable TCB temporarily to get primary "linked" token .

    * Without TCB GetTokenInformation() would return

    * Identity token , unusable for CreateProcessAsUser()

    */

    bGotTcbPriv = EnablePrivilege(hMyToken, SE_TCB_NAME,TRUE,&TcbPrevState) ;

    bSuccess = GetTokenInformation(*phToken,

    TokenLinkedToken,

    (VOID*) &hLinkedToken,

    sizeof(HANDLE),

    &dwLength);

    if(bGotTcbPriv)

    {

    /*Reset TCB privilege, if was set previously*/

    AdjustTokenPrivileges(hMyToken,FALSE,&TcbPrevState,sizeof(TcbPrevState),NULL,NULL);

    }

    CloseHandle(hMyToken);

     

    if(!bSuccess)

    {

    if((dwLastError = GetLastError())==ERROR_NO_SUCH_LOGON_SESSION)

    {

    /* Can happend if we have standard user/UAC switched off*/

    SetLastError(ERROR_SUCCESS);

    hLinkedToken = NULL;

    }

    else

    {

    return FALSE;

    }

    }

    if(!hLinkedToken)

    {

    /* No UAC or standard user */

    return TRUE;

    }

    if(!bGotTcbPriv)

    {

    /*Could not enable TCB , *phToken is restricted */

    *bRestrictedToken = TRUE;

    return TRUE;

    }

    CloseHandle(*phToken);

    /* primary linked token*/

    *phToken = hLinkedToken;

    return TRUE;

    }

    }

     

    Friday, July 6, 2007 1:49 PM