5

I have an ASP.NET MVC4 website where I'm trying to execute a process on the server. The code is as follows:

ProcessStartInfo startInfo = new ProcessStartInfo()
{
    FileName = ExeLocation,
    Arguments = string.Format("\"{0}\"{1}", ScriptLocation, Arguments),
    UseShellExecute = false,
    RedirectStandardOutput = true,
    RedirectStandardError = true,
    WorkingDirectory = AppDir,
    CreateNoWindow = true,
    UserName = ExeUsername,
    Password = ExePassword,
    Domain = ExeDomain
};

using (Process process = Process.Start(startInfo))
{
    using (StreamReader reader = process.StandardOutput)
    {
        output = reader.ReadToEnd();
    }
    using (StreamReader reader = process.StandardError)
    {
        error = reader.ReadToEnd();
    }
    process.WaitForExit();
    if (process.ExitCode != 0)
    {
        throw new Exception(string.IsNullOrEmpty(output) ? error : output);
    }
}

This works fine on my local machine in Visual Studio, but when I deployed to my server (W2K12) I get the following error:

Access is denied   
at System.Diagnostics.Process.StartWithCreateProcess(ProcessStartInfo startInfo)

I have the account referenced by ExeUsername in both the Administrators and IIS_IUSRS groups on the server.

The application pool is running as a different account (hence the need to assign a specific account to run the process) which is also a member of Administrators and IIS_IUSRS on the server.

When I log into the server and run a command prompt as ExeUsername, I am able to execute the process, so the issue must be related to executing from IIS.

What else could be blocking this access?

Paul
  • 3,725
  • 12
  • 50
  • 86
  • Possible answer here: https://stackoverflow.com/questions/11575386/foo-cmd-wont-output-lines-in-process-on-website – Brendan Green Apr 11 '19 at 01:29
  • 1
    Does your ApplicationPool identity has access to `ExeLocation`? – kapsiR Apr 11 '19 at 06:44
  • The other way is to give permissions to the IIS_IUSERS built in group to the folder that you want access to. This will give *all* default application pools access tho, so consider your use case – ste-fu Apr 11 '19 at 08:10
  • @kapsiR ApplicationPool identity is also in Administrators and IIS_IUSRS – Paul Apr 11 '19 at 14:04
  • 1
    @Paul Yes, but has that identity access to the executable and has it the permission to execute the process? [Take a look at this question/answer](https://stackoverflow.com/questions/6314173/access-is-denied-at-system-diagnostics-process-startwithcreateprocessprocesssta) – kapsiR Apr 11 '19 at 14:43

3 Answers3

1
  1. Right click on applicationpool
  2. Click on advanced setting
  3. Identity
  4. Custom Account
  5. Set username and password

If you have domain be careful use domain\username for username
and also access to folder of deployment.

Shayki Abramczyk
  • 36,824
  • 16
  • 89
  • 114
hassan.ef
  • 1,300
  • 2
  • 11
  • 19
  • 1
    I think this just about answers the question, but offers nothing over the accepted answer in the link from the comments – ste-fu Apr 11 '19 at 08:08
  • I already have the application pool running under a custom account. But the process needs to run as a different account. That's why I'm setting a specific username and password for the process. – Paul Apr 11 '19 at 14:06
0

I'd try a different approach. Firstly impersonate a custom user (the one that has permission to run a command) and then start a process within the context of impersonated user:

SafeAccessTokenHandle safeAccessTokenHandle;  
bool returnValue = LogonUser(ExeUsername, ExeDomain, ExePassword,  
        LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,  
        out safeAccessTokenHandle);

if (false == returnValue)  
{  
    int ret = Marshal.GetLastWin32Error();  
    throw new System.ComponentModel.Win32Exception(ret);  
}  

WindowsIdentity.RunImpersonated(safeAccessTokenHandle, () =>  
{  
     var startInfo = new ProcessStartInfo()
     {
         FileName = ExeLocation,
         Arguments = string.Format("\"{0}\"{1}", ScriptLocation, Arguments),
         UseShellExecute = false,
         RedirectStandardOutput = true,
         RedirectStandardError = true,
         WorkingDirectory = AppDir,
         CreateNoWindow = true,
         UserName = ExeUsername,
         Password = ExePassword,
         Domain = ExeDomain
     };

     using (Process process = Process.Start(startInfo))
     {
         using (StreamReader reader = process.StandardOutput)
         {
             output = reader.ReadToEnd();
         }

         using (StreamReader reader = process.StandardError)
         {
             error = reader.ReadToEnd();
         }

         process.WaitForExit();
         if (process.ExitCode != 0)
         {
             throw new Exception(string.IsNullOrEmpty(output) ? error : output);
         }
     } 
);  

And the LogonUser method looks like this:

[DllImport("advapi32.dll", SetLastError = true, CharSet = CharSet.Unicode)]  
public static extern bool LogonUser(String lpszUsername, String lpszDomain, 
String lpszPassword, int dwLogonType, int dwLogonProvider, 
out SafeAccessTokenHandle phToken);

More info about impersonating in .NET is here: https://learn.microsoft.com/en-gb/dotnet/api/system.security.principal.windowsidentity.runimpersonated?view=netframework-4.7.2

Lesmian
  • 3,932
  • 1
  • 17
  • 28
  • I tried a similar approach, but still no luck. The exe was still running as the Application Pool Identity. My code is in .NET 4.0: https://learn.microsoft.com/en-us/dotnet/api/system.security.principal.windowsimpersonationcontext?redirectedfrom=MSDN&view=netframework-4.0 – Paul Apr 12 '19 at 13:19
  • So impersonation worked but still app throws access denied when you called Process.Start within the context of impersonated user? Can you change temporary identity of the pool to Local system and see if the error still exists? – Lesmian Apr 12 '19 at 13:28
  • If I run the AppPool as LocalSystem, I still get the access denied error when providing a Username/Password to the Process.Start. If I remove the Username/Password from the Process.Start, it runs successfully, but as the AppPool account. My goal is to run the process as the specified account while my AppPool runs as a different account (due to another requirement of the environment). – Paul Apr 12 '19 at 13:35
  • 2
    Ok, can you try one more thing... Create a simple console app with just the code you posted in your question (ProcessStartInfo with ExeUsername) and try to run it on the server. Does it work? – Lesmian Apr 12 '19 at 13:43
  • I ran a console app on the server as the AppPool account with original code and I did not get the error. So it sure seems to be related to the way the app is running under IIS with ASP.NET Impersonation. – Paul Apr 12 '19 at 15:19
0

Maybe using this helps you.

ProcessStartInfo startInfo = new ProcessStartInfo()
{
   //...
   UseShellExecute = true,                
   Verb = "runas"
};

If you get an error you can check this also.

Engineert
  • 192
  • 1
  • 1
  • 16