Execute code in another users context - c#

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.

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.

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.

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

Related

How to force Windows to create the running user's profile directory

I am having an issue with a process being run, where the profile directory of the process' user has not yet been created.
To explain, here are the details of how this is happening:
We run a large distributed server grid, and are using (parts of) DataSynapse to execute processes on this grid. For those familiar with DataSynapse, the Engine is configured to run the particular service with "RunAs", where we use a certain AD domain service account for the service processes. I believe the problem is that DataSynapse, when running the process under "runas", does not set the LoadUserProfile flag (nor should it). Whatever the precise reason, if the "runas" service account (and AD domain account) has never logged on to some of the grid machines, then those machines will not have the user profile directory for the account.
For those not familiar with DataSynapse, here is a more generic explanation. On each machine on the grid, there is a process running, I'll call it dsService, and it runs under the credentials of the local machine's system account (or some similar account with elevated credentials). The process dsService will spawn a child process, say childProcess, but it runs childProcess under the credentials of our AD domain account, which I'll call serviceUser. There are thousands of machines on the grid, and typically they are never logged on to manually. In particular, the profile directory C:\users\serviceUser may not initially exist. Once it is created once, there are not further issues. But if new nodes are added to the grid, typically they will not have the C:\users\serviceUser initially. The problem is that when the dsService spawns childProcess, C:\users\serviceUser does not get created, and we need it.
I believe that this is because dsService does not set the LoadUserProfile flag to true when spawning childProcess, though I am not certain.
In any event, childProcess is a (.net) process (running as serviceUser) under our control, and I would like to know if there is a way (in C#) that childProcess can force the OS to create the running user's profile directory C:\users\serviceUser when it determines that it does not yet exist?
Edit:
Experimentation has confirmed that if one starts a process under another user ID, and the user's profile directory is not there (more specifically, if the user's local profile has not been created yet - merely deleting a pre-existing profile directory creates a different situation, one we're not interested in anyway), then (1) the profile directory (and one presumes, the local profile) gets created if the process is started with the LoadUserProfile set to true; and (2) the profile directory (and one presumes, the local profile) does NOT get created if the process is started with the LoadUserProfile set to false. This makes sense, and is as one would expect.
Related post: stackoverflow.com/q/9008742/1082063
If the running account has admin privileges, the following code will cause the creation of the running account's profile, including its UserProfile directory. Without admin, I don't know if it is possible:
using System.Runtime.InteropServices;
...
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int CreateProfile(
[In] string pszUserSid,
[In] string pszUserName,
System.Text.StringBuilder pszProfilePath,
int cchProfilePath);
....
public static string getUserProfilePath()
{
string userProfilePath = Environment.GetFolderPath(Environment.SpecialFolder.UserProfile);
if(string.IsNullOrWhiteSpace(userProfilePath) || !Directory.Exists(userProfilePath))
{ //This will only work if we have admin...
var pathBuf = new System.Text.StringBuilder(240);
var Up = System.DirectoryServices.AccountManagement.UserPrincipal.Current;
if( 0 == CreateProfile(Up.Sid.ToString(), Up.SamAccountName, pathBuf, pathBuf.Capacity) }
{
userProfilePath = pathBuf.ToString();
}
}
return userProfilePath;
}
If anyone can tell me how to do this when the account is not admin, they will get their answer accepted as the correct answer. Until then, this at least gives others some idea.

Reboot machine from C#/Forms App while session is locked

Referring to this question: .net - Reboot machine from a C#/WPF App
I am attempting to create a c#/.net app that can restart the machine even if the session is locked (i.e., user is logged in, this app is running, but session is locked).
I tried this from the question: System.Diagnostics.Process.Start("shutdown.exe", "-r -t 0");
but apparently that only works if the session is unlocked. Additionally, after reading this: MSDN - InitiateSystemShutdown Function it seems the InitiateSystemShutdown function will display the System Shutdown dialog box, which doesn't seem like it will suite my purposes.
Are there any other methods of doing this?
The ExitWindowsEx function accomplished what I was trying to do.
Using:
[DllImport("user32.dll", SetLastError = true)]
public static extern int ExitWindowsEx(ExitWindows uFlags, ShutdownReason dwReason);
after adjusting token privileges, and using uFlags 0x06 (reboot / force). I used dwReason 0 as well. This function will restart the machine whether or not the session is locked.
here

Windows security and identifying privilages in .Net

I have a windows forms application that will be run in both domain and on non-domain (local desktop) environments. I'm trying to understand how the windows security works in these different environments. I need to programmatically identify when the windows user running my application as an Administrator which I'm assuming is different for domain and local environments (and possibly when the UAC is in control?? ).
I'm also a little confused as to whether the UAC supersedes a domain log in if turned on?
I expect most remote users of the product will be set as local Administrators too, and restricted by the UAC.
How do you check for privileges under these conditions? (vb.net app but c# is also fine - thank you)
Cheers, Tim.
Public Function isWindowsAdministrator() As Boolean
My.User.InitializeWithWindowsUser()
If My.User.IsAuthenticated Then
If My.User.IsInRole(Microsoft.VisualBasic.ApplicationServices.BuiltInRole.Administrator) Then
Return True
End If
End If
Return False
End Function
There is probably a nonVB/'pure' NET alternative, I just dont know the equivalents. There is also a way to test if the user can elevate to Admin, but it is a PInvoke, messy win32 thing, and doesnt actually elevate, just tests.
UAC will still pop up, the above just lets you know in advance if the user can authorize.
Vb.Net:
Public Function IsUserAnAdmin() As Boolean
End Function
C#:
[DllImport("shell32.dll")]
public static extern bool IsUserAnAdmin();
As you can see returns a Boolean by calling IsUserAnAdmin (you could obviously use an alias). for clarity I believe this works in all scenarios I mentioned but I haven't fully completed my Domain testing.... yet

create interactive elevated process from windows service and show to logged-on user

I have a service that spawns a WPF application process when a user logs on.
But for some reason the WPF application gets killed about 10 minutes after it has been created? The termination is immediate with no traces found in the Event Log nor are any normal close/exit events called in the WPF application.
In fact, when the termination occurs, Windows 7 seems to hang for a second, the mouse becoming unresponsive and then acting out the mouse gestures after a short delay (when it normalizes, but now lacking the created process).
The When
public partial class Service1 : ServiceBase
{
public Service1()
{
InitializeComponent();
CanHandleSessionChangeEvent = true;
}
protected override void OnSessionChange(SessionChangeDescription changeDescription)
{
if (changeDescription.Reason == SessionChangeReason.SessionLogon
&& changeDescription.SessionId > 0)
{
ApplicationLoader.PROCESS_INFORMATION procInfo;
ApplicationLoader.StartProcessAndBypassUAC(#"myapp.exe", out procInfo);
}
base.OnSessionChange(changeDescription);
}
}
Process Creation As Per Pero Matic Code
// ...
bool result = CreateProcessAsUser(hUserTokenDup, // client's access token
null, // file to execute
applicationName, // command line
ref sa, // pointer to process SECURITY_ATTRIBUTES
ref sa, // pointer to thread SECURITY_ATTRIBUTES
false, // handles are not inheritable
dwCreationFlags, // creation flags
IntPtr.Zero, // pointer to new environment block
null, // name of current directory
ref si, // pointer to STARTUPINFO structure
out procInfo // receives information about new process
);
the termination does not seem to happen if i target notepad.exe, however?
tested it with a vanilla\empty WPF application (.NET 4), and that crashed as well
Process Creation with Administrative Privileges and No Prompt
It seems that the issue is trying to duplicate the administrative SYSTEM token from winlogon.exe (but which is running in session 1+), because if you duplicate the specific user token instead (e.g. from explorer.exe) then the crashes are no more!
this is confirmed with the same vanilla/empty WPF application, and with running Marcel Roma code here - note that he uses explorer.exe instead of winlogon.exe
although using explorer.exe gets rid of the termination I lose the administrative privileges with that, which does not work for me
any ideas how to get it to work with the winlogon process token?
or is it possible to adjust the exlorer.exe token to make the duplicate elevated? im guessing somehow using TokenElevation and SetTokenInformation or AdjustTokenPrivileges
or could it be that Windows 7 has been patched to disallow such process impersonation?
alternatively, is there any way to get the specific user token with administrative privileges (rather than the owner being SYSTEM), but again, without password knowledge/prompts (excluding CreateProcessWithLogonW)
is this maybe to do with garbage collection somehow?
Well I'm just suggesting you a work around:
Why you don't put your core functionalities in a windows service, and then use the wpf app as a frontend ? So that if the user kill it, it doesn't stop the service. Then the service can regularly check that the wpf front end is started, and if needed restart it.
I think it'll be a more "trusted" design that the one you're trying to do, which could let the antivirus think you're a bad software and block you.
And to protect the windows service there is another question here: Protecting a Windows Service from untrusted users
I don't think you can (and definitly should not be able) to do this. Your best bet is to create an application that doesn't need elevated privileges and then use IPC to talk back to your service which then performs administrative tasks on the users behalf.

Run as SYSTEM and logoff user "USER" Pin

I have a program that runs as a scheduled task. The program runs on XP as SYSTEM.
The idea is that the program will run in the background, while USER is active.
I need the program to logoff USER when specific conditions occur.
I tried using:
[DllImport("user32.dll")]
public static extern int ExitWindowsEx(int uFlags, int dwReason);
but that appears to not log USER off.
I think maybe it's logging SYSTEM off, as it is running as SYSTEM.
How can i logogg USER?
Thanks,
SummerBulb.
I think that you will need to run some code as that user. Create an app that runs when a user logs in and then monitors an event. Have your service set the event and then the code will call the ExitWindowsEx method. You will still need to use the forceifhung and logoff params as James mentioned.
It would help if you showed the flags for ExitWindowsEx, but you may need to impersonate the user, though I think this is unlikely. If I remember logging off the current user was enough, but you may have to force the logoff, as it can be cancelled otherwise, if the user hasn't saved some changes for example.
But to impersonate a user you can look at this:
http://www.codeproject.com/KB/system/UserImpersonation.aspx
I would start with looking here, and include both the logoff and forceifhung values:
http://msdn.microsoft.com/en-us/library/aa376868(VS.85).aspx
It would be similar to EWX_FORCEIFHUNG | EWX_LOGOFF as the parameter.
UPDATE:
I expect Mike is correct that impersonation won't help here.

Categories

Resources