From: mb on
Hi,
there was a message from "Reinhold Droege"/"Wed, 22 May 2002 03:11:35
-0700" with the topic "SwitchDesktop after first login" I tried to
answer, but that failed.

I know this message is rather old but it describes exactly my problem
but Jonathans answer is dissatisfying.
At first my situation:
I have an interactive service(Windows XPSP2), so its bound to WinSta0/
Default. Yes I known that this isn't a good idea for security reasons
and so one, but thats not the topic here.
Because this service needs to display some informations, even if no
user is logged on, I need to switch the visible desktop from Winlogon
(or whatever) to WinSta0/Default. It is currently also not possible to
"injecting" the informations directly on the "WinSta0/Winlogon" using
SetThreadDesktop() in the service (would that work?).
So what my service currently successful does is:
1. threadDesktop = ::GetThreadDesktop(::GetCurrentThreadId());
2. backupedDesktop = OpenInputDesktop()
3. SwitchDesktop(threadDesktop)
[... displaying informations ...]
4. SwitchDesktop( backupedDesktop )
The Desktop isn't switched if a user is "logged on" because then
ThreadDesktop==InputDesktop.
This works if there was never a login on the machine, but after that
initial login the SwitchDesktop() gives failed+ERROR_SUCCESS.

MSDN descripes the following remarks for SwitchDesktop():
"The SwitchDesktop function fails if the desktop belongs to an
invisible window station. SwitchDesktop also fails when called from a
process associated with a secured desktop, such as the WinLogon and
ScreenSaver desktops."

Jonathan sad the same:
>It explicitly fails when a process associated with the winlogon
> or screensaver desktop attempts to switch to another desktop viaSwitchDesktop().

But as an interactive services it is associated with "WinSta0/default"
and not with WinLogon or ScreenSaver so this couldn't be the problem.

If tried the following in the service
1. newDesktop = CreateDesktop("MyOwnDesktop");
2. backupedDesktop = OpenInputDesktop()
3. SwitchDesktop(newDesktop )
Result:
1# works in "logged off" before the first login
2# works every time a user is "logged on"
3# doesn't work after first login AND user isn't "logged on"


So what we have:
1. doc say that SwitchDesktop() works for applications not bound to
Winlogon/Screensaver-Desktops
2. SwitchDesktop() to Winlogon is possible before the first login and
fails after that
3. SwitchDesktop() to an fresh created desktop is possible before the
first login and if a user is "logged on", but fails after if no user
is "logged on" after the first login

1# Assuming the doc is also a specification for the behavior a
developer can rely on, the bug is that SwitchDesktop() isn't working
in the winlogon state "logged off" if there was an login before
2# If 2+3 is intended there is a bug in the doc and XP because it
isn't working as specified and it works before the first login or if a
user is "logged on"
If SwitchDesktop() should never work for a service for "security
reasons" this is also have a security hole because the system is
unsafe if winlogon state is "logged on" or if the state is "logged
off" without any login before.

Maybe someone could unearth the truth, I really have headache now...
Marco


On 23 Mai 2002, 22:35, j...(a)online.microsoft.com ("Jonathan Russ
[MS]") wrote:
> Hi Reinhold,
>
> Thanks for the complete description.
>
> SwitchDesktop() is designed to fail in this manner for security reasons.
> The system is actually not looking at the DACL on the desktops in this
> scenario. It explicitly fails when a process associated with the winlogon
> or screensaver desktop attempts to switch to another desktop viaSwitchDesktop(). (I honestly don't know why the call succeeds before a
> user logs on, but I wouldn't depend on this behavior... especially since
> you can't really control whether your service is started before or after a
> user logs on.)
>
> The ability to dynamically switch between winlogon and default is only
> allowed for GINAs. A GINA DLL would use one of the WlxSwitchDesktop*()
> functions.
>
> Regards,
> Jonathan
>
>
> > The plan is to have a service switch desktops and start a
> > program every time the logon screen is visible. It
> > succeeds before the first login, but fails on every
> > following attempt.
>
> > The service runs under the localsystem account. Before the
> > user logs in after the reboot it opens both the
> > desktops "default" and "winlogon" by issuing
>
> > OpenDesktop( "Default", DF_ALLOWOTHERACCOUNTHOOK, TRUE,
> > DESKTOP_SWITCHDESKTOP);
>
> > resp.
>
> > OpenDesktop( "Winlogon", DF_ALLOWOTHERACCOUNTHOOK, TRUE,
> > DESKTOP_SWITCHDESKTOP);
>
> > It then usesSwitchDesktop() to switch to the "default"
> > desktop, without changing any ACE entries of any desktop
> > involved. The desktop switch succeeds and the service
> > starts a program using CreateProcessAsUser using a user
> > account with administrative privileges. The new process
> > uses the default desktop just fine. On Program exit the
> > service switches back to the "winlogon" screen, again
> > without altering any security entries, and closes all of
> > its desktop handles. All of this succeeds before the
> > first user logs on.
>
> > After a user session the service fails, as explained, on
> > theSwitchDesktopcall. TheSwitchDesktopAPI function
> > returns "failure" as its return value but does not provide
> > any hint on GetLastError(). The documentation for
> >SwitchDesktopexplains that this API function only
> > supplies error values on some of its possible failure
> > exits.
>
> > "Access denied" is not among those cases that are reportet
> > by error value. Only invisible window stations or
> > nonexistant desktops are listed in MSDN for SwitchDesktops.
>
> > Therefore it could be that ACE entries cause an access
> > denied error. We can only guess. Does the default desktop
> > come with default ACE entries that only last until the
> > first user session is ended ? Does it carry a blank ACL
> > after that ? What ACEs do we have to set ?
>
> > Regards,
>
> > Reinhold