Google Groups

Create Process as a different user


Willy Denoyette [MVP] May 29, 2002 2:15 PM
Posted in group: microsoft.public.dotnet.languages.csharp
Use PInvoke to call CreateProcessWithLogonW, this gives you the largest possibilities regarding environment block and profile
loading.

Other options using LogonUser and impersonate have are a number of issues:
    - No profile gets loaded,
    - only the system environment is loaded,
    - LogonUser caller needs to run in the TCB on W2K and lower
    - WindowsIdentity.Impersonate can only impersonate NETWORK style logon's NOT Interactive.

Here is a sample to get you started:

using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;

[assembly:SecurityPermissionAttribute(SecurityAction.RequestMinimum, UnmanagedCode=true)]
[SecurityPermission(SecurityAction.Demand,ControlPrincipal = true)]
public class Class1
{
 [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);

 [DllImport("kernel32")]
 static extern bool CloseHandle(IntPtr handle);

 [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;


 public static void Main(string[] args)
 {
  // Account to run as
  string _logonName = "someone";    // some user
  string _domain = "."; // local machine account
  string _password = "secret";
  StringBuilder sb = new StringBuilder();
  // command to execute
  sb.Append(@"devenv.exe");

  PROCESS_INFORMATION processInfo;
  STARTUPINFO startInfo = new STARTUPINFO();
  startInfo.cb = Marshal.SizeOf(startInfo);
  startInfo.lpTitle = "This is a Command 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 ...
   Console.WriteLine("Error: {0}", Marshal.GetLastWin32Error());
  else
   Console.WriteLine("ProcessID: {0}", processInfo.dwProcessId);
   }
}

Willy.

"Richard Webb" <richar...@jda.com> wrote in message news:#xU4f2zBCHA.1692@tkmsftngp05...
> Is there a way in C# to create a process as a different user?
>
>
>
>