olavhansen

I have a printer port monitor that runs fine on Windows XP. In order to avoid "session 0 isolation" on Vista, dialogs are opened from a rpcserver process running in session 1 which is instructed by the printer port monitor through a pipe, running in session 0. When the port monitor is run on Vista it fails to create the rpcserver process because openthreadtoken fails (invoked by the print spooler service) with error 1008 (ERROR_NO_TOKEN). The complete function for creating the process is attached. Why is this working on Windows XP and not Windows Vista

Olav

void CreateServer()

{

RPC_STATUS status;

unsigned short *szStringBinding = NULL;

TCHAR pszProtocolSequence[] = _T("ncacn_np");

TCHAR pszEndpoint[] = _T(\\pipe\\rpcserver);

status = RpcStringBindingCompose(

NULL,

reinterpret_cast<unsigned short*>(pszProtocolSequence),

NULL,

reinterpret_cast<unsigned short*>(pszEndpoint),

NULL,

&szStringBinding); // String binding output.

if (status)

{

::MessageBox(NULL,_T("rpcstringbindingcompose feilet"),_T("debug"),MB_OK);

}

status = RpcBindingFromStringBinding(

szStringBinding, // The string binding to validate.

&hRpc1Binding); // Put the result in the implicit binding handle defined in the IDL file.

if (status)

{

::MessageBox(NULL,_T("rpcbindingfromstringbinding feilet"),_T("debug"),MB_OK);

}

HANDLE hToken = NULL;

HANDLE hTokenDup = NULL;

LPVOID pEnvironment = NULL;

STARTUPINFO si;

PROCESS_INFORMATION pi;

memset(&si, 0, sizeof(STARTUPINFO));

memset(&pi, 0, sizeof(PROCESS_INFORMATION));

si.cb = sizeof(STARTUPINFO);

si.lpDesktop = _T("Winsta0\\Default");

// This function fails with error 1008 on Windows Vista, but succeeds on Windows XP

if (!OpenThreadToken(GetCurrentThread(), TOKEN_DUPLICATE, TRUE, &hToken))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("openthreadtoken failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

if (!DuplicateTokenEx(hToken,

TOKEN_IMPERSONATE|TOKEN_READ|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE,

NULL, SecurityImpersonation, TokenPrimary, &hTokenDup))

{

::MessageBox(NULL,_T("duplicatetokenex failed"),_T("debug"),MB_OK);

}

CloseHandle(hToken);

if (!CreateEnvironmentBlock(&pEnvironment, hTokenDup, FALSE))

{

::MessageBox(NULL,_T("createenvironment failed"),_T("debug"),MB_OK);

}

if (!CreateProcessAsUser(hTokenDup,

settings->GetRpcServer(),

NULL,

NULL,

NULL,

FALSE,

CREATE_NO_WINDOW,

pEnvironment,

NULL,

&si,

&pi))

{

::MessageBox(NULL,_T("createprocessasuser feilet"),_T("debug"),MB_OK);

}

DestroyEnvironmentBlock(pEnvironment);

CloseHandle(hTokenDup);

}



Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

Bruce N. Baker - MSFT

Note: The full error is: " An attempt was made to reference a token that does not exist."

Did you run this as an administrator

Just as a wild shot, try duplicatehander after getting the thread before doing an openthreadtoken.

The function cannot be used by one thread to create a handle that can be used by other threads to refer to the first thread. The handle is always interpreted as referring to the thread that is using it. A thread can create a "real" handle to itself that can be used by other threads, or inherited by other processes, by specifying the pseudo handle as the source handle in a call to the DuplicateHandle function.






Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

olavhansen

I am not logged in as an administrator.

However, the CreateServer() function is invoked inside my port monitor. The port monitor is again invoked by the print spooler service. On Windows XP the service "SPOOLSV.EXE" is running as the user "SYSTEM". On Windows Vista the service "Spooler" is running as the "Local System" account.

I tried to DuplicateHandle() of current thread as you suggested, see updated function. It works on Windows XP but on Windows Vista it still fails. However, now the error occurs a bit later, in the CreateProcessAsUser() function. GetLastError() returns 87 (ERROR_INVALID_PARAMETER) after calling CreateProcessAsUser().

I am trying to avoid the "session 0 isolation" issue on Windows Vista (not allowed to display any dialogs from a service which runs in session 0). In order to achieve that I have to create a process which runs as the current user (without knowing the username/password). The CreateProcessAsUser() function is invoked from a printer port monitor dll which is loaded by the print spooler service.

Olav

void CreateServer()

{

RPC_STATUS status;

unsigned short *szStringBinding = NULL;

TCHAR pszProtocolSequence[] = _T("ncacn_np");

TCHAR pszEndpoint[] = _T(\\pipe\\rpcserver);

status = RpcStringBindingCompose(

NULL,

reinterpret_cast<unsigned short*>(pszProtocolSequence),

NULL,

reinterpret_cast<unsigned short*>(pszEndpoint),

NULL,

&szStringBinding); // String binding output.

if (status)

{

::MessageBox(NULL,_T("rpcstringbindingcompose feilet"),_T("debug"),MB_OK);

}

status = RpcBindingFromStringBinding(

szStringBinding, // The string binding to validate.

&hRpc1Binding); // Put the result in the implicit binding handle defined in the IDL file.

if (status)

{

::MessageBox(NULL,_T("rpcbindingfromstringbinding feilet"),_T("debug"),MB_OK);

}

HANDLE hToken = NULL;

HANDLE hTokenDup = NULL;

LPVOID pEnvironment = NULL;

STARTUPINFO si;

PROCESS_INFORMATION pi;

memset(&si, 0, sizeof(STARTUPINFO));

memset(&pi, 0, sizeof(PROCESS_INFORMATION));

si.cb = sizeof(STARTUPINFO);

si.lpDesktop = _T("Winsta0\\Default");

HANDLE hThread = GetCurrentThread();

HANDLE hThreadDup = NULL;

if (!DuplicateHandle(GetCurrentProcess(), hThread, GetCurrentProcess(), &hThreadDup, 0, FALSE, DUPLICATE_SAME_ACCESS))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("duplicatehandle failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

if (!OpenThreadToken(hThreadDup, TOKEN_DUPLICATE, TRUE, &hToken))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("openthreadtoken failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

CloseHandle(hThreadDup);

if (!DuplicateTokenEx(hToken,

TOKEN_IMPERSONATE|TOKEN_READ|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE,

NULL, SecurityImpersonation, TokenPrimary, &hTokenDup))

{

::MessageBox(NULL,_T("duplicatetokenex failed"),_T("debug"),MB_OK);

}

CloseHandle(hToken);

if (!CreateEnvironmentBlock(&pEnvironment, hTokenDup, FALSE))

{

::MessageBox(NULL,_T("createenvironment failed"),_T("debug"),MB_OK);

}

// This function fails on Vista with error code 87, on Windows XP it is successfull

if (!CreateProcessAsUser(hTokenDup,

settings->GetRpcServer(),

NULL,

NULL,

NULL,

FALSE,

CREATE_NO_WINDOW,

pEnvironment,

NULL,

&si,

&pi))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("createprocessasuser failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

DestroyEnvironmentBlock(pEnvironment);

CloseHandle(hTokenDup);

}





Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

Aaron Margosis - MSFT

OpenThreadToken will fail if you are not impersonating. If you never call any impersonation APIs, then the process will have a token but individual threads will not. Access checks typically verify access against the current thread token, or the process token if there is no thread token. You should do the same: if OpenThreadToken fails with ERROR_NO_TOKEN, you should call OpenProcessToken(GetCurrentProcess(), ...) instead and use that token.

HTH





Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

olavhansen

Thanks. I followed your suggestion; OpenProcessToken succeeds on Vista (see updated function).

CreateProcessAsUser() still fails with error code 87 (ERROR_INVALID_PARAMETER) on Vista but succeeds on XP. I don't understand why it is failing on Vista with ERROR_INVALID_PARAMETER when it works on XP with the same parameters (settings->GetRpcServer() returns "c:\Program Files\test app\rpcserver.exe"). Isn't the CreateProcessAsUser() interface supposed to be unchanged between Vista and XP Is there a way of debugging this further

Olav

void CreateServer()

{

RPC_STATUS status;

unsigned short *szStringBinding = NULL;

TCHAR pszProtocolSequence[] = _T("ncacn_np");

TCHAR pszEndpoint[] = _T(\\pipe\\rpcserver);

status = RpcStringBindingCompose(

NULL,

reinterpret_cast<unsigned short*>(pszProtocolSequence),

NULL,

reinterpret_cast<unsigned short*>(pszEndpoint),

NULL,

&szStringBinding); // String binding output.

if (status)

{

::MessageBox(NULL,_T("rpcstringbindingcompose feilet"),_T("debug"),MB_OK);

}

status = RpcBindingFromStringBinding(

szStringBinding, // The string binding to validate.

&hRpc1Binding); // Put the result in the implicit binding handle defined in the IDL file.

if (status)

{

::MessageBox(NULL,_T("rpcbindingfromstringbinding feilet"),_T("debug"),MB_OK);

}

HANDLE hToken = NULL;

HANDLE hTokenDup = NULL;

LPVOID pEnvironment = NULL;

STARTUPINFO si;

PROCESS_INFORMATION pi;

memset(&si, 0, sizeof(STARTUPINFO));

memset(&pi, 0, sizeof(PROCESS_INFORMATION));

si.cb = sizeof(STARTUPINFO);

si.lpDesktop = _T("Winsta0\\Default");

if (!OpenThreadToken(GetCurrentThread(), TOKEN_QUERY|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE, TRUE, &hToken))

{

DWORD error = GetLastError();

if (error == ERROR_NO_TOKEN)

{

if (!OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE, &hToken))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("openprocesstoken failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

}

else

{

TCHAR tmp[500];

wsprintf(tmp,_T("openthreadtoken failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

}

if (!DuplicateTokenEx(hToken,

TOKEN_IMPERSONATE|TOKEN_READ|TOKEN_ASSIGN_PRIMARY|TOKEN_DUPLICATE,

NULL, SecurityImpersonation, TokenPrimary, &hTokenDup))

{

::MessageBox(NULL,_T("duplicatetokenex failed"),_T("debug"),MB_OK);

}

CloseHandle(hToken);

if (!CreateEnvironmentBlock(&pEnvironment, hTokenDup, FALSE))

{

::MessageBox(NULL,_T("createenvironment failed"),_T("debug"),MB_OK);

}

// This function fails on Vista with error code 87, on Windows XP it is successfull

if (!CreateProcessAsUser(hTokenDup,

settings->GetRpcServer(),

NULL,

NULL,

NULL,

FALSE,

CREATE_NO_WINDOW,

pEnvironment,

NULL,

&si,

&pi))

{

DWORD error = GetLastError();

TCHAR tmp[500];

wsprintf(tmp,_T("createprocessasuser failed %d"), error);

::MessageBox(NULL,tmp,_T("debug"),MB_OK);

}

DestroyEnvironmentBlock(pEnvironment);

CloseHandle(hTokenDup);

}





Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

Aaron Margosis - MSFT

Why are you calling CreateProcessAsUser instead of just CreateProcess And why aren't you just passing NULL for the environment parameter





Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

olavhansen

Thanks! Using NULL for the environment parameter made the example run on both Vista and XP.

The service (print spooler) is running in session 0 on Vista. If I call CreateProcess() I thought the new process would run in the same session as the parent. Since the session is 0, the new process will not be able to display my dialogs. Hence, I need to create the process with access to the desktop of the current user.

Olav




Re: Application Compatibility for Windows Vista openthreadtoken fails on Windows Vista but not on Windows XP

Aaron Margosis - MSFT

You are correct -- with CreateProcess the child runs with a token (and session) inherited from the parent. I think the disconnect for me is that your code doesn't show any impersonation happening. So this code is being executed by the service, in order to run a program on the interactive user's desktop You need to impersonate the client before getting the thread token -- perhaps that's what was missing.