views:

186

answers:

3

I have an app with a manifest that requires running as administrator, but part of the app is to map a drive using WNetAddConnection2 which I believe requires it to be run in the normal user context due to credentials etc. Is there a way to execute this bit of code in the normal user context without creating a separate process.

EDIT

From the comments I have got this far but it doesnt work. I expected it not to as I dont really understand quite how I should use this. Perhaps it best if I open a new question?

class Program
{
    [DllImport("advapi32.DLL")]
    public static extern bool ImpersonateLoggedOnUser(IntPtr hToken);
    [DllImport("advapi32.DLL")]
    public static extern bool RevertToSelf();

    static void Main(string[] args)
    {
        IntPtr phToken = IntPtr.Zero;
        ImpersonateLoggedOnUser(phToken);
        MapDrives();
        RevertToSelf();
    }
}

EDIT

If the current user has admin privileges then the main process is elevated with the manifest, in the code which is elevated I want to run a command in the users non-elevated space as this appears to have different environment variables etc. I believe once a thread is started it cant change itself, it needs to run a new one.

A: 

First you need to obtain the user token that you want to start the app as, you can do this using WTSQueryUserToken. If the user is not yet logged on you can use LogonUser Win32 API to obtain a new one in a new session. To get all the sessions on your computer you can use WTSEnumerateSessions.

Then once you have the token you can use CreateProcessAsUser or else ImpersonateLoggedOnUser Win32 APIs.

Please make sure to call CloseHandle on the handles you obtain, they are especially bad leaks for this type of work.

Brian R. Bondy
Please don't forget to mention to call the CloseHandle function after finished to use the token returned by LogonUser function. If you don't do this you can have an operating system level handle leak. I've seen this happen before.
Carlos Loth
@Carlos: Ditto they are especially bad leaks too. I added a comment about that.
Brian R. Bondy
Arent both CreateProcessAsUser and ImpersonateLoggedOnUser used to create a new thread with different credentials? How do I get WNetAddConnections2 to run in this new process?
Charles Gargent
@Charles: CreateProcessAsUser creates a new process as the specified user. ImpersonateLoggedOnUser executes the code within the same process and thread. WNetAddConnections2 is for something entirely different, authenticating yourself with a LAN machine or other resource.
Brian R. Bondy
So what I want is my WNetAddConnections2 function to be called using ImpersonateLoggedOnUser ?
Charles Gargent
@Charles: Yes or within a new process you create using CreateProcessAsUser.
Brian R. Bondy
+2  A: 

Hi, take a look on A small C# Class for impersonating a User code project article. It implements an IDisposable class (that releases the authentication token after its use). I've seen .NET code leaking due to not releasing the impersonation tokens.

You can impersonate a user only for a block of code that will access the network resource you need to access as a different user. Your code will look like

using ( new Impersonator( "myUsername", "myDomainname", "myPassword" ) )
{
   /* code that executes under the new context */
   ...
}

I hope it helps.

Carlos Loth
A: 

Im not sure this is a way to do this without creating a new process, ImpersonateLoggedOnUser will only work from a service, and I dont want to provide credentials.

correct me if I am wrong

Charles Gargent
How do you want to impersonate a user without provide the credentials? I mean would you like to provide only the user name? Or what else?
Carlos Loth
If the current user has admin privileges then the main process is elevated with the manifest, in this code which is elevated I want to run a command in the users non-elevated space as this appears to have different environment variables etc. I believe once a thread is started it cant change itself, it needs to run a new one
Charles Gargent