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