473,765 Members | 2,010 Online
Bytes | Software Development & Data Engineering Community
+ Post

Home Posts Topics Members FAQ

Run app as specified user from ASP.NET 2.0

Hi,

First please forgive that this is a repost as the first time I didn't have
my proper nospam email configured...

I'm writing a web service where one method will launch another .NET program
under a specified user's account. It launches fine as the NT
AUTHORITY\NETWO RK SERVICE user when I dont specify a username/password for
the ProcessStartInf o but I am having trouble getting it to work when I
specify any other username/password pair. I immediately get "The application
failed to initialize properly (0xC0000142). I think this is because these
apps want to "interact" with the desktop. For instance devenv even though
everything is passed on the cmdline and there will be no windows and/or user
interaction.

Has anyone ever gotten this to work using Process.Start/ProcessStartInf o?

Note I do *not* want to impersonate the client nor have any of the other
code run during the processing of the request run using any credentials other
than NETWORK SERVICE so I don't think I want any form of impersonation that
can be configured through web.config, machine.config, etc. I only want the
third party app I want to launch and get the stderr/stdout streams back from
to be run in the specified user account.

Also this fails identically regardless of the setting of "Allow service to
interact with desktop" for the www service although idealy I would like it to
work with that not checked. For some strange reason I don't see a desktop
property on the managed ProcessStartInf o like there is on the unmanaged
startinfo struct... If necessary I will pinvoke Win32 api's but have failed
even getting that juju correct...

Thanks in advance :-)

-john

PS yes I know MSBuild would launch ok but I'm not sure it will build all
VS2003 sln files and I know it doesn't build deployment projects and several
of the sln files I need to build include deployment projects... (groan)
Jul 20 '06 #1
7 3875
Hi Steven,

Thanks very much for your response. I was trying to save steps by using
CreateProcessWi thLogon. I still had a mysterious problem with one user
account but it went away when I removed and recreated that account. So I have
switched over using the sample code you so helpfully embedded and now have it
launching successfully. Im not sure if I'll run into trouble later with the
user profile loading issue or not (or does logonuser do that too?). I would
be interested in hearing why you chose to use the logonuser/createasuser
combination over createwithlogon if you have the time.

Anyway now I'm just trying to get the reading/writing to/from
stdin/stdout/stderr working and was wondering if you also had sample code for
creating the handles and duplicates, getting the pipes read on worker
threads, etc?

Also I wanted to ask you if as part of your role here supporting the real
world you have a chance to give some feedback to the dev teams to make your
life and ours easier. If so please comment to them on their disturbing trend
of making so many useful parts of the framework assembly scoped or worse yet
private.
Here we see the processinfo and startupinfo that are assembly scoped in
System.Win32.Na tiveMethods so we cant use them and have to duplicate them.
When trying to get the stdin/stdout/stderr stuff working I additionally could
have used securityattribu te, createpipe, duplicatehandle , etc. Again all
exist in the framework out of reach. Other examples in the past I've
encountered were getting the soapprotocolver sion from a webservice, getting
the httpworkerreque st from the httpcontext, and many many more examples. This
means we all have to duplicate the classes/code, bug you guys when we have
problems getting it to work, worry our pinvoking slightly incorrect and is
slowly leaking unmanaged resources, and find working with this framework all
in all less productive than it could be.

sorry for the frustration induced mini rant.
you personally for one have been a great help!

thanks again :-)
-john

"Steven Cheng[MSFT]" wrote:
Hello John,

Welcome to the ASP.NET newsgroup.

From your description, I understand you're going to launch the visual
studio's devenv.exe program(in a new process) to build some projects in
ASP.NET web application. You've tried using the new
System.Diagnost ics.Process/ProcessStartInf o class with no success, correct?

According to your test cases, I've also performed some tests on my local
side and also encoutered the similiar behavior as yours. Here are the
results I got:

1. Let the new process(through Process class) start under the default
security context( the default process identity-----NT AUTHORITY\NETWO RK
SERVICE). The sub process started correctly and finished the build task.

2. Use Process class with ProcessStartInf o(supply a different user
account's credentials), after the Process.Start call, the page hangs(I call
Process.Waitfor Exit), I think it is due to the same error you mentioned and
since ASP.NET process(or any created sub process) running under a
non-interactive winstation, the popup error message is not displayed and
the process hangs.

I've analyized this issue with some other engineers and we've concluded
that it is likely caused by the ProcessStartInf o class. Though the managed
ProcessStartInf o provide username/password properties for launching
processes under different security context, it still doesn't provide some
advanced options like desktop. For this issue, when we try creating the new
process through a new specific account, it internally require an
interactive/desktop(at least not the original ASP.NET server process's
desktop), then the error raise out. Therefore, the managed Process class
may only be supposed to work in interactive application context (such as
console or winform) if we want to use different security context(by
assigning the username/password) property.

For your scenario, I've tried some other approachs and currently we can
managed programmtically execute separate process under specific user
account by calling the win32 "CreateProcessA sUser" function(throug h
pinvoke). Also, before calling this function, we need to get the security
token of the specific user which we also need to programmaticall y call some
win32 API to logon the user and programmtically impersonate it. Here we're
using programmtic impersonate rather than use web.config or machine.config.
And all these tasks are well demonstrated in the following two knowledge
base articles:

#How to implement impersonation in an ASP.NET application
http://support.microsoft.com/kb/306158/en-us

#How to spawn a process that runs under the context of the impersonated
user in Microsoft ASP.NET pages
http://support.microsoft.com/kb/889251/en-us

Further more, I've created a simple sample page which use the win32 API to
programmtically launch the devenv.exe to build a project in a button's
postback event. Here is the page's complete codebehind (in case the code
may display incorrect on page, I've also attached the code file in this
message, you can get the file if you're using outlook express to access the
newsgroup):

===========page code=====
using System;
using System.Data;
using System.Configur ation;
using System.Collecti ons;
using System.Web;
using System.Web.Secu rity;
using System.Web.UI;
using System.Web.UI.W ebControls;
using System.Web.UI.W ebControls.WebP arts;
using System.Web.UI.H tmlControls;
using System.Diagnost ics;
using System.Security ;

using System.Web.Secu rity;
using System.Security .Principal;
using System.Runtime. InteropServices ;
public partial class Execute_Default : System.Web.UI.P age
{

public const int LOGON32_LOGON_I NTERACTIVE = 2;
public const int LOGON32_PROVIDE R_DEFAULT = 0;

WindowsImperson ationContext impersonationCo ntext;

protected void Page_Load(objec t sender, EventArgs e)
{

}
protected void btnExecute_Clic k(object sender, EventArgs e)
{
if (impersonateVal idUser("Adminis trator", "machinenam e",
"password") )
{
Response.Write( "<br/>User:" +
System.Security .Principal.Wind owsIdentity.Get Current().Name) ;

RunWin32Command ();

undoImpersonati on();
}
else
{
Response.Write( "<br/>Impersonate failed...");
}

}
void RunWin32Command ()
{
IntPtr Token = new IntPtr(0);
IntPtr DupedToken = new IntPtr(0);
bool ret;
//Label2.Text += WindowsIdentity .GetCurrent().N ame.ToString();
SECURITY_ATTRIB UTES sa = new SECURITY_ATTRIB UTES();
sa.bInheritHand le = false;
sa.Length = Marshal.SizeOf( sa);
sa.lpSecurityDe scriptor = (IntPtr)0;

Token = WindowsIdentity .GetCurrent().T oken;

const uint GENERIC_ALL = 0x10000000;

const int SecurityImperso nation = 2;
const int TokenType = 1;

ret = DuplicateTokenE x(Token, GENERIC_ALL, ref sa,
SecurityImperso nation, TokenType, ref DupedToken);

if (ret == false)
Response.Write( "<br/>" + "DuplicateToken Ex failed with " +
Marshal.GetLast Win32Error());

else
Response.Write( "<br/>" + "DuplicateToken Ex SUCCESS");

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

string filename = @"C:\Program Files\Microsoft Visual Studio
8\Common7\IDE\d evenv.exe";

string arguments = " \"D:\\temp\\wor kspace\\Protect Config.sln\"
/build Debug /project \"ProtectConfig \\ProtectConfig .csproj\"
/projectconfig Debug";

string commandLinePath ;

commandLinePath = filename + arguments;
PROCESS_INFORMA TION pi = new PROCESS_INFORMA TION();
ret = CreateProcessAs User(DupedToken , null, commandLinePath , ref
sa, ref sa, false, 0, (IntPtr)0, "d:\\temp", ref si, out pi);

if (ret == false)
Response.Write( "<br/>" + "CreateProcessA sUser failed with " +
Marshal.GetLast Win32Error());
else
{
Response.Write( "<br/>" + "CreateProcessA sUser SUCCESS. The
child PID is" + pi.dwProcessId) ;

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

ret = CloseHandle(Dup edToken);
if (ret == false)
Response.Write( "<br/>" + Marshal.GetLast Win32Error());
else
Response.Write( "<br/>" + "CloseHandl e SUCCESS");

}



private bool impersonateVali dUser(String userName, String domain,
String password)
{
WindowsIdentity tempWindowsIden tity;
IntPtr token = IntPtr.Zero;
IntPtr tokenDuplicate = IntPtr.Zero;

if (RevertToSelf() )
{
if (LogonUserA(use rName, domain, password,
LOGON32_LOGON_I NTERACTIVE,
LOGON32_PROVIDE R_DEFAULT, ref token) != 0)
{
if (DuplicateToken (token, 2, ref tokenDuplicate) != 0)
{
tempWindowsIden tity = new
WindowsIdentity (tokenDuplicate );
impersonationCo ntext =
tempWindowsIden tity.Impersonat e();
if (impersonationC ontext != null)
{
CloseHandle(tok en);
CloseHandle(tok enDuplicate);
return true;
}
}
}
}
if (token != IntPtr.Zero)
CloseHandle(tok en);
if (tokenDuplicate != IntPtr.Zero)
CloseHandle(tok enDuplicate);
return false;
}

private void undoImpersonati on()
{
impersonationCo ntext.Undo();
}

//for impersonate/////////////////
[DllImport("adva pi32.dll")]
public static extern int LogonUserA(Stri ng lpszUserName,
String lpszDomain,
String lpszPassword,
int dwLogonType,
int dwLogonProvider ,
ref IntPtr phToken);
[DllImport("adva pi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern int DuplicateToken( IntPtr hToken,
int impersonationLe vel,
ref IntPtr hNewToken);

[DllImport("adva pi32.dll", CharSet = CharSet.Auto, SetLastError = true)]
public static extern bool RevertToSelf();

//[DllImport("kern el32.dll", CharSet = CharSet.Auto)]
//public static extern bool CloseHandle(Int Ptr handle);
///////////////////////////////////////////////////////
[StructLayout(La youtKind.Sequen tial)]
public 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(La youtKind.Sequen tial)]
public struct PROCESS_INFORMA TION
{
public IntPtr hProcess;
public IntPtr hThread;
public uint dwProcessId;
public uint dwThreadId;
}

[StructLayout(La youtKind.Sequen tial)]
public struct SECURITY_ATTRIB UTES
{
public int Length;
public IntPtr lpSecurityDescr iptor;
public bool bInheritHandle;
}

[DllImport("kern el32.dll", EntryPoint = "CloseHandl e", SetLastError =
true, CharSet = CharSet.Auto, CallingConventi on =
CallingConventi on.StdCall)]
public extern static bool CloseHandle(Int Ptr handle);
Jul 24 '06 #2
PS: Here is the code Im using so you can see what I've tried so far...
---------------------------------------------------------------------------
using System;
using System.Collecti ons;
using System.Collecti ons.Specialized ;
using System.Componen tModel;
using System.Diagnost ics;
using System.IO;
using System.Security ;
using System.Security .Principal;
using System.Runtime. InteropServices ;
using System.Text;

internal class ProcessManager
{
private static readonly int MillisPerMinute =
(int)(TimeSpan. TicksPerMinute / TimeSpan.TicksP erMillisecond);
internal static readonly int OneMinute = MillisPerMinute ;
internal static readonly int TwoMinutes = 2 * MillisPerMinute ;
internal static readonly int ThreeMinutes = 3 * MillisPerMinute ;
internal static readonly int ThirtyMinutes = 30 * MillisPerMinute ;

private static readonly int s_LogonInteract ive = 2;
private static readonly int s_LogonProvider Default = 0;
private static readonly uint s_GenericAll = 0x10000000;
private static readonly int s_SecurityImper sonation = 2;
private static readonly int s_TokenType = 1;
private static readonly int s_StillActive = 259;
private static readonly int s_TimedOut = 0x102;

private static readonly int s_PipeSize = 16 * 1024;
private static readonly int s_CloseSource = 1;
private static readonly int s_SameAccess = 2;

internal static bool SyncRunHiddenPr ocess(string Domain, string UserName,
string Password, string WorkingDirector y, string Command, string Args, int
Timeout, out string StdOut, out string StdErr)
{
bool result = false;

StdOut = string.Empty;
StdErr = string.Empty;

try
{
WindowsImperson ationContext impersonation = null;

if( (!string.IsNull OrEmpty( UserName )) && (!string.IsNull OrEmpty(
Password )) )
{
impersonation = ImpersonateUser ( Domain, UserName, Password );
}

RunWin32Command ( Command, Args, WorkingDirector y, ref StdOut, Timeout );

if( impersonation != null ) impersonation.U ndo();

result = true;
}
catch(Exception e)
{
StdErr = string.Format( "SyncRunHiddenP rocess({0} {1}) failed! {2}",
Command, Args, e.Message );
}

return( result );
}

private static void RunWin32Command (string Command, string Args, string
WorkingDirector y, ref string StdOut, int Timeout)
{
IntPtr token = WindowsIdentity .GetCurrent().T oken;
IntPtr dupedToken = IntPtr.Zero;
SecurityAttribu tes sa = new SecurityAttribu tes( false );

if( !DuplicateToken Ex( token, s_GenericAll, ref sa,
s_SecurityImper sonation, s_TokenType, out dupedToken ) )
{
throw new ApplicationExce ption( string.Format( "DuplicateT oken
failed({0})", Marshal.GetLast Win32Error() ) );
}

try
{
StartupInfo si = new StartupInfo( true );
ProcessInformat ion pi = new ProcessInformat ion();
IntPtr stdIn = IntPtr.Zero;
IntPtr stdOut = IntPtr.Zero;
IntPtr stdErr = IntPtr.Zero;

try
{
StringBuilder sbOut = new StringBuilder( s_PipeSize );
StringBuilder sbErr = new StringBuilder( s_PipeSize );

CreateStdPipes( ref si, out stdIn, out stdOut, out stdErr );

if( !CreateProcessA sUser( dupedToken, null, string.Format( "{0} {1}",
Command, Args ), ref sa, ref sa, false, 0, IntPtr.Zero, WorkingDirector y, ref
si, out pi ) )
{
throw new ApplicationExce ption( string.Format( "CreateProcessA sUser
failed({0})", Marshal.GetLast Win32Error() ) );
}

try
{
uint exitCode;
int cb;

if( pi.Thread != IntPtr.Zero ) CloseHandle( pi.Thread );

GetExitCodeProc ess( pi.Process, out exitCode );

if( exitCode == s_StillActive )
{
if( WaitForSingleOb ject( pi.Process, Timeout ) == s_TimedOut )
{
throw new ApplicationExce ption( "CreateProcessA sUser timed out" );
}
else GetExitCodeProc ess( pi.Process, out exitCode );
}

// This needs to be moved to a worker thread once I get it working at
all...
ReadPipe( stdErr, out sbOut, sbOut.Capacity, out cb, IntPtr.Zero );
ReadPipe( stdOut, out sbErr, sbErr.Capacity, out cb, IntPtr.Zero );

if( exitCode != 0 )
{
throw new ApplicationExce ption( string.Format( "CreateProcessA sUser
exited with exitcode({0})\n {1}", exitCode, sbErr ) );
}
else
{
StdOut = sbOut.ToString( );
}
}
finally{ if( pi.Process != IntPtr.Zero ) CloseHandle( pi.Process ); }
}
finally
{
if( si.StdInput != IntPtr.Zero ) CloseHandle( si.StdInput );
if( si.StdOutput != IntPtr.Zero ) CloseHandle( si.StdOutput );
if( si.StdError != IntPtr.Zero ) CloseHandle( si.StdError );

if( stdIn != IntPtr.Zero ) CloseHandle( stdIn );
if( stdOut != IntPtr.Zero ) CloseHandle( stdOut );
if( stdErr != IntPtr.Zero ) CloseHandle( stdErr );
}
}
finally{ CloseHandle( dupedToken ); }
}

private static WindowsImperson ationContext ImpersonateUser (string Domain,
string UserName, string Password)
{
WindowsImperson ationContext impersonation = null;
IntPtr token;
IntPtr dupedToken;

if( LogonUser( UserName, Domain, Password, s_LogonInteract ive,
s_LogonProvider Default, out token ) != 0 )
{
try
{
if( DuplicateToken( token, s_SecurityImper sonation, out dupedToken ) !=
0 )
{
try
{
WindowsIdentity identity = new WindowsIdentity ( dupedToken );

impersonation = identity.Impers onate();

if( impersonation == null ) throw new ApplicationExce ption(
string.Format( @"ImpersonateUs er {0}\{1} failed!", Domain, UserName ) );
}
finally{ CloseHandle( dupedToken ); }
}
}
finally{ CloseHandle( token ); }
}

return( impersonation );
}

private static void CreateStdPipes( ref StartupInfo si, out IntPtr
ChildStdIn, out IntPtr ChildStdOut, out IntPtr ChildStdErr)
{
SecurityAttribu tes sa1 = new SecurityAttribu tes( true );
IntPtr stdInRead = IntPtr.Zero;
IntPtr stdInWrite = IntPtr.Zero;
IntPtr stdOutRead = IntPtr.Zero;
IntPtr stdOutWrite = IntPtr.Zero;
IntPtr stdErrRead = IntPtr.Zero;
IntPtr stdErrWrite = IntPtr.Zero;
IntPtr dupedStdIn = IntPtr.Zero;
IntPtr dupedStdOut = IntPtr.Zero;
IntPtr dupedStdErr = IntPtr.Zero;
bool result = false;

si.StdInput = IntPtr.Zero;
si.StdOutput = IntPtr.Zero;
si.StdError = IntPtr.Zero;

ChildStdIn = IntPtr.Zero;
ChildStdOut = IntPtr.Zero;
ChildStdErr = IntPtr.Zero;

try
{
if( CreatePipe( out stdInRead, out stdInWrite, ref sa1, s_PipeSize ) &&
CreatePipe( out stdOutRead, out stdOutWrite, ref sa1, s_PipeSize ) &&
CreatePipe( out stdErrRead, out stdErrWrite, ref sa1, s_PipeSize ) &&
DuplicateHandle ( GetCurrentProce ss(), stdInWrite, GetCurrentProce ss(),
out dupedStdIn, 0, false, s_SameAccess | s_CloseSource ) &&
DuplicateHandle ( GetCurrentProce ss(), stdOutRead, GetCurrentProce ss(),
out dupedStdOut, 0, false, s_SameAccess | s_CloseSource ) &&
DuplicateHandle ( GetCurrentProce ss(), stdErrRead, GetCurrentProce ss(),
out dupedStdErr, 0, false, s_SameAccess | s_CloseSource ) )
{
si.StdInput = stdInRead;
si.StdOutput = stdOutWrite;
si.StdError = stdErrWrite;

ChildStdIn = dupedStdIn;
ChildStdOut = dupedStdOut;
ChildStdErr = dupedStdErr;

result = true;
}
else throw new ApplicationExce ption( "CreatePipe s failed" );
}
finally
{
if( !result )
{
if( stdInRead != IntPtr.Zero ) CloseHandle( stdInRead );
if( stdOutWrite != IntPtr.Zero ) CloseHandle( stdOutWrite );
if( stdErrWrite != IntPtr.Zero ) CloseHandle( stdErrWrite );
if( dupedStdOut != IntPtr.Zero ) CloseHandle( dupedStdOut );
if( dupedStdErr != IntPtr.Zero ) CloseHandle( dupedStdErr );
}
}
}

[StructLayout(La youtKind.Sequen tial)]
public struct SecurityAttribu tes
{
public int Length;
public IntPtr SecurityDescrip tor;
public bool InheritHandle;

internal SecurityAttribu tes(bool Inherit): this()
{
InheritHandle = Inherit;
Length = Marshal.SizeOf( this );
SecurityDescrip tor = IntPtr.Zero;
}
}

[StructLayout(La youtKind.Sequen tial)]
public struct ProcessInformat ion
{
public IntPtr Process;
public IntPtr Thread;
public uint ProcessId;
public uint ThreadId;
}

[StructLayout(La youtKind.Sequen tial)]
private struct StartupInfo
{
public int cb;
public string Reserved;
public string Desktop;
public string Title;
public uint X;
public uint Y;
public uint XSize;
public uint YSize;
public uint XCountChars;
public uint YCountChars;
public uint FillAttribute;
public uint Flags;
public short ShowWindow;
public short cbReserved2;
public IntPtr Reserved2;
public IntPtr StdInput;
public IntPtr StdOutput;
public IntPtr StdError;

internal StartupInfo(boo l init): this()
{
cb = Marshal.SizeOf( this );
Desktop = string.Empty;
Flags = 0x100 | 0x400; // STARTF_USESHOWW INDOW | STARTF_USESTDHA NDLES;
ShowWindow = 0; // SW_HIDE
}
}

[DllImport("adva pi32.dll",Entry Point="LogonUse rW",CharSet=Cha rSet.Unicode,Se tLastError=true ,CallingConvent ion=CallingConv ention.StdCall) ,SuppressUnmana gedCodeSecurity]
private static extern int LogonUser(strin g UserName, string Domain, string
Password, int CreateFlags, int ProviderFlags, out IntPtr Token);

[DllImport("adva pi32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private static extern int DuplicateToken( IntPtr Token, int
ImpersonationLe vel, out IntPtr DupedToken);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private extern static bool CloseHandle(Int Ptr Handle);

[DllImport("adva pi32.dll",Entry Point="CreatePr ocessAsUserW",C harSet=CharSet. Unicode,SetLast Error=true,Call ingConvention=C allingConventio n.StdCall),Supp ressUnmanagedCo deSecurity]
private extern static bool CreateProcessAs User(IntPtr Token, string
ApplicationName , string CommandLine, ref SecurityAttribu tes
ProcessAttribut es, ref SecurityAttribu tes ThreadAttribute s, bool
InheritHandle, int CreationFlags, IntPtr Environment, string
CurrentDirector y, ref StartupInfo StartupInfo, out ProcessInformat ion
ProcessInformat ion);

[DllImport("adva pi32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private extern static bool DuplicateTokenE x(IntPtr Token, uint
DesiredAccess, ref SecurityAttribu tes ThreadAttribute s, int TokenType, int
ImpersonationLe vel, out IntPtr DupedToken);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
static extern bool GetExitCodeProc ess(IntPtr Process, out uint ExitCode);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private static extern Int32 WaitForSingleOb ject(IntPtr Handle, Int32 Wait);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private static extern bool CreatePipe(out IntPtr ReadPipe, out IntPtr
WritePipe, ref SecurityAttribu tes sa, int Size);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private static extern bool DuplicateHandle (IntPtr Process1, IntPtr Handle,
IntPtr Process2, out IntPtr DupedHandle, int Flags, bool Inheritable, int
Options);

[DllImport("kern el32.dll",Entry Point="ReadFile ",CharSet=CharS et.Unicode,SetL astError=true,C allingConventio n=CallingConven tion.StdCall),S uppressUnmanage dCodeSecurity]
private static extern bool ReadPipe(IntPtr Pipe, out StringBuilder Sb, int
Size, out int BytesRead, IntPtr Overlapped);

[DllImport("kern el32.dll",SetLa stError=true,Ca llingConvention =CallingConvent ion.StdCall),Su ppressUnmanaged CodeSecurity]
private static extern IntPtr GetCurrentProce ss();
}

Jul 24 '06 #3
Thanks for your reply and the further information.

yes, I've noticed that accessing the output and err buffer of the new
process through PINVOKE is a hard work. I'll perform some further research
on this and will update you as soon as I get any new result. In addition,
I've also sent the problem with the managed Process class to our internal
technical group to inform them of this issue.
Thanks for your understanding!

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead
This posting is provided "AS IS" with no warranties, and confers no rights.

Jul 25 '06 #4
Thanks Steven any help will be MUCH APPRECIATED :-)

"Steven Cheng[MSFT]" wrote:
Thanks for your reply and the further information.

yes, I've noticed that accessing the output and err buffer of the new
process through PINVOKE is a hard work. I'll perform some further research
on this and will update you as soon as I get any new result. In addition,
I've also sent the problem with the managed Process class to our internal
technical group to inform them of this issue.
Thanks for your understanding!

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead
This posting is provided "AS IS" with no warranties, and confers no rights.

Jul 25 '06 #5
Hi John,

Just post to inform some further results I've got, here is my current test
results:

1. I first tried redirecting the devenv.exe's output (build info) to a
file, and that can be done through the following means(i've tested):

i) Use the natural /out option of devenv.exe to redirect the output to a
file

ii) Use cmd.exe /c to execute the devenv build command and use the ">"
flag to redirect the cmd output to a file.

Therefore, if in-memory redirection is possible, this would be a workaround
you can consider(create a temp file for the output in your asp.net paeg and
read the content out).
2. I've tried use pinvoke to create NamedPipe and redirect process
stdout/stderr into the pipe and read it out. I did get the code to
work(test in console program first) and get the standard output when
testing through some simple command such as "cmd /?". However, when
executing the "devenv" command, I still can not get the stdout or stderr,
actually the whole creating process and write/read pipe code has been
executed, but there is nothing read out from the pipe. Therefore, I'm
wondering whether it is the devenv.exe itself which has hook the output and
manually print it out (when we execute it in command prompt), but can not
get it from stdout when we programmtically launch it.

I'll perform some further research on this, try creating a pure win32
program to create subprocess and read stdout/stderr, if still unable to get
it, I'm afraid it is the devenv.exe's limitation that make us fail to
programmtically get the output in-memory. I'll update you as soon as I get
the results.

Thanks for your understanding and patience!

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead
This posting is provided "AS IS" with no warranties, and confers no rights.
Jul 26 '06 #6
Hi Steven,

Sorry for the long pause but I've being busymaking several valiant but
unsuccessful attempts to resolve this.

I've tried to use the command line redirection tact but unfortunately that
seems to fail when the .sln file being built has projects in it that contain
pre/post build events that do things like md, copy, etc. The cmd.exe's that
the pre/post build events spawn all fail with exitcode 128.

Then i tried using ildasm to inspect what Prcocess.StartW ithCreateProces s
did and duplicate that as precisely as i could. This was not exactly
possible due to the non public scope (grrr) of a lot of the helper
classes/methods. I used ildasm on those too to get as close as possible.
After trying safehandles and intptrs i still wound up without success.

I also even tried going back to the original Process.Start based
implementation I started with but using the corprofiler hooks to catch the
prejit event on the Microsoft.Win32 .NatvieMethods. STARTUPINFO..ct or and munge
the bytecode to initialize the desktop field to "" (via
Marshall.Runtim e.InteropServic es.StringToCoTa skMemUni( string.Empty ))
instead of null. This still failed with the 142 so I think that even with the
field set to "" Process.Start( ) wont work because it boils down to
CreateProcessWi thLogon instead of CreateProcessAs User.

The short of it is I have invested a significant amount of time/effort into
this and still dont seem to be able to get what should be a simple common
thing to work.

I'm starting to feel brutally smack'd down by ASP.NET. Is there any chance
that someone on the ASP.NET team itself has already constructed a solution
for this shortcoming that they'd be willing to share with their customer base?

thanks again,
-john
"Steven Cheng[MSFT]" wrote:
Hello John,

How are you doing on this issue? Just finished some further tests against
the output redirection with Namepipe(both managed and unmanaged code).
After that, I found that the devenv process won't write output to the
standard output, at least the normal pipeline redirection does not work.
I've tried the following tests:

1. Use a pure .net managed application (console) to create subprocess run
the devenv and try getting standard output , but the output buffer is empty.

2. Use pure win32 unmanaged code to start a subprocess and try retrieving
the redirected output(from named pipe) , but get nothing.

3. Use pinvoke to repeat the test in #2 and same result.

Therefore, I think it is the devenv which has particular implementation on
its build result displaying, at least we can not get the output data
through standard output redirection. So far would you consider using a
temp file as the output storage in your ASP.NET web page(as I mentioned in
my last reply)?

BTW, I've included my c# pinvoke test program in this message you can try
performing some further test if you feel necessary(I can use it to capture
output for some normal commandline tools such as ping, cmd ...). If you
have problem access the attachment, please feel free to let me know, I can
send them to you through email.

#To run the program in console, the logon user need some certain privileges
, you can refer to the code in the following blog thread:

http://odetocode.com/Blogs/scott/comments/602.aspx

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead
This posting is provided "AS IS" with no warranties, and confers no rights
Aug 5 '06 #7
Hello John,

Thanks for your followup.

Yes, creating a process as specific user in ASP.NET environment is a hard
work here. As you can seen in my previous thread, I've tried some pinvoke
approach with the namepipe, however, the devenv seems a special case that
the output seems not available in the redirect pipe. I've attached my test
project in the previous message which use pinvoke code to run application
under specific user and read stdout and stderr. Normal application such
cmd, ping can successfully redirect the output into pipe, however, the
devenv seems handle the output particularly.

BTW, do you think using temp file as the redirect ouput doable in your
scenario? It is convenient to redirect the output to a file and read the
output content from that file.

In addition, I've discussed this question with some other ASPNET engineers,
currently for spawning a new process in ASP.NET under a specifci account,
the pinvoke(through createProcessAs user) is their recommended approach,
though it's a bit pity that it didn't work against the devenv application.

Anyway, as for this issue, I suggest you submit this request in our MSDN
product feedback center so that the dev team engineers and also hear more
from the community on such issue. And any comments and feedback from you is
really appreciated.

http://connect.microsoft.com/feedbac...spx?SiteID=210

Please feel free to let me know if there is anything else we can help.

Sincerely,

Steven Cheng

Microsoft MSDN Online Support Lead

Aug 8 '06 #8

This thread has been closed and replies have been disabled. Please start a new discussion.

Similar topics

1
2550
by: Gabriel K. | last post by:
With the command '/user username' I can connect to the access-db as the specified user. How can I set the user with an the AutoExec makro or in the VBA-Code? Thanks a lot
10
14422
by: Sorin Dolha [MCSD .NET] | last post by:
I would like to start a process from C# code as another user. The C# code is executed as the ASPNET user because it relies in a Web Page class, and I would like that the process will run as another user to gain the required rights for execution (the external process needs to create a mailbox in Exchange, so it needs to be run as an Exchange Full Administrator-powered user). For the moment, I have tries using the Start() static method of the...
3
1953
by: Jiho Han | last post by:
Should ASPNET user belong to the local Users group? I may have made some changes that affected my workstation setup and I am experiencing some unexpected behaviors. For example, I have my IIS set up with anonymous login and have ASP.NET running. My ASP.NET application then creates a log file and writes to it during its course. The only thing is that it should not be able to. My questions are below. Please correct any incorrect...
8
9469
by: Razak | last post by:
Hi, I have a class which basically do Impersonation in my web application. From MS KB sample:- ++++++++++++++++++++code starts Dim impersonationContext As System.Security.Principal.WindowsImpersonationContext Dim currentWindowsIdentity As System.Security.Principal.WindowsIdentity
8
17159
by: RTT | last post by:
i'm writing a windows form but codebased a iwant to run the code as a different user. like in a webapplication you can impersonate a user so the website does not run on the standard ASP.NET user. is it possible to do the same for a windows form and define a user codebased and run the code like that user is running the application.
0
871
by: John.NET | last post by:
Hi, I'm writing a web service where one method will launch another .NET program under a specified user's account. It launches fine as the NT AUTHORITY\NETWORK SERVICE user when I dont specify a username/password for the processStartInfo but I am having trouble getting it to work when I specify any other username/password pair. I immediately get "The application failed to initialize properly (0xC0000142). Has anyone ever gotten this to...
1
1884
by: andrewkl | last post by:
hi, I wrote a C program (runas.c) that runs a command as a different user on Solaris 8. The problem I'm having is that the new user's group memberships aren't going into effect. Take the following scenario: I login as "kirk". I need to run some commands as "spock". kirk and spock belong to these Unix groups: $ groups kirk spock
0
1353
by: sandeepkavade | last post by:
Hi i want to impersonate the process in SYSTEM, Logged in user and specified user. for Specified user i am giving the username and password and impersonation is working fine. The code is taken from http://msdn.microsoft.com/en-us/library/aa379608(VS.85).aspx The main process starts in SYSTEM account so by only using CreateProcess() api i can handle the case of SYSTEM user. But i am not finding any way to handle the logged in user case. How to...
24
3687
by: =?Utf-8?B?QnJpYW4gTmljaG9sc29u?= | last post by:
Hello, I'm trying to create an admin page that can run miscellaneous scripts for our IT department. Currently, I'm trying to create a script that can map a network drive for a user (e.g. a form where I can input \\path\folder, drive letter, and domain\user). Is this possible? If so, can someone point me in the right direction? Thank you, Brian Nicholson
0
9568
marktang
by: marktang | last post by:
ONU (Optical Network Unit) is one of the key components for providing high-speed Internet services. Its primary function is to act as an endpoint device located at the user's premises. However, people are often confused as to whether an ONU can Work As a Router. In this blog post, we’ll explore What is ONU, What Is Router, ONU & Router’s main usage, and What is the difference between ONU and Router. Let’s take a closer look ! Part I. Meaning of...
0
9404
by: Hystou | last post by:
Most computers default to English, but sometimes we require a different language, especially when relocating. Forgot to request a specific language before your computer shipped? No problem! You can effortlessly switch the default language on Windows 10 without reinstalling. I'll walk you through it. First, let's disable language synchronization. With a Microsoft account, language settings sync across devices. To prevent any complications,...
0
10164
Oralloy
by: Oralloy | last post by:
Hello folks, I am unable to find appropriate documentation on the type promotion of bit-fields when using the generalised comparison operator "<=>". The problem is that using the GNU compilers, it seems that the internal comparison operator "<=>" tries to promote arguments from unsigned to signed. This is as boiled down as I can make it. Here is my compilation command: g++-12 -std=c++20 -Wnarrowing bit_field.cpp Here is the code in...
0
9835
tracyyun
by: tracyyun | last post by:
Dear forum friends, With the development of smart home technology, a variety of wireless communication protocols have appeared on the market, such as Zigbee, Z-Wave, Wi-Fi, Bluetooth, etc. Each protocol has its own unique characteristics and advantages, but as a user who is planning to build a smart home system, I am a bit confused by the choice of these technologies. I'm particularly interested in Zigbee because I've heard it does some...
0
8833
agi2029
by: agi2029 | last post by:
Let's talk about the concept of autonomous AI software engineers and no-code agents. These AIs are designed to manage the entire lifecycle of a software development project—planning, coding, testing, and deployment—without human intervention. Imagine an AI that can take a project description, break it down, write the code, debug it, and then launch it, all on its own.... Now, this would greatly impact the work of software developers. The idea...
1
7379
isladogs
by: isladogs | last post by:
The next Access Europe User Group meeting will be on Wednesday 1 May 2024 starting at 18:00 UK time (6PM UTC+1) and finishing by 19:30 (7.30PM). In this session, we are pleased to welcome a new presenter, Adolph Dupré who will be discussing some powerful techniques for using class modules. He will explain when you may want to use classes instead of User Defined Types (UDT). For example, to manage the data in unbound forms. Adolph will...
0
5277
by: TSSRALBI | last post by:
Hello I'm a network technician in training and I need your help. I am currently learning how to create and manage the different types of VPNs and I have a question about LAN-to-LAN VPNs. The last exercise I practiced was to create a LAN-to-LAN VPN between two Pfsense firewalls, by using IPSEC protocols. I succeeded, with both firewalls in the same network. But I'm wondering if it's possible to do the same thing, with 2 Pfsense firewalls...
0
5423
by: adsilva | last post by:
A Windows Forms form does not have the event Unload, like VB6. What one acts like?
1
3926
by: 6302768590 | last post by:
Hai team i want code for transfer the data from one system to another through IP address by using C# our system has to for every 5mins then we have to update the data what the data is updated we have to send another system

By using Bytes.com and it's services, you agree to our Privacy Policy and Terms of Use.

To disable or enable advertisements and analytics tracking please visit the manage ads & tracking page.