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