///////////////////////////////////////////////////////////////////////////////////////////////
//
// This File is Part of the CallButler Open Source PBX (http://www.codeplex.com/callbutler
//
// Copyright (c) 2005-2008, Jim Heising
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without modification,
// are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
//
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation and/or
// other materials provided with the distribution.
//
// * Neither the name of Jim Heising nor the names of its contributors may be
// used to endorse or promote products derived from this software without specific prior
// written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
// ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
// IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
// INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
// NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
///////////////////////////////////////////////////////////////////////////////////////////////
using System;
using System.Text;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Security.Permissions;
namespace WOSI.Utilities
{
public class ProcessUtils
{
[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;
}
// Declare the logon types as constants
const long LOGON32_LOGON_INTERACTIVE = 2;
const long LOGON32_LOGON_NETWORK = 3;
// Declare the logon providers as constants
const long LOGON32_PROVIDER_DEFAULT = 0;
const long LOGON32_PROVIDER_WINNT50 = 3;
const long LOGON32_PROVIDER_WINNT40 = 2;
const long LOGON32_PROVIDER_WINNT35 = 1;
[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);
[DllImport("advapi32.dll", EntryPoint = "LogonUser")]
private static extern bool LogonUser(string lpszUsername, string lpszDomain, string lpszPassword, int dwLogonType, int dwLogonProvider, ref IntPtr phToken);
[DllImport("userenv.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool LoadUserProfile(IntPtr hToken, ref ProfileInfo lpProfileInfo);
[DllImport("userenv.dll", SetLastError = true)]
static extern bool CreateEnvironmentBlock(out IntPtr lpEnvironment, IntPtr hToken, bool bInherit);
///
/// Profile Info
///
[StructLayout(LayoutKind.Sequential)]
public struct ProfileInfo
{
///
/// Specifies the size of the structure, in bytes.
///
public int dwSize;
///
/// This member can be one of the following flags: PI_NOUI or PI_APPLYPOLICY
///
public int dwFlags;
///
/// Pointer to the name of the user.
/// This member is used as the base name of the directory in which to store a new profile.
///
public string lpUserName;
///
/// Pointer to the roaming user profile path.
/// If the user does not have a roaming profile, this member can be NULL.
///
public string lpProfilePath;
///
/// Pointer to the default user profile path. This member can be NULL.
///
public string lpDefaultPath;
///
/// Pointer to the name of the validating domain controller, in NetBIOS format.
/// If this member is NULL, the Windows NT 4.0-style policy will not be applied.
///
public string lpServerName;
///
/// Pointer to the path of the Windows NT 4.0-style policy file. This member can be NULL.
///
public string lpPolicyPath;
///
/// Handle to the HKEY_CURRENT_USER registry key.
///
public IntPtr hProfile;
}
public static void CreateProcessAsUser(string username, string domain, string password, string commandLine)
{
IntPtr hToken = IntPtr.Zero;
IntPtr hDupedToken = IntPtr.Zero;
PROCESS_INFORMATION pi = new PROCESS_INFORMATION();
try
{
bool result = LogonUser(username, domain, password, (int)LOGON32_LOGON_INTERACTIVE, (int)LOGON32_PROVIDER_DEFAULT, ref hToken);
if (!result)
{
throw new ApplicationException("LogonUser failed");
}
SECURITY_ATTRIBUTES sa = new SECURITY_ATTRIBUTES();
sa.Length = Marshal.SizeOf(sa);
result = DuplicateTokenEx(
hToken,
GENERIC_ALL_ACCESS,
ref sa,
(int)SECURITY_IMPERSONATION_LEVEL.SecurityIdentification,
(int)TOKEN_TYPE.TokenPrimary,
ref hDupedToken
);
if (!result)
{
throw new ApplicationException("DuplicateTokenEx failed");
}
STARTUPINFO si = new STARTUPINFO();
si.cb = Marshal.SizeOf(si);
si.lpDesktop = "winsta0\\default";
ProfileInfo info = new ProfileInfo();
info.dwSize = Marshal.SizeOf(info);
info.lpUserName = username;
info.dwFlags = 1;
result = LoadUserProfile(hDupedToken, ref info);
if (!result)
{
int error = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(error);
}
IntPtr lpEnvironment;
result = CreateEnvironmentBlock(out lpEnvironment, hDupedToken, false);
if (!result)
{
int error = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(error);
}
result = CreateProcessAsUser(
hDupedToken,
null,
commandLine,
ref sa, ref sa,
false, 0x00000400, lpEnvironment,
null, ref si, ref pi
);
if (!result)
{
int error = Marshal.GetLastWin32Error();
throw new System.ComponentModel.Win32Exception(error);
}
}
finally
{
if (pi.hProcess != IntPtr.Zero)
CloseHandle(pi.hProcess);
if (pi.hThread != IntPtr.Zero)
CloseHandle(pi.hThread);
if (hDupedToken != IntPtr.Zero)
CloseHandle(hDupedToken);
}
}
}
}