Why CreateProcessAsUser fail on Vista?

Following is the code segment

if ( !CreateProcessAsUser(
hToken,// obtained from LogonUser
NULL,
( char * )pszCmd,
NULL,
NULL,
FALSE,
dwCreationFlag,
pEnv,//obtained from CreateEnvironmentBlock
NULL,
&si,
&pi
) )
{
//error;
}

GetLastError gives error code 183

[363 byte] By [Ganeshm] at [2007-12-22]
# 1

I have the same when using CreateProcessAsUser it failed with error 183
Did you solve the issue - where it come from ?

LucLebosse at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 2

Can I have a little context (or more code)?
Is that code executing from within a service?

Note that the token returned by LogonUser will not have have administrative privileges.

EricPerlin at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 3

BOOL StartSDProcess(CString csProcessPath, CString csCommandLineParam)
{
// WritePrivateProfileString("Info","10","start >> " + csProcessPath,CSystemInfo::m_strAppPath + "info.ini");
OutputDebugString("Start SD Process");
HANDLE hToken = NULL;
TOKEN_USER oUser[16];
DWORD u32Needed;
TCHAR sUserName[256], domainName[256];
DWORD userNameSize, domainNameSize;
SID_NAME_USE sidType;

ZeroMemory(oUser,sizeof(oUser));

OpenProcessToken(GetExplorerProcessHandle(), TOKEN_ALL_ACCESS, &hToken);

OutputDebugString("get exp token");
if(hToken == NULL)
return FALSE;

GetTokenInformation(hToken,TokenUser,&oUser[0], sizeof(oUser), &u32Needed);
userNameSize = sizeof (sUserName) - 1;
domainNameSize = sizeof (domainName) - 1;
LookupAccountSid (NULL, oUser[0].User.Sid, sUserName, &userNameSize, domainName, &domainNameSize, &sidType);
HDESK hdesk = NULL;
HWINSTA hwinsta = NULL, hwinstaSave = NULL;
PROCESS_INFORMATION pi;
PSID pSid = NULL;
STARTUPINFO si;
BOOL bResult = FALSE;
CString csErr;

OutputDebugString("GetProcessWindowStation");
// Save a handle to the caller's current window station.
if ( (hwinstaSave = GetProcessWindowStation() ) == NULL)
{
CloseHandle(hToken);
return FALSE;
}


// Get a handle to the interactive window station.
hwinsta = OpenWindowStation(
"winsta0", // the interactive window station
FALSE, // handle is not inheritable
READ_CONTROL | WRITE_DAC); // rights to read/write the DACL

OutputDebugString("OpenWindowStation");
if (hwinsta == NULL)
{
SetProcessWindowStation (hwinstaSave);
CloseHandle(hToken);
return FALSE;
}

// To get the correct default desktop, set the caller's
// window station to the interactive window station.

OutputDebugString("SetProcessWindowStation");
if (!SetProcessWindowStation(hwinsta))
{
SetProcessWindowStation (hwinstaSave);
CloseWindowStation(hwinsta);
CloseHandle(hToken);
return FALSE;
}

// Get a handle to the interactive desktop.

hdesk = OpenDesktop(
"default", // the interactive window station
0, // no interaction with other desktop processes
FALSE, // handle is not inheritable
READ_CONTROL | // request the rights to read and write the DACL
WRITE_DAC |
DESKTOP_WRITEOBJECTS |
DESKTOP_READOBJECTS);

OutputDebugString("OpenDesktop");
if (hdesk == NULL)
{
SetProcessWindowStation (hwinstaSave);
CloseWindowStation(hwinsta);
CloseHandle(hToken);
return FALSE;
}

OutputDebugString("SetProcessWindowStation");
// Restore the caller's window station.
if (!SetProcessWindowStation(hwinstaSave))
{

SetProcessWindowStation (hwinstaSave);
CloseWindowStation(hwinsta);
CloseDesktop(hdesk);
CloseHandle(hToken);
return FALSE;
}

// Impersonate client to ensure access to executable file.

OutputDebugString("ImpersonateLoggedOnUser");
if (! ImpersonateLoggedOnUser(hToken) )
{
SetProcessWindowStation (hwinstaSave);
CloseWindowStation(hwinsta);
CloseDesktop(hdesk);
CloseHandle(hToken);
return FALSE;
}

// Initialize the STARTUPINFO structure.
// Specify that the process runs in the interactive desktop.
ZeroMemory(&si, sizeof(STARTUPINFO));
si.cb= sizeof(STARTUPINFO);
si.lpDesktop = TEXT("winsta0\\default");

char csCmdParam[MAX_PATH];
DWORD dwSize = MAX_PATH;
strcpy(csCmdParam, csCommandLineParam);
OutputDebugString("CreateProcessAsUser");
bResult = CreateProcessAsUser(
hToken, // client's access token
csProcessPath, // file to execute
csCmdParam, // command line
NULL, // pointer to process SECURITY_ATTRIBUTES
NULL, // pointer to thread SECURITY_ATTRIBUTES
FALSE, // handles are not inheritable
NORMAL_PRIORITY_CLASS | CREATE_NEW_CONSOLE, // creation flags
NULL, // pointer to new environment block
NULL, // name of current directory
&si, // pointer to STARTUPINFO structure
&pi // receives information about new process
);
if(!bResult)
{
DWORD dw = GetLastError();
CString csStr;
csStr.Format("CreateProcessAsUser failed %d",dw);
OutputDebugString(csStr);
}

SetProcessWindowStation (hwinstaSave);
CloseWindowStation(hwinsta);
CloseDesktop(hdesk);
CloseHandle(hToken);
// End impersonation of client.

RevertToSelf();
return bResult ;
}

dipa at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 4

Dipa's solution will work if you want the currently logged on user to run the process. But if I understand your question that you want another user account other than the currently logged on user, hence why you call LogonUser, (maybe with a restricted account) then there are a list of things you need to do.

There are examples of how to do this on msdn, but mainly you have to do exactly what is stated above but from the stand point of assigning the token to the desktop and ImpersonateLoggedOnUser. But you should also Call LoadUserProfile, between LogonUser and ImpersonateLoggedOnUser, so that the user's profile is loaded and registry openned accordingly for that user's key. Also you need to load the Environment for that specific user by calling CreateEnvironmentBlock with the token of the LogonUser. Pass this into your CreateProcess and set the UNICODE flag in the dwCreationFlags.

Also user that is calling all these things must be an administrator or local system because they are the one's that have the granted rights to make such calls.

Hope this helps.

buffyardor at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 5

I have code that launches my application from a service that works on XP SP2. I have a call to NetUserGetInfo(NULL,username,4, (LPBYTE*) &userInfo4) and then LoadUserProfile.

My problem is that userInfo4.usri4_profile is NULL, as are all the fields except usri4_name.

Is there some other way that I can LoadUserProfile?

My full code is as follows:

DWORD sessionId = WTSGetActiveConsoleSessionId();
HANDLE hToken;
if (!WTSQueryUserToken(sessionId, &hToken))
{
// need Query Information permission
ReportError(_T("WTSQueryUserToken failed"));
return;
}

LPVOID environment = NULL;
if (!CreateEnvironmentBlock (&environment, hToken, FALSE))
{
ReportError(_T("Unable to CreateEnvironmentBlock."));
return;
}

LPTSTR username;
DWORD size = 0;
if (!WTSQuerySessionInformation (WTS_CURRENT_SERVER_HANDLE, sessionId, WTSUserName, &username, &size))
{
ReportError(_T("Unable to WTSQuerySessionInformation."));
return;
}

USER_INFO_4 userInfo4;
ZeroMemory (&userInfo4, sizeof (userInfo4));
if (NERR_Success != NetUserGetInfo (NULL, username, 4, (LPBYTE*) &userInfo4))
{
ReportError (_T("NetUserGetInfo failed"));
return;
}
else if (userInfo4.usri4_profile == NULL)
{
WriteToLog (_T("NetUserGetInfo failed to get usri4_profile"));
return;
}

PROFILEINFO profileInfo;
memset (&profileInfo, 0 , sizeof(profileInfo));
profileInfo.dwSize = sizeof(profileInfo);
profileInfo.lpUserName = username;
profileInfo.lpProfilePath = userInfo4.usri4_profile; // <- this is NULL under Vista (RTM)
if (!LoadUserProfile (hToken, &profileInfo))
{
ReportError(_T("Unable to LoadUserProfile."));
return;
}

WTSFreeMemory (username);

if ( !::CreateProcessAsUser(
hToken,
NULL, // program
controlCenterPath, // command line
NULL, // process handle not inheritable
NULL, // thread handle not inheritable
FALSE, // set handle inheritance to false
CREATE_UNICODE_ENVIRONMENT, // creation flags
environment, // environment block
NULL, // use parent's starting directory
&si, // address to startup info
&pi)) // address to process information
{
ReportError(_T("Unable to launch Control Center as user."));
WriteToLog(controlCenterPath);
}
UnloadUserProfile (hToken, profileInfo.hProfile);
if (environment != NULL)
DestroyEnvironmentBlock (environment);
NetApiBufferFree (&userInfo4);
CloseHandle (hToken);

JonathanCohen at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...
# 6

The profile of logged on users is already loaded by winlogon.
You don't need to do this yourself.

And by the way, if you had to, you'd want to call CreateEnvironmentBlock *after* you've loaded the profile...

EricPerlin at 2007-8-30 > top of Msdn Tech,Software Development for Windows Vista,Security for Applications in Windows Vista...

Software Development for Windows Vista

Site Classified