I have an implementation of the Process.Start method that fails on my Windows 7 Professional 64-bit development machine, while working in our Windows 2008 test environment.
const string CommandDirectory = #"C:\Program Files (x86)\Command";
var process = new Process
{
StartInfo =
{
FileName = string.Format("{1}{0}MyExecutable.exe", Path.DirectorySeparatorChar, CommandDirectory),
RedirectStandardError = true,
RedirectStandardOutput = true,
UseShellExecute = false,
UserName = userName,
Password = securePassword,
Domain = "MYDOMAIN",
},
};
process.Start();
At process.Start();, I get the following exception on my development machine:
System.ComponentModel.Win32Exception occurred
HResult=-2147467259
Message=The directory name is invalid
Source=System
ErrorCode=-2147467259
NativeErrorCode=267
StackTrace:
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)
at System.Diagnostics.Process.Start()
InnerException:
I have tried a few things:
I have ensured that the user account I assign to the process has full rights on the path where the executable lies, as well as the %systemroot% location. I have also ensured the user has "Impersonate a client after authentication" rights in the Local Security Policy.
I have tried explicitly setting the ProcessStartInfo.WorkingDirectory to CommandDirectory. When I do this, the executable launches but immediately crashes, without explanation.
I've made this function on my development machine by removing the UserName, Password, and Domain properties such that it uses my personal credentials. But this is not practical for deployment. This makes it seem to me that it the problem is related to credentials and permissions.
Can anyone advise what I am doing wrong?
#Julien Lebosquain's comment led me to the answer. I needed to log on locally one time as the user I wanted to impersonate. This created the default user folders.
Presumably, the executable I was calling needed to write to AppData or another subfolder of the user directory.
Related
I have an application that requires administrator permissions. It has a manifest with the required security settings:
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
Since a regular user shall be able to run this program, the installer adds a technical user having administrator permissions. The user now calls a launcher application that tries to use this account and the stored password to call the target application in an elevated context.
The launcher contains the following setting in its manifest:
<requestedExecutionLevel level="asInvoker" uiAccess="false" />
When calling the target application, I'm able to switch the user or elevate the context but not both. This is my (simplified) attempt:
public static Process RunElevatedIn(string userDomain, string userName, string userPassword, string workingDirectory, string programPath, string arguments)
{
if (userName != null)
{
// try to start with technical user credentials
try
{
var processStartInfo = new ProcessStartInfo
{
UseShellExecute = false,
FileName = programPath,
Arguments = arguments,
UserName = userName,
Password = userPassword,
Domain = userDomain,
WorkingDirectory = workingDirectory,
};
return Process.Start(processStartInfo);
}
catch (Exception exception)
{
// Log error and continue with default UAC method
}
}
// try elevation using UAC
{
var processStartInfo = new ProcessStartInfo
{
UseShellExecute = true,
FileName = programPath,
Arguments = arguments,
Verb = "runas",
WorkingDirectory = workingDirectory,
};
return Process.Start(processStartInfo);
}
}
When running this code a non-privileged user I get an error (from the first catch-clause):
System.ComponentModel.Win32Exception (0x80004005): the requested operation requires elevated privileges*
*) translated from localized error message (I hate this!)
I believe is due to switching to the right user, but failing to elevate into the administrator context. I hoped that specifying a proper manifest made Windows start the UAC to request a confirmation about the elevation from the user.
According to my search results, most hits were about people trying to circumvent the UAC entirely. This ist not my goal. The user may still be prompted with an elevation request, but shall not be asked for any credentials.
Further investigations
I tested my launcher with regedit.exe as target. regedit.exe has the following manifest and allows normal users to start it:
<requestedExecutionLevel level="highestAvailable" uiAccess="false" />
When using the user-switch in my launcher the start fails (unprivileged) despite the user being in the "administrator" group. When I manually start regedit.exe as the privileged user, I have to acknowledge the UAC.
The same test with calc.exe (no special privileges required) works fine. Conclusion:
Elevating permissions using the UAC works fine, but doesn't allow to switch the user.
Switching the user when starting an application works fine, but always drops to unprivileged (even when the launcher was started with a privileged account).
I'm starting to believe that it's impossible to switch the user and elevate the privileges via UAC in a single call. But I fail to see why this would be impossible or forbidden.
I need to run an executable on the server from an MVC controller. Problem: the executable sits within Program Files folder and will also read a value from registry.
I have granted execution rights on the respective folder to my application pool.
So here's my problem:
Running the exe just with Process.Start(exe) will start the executable which in turn then exits with an error because it cannot read the registry value (no access).
Assigning a local admin user to ProcessStartInfo fails:
var exe = #"C:\Program Files (x86)\[path to exe]";
var secString = new SecureString();
secString.AppendChar('character');
//...
secString.MakeReadOnly();
var procInfo = new ProcessStartInfo(exe, settingsPath)
{
UseShellExecute = false,
UserName = "[username]",
Domain = "[domain]",
Password = secString,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
Verb = "runas"
};
var proc = Process.Start(procInfo);
proc.WaitForExit();
This will cause a crash of conhost and the executable.
Using impersonation like this:
var impers = new ImpersonationService();
impers.PerformImpersonatedTask("[user]", "[domain]", "[password]",
ImpersonationService.LOGON32_LOGON_INTERACTIVE, ImpersonationService.LOGON32_PROVIDER_DEFAULT, new Action(RunClient));
...with the method RunClient() simply using Process.Start(exe) will do absolutely nothing! The method is run but the process is not being started. I know that the method is run because I added this line to it:
_logger.Debug("Impersonated: {0}", Environment.UserName);
Which correctly gives me the desired user name the process shall use. That user has local Admin privileges, so there should not be an issue there.
I have even tried starting a different executable from my Controller and have that one use impersonation (both variants) to start the target executable - same outcome.
So right now I'm at a dead end. Can anyone please tell me what I'm doing wrong and what I have to do to make it work?
P.S: running the target executable directly on the server when logged in as the local admin user works perfectly fine, so no prob with the exe itself.
Edit:
It seems one part of my description was incorrect: with impersonation and RunClient method I actually did not use Process.Start(exe) but this:
var procInfo = new ProcessStartInfo(exe, settingsPath)
{
UseShellExecute = false,
};
_logger.Debug("Impersonated: {0}", Environment.UserName);
var proc = Process.Start(procInfo);
Out of desperation I have now circumvented procInfo(don't actually need it) and really called
var proc = Process.Start(exe, argument);
And now the .exe starts! It seems using ProcessStartInfo overrides the impersonation for the process??
Still not OK though, as now I get an "Access denied" error. Despite being local admin. This is just weird.
Edit 2:
This is how my latest attempt went:
Switched back to calling a helper .exe, passing the same arguments later used for the actual target exe in Program Files
added a manifest to that helper exe with level="requireAdministrator"
Added Impersonation to my helper exe according to https://msdn.microsoft.com/en-us/library/w070t6ka(v=vs.110).aspx with [PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")] added before the method starting the target process.
Started the process by providing ProcessStartInfo with all the jazz
Resulting code:
try
{
var secString = new SecureString();
//...
secString.MakeReadOnly();
var procInfo = new ProcessStartInfo()
{
FileName = Path.GetFileName(exe),
UserName = "[UserName]",
Domain = "[domain]",
Password = secString,
UseShellExecute = false,
RedirectStandardError = true,
RedirectStandardOutput = true,
RedirectStandardInput = true,
Arguments = settingsPath,
WorkingDirectory = #"C:\Program Files (x86)\[rest]"
};
var proc = Process.Start(procInfo);
proc.WaitForExit();
if (proc.ExitCode != 0)
{
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log"), true))
{
sw.WriteLine("Error running process:\r\n{0}", proc.ExitCode.ToString());
}
}
}
catch (Exception ex)
{
using (var sw = new StreamWriter(Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "error.log"), true))
{
sw.WriteLine("Error running process:\r\n{0}\r\nRunning as: {1}", ex.ToString(), WindowsIdentity.GetCurrent().Name);
}
}
Resulting output to error.log:
Helper running!
[passed argument]
Error running process: System.ComponentModel.Win32Exception
(0x80004005): Access denied at
System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo
startInfo) at System.Diagnostics.Process.Start() at
System.Diagnostics.Process.Start(ProcessStartInfo startInfo) at
RunClient.ImpersonationDemo.RunClient(String settingsPath)
Running as: [correct domain user in Admin group]
So I can start the helper exe but that cannot start the real exe in Program Files due to Acess denied despite running under a local Admin account and all files access locally, not on network drives.
The logic of this eludes me.
Edit 3
Update: I have added a manifest to the target .exe also,
<requestedExecutionLevel level="requireAdministrator" uiAccess="false" />
This means I now:
Call a helper exe from the controller: works
The helper .exe has a manifest to run with elevated rights (Admin)
The helper .exe uses impersonation to assume the identity of a local admin to start a process
Said process is started using a ProcessStartInfo in which username, domain, and password are additionally set to the same local admin user
The helper exe then tries to run the target exe using Process.Start(Startinfo) with the local admin user set, while still impersonating that user's windows identity
And still the error log spouts "Access denied" while correctly returning WindowsIdentity.GetCurrent().Name as that of the local admin.
And now, the greatest of all happened: I created a new local user on that server, added him to local admin group and used that user for impersonation just in case there is a problem with domain users. Guess what? Now I get an error Access denied to ...\error.log - written to the effing error log.
Really?
Edit 4
I think I'll try TopShelf to convert this shebang to a service. Hope to get this done over the weekend.
According to this article your mvc controller thread should have full-trust permission to run the process:
This class contains a link demand at the class level that applies to
all members. A SecurityException is thrown when the immediate caller
does not have full-trust permission. For details about security
demands, see Link Demands.
Seems you problem is not the user but full-trust. I do not know which version of MVC you use but you can read the articles Trust Levels and Code Access to find out the best way to configure your application. Seems you can grant full-trust permission only to specific .exe file or grant full-trust permission to application pool user (do not forget about folder permissions).
But the best approach is to write some windows service and run it instead of running some .exe file directly.
You can try trust level in web.config of your application
<system.web>
<securityPolicy>
<trustLevel name="Full" policyFile="internal"/>
</securityPolicy>
</system.web>
I am trying to launch an external exe from a web application (running on Visual Studio development server). When I run the code below from a console application it works fine, but when I run it from a web page the application crashes. I presume this must be a permissions issue, but have tried a few things and not been able to get it working.
private void RunExe(string pythonOutputFileNameAndLocation)
{
var process = new Process { StartInfo = GetProcessStartInfo(pythonOutputFileNameAndLocation) };
// This is where the application crashes
process.Start();
// ...do some more things here
}
private ProcessStartInfo GetProcessStartInfo(string pythonOutputFileNameAndLocation)
{
var startInfo = new ProcessStartInfo
{
CreateNoWindow = true,
UseShellExecute = false,
RedirectStandardOutput = true,
RedirectStandardInput = true,
FileName = _exeFileLocation,
WindowStyle = ProcessWindowStyle.Hidden,
Arguments = String.Format("--hideUI --runScript {0}", pythonOutputFileNameAndLocation)
};
return startInfo;
}
What I am asking is why this code would work from a console application, but not from visual studio web server?
I am using Windows 7 and Visual Studio 2010.
EDIT:
As requested here are the problem details being caught by Windows:
Problem Event Name: BEX
Application Name:
Application Version: 2.2.2.2909
Application Timestamp: 507bf285
Fault Module Name: MSVCR100.dll
Fault Module Version: 10.0.40219.325
Fault Module Timestamp: 4df2be1e
Exception Offset: 0008af3e
Exception Code: c0000417
Exception Data: 00000000
OS Version: 6.1.7601.2.1.0.256.48
Locale ID: 2057
Additional Information 1: c5a0
Additional Information 2: c5a0d9e876212c0d3929ba8445f002dc
Additional Information 3: 5e93
Additional Information 4: 5e93e44f8aa24f99d37e055f533d1658
I can't debug the external application as I don't have the code from it. Also I don't have a stack trace as I am not getting an exception. The external process is just crashing.
Thanks
Ronnie, you might be running into a UAC and security access issue. Try disabling UAC and trying again. Also, consider on a real webserver this process will be started with the ASP.NET or web user permissions. These accounts are limited on purpose for security reasons. This means the application you are trying to start may fail because it cannot access files it needs. For this reason starting an external exe from a web server is not recommended. However, you can check this stackoverflow question about running applications with admin credentials. How to run c# application with admin creds?
Probably security issue with permissions but it would be best if you could give us some more details about the exception.
Have you tried running this on IIS and checking how it works there?
The exception code c0000417 has the symbolic name STATUS_INVALID_CRUNTIME_PARAMETER. Googling for "python" and "STATUS_INVALID_CRUNTIME_PARAMETER" lead to various python issues around directory permissions. You can user Process Monitor to discover if there are any permission issues while trying to run your application.
We have a .exe which we need to execute at the time an order is placed on a website. When
we test this locally it works fine using IIS Express. When we move it to IIS, it fails. We assume this is a permissions error as if we set the App Pool to run as the administrator then the script works again. The question we have is how do we execute the .exe as the administrator whilst the App Pool is ApplicationIdentity? We are using the following code:
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = executablePath,
Arguments = argumentList,
Domain = domain,
UserName = userName,
Password = securePassword,
UseShellExecute = false,
LoadUserProfile = true
}
};
process.Start();
process.WaitForExit();
process.Close();
The .exe is trying to write to the Users AppData folder which is why it fails. It is a 3rd party app so we cannot change the source code.
EDIT: Just to clarify also, when we specify the username and password in procmon it still appears to run from ISUR.
We fixed this by enabling User profile on IIS AppPool and setting permission for the IIS user on the folder it was trying to write to.
We sue ProcMon to find where the program was failing and the folder it was trying towrite to was C:\Windows\System32\config\systemprofile
i dont remember actually, but one of them is working 100% ( i had this issue before)
just let me know ehich one of them is the correct one.
I tried
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = filename,
UserName = "System",
UseShellExecute = false,
},
};
process.Start();
but it yields
Win32Exception was unhandled
Login failed: unknown user name or wrong password
I will have to use CreateProcessAsUser?
How can I get the appropriate parameters to pass to that method?
The System accounts password is maintained interally by Windows (I think) i.e. attempting to start a process as the System account by supplying credentials in this way is ultimately destined to failure.
I did however find a forum post that describes a neat trick that can be used to run processes under the system account by (ab)using windows services:
Tip: Run process in system account (sc.exe)
Alternatively the Windows Sysinternals tool PsExec appears to allow you to run a process under the System account by using the -s switch.
The Username should be LocalSystem if you want to run your process with high privileges (it's a member of Administrators group) or LocalService for normal privileges
EDIT: My mistake LocalSystem & LocalService are not regulary users and, therefore, they cannot be provided as a username. Kragen's solution is the right one