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