KTS_HOWTO: Start a program on the currently logged in users desktop.


Few people had asked how to run a program on the user desktop from within KTS session.
I used to answer that it's not possible, actually I wasn't totally right you can start a program on the user desktop, kinda.

OK, first the problem in details (to whoever is interested).
KTS sessions are started on separate "hidden" windows station and desktop. This means that every process started from within KTS session by default will run on these "hidden" winsta and desktop with no access to the "input" desktop (or the user desktop).

The obvious solution is to tell a program to not use the KTS desktop but instead attach itself to the "user" desktop. But you have to consider one more thing, the windows access control model. Windows stations and desktops as almost any other object in the Windows world are securable object, this means that the system (based on the objects access control model) controls the access to these objects.

In a perfect world the user running the KTS session would have all the permissions necessery to change the the "user" winsta and desktop discretionary access control list and grant itself access to these winsta and desktop.

Luckily we are not living in perfect world, we are living in a dangerous place where users should run with the least possible permissions.
The result is that this approach sucks, and you can't start a program on the "user" desktop directly.

What you can do instead is to ask(or force) the logged in user to grant you access to "his" desktop.

How to start a program on the user desktop

1) Get the ondesk.exe program

2) Ask the logged in user to run "ondesk.exe allow", if you are evel enough you can set this up to start automatically upon login.
The "ondesk.exe allow" command will strip any securities applied over the "user" winsta nad desktop and replace them with null DACL.

A null DACL grants full access to any user that requests it; normal security checking is not performed with respect to the object.
Null DACL is a HUGE SECURITY RISK - Use At Your Own Risk!


3) Once the security is stripped from the "user" winsta and desktop, you can run "ondesk.exe <program name here>" from within KTS session and your program will run on the "user" desktop.
ex:
ondesk.exe notepad.exe

Note:
Although the program runs on the user desktop it runs under the account of the logged KTS user.
In short this means that if the computer admin logs through KTS and runs "ondesk.exe explorer.exe" the user will have full access to the computer through the "explorer.exe" as it will run with admin rights.

Finally, one more time - Use At Your Own Risk!

ondesk.exe source, use for whatever you like at your own risk:



/**********************************************************
* I take no responsibility for what you or others might do
* with this knowledge.
***********************************************************/
#include <windows.h>
#include <stdio.h>
#include <Aclapi.h>

#pragma comment(lib,"Advapi32")
#pragma comment(lib,"User32")

static bool AllowWinstaAndDesktop( )
{

HWINSTA hWinsta;
HDESK hDesk;

hWinsta = OpenWindowStationA( "winsta0", TRUE, GENERIC_ALL );
if( hWinsta==NULL )
{
printf( "OpenWindowStation( ):err %u", GetLastError() );
return( false );
}

if( SetSecurityInfo( hWinsta, SE_WINDOW_OBJECT
, DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION
, NULL, NULL, NULL, NULL )!=ERROR_SUCCESS )
{
printf( "SetSecurityInfo( ):err %u", GetLastError() );
return( false );
}

if( !SetProcessWindowStation( hWinsta ) )
{
printf( "SetProcessWindowStation( ):err %u", GetLastError() );
return( false );
}

hDesk = OpenDesktopA( "default", 0,TRUE, GENERIC_ALL );
if( !hDesk )
{
printf( "OpenDesktop( ):err %u", GetLastError() );
return( false );
}

if( SetSecurityInfo( hDesk, SE_WINDOW_OBJECT
, DACL_SECURITY_INFORMATION|PROTECTED_DACL_SECURITY_INFORMATION
, NULL, NULL, NULL, NULL )!=ERROR_SUCCESS )
{
printf( "SetSecurityInfo( ):err %u", GetLastError() );
return( false );
}

if( !SetThreadDesktop( hDesk ) )
{
printf( "SetThreadDesktop( ):err %u", GetLastError() );
return( false );
}

return( true );
}

static bool SetWinstaAndDesktop( )
{

HWINSTA hWinsta;
HDESK hDesk;


hWinsta = OpenWindowStationA( "winsta0", TRUE, GENERIC_ALL );
if( hWinsta==NULL )
{
printf( "OpenWindowStation( ):err %u", GetLastError() );
return( false );
}

if( !SetProcessWindowStation( hWinsta ) )
{
printf( "SetProcessWindowStation( ):err %u", GetLastError() );
return( false );
}


hDesk = OpenDesktopA( "default", 0,TRUE, GENERIC_ALL );
if( !hDesk )
{
printf( "OpenDesktop( ):err %u", GetLastError() );
return( false );
}

if( !SetThreadDesktop( hDesk ) )
{
printf( "SetThreadDesktop( ):err %u", GetLastError() );
return( false );
}

return( true );
}

int main(int argc, char* argv[])
{

if( argc != 2 )
{
printf("ondesk.exe allow\n");
printf(" - or -\n");
printf("ondesk.exe [command line]");
return 2;
}

if( strcmp( argv[1], "allow" ) == 0 )
{
AllowWinstaAndDesktop();
return 0;
}

if( !SetWinstaAndDesktop() ) return 1;

STARTUPINFOA si;
SECURITY_ATTRIBUTES sa;

ZeroMemory( &si, sizeof( si ) );
si.cb = sizeof( si );
si.lpDesktop = "winsta0\\default";
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = SW_SHOW;

ZeroMemory( &sa, sizeof( sa ));
sa.nLength = sizeof( sa );
sa.bInheritHandle = true;

BOOL ret = false;

PROCESS_INFORMATION pri = {0};

if( !CreateProcessA( NULL, ( char * )argv[1], &sa, NULL, TRUE
, NORMAL_PRIORITY_CLASS, NULL, NULL, &si, &pri ) )
{
printf( "CreateProcess( ):err %u", GetLastError() );
return 3;
}

return 0;
}


Tuesday, September 04, 2007


© 2002 - 2008 Kroum Grigorov
This page is powered by Blogger. Isn't yours?