Hello, I wrote a windows service that is supposed to start an interactive GUI app. I realize a service will not readily do this so I've pieced together the code below to bypass that. However, the call to CreateProcessAsUser always returns a 1314 error: 'A required privilege is not held by the client.'
I realize from the doc's that the calling process must have SE_TCB_NAME privilaege to assign new privileges to the new process and I have done that in a method further below.
So I'm not sure why this is not launching the app. To keep things simple, I'm running notepad.exe from a cmd console, I'm just running this code as its own app so there's no service on top to muddle things up. Also I'm running it locally to make things simpler, but still that error keeps popping up. Also I'm on XP.
Would someone that has had experience with this please tell me what's wrong? Thanks in advance!!
public static void Main(string[] args)
{
IntPtr tokenHandle = new IntPtr(0);
IntPtr dupeTokenHandle = new IntPtr(0);
try
{
string userName, domainName;
//USE YOUR LOGIN INFO HERE
domainName = "mydomain";
userName = "user";
pwd="mypass";
tokenHandle = IntPtr.Zero;
dupeTokenHandle = IntPtr.Zero;
bool returnValue = LogonUser(userName, domainName, pwd,
LOGON32_LOGON_INTERACTIVE, LOGON32_PROVIDER_DEFAULT,
ref tokenHandle);
if(false == returnValue)
{
int ret = Marshal.GetLastWin32Error();
Console.WriteLine("LogonUser failed with error code : {0}", ret);
int errorCode = 0x5;
throw new System.ComponentModel.Win32Exception(errorCode);
}
SECURITY_ATTRIBUTES pSec = new SECURITY_ATTRIBUTES();
SECURITY_ATTRIBUTES tSec = new SECURITY_ATTRIBUTES();
pSec.nLength = Marshal.SizeOf(pSec);
tSec.nLength = Marshal.SizeOf(tSec);
bool retVal = DuplicateTokenEx(tokenHandle, (uint)TokenAccessLevels.AllAccess, ref pSec,
SECURITY_IMPERSONATION_LEVEL.SecurityIdentificatio n, TOKEN_TYPE.TokenPrimary,
out dupeTokenHandle);
if(false == retVal)
{
CloseHandle(tokenHandle);
Console.WriteLine("Exception thrown in trying to duplicate token.");
return;
}
WindowsIdentity newId = new WindowsIdentity(dupeTokenHandle);
WindowsImpersonationContext impersonatedUser = newId.Impersonate();
PROFILEINFO aPI = new PROFILEINFO();
aPI.dwSize = 32;
aPI.lpUserName = WindowsIdentity.GetCurrent().Name;
bool retLoadProfile = LoadUserProfile(newId.Token, ref aPI);
StringBuilder CommandLine = new StringBuilder(@"cmd /c C:\windows\system32\notepad.exe");
const uint NORMAL_PRIORITY_CLASS = 0x0020;
PROCESS_INFORMATION pInfo = new PROCESS_INFORMATION();
STARTUPINFO sInfo = new STARTUPINFO();
IntPtr aToken=newId.Token;
SetPrivs(ref aToken);
sInfo.wShowWindow = 5;
sInfo.lpTitle = "Hello!";
sInfo.lpDesktop="winsta0\\default";
uint dwCreationFlags = NORMAL_PRIORITY_CLASS| CREATE_NEW_CONSOLE;
IntPtr pEnv = IntPtr.Zero;
if(CreateEnvironmentBlock(out pEnv, dupeTokenHandle, true))
{
dwCreationFlags |= CREATE_UNICODE_ENVIRONMENT;
}
else
{
pEnv = IntPtr.Zero;
}
bool retCreateProcess = CreateProcessAsUser(newId.Token,
null,
CommandLine,
ref pSec,
ref tSec,
false,
NORMAL_PRIORITY_CLASS,
pEnv,
null,
ref sInfo,
out pInfo);
int err = Marshal.GetLastWin32Error();
Console.WriteLine("CreateProcess="+retCreateProces s.ToString()+". With error:"+ err.ToString());
// Check the identity.
Console.WriteLine("After impersonation: " + WindowsIdentity.GetCurrent().Name);
Console.ReadKey();
// Stop impersonating the user.
impersonatedUser.Undo();
// Free the tokens.
if(tokenHandle != IntPtr.Zero)
CloseHandle(tokenHandle);
if(dupeTokenHandle != IntPtr.Zero)
CloseHandle(dupeTokenHandle);
}
catch(Exception ex)
{
Console.WriteLine("Exception occurred. " + ex.Message);
}
}
}
In this method as an experiment I tried setting all privileges to see if perhaps I had been missing one but generally I will be setting TCB(if that's the right one to set.)
You'll note that I'm setting the Current Process Privilage to TCB because the Doc's say that that needs to be done.
private static bool SetPrivs(ref IntPtr theToken)
{
const int SE_PRIVILEGE_ENABLED = 0x0002;
List<string> aPrivs = new List<string>();
aPrivs.Add(SE_CREATE_TOKEN_NAME);
aPrivs.Add(SE_ASSIGNPRIMARYTOKEN_NAME);
aPrivs.Add(SE_LOCK_MEMORY_NAME);
aPrivs.Add(SE_INCREASE_QUOTA_NAME);
aPrivs.Add(SE_UNSOLICITED_INPUT_NAME);
aPrivs.Add(SE_MACHINE_ACCOUNT_NAME);
aPrivs.Add(SE_TCB_NAME);
aPrivs.Add(SE_SECURITY_NAME);
aPrivs.Add(SE_TAKE_OWNERSHIP_NAME);
aPrivs.Add(SE_LOAD_DRIVER_NAME);
aPrivs.Add(SE_SYSTEM_PROFILE_NAME);
aPrivs.Add(SE_SYSTEMTIME_NAME);
aPrivs.Add(SE_PROF_SINGLE_PROCESS_NAME);
aPrivs.Add(SE_INC_BASE_PRIORITY_NAME);
aPrivs.Add(SE_CREATE_PAGEFILE_NAME);
aPrivs.Add(SE_CREATE_PERMANENT_NAME);
aPrivs.Add(SE_BACKUP_NAME);
aPrivs.Add(SE_RESTORE_NAME);
aPrivs.Add(SE_SHUTDOWN_NAME);
aPrivs.Add(SE_DEBUG_NAME);
aPrivs.Add(SE_AUDIT_NAME);
aPrivs.Add(SE_SYSTEM_ENVIRONMENT_NAME);
aPrivs.Add(SE_CHANGE_NOTIFY_NAME);
aPrivs.Add(SE_REMOTE_SHUTDOWN_NAME);
aPrivs.Add(SE_UNDOCK_NAME);
aPrivs.Add(SE_SYNC_AGENT_NAME);
aPrivs.Add(SE_ENABLE_DELEGATION_NAME);
aPrivs.Add(SE_MANAGE_VOLUME_NAME);
aPrivs.Add(SE_IMPERSONATE_NAME);
aPrivs.Add(SE_CREATE_GLOBAL_NAME);
SetCurrProcPriv(SE_TCB_NAME);
foreach(string aPriv in aPrivs)
{
TOKEN_PRIVILEGES aTP = new TOKEN_PRIVILEGES();
LUID luid = new LUID();
aTP.PrivilegeCount = 1;
aTP.Privileges = new int[3];
aTP.Privileges[2] = SE_PRIVILEGE_ENABLED;
aTP.Privileges[1] = luid.HighPart;
aTP.Privileges[0] = luid.LowPart;
try
{
LookupPrivilegeValue(IntPtr.Zero, aPriv, ref luid);
bool isSuccess=AdjustTokenPrivileges(theToken, false, ref aTP, Marshal.SizeOf(aTP), IntPtr.Zero, IntPtr.Zero);
if(!isSuccess)
return false;
else
return true;
}
catch (Exception e)
{
Console.WriteLine(e.Message);
Console.ReadKey();
}
}
return false;
}
private static IntPtr SetCurrProcPriv(string thePrivilegeName)
{
IntPtr hToken =new IntPtr();
bool isSuccess=false;
LUID luid = new LUID();
IntPtr aCurrProc = GetCurrentProcess();
TOKEN_PRIVILEGES aTP=new TOKEN_PRIVILEGES();
STARTUPINFO si=new STARTUPINFO();
si.cb = (int)Marshal.SizeOf(si);
isSuccess = OpenProcessToken(aCurrProc,
TOKEN_QUERY | TOKEN_ADJUST_PRIVILEGES |
TOKEN_ADJUST_SESSIONID |TOKEN_ADJUST_DEFAULT |
TOKEN_ASSIGN_PRIMARY | TOKEN_DUPLICATE, out hToken);
if(!isSuccess)
Console.WriteLine("Error OpenProcessToken " + Marshal.GetLastWin32Error().ToString());
isSuccess = LookupPrivilegeValue(IntPtr.Zero, thePrivilegeName, ref luid);
if(!isSuccess)
Console.WriteLine("Error OpenProcessToken " + Marshal.GetLastWin32Error().ToString());
aTP.PrivilegeCount = 1;
aTP.Privileges = new int[3];
aTP.Privileges[0] = luid.LowPart;
aTP.Privileges[1] = luid.HighPart;
aTP.Privileges[2] = SE_PRIVILEGE_ENABLED;
isSuccess = AdjustTokenPrivileges(hToken, false, ref aTP, Marshal.SizeOf(aTP), IntPtr.Zero, (IntPtr)Marshal.SizeOf(aTP));
if(!isSuccess)
return IntPtr.Zero;
else
return hToken;
}