I'm trying to install a service using InstallUtil.exe but invoked through Process.Start. Here's the code:
ProcessStartInfo startInfo = new ProcessStartInfo (m_strInstallUtil, strExePath);
System.Diagnostics.Process.Start (startInfo);
where m_strInstallUtil is the fully qualified path and exe to "InstallUtil.exe" and strExePath is the fully qualified path/name to my service.
Running the command line syntax from an elevated command prompt works; running from my app (using the above code) does not. I assume I'm dealing with some process elevation issue, so how would I run my process in an elevated state? Do I need to look at ShellExecute for this?
This is all on Windows Vista. I am running the process in the VS2008 debugger elevated to admin privilege.
I also tried setting startInfo.Verb = "runas"; but it didn't seem to solve the problem.
You can indicate the new process should be started with elevated permissions by setting the Verb property of your startInfo object to 'runas', as follows:
startInfo.Verb = "runas";
This will cause Windows to behave as if the process has been started from Explorer with the "Run as Administrator" menu command.
This does mean the UAC prompt will come up and will need to be acknowledged by the user: if this is undesirable (for example because it would happen in the middle of a lengthy process), you'll need to run your entire host process with elevated permissions by Create and Embed an Application Manifest (UAC) to require the 'highestAvailable' execution level: this will cause the UAC prompt to appear as soon as your app is started, and cause all child processes to run with elevated permissions without additional prompting.
Edit: I see you just edited your question to state that "runas" didn't work for you. That's really strange, as it should (and does for me in several production apps). Requiring the parent process to run with elevated rights by embedding the manifest should definitely work, though.
This code puts the above all together and restarts the current wpf app with admin privs:
if (IsAdministrator() == false)
{
// Restart program and run as admin
var exeName = System.Diagnostics.Process.GetCurrentProcess().MainModule.FileName;
ProcessStartInfo startInfo = new ProcessStartInfo(exeName);
startInfo.Verb = "runas";
System.Diagnostics.Process.Start(startInfo);
Application.Current.Shutdown();
return;
}
private static bool IsAdministrator()
{
WindowsIdentity identity = WindowsIdentity.GetCurrent();
WindowsPrincipal principal = new WindowsPrincipal(identity);
return principal.IsInRole(WindowsBuiltInRole.Administrator);
}
// To run as admin, alter exe manifest file after building.
// Or create shortcut with "as admin" checked.
// Or ShellExecute(C# Process.Start) can elevate - use verb "runas".
// Or an elevate vbs script can launch programs as admin.
// (does not work: "runas /user:admin" from cmd-line prompts for admin pass)
Update: The app manifest way is preferred:
Right click project in visual studio, add, new application manifest file, change the file so you have requireAdministrator set as shown in the above.
A problem with the original way: If you put the restart code in app.xaml.cs OnStartup, it still may start the main window briefly even though Shutdown was called. My main window blew up if app.xaml.cs init was not run and in certain race conditions it would do this.
According to the article Chris Corio: Teach Your Apps To Play Nicely With Windows Vista User Account Control, MSDN Magazine, Jan. 2007, only ShellExecute checks the embedded manifest and prompts the user for elevation if needed, while CreateProcess and other APIs don't. Hope it helps.
See also: same article as .chm.
[PrincipalPermission(SecurityAction.Demand, Role = #"BUILTIN\Administrators")]
This will do it without UAC - no need to start a new process. If the running user is member of Admin group as for my case.
i know this is a very old post, but i just wanted to share my solution:
System.Diagnostics.ProcessStartInfo StartInfo = new System.Diagnostics.ProcessStartInfo
{
UseShellExecute = true, //<- for elevation
Verb = "runas", //<- for elevation
WorkingDirectory = Environment.CurrentDirectory,
FileName = "EDHM_UI_Patcher.exe",
Arguments = #"\D -FF"
};
System.Diagnostics.Process p = System.Diagnostics.Process.Start(StartInfo);
NOTE: If VisualStudio is already running Elevated then the UAC dialog won't show up, to test it run the exe from the bin folder.
You should use Impersonation to elevate the state.
WindowsIdentity identity = new WindowsIdentity(accessToken);
WindowsImpersonationContext context = identity.Impersonate();
Don't forget to undo the impersonated context when you are done.
Related
Design Flow:
Non-Admin User ----> Program A (Non-Admin) --> Program B (Requires Admin)
I'm writing a program to launch a program that requires admin rights from a non-admin account. The program is launched on start-up with any user and it launches the second program (requiring admin rights) as a different user who has admin rights. The issue I am having is the program is saying that to launch a program as a different user it requires admin rights. I know this not to be true so I know I have something incorrect in my code to launch the second process.
The code is as follows:
try
{
ProcessStartInfo myProcess = new ProcessStartInfo(path);
myProcess.UserName = username;
myProcess.Password = MakeSecureString(password);
myProcess.WorkingDirectory = #"C:\Windows\System32";
myProcess.UseShellExecute = false;
myProcess.Verb = "runas"; //Does not work with or without this command
Process.Start(myProcess);
}
The exception is as follows:
System.ComponentModel.Win32Exception (0x80004005): The requested operation requires elevation
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
at System.Diagnostics.Process.Start(ProcessStartInfo startInfo)
at Loader.Program.RunProgram(String path, String username, String password)
I guess you're referring to is to trigger an UAC prompt on the newly created process. If so, just a few lines will do the trick, specifically removing the user/pass properties (since they'll be asked by Windows) and setting UseShellExecute to true:
ProcessStartInfo myProcess = new ProcessStartInfo(path);
myProcess.WorkingDirectory = #"C:\Windows\System32";
myProcess.UseShellExecute = true;
myProcess.Verb = "runas";
Process.Start(myProcess);
Two caveats I've noticed with this approach is that, if the user cancels the prompt, an exception will be thrown saying that the user has cancelled (which you must be ready to cancel your processing). Also, if UAC is disabled/not present on the system, the process will NOT be elevated. To counter that, the launched program must be ready to check if it was really given admin permissions.
A complete different approach would be to just add a manifest to the target application (if yuo're able to recompile it) specifying that it requires admin permission.
I'm trying to delete a folder off the desktop when I get the error that the path is denied. I've even made my app.manifest start the program as administrator. Now with the code below I can delete the folder successfully, but it seems so unnecessary.
string folder = "c:\\users\\jim\\desktop\\Proto";
ProcessStartInfo process = new ProcessStartInfo("cmd.exe", #"/C " + #"rmdir " + folder + " /s /q");
process.Verb = "runas";
Process p = Process.Start(process);
p.WaitForExit();
Im trying to use ...
string folder = "c:\\users\\jim\\desktop\\Proto";
Directory.Delete(folder, true);
Is it possible to to make that method "runas"?
As far as I know it's impossible to elevate just a single call/command. You'll have to launch a new process that might get blocked by UAC. Some programs seem to do so otherwise (e.g. different Windows dialogs), but they just call another process (or their own executable) with different parameters in background.
Besides that: By default, you should have full access to everything on your own desktop. Or are you trying to modify some other user's desktop?
Well for a start, the user running the application should be able to create a folder on their own desktop.
If the above is the case get rid of the stuff you put in the manifest but don't use a hard coded path
String desktopFolder = Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory);
Directory.Delete(Path.Combine(desktopFolder,"proto");
If this folder is being deleted for another other user (and admin is another user, elevated or not), then you have to run with elevated all the time, (not a good idea) , or as you are kick off another process with elevated rights to do the elevated stuff.
Take a look at this, it shows you how to run a single method as Admin user
When a user saves a file from my application, they currently can't save to restricted locations (like C:). I think this is a good restriction, but I would like to provide a UAC prompt to elevate privileges and allow a user to save in a restricted area.
I've seen lots of answers around this topic that involve spawning a new process with elevated privileges using 'runas'. Also, it seems like this can be done by impersonating another user. From what I understand, both of those methods require a user to provide user credentials.
What I'm wanting to do is basically what Windows itself does. When you try to copy a file to C:\ in Windows 7 (assuming you've got UAC set to its default level), you get the following prompt:
Once you click the Continue button with the UAC shield, the file is copied to C:\ with no prompt for credentials (assuming you're logged on with admin privileges).
How can I replicate this behavior in my application for admin users? They shouldn't have to impersonate any other user because they already have admin privileges. Can anyone provide details on what Windows is doing during this process? Are they spawning a new explorer.exe process with elevated privileges?
You need to do what Windows does. And spawn a new process which will run with elevated rights. There are no shortcuts here. The token that is allocated when a process starts is what determines what rights the process has. That token cannot be changed after the process has started. If you need to elevate, you need a new process.
I've seen lots of answers around this topic that involve spawning a new process with elevated privileges using 'runas'. Also, it seems like this can be done by impersonating another user. From what I understand, both of those methods require a user to provide user credentials.
No that's not the case. If the current user is not an admin, then the UAC dialog will prompt for new credentials of a user that does have admin rights. That's the over-the-shoulder UAC dialog. On the other hand, if the current user is an admin then they just get the consent dialog. That's the dialog that's shown on the secure desktop and just asks for you to click Continue.
The one thing that Windows components can do that you cannot is start a process elevated without showing you the consent dialog. That happens on Windows 7 only (not on Vista), and only if you have the UAC setting at the new Default setting that was added in Windows 7. That's how Explorer is able to show the dialog that you included in the question and then start an elevated process to do the copying without showing the consent UAC dialog. Only Windows components are granted that ability.
But the bottom line is that you need to start a new process that runs elevated. Using the runas verb is the canonical way to do it.
Programming Elevated Privilege/UAC
Running applications with more privileges than required is against the
principle of least privilege, and may have potential security
vulnerability. To defend this, Windows Vista introduces User Account
Control (UAC), to protect operating system by running applications
with reduced privileges (as a normal user), even the current user is
signed in as an administrator. More and more XP/2K users are also use
normal user account for daily use. Read UAC Demystified first to fully
understand UAC.
There are two common mistakes that developers tend to make:
Request the end-user to run an application with administrator privilege even
though this is not necessary, most of the time because of bad design
practices. These applications either scare away end-users, or
potentially have security vulnerability.
Do not request the end-user
to run the application elevated but try to perform operations that
require administrator privilege. These applications simply break under
Windows Vista or Windows XP/2K normal user account.
The downloadable sample code demonstrates how to programming elevated
privilege/UAC. Both WPF and Windows Forms sample applications are
provided. Run the application for the following scenarios to see the
difference:
Normal user, Windows XP/Windows Vista: the UAC shield icon
is displayed. Clicking “Save to C:\” displays “Run As” dialog, asking
user to enter administrator password to continue;
Administrator, Windows XP/Windows Vista with UAC disabled: the UAC shield icon is
hidden. Clicking “Save to C:\” completed without any dialog;
Administrator, Windows Vista with UAC enabled: the UAC shield icon is
displayed. Clicking “Save to C:\” displays dialog asking user’s
permission to continue.
Link to Download
Calling the elevated execute (testing for admin first):
private void SaveToRootFolder_Click(object sender, EventArgs e)
{
string fileName = #"C:\Test.txt";
if (App.IsAdmin)
DoSaveFile(textBox1.Text, textBox2.Text, fileName);
else
{
NameValueCollection parameters = new NameValueCollection();
parameters.Add("Text1", textBox1.Text);
parameters.Add("Text2", textBox2.Text);
parameters.Add("FileName", fileName);
string result = Program.ElevatedExecute(parameters);
if (!string.IsNullOrEmpty(result))
MessageBox.Show(result);
}
}
Elevated Executes:
internal static string ElevatedExecute(NameValueCollection parameters)
{
string tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, ConstructQueryString(parameters));
try
{
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.UseShellExecute = true;
startInfo.WorkingDirectory = Environment.CurrentDirectory;
Uri uri = new Uri(Assembly.GetExecutingAssembly().GetName().CodeBase);
startInfo.FileName = uri.LocalPath;
startInfo.Arguments = "\"" + tempFile + "\"";
startInfo.Verb = "runas";
Process p = Process.Start(startInfo);
p.WaitForExit();
return File.ReadAllText(tempFile);
}
catch (Win32Exception exception)
{
return exception.Message;
}
finally
{
File.Delete(tempFile);
}
}
A limited option, useful only when Moving, Renaming, Copying, and Deleting files:
SHFileOperation
If you attempt to perform a file operation via this function, Windows will provide the elevation prompt to the user.
Note there are some drawbacks for this:
This only works for Moving, Renaming, Copying, and Deleting. Saving a new file this way would require saving to a temp directory, then Moving it to the desired location. This does not solve the problem of the Save File Dialog not allowing you to select a UAC protected location as a target.
If the target directory doesn't exist (for a Move or Copy), SHFileOperation can prompt the user if the target directory should be created. However, it will NOT ask for elevated privileges to do so, and so will fail under a UAC protected location. The workaround for this is to manually create the non-existent directories in a temporary location, then Move/Copy them to the target location. This WILL provide the UAC prompt.
You need to have contingency plans in place for if the user selects 'Skip' or 'Cancel' to the Move/Copy dialog, or if the user selects 'No' at the UAC prompt.
I know that user accounts in Windows 7 are limited by default, so a program cannot just write anywhere on the system (as it was possible in Win XP).
But I thought that it would be possible that e.g. a c# app is allowed to write inside it's own exe-directory or it's subfolders at least (not everything is 'user settings' or should be written to "MyDocuments"...).
So currently my c# app throws an UnauthorizedAccessException when trying to write inside the exe dir.
Is there anything you can do in c# code to allow writing inside the exe dir?
No, if the user your application is running under doesn't have permissions to write to this folder you cannot write to it. When installing your application (probably through an MSI) you could grant the necessary rights.
You could also provide a manifest file with your application.
Is there anything you can do in c# code to allow writing inside the exe dir?
Yes, but this code (that changes the permissions) would need to be executed with admin permission, so you're back at the start.
In my opinion, the correct way would be to set up appropriate write permissions to a directory below C:\ProgramData (actually: Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData)) in a custom action during the installation of your software.
Yes.
Install the program in a location where user's have write/modify rights.
(Of course this opens you to those same users modifying your program.)
Yes, you should make sure you're program runs with admin privileges.
You can do this manually by rightclicking on the exec and click "Run as Administrator" or you can demand from code that the program runs with admin privileges.
WindowsPrincipal pricipal = new WindowsPrincipal(WindowsIdentity.GetCurrent());
bool hasAdministrativeRight = pricipal.IsInRole(WindowsBuiltInRole.Administrator);
if (!hasAdministrativeRight)
{
RunElevated(Application.ExecutablePath);
Environment.Exit(0);
}
private static void RunElevated(string fileName)
{
ProcessStartInfo processInfo = new ProcessStartInfo();
processInfo.Verb = "runas";
processInfo.FileName = fileName;
try
{
Process.Start(processInfo);
}
catch (Win32Exception)
{
MessageBox.Show("Program needs administrator rights");
}
}
Is it possible to require administrator rights for one single method?
Something like this:
[RequireAdminRightsForThisMethod()]
private void TheMethod(){
// Do something
}
You can add a PrincipalPermission attribute to your method to demand administrative privileges for its execution:
[PrincipalPermission(SecurityAction.Demand, Role = #"BUILTIN\Administrators")]
public void MyMethod()
{
}
This is described in more detail in the following article:
Security Principles and Local Admin Rights in C# .Net
If you are looking for a way to elevate an already existing process I doubt that this is possible as administrator privileges are given on process-level to a process upon startup (see this related question). You would have to run your application "as administrator" to get the desired behavior.
However, there are some tricks that might allow you to do what you want, but be warned that this might open up severe security risks. See the following thread in the MSDN forums:
Launching MyElevatedCom Server without prompting Administrator credentialls from Standard User
Update (from comment)
It seems that if an update requires elevation your application update is best done by a separate process (either another executable, or your application called with a command line switch). For that separate process you can request elevation as follows:
var psi = new ProcessStartInfo();
psi.FileName = "path to update.exe";
psi.Arguments = "arguments for update.exe";
psi.Verb = "runas";
var process = new Process();
process.StartInfo = psi;
process.Start();
process.WaitForExit();
A method can require administrative privileges to run, but it's not possible to automatically elevate to Admin when executing a method.