Access Denied executing Batch File from CreateProcessAsUser

S

S Hayes

I am trying to run a batch file from within an Asp.net webservice and am
receiving an Access Denied error. I have verified that the impersonated user
has proper rights to the directory that the batch file is in by executing a
program from the same directory. It seems that everything works fine for non
batch file execution, but batch files return an error.

I'm currently running under IIS 5.
 
Y

Yunus Emre ALPÖZEN [MCP]

The batch file executed under IIS user account. You should define rights for
it. Impersonation doesn't work for your scenario
 
S

S Hayes

I don't understand what you mean by "The batch file executed under IIS user
account". I am using the CreateProcessAsUser which will create the process
using the credentials of the passed in Token which I am getting from the
Impersonated user. Again, I have verified this works when executing a
program file, but fails when executing a batch file.
 
Y

Yunus Emre ALPÖZEN [MCP]

do u develop an ASP.NET web service ???

"CreateProcessAsUser property specifies whether a CGI process is created in
the system context or in the context of the requesting user"
not a batch application.

My advice u to use System.Diagnostics.Process...

Do u have any sample code to cause error again??
 
S

S Hayes

I can't use System.Diagnostics.Process in my case since this class ALWAYS
creates the process with the underlying process security context, not the
impersonated users security context.

This code is being executed within a ASP.NET web services.

The following is the function that is being called. When the executable
parameter passed in is a batch file, I get the 'Access Denied' error on the
CreateProcessAsUser call. If the executable parameter is a program, then
everything works nicely. As stated in earlier Threads, both the batch file
and the program file are in the same directory and the impersonated user has
Full rights.

<<**********************************
#region Win32 declarations

[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}

[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}

[DllImport("kernel32.dll")]
private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint
lpExitCode);

[DllImport("kernel32", SetLastError=true, ExactSpelling=true)]
private static extern Int32 WaitForSingleObject(IntPtr handle, Int32
milliseconds);

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

[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser",
SetLastError=true, CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.StdCall)]
private extern static bool CreateProcessAsUser(IntPtr hToken, String
lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES
lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int
dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out
PROCESS_INFORMATION lpProcessInformation);

[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx",
SetLastError=true)]
private extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);

#endregion

public static int RunProcessAsUser(string executable,string cmdLine,int
timeOut)
{
int errorCode = 0;
bool ret;
IntPtr token = new IntPtr(0);
IntPtr dupedToken = new IntPtr(0);

SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.bInheritHandle = false;
sa.Length = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = (IntPtr)0;

token = WindowsIdentity.GetCurrent().Token;
const uint GENERIC_ALL = 0x10000000;

const int SecurityImpersonation = 2;
const int TokenType = 1;

ret = DuplicateTokenEx(token, GENERIC_ALL, ref sa, SecurityImpersonation,
TokenType, ref dupedToken);

if (ret == false)
{
errorCode = Marshal.GetLastWin32Error();
throw new Exceptions.SecurityException("Unable to duplicate User
Security Token",new Win32Exception(errorCode));
}

STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";

PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
ret = CreateProcessAsUser(dupedToken, executable, cmdLine, ref sa, ref
sa, false, 0, (IntPtr)0, null, ref si, out pi);

if (ret == false)
{
errorCode = Marshal.GetLastWin32Error();
throw new Exceptions.SecurityException("Unable to Create Process for
User",new Win32Exception(errorCode));
}

if(WaitForSingleObject( pi.hProcess, timeOut ) != 0)
throw new Exceptions.WarningException("Timeout running User Process");

uint ec;
GetExitCodeProcess(pi.hProcess,out ec);
errorCode = (int)ec;

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

CloseHandle(dupedToken);

return errorCode;
}

**********************************>>
 
J

Joe Kaplan \(MVP - ADSI\)

Did you see some of the references to previous threads that suggested using
WMI to accomplish this? Apparently that solution works well. I can't
remember what the problem is with CreateProcessAsUser, but you seem to have
the same symptoms that others have complained of in the past.

Just a thought...

Joe K.

S Hayes said:
I can't use System.Diagnostics.Process in my case since this class ALWAYS
creates the process with the underlying process security context, not the
impersonated users security context.

This code is being executed within a ASP.NET web services.

The following is the function that is being called. When the executable
parameter passed in is a batch file, I get the 'Access Denied' error on
the
CreateProcessAsUser call. If the executable parameter is a program, then
everything works nicely. As stated in earlier Threads, both the batch
file
and the program file are in the same directory and the impersonated user
has
Full rights.

<<**********************************
#region Win32 declarations

[StructLayout(LayoutKind.Sequential)]
private struct STARTUPINFO
{
public int cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public uint dwX;
public uint dwY;
public uint dwXSize;
public uint dwYSize;
public uint dwXCountChars;
public uint dwYCountChars;
public uint dwFillAttribute;
public uint dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
private struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}

[StructLayout(LayoutKind.Sequential)]
private struct SECURITY_ATTRIBUTES
{
public int Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}

[DllImport("kernel32.dll")]
private static extern bool GetExitCodeProcess(IntPtr hProcess, out uint
lpExitCode);

[DllImport("kernel32", SetLastError=true, ExactSpelling=true)]
private static extern Int32 WaitForSingleObject(IntPtr handle, Int32
milliseconds);

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

[DllImport("advapi32.dll", EntryPoint="CreateProcessAsUser",
SetLastError=true, CharSet=CharSet.Ansi,
CallingConvention=CallingConvention.StdCall)]
private extern static bool CreateProcessAsUser(IntPtr hToken, String
lpApplicationName, String lpCommandLine, ref SECURITY_ATTRIBUTES
lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandle, int
dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo, out
PROCESS_INFORMATION lpProcessInformation);

[DllImport("advapi32.dll", EntryPoint="DuplicateTokenEx",
SetLastError=true)]
private extern static bool DuplicateTokenEx(IntPtr ExistingTokenHandle,
uint dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes, int TokenType,
int ImpersonationLevel, ref IntPtr DuplicateTokenHandle);

#endregion

public static int RunProcessAsUser(string executable,string cmdLine,int
timeOut)
{
int errorCode = 0;
bool ret;
IntPtr token = new IntPtr(0);
IntPtr dupedToken = new IntPtr(0);

SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.bInheritHandle = false;
sa.Length = Marshal.SizeOf(sa);
sa.lpSecurityDescriptor = (IntPtr)0;

token = WindowsIdentity.GetCurrent().Token;
const uint GENERIC_ALL = 0x10000000;

const int SecurityImpersonation = 2;
const int TokenType = 1;

ret = DuplicateTokenEx(token, GENERIC_ALL, ref sa,
SecurityImpersonation,
TokenType, ref dupedToken);

if (ret == false)
{
errorCode = Marshal.GetLastWin32Error();
throw new Exceptions.SecurityException("Unable to duplicate User
Security Token",new Win32Exception(errorCode));
}

STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";

PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
ret = CreateProcessAsUser(dupedToken, executable, cmdLine, ref sa, ref
sa, false, 0, (IntPtr)0, null, ref si, out pi);

if (ret == false)
{
errorCode = Marshal.GetLastWin32Error();
throw new Exceptions.SecurityException("Unable to Create Process for
User",new Win32Exception(errorCode));
}

if(WaitForSingleObject( pi.hProcess, timeOut ) != 0)
throw new Exceptions.WarningException("Timeout running User
Process");

uint ec;
GetExitCodeProcess(pi.hProcess,out ec);
errorCode = (int)ec;

CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

CloseHandle(dupedToken);

return errorCode;
}

**********************************>>

Yunus Emre ALPÖZEN said:
do u develop an ASP.NET web service ???

"CreateProcessAsUser property specifies whether a CGI process is created
in
the system context or in the context of the requesting user"
not a batch application.

My advice u to use System.Diagnostics.Process...

Do u have any sample code to cause error again??
 

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

Members online

Forum statistics

Threads
474,001
Messages
2,570,249
Members
46,848
Latest member
Graciela Mitchell

Latest Threads

Top