xref: /reactos/base/system/winlogon/wlx.c (revision c2c66aff)
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 #define DESKTOP_ALL (DESKTOP_READOBJECTS | DESKTOP_CREATEWINDOW | \
16     DESKTOP_CREATEMENU | DESKTOP_HOOKCONTROL | DESKTOP_JOURNALRECORD | \
17     DESKTOP_JOURNALPLAYBACK | DESKTOP_ENUMERATE | DESKTOP_WRITEOBJECTS | \
18     DESKTOP_SWITCHDESKTOP | STANDARD_RIGHTS_REQUIRED)
19 
20 #define WINSTA_ALL (WINSTA_ENUMDESKTOPS | WINSTA_READATTRIBUTES | \
21     WINSTA_ACCESSCLIPBOARD | WINSTA_CREATEDESKTOP | \
22     WINSTA_WRITEATTRIBUTES | WINSTA_ACCESSGLOBALATOMS | \
23     WINSTA_EXITWINDOWS | WINSTA_ENUMERATE | WINSTA_READSCREEN | \
24     STANDARD_RIGHTS_REQUIRED)
25 
26 #define GENERIC_ACCESS (GENERIC_READ | GENERIC_WRITE | \
27     GENERIC_EXECUTE | GENERIC_ALL)
28 
29 typedef struct _DIALOG_LIST_ENTRY
30 {
31     LIST_ENTRY Entry;
32     HWND hWnd;
33     DLGPROC DlgProc;
34     LPARAM lParam;
35 } DIALOG_LIST_ENTRY, *PDIALOG_LIST_ENTRY;
36 
37 /* GLOBALS ******************************************************************/
38 
39 //static UINT_PTR IdTimer;
40 static LIST_ENTRY DialogListHead;
41 
42 /* FUNCTIONS ****************************************************************/
43 
44 VOID
45 InitDialogListHead(VOID)
46 {
47     InitializeListHead(&DialogListHead);
48 }
49 
50 
51 static
52 PDIALOG_LIST_ENTRY
53 AddDialogListEntry(VOID)
54 {
55     PDIALOG_LIST_ENTRY ListEntry;
56 
57     ListEntry = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(DIALOG_LIST_ENTRY));
58     if (ListEntry == NULL)
59         return NULL;
60 
61     TRACE("Add entry %p\n", ListEntry);
62 
63     InsertHeadList(&DialogListHead,
64                    &ListEntry->Entry);
65 
66     return ListEntry;
67 }
68 
69 
70 static
71 VOID
72 RemoveDialogListEntry(PDIALOG_LIST_ENTRY ListEntry)
73 {
74     TRACE("Remove entry %p\n", ListEntry);
75 
76     RemoveEntryList(&ListEntry->Entry);
77     RtlFreeHeap(RtlGetProcessHeap(), 0, ListEntry);
78 }
79 
80 
81 static
82 PDIALOG_LIST_ENTRY
83 GetDialogListEntry(HWND hwndDlg)
84 {
85     PDIALOG_LIST_ENTRY Current;
86     PLIST_ENTRY ListEntry;
87 
88     ListEntry = DialogListHead.Flink;
89     while (ListEntry != &DialogListHead)
90     {
91         Current = CONTAINING_RECORD(ListEntry,
92                                     DIALOG_LIST_ENTRY,
93                                     Entry);
94         if (Current->hWnd == hwndDlg)
95         {
96             TRACE("Found entry: %p\n", Current);
97             return Current;
98         }
99 
100         ListEntry = ListEntry->Flink;
101     }
102 
103     TRACE("Found no entry!\n");
104     return NULL;
105 }
106 
107 
108 HWND
109 GetTopDialogWindow(VOID)
110 {
111     PDIALOG_LIST_ENTRY Current;
112     PLIST_ENTRY ListEntry;
113 
114     ListEntry = DialogListHead.Flink;
115     if (ListEntry != &DialogListHead)
116     {
117         Current = CONTAINING_RECORD(ListEntry,
118                                     DIALOG_LIST_ENTRY,
119                                     Entry);
120 
121         TRACE("Found entry: %p window %p\n", Current, Current->hWnd);
122         return Current->hWnd;
123     }
124 
125     TRACE("Found no window\n");
126     return NULL;
127 }
128 
129 
130 static
131 INT_PTR
132 CALLBACK
133 DefaultWlxWindowProc(
134     IN HWND hwndDlg,
135     IN UINT uMsg,
136     IN WPARAM wParam,
137     IN LPARAM lParam)
138 {
139     PDIALOG_LIST_ENTRY ListEntry;
140     INT_PTR ret;
141 
142     if (uMsg == WM_INITDIALOG)
143     {
144         ListEntry = (PDIALOG_LIST_ENTRY)lParam;
145 
146         TRACE("Set dialog handle: %p\n", hwndDlg);
147         ListEntry->hWnd = hwndDlg;
148         lParam = ListEntry->lParam;
149 //        SetTopTimeout(hWnd);
150     }
151     else
152     {
153         ListEntry = GetDialogListEntry(hwndDlg);
154         if (ListEntry == NULL)
155             return FALSE;
156     }
157 
158     if (uMsg == WLX_WM_SAS)
159     {
160         EndDialog(hwndDlg, WLX_DLG_SAS);
161         return 0;
162     }
163 
164     ret = ListEntry->DlgProc(hwndDlg, uMsg, wParam, lParam);
165 
166     return ret;
167 
168 /*
169     if (uMsg == WM_TIMER && (UINT_PTR)wParam == IdTimer)
170     {
171         EndDialog(hwndDlg, -1);
172         KillTimer(hwndDlg, IdTimer);
173         return TRUE;
174     }
175     else if (uMsg == WM_INITDIALOG)
176     {
177         IdTimer = SetTimer(hwndDlg, 0, WLSession->DialogTimeout * 1000, NULL);
178         return PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
179     }
180     else if (uMsg == WM_NCDESTROY)
181     {
182         BOOL ret;
183         ret = PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
184         PreviousWindowProc = NULL;
185         return ret;
186     }
187     else
188     {
189         return PreviousWindowProc(hwndDlg, uMsg, wParam, lParam);
190     }
191 */
192 }
193 
194 /*
195  * @implemented
196  */
197 VOID
198 WINAPI
199 WlxUseCtrlAltDel(
200     HANDLE hWlx)
201 {
202     ULONG_PTR OldValue;
203 
204     TRACE("WlxUseCtrlAltDel()\n");
205 
206     WlxSetOption(hWlx, WLX_OPTION_USE_CTRL_ALT_DEL, TRUE, &OldValue);
207 }
208 
209 /*
210  * @implemented
211  */
212 VOID
213 WINAPI
214 WlxSetContextPointer(
215     HANDLE hWlx,
216     PVOID pWlxContext)
217 {
218     ULONG_PTR OldValue;
219 
220     TRACE("WlxSetContextPointer(%p)\n", pWlxContext);
221 
222     WlxSetOption(hWlx, WLX_OPTION_CONTEXT_POINTER, (ULONG_PTR)pWlxContext, &OldValue);
223 }
224 
225 /*
226  * @implemented
227  */
228 VOID
229 WINAPI
230 WlxSasNotify(
231     HANDLE hWlx,
232     DWORD dwSasType)
233 {
234     PWLSESSION Session = (PWLSESSION)hWlx;
235 
236     TRACE("WlxSasNotify(0x%lx)\n", dwSasType);
237 
238     if (dwSasType == WLX_SAS_TYPE_CTRL_ALT_DEL || dwSasType > WLX_SAS_TYPE_MAX_MSFT_VALUE)
239         PostMessageW(Session->SASWindow, WLX_WM_SAS, dwSasType, 0);
240 }
241 
242 /*
243  * @implemented
244  */
245 BOOL
246 WINAPI
247 WlxSetTimeout(
248     HANDLE hWlx,
249     DWORD Timeout)
250 {
251     PWLSESSION Session = (PWLSESSION)hWlx;
252 
253     TRACE("WlxSetTimeout(%lu)\n", Timeout);
254 
255     Session->DialogTimeout = Timeout;
256     return TRUE;
257 }
258 
259 /*
260  * @unimplemented
261  */
262 int
263 WINAPI
264 WlxAssignShellProtection(
265     HANDLE hWlx,
266     HANDLE hToken,
267     HANDLE hProcess,
268     HANDLE hThread)
269 {
270     UNREFERENCED_PARAMETER(hWlx);
271     UNREFERENCED_PARAMETER(hToken);
272     UNREFERENCED_PARAMETER(hProcess);
273     UNREFERENCED_PARAMETER(hThread);
274 
275     UNIMPLEMENTED;
276     return 0;
277 }
278 
279 /*
280  * @implemented
281  */
282 int
283 WINAPI
284 WlxMessageBox(
285     HANDLE hWlx,
286     HWND hwndOwner,
287     LPWSTR lpszText,
288     LPWSTR lpszTitle,
289     UINT fuStyle)
290 {
291     UNREFERENCED_PARAMETER(hWlx);
292 
293     TRACE("WlxMessageBox()\n");
294     /* FIXME: Provide a custom window proc to be able to handle timeout */
295     return MessageBoxW(hwndOwner, lpszText, lpszTitle, fuStyle);
296 }
297 
298 /*
299  * @implemented
300  */
301 int
302 WINAPI
303 WlxDialogBox(
304     HANDLE hWlx,
305     HANDLE hInst,
306     LPWSTR lpszTemplate,
307     HWND hwndOwner,
308     DLGPROC dlgprc)
309 {
310     UNREFERENCED_PARAMETER(hWlx);
311 
312     TRACE("WlxDialogBox()\n");
313 
314     return (int)WlxDialogBoxParam(hWlx, hInst, lpszTemplate, hwndOwner, dlgprc, 0);
315 }
316 
317 /*
318  * @implemented
319  */
320 int
321 WINAPI
322 WlxDialogBoxParam(
323     HANDLE hWlx,
324     HANDLE hInst,
325     LPWSTR lpszTemplate,
326     HWND hwndOwner,
327     DLGPROC dlgprc,
328     LPARAM dwInitParam)
329 {
330     PDIALOG_LIST_ENTRY ListEntry;
331     int ret;
332 
333     UNREFERENCED_PARAMETER(hWlx);
334 
335     TRACE("WlxDialogBoxParam()\n");
336 
337     ListEntry = AddDialogListEntry();
338     if (ListEntry == NULL)
339         return -1;
340 
341     ListEntry->DlgProc = dlgprc;
342     ListEntry->lParam = dwInitParam;
343 
344     ret = (int)DialogBoxParamW(hInst, lpszTemplate, hwndOwner, DefaultWlxWindowProc, (LPARAM)ListEntry);
345 
346     RemoveDialogListEntry(ListEntry);
347 
348     return ret;
349 }
350 
351 /*
352  * @implemented
353  */
354 int
355 WINAPI
356 WlxDialogBoxIndirect(
357     HANDLE hWlx,
358     HANDLE hInst,
359     LPCDLGTEMPLATE hDialogTemplate,
360     HWND hwndOwner,
361     DLGPROC dlgprc)
362 {
363     UNREFERENCED_PARAMETER(hWlx);
364 
365     TRACE("WlxDialogBoxIndirect()\n");
366 
367     return (int)WlxDialogBoxIndirectParam(hWlx, hInst, hDialogTemplate, hwndOwner, dlgprc, 0);
368 }
369 
370 /*
371  * @implemented
372  */
373 int
374 WINAPI
375 WlxDialogBoxIndirectParam(
376     HANDLE hWlx,
377     HANDLE hInst,
378     LPCDLGTEMPLATE hDialogTemplate,
379     HWND hwndOwner,
380     DLGPROC dlgprc,
381     LPARAM dwInitParam)
382 {
383     PDIALOG_LIST_ENTRY ListEntry;
384     int ret;
385 
386     UNREFERENCED_PARAMETER(hWlx);
387 
388     TRACE("WlxDialogBoxIndirectParam()\n");
389 
390     ListEntry = AddDialogListEntry();
391     if (ListEntry == NULL)
392         return -1;
393 
394     ListEntry->DlgProc = dlgprc;
395     ListEntry->lParam = dwInitParam;
396 
397     ret = (int)DialogBoxIndirectParamW(hInst, hDialogTemplate, hwndOwner, DefaultWlxWindowProc, (LPARAM)ListEntry);
398 
399     RemoveDialogListEntry(ListEntry);
400 
401     return ret;
402 }
403 
404 /*
405  * @implemented
406  */
407 int
408 WINAPI
409 WlxSwitchDesktopToUser(
410     HANDLE hWlx)
411 {
412     PWLSESSION Session = (PWLSESSION)hWlx;
413 
414     TRACE("WlxSwitchDesktopToUser()\n");
415 
416     return (int)SwitchDesktop(Session->ApplicationDesktop);
417 }
418 
419 /*
420  * @implemented
421  */
422 int
423 WINAPI
424 WlxSwitchDesktopToWinlogon(
425     HANDLE hWlx)
426 {
427     PWLSESSION Session = (PWLSESSION)hWlx;
428 
429     TRACE("WlxSwitchDesktopToWinlogon()\n");
430 
431     return (int)SwitchDesktop(Session->WinlogonDesktop);
432 }
433 
434 /*
435  * @unimplemented
436  */
437 int
438 WINAPI
439 WlxChangePasswordNotify(
440     HANDLE hWlx,
441     PWLX_MPR_NOTIFY_INFO pMprInfo,
442     DWORD dwChangeInfo)
443 {
444     UNREFERENCED_PARAMETER(hWlx);
445     UNREFERENCED_PARAMETER(pMprInfo);
446     UNREFERENCED_PARAMETER(dwChangeInfo);
447 
448     UNIMPLEMENTED;
449     return 0;
450 }
451 
452 /*
453  * @unimplemented
454  */
455 BOOL
456 WINAPI
457 WlxGetSourceDesktop(
458     HANDLE hWlx,
459     PWLX_DESKTOP* ppDesktop)
460 {
461     UNREFERENCED_PARAMETER(hWlx);
462     UNREFERENCED_PARAMETER(ppDesktop);
463 
464     UNIMPLEMENTED;
465     return FALSE;
466 }
467 
468 /*
469  * @unimplemented
470  */
471 BOOL
472 WINAPI
473 WlxSetReturnDesktop(
474     HANDLE hWlx,
475     PWLX_DESKTOP pDesktop)
476 {
477     UNREFERENCED_PARAMETER(hWlx);
478     UNREFERENCED_PARAMETER(pDesktop);
479 
480     UNIMPLEMENTED;
481     return FALSE;
482 }
483 
484 /*
485  * @unimplemented
486  */
487 BOOL
488 WINAPI
489 WlxCreateUserDesktop(
490     HANDLE hWlx,
491     HANDLE hToken,
492     DWORD Flags,
493     PWSTR pszDesktopName,
494     PWLX_DESKTOP* ppDesktop)
495 {
496     UNREFERENCED_PARAMETER(hWlx);
497     UNREFERENCED_PARAMETER(hToken);
498     UNREFERENCED_PARAMETER(Flags);
499     UNREFERENCED_PARAMETER(pszDesktopName);
500     UNREFERENCED_PARAMETER(ppDesktop);
501 
502     UNIMPLEMENTED;
503     return FALSE;
504 }
505 
506 /*
507  * @unimplemented
508  */
509 int
510 WINAPI
511 WlxChangePasswordNotifyEx(
512     HANDLE hWlx,
513     PWLX_MPR_NOTIFY_INFO pMprInfo,
514     DWORD dwChangeInfo,
515     PWSTR ProviderName,
516     PVOID Reserved)
517 {
518     UNREFERENCED_PARAMETER(hWlx);
519     UNREFERENCED_PARAMETER(pMprInfo);
520     UNREFERENCED_PARAMETER(dwChangeInfo);
521     UNREFERENCED_PARAMETER(ProviderName);
522     UNREFERENCED_PARAMETER(Reserved);
523 
524     UNIMPLEMENTED;
525     return 0;
526 }
527 
528 /*
529  * @unimplemented
530  */
531 BOOL
532 WINAPI
533 WlxCloseUserDesktop(
534     HANDLE hWlx,
535     PWLX_DESKTOP pDesktop,
536     HANDLE hToken)
537 {
538     UNREFERENCED_PARAMETER(hWlx);
539     UNREFERENCED_PARAMETER(pDesktop);
540     UNREFERENCED_PARAMETER(hToken);
541 
542     UNIMPLEMENTED;
543     return FALSE;
544 }
545 
546 /*
547  * @implemented
548  */
549 BOOL
550 WINAPI
551 WlxSetOption(
552     HANDLE hWlx,
553     DWORD Option,
554     ULONG_PTR Value,
555     ULONG_PTR* OldValue)
556 {
557     PWLSESSION Session = (PWLSESSION)hWlx;
558 
559     TRACE("WlxSetOption(%lu)\n", Option);
560 
561     switch (Option)
562     {
563         case WLX_OPTION_USE_CTRL_ALT_DEL:
564             *OldValue = (ULONG_PTR)Session->Gina.UseCtrlAltDelete;
565             Session->Gina.UseCtrlAltDelete = (BOOL)Value;
566             return TRUE;
567         case WLX_OPTION_CONTEXT_POINTER:
568             *OldValue = (ULONG_PTR)Session->Gina.Context;
569             Session->Gina.Context = (PVOID)Value;
570             return TRUE;
571         case WLX_OPTION_USE_SMART_CARD:
572             UNIMPLEMENTED;
573             return FALSE;
574     }
575 
576     return FALSE;
577 }
578 
579 /*
580  * @implemented
581  */
582 BOOL
583 WINAPI
584 WlxGetOption(
585     HANDLE hWlx,
586     DWORD Option,
587     ULONG_PTR* Value)
588 {
589     PWLSESSION Session = (PWLSESSION)hWlx;
590 
591     TRACE("WlxGetOption(%lu)\n", Option);
592 
593     switch (Option)
594     {
595         case WLX_OPTION_USE_CTRL_ALT_DEL:
596             *Value = (ULONG_PTR)Session->Gina.UseCtrlAltDelete;
597             return TRUE;
598         case WLX_OPTION_CONTEXT_POINTER:
599         {
600             *Value = (ULONG_PTR)Session->Gina.Context;
601             return TRUE;
602         }
603         case WLX_OPTION_USE_SMART_CARD:
604         case WLX_OPTION_SMART_CARD_PRESENT:
605         case WLX_OPTION_SMART_CARD_INFO:
606             UNIMPLEMENTED;
607             return FALSE;
608         case WLX_OPTION_DISPATCH_TABLE_SIZE:
609         {
610             switch (Session->Gina.Version)
611             {
612                 case WLX_VERSION_1_0:
613                     *Value = sizeof(WLX_DISPATCH_VERSION_1_0);
614                     break;
615                 case WLX_VERSION_1_1:
616                     *Value = sizeof(WLX_DISPATCH_VERSION_1_1);
617                     break;
618                 case WLX_VERSION_1_2:
619                     *Value = sizeof(WLX_DISPATCH_VERSION_1_2);
620                     break;
621                 case WLX_VERSION_1_3:
622                     *Value = sizeof(WLX_DISPATCH_VERSION_1_3);
623                     break;
624                 case WLX_VERSION_1_4:
625                     *Value = sizeof(WLX_DISPATCH_VERSION_1_4);
626                     break;
627                 default:
628                     return FALSE;
629             }
630             return TRUE;
631         }
632     }
633 
634     return FALSE;
635 }
636 
637 /*
638  * @unimplemented
639  */
640 VOID
641 WINAPI
642 WlxWin31Migrate(
643     HANDLE hWlx)
644 {
645     UNREFERENCED_PARAMETER(hWlx);
646 
647     UNIMPLEMENTED;
648 }
649 
650 /*
651  * @unimplemented
652  */
653 BOOL
654 WINAPI
655 WlxQueryClientCredentials(
656     PWLX_CLIENT_CREDENTIALS_INFO_V1_0 pCred)
657 {
658     UNREFERENCED_PARAMETER(pCred);
659 
660     UNIMPLEMENTED;
661     return FALSE;
662 }
663 
664 /*
665  * @unimplemented
666  */
667 BOOL
668 WINAPI
669 WlxQueryInetConnectorCredentials(
670     PWLX_CLIENT_CREDENTIALS_INFO_V1_0 pCred)
671 {
672     UNREFERENCED_PARAMETER(pCred);
673 
674     UNIMPLEMENTED;
675     return FALSE;
676 }
677 
678 /*
679  * @unimplemented
680  */
681 BOOL
682 WINAPI
683 WlxDisconnect(VOID)
684 {
685     UNIMPLEMENTED;
686     return FALSE;
687 }
688 
689 /*
690  * @unimplemented
691  */
692 DWORD
693 WINAPI
694 WlxQueryTerminalServicesData(
695     HANDLE hWlx,
696     PWLX_TERMINAL_SERVICES_DATA pTSData,
697     WCHAR* UserName,
698     WCHAR* Domain)
699 {
700     UNREFERENCED_PARAMETER(hWlx);
701     UNREFERENCED_PARAMETER(pTSData);
702     UNREFERENCED_PARAMETER(UserName);
703     UNREFERENCED_PARAMETER(Domain);
704 
705     UNIMPLEMENTED;
706     return 0;
707 }
708 
709 /*
710  * @unimplemented
711  */
712 DWORD
713 WINAPI
714 WlxQueryConsoleSwitchCredentials(
715     PWLX_CONSOLESWITCH_CREDENTIALS_INFO_V1_0 pCred)
716 {
717     UNREFERENCED_PARAMETER(pCred);
718 
719     UNIMPLEMENTED;
720     return 0;
721 }
722 
723 /*
724  * @unimplemented
725  */
726 BOOL
727 WINAPI
728 WlxQueryTsLogonCredentials(
729     PWLX_CLIENT_CREDENTIALS_INFO_V2_0 pCred)
730 {
731     UNREFERENCED_PARAMETER(pCred);
732 
733     UNIMPLEMENTED;
734     return FALSE;
735 }
736 
737 static
738 WLX_DISPATCH_VERSION_1_4 FunctionTable = {
739     WlxUseCtrlAltDel,
740     WlxSetContextPointer,
741     WlxSasNotify,
742     WlxSetTimeout,
743     WlxAssignShellProtection,
744     WlxMessageBox,
745     WlxDialogBox,
746     WlxDialogBoxParam,
747     WlxDialogBoxIndirect,
748     WlxDialogBoxIndirectParam,
749     WlxSwitchDesktopToUser,
750     WlxSwitchDesktopToWinlogon,
751     WlxChangePasswordNotify,
752     WlxGetSourceDesktop,
753     WlxSetReturnDesktop,
754     WlxCreateUserDesktop,
755     WlxChangePasswordNotifyEx,
756     WlxCloseUserDesktop,
757     WlxSetOption,
758     WlxGetOption,
759     WlxWin31Migrate,
760     WlxQueryClientCredentials,
761     WlxQueryInetConnectorCredentials,
762     WlxDisconnect,
763     WlxQueryTerminalServicesData,
764     WlxQueryConsoleSwitchCredentials,
765     WlxQueryTsLogonCredentials
766 };
767 
768 /******************************************************************************/
769 
770 static
771 BOOL
772 GetGinaPath(
773     OUT LPWSTR Path,
774     IN DWORD Len)
775 {
776     LONG Status;
777     DWORD Type, Size;
778     HKEY hKey;
779 
780     Status = RegOpenKeyExW(
781         HKEY_LOCAL_MACHINE,
782         L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
783         0,
784         KEY_QUERY_VALUE,
785         &hKey);
786     if (Status != ERROR_SUCCESS)
787     {
788         /* Default value */
789         wcsncpy(Path, L"msgina.dll", Len);
790         return TRUE;
791     }
792 
793     Size = Len * sizeof(WCHAR);
794     Status = RegQueryValueExW(
795         hKey,
796         L"GinaDLL",
797         NULL,
798         &Type,
799         (LPBYTE)Path,
800         &Size);
801     if (Status != ERROR_SUCCESS || Type != REG_SZ || Size == 0)
802         wcsncpy(Path, L"msgina.dll", Len);
803     RegCloseKey(hKey);
804     return TRUE;
805 }
806 
807 static
808 BOOL
809 WINAPI
810 DefaultWlxScreenSaverNotify(
811     IN PVOID pWlxContext,
812     IN OUT BOOL *pSecure)
813 {
814     if (*pSecure)
815         *pSecure = WLSession->Gina.Functions.WlxIsLogoffOk(pWlxContext);
816     return TRUE;
817 }
818 
819 static
820 BOOL
821 LoadGina(
822     IN OUT PGINAFUNCTIONS Functions,
823     OUT DWORD *DllVersion,
824     OUT HMODULE *GinaInstance)
825 {
826     HMODULE hGina = NULL;
827     WCHAR GinaDll[MAX_PATH + 1];
828     BOOL ret = FALSE;
829 
830     GinaDll[0] = '\0';
831     if (!GetGinaPath(GinaDll, MAX_PATH))
832         goto cleanup;
833     /* Terminate string */
834     GinaDll[MAX_PATH] = '\0';
835 
836     hGina = LoadLibraryW(GinaDll);
837     if (!hGina)
838         goto cleanup;
839 
840     Functions->WlxNegotiate = (PFWLXNEGOTIATE)GetProcAddress(hGina, "WlxNegotiate");
841     Functions->WlxInitialize = (PFWLXINITIALIZE)GetProcAddress(hGina, "WlxInitialize");
842 
843     if (!Functions->WlxInitialize)
844         goto cleanup;
845 
846     if (!Functions->WlxNegotiate)
847     {
848         /* Assume current version */
849         *DllVersion = WLX_CURRENT_VERSION;
850     }
851     else
852     {
853         TRACE("About to negotiate with Gina %S. Winlogon uses version %x\n",
854             GinaDll, WLX_CURRENT_VERSION);
855         if (!Functions->WlxNegotiate(WLX_CURRENT_VERSION, DllVersion))
856             goto cleanup;
857     }
858 
859     TRACE("Gina uses WLX_VERSION %lx\n", *DllVersion);
860 
861     if (*DllVersion >= WLX_VERSION_1_0)
862     {
863         Functions->WlxActivateUserShell = (PFWLXACTIVATEUSERSHELL)GetProcAddress(hGina, "WlxActivateUserShell");
864         if (!Functions->WlxActivateUserShell) goto cleanup;
865         Functions->WlxDisplayLockedNotice = (PFWLXDISPLAYLOCKEDNOTICE)GetProcAddress(hGina, "WlxDisplayLockedNotice");
866         if (!Functions->WlxDisplayLockedNotice) goto cleanup;
867         Functions->WlxDisplaySASNotice = (PFWLXDISPLAYSASNOTICE)GetProcAddress(hGina, "WlxDisplaySASNotice");
868         if (!Functions->WlxDisplaySASNotice) goto cleanup;
869         Functions->WlxIsLockOk = (PFWLXISLOCKOK)GetProcAddress(hGina, "WlxIsLockOk");
870         if (!Functions->WlxIsLockOk) goto cleanup;
871         Functions->WlxIsLogoffOk = (PFWLXISLOGOFFOK)GetProcAddress(hGina, "WlxIsLogoffOk");
872         if (!Functions->WlxIsLogoffOk) goto cleanup;
873         Functions->WlxLoggedOnSAS = (PFWLXLOGGEDONSAS)GetProcAddress(hGina, "WlxLoggedOnSAS");
874         if (!Functions->WlxLoggedOnSAS) goto cleanup;
875         Functions->WlxLoggedOutSAS = (PFWLXLOGGEDOUTSAS)GetProcAddress(hGina, "WlxLoggedOutSAS");
876         if (!Functions->WlxLoggedOutSAS) goto cleanup;
877         Functions->WlxLogoff = (PFWLXLOGOFF)GetProcAddress(hGina, "WlxLogoff");
878         if (!Functions->WlxLogoff) goto cleanup;
879         Functions->WlxShutdown = (PFWLXSHUTDOWN)GetProcAddress(hGina, "WlxShutdown");
880         if (!Functions->WlxShutdown) goto cleanup;
881         Functions->WlxWkstaLockedSAS = (PFWLXWKSTALOCKEDSAS)GetProcAddress(hGina, "WlxWkstaLockedSAS");
882         if (!Functions->WlxWkstaLockedSAS) goto cleanup;
883     }
884 
885     if (*DllVersion >= WLX_VERSION_1_1)
886     {
887         Functions->WlxScreenSaverNotify = (PFWLXSCREENSAVERNOTIFY)GetProcAddress(hGina, "WlxScreenSaverNotify");
888         Functions->WlxStartApplication = (PFWLXSTARTAPPLICATION)GetProcAddress(hGina, "WlxStartApplication");
889     }
890 
891     if (*DllVersion >= WLX_VERSION_1_3)
892     {
893         Functions->WlxDisplayStatusMessage = (PFWLXDISPLAYSTATUSMESSAGE)GetProcAddress(hGina, "WlxDisplayStatusMessage");
894         if (!Functions->WlxDisplayStatusMessage) goto cleanup;
895         Functions->WlxGetStatusMessage = (PFWLXGETSTATUSMESSAGE)GetProcAddress(hGina, "WlxGetStatusMessage");
896         if (!Functions->WlxGetStatusMessage) goto cleanup;
897         Functions->WlxNetworkProviderLoad = (PFWLXNETWORKPROVIDERLOAD)GetProcAddress(hGina, "WlxNetworkProviderLoad");
898         if (!Functions->WlxNetworkProviderLoad) goto cleanup;
899         Functions->WlxRemoveStatusMessage = (PFWLXREMOVESTATUSMESSAGE)GetProcAddress(hGina, "WlxRemoveStatusMessage");
900         if (!Functions->WlxRemoveStatusMessage) goto cleanup;
901     }
902 
903     /* Provide some default functions */
904     if (!Functions->WlxScreenSaverNotify)
905         Functions->WlxScreenSaverNotify = DefaultWlxScreenSaverNotify;
906 
907     ret = TRUE;
908 
909 cleanup:
910     if (!ret)
911     {
912         if (hGina)
913             FreeLibrary(hGina);
914     }
915     else
916         *GinaInstance = hGina;
917     return ret;
918 }
919 
920 BOOL
921 GinaInit(
922     IN OUT PWLSESSION Session)
923 {
924     DWORD GinaDllVersion;
925 
926     if (!LoadGina(&Session->Gina.Functions, &GinaDllVersion, &Session->Gina.hDllInstance))
927         return FALSE;
928 
929     Session->Gina.Context = NULL;
930     Session->Gina.Version = GinaDllVersion;
931     Session->Gina.UseCtrlAltDelete = FALSE;
932     Session->SuppressStatus = FALSE;
933 
934     TRACE("Calling WlxInitialize(\"%S\")\n", Session->InteractiveWindowStationName);
935     return Session->Gina.Functions.WlxInitialize(
936         Session->InteractiveWindowStationName,
937         (HANDLE)Session,
938         NULL,
939         (PVOID)&FunctionTable,
940         &Session->Gina.Context);
941 }
942 
943 BOOL
944 AddAceToWindowStation(
945     IN HWINSTA WinSta,
946     IN PSID Sid)
947 {
948     DWORD AclSize;
949     SECURITY_INFORMATION SecurityInformation;
950     PACL pDefaultAcl = NULL;
951     PSECURITY_DESCRIPTOR WinstaSd = NULL;
952     PACCESS_ALLOWED_ACE Ace = NULL;
953     BOOL Ret = FALSE;
954 
955     /* Allocate space for an ACL */
956     AclSize = sizeof(ACL)
957         + 2 * (FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(Sid));
958     pDefaultAcl = HeapAlloc(GetProcessHeap(), 0, AclSize);
959     if (!pDefaultAcl)
960     {
961         ERR("WL: HeapAlloc() failed\n");
962         goto cleanup;
963     }
964 
965     /* Initialize it */
966     if (!InitializeAcl(pDefaultAcl, AclSize, ACL_REVISION))
967     {
968         ERR("WL: InitializeAcl() failed (error %lu)\n", GetLastError());
969         goto cleanup;
970     }
971 
972     /* Initialize new security descriptor */
973     WinstaSd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
974     if (!InitializeSecurityDescriptor(WinstaSd, SECURITY_DESCRIPTOR_REVISION))
975     {
976         ERR("WL: InitializeSecurityDescriptor() failed (error %lu)\n", GetLastError());
977         goto cleanup;
978     }
979 
980     /* Allocate memory for access allowed ACE */
981     Ace = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ACCESS_ALLOWED_ACE)+
982         GetLengthSid(Sid) - sizeof(DWORD));
983 
984     /* Create the first ACE for the window station */
985     Ace->Header.AceType = ACCESS_ALLOWED_ACE_TYPE;
986     Ace->Header.AceFlags = CONTAINER_INHERIT_ACE | INHERIT_ONLY_ACE | OBJECT_INHERIT_ACE;
987     Ace->Header.AceSize = sizeof(ACCESS_ALLOWED_ACE) + GetLengthSid(Sid) - sizeof(DWORD);
988     Ace->Mask = GENERIC_ACCESS;
989 
990     /* Copy the sid */
991     if (!CopySid(GetLengthSid(Sid), &Ace->SidStart, Sid))
992     {
993         ERR("WL: CopySid() failed (error %lu)\n", GetLastError());
994         goto cleanup;
995     }
996 
997     /* Add the first ACE */
998     if (!AddAce(pDefaultAcl, ACL_REVISION, MAXDWORD, (LPVOID)Ace, Ace->Header.AceSize))
999     {
1000         ERR("WL: AddAce() failed (error %lu)\n", GetLastError());
1001         goto cleanup;
1002     }
1003 
1004     /* Add the second ACE to the end of ACL */
1005     Ace->Header.AceFlags = NO_PROPAGATE_INHERIT_ACE;
1006     Ace->Mask = WINSTA_ALL;
1007     if (!AddAce(pDefaultAcl, ACL_REVISION, MAXDWORD, (LPVOID)Ace, Ace->Header.AceSize))
1008     {
1009         ERR("WL: AddAce() failed (error %lu)\n", GetLastError());
1010         goto cleanup;
1011     }
1012 
1013     /* Add ACL to winsta's security descriptor */
1014     if (!SetSecurityDescriptorDacl(WinstaSd, TRUE, pDefaultAcl, FALSE))
1015     {
1016         ERR("WL: SetSecurityDescriptorDacl() failed (error %lu)\n", GetLastError());
1017         goto cleanup;
1018     }
1019 
1020     /* Apply security to the window station */
1021     SecurityInformation = DACL_SECURITY_INFORMATION;
1022     if (!SetUserObjectSecurity(WinSta, &SecurityInformation, WinstaSd))
1023     {
1024         ERR("WL: SetUserObjectSecurity() failed (error %lu)\n", GetLastError());
1025         goto cleanup;
1026     }
1027 
1028     /* Indicate success */
1029     Ret = TRUE;
1030 
1031 cleanup:
1032     /* Free allocated stuff */
1033     if (pDefaultAcl) HeapFree(GetProcessHeap(), 0, pDefaultAcl);
1034     if (WinstaSd) HeapFree(GetProcessHeap(), 0, WinstaSd);
1035     if (Ace) HeapFree(GetProcessHeap(), 0, Ace);
1036 
1037     return Ret;
1038 }
1039 
1040 BOOL
1041 AddAceToDesktop(
1042     IN HDESK Desktop,
1043     IN PSID WinlogonSid,
1044     IN PSID UserSid)
1045 {
1046     DWORD AclSize;
1047     SECURITY_INFORMATION SecurityInformation;
1048     PACL Acl = NULL;
1049     PSECURITY_DESCRIPTOR DesktopSd = NULL;
1050     BOOL Ret = FALSE;
1051 
1052     /* Allocate ACL */
1053     AclSize = sizeof(ACL)
1054         + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(WinlogonSid);
1055 
1056     /* Take user's sid into account */
1057     if (UserSid)
1058         AclSize += FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(UserSid);
1059 
1060     Acl = HeapAlloc(GetProcessHeap(), 0, AclSize);
1061     if (!Acl)
1062     {
1063         ERR("WL: HeapAlloc() failed\n");
1064         goto cleanup;
1065     }
1066 
1067     /* Initialize ACL */
1068     if (!InitializeAcl(Acl, AclSize, ACL_REVISION))
1069     {
1070         ERR("WL: InitializeAcl() failed (error %lu)\n", GetLastError());
1071         goto cleanup;
1072     }
1073 
1074     /* Add full desktop access ACE for winlogon */
1075     if (!AddAccessAllowedAce(Acl, ACL_REVISION, DESKTOP_ALL, WinlogonSid))
1076     {
1077         ERR("WL: AddAccessAllowedAce() failed (error %lu)\n", GetLastError());
1078         goto cleanup;
1079     }
1080 
1081     /* Add full desktop access ACE for a user (if provided) */
1082     if (UserSid && !AddAccessAllowedAce(Acl, ACL_REVISION, DESKTOP_ALL, UserSid))
1083     {
1084         ERR("WL: AddAccessAllowedAce() failed (error %lu)\n", GetLastError());
1085         goto cleanup;
1086     }
1087 
1088     /* Initialize new security descriptor */
1089     DesktopSd = HeapAlloc(GetProcessHeap(), 0, SECURITY_DESCRIPTOR_MIN_LENGTH);
1090     if (!InitializeSecurityDescriptor(DesktopSd, SECURITY_DESCRIPTOR_REVISION))
1091     {
1092         ERR("WL: InitializeSecurityDescriptor() failed (error %lu)\n", GetLastError());
1093         goto cleanup;
1094     }
1095 
1096     /* Add ACL to the security descriptor */
1097     if (!SetSecurityDescriptorDacl(DesktopSd, TRUE, Acl, FALSE))
1098     {
1099         ERR("WL: SetSecurityDescriptorDacl() failed (error %lu)\n", GetLastError());
1100         goto cleanup;
1101     }
1102 
1103     /* Apply security to the window station */
1104     SecurityInformation = DACL_SECURITY_INFORMATION;
1105     if (!SetUserObjectSecurity(Desktop, &SecurityInformation, DesktopSd))
1106     {
1107         ERR("WL: SetUserObjectSecurity() failed (error %lu)\n", GetLastError());
1108         goto cleanup;
1109     }
1110 
1111     /* Indicate success */
1112     Ret = TRUE;
1113 
1114 cleanup:
1115     /* Free allocated stuff */
1116     if (Acl) HeapFree(GetProcessHeap(), 0, Acl);
1117     if (DesktopSd) HeapFree(GetProcessHeap(), 0, DesktopSd);
1118 
1119     return Ret;
1120 }
1121 
1122 BOOL
1123 CreateWindowStationAndDesktops(
1124     IN OUT PWLSESSION Session)
1125 {
1126     BYTE LocalSystemBuffer[SECURITY_MAX_SID_SIZE];
1127     BYTE InteractiveBuffer[SECURITY_MAX_SID_SIZE];
1128     PSID pLocalSystemSid = (PSID)&LocalSystemBuffer;
1129     PSID pInteractiveSid = (PSID)InteractiveBuffer;
1130     DWORD SidSize, AclSize;
1131     PACL pDefaultAcl = NULL;
1132     PACL pUserDesktopAcl = NULL;
1133     SECURITY_DESCRIPTOR DefaultSecurityDescriptor;
1134     SECURITY_ATTRIBUTES DefaultSecurity;
1135     SECURITY_DESCRIPTOR UserDesktopSecurityDescriptor;
1136     SECURITY_ATTRIBUTES UserDesktopSecurity;
1137     BOOL ret = FALSE;
1138 
1139     /*
1140      * Prepare information for ACLs we will apply
1141      */
1142     SidSize = SECURITY_MAX_SID_SIZE;
1143     if (!CreateWellKnownSid(WinLocalSystemSid, NULL, pLocalSystemSid, &SidSize))
1144     {
1145         ERR("WL: CreateWellKnownSid() failed (error %lu)\n", GetLastError());
1146         goto cleanup;
1147     }
1148     SidSize = SECURITY_MAX_SID_SIZE;
1149     if (!CreateWellKnownSid(WinInteractiveSid, NULL, pInteractiveSid, &SidSize))
1150     {
1151         ERR("WL: CreateWellKnownSid() failed (error %lu)\n", GetLastError());
1152         goto cleanup;
1153     }
1154 
1155     AclSize = sizeof(ACL)
1156         + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(pLocalSystemSid)
1157         + FIELD_OFFSET(ACCESS_ALLOWED_ACE, SidStart) + GetLengthSid(pInteractiveSid);
1158     pDefaultAcl = HeapAlloc(GetProcessHeap(), 0, AclSize);
1159     pUserDesktopAcl = HeapAlloc(GetProcessHeap(), 0, AclSize);
1160     if (!pDefaultAcl || !pUserDesktopAcl)
1161     {
1162         ERR("WL: HeapAlloc() failed\n");
1163         goto cleanup;
1164     }
1165 
1166     if (!InitializeAcl(pDefaultAcl, AclSize, ACL_REVISION)
1167      || !InitializeAcl(pUserDesktopAcl, AclSize, ACL_REVISION))
1168     {
1169         ERR("WL: InitializeAcl() failed (error %lu)\n", GetLastError());
1170         goto cleanup;
1171     }
1172 
1173     /*
1174      * Create default ACL (window station, winlogon desktop, screen saver desktop)
1175      */
1176     if (!AddAccessAllowedAce(pDefaultAcl, ACL_REVISION, GENERIC_ALL, pLocalSystemSid)
1177      || !AddAccessAllowedAce(pDefaultAcl, ACL_REVISION, GENERIC_READ, pInteractiveSid))
1178     {
1179         ERR("WL: AddAccessAllowedAce() failed (error %lu)\n", GetLastError());
1180         goto cleanup;
1181     }
1182 
1183     /*
1184      * Create the default security descriptor
1185      */
1186     if (!InitializeSecurityDescriptor(&DefaultSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
1187     {
1188         ERR("WL: InitializeSecurityDescriptor() failed (error %lu)\n", GetLastError());
1189         goto cleanup;
1190     }
1191 
1192     if (!SetSecurityDescriptorDacl(&DefaultSecurityDescriptor, TRUE, pDefaultAcl, FALSE))
1193     {
1194         ERR("WL: SetSecurityDescriptorDacl() failed (error %lu)\n", GetLastError());
1195         goto cleanup;
1196     }
1197 
1198     DefaultSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
1199     DefaultSecurity.lpSecurityDescriptor = &DefaultSecurityDescriptor;
1200     DefaultSecurity.bInheritHandle = TRUE;
1201 
1202     /*
1203      * Create user desktop ACL
1204      */
1205     if (!AddAccessAllowedAce(pUserDesktopAcl, ACL_REVISION, GENERIC_ALL, pLocalSystemSid)
1206      || !AddAccessAllowedAce(pUserDesktopAcl, ACL_REVISION, GENERIC_ALL, pInteractiveSid))
1207     {
1208         ERR("WL: AddAccessAllowedAce() failed (error %lu)\n", GetLastError());
1209         goto cleanup;
1210     }
1211 
1212     /*
1213      * Create the user desktop security descriptor
1214      */
1215     if (!InitializeSecurityDescriptor(&UserDesktopSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION))
1216     {
1217         ERR("WL: InitializeSecurityDescriptor() failed (error %lu)\n", GetLastError());
1218         goto cleanup;
1219     }
1220 
1221     if (!SetSecurityDescriptorDacl(&UserDesktopSecurityDescriptor, TRUE, pUserDesktopAcl, FALSE))
1222     {
1223         ERR("WL: SetSecurityDescriptorDacl() failed (error %lu)\n", GetLastError());
1224         goto cleanup;
1225     }
1226 
1227     UserDesktopSecurity.nLength = sizeof(SECURITY_ATTRIBUTES);
1228     UserDesktopSecurity.lpSecurityDescriptor = &UserDesktopSecurityDescriptor;
1229     UserDesktopSecurity.bInheritHandle = TRUE;
1230 
1231     /*
1232      * Create the interactive window station
1233      */
1234     Session->InteractiveWindowStationName = L"WinSta0";
1235     Session->InteractiveWindowStation = CreateWindowStationW(
1236         Session->InteractiveWindowStationName,
1237         0,
1238         MAXIMUM_ALLOWED,
1239         &DefaultSecurity);
1240     if (!Session->InteractiveWindowStation)
1241     {
1242         ERR("WL: Failed to create window station (%lu)\n", GetLastError());
1243         goto cleanup;
1244     }
1245     if (!SetProcessWindowStation(Session->InteractiveWindowStation))
1246     {
1247         ERR("WL: SetProcessWindowStation() failed (error %lu)\n", GetLastError());
1248         goto cleanup;
1249     }
1250 
1251     /*
1252      * Create the application desktop
1253      */
1254     Session->ApplicationDesktop = CreateDesktopW(
1255         L"Default",
1256         NULL,
1257         NULL,
1258         0, /* FIXME: Add DF_ALLOWOTHERACCOUNTHOOK flag? */
1259         MAXIMUM_ALLOWED,
1260         &UserDesktopSecurity);
1261     if (!Session->ApplicationDesktop)
1262     {
1263         ERR("WL: Failed to create Default desktop (%lu)\n", GetLastError());
1264         goto cleanup;
1265     }
1266 
1267     /*
1268      * Create the winlogon desktop
1269      */
1270     Session->WinlogonDesktop = CreateDesktopW(
1271         L"Winlogon",
1272         NULL,
1273         NULL,
1274         0,
1275         MAXIMUM_ALLOWED,
1276         &DefaultSecurity);
1277     if (!Session->WinlogonDesktop)
1278     {
1279         ERR("WL: Failed to create Winlogon desktop (%lu)\n", GetLastError());
1280         goto cleanup;
1281     }
1282 
1283     /*
1284      * Create the screen saver desktop
1285      */
1286     Session->ScreenSaverDesktop = CreateDesktopW(
1287         L"Screen-Saver",
1288         NULL,
1289         NULL,
1290         0,
1291         MAXIMUM_ALLOWED,
1292         &DefaultSecurity);
1293     if(!Session->ScreenSaverDesktop)
1294     {
1295         ERR("WL: Failed to create Screen-Saver desktop (%lu)\n", GetLastError());
1296         goto cleanup;
1297     }
1298 
1299     /*
1300      * Switch to winlogon desktop
1301     */
1302     if (!SetThreadDesktop(Session->WinlogonDesktop) ||
1303         !SwitchDesktop(Session->WinlogonDesktop))
1304     {
1305         ERR("WL: Cannot switch to Winlogon desktop (%lu)\n", GetLastError());
1306         goto cleanup;
1307     }
1308 
1309     ret = TRUE;
1310 
1311 cleanup:
1312     if (!ret)
1313     {
1314         if (Session->ApplicationDesktop)
1315         {
1316             CloseDesktop(Session->ApplicationDesktop);
1317             Session->ApplicationDesktop = NULL;
1318         }
1319         if (Session->WinlogonDesktop)
1320         {
1321             CloseDesktop(Session->WinlogonDesktop);
1322             Session->WinlogonDesktop = NULL;
1323         }
1324         if (Session->ScreenSaverDesktop)
1325         {
1326             CloseDesktop(Session->ScreenSaverDesktop);
1327             Session->ScreenSaverDesktop = NULL;
1328         }
1329         if (Session->InteractiveWindowStation)
1330         {
1331             CloseWindowStation(Session->InteractiveWindowStation);
1332             Session->InteractiveWindowStation = NULL;
1333         }
1334     }
1335     HeapFree(GetProcessHeap(), 0, pDefaultAcl);
1336     HeapFree(GetProcessHeap(), 0, pUserDesktopAcl);
1337     return ret;
1338 }
1339