How to impersonate the child process of a web service

A

Aadil Abbas

I am running a web service on IIS 6.0, impersonation is set to true, so my
web service can access resources depending on the client's privileges, but
when I launch a child process from the web service, this child process does
not inherit the security context of its parent (impersonated) thread. How
can I delegate this impersonation to the child process without making any
calls to unmanaged code like CreateProcess etc.

Here is my C# code, that is run from a web service, creates a child process
(a command shell) and tries to access a network resource. This child process
runs as
"NT Authority\Network Service" and therefore cannot access network
resources. I want to impersonate this child process, so it can access
network resources depending on the rights of client.

Process proc = new Process();
proc.StartInfo.FileName = "cmd";
proc.StartInfo.Arguments = "/k "+str+ " > h:\\temp\\log.txt";
proc.StartInfo.WorkingDirectory = @"h:\temp";
proc.StartInfo.UseShellExecute = false;
proc.StartInfo.CreateNoWindow = true;
proc.Start();

Thanks
Aadil
 
A

Aadil Abbas

Thanks Bjoern, but I have already impersonated my ASP.NET application and it
can access Network Resources. The problem, that I am facing is with the
child process of this ASP.NET application. I spawn a new process from my web
service and this new process cannot inherit the security context of its
parent thread and therefore runs under the default identity of ASP.NET
application i.e Network Service account.

The code that I supplied, is used for the creation of a new process.

Thanks
Aadil
 
B

Bjoern Wolfgardt

Hi,

yes I was able to do so (I just tried this, and it was my first time - I am
a newbee).
I disabled anonymous access in my webapp folder in the IIS. I also granted
my user the right "Replace a process level token" and activated the
impersonation in my web.config.

My sample Code (based on the one supplied by Willy Denoyette)

using System;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;


namespace ImpProcess
{
/// <summary>
/// Summary description for WebForm1.
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
internal static extern bool CreateProcessWithLogonW(String lpszUsername,
String lpszDomain, String lpszPassword,
int dwLogonFlags, string applicationName, StringBuilder commandLine,
int creationFlags, IntPtr environment,
string currentDirectory,
ref STARTUPINFO sui,
out PROCESS_INFORMATION processInfo);

[StructLayout(LayoutKind.Sequential)]
internal struct STARTUPINFO
{
internal int cb;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpReserved;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpDesktop;
[MarshalAs(UnmanagedType.LPTStr)]
internal string lpTitle;
internal int dwX;
internal int dwY;
internal int dwXSize;
internal int dwYSize;
internal int dwXCountChars;
internal int dwYCountChars;
internal int dwFillAttribute;
internal int dwFlags;
internal short wShowWindow;
internal short cbReserved2;
internal IntPtr lpReserved2;
internal IntPtr hStdInput;
internal IntPtr hStdOutput;
internal IntPtr hStdError;
}

[StructLayout(LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
internal IntPtr hProcess;
internal IntPtr hThread;
internal int dwProcessId;
internal int dwThreadId;
}

//dwLogonFlags Specifies the logon option
const int LOGON_WITH_PROFILE = 1;
const int LOGON_NETCREDENTIALS_ONLY = 2;

//dwCreationFlags - Specifies how the process is created
const int CREATE_SUSPENDED = 0x00000004;
const int CREATE_NEW_CONSOLE = 0x00000010;
const int CREATE_NEW_PROCESS_GROUP = 0x00000200;
const int CREATE_SEPARATE_WOW_VDM = 0x00000800;
const int CREATE_UNICODE_ENVIRONMENT = 0x00000400;
const int CREATE_DEFAULT_ERROR_MODE = 0x04000000;

//dwCreationFlags parameter controls the new process's priority class
const int NORMAL_PRIORITY_CLASS = 0x00000020;
const int IDLE_PRIORITY_CLASS = 0x00000040;
const int HIGH_PRIORITY_CLASS = 0x00000080;
const int REALTIME_PRIORITY_CLASS = 0x00000100;
const int BELOW_NORMAL_PRIORITY_CLASS = 0x00004000;
const int ABOVE_NORMAL_PRIORITY_CLASS = 0x00008000;
//dwFlags
// This is a bit field that determines whether certain STARTUPINFO
// members are used when the process creates a window.
// Any combination of the following values can be specified:
const int STARTF_USESHOWWINDOW = 0x0000000;
const int STARTF_USESIZE = 0x00000002;
const int STARTF_USEPOSITION = 0x00000004;
const int STARTF_USECOUNTCHARS = 0x00000008;
const int STARTF_USEFILLATTRIBUTE = 0x00000010;
const int STARTF_FORCEONFEEDBACK = 0x00000040;
const int STARTF_FORCEOFFFEEDBACK = 0x00000080;
const int STARTF_USESTDHANDLES = 0x00000100;
const int STARTF_USEHOTKEY = 0x00000200;


protected System.Web.UI.WebControls.Button Button1;

private void Page_Load(object sender, System.EventArgs e)
{
// Put user code to initialize the page here
}

#region Web Form Designer generated code
override protected void OnInit(EventArgs e)
{
//
// CODEGEN: This call is required by the ASP.NET Web Form Designer.
//
InitializeComponent();
base.OnInit(e);
}

/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
this.Button1.Click += new System.EventHandler(this.Button1_Click);
this.Load += new System.EventHandler(this.Page_Load);

}
#endregion

private void Button1_Click(object sender, System.EventArgs e)
{
// I inserted this to check that my ASP.NET Web App is corectly
impersonated.
string temp = System.Web.HttpContext.Current.User.Identity.Name;
// Account to run as
string _logonName = "myuser"; // some user
string _domain = "."; // local machine account
string _password = "myPassword";
StringBuilder sb = new StringBuilder();
// command to execute
sb.Append(@"notepad.exe");

PROCESS_INFORMATION processInfo;
STARTUPINFO startInfo = new STARTUPINFO();
startInfo.cb = Marshal.SizeOf(startInfo);
startInfo.lpTitle = "This is a NotePad console";
startInfo.dwFlags = STARTF_USECOUNTCHARS;
startInfo.dwYCountChars = 50;

// create process similar as "runas" using the logon users profile
bool ret = CreateProcessWithLogonW(_logonName, _domain, _password,
LOGON_WITH_PROFILE, null, sb,
NORMAL_PRIORITY_CLASS | CREATE_UNICODE_ENVIRONMENT,
IntPtr.Zero, "c:\\",
ref startInfo, out processInfo);
Console.WriteLine("CreateProcessWithLogonW called");
if(!ret)
{ // If failure ...
Response.Write(Marshal.GetLastWin32Error());
}
else
{
Response.Write(processInfo.dwProcessId);
}
}
}
}

I inserted a breakpoint after CreateProcessWithLogonW and watched the
taskpad for my new notepad. And it runs as my user.
My Config:
Windows XP with SP1
Framework 1.1

Hope this helps
Bjoern Wolfgardt
 
A

Aadil Abbas

The function "CreateProcessWithLogonW" works fine from a web service running
on IIS 5.0 and Windows XP Pro, but when I run the same code from a web
service in Windows 2003 Server and IIS 6.0, this specific function call
results in an error window: "Application Error: The application failed to
initialize properly (0xc0000142). Click on OK to terminate the application."

I have made sure that "Replace a process level token" right is assigned to
my user. Are you getting the same behavior on Windows 2003?

Thanks
Aadil
 

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
473,994
Messages
2,570,223
Members
46,810
Latest member
Kassie0918

Latest Threads

Top