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