Process.Start access not allowed for File

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
 
K

Kevin Spencer

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
}
}
 
J

Jenbo

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 -
 
G

Guest

Couldn't you just use the Domain, Username and Password properties of the
Process.StartInfo object?
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top