How do I change system time from a non elevated c# program - c#

I need your help again :)
What I want to do:
I have a c# program which runs with normal user permissions - those can't be raised - and I want to change the system date (not time) from that program.
[EDIT] To be a bit more specific: I do have administrator credentials which could be embedded to the program (yikes, I know), but I want to avoid an UAC prompt.
When I launch cmd from outside Visual Studio and try to change the date, it fails with "missing client permission" (roughly translated from German). When I launch cmd as administrator, confirm the UAC prompt the same command succeeds.
I am writing from home, so I cant provide running code at the moment. But all my tries did compile and run without error but the date wasn't changed.
What I've tried:
Created a Process instance, applied admin credentials to ProcessStartInfo, set the FileName to c:\windows\system32\cmd.exe and the argument to /C date {thedate}. I redirected StandardOutput and StandardError and after execution StandardError contains the same message as stated above: "missing client permission"
I've modified this example MSDN: WindowsIdentity.Impersonate using PInvoke with AdvAPI32.LogonUser to raise permissions and Kernel32.SetSystemTime to change the system time. AdvAPI32.LogonUser succeeds and WindowsIdentity.GetCurrent().Name returns the admin name, but calling Kernel32.SetSystemTime fails with "missing client permission".
I've tried opening the current process AdvApi32.OpenCurrentProcess and adjusting the permissions using AdvApi32.AdjustTokenPrivileges following this example StackOverflow: Change system time programmaticaly using datetimepeaker and the code runs totally fine but Kernel32.SetSystemTime fails...
[EDIT] Solution:
I ended up writing a small program with an embedded app.manifest that requests administrator privilegs. This app is called from the main program so this can still be run by a normal user.

It is not possible to change the privileges of the process, once it's started. The original process has to start another process with elevated privileges. This second process can actually be the same .exe file, but with a command parameter that tells the process to do some small stuff and exit immediately.
To start a process with elevated privileges use Process.Start, but with .Verb = "runas", as described in another question. This will of course cause UAC prompt to pop up, if it's enabled on the machine. At least one UAC prompt has to be shown, because UAC prompt is the whole point if this defense mechanism.
If you want to reduce many UAC prompts to just one then you can set the original app to be started as administrator (UAC prompt shows when original process starts) and have just one process. Or have some interprocess communication between original process and elevated process, so that elevated process is started only once and made to finish when original process ends. In the second case UAC prompt shows the first time it's needed.

Can I ask why you are needing to change the system time from an unprivileged application?
If it is to influence other applications then you will need admin privilege since date time is such a vital system function to many other applications. However if you are just needing to adjust the date in your application only then I would suggest creating your own date/time provider that can return the date offset to the date that you desire in your application.
For example.
public DateTime GetDateWithOffset(int daysToOffset)
{
return DateTime.UtcNow.AddDays(daysToOffset);
}

Related

install as administrator but run as current user

my installer run as administrator, but on complete i want the exe to run as current user.
i am using nsis and already tried UAC
!insertmacro UAC_AsUser_ExecShell "" "some.exe" "" "" ""
but still it run as administrator.
tried to use task scheduler
string path = System.Reflection.Assembly.GetExecutingAssembly().Location;
td.Actions.Add(new ExecAction("" + path + "", "", null));
td.Settings.DisallowStartIfOnBatteries = false;
td.Settings.AllowHardTerminate = false;
td.Settings.StopIfGoingOnBatteries = false;
td.Settings.ExecutionTimeLimit = System.TimeSpan.Zero;
td.Settings.IdleSettings.StopOnIdleEnd = false;
// Register the task in the root folder
ts.RootFolder.RegisterTaskDefinition("task", td);
but the task also goto administrator and i cant get it to current user.
any ideas ?
My personal recommendation is that you just remove the option to run your application at the end of your installer. The user can just start it from the start menu, it should be highlighted as new and everything.
As you probably know, UAC really changed how common it is for applications to run as a different user than the "logged in" user. You just have to deal with the fact that UAC exists and decide if you feel it is worth the amount of time required to work around it and possible bugs and issues that might arise.
There are at least 4 ways to run something as the "current user", all of them have issues and can fail or end up running as the "wrong" non-admin user:
Use the token of the (hopefully) non-elevated parent, this is what the NSIS UAC plugin does.
Use the Windows Task Scheduler. This was a recommended practice in the early Vista days but I believe Microsoft has moved away from this method.
Use a shell COM object in the Explorer process that hosts the taskbar to call ShellExecute for you. The StdUtils plugin provides a ExecShellAsUser method that does this.
Use a Windows NT service. Because it runs as SYSTEM it can get the token handle of a user in any session.
If you decide that you still want to attempt to do this then you need to decide on your definition of current user before you choose a method.
Is it the user that logged in on the welcome screen? Is it the user the Explorer shell (Taskbar etc) is running as? Is it the parent process of your setup process? You should also keep in mind that runas.exe exists and a user might try to run something as a particular user for a reason...

How to run a non-admin process from admin c# application

I have a c# application that needs to do some things as an admin (some installation stuff) and then it needs to run another process as a non-admin. I haven't done anything with UAC before, but I assume there must be a way to do this, right?
This also needs to be automated, so assume that the c# app is started with admin credentials.
Basically the program will need to do something like this:
// MUST run this process as admin
Process adminInstall = new Process();
adminInstall.StartInfo.FileName = "install.bat";
adminInstall.Start();
adminInstall.WaitForExit();
// CANNOT run this process as admin
Process nonAdminProcess = new Process();
nonAdminProcess.StartInfo.FileName = "runner.cmd";
nonAdminProcess.StartInfo.UseShellExecute = false;
nonAdminProcess.StartInfo.RedirectStandardOutput = true;
nonAdminProcess.OutputDataReceived += new DataReceivedEventHandler(myHandler);
nonAdminProcess.Start();
nonAdminProcess.BeginOutputReadLine();
nonAdminProcess.WaitForExit();
You can embed a manifest in the executable using MT.exe (manifest tool) in the platform SDK after the binary is compiled, but before it is signed. You also have the option of using a custom manifest within your project properties. Open the project properties, then go to the application tab, then change the manifest option from default manifest, to custom manifest. Visual Studio will add a manifest to your project where you can specify "requireAdministrator" privleges. When your app runs, it will provide a UAC prompt, or ask for credentials if logged on as user. There is a good chance sub process will start as admin as well. Otherwise you will need to launch them with the "runas" verb which is undocumented.
Process.Start parameters has one for Username. See Process.Start reference:
http://msdn.microsoft.com/en-us/library/sxf2saat.aspx
There does not appear to be a nice way of doing this using the .Net classes. However, Process.Start with different credentials with UAC on explains a way of doing it using CreateProcessAsUserW after stealing a handle from another process.
If the aforementioned methods aren't viable, then you can try my method. But its ugly; you need to get a handle to a non admin process, then use DuplicateTokenEx (p/invoke) to copy its (non admin) privileges, then pass that into CreateProcessAsUser. You first need to identify a non admin process though, there may not be any. The newly created process will be spawned with whatever privileges the token you copied contained, not the token of the parent process.

Interactively log on another Windows user from c# code

I am trying to achive a situation:
I am logged as a user on my account.
I've created a two more accounts which I will try to log on in the
"background"
And now I want to execute my code to log on different user in the background,
so that if i can click ctrl+alt+del and go to the switch user screen
i can see that another account was logged on the system.
During investigation I've read that this was possbile with some undocumented winapi methods before Microsoft implemented Fast User Switch(FUS) which replaced GINA.
I don't want to Impersonate code as user. I want to start up the whole windows session for a user from code.
I've tried to do sth with CreateProcessWithLogonW() but this was unsuccessful.
Big virtual beer for anybody who can give me a hand with this! :)
Okay had to do a bit of digging to figure this out my self.
Essentially you would need to run a command in command prompt.
This should load explorer.exe as a second user.
runas /user:*computer name\*account name explorer.exe
Follow this to get an idea on running a command line command via c#:
How To: Execute command line in C#, get STD OUT results
Other sources:
http://www.computerhope.com/runas.htm
http://lifehacker.com/290435/switch-user-accounts-from-the-command-prompt

Restart program unelevated

For some reason, my C# program needs to restart with elevated privileges. I use the following code to achieve it:
private static void RestartForPermissionsFix()
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.Verb = "runas";
processInfo.FileName = Assembly.GetExecutingAssembly().Location;
Process.Start(processInfo);
}
This works great.
After I "fix my privileges", I want to restart the program unelevated. I tried the same as above without the "runas", but it does not work. I assume the process being started from an elevated process automatically gets elevated. Any idea?
In order to launch a process at medium integrity from a high integrity process, I believe you would have to get the current process token using OpenProcessToken, duplicate it, remove the high integrity SID from the token using SetTokenInformation, and then use that token to create the new process using CreateProcessAsUser. This would be similar to this example, except rather than add the low integrity SID you'd have to remove the high integrity one. Note: I haven't tested this, so I'm not 100% sure it would work.
I suggest you leave the original unelevated process running, and have it wait for its elevated counterpart to finish (e.g. using Process.WaitForExit). Once that finishes, it can continue unelevated as before. This would be a lot easier and more foolproof.
I had the same problem with an application that I wanted to update automatically (The update program requires elevated privileges).
What I did was creating an external .exe that would start my updater program with elevated privileges, wait for it to exit, then restart my application with normal privileges.
I then embedded this .exe in my main application, and start this .exe just before leaving my application when I update it.

plink process doesn't end if calling user isn't logged in

I'm calling plink from C# code which is running as a certain Windows user. I call plink like
plink.exe user#hostname -pw password commands
Usually the plink process ends immediately after the commands have been run, but when the user which the code runs under is not logged into Windows, the plink process doesn't end.
As all these zombie processes build up there comes a point when new processes can't be created anymore...
Any idea why this would be happening?
This could be because the first time you connect to a new server PuTTY registers a host key in the registry, under the currently logged in user (under HKEY_CURRENT_USER). With that user not being logged in, that portion of the registry may be inaccessible.
Try moving the key to HKEY_LOCAL_SYSTEM. That process is described in detail here:
http://xxlinxx.wordpress.com/2009/03/23/set-up-an-ssh-tunnel-as-a-windows-service-using-putty-plink/
There is a final note on that page that could prove to be important too depending on your specific use case:
"Also, if the Windows SYSTEM user cannot see the host key for SSH connection, the tunnel cannot be established."
PS: There is another page here here that talks about moving the cert to HKEY_USERS.DEFAULT

Categories

Resources