The console boot switch is really named CONSOLE, not CMDCONS, since r29948.
[reactos.git] / reactos / dll / win32 / msgina / msgina.c
1 /*
2 * ReactOS GINA
3 * Copyright (C) 2003-2004, 2006 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19 /*
20 * PROJECT: ReactOS msgina.dll
21 * FILE: dll/win32/msgina/msgina.c
22 * PURPOSE: ReactOS Logon GINA DLL
23 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
24 * Hervé Poussineau (hpoussin@reactos.org)
25 */
26
27 #include "msgina.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(msgina);
30
31 HINSTANCE hDllInstance;
32
33 extern GINA_UI GinaGraphicalUI;
34 extern GINA_UI GinaTextUI;
35 static PGINA_UI pGinaUI;
36
37 /*
38 * @implemented
39 */
40 BOOL WINAPI
41 WlxNegotiate(
42 IN DWORD dwWinlogonVersion,
43 OUT PDWORD pdwDllVersion)
44 {
45 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion, pdwDllVersion);
46
47 if(!pdwDllVersion || (dwWinlogonVersion < WLX_VERSION_1_3))
48 return FALSE;
49
50 *pdwDllVersion = WLX_VERSION_1_3;
51
52 return TRUE;
53 }
54
55 static LONG
56 ReadRegSzKey(
57 IN HKEY hKey,
58 IN LPCWSTR pszKey,
59 OUT LPWSTR* pValue)
60 {
61 LONG rc;
62 DWORD dwType;
63 DWORD cbData = 0;
64 LPWSTR Value;
65
66 if (!pValue)
67 return ERROR_INVALID_PARAMETER;
68
69 *pValue = NULL;
70 rc = RegQueryValueExW(hKey, pszKey, NULL, &dwType, NULL, &cbData);
71 if (rc != ERROR_SUCCESS)
72 return rc;
73 if (dwType != REG_SZ)
74 return ERROR_FILE_NOT_FOUND;
75 Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR));
76 if (!Value)
77 return ERROR_NOT_ENOUGH_MEMORY;
78 rc = RegQueryValueExW(hKey, pszKey, NULL, NULL, (LPBYTE)Value, &cbData);
79 if (rc != ERROR_SUCCESS)
80 {
81 HeapFree(GetProcessHeap(), 0, Value);
82 return rc;
83 }
84 /* NULL-terminate the string */
85 Value[cbData / sizeof(WCHAR)] = '\0';
86
87 *pValue = Value;
88 return ERROR_SUCCESS;
89 }
90
91 static VOID
92 ChooseGinaUI(VOID)
93 {
94 HKEY ControlKey = NULL;
95 LPWSTR SystemStartOptions = NULL;
96 LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */
97 BOOL ConsoleBoot = FALSE;
98 LONG rc;
99
100 rc = RegOpenKeyExW(
101 HKEY_LOCAL_MACHINE,
102 L"SYSTEM\\CurrentControlSet\\Control",
103 0,
104 KEY_QUERY_VALUE,
105 &ControlKey);
106
107 rc = ReadRegSzKey(ControlKey, L"SystemStartOptions", &SystemStartOptions);
108 if (rc != ERROR_SUCCESS)
109 goto cleanup;
110
111 /* Check for CONSOLE switch in SystemStartOptions */
112 CurrentOption = SystemStartOptions;
113 while (CurrentOption)
114 {
115 NextOption = wcschr(CurrentOption, L' ');
116 if (NextOption)
117 *NextOption = L'\0';
118 if (wcsicmp(CurrentOption, L"CONSOLE") == 0)
119 {
120 TRACE("Found %S. Switching to console boot\n", CurrentOption);
121 ConsoleBoot = TRUE;
122 goto cleanup;
123 }
124 CurrentOption = NextOption ? NextOption + 1 : NULL;
125 }
126
127 cleanup:
128 if (ConsoleBoot)
129 pGinaUI = &GinaTextUI;
130 else
131 pGinaUI = &GinaGraphicalUI;
132
133 if (ControlKey != NULL)
134 RegCloseKey(ControlKey);
135 HeapFree(GetProcessHeap(), 0, SystemStartOptions);
136 }
137
138 /*
139 * @implemented
140 */
141 BOOL WINAPI
142 WlxInitialize(
143 LPWSTR lpWinsta,
144 HANDLE hWlx,
145 PVOID pvReserved,
146 PVOID pWinlogonFunctions,
147 PVOID *pWlxContext)
148 {
149 PGINA_CONTEXT pgContext;
150
151 UNREFERENCED_PARAMETER(pvReserved);
152
153 pgContext = (PGINA_CONTEXT)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINA_CONTEXT));
154 if(!pgContext)
155 {
156 WARN("LocalAlloc() failed\n");
157 return FALSE;
158 }
159
160 /* Return the context to winlogon */
161 *pWlxContext = (PVOID)pgContext;
162 pgContext->hDllInstance = hDllInstance;
163
164 /* Save pointer to dispatch table */
165 pgContext->pWlxFuncs = (PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions;
166
167 /* Save the winlogon handle used to call the dispatch functions */
168 pgContext->hWlx = hWlx;
169
170 /* Save window station */
171 pgContext->station = lpWinsta;
172
173 /* Clear status window handle */
174 pgContext->hStatusWindow = 0;
175
176 /* Notify winlogon that we will use the default SAS */
177 pgContext->pWlxFuncs->WlxUseCtrlAltDel(hWlx);
178
179 /* Locates the authentification package */
180 //LsaRegisterLogonProcess(...);
181
182 /* Check autologon settings the first time */
183 pgContext->AutoLogonState = AUTOLOGON_CHECK_REGISTRY;
184
185 ChooseGinaUI();
186 return pGinaUI->Initialize(pgContext);
187 }
188
189 /*
190 * @implemented
191 */
192 BOOL WINAPI
193 WlxStartApplication(
194 PVOID pWlxContext,
195 PWSTR pszDesktopName,
196 PVOID pEnvironment,
197 PWSTR pszCmdLine)
198 {
199 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
200 STARTUPINFOW StartupInfo;
201 PROCESS_INFORMATION ProcessInformation;
202 WCHAR CurrentDirectory[MAX_PATH];
203 HANDLE hAppToken;
204 UINT len;
205 BOOL ret;
206
207 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
208 if (len == 0 || len > MAX_PATH)
209 {
210 WARN("GetWindowsDirectoryW() failed\n");
211 return FALSE;
212 }
213
214 ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken);
215 if (!ret)
216 {
217 WARN("DuplicateTokenEx() failed with error %lu\n", GetLastError());
218 return FALSE;
219 }
220
221 ZeroMemory(&StartupInfo, sizeof(STARTUPINFOW));
222 ZeroMemory(&ProcessInformation, sizeof(PROCESS_INFORMATION));
223 StartupInfo.cb = sizeof(STARTUPINFOW);
224 StartupInfo.lpTitle = pszCmdLine;
225 StartupInfo.dwX = StartupInfo.dwY = StartupInfo.dwXSize = StartupInfo.dwYSize = 0L;
226 StartupInfo.dwFlags = 0;
227 StartupInfo.wShowWindow = SW_SHOW;
228 StartupInfo.lpDesktop = pszDesktopName;
229
230 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH);
231 if (len == 0 || len > MAX_PATH)
232 {
233 WARN("GetWindowsDirectoryW() failed\n");
234 return FALSE;
235 }
236 ret = CreateProcessAsUserW(
237 hAppToken,
238 pszCmdLine,
239 NULL,
240 NULL,
241 NULL,
242 FALSE,
243 CREATE_UNICODE_ENVIRONMENT,
244 pEnvironment,
245 CurrentDirectory,
246 &StartupInfo,
247 &ProcessInformation);
248 CloseHandle(ProcessInformation.hProcess);
249 CloseHandle(ProcessInformation.hThread);
250 CloseHandle(hAppToken);
251 if (!ret)
252 WARN("CreateProcessAsUserW() failed with error %lu\n", GetLastError());
253 return ret;
254 }
255
256 /*
257 * @implemented
258 */
259 BOOL WINAPI
260 WlxActivateUserShell(
261 PVOID pWlxContext,
262 PWSTR pszDesktopName,
263 PWSTR pszMprLogonScript,
264 PVOID pEnvironment)
265 {
266 HKEY hKey;
267 DWORD BufSize, ValueType;
268 WCHAR pszUserInitApp[MAX_PATH + 1];
269 WCHAR pszExpUserInitApp[MAX_PATH];
270 DWORD len;
271 LONG rc;
272
273 TRACE("WlxActivateUserShell()\n");
274
275 UNREFERENCED_PARAMETER(pszMprLogonScript);
276
277 /* Get the path of userinit */
278 rc = RegOpenKeyExW(
279 HKEY_LOCAL_MACHINE,
280 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon",
281 0,
282 KEY_QUERY_VALUE,
283 &hKey);
284 if (rc != ERROR_SUCCESS)
285 {
286 WARN("RegOpenKeyExW() failed with error %lu\n", rc);
287 return FALSE;
288 }
289
290 /* Query userinit application */
291 BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL);
292 rc = RegQueryValueExW(
293 hKey,
294 L"Userinit",
295 NULL,
296 &ValueType,
297 (LPBYTE)pszUserInitApp,
298 &BufSize);
299 RegCloseKey(hKey);
300 if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ))
301 {
302 WARN("RegQueryValueExW() failed with error %lu\n", rc);
303 return FALSE;
304 }
305 pszUserInitApp[MAX_PATH] = UNICODE_NULL;
306
307 len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH);
308 if (len > MAX_PATH)
309 {
310 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len);
311 return FALSE;
312 }
313
314 /* Start userinit app */
315 return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp);
316 }
317
318 /*
319 * @implemented
320 */
321 int WINAPI
322 WlxLoggedOnSAS(
323 PVOID pWlxContext,
324 DWORD dwSasType,
325 PVOID pReserved)
326 {
327 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
328 INT SasAction = WLX_SAS_ACTION_NONE;
329
330 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType);
331
332 UNREFERENCED_PARAMETER(pReserved);
333
334 switch (dwSasType)
335 {
336 case WLX_SAS_TYPE_CTRL_ALT_DEL:
337 case WLX_SAS_TYPE_TIMEOUT:
338 {
339 SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType);
340 break;
341 }
342 case WLX_SAS_TYPE_SC_INSERT:
343 {
344 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n");
345 break;
346 }
347 case WLX_SAS_TYPE_SC_REMOVE:
348 {
349 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n");
350 break;
351 }
352 default:
353 {
354 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType);
355 break;
356 }
357 }
358
359 return SasAction;
360 }
361
362 /*
363 * @implemented
364 */
365 BOOL WINAPI
366 WlxDisplayStatusMessage(
367 IN PVOID pWlxContext,
368 IN HDESK hDesktop,
369 IN DWORD dwOptions,
370 IN PWSTR pTitle,
371 IN PWSTR pMessage)
372 {
373 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
374
375 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage);
376
377 return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage);
378 }
379
380 /*
381 * @implemented
382 */
383 BOOL WINAPI
384 WlxRemoveStatusMessage(
385 IN PVOID pWlxContext)
386 {
387 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
388
389 TRACE("WlxRemoveStatusMessage()\n");
390
391 return pGinaUI->RemoveStatusMessage(pgContext);
392 }
393
394 static PWSTR
395 DuplicationString(PWSTR Str)
396 {
397 DWORD cb;
398 PWSTR NewStr;
399
400 if (Str == NULL) return NULL;
401
402 cb = (wcslen(Str) + 1) * sizeof(WCHAR);
403 if ((NewStr = LocalAlloc(LMEM_FIXED, cb)))
404 memcpy(NewStr, Str, cb);
405 return NewStr;
406 }
407
408 BOOL
409 DoLoginTasks(
410 IN OUT PGINA_CONTEXT pgContext,
411 IN PWSTR UserName,
412 IN PWSTR Domain,
413 IN PWSTR Password)
414 {
415 LPWSTR ProfilePath = NULL;
416 LPWSTR lpEnvironment = NULL;
417 TOKEN_STATISTICS Stats;
418 PWLX_PROFILE_V2_0 pProfile = NULL;
419 DWORD cbStats, cbSize;
420 BOOL bResult;
421
422 if (!LogonUserW(UserName, Domain, Password,
423 LOGON32_LOGON_INTERACTIVE,
424 LOGON32_PROVIDER_DEFAULT,
425 &pgContext->UserToken))
426 {
427 WARN("LogonUserW() failed\n");
428 goto cleanup;
429 }
430
431 /* Get profile path */
432 cbSize = 0;
433 bResult = GetProfilesDirectoryW(NULL, &cbSize);
434 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER)
435 {
436 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR));
437 if (!ProfilePath)
438 {
439 WARN("HeapAlloc() failed\n");
440 goto cleanup;
441 }
442 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize);
443 }
444 if (!bResult)
445 {
446 WARN("GetUserProfileDirectoryW() failed\n");
447 goto cleanup;
448 }
449
450 /* Allocate memory for profile */
451 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0));
452 if (!pProfile)
453 {
454 WARN("HeapAlloc() failed\n");
455 goto cleanup;
456 }
457 pProfile->dwType = WLX_PROFILE_TYPE_V2_0;
458 pProfile->pszProfile = ProfilePath;
459
460 lpEnvironment = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 32 * sizeof(WCHAR));
461 if (!lpEnvironment)
462 {
463 WARN("HeapAlloc() failed\n");
464 goto cleanup;
465 }
466 wcscpy(lpEnvironment, L"LOGONSERVER=\\\\Test");
467
468 pProfile->pszEnvironment = lpEnvironment;
469
470 if (!GetTokenInformation(pgContext->UserToken,
471 TokenStatistics,
472 (PVOID)&Stats,
473 sizeof(TOKEN_STATISTICS),
474 &cbStats))
475 {
476 WARN("Couldn't get Authentication id from user token!\n");
477 goto cleanup;
478 }
479
480 *pgContext->pAuthenticationId = Stats.AuthenticationId;
481 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName);
482 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain);
483 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password);
484 pgContext->pMprNotifyInfo->pszOldPassword = NULL;
485 *pgContext->pdwOptions = 0;
486 *pgContext->pProfile = pProfile;
487 return TRUE;
488
489 cleanup:
490 if (pProfile)
491 {
492 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment);
493 }
494 HeapFree(GetProcessHeap(), 0, pProfile);
495 HeapFree(GetProcessHeap(), 0, ProfilePath);
496 return FALSE;
497 }
498
499 static BOOL
500 DoAutoLogon(
501 IN PGINA_CONTEXT pgContext)
502 {
503 HKEY WinLogonKey = NULL;
504 LPWSTR AutoLogon = NULL;
505 LPWSTR AutoCount = NULL;
506 LPWSTR IgnoreShiftOverride = NULL;
507 LPWSTR UserName = NULL;
508 LPWSTR DomainName = NULL;
509 LPWSTR Password = NULL;
510 BOOL result = FALSE;
511 LONG rc;
512
513 TRACE("DoAutoLogon(): AutoLogonState = %lu\n",
514 pgContext->AutoLogonState);
515
516 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED)
517 return FALSE;
518
519 rc = RegOpenKeyExW(
520 HKEY_LOCAL_MACHINE,
521 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon",
522 0,
523 KEY_QUERY_VALUE,
524 &WinLogonKey);
525 if (rc != ERROR_SUCCESS)
526 goto cleanup;
527
528 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY)
529 {
530 /* Set it by default to disabled, we might reenable it again later */
531 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
532
533 rc = ReadRegSzKey(WinLogonKey, L"AutoAdminLogon", &AutoLogon);
534 if (rc != ERROR_SUCCESS)
535 goto cleanup;
536 if (wcscmp(AutoLogon, L"1") != 0)
537 goto cleanup;
538
539 rc = ReadRegSzKey(WinLogonKey, L"AutoLogonCount", &AutoCount);
540 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0)
541 goto cleanup;
542 else if (rc != ERROR_FILE_NOT_FOUND)
543 goto cleanup;
544
545 rc = ReadRegSzKey(WinLogonKey, L"IgnoreShiftOverride", &UserName);
546 if (rc == ERROR_SUCCESS)
547 {
548 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0)
549 goto cleanup;
550 }
551 else if (GetKeyState(VK_SHIFT) < 0)
552 {
553 /* User pressed SHIFT */
554 goto cleanup;
555 }
556
557 pgContext->AutoLogonState = AUTOLOGON_ONCE;
558 result = TRUE;
559 }
560 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */
561 {
562 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
563
564 rc = ReadRegSzKey(WinLogonKey, L"DefaultUserName", &UserName);
565 if (rc != ERROR_SUCCESS)
566 goto cleanup;
567 rc = ReadRegSzKey(WinLogonKey, L"DefaultDomainName", &DomainName);
568 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND)
569 goto cleanup;
570 rc = ReadRegSzKey(WinLogonKey, L"DefaultPassword", &Password);
571 if (rc != ERROR_SUCCESS)
572 goto cleanup;
573
574 result = DoLoginTasks(pgContext, UserName, DomainName, Password);
575
576 if (result == TRUE)
577 NotifyBootConfigStatus(TRUE);
578 }
579
580 cleanup:
581 if (WinLogonKey != NULL)
582 RegCloseKey(WinLogonKey);
583 HeapFree(GetProcessHeap(), 0, AutoLogon);
584 HeapFree(GetProcessHeap(), 0, AutoCount);
585 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride);
586 HeapFree(GetProcessHeap(), 0, UserName);
587 HeapFree(GetProcessHeap(), 0, DomainName);
588 HeapFree(GetProcessHeap(), 0, Password);
589 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n",
590 pgContext->AutoLogonState, result);
591 return result;
592 }
593
594 /*
595 * @implemented
596 */
597 VOID WINAPI
598 WlxDisplaySASNotice(
599 IN PVOID pWlxContext)
600 {
601 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
602
603 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext);
604
605 if (GetSystemMetrics(SM_REMOTESESSION))
606 {
607 /* User is remotely logged on. Don't display a notice */
608 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
609 return;
610 }
611
612 if (DoAutoLogon(pgContext))
613 {
614 /* Don't display the window, we want to do an automatic logon */
615 pgContext->AutoLogonState = AUTOLOGON_ONCE;
616 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL);
617 return;
618 }
619 else
620 pgContext->AutoLogonState = AUTOLOGON_DISABLED;
621
622 pGinaUI->DisplaySASNotice(pgContext);
623
624 TRACE("WlxDisplaySASNotice() done\n");
625 }
626
627 /*
628 * @implemented
629 */
630 INT WINAPI
631 WlxLoggedOutSAS(
632 IN PVOID pWlxContext,
633 IN DWORD dwSasType,
634 OUT PLUID pAuthenticationId,
635 IN OUT PSID pLogonSid,
636 OUT PDWORD pdwOptions,
637 OUT PHANDLE phToken,
638 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo,
639 OUT PVOID *pProfile)
640 {
641 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
642 INT res;
643
644 TRACE("WlxLoggedOutSAS()\n");
645
646 UNREFERENCED_PARAMETER(dwSasType);
647 UNREFERENCED_PARAMETER(pLogonSid);
648
649 pgContext->pAuthenticationId = pAuthenticationId;
650 pgContext->pdwOptions = pdwOptions;
651 pgContext->pMprNotifyInfo = pMprNotifyInfo;
652 pgContext->pProfile = pProfile;
653
654 if (0 == GetSystemMetrics(SM_REMOTESESSION) &&
655 DoAutoLogon(pgContext))
656 {
657 /* User is local and registry contains information
658 * to log on him automatically */
659 *phToken = pgContext->UserToken;
660 return WLX_SAS_ACTION_LOGON;
661 }
662
663 res = pGinaUI->LoggedOutSAS(pgContext);
664 *phToken = pgContext->UserToken;
665 return res;
666 }
667
668 /*
669 * @implemented
670 */
671 int WINAPI
672 WlxWkstaLockedSAS(
673 PVOID pWlxContext,
674 DWORD dwSasType)
675 {
676 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext;
677
678 TRACE("WlxWkstaLockedSAS()\n");
679
680 UNREFERENCED_PARAMETER(dwSasType);
681
682 return pGinaUI->LockedSAS(pgContext);
683 }
684
685 /*
686 * @implemented
687 */
688 BOOL WINAPI
689 WlxIsLogoffOk(
690 PVOID pWlxContext)
691 {
692 TRACE("WlxIsLogoffOk()\n");
693 UNREFERENCED_PARAMETER(pWlxContext);
694 return TRUE;
695 }
696
697 BOOL WINAPI
698 DllMain(
699 IN HINSTANCE hinstDLL,
700 IN DWORD dwReason,
701 IN LPVOID lpvReserved)
702 {
703 UNREFERENCED_PARAMETER(lpvReserved);
704
705 if (dwReason == DLL_PROCESS_ATTACH)
706 hDllInstance = hinstDLL;
707
708 return TRUE;
709 }