Process.Start access not allowed for File

  • Thread starter Thread starter Jenbo
  • Start date Start date
J

Jenbo

Hi, I have a small client app which calls another application to do
some processing. So I use the following:

Process watcherProc = new Process();
watcherProc.StartInfo.FileName = @"C:\windows\system32\app2.exe";
watcherProc.Start();

This works fine as administrator but if another account tries to run
the first app I get an access is denied error, I assume this is
because the normal user doesn't have access to windows\system32 to run
the process. Is there a way to get around this? Can you impersonate
administrator in windows forms and run the watcherProc like that, I
have googled this but not found much good info so any would be a great
help.

Thanks
Eamonn
 
You can impersonate any account for which you supply the credentials (user
name and password).

It involves some unmanged Interop with Windows API to do it. Here's a class
I wrote that does this, and makes it fairly easy to do. You create an
instance of it, assign the credentials, and call the ImpersonateValidUser()
method. Alternatively, it has a constructor which takes all of the necessary
information and automatically calls the ImpersonateValidUser() method. The
UndoImpersonation() reverts the app back to its' original identity. In
addition, I implemented the IDisposable interface, so that you can put it
into a using block and don't have to explicitly call UndoImpersonation(), as
in the following:

using (Impersonator person = new Impersonator("domainName", "userName",
"password")
{
// do something requiring special permissions
}

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:
http://www.miradyne.net

using System;
using System.Security;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace DsiGlobal
{
/// <summary>
/// Provides Impersonation capability.
/// </summary>
/// <remarks>This class can impersonate any user in a domain. The
/// parameterized Constructor will attempt to impersonate a User
according to
/// the Domain, User Name, and Password passed to it. In addition, the
/// <var>ImpersonateValidUser()</var> can impersonate, or change the
impersonation
/// from one user to another. The <var>UndoImpersonation()</var> method
reverts the
/// application impersonation context to its original state.</remarks>
/// <permission cref="System.Security.Permissions">Requires FullTrust
/// for this assembly</permission>
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonator : IDisposable
{
private bool _Impersonated = false;
/// <summary type="System.Boolean">
/// Is this process impersonating?
/// </summary>
public bool Impersonated
{
get { return _Impersonated; }
}


// Set up Impersonation via InterOp
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;

//need to import from COM via InteropServices to do the impersonation when
saving the details
private System.Security.Principal.WindowsImpersonationContext
ImpersonationContext;

[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
private static extern int LogonUser(String lpszUserName, String
lpszDomain,String lpszPassword,int dwLogonType, int dwLogonProvider,ref
IntPtr phToken);

[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("advapi32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true)]
private extern static int DuplicateToken(IntPtr hToken, int
impersonationLevel, ref IntPtr hNewToken);

[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr
lpSource,
int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr
*Arguments);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);

/// <summary mod="unsafe static" type="System.String">
/// Formats and returns an error message
/// corresponding to the input <paramref name="errorCode"/>.
/// </summary>
/// <param name="errorCode">A Win32 Error code</param>
/// <returns>The string translation of the <paramref
name="errorCode"/></returns>
public unsafe static string GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

//int errorCode = 0x5; //ERROR_ACCESS_DENIED
//throw new System.ComponentModel.Win32Exception(errorCode);

int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS;

IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;

int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref
lpMsgBuf, messageSize, &prtArguments);
if (0 == retVal)
{
throw new Exception("Failed to format message for error code " +
errorCode + ". ");
}
return lpMsgBuf;
}

/// <summary>
/// Constructor. Initializes <var>Domain</var>, <var>UserName</var>,
and
/// <var>Password</var>
/// </summary>
/// <param name="domain">Domain of impersonated User account</param>
/// <param name="userName">User name of impersonated User
account</param>
/// <param name="password">Password of impersonated User
account</param>
public Impersonator(string domain, string userName, string password)
{
ImpersonateValidUser(userName, domain, password);
}

/// <summary>
/// Constructor.
/// </summary>
public Impersonator()
{
}

/// <summary type="System.Boolean">
/// Impersonate a User
/// </summary>
/// <param name="userName">User Name of User to impersonate</param>
/// <param name="domain">Domain of User to impersonate</param>
/// <param name="password">Password of User to impersonate</param>
/// <returns>true if Successful, false if not</returns>
public bool ImpersonateValidUser(String userName, String domain, String
password)
{
WindowsIdentity _TempWindowsIdentity;
IntPtr _Token = IntPtr.Zero;
IntPtr _TokenDuplicate = IntPtr.Zero;

try
{
if (_Impersonated) UndoImpersonation();

if (LogonUser(userName, domain, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _Token) != 0)
{
if (DuplicateToken(_Token, 2, ref _TokenDuplicate) != 0)
{
_TempWindowsIdentity = new
WindowsIdentity(_TokenDuplicate);
ImpersonationContext =
_TempWindowsIdentity.Impersonate();
if (ImpersonationContext != null)
_Impersonated = true;
else
_Impersonated = false;
}
else
_Impersonated = false;
}
else
_Impersonated = false;
return _Impersonated;
}
catch (Exception ex)
{
Utilities.HandleError(ex);
return false;
}
}


/// <summary>
/// Revert back to local identity
/// </summary>
public void UndoImpersonation()
{
if (ImpersonationContext != null) ImpersonationContext.Undo();
ImpersonationContext = null;
}

/// <summary mod="~">
/// Destructor. Ensures that Impersonation is cancelled.
/// </summary>
~Impersonator()
{
UndoImpersonation();
}

#region IDisposable Members
/// <summary>
/// Calls <see cref="UndoImpersonation">UndoImpersonation</see> method.
/// </summary>
public void Dispose()
{
UndoImpersonation();
GC.SuppressFinalize(this);
}

#endregion
}
}
 
Thanks very much Kevin, I will try this tomorrow, seems nice way of
doing this.
#
You can impersonate any account for which you supply the credentials (user
name and password).

It involves some unmanged Interop with Windows API to do it. Here's a class
I wrote that does this, and makes it fairly easy to do. You create an
instance of it, assign the credentials, and call the ImpersonateValidUser()
method. Alternatively, it has a constructor which takes all of the necessary
information and automatically calls the ImpersonateValidUser() method. The
UndoImpersonation() reverts the app back to its' original identity. In
addition, I implemented the IDisposable interface, so that you can put it
into a using block and don't have to explicitly call UndoImpersonation(), as
in the following:

using (Impersonator person = new Impersonator("domainName", "userName",
"password")
{
// do something requiring special permissions

}

--
HTH,

Kevin Spencer
Microsoft MVP

Printing Components, Email Components,
FTP Client Classes, Enhanced Data Controls, much more.
DSI PrintManager, Miradyne Component Libraries:http://www.miradyne.net

using System;
using System.Security;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

namespace DsiGlobal
{
/// <summary>
/// Provides Impersonation capability.
/// </summary>
/// <remarks>This class can impersonate any user in a domain. The
/// parameterized Constructor will attempt to impersonate a User
according to
/// the Domain, User Name, and Password passed to it. In addition, the
/// <var>ImpersonateValidUser()</var> can impersonate, or change the
impersonation
/// from one user to another. The <var>UndoImpersonation()</var> method
reverts the
/// application impersonation context to its original state.</remarks>
/// <permission cref="System.Security.Permissions">Requires FullTrust
/// for this assembly</permission>
[PermissionSetAttribute(SecurityAction.Demand, Name = "FullTrust")]
public class Impersonator : IDisposable
{
private bool _Impersonated = false;
/// <summary type="System.Boolean">
/// Is this process impersonating?
/// </summary>
public bool Impersonated
{
get { return _Impersonated; }
}

// Set up Impersonation via InterOp
private const int LOGON32_LOGON_INTERACTIVE = 2;
private const int LOGON32_PROVIDER_DEFAULT = 0;

//need to import from COM via InteropServices to do the impersonation when
saving the details
private System.Security.Principal.WindowsImpersonationContext
ImpersonationContext;

[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("advapi32.dll", CharSet=CharSet.Auto)]
private static extern int LogonUser(String lpszUserName, String
lpszDomain,String lpszPassword,int dwLogonType, int dwLogonProvider,ref
IntPtr phToken);

[SuppressUnmanagedCodeSecurityAttribute()]
[DllImport("advapi32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto, SetLastError=true)]
private extern static int DuplicateToken(IntPtr hToken, int
impersonationLevel, ref IntPtr hNewToken);

[DllImport("kernel32.dll",
CharSet=System.Runtime.InteropServices.CharSet.Auto)]
private unsafe static extern int FormatMessage(int dwFlags, ref IntPtr
lpSource,
int dwMessageId, int dwLanguageId, ref String lpBuffer, int nSize, IntPtr
*Arguments);

[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
private extern static bool CloseHandle(IntPtr handle);

/// <summary mod="unsafe static" type="System.String">
/// Formats and returns an error message
/// corresponding to the input <paramref name="errorCode"/>.
/// </summary>
/// <param name="errorCode">A Win32 Error code</param>
/// <returns>The string translation of the <paramref
name="errorCode"/></returns>
public unsafe static string GetErrorMessage(int errorCode)
{
int FORMAT_MESSAGE_ALLOCATE_BUFFER = 0x00000100;
int FORMAT_MESSAGE_IGNORE_INSERTS = 0x00000200;
int FORMAT_MESSAGE_FROM_SYSTEM = 0x00001000;

//int errorCode = 0x5; //ERROR_ACCESS_DENIED
//throw new System.ComponentModel.Win32Exception(errorCode);

int messageSize = 255;
String lpMsgBuf = "";
int dwFlags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM
| FORMAT_MESSAGE_IGNORE_INSERTS;

IntPtr ptrlpSource = IntPtr.Zero;
IntPtr prtArguments = IntPtr.Zero;

int retVal = FormatMessage(dwFlags, ref ptrlpSource, errorCode, 0, ref
lpMsgBuf, messageSize, &prtArguments);
if (0 == retVal)
{
throw new Exception("Failed to format message for error code " +
errorCode + ". ");
}
return lpMsgBuf;
}

/// <summary>
/// Constructor. Initializes <var>Domain</var>, <var>UserName</var>,
and
/// <var>Password</var>
/// </summary>
/// <param name="domain">Domain of impersonated User account</param>
/// <param name="userName">User name of impersonated User
account</param>
/// <param name="password">Password of impersonated User
account</param>
public Impersonator(string domain, string userName, string password)
{
ImpersonateValidUser(userName, domain, password);
}

/// <summary>
/// Constructor.
/// </summary>
public Impersonator()
{
}

/// <summary type="System.Boolean">
/// Impersonate a User
/// </summary>
/// <param name="userName">User Name of User to impersonate</param>
/// <param name="domain">Domain of User to impersonate</param>
/// <param name="password">Password of User to impersonate</param>
/// <returns>true if Successful, false if not</returns>
public bool ImpersonateValidUser(String userName, String domain, String
password)
{
WindowsIdentity _TempWindowsIdentity;
IntPtr _Token = IntPtr.Zero;
IntPtr _TokenDuplicate = IntPtr.Zero;

try
{
if (_Impersonated) UndoImpersonation();

if (LogonUser(userName, domain, password,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT, ref _Token) != 0)
{
if (DuplicateToken(_Token, 2, ref _TokenDuplicate) != 0)
{
_TempWindowsIdentity = new
WindowsIdentity(_TokenDuplicate);
ImpersonationContext =
_TempWindowsIdentity.Impersonate();
if (ImpersonationContext != null)
_Impersonated = true;
else
_Impersonated = false;
}
else
_Impersonated = false;
}
else
_Impersonated = false;
return _Impersonated;
}
catch (Exception ex)
{
Utilities.HandleError(ex);
return false;
}
}

/// <summary>
/// Revert back to local identity
/// </summary>
public void UndoImpersonation()
{
if (ImpersonationContext != null) ImpersonationContext.Undo();
ImpersonationContext = null;
}

/// <summary mod="~">
/// Destructor. Ensures that Impersonation is cancelled.
/// </summary>
~Impersonator()
{
UndoImpersonation();
}

#region IDisposable Members
/// <summary>
/// Calls <see cref="UndoImpersonation">UndoImpersonation</see> method.
/// </summary>
public void Dispose()
{
UndoImpersonation();
GC.SuppressFinalize(this);
}

#endregion
}

}



Hi, I have a small client app which calls another application to do
some processing. So I use the following:
Process watcherProc = new Process();
watcherProc.StartInfo.FileName = @"C:\windows\system32\app2.exe";
watcherProc.Start();
This works fine as administrator but if another account tries to run
the first app I get an access is denied error, I assume this is
because the normal user doesn't have access to windows\system32 to run
the process. Is there a way to get around this? Can you impersonate
administrator in windows forms and run the watcherProc like that, I
have googled this but not found much good info so any would be a great
help.
Thanks
Eamonn- Hide quoted text -

- Show quoted text -
 
Couldn't you just use the Domain, Username and Password properties of the
Process.StartInfo object?
 
Back
Top