| [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single)]
public partial class RunApp : ServiceBase, IRunApp
{
ServiceHost WcfHost;
IPermission admins;
public string[] Arguments;
bool IRunApp.CreateProcess(string FileName, string Arguments,
string CurrentDir, string DesktopName, bool UseServiceAccount,
out string ErrorText)
{
admins.Demand();
var SessId = WTSGetActiveConsoleSessionId();
WriteEventLog(string.Format("SessId = {0}", SessId));
int R;
IntPtr pBuf = new IntPtr();
Int32 bufLen;
if (!WTSQuerySessionInformation(
IntPtr.Zero, SessId, WTSConnectState, out pBuf, out bufLen))
{
R = Marshal.GetLastWin32Error();
ErrorText = string.Format(
"Query session information failed({0}: {1}",
R, GetErrorMessage(R));
return false;
}
WTS_CONNECTSTATE_CLASS state =
(WTS_CONNECTSTATE_CLASS)Marshal.ReadInt32(pBuf);
WTSFreeMemory(pBuf);
if (state != WTS_CONNECTSTATE_CLASS.WTSActive)
{
ErrorText =
string.Format("Console session is inactive. Current state = {0}", state);
return false;
}
R = RunInteractiveProcess(
SessId, FileName, Arguments, DesktopName, UseServiceAccount);
if (R != 0)
{
ErrorText = string.Format(
"RunInteractiveProcess failed({0}): {1}", R, GetErrorMessage(R));
return false;
}
ErrorText = "";
return true;
}
public RunApp()
{
InitializeComponent();
EventLog.Source = this.ServiceName;
}
public void AddUsers(NetPeerTcpBinding binding)
{
}
protected override void OnStart(string[] args)
{
var id = new SecurityIdentifier(
WellKnownSidType.BuiltinAdministratorsSid, null);
var ntId = id.Translate(typeof(NTAccount));
admins = new PrincipalPermission(null, ntId.ToString());
WcfHost = new ServiceHost(this);
//var binding = new NetNamedPipeBinding(NetNamedPipeSecurityMode.Transport);
var binding = new NetNamedPipeBinding();
//binding.Security.Transport.ProtectionLevel =
//System.Net.Security.ProtectionLevel.EncryptAndSign;
var endPoint = WcfHost.AddServiceEndpoint(
typeof(IRunApp), binding, "net.pipe://localhost/RunAppService");
WcfHost.Open();
}
protected override void OnStop()
{
WcfHost.Close();
admins = null;
}
private void Execute()
{
}
[StructLayout(LayoutKind.Sequential)]
struct STARTUPINFO
{
public Int32 cb;
public String lpReserved;
public String lpDesktop;
public String lpTitle;
public UInt32 dwX;
public UInt32 dwY;
public UInt32 dwXSize;
public UInt32 dwYSize;
public UInt32 dwXCountChars;
public UInt32 dwYCountChars;
public UInt32 dwFillAttribute;
public UInt32 dwFlags;
public short wShowWindow;
public short cbReserved2;
public IntPtr lpReserved2;
public IntPtr hStdInput;
public IntPtr hStdOutput;
public IntPtr hStdError;
}
[StructLayout(LayoutKind.Sequential)]
struct PROCESS_INFORMATION
{
public IntPtr hProcess;
public IntPtr hThread;
public UInt32 dwProcessId;
public UInt32 dwThreadId;
}
const UInt32 WTSConnectState = 8;
enum WTS_CONNECTSTATE_CLASS
{
WTSActive,
WTSConnected,
WTSConnectQuery,
WTSShadow,
WTSDisconnected,
WTSIdle,
WTSListen,
WTSReset,
WTSDown,
WTSInit
}
[DllImport("kernel32.dll")]
public static extern int FormatMessage(
int Flags, IntPtr Source, int MessageID, int LanguageID,
StringBuilder Buffer, int Size, IntPtr Args);
public static string GetErrorMessage(int ErrorCode)
{
var buf = new StringBuilder(256);
int len = FormatMessage(0x1200, IntPtr.Zero,
ErrorCode, 0, buf, buf.Capacity, IntPtr.Zero);
if (len <= 0) return "";
int k = buf.Length - 1;
for (; k > 0; k--)
{
char u = buf[k];
if (u > ' ' && u != '.') break;
}
buf.Length = k + 1;
buf.Append('.');
return buf.ToString();
}
[DllImport("kernel32.dll", SetLastError = true)]
static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
public static extern Int32 WTSGetActiveConsoleSessionId();
[DllImport("Wtsapi32.dll", SetLastError = true)]
static extern bool WTSQueryUserToken(Int32 SessionId, ref IntPtr hToken);
[DllImport("Wtsapi32.dll", SetLastError = true)]
static extern bool WTSQuerySessionInformation(
IntPtr hServer, Int32 SessionId, UInt32 WTSInfoClass,
out IntPtr ppBuffer, out Int32 BytesReturned);
[DllImport("Wtsapi32.dll")]
static extern void WTSFreeMemory(IntPtr pBuf);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool CreateProcessAsUser(
IntPtr hToken, String lpApplicationName, String lpCommandLine,
IntPtr lpProcessAttributes, IntPtr lpThreadAttributes,
bool bInheritHandle, UInt32 dwCreationFlags, IntPtr lpEnvironment,
String lpCurrentDirectory, ref STARTUPINFO lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[DllImport("kernel32.dll")]
static extern IntPtr GetCurrentProcess();
[DllImport("advapi32", SetLastError = true)]
static extern bool OpenProcessToken(
IntPtr ProcessHandle, Int32 DesiredAccess, ref IntPtr TokenHandle);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(
ref IntPtr lpEnvironment, IntPtr hToken, Boolean bInherit);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool DestroyEnvironmentBlock(IntPtr lpEnvironment);
[DllImport("advapi32.dll", SetLastError = true)]
static extern bool SetTokenInformation(
IntPtr TokenHandle, UInt32 TokenInformationClass,
ref Int32 TokenInformation, Int32 TokenInformationLength);
[Conditional("LOG_ON")]
private void WriteEventLog(string s) { EventLog.WriteEntry(s); }
private int RunInteractiveProcess(
Int32 SessId, string FileName, string Args, string Desktop, bool AsSystem)
{
WriteEventLog("Enter");
var userToken = IntPtr.Zero; ;
var Environment = IntPtr.Zero;
try
{
int result;
if (AsSystem)
{
if (!OpenProcessToken(GetCurrentProcess(), 0x2000000, ref userToken))
return Marshal.GetLastWin32Error();
if (!SetTokenInformation(userToken, 12, ref SessId, Marshal.SizeOf(SessId)))
return Marshal.GetLastWin32Error();
}
else
{
if (!WTSQueryUserToken(SessId, ref userToken))
{
result = Marshal.GetLastWin32Error();
WriteEventLog(string.Format("QueryToken = {0}", result));
return result;
}
if (!CreateEnvironmentBlock(ref Environment, userToken, false))
return Marshal.GetLastWin32Error();
WriteEventLog("Environment created");
}
var SI = new STARTUPINFO();
SI.cb = Marshal.SizeOf(SI);
SI.lpDesktop = Desktop;
UInt32 ctorFlags = 0;
if (Environment != IntPtr.Zero) ctorFlags |= 0x400;
var PI = new PROCESS_INFORMATION();
WriteEventLog("Before create process");
if (CreateProcessAsUser(userToken,
FileName, Args, IntPtr.Zero, IntPtr.Zero, false,
ctorFlags, Environment, null, ref SI, out PI))
{
CloseHandle(PI.hProcess);
CloseHandle(PI.hThread);
}
else
return Marshal.GetLastWin32Error();
}
finally
{
WriteEventLog("Finally");
if (userToken != IntPtr.Zero) CloseHandle(userToken);
if (Environment != IntPtr.Zero) DestroyEnvironmentBlock(Environment);
}
WriteEventLog("Leave - Success");
return 0;
}
}
|