xref: /reactos/base/system/winlogon/wlx.c (revision bbccad0e)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Winlogon
4  * FILE:            base/system/winlogon/wlx.c
5  * PURPOSE:         Logon
6  * PROGRAMMERS:     Thomas Weidenmueller (w3seek@users.sourceforge.net)
7  *                  Ge van Geldorp (gvg@reactos.com)
8  *                  Herv� Poussineau (hpoussin@reactos.org)
9  */
10 
11 /* INCLUDES *****************************************************************/
12 
13 #include "winlogon.h"
14 
15 typedef struct _DIALOG_LIST_ENTRY
16 {
17     LIST_ENTRY Entry;
18     HWND hWnd;
19     DLGPROC DlgProc;
20     LPARAM lParam;
21 } DIALOG_LIST_ENTRY, *PDIALOG_LIST_ENTRY;
22 
23 /* GLOBALS ******************************************************************/
24 
25 //static UINT_PTR IdTimer;
26 static LIST_ENTRY DialogListHead;
27 
28 /* FUNCTIONS ****************************************************************/
29 
30 VOID
31 InitDialogListHead(VOID)
32 {
33     InitializeListHead(&DialogListHead);
34 }
35 
36 
37 static
38 PDIALOG_LIST_ENTRY
39 AddDialogListEntry(VOID)
40 {
41     PDIALOG_LIST_ENTRY ListEntry;
42 
43     ListEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIALOG_LIST_ENTRY));
44     if (ListEntry == NULL)
45         return NULL;
46 
47     TRACE("Add entry %p\n", ListEntry);
48 
49     InsertHeadList(&DialogListHead,
50                    &ListEntry->Entry);
51 
52     return ListEntry;
53 }
54 
55 
56 static
57 VOID
58 RemoveDialogListEntry(PDIALOG_LIST_ENTRY ListEntry)
59 {
60     TRACE("Remove entry %p\n", ListEntry);
61 
62     RemoveEntryList(&ListEntry->Entry);
63     RtlFreeHeap(RtlGetProcessHeap(), 0, ListEntry);
64 }
65 
66 
67 static
68 PDIALOG_LIST_ENTRY
69 GetDialogListEntry(HWND hwndDlg)
70 {
71     PDIALOG_LIST_ENTRY Current;
72     PLIST_ENTRY ListEntry;
73 
74     ListEntry = DialogListHead.Flink;
75     while (ListEntry != &DialogListHead)
76     {
77         Current = CONTAINING_RECORD(ListEntry,
78                                     DIALOG_LIST_ENTRY,
79                                     Entry);
80         if (Current->hWnd == hwndDlg)
81         {
82             TRACE("Found entry: %p\n", Current);
83             return Current;
84         }
85 
86         ListEntry = ListEntry->Flink;
87     }
88 
89     TRACE("Found no entry!\n");
90     return NULL;
91 }
92 
93 
94 VOID
95 CloseAllDialogWindows(VOID)
96 {
97     PDIALOG_LIST_ENTRY Current;
98     PLIST_ENTRY ListEntry;
99 
100     ListEntry = DialogListHead.Flink;
101     while (ListEntry != &DialogListHead)
102     {
103         Current = CONTAINING_RECORD(ListEntry,
104                                     DIALOG_LIST_ENTRY,
105                                     Entry);
106 
107         PostMessage(Current->hWnd, WLX_WM_SAS, 0, 0);
108 
109         ListEntry = ListEntry->Flink;
110     }
111 }
112 
113 
114 static
115 INT_PTR
116 CALLBACK
117 DefaultWlxWindowProc(
118     IN HWND hwndDlg,
119     IN UINT uMsg,
120     IN WPARAM wParam,
121     IN LPARAM lParam)
122 {
123     PDIALOG_LIST_ENTRY ListEntry;
124     INT_PTR ret;
125 
126     if (uMsg == WM_INITDIALOG)
127     {
128         ListEntry = (PDIALOG_LIST_ENTRY)lParam;
129 
130         TRACE("Set dialog handle: %p\n", hwndDlg);
131         ListEntry->hWnd = hwndDlg;
132         lParam = ListEntry->lParam;
133 //        SetTopTimeout(hWnd);
134     }
135     else
136     {
137         ListEntry = GetDialogListEntry(hwndDlg);
138         if (ListEntry == NULL)
139             return FALSE;
140     }
141 
142     if (uMsg == WLX_WM_SAS)
143     {
144         EndDialog(hwndDlg, WLX_DLG_SAS);
145         return 0;
146     }
147 
148     ret = ListEntry->DlgProc(hwndDlg, uMsg, wParam, lParam);
149 
150     return ret;
151 
152 /*
153     if (uMsg == WM_TIMER && (UINT_PTR)wParam == IdTimer)
154     {
155         EndDialog(hwndDlg, -1);
156         KillTimer(hwndDlg, IdTimer);
157         return TRUE;
158     }
159     else if (uMsg == WM_INITDIALOG)
160     {
161         IdTimer = SetTimer(hwndDlg, 0, WLSession->DialogTimeout * 1000, NULL);
162         return PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
163     }
164     else if (uMsg == WM_NCDESTROY)
165     {
166         BOOL ret;
167         ret = PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
168         PreviousWindowProc = NULL;
169         return ret;
170     }
171     else
172     {
173         return PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
174     }
175 */
176 }
177 
178 /*
179  * @implemented
180  */
181 VOID
182 WINAPI
183 WlxUseCtrlAltDel(
184     HANDLE hWlx)
185 {
186     ULONG_PTR OldValue;
187 
188     TRACE("WlxUseCtrlAltDel()\n");
189 
190     WlxSetOption(hWlx, WLX_OPTION_USE_CTRL_ALT_DEL, TRUE, &OldValue);
191 }
192 
193 /*
194  * @implemented
195  */
196 VOID
197 WINAPI
198 WlxSetContextPointer(
199     HANDLE hWlx,
200     PVOID pWlxContext)
201 {
202     ULONG_PTR OldValue;
203 
204     TRACE("WlxSetContextPointer(%p)\n", pWlxContext);
205 
206     WlxSetOption(hWlx, WLX_OPTION_CONTEXT_POINTER, (ULONG_PTR)pWlxContext, &OldValue);
207 }
208 
209 /*
210  * @implemented
211  */
212 VOID
213 WINAPI
214 WlxSasNotify(
215     HANDLE hWlx,
216     DWORD dwSasType)
217 {
218     PWLSESSION Session = (PWLSESSION)hWlx;
219 
220     TRACE("WlxSasNotify(0x%lx)\n", dwSasType);
221 
222     if (dwSasType == WLX_SAS_TYPE_CTRL_ALT_DEL || dwSasType > WLX_SAS_TYPE_MAX_MSFT_VALUE)
223         PostMessageW(Session->SASWindow, WLX_WM_SAS, dwSasType, 0);
224 }
225 
226 /*
227  * @implemented
228  */
229 BOOL
230 WINAPI
231 WlxSetTimeout(
232     HANDLE hWlx,
233     DWORD Timeout)
234 {
235     PWLSESSION Session = (PWLSESSION)hWlx;
236 
237     TRACE("WlxSetTimeout(%lu)\n", Timeout);
238 
239     Session->DialogTimeout = Timeout;
240     return TRUE;
241 }
242 
243 /*
244  * @unimplemented
245  */
246 int
247 WINAPI
248 WlxAssignShellProtection(
249     HANDLE hWlx,
250     HANDLE hToken,
251     HANDLE hProcess,
252     HANDLE hThread)
253 {
254     UNREFERENCED_PARAMETER(hWlx);
255     UNREFERENCED_PARAMETER(hToken);
256     UNREFERENCED_PARAMETER(hProcess);
257     UNREFERENCED_PARAMETER(hThread);
258 
259     UNIMPLEMENTED;
260     return 0;
261 }
262 
263 /*
264  * @implemented
265  */
266 int
267 WINAPI
268 WlxMessageBox(
269     HANDLE hWlx,
270     HWND hwndOwner,
271     LPWSTR lpszText,
272     LPWSTR lpszTitle,
273     UINT fuStyle)
274 {
275     UNREFERENCED_PARAMETER(hWlx);
276 
277     TRACE("WlxMessageBox()\n");
278     /* FIXME: Provide a custom window proc to be able to handle timeout */
279     return MessageBoxW(hwndOwner, lpszText, lpszTitle, fuStyle);
280 }
281 
282 /*
283  * @implemented
284  */
285 int
286 WINAPI
287 WlxDialogBox(
288     HANDLE hWlx,
289     HANDLE hInst,
290     LPWSTR lpszTemplate,
291     HWND hwndOwner,
292     DLGPROC dlgprc)
293 {
294     UNREFERENCED_PARAMETER(hWlx);
295 
296     TRACE("WlxDialogBox()\n");
297 
298     return (int)WlxDialogBoxParam(hWlx, hInst, lpszTemplate, hwndOwner, dlgprc, 0);
299 }
300 
301 /*
302  * @implemented
303  */
304 int
305 WINAPI
306 WlxDialogBoxParam(
307     HANDLE hWlx,
308     HANDLE hInst,
309     LPWSTR lpszTemplate,
310     HWND hwndOwner,
311     DLGPROC dlgprc,
312     LPARAM dwInitParam)
313 {
314     PDIALOG_LIST_ENTRY ListEntry;
315     int ret;
316 
317     UNREFERENCED_PARAMETER(hWlx);
318 
319     TRACE("WlxDialogBoxParam()\n");
320 
321     ListEntry = AddDialogListEntry();
322     if (ListEntry == NULL)
323         return -1;
324 
325     ListEntry->DlgProc = dlgprc;
326     ListEntry->lParam = dwInitParam;
327 
328     ret = (int)DialogBoxParamW(hInst, lpszTemplate, hwndOwner, DefaultWlxWindowProc, (LPARAM)ListEntry);
329 
330     RemoveDialogListEntry(ListEntry);
331 
332     return ret;
333 }
334 
335 /*
336  * @implemented
337  */
338 int
339 WINAPI
340 WlxDialogBoxIndirect(
341     HANDLE hWlx,
342     HANDLE hInst,
343     LPCDLGTEMPLATE hDialogTemplate,
344     HWND hwndOwner,
345     DLGPROC dlgprc)
346 {
347     UNREFERENCED_PARAMETER(hWlx);
348 
349     TRACE("WlxDialogBoxIndirect()\n");
350 
351     return (int)WlxDialogBoxIndirectParam(hWlx, hInst, hDialogTemplate, hwndOwner, dlgprc, 0);
352 }
353 
354 /*
355  * @implemented
356  */
357 int
358 WINAPI
359 WlxDialogBoxIndirectParam(
360     HANDLE hWlx,
361     HANDLE hInst,
362     LPCDLGTEMPLATE hDialogTemplate,
363     HWND hwndOwner,
364     DLGPROC dlgprc,
365     LPARAM dwInitParam)
366 {
367     PDIALOG_LIST_ENTRY ListEntry;
368     int ret;
369 
370     UNREFERENCED_PARAMETER(hWlx);
371 
372     TRACE("WlxDialogBoxIndirectParam()\n");
373 
374     ListEntry = AddDialogListEntry();
375     if (ListEntry == NULL)
376         return -1;
377 
378     ListEntry->DlgProc = dlgprc;
379     ListEntry->lParam = dwInitParam;
380 
381     ret = (int)DialogBoxIndirectParamW(hInst, hDialogTemplate, hwndOwner, DefaultWlxWindowProc, (LPARAM)ListEntry);
382 
383     RemoveDialogListEntry(ListEntry);
384 
385     return ret;
386 }
387 
388 /*
389  * @implemented
390  */
391 int
392 WINAPI
393 WlxSwitchDesktopToUser(
394     HANDLE hWlx)
395 {
396     PWLSESSION Session = (PWLSESSION)hWlx;
397 
398     TRACE("WlxSwitchDesktopToUser()\n");
399 
400     return (int)SwitchDesktop(Session->ApplicationDesktop);
401 }
402 
403 /*
404  * @implemented
405  */
406 int
407 WINAPI
408 WlxSwitchDesktopToWinlogon(
409     HANDLE hWlx)
410 {
411     PWLSESSION Session = (PWLSESSION)hWlx;
412 
413     TRACE("WlxSwitchDesktopToWinlogon()\n");
414 
415     return (int)SwitchDesktop(Session->WinlogonDesktop);
416 }
417 
418 /*
419  * @unimplemented
420  */
421 int
422 WINAPI
423 WlxChangePasswordNotify(
424     HANDLE hWlx,
425     PWLX_MPR_NOTIFY_INFO pMprInfo,
426     DWORD dwChangeInfo)
427 {
428     UNREFERENCED_PARAMETER(hWlx);
429     UNREFERENCED_PARAMETER(pMprInfo);
430     UNREFERENCED_PARAMETER(dwChangeInfo);
431 
432     UNIMPLEMENTED;
433     return 0;
434 }
435 
436 /*
437  * @unimplemented
438  */
439 BOOL
440 WINAPI
441 WlxGetSourceDesktop(
442     HANDLE hWlx,
443     PWLX_DESKTOP* ppDesktop)
444 {
445     UNREFERENCED_PARAMETER(hWlx);
446     UNREFERENCED_PARAMETER(ppDesktop);
447 
448     UNIMPLEMENTED;
449     return FALSE;
450 }
451 
452 /*
453  * @unimplemented
454  */
455 BOOL
456 WINAPI
457 WlxSetReturnDesktop(
458     HANDLE hWlx,
459     PWLX_DESKTOP pDesktop)
460 {
461     UNREFERENCED_PARAMETER(hWlx);
462     UNREFERENCED_PARAMETER(pDesktop);
463 
464     UNIMPLEMENTED;
465     return FALSE;
466 }
467 
468 /*
469  * @unimplemented
470  */
471 BOOL
472 WINAPI
473 WlxCreateUserDesktop(
474     HANDLE hWlx,
475     HANDLE hToken,
476     DWORD Flags,
477     PWSTR pszDesktopName,
478     PWLX_DESKTOP* ppDesktop)
479 {
480     UNREFERENCED_PARAMETER(hWlx);
481     UNREFERENCED_PARAMETER(hToken);
482     UNREFERENCED_PARAMETER(Flags);
483     UNREFERENCED_PARAMETER(pszDesktopName);
484     UNREFERENCED_PARAMETER(ppDesktop);
485 
486     UNIMPLEMENTED;
487     return FALSE;
488 }
489 
490 /*
491  * @unimplemented
492  */
493 int
494 WINAPI
495 WlxChangePasswordNotifyEx(
496     HANDLE hWlx,
497     PWLX_MPR_NOTIFY_INFO pMprInfo,
498     DWORD dwChangeInfo,
499     PWSTR ProviderName,
500     PVOID Reserved)
501 {
502     UNREFERENCED_PARAMETER(hWlx);
503     UNREFERENCED_PARAMETER(pMprInfo);
504     UNREFERENCED_PARAMETER(dwChangeInfo);
505     UNREFERENCED_PARAMETER(ProviderName);
506     UNREFERENCED_PARAMETER(Reserved);
507 
508     UNIMPLEMENTED;
509     return 0;
510 }
511 
512 /*
513  * @unimplemented
514  */
515 BOOL
516 WINAPI
517 WlxCloseUserDesktop(
518     HANDLE hWlx,
519     PWLX_DESKTOP pDesktop,
520     HANDLE hToken)
521 {
522     UNREFERENCED_PARAMETER(hWlx);
523     UNREFERENCED_PARAMETER(pDesktop);
524     UNREFERENCED_PARAMETER(hToken);
525 
526     UNIMPLEMENTED;
527     return FALSE;
528 }
529 
530 /*
531  * @implemented
532  */
533 BOOL
534 WINAPI
535 WlxSetOption(
536     HANDLE hWlx,
537     DWORD Option,
538     ULONG_PTR Value,
539     ULONG_PTR* OldValue)
540 {
541     PWLSESSION Session = (PWLSESSION)hWlx;
542 
543     TRACE("WlxSetOption(%lu)\n", Option);
544 
545     switch (Option)
546     {
547         case WLX_OPTION_USE_CTRL_ALT_DEL:
548             *OldValue = (ULONG_PTR)Session->Gina.UseCtrlAltDelete;
549             Session->Gina.UseCtrlAltDelete = (BOOL)Value;
550             return TRUE;
551         case WLX_OPTION_CONTEXT_POINTER:
552             *OldValue = (ULONG_PTR)Session->Gina.Context;
553             Session->Gina.Context = (PVOID)Value;
554             return TRUE;
555         case WLX_OPTION_USE_SMART_CARD:
556             UNIMPLEMENTED;
557             return FALSE;
558     }
559 
560     return FALSE;
561 }
562 
563 /*
564  * @implemented
565  */
566 BOOL
567 WINAPI
568 WlxGetOption(
569     HANDLE hWlx,
570     DWORD Option,
571     ULONG_PTR* Value)
572 {
573     PWLSESSION Session = (PWLSESSION)hWlx;
574 
575     TRACE("WlxGetOption(%lu)\n", Option);
576 
577     switch (Option)
578     {
579         case WLX_OPTION_USE_CTRL_ALT_DEL:
580             *Value = (ULONG_PTR)Session->Gina.UseCtrlAltDelete;
581             return TRUE;
582         case WLX_OPTION_CONTEXT_POINTER:
583         {
584             *Value = (ULONG_PTR)Session->Gina.Context;
585             return TRUE;
586         }
587         case WLX_OPTION_USE_SMART_CARD:
588         case WLX_OPTION_SMART_CARD_PRESENT:
589         case WLX_OPTION_SMART_CARD_INFO:
590             UNIMPLEMENTED;
591             return FALSE;
592         case WLX_OPTION_DISPATCH_TABLE_SIZE:
593         {
594             switch (Session->Gina.Version)
595             {
596                 case WLX_VERSION_1_0:
597                     *Value = sizeof(WLX_DISPATCH_VERSION_1_0);
598                     break;
599                 case WLX_VERSION_1_1:
600                     *Value = sizeof(WLX_DISPATCH_VERSION_1_1);
601                     break;
602                 case WLX_VERSION_1_2:
603                     *Value = sizeof(WLX_DISPATCH_VERSION_1_2);
604                     break;
605                 case WLX_VERSION_1_3:
606                     *Value = sizeof(WLX_DISPATCH_VERSION_1_3);
607                     break;
608                 case WLX_VERSION_1_4:
609                     *Value = sizeof(WLX_DISPATCH_VERSION_1_4);
610                     break;
611                 default:
612                     return FALSE;
613             }
614             return TRUE;
615         }
616     }
617 
618     return FALSE;
619 }
620 
621 /*
622  * @unimplemented
623  */
624 VOID
625 WINAPI
626 WlxWin31Migrate(
627     HANDLE hWlx)
628 {
629     UNREFERENCED_PARAMETER(hWlx);
630 
631     UNIMPLEMENTED;
632 }
633 
634 /*
635  * @unimplemented
636  */
637 BOOL
638 WINAPI
639 WlxQueryClientCredentials(
640     PWLX_CLIENT_CREDENTIALS_INFO_V1_0 pCred)
641 {
642     UNREFERENCED_PARAMETER(pCred);
643 
644     UNIMPLEMENTED;
645     return FALSE;
646 }
647 
648 /*
649  * @unimplemented
650  */
651 BOOL
652 WINAPI
653 WlxQueryInetConnectorCredentials(
654     PWLX_CLIENT_CREDENTIALS_INFO_V1_0 pCred)
655 {
656     UNREFERENCED_PARAMETER(pCred);
657 
658     UNIMPLEMENTED;
659     return FALSE;
660 }
661 
662 /*
663  * @unimplemented
664  */
665 BOOL
666 WINAPI
667 WlxDisconnect(VOID)
668 {
669     UNIMPLEMENTED;
670     return FALSE;
671 }
672 
673 /*
674  * @unimplemented
675  */
676 DWORD
677 WINAPI
678 WlxQueryTerminalServicesData(
679     HANDLE hWlx,
680     PWLX_TERMINAL_SERVICES_DATA pTSData,
681     WCHAR* UserName,
682     WCHAR* Domain)
683 {
684     UNREFERENCED_PARAMETER(hWlx);
685     UNREFERENCED_PARAMETER(pTSData);
686     UNREFERENCED_PARAMETER(UserName);
687     UNREFERENCED_PARAMETER(Domain);
688 
689     UNIMPLEMENTED;
690     return 0;
691 }
692 
693 /*
694  * @unimplemented
695  */
696 DWORD
697 WINAPI
698 WlxQueryConsoleSwitchCredentials(
699     PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 pCred)
700 {
701     UNREFERENCED_PARAMETER(pCred);
702 
703     UNIMPLEMENTED;
704     return 0;
705 }
706 
707 /*
708  * @unimplemented
709  */
710 BOOL
711 WINAPI
712 WlxQueryTsLogonCredentials(
713     PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pCred)
714 {
715     UNREFERENCED_PARAMETER(pCred);
716 
717     UNIMPLEMENTED;
718     return FALSE;
719 }
720 
721 static
722 WLX_DISPATCH_VERSION_1_4 FunctionTable = {
723     WlxUseCtrlAltDel,
724     WlxSetContextPointer,
725     WlxSasNotify,
726     WlxSetTimeout,
727     WlxAssignShellProtection,
728     WlxMessageBox,
729     WlxDialogBox,
730     WlxDialogBoxParam,
731     WlxDialogBoxIndirect,
732     WlxDialogBoxIndirectParam,
733     WlxSwitchDesktopToUser,
734     WlxSwitchDesktopToWinlogon,
735     WlxChangePasswordNotify,
736     WlxGetSourceDesktop,
737     WlxSetReturnDesktop,
738     WlxCreateUserDesktop,
739     WlxChangePasswordNotifyEx,
740     WlxCloseUserDesktop,
741     WlxSetOption,
742     WlxGetOption,
743     WlxWin31Migrate,
744     WlxQueryClientCredentials,
745     WlxQueryInetConnectorCredentials,
746     WlxDisconnect,
747     WlxQueryTerminalServicesData,
748     WlxQueryConsoleSwitchCredentials,
749     WlxQueryTsLogonCredentials
750 };
751 
752 /******************************************************************************/
753 
754 static
755 BOOL
756 GetGinaPath(
757     OUT LPWSTR Path,
758     IN DWORD Len)
759 {
760     LONG Status;
761     DWORD Type, Size;
762     HKEY hKey;
763 
764     Status = RegOpenKeyExW(
765         HKEY_LOCAL_MACHINE,
766         L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
767         0,
768         KEY_QUERY_VALUE,
769         &hKey);
770     if (Status != ERROR_SUCCESS)
771     {
772         /* Default value */
773         wcsncpy(Path, L"msgina.dll", Len);
774         return TRUE;
775     }
776 
777     Size = Len * sizeof(WCHAR);
778     Status = RegQueryValueExW(
779         hKey,
780         L"GinaDLL",
781         NULL,
782         &Type,
783         (LPBYTE)Path,
784         &Size);
785     if (Status != ERROR_SUCCESS || Type != REG_SZ || Size == 0)
786         wcsncpy(Path, L"msgina.dll", Len);
787     RegCloseKey(hKey);
788     return TRUE;
789 }
790 
791 static
792 BOOL
793 WINAPI
794 DefaultWlxScreenSaverNotify(
795     IN PVOID pWlxContext,
796     IN OUT BOOL *pSecure)
797 {
798     if (*pSecure)
799         *pSecure = WLSession->Gina.Functions.WlxIsLogoffOk(pWlxContext);
800     return TRUE;
801 }
802 
803 static
804 BOOL
805 LoadGina(
806     IN OUT PGINAFUNCTIONS Functions,
807     OUT DWORD *DllVersion,
808     OUT HMODULE *GinaInstance)
809 {
810     HMODULE hGina = NULL;
811     WCHAR GinaDll[MAX_PATH + 1];
812     BOOL ret = FALSE;
813 
814     GinaDll[0] = '\0';
815     if (!GetGinaPath(GinaDll, MAX_PATH))
816         goto cleanup;
817     /* Terminate string */
818     GinaDll[MAX_PATH] = '\0';
819 
820     hGina = LoadLibraryW(GinaDll);
821     if (!hGina)
822         goto cleanup;
823 
824     Functions->WlxNegotiate = (PFWLXNEGOTIATE)GetProcAddress(hGina, "WlxNegotiate");
825     Functions->WlxInitialize = (PFWLXINITIALIZE)GetProcAddress(hGina, "WlxInitialize");
826 
827     if (!Functions->WlxInitialize)
828         goto cleanup;
829 
830     if (!Functions->WlxNegotiate)
831     {
832         /* Assume current version */
833         *DllVersion = WLX_CURRENT_VERSION;
834     }
835     else
836     {
837         TRACE("About to negotiate with Gina %S. Winlogon uses version %x\n",
838             GinaDll, WLX_CURRENT_VERSION);
839         if (!Functions->WlxNegotiate(WLX_CURRENT_VERSION, DllVersion))
840             goto cleanup;
841     }
842 
843     TRACE("Gina uses WLX_VERSION %lx\n", *DllVersion);
844 
845     if (*DllVersion >= WLX_VERSION_1_0)
846     {
847         Functions->WlxActivateUserShell = (PFWLXACTIVATEUSERSHELL)GetProcAddress(hGina, "WlxActivateUserShell");
848         if (!Functions->WlxActivateUserShell) goto cleanup;
849         Functions->WlxDisplayLockedNotice = (PFWLXDISPLAYLOCKEDNOTICE)GetProcAddress(hGina, "WlxDisplayLockedNotice");
850         if (!Functions->WlxDisplayLockedNotice) goto cleanup;
851         Functions->WlxDisplaySASNotice = (PFWLXDISPLAYSASNOTICE)GetProcAddress(hGina, "WlxDisplaySASNotice");
852         if (!Functions->WlxDisplaySASNotice) goto cleanup;
853         Functions->WlxIsLockOk = (PFWLXISLOCKOK)GetProcAddress(hGina, "WlxIsLockOk");
854         if (!Functions->WlxIsLockOk) goto cleanup;
855         Functions->WlxIsLogoffOk = (PFWLXISLOGOFFOK)GetProcAddress(hGina, "WlxIsLogoffOk");
856         if (!Functions->WlxIsLogoffOk) goto cleanup;
857         Functions->WlxLoggedOnSAS = (PFWLXLOGGEDONSAS)GetProcAddress(hGina, "WlxLoggedOnSAS");
858         if (!Functions->WlxLoggedOnSAS) goto cleanup;
859         Functions->WlxLoggedOutSAS = (PFWLXLOGGEDOUTSAS)GetProcAddress(hGina, "WlxLoggedOutSAS");
860         if (!Functions->WlxLoggedOutSAS) goto cleanup;
861         Functions->WlxLogoff = (PFWLXLOGOFF)GetProcAddress(hGina, "WlxLogoff");
862         if (!Functions->WlxLogoff) goto cleanup;
863         Functions->WlxShutdown = (PFWLXSHUTDOWN)GetProcAddress(hGina, "WlxShutdown");
864         if (!Functions->WlxShutdown) goto cleanup;
865         Functions->WlxWkstaLockedSAS = (PFWLXWKSTALOCKEDSAS)GetProcAddress(hGina, "WlxWkstaLockedSAS");
866         if (!Functions->WlxWkstaLockedSAS) goto cleanup;
867     }
868 
869     if (*DllVersion >= WLX_VERSION_1_1)
870     {
871         Functions->WlxScreenSaverNotify = (PFWLXSCREENSAVERNOTIFY)GetProcAddress(hGina, "WlxScreenSaverNotify");
872         Functions->WlxStartApplication = (PFWLXSTARTAPPLICATION)GetProcAddress(hGina, "WlxStartApplication");
873     }
874 
875     if (*DllVersion >= WLX_VERSION_1_3)
876     {
877         Functions->WlxDisplayStatusMessage = (PFWLXDISPLAYSTATUSMESSAGE)GetProcAddress(hGina, "WlxDisplayStatusMessage");
878         if (!Functions->WlxDisplayStatusMessage) goto cleanup;
879         Functions->WlxGetStatusMessage = (PFWLXGETSTATUSMESSAGE)GetProcAddress(hGina, "WlxGetStatusMessage");
880         if (!Functions->WlxGetStatusMessage) goto cleanup;
881         Functions->WlxNetworkProviderLoad = (PFWLXNETWORKPROVIDERLOAD)GetProcAddress(hGina, "WlxNetworkProviderLoad");
882         if (!Functions->WlxNetworkProviderLoad) goto cleanup;
883         Functions->WlxRemoveStatusMessage = (PFWLXREMOVESTATUSMESSAGE)GetProcAddress(hGina, "WlxRemoveStatusMessage");
884         if (!Functions->WlxRemoveStatusMessage) goto cleanup;
885     }
886 
887     /* Provide some default functions */
888     if (!Functions->WlxScreenSaverNotify)
889         Functions->WlxScreenSaverNotify = DefaultWlxScreenSaverNotify;
890 
891     ret = TRUE;
892 
893 cleanup:
894     if (!ret)
895     {
896         if (hGina)
897             FreeLibrary(hGina);
898     }
899     else
900         *GinaInstance = hGina;
901     return ret;
902 }
903 
904 BOOL
905 GinaInit(
906     IN OUT PWLSESSION Session)
907 {
908     DWORD GinaDllVersion;
909 
910     if (!LoadGina(&Session->Gina.Functions, &GinaDllVersion, &Session->Gina.hDllInstance))
911         return FALSE;
912 
913     Session->Gina.Context = NULL;
914     Session->Gina.Version = GinaDllVersion;
915     Session->Gina.UseCtrlAltDelete = FALSE;
916     Session->SuppressStatus = FALSE;
917 
918     TRACE("Calling WlxInitialize(\"%S\")\n", Session->InteractiveWindowStationName);
919     return Session->Gina.Functions.WlxInitialize(
920         Session->InteractiveWindowStationName,
921         (HANDLE)Session,
922         NULL,
923         (PVOID)&FunctionTable,
924         &Session->Gina.Context);
925 }
926 
927 BOOL
928 CreateWindowStationAndDesktops(
929     _Inout_ PWLSESSION Session)
930 {
931     SECURITY_ATTRIBUTES WinstaSecurity;
932     SECURITY_ATTRIBUTES ApplicationDesktopSecurity;
933     SECURITY_ATTRIBUTES WinlogonDesktopSecurity;
934     SECURITY_ATTRIBUTES ScreenSaverDesktopSecurity;
935     PSECURITY_DESCRIPTOR WlWinstaSecurityDescriptor;
936     PSECURITY_DESCRIPTOR WlApplicationDesktopSecurityDescriptor;
937     PSECURITY_DESCRIPTOR WlWinlogonDesktopSecurityDescriptor;
938     PSECURITY_DESCRIPTOR WlScreenSaverDesktopSecurityDescriptor;
939     BOOL ret = FALSE;
940 
941     if (!CreateWinstaSecurity(&WlWinstaSecurityDescriptor))
942     {
943         ERR("WL: Failed to create winsta security!\n");
944         return ret;
945     }
946 
947     WinstaSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
948     WinstaSecurity.lpSecurityDescriptor = WlWinstaSecurityDescriptor;
949     WinstaSecurity.bInheritHandle = TRUE;
950 
951     if (!CreateApplicationDesktopSecurity(&WlApplicationDesktopSecurityDescriptor))
952     {
953         ERR("WL: Failed to create application desktop security!\n");
954         goto cleanup;
955     }
956 
957     ApplicationDesktopSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
958     ApplicationDesktopSecurity.lpSecurityDescriptor = WlApplicationDesktopSecurityDescriptor;
959     ApplicationDesktopSecurity.bInheritHandle = TRUE;
960 
961     if (!CreateWinlogonDesktopSecurity(&WlWinlogonDesktopSecurityDescriptor))
962     {
963         ERR("WL: Failed to create winlogon desktop security!\n");
964         goto cleanup;
965     }
966 
967     WinlogonDesktopSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
968     WinlogonDesktopSecurity.lpSecurityDescriptor = WlWinlogonDesktopSecurityDescriptor;
969     WinlogonDesktopSecurity.bInheritHandle = FALSE;
970 
971     if (!CreateScreenSaverSecurity(&WlScreenSaverDesktopSecurityDescriptor))
972     {
973         ERR("WL: Failed to create winlogon desktop security!\n");
974         goto cleanup;
975     }
976 
977     ScreenSaverDesktopSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
978     ScreenSaverDesktopSecurity.lpSecurityDescriptor = WlScreenSaverDesktopSecurityDescriptor;
979     ScreenSaverDesktopSecurity.bInheritHandle = TRUE;
980 
981     /*
982      * Create the interactive window station
983      */
984     Session->InteractiveWindowStationName = L"WinSta0";
985     Session->InteractiveWindowStation = CreateWindowStationW(
986         Session->InteractiveWindowStationName,
987         0,
988         MAXIMUM_ALLOWED,
989         &WinstaSecurity);
990     if (!Session->InteractiveWindowStation)
991     {
992         ERR("WL: Failed to create window station (%lu)\n", GetLastError());
993         goto cleanup;
994     }
995 
996     if (!SetProcessWindowStation(Session->InteractiveWindowStation))
997     {
998         ERR("WL: SetProcessWindowStation() failed (error %lu)\n", GetLastError());
999         goto cleanup;
1000     }
1001 
1002     /*
1003      * Create the application desktop
1004      */
1005     Session->ApplicationDesktop = CreateDesktopW(
1006         L"Default",
1007         NULL,
1008         NULL,
1009         0, /* FIXME: Add DF_ALLOWOTHERACCOUNTHOOK flag? */
1010         MAXIMUM_ALLOWED,
1011         &ApplicationDesktopSecurity);
1012     if (!Session->ApplicationDesktop)
1013     {
1014         ERR("WL: Failed to create Default desktop (%lu)\n", GetLastError());
1015         goto cleanup;
1016     }
1017 
1018     /*
1019      * Create the winlogon desktop
1020      */
1021     Session->WinlogonDesktop = CreateDesktopW(
1022         L"Winlogon",
1023         NULL,
1024         NULL,
1025         0,
1026         MAXIMUM_ALLOWED,
1027         &WinlogonDesktopSecurity);
1028     if (!Session->WinlogonDesktop)
1029     {
1030         ERR("WL: Failed to create Winlogon desktop (%lu)\n", GetLastError());
1031         goto cleanup;
1032     }
1033 
1034     /*
1035      * Create the screen saver desktop
1036      */
1037     Session->ScreenSaverDesktop = CreateDesktopW(
1038         L"Screen-Saver",
1039         NULL,
1040         NULL,
1041         0,
1042         MAXIMUM_ALLOWED,
1043         &ScreenSaverDesktopSecurity);
1044     if(!Session->ScreenSaverDesktop)
1045     {
1046         ERR("WL: Failed to create Screen-Saver desktop (%lu)\n", GetLastError());
1047         goto cleanup;
1048     }
1049 
1050     /*
1051      * Switch to winlogon desktop
1052     */
1053     if (!SetThreadDesktop(Session->WinlogonDesktop) ||
1054         !SwitchDesktop(Session->WinlogonDesktop))
1055     {
1056         ERR("WL: Cannot switch to Winlogon desktop (%lu)\n", GetLastError());
1057         goto cleanup;
1058     }
1059 
1060     SetWindowStationUser(Session->InteractiveWindowStation,
1061                          &LuidNone, NULL, 0);
1062 
1063     ret = TRUE;
1064 
1065 cleanup:
1066     if (!ret)
1067     {
1068         if (Session->ApplicationDesktop)
1069         {
1070             CloseDesktop(Session->ApplicationDesktop);
1071             Session->ApplicationDesktop = NULL;
1072         }
1073         if (Session->WinlogonDesktop)
1074         {
1075             CloseDesktop(Session->WinlogonDesktop);
1076             Session->WinlogonDesktop = NULL;
1077         }
1078         if (Session->ScreenSaverDesktop)
1079         {
1080             CloseDesktop(Session->ScreenSaverDesktop);
1081             Session->ScreenSaverDesktop = NULL;
1082         }
1083         if (Session->InteractiveWindowStation)
1084         {
1085             CloseWindowStation(Session->InteractiveWindowStation);
1086             Session->InteractiveWindowStation = NULL;
1087         }
1088         if (WlWinstaSecurityDescriptor)
1089         {
1090             RtlFreeHeap(RtlGetProcessHeap(), 0, WlWinstaSecurityDescriptor);
1091         }
1092         if (WlApplicationDesktopSecurityDescriptor)
1093         {
1094             RtlFreeHeap(RtlGetProcessHeap(), 0, WlApplicationDesktopSecurityDescriptor);
1095         }
1096         if (WlWinlogonDesktopSecurityDescriptor)
1097         {
1098             RtlFreeHeap(RtlGetProcessHeap(), 0, WlWinlogonDesktopSecurityDescriptor);
1099         }
1100         if (WlScreenSaverDesktopSecurityDescriptor)
1101         {
1102             RtlFreeHeap(RtlGetProcessHeap(), 0, WlScreenSaverDesktopSecurityDescriptor);
1103         }
1104     }
1105 
1106     return ret;
1107 }
1108