C++/VB - CreateProcessAsUser fails with 233 (No process is on the other end of the pipe), XP

Asked By blackbor
14-Aug-07 01:24 PM
Hi.
I'm having a very strange behavior - CreateProcessAsUser fails with
error 233 when called from service while logon screen active. Service
tries to create a process when new console session connected, so when
it receives the SERVICE_CONTROL_SESSIONCHANGE notofication with the
WTS_CONSOLE_CONNECT, it obtains a user token (via WTSQueryUserToken or
OpenProcessToken/DuplicateTokenEx/SetTokenInformation - no sense). In
most cases it works well, but when it create a process after user
logoff (and now system in logon screen) it fails with error 233.
How to reproduce it:
1. Logon as console user (session 0)
2. Switch user (logon screen, session 0)
3. Logon another user (session 1) (CreateProcessAsUser succeeded)
4. Logoff another user (logon screen, session 2) (CreateProcessAsUser
fails, 233)

In my sample i'm trying to launch calc.exe, and in vista it works
well, problem appears only with the Windows XP.

Anyone else seen a similar issue, or know why this is happening? If it
helps, i can upload a sample to reproduce this behavior...

Thanks.

--
Andrew Solodovnikov
Windows XP
(1)
WTSQueryUserToken
(1)
Vista
(1)
PfWinStationQueryInformationW
(1)
PWinStationQueryInformationW
(1)
WinStationQueryInformationW
(1)
CreateRemoteSessionProcessW
(1)
CpauData.StartupInfo.lpDesktop
(1)
  Thomas Graefenhai replied...
30-Oct-07 11:32 AM

         
  ThomasGraefenhai replied...
30-Oct-07 11:35 AM
Hi there,

same problem for me, do you have any solution right now?

Greetings
(Sorry for my previous post)
  ThomasGraefenhai replied...
02-Nov-07 08:19 AM
Hi,

I've debugged a little bit with the kernel debugger, and have found the
problem: CreateProcessAsUser uses internally, when creating a process in an
other session, the function CreateRemoteProcessW from ADVAPI32.DLL. This
function opens a pipe with the name
\\.\Pipe\TerminalServer\SystemExecSrvr\%d where %d is the SessionID and
sending the request over to csrss.exe. And now the problem. After logging off
from a session other than 0 csrss.exe does not create this pipe or
CreateRemoteProcessW  is not able to read the pipe. CreateRemoteProcessW is
able to open the pipe and write to it. Is here anyone from MS listening and
can tell me what to do to get CreateProcessAsUser to work?

Thanks in advance
Thomas Graefenhain
  wjtpp replied...
30-Dec-07 05:55 AM
I disassemble advapi32.dll and simulate the not-exported function
CreateRemoteSessionProcessW, you can try and  perhaps resolve your
problem.

Known Issues:
1.Only WinXP can use the function, Vista MUST not use
2.Session 0 can't use the function, consider service always run in
session 0, this problem is not a problem.
3.When u failed with  2 (ERROR_FILE_NOT_FOUND) then u should wait a
moment and try again, I consider this is WinXP bug:),
4.When second parameter is TRUE, then hToken won't be used to create
new process. If u call CreateProcessAsUser and failed with 233, then u
should set second parameter to TRUE


typedef BOOLEAN (WINAPI* pWinStationQueryInformationW)(
IN   HANDLE hServer,
IN   ULONG LogonId,
IN   DWORD /*WINSTATIONINFOCLASS*/ WinStationInformationClass,
OUT  PVOID pWinStationInformation,
IN   ULONG WinStationInformationLength,
OUT  PULONG pReturnLength
);
DWORD MarshallString(LPCWSTR	pszText, LPVOID, DWORD	dwMaxSize,LPBYTE*
ppNextBuf, DWORD* pdwUsedBytes)
{
DWORD	dwOffset =3D *pdwUsedBytes;
if(!pszText)
return 0;
DWORD	dwLen =3D (wcslen(pszText)+1)*sizeof(WCHAR);
if(*pdwUsedBytes + dwLen> dwMaxSize)
return 0;
memmove(*ppNextBuf, pszText , dwLen);
*pdwUsedBytes +=3D dwLen;
*ppNextBuf +=3D dwLen;
return dwOffset;
}

typedef struct _CPAU_PARAM{
DWORD	cbSize;
DWORD	dwProcessId;
BOOL	bUseDefaultToken;
HANDLE	hToken;
LPWSTR	lpApplicationName;
LPWSTR	lpCommandLine;
SECURITY_ATTRIBUTES	ProcessAttributes;
SECURITY_ATTRIBUTES ThreadAttributes;
BOOL bInheritHandles;
DWORD dwCreationFlags;
LPVOID lpEnvironment;
LPWSTR lpCurrentDirectory;
STARTUPINFOW StartupInfo;
PROCESS_INFORMATION	ProcessInformation;
}CPAU_PARAM;

typedef struct _CPAU_RET_PARAM{
DWORD	cbSize;
BOOL	bRetValue;
DWORD	dwLastErr;
PROCESS_INFORMATION	ProcInfo;
}CPAU_RET_PARAM;

BOOL CreateRemoteSessionProcessW(
IN DWORD	dwSessionId,
IN BOOL		bUseDefaultToken,
IN HANDLE	hToken,
IN LPCWSTR	lpApplicationName,
IN LPWSTR	lpCommandLine,
IN LPSECURITY_ATTRIBUTES lpProcessAttributes,
IN LPSECURITY_ATTRIBUTES lpThreadAttributes,
IN BOOL bInheritHandles,
IN DWORD dwCreationFlags,
IN LPVOID lpEnvironment,
IN LPCWSTR lpCurrentDirectory,
IN LPSTARTUPINFOW lpStartupInfo,
OUT LPPROCESS_INFORMATION lpProcessInformation)
{
WCHAR		szWinStaPath[MAX_PATH];
BOOL		bGetNPName=3DFALSE;
WCHAR		szNamedPipeName[MAX_PATH]=3DL"";
DWORD		dwNameLen;
HINSTANCE	hInstWinSta;
HANDLE		hNamedPipe;
LPVOID		pData=3DNULL;
BOOL		bRet =3D FALSE;
DWORD		cbReadBytes,cbWriteBytes;
DWORD		dwEnvLen =3D 0;
union{
CPAU_PARAM	cpauData;
BYTE		bDump[0x2000];
};
CPAU_RET_PARAM	cpauRetData;
DWORD			dwUsedBytes =3D sizeof(cpauData);
LPBYTE			pBuffer =3D (LPBYTE)(&cpauData+1);
GetSystemDirectoryW(szWinStaPath, MAX_PATH);
lstrcatW(szWinStaPath,L"\\winsta.dll");
hInstWinSta =3D LoadLibrary(szWinStaPath);

if(hInstWinSta)
{
pWinStationQueryInformationW
pfWinStationQueryInformationW=3D(pWinStationQueryInformationW)GetProcAddress=
(hInstWinSta,
if(pfWinStationQueryInformationW)
{
bGetNPName =3D pfWinStationQueryInformationW(0, dwSessionId, 0x21,
szNamedPipeName, sizeof(szNamedPipeName), &dwNameLen);
}
FreeLibrary(hInstWinSta);
}
if(!bGetNPName || szNamedPipeName[0] =3D=3D '\0')
{
swprintf(szNamedPipeName, L"\\\\.\\Pipe\\TerminalServer\
\SystemExecSrvr\\%d", dwSessionId);
}

do{
hNamedPipe =3D CreateFile(szNamedPipeName, GENERIC_READ|GENERIC_WRITE,
0, NULL, OPEN_EXISTING, 0, 0);
if(hNamedPipe =3D=3D INVALID_HANDLE_VALUE)
{
if(GetLastError() =3D=3D ERROR_PIPE_BUSY)
{
if(!WaitNamedPipe(szNamedPipeName, 30000))
return FALSE;
}
else
{
return FALSE;
}
}
}while(hNamedPipe =3D=3D INVALID_HANDLE_VALUE);


memset(&cpauData, 0, sizeof(cpauData));
cpauData.bInheritHandles	=3D bInheritHandles;
cpauData.bUseDefaultToken	=3D bUseDefaultToken;
cpauData.dwCreationFlags	=3D dwCreationFlags;
cpauData.dwProcessId		=3D GetCurrentProcessId();
cpauData.hToken				=3D hToken;
cpauData.lpApplicationName	=3D
(LPWSTR)MarshallString(lpApplicationName, &cpauData, sizeof(bDump),
&pBuffer, &dwUsedBytes);
cpauData.lpCommandLine		=3D (LPWSTR)MarshallString(lpCommandLine,
&cpauData, sizeof(bDump), &pBuffer, &dwUsedBytes);
cpauData.StartupInfo		=3D *lpStartupInfo;
cpauData.StartupInfo.lpDesktop	=3D
(LPWSTR)MarshallString(cpauData.StartupInfo.lpDesktop, &cpauData,
sizeof(bDump), &pBuffer, &dwUsedBytes);
cpauData.StartupInfo.lpTitle	=3D
(LPWSTR)MarshallString(cpauData.StartupInfo.lpTitle, &cpauData,
sizeof(bDump), &pBuffer, &dwUsedBytes);

if(lpEnvironment)
{
if(dwCreationFlags & CREATE_UNICODE_ENVIRONMENT)
{
while((dwEnvLen+dwUsedBytes <=3D sizeof(bDump)))
{
if(((LPWSTR)lpEnvironment)[dwEnvLen/2]=3D=3D'\0' &&
((LPWSTR)lpEnvironment)[dwEnvLen/2+1] =3D=3D '\0')
{
dwEnvLen+=3D2*sizeof(WCHAR);
break;
}
dwEnvLen+=3Dsizeof(WCHAR);
}
}
else
{
while(dwEnvLen+dwUsedBytes <=3D sizeof(bDump))
{
if(((LPSTR)lpEnvironment)[dwEnvLen]=3D=3D'\0' && ((LPSTR)lpEnvironment)
[dwEnvLen+1]=3D=3D'\0')
{
dwEnvLen+=3D2;
break;
}
dwEnvLen++;
}
}
if(dwEnvLen+dwUsedBytes <=3D sizeof(bDump))
{
memmove(pBuffer, lpEnvironment, dwEnvLen);
cpauData.lpEnvironment =3D (LPVOID)dwUsedBytes;
pBuffer +=3D dwEnvLen;
dwUsedBytes +=3D dwEnvLen;
}
else
{
cpauData.lpEnvironment =3D NULL;
}
}
else
{
cpauData.lpEnvironment	=3D NULL;
}
cpauData.cbSize	 =3D dwUsedBytes;

if(WriteFile(hNamedPipe, &cpauData, cpauData.cbSize, &cbWriteBytes,
NULL) &&
ReadFile(hNamedPipe, & cpauRetData, sizeof(cpauRetData),
&cbReadBytes, NULL))
{
bRet =3D cpauRetData.bRetValue;
if(bRet)
{
*lpProcessInformation =3D cpauRetData.ProcInfo;
}
else
SetLastError(cpauRetData.dwLastErr);
}
else
bRet =3D FALSE;

CloseHandle(hNamedPipe);
return bRet;
}


On 11=D4=C22=C8=D5, =CF=C2=CE=E78=CA=B119=B7=D6, Thomas Graefenhain
n
off
s
d
  sm gm replied...
30-Jul-08 06:09 AM
I have the same problem (Can not launch application in winlogon desktop when user logoff). Do you have any solutions or ideas to deal with it, and could you kind enough to share with me? Thank you
Create New Account
help
CreateProcessAsUser and Windows Vista trouble C++ / VB I run under SYSTEM account the code posted below. My goal is run an executable in a specific user context. With Windows XP works fine but with Vista the executable doesn't run. anyone can help me? Thanks Dim WTSUserName As String = Marshal.PtrToStringAnsi(ppBuffer) If WTSUserName = Utente Then Dim gotToken As Boolean = WTSQueryUserToken(sessionID, token) Dim pSecurityAttributes As SECURITY_ATTRIBUTES pSecurityAttributes.bInheritHandle = True pSecurityAttributes.Length = Marshal.SizeOf(pSecurityAttributes) pSecurityAttributes For End If Next End Sub VB WinAPI Discussions CLASS.WTSUserName (1) TYPE.TokenPrimary (1) Windows XP (1) Marshal.PtrToStringAnsi (1) Windows Vista (1) WTSQueryUserToken (1) PSecurityAttributes.lpSecurityDescriptor (1) Marshal.SizeOf (1) You seem to be using dotnet. Quote from
How can I get the name of the interactivly logged on user from within a Windows NT service? Please, don't tell me to use GetUserName. When called from within an to get the interactive logged on user's name, right? Win32 Networks Discussions WTSGetActiveConsoleSessionId (1) Windows XP (1) Windows Server (1) Windows Vista (1) WTSQueryUserToken (1) LsaGetLogonSessionData (1) WTSCloseServer (1) WTSOpenServer (1) Hi, There can be many users logged on essence there is no such thing as a single user that is logged on to Windows, and to know which particular user is logged on you would need that particular user pipes, you can then impersonate the client token and call the API GetUserName(). Additinally, on Windows XP / 2k / 2003 server you can also use the following functions to retrieve the user
starts, but exits immediately. Any suggestions? Thanks. Win32 Kernel Discussions System.Diagnostics.Process.GetProcessById (1) Windows XP (1) System.Runtime.InteropServices (1) Marshal.GetLastWin32Error (1) Windows Server 2003 (1) System.Diagnostics.Process (1) WTSQueryUserToken (1) CreateProcessWithLogonW (1) Dude, what os are you running? What Kind of Process is it Latest Open-Source Projects: http: / / entwicklung.junetz.de - -- -- -- -- -- -- -- -- -- -- -- for exits what os are you running?: Windows XP Media Center (must be compatible with vista, however). What Kind of Process is it?: At first, the program I was trying to start was a windows forms app I made, but after seeing that it wasn't working I tried it target program is intended to interact with the desktop. More specifically is enumerates the desktop windows and sends the data to my service through a named pipe. Please show how you
an administrative account C++ / VB Hi, I am logged in as an Administrator on a windows xp's Telnet server. An user is currently logged on the machine, and from the telnet changes. Thanks for you help, and have a nice day! Win32 Kernel Discussions WTSGetActiveConsoleSessionId (1) Windows Server 2003 (1) WTSQueryUserToken (1) XP (1) CreateProcessAsUser (1) SystemParametersInfo (1) OpenProcessToken (1) OpenProcess (1) Hello Philou66, What you want to the superusr sample that shipped with the Platform SDK samples up to and including the Windows Server 2003 SP1 Platform SDK. - - Stefan You can determine which of the logged in users is currently the most active user. Look at WTSEnumerateSessions(), WTSGetActiveConsoleSessionId(), WTSQuerySessionInformation() and WTSQueryUserToken(). In fact, I image WTSQueryUserToken() would return the type of token you are looking for. But if you want to
How can I get my service to display windows in specific sessions? C++ / VB Hi, I need my system service (running as SYSTEM, isolated in session #0) to be able to display windows (cusom windows forms) in the specific user sessions, and possibly even multiple such windows simultaneously. I'm aware of all the reasons why creating UI by services isn't seeking practical advice on how to achieve this. I see various relevant APIs to manage "windows stations", "desktops" or particular, it looks like the best I could achieve is, to have all possible? Thanks, Krzys http: / / www.cs.cornell.edu / ~krzys / Win32 GDI Discussions WTSGetActiveConsoleSessionId (1) Windows XP (1) WTSQueryUserToken (1) WTSCloseServer (1) WTSOpenServer (1) RegSaveKeyEx (1) RegOpenKeyEx (1) SetThreadDesktop (1) Hi, You can create