xref: /reactos/dll/win32/msgina/gui.c (revision 803b5e13)
1 /*
2  * PROJECT:         ReactOS msgina.dll
3  * FILE:            dll/win32/msgina/gui.c
4  * PURPOSE:         ReactOS Logon GINA DLL
5  * PROGRAMMERS:     Herv� Poussineau (hpoussin@reactos.org)
6  *                  Katayama Hirofumi MZ (katayama.hirofumi.mz@gmail.com)
7  */
8 
9 #include "msgina.h"
10 
11 #include <wingdi.h>
12 #include <winnls.h>
13 #include <winreg.h>
14 
15 typedef struct _DISPLAYSTATUSMSG
16 {
17     PGINA_CONTEXT Context;
18     HDESK hDesktop;
19     DWORD dwOptions;
20     PWSTR pTitle;
21     PWSTR pMessage;
22     HANDLE StartupEvent;
23 } DISPLAYSTATUSMSG, *PDISPLAYSTATUSMSG;
24 
25 typedef struct _LEGALNOTICEDATA
26 {
27     LPWSTR pszCaption;
28     LPWSTR pszText;
29 } LEGALNOTICEDATA, *PLEGALNOTICEDATA;
30 
31 typedef struct _DLG_DATA
32 {
33     PGINA_CONTEXT pgContext;
34     HBITMAP hLogoBitmap;
35     HBITMAP hBarBitmap;
36     UINT_PTR TimerID;
37     DWORD BarCounter;
38     DWORD LogoWidth;
39     DWORD LogoHeight;
40     DWORD BarWidth;
41     DWORD BarHeight;
42 } DLG_DATA, *PDLG_DATA;
43 
44 static PDLG_DATA
45 DlgData_Create(HWND hwndDlg, PGINA_CONTEXT pgContext)
46 {
47     PDLG_DATA pDlgData = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*pDlgData));
48     if (pDlgData)
49     {
50         pDlgData->pgContext = pgContext;
51         SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pDlgData);
52     }
53     return pDlgData;
54 }
55 
56 static BOOL
57 DlgData_LoadBitmaps(PDLG_DATA pDlgData)
58 {
59     BITMAP bm;
60 
61     if (!pDlgData)
62         return FALSE;
63 
64     pDlgData->hLogoBitmap = LoadImageW(pDlgData->pgContext->hDllInstance,
65                                        MAKEINTRESOURCEW(IDI_ROSLOGO), IMAGE_BITMAP,
66                                        0, 0, LR_DEFAULTCOLOR);
67     GetObject(pDlgData->hLogoBitmap, sizeof(bm), &bm);
68     pDlgData->LogoWidth = bm.bmWidth;
69     pDlgData->LogoHeight = bm.bmHeight;
70 
71     pDlgData->hBarBitmap = LoadImageW(hDllInstance, MAKEINTRESOURCEW(IDI_BAR),
72                                       IMAGE_BITMAP, 0, 0, LR_DEFAULTCOLOR);
73     GetObject(pDlgData->hBarBitmap, sizeof(bm), &bm);
74     pDlgData->BarWidth = bm.bmWidth;
75     pDlgData->BarHeight = bm.bmHeight;
76 
77     return (pDlgData->hLogoBitmap != NULL && pDlgData->hBarBitmap != NULL);
78 }
79 
80 static void
81 DlgData_Destroy(PDLG_DATA pDlgData)
82 {
83     if (!pDlgData)
84         return;
85 
86     DeleteObject(pDlgData->hLogoBitmap);
87     DeleteObject(pDlgData->hBarBitmap);
88     HeapFree(GetProcessHeap(), 0, pDlgData);
89 }
90 
91 static BOOL
92 GUIInitialize(
93     IN OUT PGINA_CONTEXT pgContext)
94 {
95     TRACE("GUIInitialize(%p)\n", pgContext);
96     return TRUE;
97 }
98 
99 static
100 VOID
101 SetWelcomeText(HWND hWnd)
102 {
103     PWCHAR pBuffer = NULL, p;
104     HKEY hKey;
105     DWORD BufSize, dwType, dwWelcomeSize, dwTitleLength;
106     LONG rc;
107 
108     TRACE("SetWelcomeText(%p)\n", hWnd);
109 
110     /* Open the Winlogon key */
111     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
112                        L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
113                        0,
114                        KEY_QUERY_VALUE,
115                        &hKey);
116     if (rc != ERROR_SUCCESS)
117     {
118         WARN("RegOpenKeyExW() failed with error %lu\n", rc);
119         return;
120     }
121 
122     /* Get the size of the Welcome value */
123     dwWelcomeSize = 0;
124     rc = RegQueryValueExW(hKey,
125                           L"Welcome",
126                           NULL,
127                           &dwType,
128                           NULL,
129                           &dwWelcomeSize);
130     if (rc == ERROR_FILE_NOT_FOUND || dwWelcomeSize == 0 || dwType != REG_SZ)
131         goto done;
132 
133     dwTitleLength = GetWindowTextLengthW(hWnd);
134     BufSize = dwWelcomeSize + ((dwTitleLength + 1) * sizeof(WCHAR));
135 
136     pBuffer = HeapAlloc(GetProcessHeap(), 0, BufSize);
137     if (pBuffer == NULL)
138         goto done;
139 
140     GetWindowTextW(hWnd, pBuffer, BufSize / sizeof(WCHAR));
141     wcscat(pBuffer, L" ");
142     p = &pBuffer[dwTitleLength + 1];
143 
144     RegQueryValueExW(hKey,
145                      L"Welcome",
146                      NULL,
147                      &dwType,
148                      (PBYTE)p,
149                      &dwWelcomeSize);
150 
151     SetWindowText(hWnd, pBuffer);
152 
153 done:
154     if (pBuffer != NULL)
155         HeapFree(GetProcessHeap(), 0, pBuffer);
156 
157     RegCloseKey(hKey);
158 }
159 
160 
161 static INT_PTR CALLBACK
162 StatusDialogProc(
163     IN HWND hwndDlg,
164     IN UINT uMsg,
165     IN WPARAM wParam,
166     IN LPARAM lParam)
167 {
168     PDLG_DATA pDlgData;
169     UNREFERENCED_PARAMETER(wParam);
170 
171     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
172 
173     switch (uMsg)
174     {
175         case WM_INITDIALOG:
176         {
177             PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lParam;
178             if (!msg)
179                 return FALSE;
180 
181             msg->Context->hStatusWindow = hwndDlg;
182 
183             if (msg->pTitle)
184                 SetWindowTextW(hwndDlg, msg->pTitle);
185             SetDlgItemTextW(hwndDlg, IDC_STATUS_MESSAGE, msg->pMessage);
186             SetEvent(msg->StartupEvent);
187 
188             pDlgData = DlgData_Create(hwndDlg, msg->Context);
189             if (pDlgData == NULL)
190                 return FALSE;
191 
192             if (DlgData_LoadBitmaps(pDlgData))
193             {
194                 pDlgData->TimerID = SetTimer(hwndDlg, -1, 20, NULL);
195             }
196             return TRUE;
197         }
198 
199         case WM_TIMER:
200         {
201             if (pDlgData && pDlgData->hBarBitmap)
202             {
203                 /*
204                  * Default rotation bar image width is 413 (same as logo)
205                  * We can divide 413 by 7 without remainder
206                  */
207                 pDlgData->BarCounter = (pDlgData->BarCounter + 7) % pDlgData->BarWidth;
208                 InvalidateRect(hwndDlg, NULL, FALSE);
209                 UpdateWindow(hwndDlg);
210             }
211             return TRUE;
212         }
213 
214         case WM_DRAWITEM:
215         {
216             LPDRAWITEMSTRUCT lpDis = (LPDRAWITEMSTRUCT)lParam;
217 
218             if (lpDis->CtlID != IDC_BAR)
219             {
220                 return FALSE;
221             }
222 
223             if (pDlgData && pDlgData->hBarBitmap)
224             {
225                 HDC hdcMem;
226                 HGDIOBJ hOld;
227                 DWORD off = pDlgData->BarCounter;
228                 DWORD iw = pDlgData->BarWidth;
229                 DWORD ih = pDlgData->BarHeight;
230 
231                 hdcMem = CreateCompatibleDC(lpDis->hDC);
232                 hOld = SelectObject(hdcMem, pDlgData->hBarBitmap);
233                 BitBlt(lpDis->hDC, off, 0, iw - off, ih, hdcMem, 0, 0, SRCCOPY);
234                 BitBlt(lpDis->hDC, 0, 0, off, ih, hdcMem, iw - off, 0, SRCCOPY);
235                 SelectObject(hdcMem, hOld);
236                 DeleteDC(hdcMem);
237 
238                 return TRUE;
239             }
240             return FALSE;
241         }
242 
243         case WM_DESTROY:
244         {
245             if (pDlgData && pDlgData->hBarBitmap)
246             {
247                 KillTimer(hwndDlg, pDlgData->TimerID);
248             }
249             DlgData_Destroy(pDlgData);
250             return TRUE;
251         }
252     }
253     return FALSE;
254 }
255 
256 static DWORD WINAPI
257 StartupWindowThread(LPVOID lpParam)
258 {
259     HDESK hDesk;
260     PDISPLAYSTATUSMSG msg = (PDISPLAYSTATUSMSG)lpParam;
261 
262     /* When SetThreadDesktop is called the system closes the desktop handle when needed
263        so we have to create a new handle because this handle may still be in use by winlogon  */
264     if (!DuplicateHandle (  GetCurrentProcess(),
265                             msg->hDesktop,
266                             GetCurrentProcess(),
267                             (HANDLE*)&hDesk,
268                             0,
269                             FALSE,
270                             DUPLICATE_SAME_ACCESS))
271     {
272         ERR("Duplicating handle failed!\n");
273         HeapFree(GetProcessHeap(), 0, lpParam);
274         return FALSE;
275     }
276 
277     if(!SetThreadDesktop(hDesk))
278     {
279         ERR("Setting thread desktop failed!\n");
280         HeapFree(GetProcessHeap(), 0, lpParam);
281         return FALSE;
282     }
283 
284     DialogBoxParamW(
285         hDllInstance,
286         MAKEINTRESOURCEW(IDD_STATUS),
287         GetDesktopWindow(),
288         StatusDialogProc,
289         (LPARAM)lpParam);
290 
291     HeapFree(GetProcessHeap(), 0, lpParam);
292     return TRUE;
293 }
294 
295 static BOOL
296 GUIDisplayStatusMessage(
297     IN PGINA_CONTEXT pgContext,
298     IN HDESK hDesktop,
299     IN DWORD dwOptions,
300     IN PWSTR pTitle,
301     IN PWSTR pMessage)
302 {
303     PDISPLAYSTATUSMSG msg;
304     HANDLE Thread;
305     DWORD ThreadId;
306 
307     TRACE("GUIDisplayStatusMessage(%ws)\n", pMessage);
308 
309     if (!pgContext->hStatusWindow)
310     {
311         /*
312          * If everything goes correctly, 'msg' is freed
313          * by the 'StartupWindowThread' thread.
314          */
315         msg = (PDISPLAYSTATUSMSG)HeapAlloc(GetProcessHeap(),
316                                            HEAP_ZERO_MEMORY,
317                                            sizeof(*msg));
318         if(!msg)
319             return FALSE;
320 
321         msg->Context = pgContext;
322         msg->dwOptions = dwOptions;
323         msg->pTitle = pTitle;
324         msg->pMessage = pMessage;
325         msg->hDesktop = hDesktop;
326 
327         msg->StartupEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
328 
329         if (!msg->StartupEvent)
330         {
331             HeapFree(GetProcessHeap(), 0, msg);
332             return FALSE;
333         }
334 
335         Thread = CreateThread(NULL,
336                               0,
337                               StartupWindowThread,
338                               (PVOID)msg,
339                               0,
340                               &ThreadId);
341         if (Thread)
342         {
343             /* 'msg' will be freed by 'StartupWindowThread' */
344 
345             CloseHandle(Thread);
346             WaitForSingleObject(msg->StartupEvent, INFINITE);
347             CloseHandle(msg->StartupEvent);
348             return TRUE;
349         }
350         else
351         {
352             /*
353              * The 'StartupWindowThread' thread couldn't be created,
354              * so we need to free the allocated 'msg'.
355              */
356             HeapFree(GetProcessHeap(), 0, msg);
357         }
358 
359         return FALSE;
360     }
361 
362     if (pTitle)
363         SetWindowTextW(pgContext->hStatusWindow, pTitle);
364 
365     SetDlgItemTextW(pgContext->hStatusWindow, IDC_STATUS_MESSAGE, pMessage);
366 
367     return TRUE;
368 }
369 
370 static BOOL
371 GUIRemoveStatusMessage(
372     IN PGINA_CONTEXT pgContext)
373 {
374     if (pgContext->hStatusWindow)
375     {
376         EndDialog(pgContext->hStatusWindow, 0);
377         pgContext->hStatusWindow = NULL;
378     }
379 
380     return TRUE;
381 }
382 
383 static INT_PTR CALLBACK
384 WelcomeDialogProc(
385     IN HWND hwndDlg,
386     IN UINT uMsg,
387     IN WPARAM wParam,
388     IN LPARAM lParam)
389 {
390     PDLG_DATA pDlgData;
391 
392     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
393 
394     switch (uMsg)
395     {
396         case WM_INITDIALOG:
397         {
398             pDlgData = DlgData_Create(hwndDlg, (PGINA_CONTEXT)lParam);
399             if (pDlgData == NULL)
400                 return FALSE;
401 
402             DlgData_LoadBitmaps(pDlgData);
403             return TRUE;
404         }
405 
406         case WM_PAINT:
407         {
408             PAINTSTRUCT ps;
409             if (pDlgData && pDlgData->hLogoBitmap)
410             {
411                 BeginPaint(hwndDlg, &ps);
412                 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pDlgData->hLogoBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
413                 EndPaint(hwndDlg, &ps);
414             }
415             return TRUE;
416         }
417         case WM_DESTROY:
418         {
419             DlgData_Destroy(pDlgData);
420             return TRUE;
421         }
422     }
423     return FALSE;
424 }
425 
426 static VOID
427 GUIDisplaySASNotice(
428     IN OUT PGINA_CONTEXT pgContext)
429 {
430     TRACE("GUIDisplaySASNotice()\n");
431 
432     /* Display the notice window */
433     pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
434                                             pgContext->hDllInstance,
435                                             MAKEINTRESOURCEW(IDD_WELCOME),
436                                             GetDesktopWindow(),
437                                             WelcomeDialogProc,
438                                             (LPARAM)pgContext);
439 }
440 
441 /* Get the text contained in a textbox. Allocates memory in pText
442  * to contain the text. Returns TRUE in case of success */
443 static BOOL
444 GetTextboxText(
445     IN HWND hwndDlg,
446     IN INT TextboxId,
447     OUT LPWSTR *pText)
448 {
449     LPWSTR Text;
450     int Count;
451 
452     Count = GetWindowTextLength(GetDlgItem(hwndDlg, TextboxId));
453     Text = HeapAlloc(GetProcessHeap(), 0, (Count + 1) * sizeof(WCHAR));
454     if (!Text)
455         return FALSE;
456     if (Count != GetWindowTextW(GetDlgItem(hwndDlg, TextboxId), Text, Count + 1))
457     {
458         HeapFree(GetProcessHeap(), 0, Text);
459         return FALSE;
460     }
461     *pText = Text;
462     return TRUE;
463 }
464 
465 
466 static
467 INT
468 ResourceMessageBox(
469     IN PGINA_CONTEXT pgContext,
470     IN HWND hwnd,
471     IN UINT uType,
472     IN UINT uCaption,
473     IN UINT uText)
474 {
475     WCHAR szCaption[256];
476     WCHAR szText[256];
477 
478     LoadStringW(pgContext->hDllInstance, uCaption, szCaption, _countof(szCaption));
479     LoadStringW(pgContext->hDllInstance, uText, szText, _countof(szText));
480 
481     return pgContext->pWlxFuncs->WlxMessageBox(pgContext->hWlx,
482                                                hwnd,
483                                                szText,
484                                                szCaption,
485                                                uType);
486 }
487 
488 
489 static
490 BOOL
491 DoChangePassword(
492     IN PGINA_CONTEXT pgContext,
493     IN HWND hwndDlg)
494 {
495     WCHAR UserName[256];
496     WCHAR Domain[256];
497     WCHAR OldPassword[256];
498     WCHAR NewPassword1[256];
499     WCHAR NewPassword2[256];
500     PMSV1_0_CHANGEPASSWORD_REQUEST RequestBuffer = NULL;
501     PMSV1_0_CHANGEPASSWORD_RESPONSE ResponseBuffer = NULL;
502     ULONG RequestBufferSize;
503     ULONG ResponseBufferSize = 0;
504     LPWSTR Ptr;
505     BOOL res = FALSE;
506     NTSTATUS ProtocolStatus;
507     NTSTATUS Status;
508 
509     GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_USERNAME, UserName, _countof(UserName));
510     GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_DOMAIN, Domain, _countof(Domain));
511     GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_OLDPWD, OldPassword, _countof(OldPassword));
512     GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD1, NewPassword1, _countof(NewPassword1));
513     GetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD2, NewPassword2, _countof(NewPassword2));
514 
515     /* Compare the two passwords and fail if they do not match */
516     if (wcscmp(NewPassword1, NewPassword2) != 0)
517     {
518         ResourceMessageBox(pgContext,
519                            hwndDlg,
520                            MB_OK | MB_ICONEXCLAMATION,
521                            IDS_CHANGEPWDTITLE,
522                            IDS_NONMATCHINGPASSWORDS);
523         return FALSE;
524     }
525 
526     /* Calculate the request buffer size */
527     RequestBufferSize = sizeof(MSV1_0_CHANGEPASSWORD_REQUEST) +
528                         ((wcslen(Domain) + 1) * sizeof(WCHAR)) +
529                         ((wcslen(UserName) + 1) * sizeof(WCHAR)) +
530                         ((wcslen(OldPassword) + 1) * sizeof(WCHAR)) +
531                         ((wcslen(NewPassword1) + 1) * sizeof(WCHAR));
532 
533     /* Allocate the request buffer */
534     RequestBuffer = HeapAlloc(GetProcessHeap(),
535                               HEAP_ZERO_MEMORY,
536                               RequestBufferSize);
537     if (RequestBuffer == NULL)
538     {
539         ERR("HeapAlloc failed\n");
540         return FALSE;
541     }
542 
543     /* Initialize the request buffer */
544     RequestBuffer->MessageType = MsV1_0ChangePassword;
545     RequestBuffer->Impersonating = TRUE;
546 
547     Ptr = (LPWSTR)((ULONG_PTR)RequestBuffer + sizeof(MSV1_0_CHANGEPASSWORD_REQUEST));
548 
549     /* Pack the domain name */
550     RequestBuffer->DomainName.Length = wcslen(Domain) * sizeof(WCHAR);
551     RequestBuffer->DomainName.MaximumLength = RequestBuffer->DomainName.Length + sizeof(WCHAR);
552     RequestBuffer->DomainName.Buffer = Ptr;
553 
554     RtlCopyMemory(RequestBuffer->DomainName.Buffer,
555                   Domain,
556                   RequestBuffer->DomainName.MaximumLength);
557 
558     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->DomainName.MaximumLength);
559 
560     /* Pack the user name */
561     RequestBuffer->AccountName.Length = wcslen(UserName) * sizeof(WCHAR);
562     RequestBuffer->AccountName.MaximumLength = RequestBuffer->AccountName.Length + sizeof(WCHAR);
563     RequestBuffer->AccountName.Buffer = Ptr;
564 
565     RtlCopyMemory(RequestBuffer->AccountName.Buffer,
566                   UserName,
567                   RequestBuffer->AccountName.MaximumLength);
568 
569     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->AccountName.MaximumLength);
570 
571     /* Pack the old password */
572     RequestBuffer->OldPassword.Length = wcslen(OldPassword) * sizeof(WCHAR);
573     RequestBuffer->OldPassword.MaximumLength = RequestBuffer->OldPassword.Length + sizeof(WCHAR);
574     RequestBuffer->OldPassword.Buffer = Ptr;
575 
576     RtlCopyMemory(RequestBuffer->OldPassword.Buffer,
577                   OldPassword,
578                   RequestBuffer->OldPassword.MaximumLength);
579 
580     Ptr = (LPWSTR)((ULONG_PTR)Ptr + RequestBuffer->OldPassword.MaximumLength);
581 
582     /* Pack the new password */
583     RequestBuffer->NewPassword.Length = wcslen(NewPassword1) * sizeof(WCHAR);
584     RequestBuffer->NewPassword.MaximumLength = RequestBuffer->NewPassword.Length + sizeof(WCHAR);
585     RequestBuffer->NewPassword.Buffer = Ptr;
586 
587     RtlCopyMemory(RequestBuffer->NewPassword.Buffer,
588                   NewPassword1,
589                   RequestBuffer->NewPassword.MaximumLength);
590 
591     /* Connect to the LSA server */
592     if (ConnectToLsa(pgContext) != ERROR_SUCCESS)
593     {
594         ERR("ConnectToLsa() failed\n");
595         goto done;
596     }
597 
598     /* Call the authentication package */
599     Status = LsaCallAuthenticationPackage(pgContext->LsaHandle,
600                                           pgContext->AuthenticationPackage,
601                                           RequestBuffer,
602                                           RequestBufferSize,
603                                           (PVOID*)&ResponseBuffer,
604                                           &ResponseBufferSize,
605                                           &ProtocolStatus);
606     if (!NT_SUCCESS(Status))
607     {
608         ERR("LsaCallAuthenticationPackage failed (Status 0x%08lx)\n", Status);
609         goto done;
610     }
611 
612     if (!NT_SUCCESS(ProtocolStatus))
613     {
614         TRACE("LsaCallAuthenticationPackage failed (ProtocolStatus 0x%08lx)\n", ProtocolStatus);
615         goto done;
616     }
617 
618     res = TRUE;
619 
620     ResourceMessageBox(pgContext,
621                        hwndDlg,
622                        MB_OK | MB_ICONINFORMATION,
623                        IDS_CHANGEPWDTITLE,
624                        IDS_PASSWORDCHANGED);
625 
626     if ((wcscmp(UserName, pgContext->UserName) == 0) &&
627         (wcscmp(Domain, pgContext->DomainName) == 0) &&
628         (wcscmp(OldPassword, pgContext->Password) == 0))
629     {
630         ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
631         wcscpy(pgContext->Password, NewPassword1);
632     }
633 
634 done:
635     if (RequestBuffer != NULL)
636         HeapFree(GetProcessHeap(), 0, RequestBuffer);
637 
638     if (ResponseBuffer != NULL)
639         LsaFreeReturnBuffer(ResponseBuffer);
640 
641     return res;
642 }
643 
644 
645 static INT_PTR CALLBACK
646 ChangePasswordDialogProc(
647     IN HWND hwndDlg,
648     IN UINT uMsg,
649     IN WPARAM wParam,
650     IN LPARAM lParam)
651 {
652     PGINA_CONTEXT pgContext;
653 
654     pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
655 
656     switch (uMsg)
657     {
658         case WM_INITDIALOG:
659         {
660             pgContext = (PGINA_CONTEXT)lParam;
661             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
662 
663             SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_USERNAME, pgContext->UserName);
664             SendDlgItemMessageW(hwndDlg, IDC_CHANGEPWD_DOMAIN, CB_ADDSTRING, 0, (LPARAM)pgContext->DomainName);
665             SendDlgItemMessageW(hwndDlg, IDC_CHANGEPWD_DOMAIN, CB_SETCURSEL, 0, 0);
666             SetFocus(GetDlgItem(hwndDlg, IDC_CHANGEPWD_OLDPWD));
667             return TRUE;
668         }
669 
670         case WM_COMMAND:
671             switch (LOWORD(wParam))
672             {
673                 case IDOK:
674                     if (DoChangePassword(pgContext, hwndDlg))
675                     {
676                         EndDialog(hwndDlg, TRUE);
677                     }
678                     else
679                     {
680                         SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD1, NULL);
681                         SetDlgItemTextW(hwndDlg, IDC_CHANGEPWD_NEWPWD2, NULL);
682                         SetFocus(GetDlgItem(hwndDlg, IDC_CHANGEPWD_OLDPWD));
683                     }
684                     return TRUE;
685 
686                 case IDCANCEL:
687                     EndDialog(hwndDlg, FALSE);
688                     return TRUE;
689             }
690             break;
691 
692         case WM_CLOSE:
693             EndDialog(hwndDlg, FALSE);
694             return TRUE;
695     }
696 
697     return FALSE;
698 }
699 
700 
701 static VOID
702 OnInitSecurityDlg(HWND hwnd,
703                   PGINA_CONTEXT pgContext)
704 {
705     WCHAR Buffer1[256];
706     WCHAR Buffer2[256];
707     WCHAR Buffer3[256];
708     WCHAR Buffer4[512];
709 
710     LoadStringW(pgContext->hDllInstance, IDS_LOGONMSG, Buffer1, _countof(Buffer1));
711 
712     wsprintfW(Buffer2, L"%s\\%s", pgContext->DomainName, pgContext->UserName);
713     wsprintfW(Buffer4, Buffer1, Buffer2);
714 
715     SetDlgItemTextW(hwnd, IDC_SECURITY_MESSAGE, Buffer4);
716 
717     LoadStringW(pgContext->hDllInstance, IDS_LOGONDATE, Buffer1, _countof(Buffer1));
718 
719     GetDateFormatW(LOCALE_USER_DEFAULT, DATE_SHORTDATE,
720                    (SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer2, _countof(Buffer2));
721 
722     GetTimeFormatW(LOCALE_USER_DEFAULT, 0,
723                    (SYSTEMTIME*)&pgContext->LogonTime, NULL, Buffer3, _countof(Buffer3));
724 
725     wsprintfW(Buffer4, Buffer1, Buffer2, Buffer3);
726 
727     SetDlgItemTextW(hwnd, IDC_SECURITY_LOGONDATE, Buffer4);
728 
729     if (pgContext->bAutoAdminLogon)
730         EnableWindow(GetDlgItem(hwnd, IDC_SECURITY_LOGOFF), FALSE);
731 }
732 
733 
734 static BOOL
735 OnChangePassword(
736     IN HWND hwnd,
737     IN PGINA_CONTEXT pgContext)
738 {
739     INT res;
740 
741     TRACE("OnChangePassword()\n");
742 
743     res = pgContext->pWlxFuncs->WlxDialogBoxParam(
744         pgContext->hWlx,
745         pgContext->hDllInstance,
746         MAKEINTRESOURCEW(IDD_CHANGEPWD),
747         hwnd,
748         ChangePasswordDialogProc,
749         (LPARAM)pgContext);
750 
751     TRACE("Result: %x\n", res);
752 
753     return FALSE;
754 }
755 
756 
757 static INT_PTR CALLBACK
758 LogOffDialogProc(
759     IN HWND hwndDlg,
760     IN UINT uMsg,
761     IN WPARAM wParam,
762     IN LPARAM lParam)
763 {
764     switch (uMsg)
765     {
766         case WM_INITDIALOG:
767             return TRUE;
768 
769         case WM_COMMAND:
770             switch (LOWORD(wParam))
771             {
772                 case IDYES:
773                     EndDialog(hwndDlg, IDYES);
774                     return TRUE;
775 
776                 case IDNO:
777                     EndDialog(hwndDlg, IDNO);
778                     return TRUE;
779             }
780             break;
781 
782         case WM_CLOSE:
783             EndDialog(hwndDlg, IDNO);
784             return TRUE;
785     }
786 
787     return FALSE;
788 }
789 
790 
791 static
792 INT
793 OnLogOff(
794     IN HWND hwndDlg,
795     IN PGINA_CONTEXT pgContext)
796 {
797     return pgContext->pWlxFuncs->WlxDialogBoxParam(
798         pgContext->hWlx,
799         pgContext->hDllInstance,
800         MAKEINTRESOURCEW(IDD_LOGOFF),
801         hwndDlg,
802         LogOffDialogProc,
803         (LPARAM)pgContext);
804 }
805 
806 
807 static
808 INT
809 OnShutDown(
810     IN HWND hwndDlg,
811     IN PGINA_CONTEXT pgContext)
812 {
813     INT ret;
814     DWORD ShutdownOptions;
815 
816     TRACE("OnShutDown(%p %p)\n", hwndDlg, pgContext);
817 
818     pgContext->nShutdownAction = GetDefaultShutdownSelState();
819     ShutdownOptions = GetDefaultShutdownOptions();
820 
821     if (pgContext->UserToken != NULL)
822     {
823         if (ImpersonateLoggedOnUser(pgContext->UserToken))
824         {
825             pgContext->nShutdownAction = LoadShutdownSelState();
826             ShutdownOptions = GetAllowedShutdownOptions();
827             RevertToSelf();
828         }
829         else
830         {
831             ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
832         }
833     }
834 
835     ret = ShutdownDialog(hwndDlg, ShutdownOptions, pgContext);
836 
837     if (ret == IDOK)
838     {
839         if (pgContext->UserToken != NULL)
840         {
841             if (ImpersonateLoggedOnUser(pgContext->UserToken))
842             {
843                 SaveShutdownSelState(pgContext->nShutdownAction);
844                 RevertToSelf();
845             }
846             else
847             {
848                 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError());
849             }
850         }
851     }
852 
853     return ret;
854 }
855 
856 
857 static INT_PTR CALLBACK
858 SecurityDialogProc(
859     IN HWND hwndDlg,
860     IN UINT uMsg,
861     IN WPARAM wParam,
862     IN LPARAM lParam)
863 {
864     PGINA_CONTEXT pgContext;
865 
866     pgContext = (PGINA_CONTEXT)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
867 
868     switch (uMsg)
869     {
870         case WM_INITDIALOG:
871         {
872             pgContext = (PGINA_CONTEXT)lParam;
873             SetWindowLongPtrW(hwndDlg, GWLP_USERDATA, (LONG_PTR)pgContext);
874 
875             SetWelcomeText(hwndDlg);
876 
877             OnInitSecurityDlg(hwndDlg, (PGINA_CONTEXT)lParam);
878             SetFocus(GetDlgItem(hwndDlg, IDNO));
879             return TRUE;
880         }
881 
882         case WM_COMMAND:
883         {
884             switch (LOWORD(wParam))
885             {
886                 case IDC_SECURITY_LOCK:
887                     EndDialog(hwndDlg, WLX_SAS_ACTION_LOCK_WKSTA);
888                     return TRUE;
889                 case IDC_SECURITY_LOGOFF:
890                     if (OnLogOff(hwndDlg, pgContext) == IDYES)
891                         EndDialog(hwndDlg, WLX_SAS_ACTION_LOGOFF);
892                     return TRUE;
893                 case IDC_SECURITY_SHUTDOWN:
894                     if (OnShutDown(hwndDlg, pgContext) == IDOK)
895                         EndDialog(hwndDlg, pgContext->nShutdownAction);
896                     return TRUE;
897                 case IDC_SECURITY_CHANGEPWD:
898                     if (OnChangePassword(hwndDlg, pgContext))
899                         EndDialog(hwndDlg, WLX_SAS_ACTION_PWD_CHANGED);
900                     return TRUE;
901                 case IDC_SECURITY_TASKMGR:
902                     EndDialog(hwndDlg, WLX_SAS_ACTION_TASKLIST);
903                     return TRUE;
904                 case IDCANCEL:
905                     EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
906                     return TRUE;
907             }
908             break;
909         }
910         case WM_CLOSE:
911         {
912             EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
913             return TRUE;
914         }
915     }
916 
917     return FALSE;
918 }
919 
920 static INT
921 GUILoggedOnSAS(
922     IN OUT PGINA_CONTEXT pgContext,
923     IN DWORD dwSasType)
924 {
925     INT result;
926 
927     TRACE("GUILoggedOnSAS()\n");
928 
929     if (dwSasType != WLX_SAS_TYPE_CTRL_ALT_DEL)
930     {
931         /* Nothing to do for WLX_SAS_TYPE_TIMEOUT ; the dialog will
932          * close itself thanks to the use of WlxDialogBoxParam */
933         return WLX_SAS_ACTION_NONE;
934     }
935 
936     pgContext->pWlxFuncs->WlxSwitchDesktopToWinlogon(
937         pgContext->hWlx);
938 
939     result = pgContext->pWlxFuncs->WlxDialogBoxParam(
940         pgContext->hWlx,
941         pgContext->hDllInstance,
942         MAKEINTRESOURCEW(IDD_SECURITY),
943         GetDesktopWindow(),
944         SecurityDialogProc,
945         (LPARAM)pgContext);
946 
947     if (result < WLX_SAS_ACTION_LOGON ||
948         result > WLX_SAS_ACTION_SWITCH_CONSOLE)
949     {
950         result = WLX_SAS_ACTION_NONE;
951     }
952 
953     if (result == WLX_SAS_ACTION_NONE)
954     {
955         pgContext->pWlxFuncs->WlxSwitchDesktopToUser(
956             pgContext->hWlx);
957     }
958 
959     return result;
960 }
961 
962 
963 static
964 BOOL
965 DoLogon(
966     IN HWND hwndDlg,
967     IN OUT PGINA_CONTEXT pgContext)
968 {
969     LPWSTR UserName = NULL;
970     LPWSTR Password = NULL;
971     LPWSTR Domain = NULL;
972     BOOL result = FALSE;
973     NTSTATUS Status, SubStatus = STATUS_SUCCESS;
974 
975     if (GetTextboxText(hwndDlg, IDC_LOGON_USERNAME, &UserName) && *UserName == '\0')
976         goto done;
977 
978     if (GetTextboxText(hwndDlg, IDC_LOGON_DOMAIN, &Domain) && *Domain == '\0')
979         goto done;
980 
981     if (!GetTextboxText(hwndDlg, IDC_LOGON_PASSWORD, &Password))
982         goto done;
983 
984     Status = DoLoginTasks(pgContext, UserName, Domain, Password, &SubStatus);
985     if (Status == STATUS_LOGON_FAILURE)
986     {
987         ResourceMessageBox(pgContext,
988                            hwndDlg,
989                            MB_OK | MB_ICONEXCLAMATION,
990                            IDS_LOGONTITLE,
991                            IDS_LOGONWRONGUSERORPWD);
992         goto done;
993     }
994     else if (Status == STATUS_ACCOUNT_RESTRICTION)
995     {
996         TRACE("DoLoginTasks failed! Status 0x%08lx  SubStatus 0x%08lx\n", Status, SubStatus);
997 
998         if (SubStatus == STATUS_ACCOUNT_DISABLED)
999         {
1000             ResourceMessageBox(pgContext,
1001                                hwndDlg,
1002                                MB_OK | MB_ICONEXCLAMATION,
1003                                IDS_LOGONTITLE,
1004                                IDS_LOGONUSERDISABLED);
1005             goto done;
1006         }
1007         else if (SubStatus == STATUS_ACCOUNT_LOCKED_OUT)
1008         {
1009             TRACE("Account locked!\n");
1010             ResourceMessageBox(pgContext,
1011                                hwndDlg,
1012                                MB_OK | MB_ICONERROR,
1013                                IDS_LOGONTITLE,
1014                                IDS_ACCOUNTLOCKED);
1015             goto done;
1016         }
1017         else if ((SubStatus == STATUS_PASSWORD_MUST_CHANGE) ||
1018                  (SubStatus == STATUS_PASSWORD_EXPIRED))
1019         {
1020             if (SubStatus == STATUS_PASSWORD_MUST_CHANGE)
1021                 ResourceMessageBox(pgContext,
1022                                    hwndDlg,
1023                                    MB_OK | MB_ICONSTOP,
1024                                    IDS_LOGONTITLE,
1025                                    IDS_PASSWORDMUSTCHANGE);
1026             else
1027                 ResourceMessageBox(pgContext,
1028                                    hwndDlg,
1029                                    MB_OK | MB_ICONSTOP,
1030                                    IDS_LOGONTITLE,
1031                                    IDS_PASSWORDEXPIRED);
1032 
1033             if (!OnChangePassword(hwndDlg,
1034                                   pgContext))
1035                 goto done;
1036 
1037             Status = DoLoginTasks(pgContext,
1038                                   pgContext->UserName,
1039                                   pgContext->DomainName,
1040                                   pgContext->Password,
1041                                   &SubStatus);
1042             if (!NT_SUCCESS(Status))
1043             {
1044                 TRACE("Login after password change failed! (Status 0x%08lx)\n", Status);
1045 
1046                 goto done;
1047             }
1048         }
1049         else if (SubStatus == STATUS_ACCOUNT_EXPIRED)
1050         {
1051             ResourceMessageBox(pgContext,
1052                                hwndDlg,
1053                                MB_OK | MB_ICONEXCLAMATION,
1054                                IDS_LOGONTITLE,
1055                                IDS_ACCOUNTEXPIRED);
1056         }
1057         else if (SubStatus == STATUS_INVALID_LOGON_HOURS)
1058         {
1059             ResourceMessageBox(pgContext,
1060                                hwndDlg,
1061                                MB_OK | MB_ICONERROR,
1062                                IDS_LOGONTITLE,
1063                                IDS_INVALIDLOGONHOURS);
1064             goto done;
1065         }
1066         else if (SubStatus == STATUS_INVALID_WORKSTATION)
1067         {
1068             ResourceMessageBox(pgContext,
1069                                hwndDlg,
1070                                MB_OK | MB_ICONERROR,
1071                                IDS_LOGONTITLE,
1072                                IDS_INVALIDWORKSTATION);
1073             goto done;
1074         }
1075         else
1076         {
1077             TRACE("Other error!\n");
1078             ResourceMessageBox(pgContext,
1079                                hwndDlg,
1080                                MB_OK | MB_ICONERROR,
1081                                IDS_LOGONTITLE,
1082                                IDS_ACCOUNTRESTRICTION);
1083             goto done;
1084         }
1085     }
1086     else if (!NT_SUCCESS(Status))
1087     {
1088         TRACE("DoLoginTasks failed! Status 0x%08lx\n", Status);
1089         goto done;
1090     }
1091 
1092     if (!CreateProfile(pgContext, UserName, Domain, Password))
1093     {
1094         ERR("Failed to create the profile!\n");
1095         goto done;
1096     }
1097 
1098     ZeroMemory(pgContext->Password, sizeof(pgContext->Password));
1099     wcscpy(pgContext->Password, Password);
1100 
1101     result = TRUE;
1102 
1103 done:
1104     pgContext->bAutoAdminLogon = FALSE;
1105 
1106     if (UserName != NULL)
1107         HeapFree(GetProcessHeap(), 0, UserName);
1108 
1109     if (Password != NULL)
1110         HeapFree(GetProcessHeap(), 0, Password);
1111 
1112     if (Domain != NULL)
1113         HeapFree(GetProcessHeap(), 0, Domain);
1114 
1115     return result;
1116 }
1117 
1118 
1119 static
1120 VOID
1121 SetDomainComboBox(
1122     HWND hwndDomainComboBox,
1123     PGINA_CONTEXT pgContext)
1124 {
1125     WCHAR szComputerName[MAX_COMPUTERNAME_LENGTH + 1];
1126     DWORD dwComputerNameLength;
1127     LONG lIndex = 0;
1128     LONG lFindIndex;
1129 
1130     SendMessageW(hwndDomainComboBox, CB_RESETCONTENT, 0, 0);
1131 
1132     dwComputerNameLength = _countof(szComputerName);
1133     if (GetComputerNameW(szComputerName, &dwComputerNameLength))
1134     {
1135         lIndex = SendMessageW(hwndDomainComboBox, CB_ADDSTRING, 0, (LPARAM)szComputerName);
1136     }
1137 
1138     if (wcslen(pgContext->DomainName) != 0)
1139     {
1140         lFindIndex = SendMessageW(hwndDomainComboBox, CB_FINDSTRINGEXACT, (WPARAM)-1, (LPARAM)pgContext->DomainName);
1141         if (lFindIndex == CB_ERR)
1142         {
1143             lIndex = SendMessageW(hwndDomainComboBox, CB_ADDSTRING, 0, (LPARAM)pgContext->DomainName);
1144         }
1145         else
1146         {
1147             lIndex = lFindIndex;
1148         }
1149     }
1150 
1151     SendMessageW(hwndDomainComboBox, CB_SETCURSEL, lIndex, 0);
1152 }
1153 
1154 
1155 static INT_PTR CALLBACK
1156 LogonDialogProc(
1157     IN HWND hwndDlg,
1158     IN UINT uMsg,
1159     IN WPARAM wParam,
1160     IN LPARAM lParam)
1161 {
1162     PDLG_DATA pDlgData;
1163 
1164     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
1165 
1166     switch (uMsg)
1167     {
1168         case WM_INITDIALOG:
1169         {
1170             /* FIXME: take care of NoDomainUI */
1171             pDlgData = DlgData_Create(hwndDlg, (PGINA_CONTEXT)lParam);
1172             if (pDlgData == NULL)
1173                 return FALSE;
1174 
1175             DlgData_LoadBitmaps(pDlgData);
1176 
1177             SetWelcomeText(hwndDlg);
1178 
1179             if (pDlgData->pgContext->bAutoAdminLogon ||
1180                 !pDlgData->pgContext->bDontDisplayLastUserName)
1181                 SetDlgItemTextW(hwndDlg, IDC_LOGON_USERNAME, pDlgData->pgContext->UserName);
1182 
1183             if (pDlgData->pgContext->bAutoAdminLogon)
1184                 SetDlgItemTextW(hwndDlg, IDC_LOGON_PASSWORD, pDlgData->pgContext->Password);
1185 
1186             SetDomainComboBox(GetDlgItem(hwndDlg, IDC_LOGON_DOMAIN), pDlgData->pgContext);
1187 
1188             if (pDlgData->pgContext->bDisableCAD)
1189                 EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
1190 
1191             if (!pDlgData->pgContext->bShutdownWithoutLogon)
1192                 EnableWindow(GetDlgItem(hwndDlg, IDC_LOGON_SHUTDOWN), FALSE);
1193 
1194             SetFocus(GetDlgItem(hwndDlg, pDlgData->pgContext->bDontDisplayLastUserName ? IDC_LOGON_USERNAME : IDC_LOGON_PASSWORD));
1195 
1196             if (pDlgData->pgContext->bAutoAdminLogon)
1197                 PostMessage(GetDlgItem(hwndDlg, IDOK), BM_CLICK, 0, 0);
1198 
1199             return TRUE;
1200         }
1201 
1202         case WM_PAINT:
1203         {
1204             PAINTSTRUCT ps;
1205             if (pDlgData && pDlgData->hLogoBitmap)
1206             {
1207                 BeginPaint(hwndDlg, &ps);
1208                 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pDlgData->hLogoBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
1209                 EndPaint(hwndDlg, &ps);
1210             }
1211             return TRUE;
1212         }
1213 
1214         case WM_DESTROY:
1215             DlgData_Destroy(pDlgData);
1216             return TRUE;
1217 
1218         case WM_COMMAND:
1219             switch (LOWORD(wParam))
1220             {
1221                 case IDOK:
1222                     if (DoLogon(hwndDlg, pDlgData->pgContext))
1223                         EndDialog(hwndDlg, WLX_SAS_ACTION_LOGON);
1224                     return TRUE;
1225 
1226                 case IDCANCEL:
1227                     EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
1228                     return TRUE;
1229 
1230                 case IDC_LOGON_SHUTDOWN:
1231                     if (OnShutDown(hwndDlg, pDlgData->pgContext) == IDOK)
1232                         EndDialog(hwndDlg, pDlgData->pgContext->nShutdownAction);
1233                     return TRUE;
1234             }
1235             break;
1236     }
1237 
1238     return FALSE;
1239 }
1240 
1241 
1242 static
1243 INT_PTR
1244 CALLBACK
1245 LegalNoticeDialogProc(
1246     IN HWND hwndDlg,
1247     IN UINT uMsg,
1248     IN WPARAM wParam,
1249     IN LPARAM lParam)
1250 {
1251     PLEGALNOTICEDATA pLegalNotice;
1252 
1253     switch (uMsg)
1254     {
1255         case WM_INITDIALOG:
1256             pLegalNotice = (PLEGALNOTICEDATA)lParam;
1257             SetWindowTextW(hwndDlg, pLegalNotice->pszCaption);
1258             SetDlgItemTextW(hwndDlg, IDC_LEGALNOTICE_TEXT, pLegalNotice->pszText);
1259             return TRUE;
1260 
1261         case WM_COMMAND:
1262             switch (LOWORD(wParam))
1263             {
1264                 case IDOK:
1265                     EndDialog(hwndDlg, 0);
1266                     return TRUE;
1267 
1268                 case IDCANCEL:
1269                     EndDialog(hwndDlg, 0);
1270                     return TRUE;
1271             }
1272             break;
1273     }
1274 
1275     return FALSE;
1276 }
1277 
1278 
1279 static INT
1280 GUILoggedOutSAS(
1281     IN OUT PGINA_CONTEXT pgContext)
1282 {
1283     LEGALNOTICEDATA LegalNotice = {NULL, NULL};
1284     HKEY hKey = NULL;
1285     LONG rc;
1286     int result;
1287 
1288     TRACE("GUILoggedOutSAS()\n");
1289 
1290     rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
1291                        L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
1292                        0,
1293                        KEY_QUERY_VALUE,
1294                        &hKey);
1295     if (rc == ERROR_SUCCESS)
1296     {
1297         ReadRegSzValue(hKey,
1298                        L"LegalNoticeCaption",
1299                        &LegalNotice.pszCaption);
1300 
1301         ReadRegSzValue(hKey,
1302                        L"LegalNoticeText",
1303                        &LegalNotice.pszText);
1304 
1305         RegCloseKey(hKey);
1306     }
1307 
1308     if (LegalNotice.pszCaption != NULL && wcslen(LegalNotice.pszCaption) != 0 &&
1309         LegalNotice.pszText != NULL && wcslen(LegalNotice.pszText) != 0)
1310     {
1311         pgContext->pWlxFuncs->WlxDialogBoxParam(pgContext->hWlx,
1312                                                 pgContext->hDllInstance,
1313                                                 MAKEINTRESOURCEW(IDD_LEGALNOTICE),
1314                                                 GetDesktopWindow(),
1315                                                 LegalNoticeDialogProc,
1316                                                 (LPARAM)&LegalNotice);
1317     }
1318 
1319     if (LegalNotice.pszCaption != NULL)
1320         HeapFree(GetProcessHeap(), 0, LegalNotice.pszCaption);
1321 
1322     if (LegalNotice.pszText != NULL)
1323         HeapFree(GetProcessHeap(), 0, LegalNotice.pszText);
1324 
1325     result = pgContext->pWlxFuncs->WlxDialogBoxParam(
1326         pgContext->hWlx,
1327         pgContext->hDllInstance,
1328         MAKEINTRESOURCEW(IDD_LOGON),
1329         GetDesktopWindow(),
1330         LogonDialogProc,
1331         (LPARAM)pgContext);
1332     if (result >= WLX_SAS_ACTION_LOGON &&
1333         result <= WLX_SAS_ACTION_SWITCH_CONSOLE)
1334     {
1335         WARN("WlxLoggedOutSAS() returns 0x%x\n", result);
1336         return result;
1337     }
1338 
1339     WARN("WlxDialogBoxParam() failed (0x%x)\n", result);
1340     return WLX_SAS_ACTION_NONE;
1341 }
1342 
1343 
1344 static VOID
1345 SetLockMessage(HWND hwnd,
1346                INT nDlgItem,
1347                PGINA_CONTEXT pgContext)
1348 {
1349     WCHAR Buffer1[256];
1350     WCHAR Buffer2[256];
1351     WCHAR Buffer3[512];
1352 
1353     LoadStringW(pgContext->hDllInstance, IDS_LOCKMSG, Buffer1, _countof(Buffer1));
1354 
1355     wsprintfW(Buffer2, L"%s\\%s", pgContext->DomainName, pgContext->UserName);
1356     wsprintfW(Buffer3, Buffer1, Buffer2);
1357 
1358     SetDlgItemTextW(hwnd, nDlgItem, Buffer3);
1359 }
1360 
1361 
1362 static
1363 BOOL
1364 DoUnlock(
1365     IN HWND hwndDlg,
1366     IN PGINA_CONTEXT pgContext,
1367     OUT LPINT Action)
1368 {
1369     WCHAR Buffer1[256];
1370     WCHAR Buffer2[256];
1371     LPWSTR UserName = NULL;
1372     LPWSTR Password = NULL;
1373     BOOL res = FALSE;
1374 
1375     if (GetTextboxText(hwndDlg, IDC_UNLOCK_USERNAME, &UserName) && *UserName == '\0')
1376     {
1377         HeapFree(GetProcessHeap(), 0, UserName);
1378         return FALSE;
1379     }
1380 
1381     if (GetTextboxText(hwndDlg, IDC_UNLOCK_PASSWORD, &Password))
1382     {
1383         if (UserName != NULL && Password != NULL &&
1384             wcscmp(UserName, pgContext->UserName) == 0 &&
1385             wcscmp(Password, pgContext->Password) == 0)
1386         {
1387             *Action = WLX_SAS_ACTION_UNLOCK_WKSTA;
1388             res = TRUE;
1389         }
1390         else if (wcscmp(UserName, pgContext->UserName) == 0 &&
1391                  wcscmp(Password, pgContext->Password) != 0)
1392         {
1393             /* Wrong Password */
1394             LoadStringW(pgContext->hDllInstance, IDS_LOCKEDWRONGPASSWORD, Buffer2, _countof(Buffer2));
1395             LoadStringW(pgContext->hDllInstance, IDS_COMPUTERLOCKED, Buffer1, _countof(Buffer1));
1396             MessageBoxW(hwndDlg, Buffer2, Buffer1, MB_OK | MB_ICONERROR);
1397         }
1398         else
1399         {
1400             /* Wrong user name */
1401             if (DoAdminUnlock(pgContext, UserName, NULL, Password))
1402             {
1403                 *Action = WLX_SAS_ACTION_UNLOCK_WKSTA;
1404                 res = TRUE;
1405             }
1406             else
1407             {
1408                 LoadStringW(pgContext->hDllInstance, IDS_LOCKEDWRONGUSER, Buffer1, _countof(Buffer1));
1409                 wsprintfW(Buffer2, Buffer1, pgContext->DomainName, pgContext->UserName);
1410                 LoadStringW(pgContext->hDllInstance, IDS_COMPUTERLOCKED, Buffer1, _countof(Buffer1));
1411                 MessageBoxW(hwndDlg, Buffer2, Buffer1, MB_OK | MB_ICONERROR);
1412             }
1413         }
1414     }
1415 
1416     if (UserName != NULL)
1417         HeapFree(GetProcessHeap(), 0, UserName);
1418 
1419     if (Password != NULL)
1420         HeapFree(GetProcessHeap(), 0, Password);
1421 
1422     return res;
1423 }
1424 
1425 
1426 static
1427 INT_PTR
1428 CALLBACK
1429 UnlockDialogProc(
1430     IN HWND hwndDlg,
1431     IN UINT uMsg,
1432     IN WPARAM wParam,
1433     IN LPARAM lParam)
1434 {
1435     PDLG_DATA pDlgData;
1436     INT result = WLX_SAS_ACTION_NONE;
1437 
1438     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
1439 
1440     switch (uMsg)
1441     {
1442         case WM_INITDIALOG:
1443         {
1444             pDlgData = DlgData_Create(hwndDlg, (PGINA_CONTEXT)lParam);
1445             if (pDlgData == NULL)
1446                 return FALSE;
1447 
1448             SetWelcomeText(hwndDlg);
1449 
1450             SetLockMessage(hwndDlg, IDC_UNLOCK_MESSAGE, pDlgData->pgContext);
1451 
1452             SetDlgItemTextW(hwndDlg, IDC_UNLOCK_USERNAME, pDlgData->pgContext->UserName);
1453             SetFocus(GetDlgItem(hwndDlg, IDC_UNLOCK_PASSWORD));
1454 
1455             if (pDlgData->pgContext->bDisableCAD)
1456                 EnableWindow(GetDlgItem(hwndDlg, IDCANCEL), FALSE);
1457 
1458             DlgData_LoadBitmaps(pDlgData);
1459             return TRUE;
1460         }
1461 
1462         case WM_PAINT:
1463         {
1464             PAINTSTRUCT ps;
1465             if (pDlgData && pDlgData->hLogoBitmap)
1466             {
1467                 BeginPaint(hwndDlg, &ps);
1468                 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pDlgData->hLogoBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
1469                 EndPaint(hwndDlg, &ps);
1470             }
1471             return TRUE;
1472         }
1473         case WM_DESTROY:
1474             DlgData_Destroy(pDlgData);
1475             return TRUE;
1476 
1477         case WM_COMMAND:
1478             switch (LOWORD(wParam))
1479             {
1480                 case IDOK:
1481                     if (DoUnlock(hwndDlg, pDlgData->pgContext, &result))
1482                         EndDialog(hwndDlg, result);
1483                     return TRUE;
1484 
1485                 case IDCANCEL:
1486                     EndDialog(hwndDlg, WLX_SAS_ACTION_NONE);
1487                     return TRUE;
1488             }
1489             break;
1490     }
1491 
1492     return FALSE;
1493 }
1494 
1495 
1496 static INT
1497 GUILockedSAS(
1498     IN OUT PGINA_CONTEXT pgContext)
1499 {
1500     int result;
1501 
1502     TRACE("GUILockedSAS()\n");
1503 
1504     result = pgContext->pWlxFuncs->WlxDialogBoxParam(
1505         pgContext->hWlx,
1506         pgContext->hDllInstance,
1507         MAKEINTRESOURCEW(IDD_UNLOCK),
1508         GetDesktopWindow(),
1509         UnlockDialogProc,
1510         (LPARAM)pgContext);
1511     if (result >= WLX_SAS_ACTION_LOGON &&
1512         result <= WLX_SAS_ACTION_SWITCH_CONSOLE)
1513     {
1514         WARN("GUILockedSAS() returns 0x%x\n", result);
1515         return result;
1516     }
1517 
1518     WARN("GUILockedSAS() failed (0x%x)\n", result);
1519     return WLX_SAS_ACTION_NONE;
1520 }
1521 
1522 
1523 static INT_PTR CALLBACK
1524 LockedDialogProc(
1525     IN HWND hwndDlg,
1526     IN UINT uMsg,
1527     IN WPARAM wParam,
1528     IN LPARAM lParam)
1529 {
1530     PDLG_DATA pDlgData;
1531 
1532     pDlgData = (PDLG_DATA)GetWindowLongPtrW(hwndDlg, GWLP_USERDATA);
1533 
1534     switch (uMsg)
1535     {
1536         case WM_INITDIALOG:
1537         {
1538             pDlgData = DlgData_Create(hwndDlg, (PGINA_CONTEXT)lParam);
1539             if (pDlgData == NULL)
1540                 return FALSE;
1541 
1542             DlgData_LoadBitmaps(pDlgData);
1543 
1544             SetWelcomeText(hwndDlg);
1545 
1546             SetLockMessage(hwndDlg, IDC_LOCKED_MESSAGE, pDlgData->pgContext);
1547             return TRUE;
1548         }
1549         case WM_PAINT:
1550         {
1551             PAINTSTRUCT ps;
1552             if (pDlgData && pDlgData->hLogoBitmap)
1553             {
1554                 BeginPaint(hwndDlg, &ps);
1555                 DrawStateW(ps.hdc, NULL, NULL, (LPARAM)pDlgData->hLogoBitmap, (WPARAM)0, 0, 0, 0, 0, DST_BITMAP);
1556                 EndPaint(hwndDlg, &ps);
1557             }
1558             return TRUE;
1559         }
1560         case WM_DESTROY:
1561         {
1562             DlgData_Destroy(pDlgData);
1563             return TRUE;
1564         }
1565     }
1566 
1567     return FALSE;
1568 }
1569 
1570 
1571 static VOID
1572 GUIDisplayLockedNotice(
1573     IN OUT PGINA_CONTEXT pgContext)
1574 {
1575     TRACE("GUIdisplayLockedNotice()\n");
1576 
1577     pgContext->pWlxFuncs->WlxDialogBoxParam(
1578         pgContext->hWlx,
1579         pgContext->hDllInstance,
1580         MAKEINTRESOURCEW(IDD_LOCKED),
1581         GetDesktopWindow(),
1582         LockedDialogProc,
1583         (LPARAM)pgContext);
1584 }
1585 
1586 GINA_UI GinaGraphicalUI = {
1587     GUIInitialize,
1588     GUIDisplayStatusMessage,
1589     GUIRemoveStatusMessage,
1590     GUIDisplaySASNotice,
1591     GUILoggedOnSAS,
1592     GUILoggedOutSAS,
1593     GUILockedSAS,
1594     GUIDisplayLockedNotice,
1595 };
1596