Here is a solution you can use in rare circumstances and with caution. Comments are more then welcomed.
Anytime someone approaches me with a design requiring the creation of a server side process – I flinch. Spinning up a process on the server is something to avoid. Having said that, I found it useful in a small Intranet applications (a build engine) to put a web service / ASP.NET interface in front of some command line CM tools. The interface is available to a small number of trusted individuals.
I wanted to run these processes with the identity of the client, but this poses a problem. The Process class in System.Diagnostics can start a new process, but the process always inherits the security context of the parent process. Even if the ASP.NET thread invoking the Start method is impersonating a client, the Process still starts with the ASP.NET worker process credentials.
Enter .NET 2.0, which includes the User, Domain, and Password properties on the ProcessStartInfo type. In .NET 2.0 you can start a process under a different set of credentials. The catch is having a password to give. I don't want the burden of managing passwords when there is a domain controller handy.
Having found no solution in the framework, the next step was to look into the Win32 API. There are four basic functions to start a process: CreateProcess, CreateProcessWithLogonW, CreateProcessAsUser, and CreateProcessWithTokenW. Since CreateProcess doesn’t allow an alternate identity, and one of 11 parameters to CreateProcessWithLogonW is a password, those are both out of the running.
The remaining two (CreateProcessWithTokenW and CreateProcessAsUser) both accept a token instead of a username and password, so these look promising. CreateProcessWithTokenW allows greater fine tuning of the logon type and creation flags, which I didn't need, so I focused in on CreateProcessAsUser.
CreateProcessAsUser accepts a user token as the first parameter. We can easily get a token representing the client we are impersonating using the WindowsIdentity class in .NET, but there still exists a problem. The token will be an impersonation token - which isn’t good enough for CreateProcessAsUser. However, the docs mention that you can use DuplicateTokenEx to convert an impersonation token into a primary token. The code at the end of this post demonstrates the incantations.
Note: The calling process needs SeAssignPrimaryTokenPrivilege and SeIncreaseQuotasPrivilege privileges, which the NETWORK SERVICE account has by default on Windows 2003.
Note: I’m not sure how far the ‘primary token’ yielded by DuplicateTokenEx can go. Could I effectively delegate without delegation enabled? I wouldn't think so. Must experiment. Anyone know?
Note: If you are thinking of using this to launch an interactive GUI application on the server – don’t. The process will start in a non-interactive window station and remain invisible but consuming memory.
private void CreateProcessAsUser()
{
IntPtr hToken = WindowsIdentity.GetCurrent().Token;
IntPtr hDupedToken = IntPtr.Zero;
ProcessUtility.PROCESS_INFORMATION pi = new ProcessUtility.PROCESS_INFORMATION();
try
{
ProcessUtility.SECURITY_ATTRIBUTES sa = new ProcessUtility.SECURITY_ATTRIBUTE();
sa.Length = Marshal.SizeOf(sa);
bool result = ProcessUtility.DuplicateTokenEx(
hToken,
ProcessUtility.GENERIC_ALL_ACCESS,
ref sa,
(int)ProcessUtility.SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)ProcessUtility.TOKEN_TYPE.TokenPrimary,
ref hDupedToken
);
if(!result)
{
throw new ApplicationException("DuplicateTokenEx failed");
}
ProcessUtility.STARTUPINFO si = new ProcessUtility.STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = String.Empty;
result = ProcessUtility.CreateProcessAsUser(
hDupedToken,
@"",
String.Empty,
ref sa, ref sa,
false, 0, IntPtr.Zero,
@"C:\", ref si, ref pi
);
if(!result)
{
int error = Marshal.GetLastWin32Error();
string message = String.Format("CreateProcessAsUser Error: {0}", error);
throw new ApplicationException(message);
}
}
finally
{
if(pi.hProcess != IntPtr.Zero)
ProcessUtility.CloseHandle(pi.hProcess);
if(pi.hThread != IntPtr.Zero)
ProcessUtility.CloseHandle(pi.hThread);
if(hDupedToken != IntPtr.Zero)
ProcessUtility.CloseHandle(hDupedToken);
}
}
ProcessUtility…
public class ProcessUtility
{
[StructLayout(LayoutKind.Sequential)]
public struct STARTUPINFO
{
public Int32 cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public Int32 dwX;
public Int32 dwY;
public Int32 dwXSize;
public Int32 dwXCountChars;
public Int32 dwYCountChars;
public Int32 dwFillAttribute;
public Int32 dwFlags;
public Int16 wShowWindow;
public Int16 cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
public struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public Int32 dwProcessID;
public Int32 dwThreadID;
}
[StructLayout(LayoutKind.Sequential)]
public struct SECURITY_ATTRIBUTES
{
public Int32 Length;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
}
public enum SECURITY_IMPERSONATION_LEVEL
{
SecurityAnonymous,
SecurityIdentification,
SecurityImpersonation,
SecurityDelegation
}
public enum TOKEN_TYPE
{
TokenPrimary = 1,
TokenImpersonation
}
public const int GENERIC_ALL_ACCESS = 0x10000000;
[
DllImport("kernel32.dll",
EntryPoint = "CloseHandle", SetLastError = true,
CharSet = CharSet.Auto, CallingConvention = CallingConvention.StdCall)
]
public static extern bool CloseHandle(IntPtr handle);
[
DllImport("advapi32.dll",
EntryPoint = "CreateProcessAsUser", SetLastError = true,
CharSet = CharSet.Ansi, CallingConvention = CallingConvention.StdCall)
]
public static extern bool
CreateProcessAsUser(IntPtr hToken, string lpApplicationName, string lpCommandLine,
ref SECURITY_ATTRIBUTES lpProcessAttributes, ref SECURITY_ATTRIBUTES lpThreadAttributes,
bool bInheritHandle, Int32 dwCreationFlags, IntPtr lpEnvrionment,
string lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
ref PROCESS_INFORMATION lpProcessInformation);
[
DllImport("advapi32.dll",
EntryPoint = "DuplicateTokenEx")
]
public static extern bool
DuplicateTokenEx(IntPtr hExistingToken, Int32 dwDesiredAccess,
ref SECURITY_ATTRIBUTES lpThreadAttributes,
Int32 ImpersonationLevel, Int32 dwTokenType,
ref IntPtr phNewToken);
}
Comments
<br>
<br>
<br>
<br>Here is the code snippet (in C++):
<br>
<br>SECURITY_ATTRIBUTES sa;
<br>sa.nLength = sizeof(sa);
<br>
<br>val = DuplicateTokenEx(existingTokenHandle, 0x10000000, &sa, SecurityIdentification, TokenPrimary, &userTokenHandle);
<br>
<br>This yields a 998 OS error. However, the following line doesn't:
<br>
<br>val = DuplicateTokenEx(existingTokenHandle, 0x10000000, NULL, SecurityIdentification, TokenPrimary, &userTokenHandle);
<br>
<br>I get a handle to a user token with the second call but it then fails on CreateProcessAsUser (because I don't have security attributes object to pass to it). So I assume that my problem is with the security attributes structure. Am I correct in assuming that DuplicateTokenEx populates the structure which can then be used by CreateProcessAsUser?
<br>
<br>Does that help?
<br>
<br>http://msdn.microsoft.com/library/default.asp?url=/library/en-us/dllproc/base/createprocessasuser.asp
<br>
<br>Also, I found this site. Looks promising, if I can get it to compile and run.
<br>
<br>http://win32.mvps.org/index.html
<br>
<br>I could probably get it into VB.NET but it might take me a little time. there are some converters available on the web that might be able to help out. Let me know if you can wait a week and I might be able to have something done over the weekend.
<br>
<br>Just thought you might want to know....
<br>Always returns with ERR_PRIVILEGE_NOTHELD
<br>Kindly help
<br>
<br>I've tried turning the lpEnvironment parameter into a string and passing a value in the format that the documentation seems to suggest - "var1=val1\0var2=val2\0\0" - and I tried putting [MarshalAs(UnmanagedType.LPStr)] on it as well. But nothing seems to work.
<br>
<br>Any suggestions?
<br>
<br>I have a horrible feeling I'm going to have to write a whole separate wrapper program which takes the args in question from the command line and then uses a regular Process.Start(). Then if I CreateProcessAsUser on *that* then everything should work. But it's pretty evil...
<br>
<br>I think you'll need to use CreateEnvironmentBlock from the win32 API.
<br>See: http://www.sayala.com/code.aspx?file=ProcessAsUser.cs
So, things like
WindowsIdentity.GetCurrent().Name
will return the name of the original process creator, which is the ASPNET user for an ASP.NET page.
Possible solution could be to store the current user in a private member before starting the new thread.
I decided to get rid of the complete thread thing, because in my case I just used a thread for spawning a new process and waiting for the process to end without blocking the main ASP.NET thread. But I just want to know, if the process is still running on refresh of the page, so I think I can ask the System.Diagnostics.Process class for that.
I'm trying to import some access databases into a SQL server using OPENDATASOURCE for linking the access database. Works all fine with doing that from ISQL with integrated security. After CreateProcessAsUser I get an error accessing the access database. I guess that it has to do with the fact, that CreateProcessAsUser doesn't load the user profile and maybe the TEMP environment isn't set.
I changed everything to serviced components. Now it works.
Have you figured out how to catch the output of a process spawned from CreateProcessAsUser in C# code? I've tried many things but am just not getting the job done. I can create the process and it does exactly what I want it to, but I just am not able to redirect the output. Here is what I've hacked at so far.
private void RunProcess(string commandLinePath)
{
try
{
IntPtr Token = new IntPtr(0);
IntPtr DupedToken = new IntPtr(0);
bool ret;
// Label2.Text+=WindowsIdentity.GetCurrent().Name.ToString();
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.bInheritHandle = true;
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)
Response.Write( "DuplicateTokenEx failed with " + Marshal.GetLastWin32Error() + "<br>");
else
Response.Write( "DuplicateTokenEx SUCCESS<br>" );
// 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;
IntPtr hOutRead = new IntPtr(0);
IntPtr hOutWrite = new IntPtr(0);
CreatePipe( ref hOutRead, ref hOutWrite, 0 );
Response.Write( hOutWrite.ToString() );
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "";
si.hStdOutput = hOutWrite;
si.hStdInput = hOutRead;
si.dwFlags = STARTF_USESTDHANDLES;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
ret = CreateProcessAsUser(DupedToken,null,commandLinePath, ref sa, ref sa, true, 0, (IntPtr)0, "c:\\", ref si, out pi);
if (ret == false)
Response.Write( "CreateProcessAsUser failed with " + Marshal.GetLastWin32Error() + "<br>" );
else
{
Response.Write( "CreateProcessAsUser SUCCESS. The child PID is" + pi.dwProcessId + "<br>" );
System.Diagnostics.Process p = System.Diagnostics.Process.GetProcessById( int.Parse( pi.dwProcessId.ToString() ) );
Response.Write( p.StartInfo.RedirectStandardOutput.ToString() );
//Response.Write( p.StandardOutput.ReadToEnd() );
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
CloseHandle(hOutRead);
CloseHandle(hOutWrite);
}
ret = CloseHandle(DupedToken);
if (ret == false)
Response.Write( Marshal.GetLastWin32Error() + "<br>");
else
Response.Write( "CloseHandle SUCCESS" + "<br>" );
}
catch( Exception err )
{
Response.Write( err.ToString() );
}
}
using System;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Reflection;
using System.Security.Principal;
using System.Text;
/// <summary>
/// UserSpecificProcess extends the standard Process object to /// create new processes under a different user than the calling parent process.
/// Also, the standard output of the child process redirected back to the parent process.
/// This is class is designed to operate inside an ASP.NET web application.
/// The assumption is that the calling thread is operating with an impersonated security token.
/// The this class will change the imperonated security token to a primary token, /// and call CreateProcessAsUser.
/// A System.Diagnostics.Process object will be returned with appropriate properties set.
/// To use this function, the following security priviliges need to be set for the ASPNET account /// using the local security policy MMC snap-in. CreateProcessAsUser requirement.
/// "Replace a process level
token"/SE_ASSIGNPRIMARYTOKEN_NAME/SeAssignPrimaryTokenPrivilege
/// "Adjust memory quotas for a
process"/SE_INCREASE_QUOTA_NAME/SeIncreaseQuotaPrivilege
///
/// This class was designed for .NET 1.1 for operating systems W2k an higher.
/// Any other features or platform support can be implemented by using the .NET reflector and /// investigating the Process class.
/// </summary>
public class UserSpecificProcess : Process {
[StructLayout(LayoutKind.Sequential)]
public class CreateProcessStartupInfo
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
public CreateProcessStartupInfo()
{
this.cb = Marshal.SizeOf(typeof (CreateProcessStartupInfo));
this.lpReserved = null;
this.lpDesktop = null;
this.lpTitle = null;
this.dwX = 0;
this.dwY = 0;
this.dwXSize = 0;
this.dwYSize = 0;
this.dwXCountChars = 0;
this.dwYCountChars = 0;
this.dwFillAttribute = 0;
this.dwFlags = 0;
this.wShowWindow = 0;
this.cbReserved2 = 0;
this.lpReserved2 = IntPtr.Zero;
this.hStdInput = IntPtr.Zero;
this.hStdOutput = IntPtr.Zero;
this.hStdError = IntPtr.Zero;
}
}
[StructLayout(LayoutKind.Sequential)]
public class CreateProcessProcessInformation
{
public IntPtr hProcess;
public IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
public CreateProcessProcessInformation()
{
this.hProcess = IntPtr.Zero;
this.hThread = IntPtr.Zero;
this.dwProcessId = 0;
this.dwThreadId = 0;
}
}
[StructLayout(LayoutKind.Sequential)]
public class SecurityAttributes
{
public int nLength;
public IntPtr lpSecurityDescriptor;
public bool bInheritHandle;
public SecurityAttributes()
{
this.nLength = Marshal.SizeOf(typeof (SecurityAttributes));
}
}
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true, ExactSpelling=true)]
public static extern bool CloseHandle(HandleRef handle);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool
CreateProcess([MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, StringBuilder lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, CreateProcessStartupInfo lpStartupInfo, CreateProcessProcessInformation lpProcessInformation);
[DllImport("advapi32.dll", CharSet=CharSet.Unicode, SetLastError=true )]
public static extern bool CreateProcessAsUserW(IntPtr token, [MarshalAs(UnmanagedType.LPTStr)] string lpApplicationName, [MarshalAs(UnmanagedType.LPTStr)] string lpCommandLine, SecurityAttributes lpProcessAttributes, SecurityAttributes lpThreadAttributes, bool bInheritHandles, int dwCreationFlags, IntPtr lpEnvironment, [MarshalAs(UnmanagedType.LPTStr)] string lpCurrentDirectory, CreateProcessStartupInfo lpStartupInfo, CreateProcessProcessInformation lpProcessInformation);
[DllImport("kernel32.dll", CharSet=CharSet.Ansi, SetLastError=true)]
public static extern IntPtr GetStdHandle(int whichHandle);
[DllImport("kernel32.dll", CharSet=CharSet.Auto)]
public static extern IntPtr CreateFile(string lpFileName, int dwDesiredAccess, int dwShareMode, SecurityAttributes lpSecurityAttributes, int dwCreationDisposition, int dwFlagsAndAttributes, HandleRef hTemplateFile);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern IntPtr CreateNamedPipe(string name, int openMode, int pipeMode, int maxInstances, int outBufSize, int inBufSize, int timeout, SecurityAttributes lpPipeAttributes);
[DllImport("kernel32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern int GetConsoleOutputCP();
[DllImport("advapi32.dll", CharSet=CharSet.Auto, SetLastError=true)]
public static extern bool DuplicateTokenEx(HandleRef hToken, int access, SecurityAttributes tokenAttributes, int impersonationLevel, int tokenType, ref IntPtr hNewToken);
// WinNT.h ACCESS TYPES
const int GENERIC_ALL = 0x10000000;
// WinNT.h enum SECURITY_IMPERSONATION_LEVEL
const int SECURITY_IMPERSONATION = 2;
// WinNT.h TOKEN TYPE
const int TOKEN_PRIMARY = 1;
// WinBase.h
const int STD_INPUT_HANDLE = -10;
const int STD_ERROR_HANDLE = -12;
// WinBase.h STARTUPINFO
const int STARTF_USESTDHANDLES = 0x100;
// Microsoft.Win23.NativeMethods
static IntPtr INVALID_HANDLE_VALUE = (IntPtr) (-1);
public static HandleRef NullHandleRef = new HandleRef(null, IntPtr.Zero);
/// <summary>
/// Starts the process with the security token of the calling thread.
/// If the security token has a token type of TokenImpersonation,
/// the token will be duplicated to a primary token before calling
/// CreateProcessAsUser.
/// </summary>
/// <param name="process">The process to start.</param>
public void StartAsUser()
{
StartAsUser(WindowsIdentity.GetCurrent().Token);
}
/// <summary>
/// Starts the process with the given security token.
/// If the security token has a token type of TokenImpersonation,
/// the token will be duplicated to a primary token before calling
/// CreateProcessAsUser.
/// </summary>
/// <param name="process"></param>
public void StartAsUser(IntPtr userToken)
{
if (StartInfo.UseShellExecute)
{
throw new InvalidOperationException("can't call this with shell execute");
}
// just assume that the securityToken is of TokenImpersonation and create a primary.
IntPtr primayUserToken = CreatePrimaryToken(userToken);
CreateProcessStartupInfo startupInfo = new CreateProcessStartupInfo();
CreateProcessProcessInformation processInformation = new CreateProcessProcessInformation();
IntPtr stdinHandle;
IntPtr stdoutReadHandle;
IntPtr stdoutWriteHandle = IntPtr.Zero;
IntPtr stderrHandle;
try
{
stdinHandle = GetStdHandle(STD_INPUT_HANDLE);
MyCreatePipe(out stdoutReadHandle, out stdoutWriteHandle, false);
stderrHandle = GetStdHandle(STD_ERROR_HANDLE);
//assign handles to startup info
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.hStdInput = stdinHandle;
startupInfo.hStdOutput = stdoutWriteHandle;
startupInfo.hStdError = stderrHandle;
string commandLine = GetCommandLine();
int creationFlags = 0;
IntPtr environment = IntPtr.Zero;
string workingDirectory = GetWorkingDirectory();
// create the process or fail trying.
if (!CreateProcessAsUserW(
primayUserToken,
null,
commandLine,
null,
null,
true,
creationFlags,
environment,
workingDirectory,
startupInfo,
processInformation))
{
throw new Win32Exception();
}
}
finally
{
// close thread handle
if (processInformation.hThread != INVALID_HANDLE_VALUE)
{
CloseHandle(new HandleRef(this, processInformation.hThread));
}
// close client stdout handle
CloseHandle(new HandleRef(this, stdoutWriteHandle));
}
// get reader for standard output from the child
Encoding encoding = Encoding.GetEncoding(GetConsoleOutputCP());
StreamReader standardOutput = new StreamReader(new FileStream(stdoutReadHandle, FileAccess.Read, true, 0x1000, true), encoding);
// set this on the object accordingly.
typeof(Process).InvokeMember("standardOutput",
BindingFlags.SetField | BindingFlags.NonPublic | BindingFlags.Instance,
null, this, new object[]{standardOutput});
// scream if a process wasn't started instead of returning false.
if (processInformation.hProcess == IntPtr.Zero)
{
throw new Exception("failed to create process");
}
// configure the properties of the Process object correctly
typeof(Process).InvokeMember("SetProcessHandle",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, this, new object[]{processInformation.hProcess});
typeof(Process).InvokeMember("SetProcessId",
BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, this, new object []{processInformation.dwProcessId});
}
/// <summary>
/// Creates a primayToken out of an existing token.
/// </summary>
/// <param name="userToken"></param>
private IntPtr CreatePrimaryToken(IntPtr userToken)
{
SecurityAttributes securityAttributes = new SecurityAttributes();
IntPtr primaryUserToken = IntPtr.Zero;
if (!DuplicateTokenEx(new HandleRef(this, userToken), GENERIC_ALL, securityAttributes, SECURITY_IMPERSONATION, TOKEN_PRIMARY, ref
primaryUserToken))
{
throw new Win32Exception();
}
return primaryUserToken;
}
/// <summary>
/// Gets the appropriate commandLine from the process.
/// </summary>
/// <param name="process"></param>
/// <returns></returns>
private string GetCommandLine()
{
StringBuilder builder1 = new StringBuilder();
string text1 = StartInfo.FileName.Trim();
string text2 = StartInfo.Arguments;
bool flag1 = text1.StartsWith("\"") && text1.EndsWith("\"");
if (!flag1)
{
builder1.Append("\"");
}
builder1.Append(text1);
if (!flag1)
{
builder1.Append("\"");
}
if ((text2 != null) && (text2.Length > 0))
{
builder1.Append(" ");
builder1.Append(text2);
}
return builder1.ToString();
}
/// <summary>
/// Gets the working directory or returns null if an empty string was found.
/// </summary>
/// <returns></returns>
private string GetWorkingDirectory()
{
return (StartInfo.WorkingDirectory != string.Empty) ?
StartInfo.WorkingDirectory : null;
}
/// <summary>
/// A clone of Process.CreatePipe. This is only implemented because reflection with
/// out parameters are a pain.
/// Note: This is only finished for w2k and higher machines.
/// </summary>
/// <param name="parentHandle"></param>
/// <param name="childHandle"></param>
/// <param name="parentInputs">Specifies whether the parent will be performing the writes.</param>
public static void MyCreatePipe(out IntPtr parentHandle, out IntPtr childHandle, bool parentInputs)
{
string pipename = @"\\.\pipe\Global\" + Guid.NewGuid().ToString();
SecurityAttributes attributes2 = new SecurityAttributes();
attributes2.bInheritHandle = false;
parentHandle = CreateNamedPipe(pipename, 0x40000003, 0, 0xff, 0x1000, 0x1000, 0, attributes2);
if (parentHandle == INVALID_HANDLE_VALUE)
{
throw new Win32Exception();
}
SecurityAttributes attributes3 = new SecurityAttributes();
attributes3.bInheritHandle = true;
int num1 = 0x40000000;
if (parentInputs)
{
num1 = -2147483648;
}
childHandle = CreateFile(pipename, num1, 3, attributes3, 3, 0x40000080, NullHandleRef);
if (childHandle == INVALID_HANDLE_VALUE)
{
throw new Win32Exception();
}
}
}
I'm sorry, I don't have an update on the issue.
Assembly assSystem = typeof(Process).Assembly;
Type oProcessManager = assSystem.GetType("System.Diagnostics.ProcessManager");
object oSafeProcessHandle = oProcessManager.InvokeMember("OpenProcess",
BindingFlags.InvokeMethod | BindingFlags.Public | BindingFlags.Static,
null, this, new object[] { processInformation.dwProcessId, 0x100000, false });
//then
typeof(Process).InvokeMember("SetProcessHandle", BindingFlags.InvokeMethod | BindingFlags.NonPublic | BindingFlags.Instance,
null, this, new object[] { oSafeProcessHandle });
Note : Am using win 7 OS
Please any can guide me how i can use 'CreateProcessAsUser' appi call
ErrorCreateProcessAsUser Error: 3
Can any one help...
Yeah me too, I have the same problem.
I need to run an app from a service, but it doesn't bring the app to the current logged user's screen. Even if it the same credentials used to run the service.
How to do that? Help me!
change the @"" in the parameter to @"C:\Windows\notepad.exe"