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 #include <winsvc.h> 30 #include <userenv.h> 31 #include <ndk/sefuncs.h> 32 33 HINSTANCE hDllInstance; 34 35 extern GINA_UI GinaGraphicalUI; 36 extern GINA_UI GinaTextUI; 37 static PGINA_UI pGinaUI; 38 static SID_IDENTIFIER_AUTHORITY SystemAuthority = {SECURITY_NT_AUTHORITY}; 39 static PSID AdminSid; 40 41 /* 42 * @implemented 43 */ 44 BOOL WINAPI 45 WlxNegotiate( 46 IN DWORD dwWinlogonVersion, 47 OUT PDWORD pdwDllVersion) 48 { 49 TRACE("WlxNegotiate(%lx, %p)\n", dwWinlogonVersion, pdwDllVersion); 50 51 if(!pdwDllVersion || (dwWinlogonVersion < WLX_VERSION_1_3)) 52 return FALSE; 53 54 *pdwDllVersion = WLX_VERSION_1_3; 55 56 return TRUE; 57 } 58 59 LONG 60 ReadRegSzValue( 61 IN HKEY hKey, 62 IN LPCWSTR pszValue, 63 OUT LPWSTR* pValue) 64 { 65 LONG rc; 66 DWORD dwType; 67 DWORD cbData = 0; 68 LPWSTR Value; 69 70 if (!pValue) 71 return ERROR_INVALID_PARAMETER; 72 73 *pValue = NULL; 74 rc = RegQueryValueExW(hKey, pszValue, NULL, &dwType, NULL, &cbData); 75 if (rc != ERROR_SUCCESS) 76 return rc; 77 if (dwType != REG_SZ) 78 return ERROR_FILE_NOT_FOUND; 79 Value = HeapAlloc(GetProcessHeap(), 0, cbData + sizeof(WCHAR)); 80 if (!Value) 81 return ERROR_NOT_ENOUGH_MEMORY; 82 rc = RegQueryValueExW(hKey, pszValue, NULL, NULL, (LPBYTE)Value, &cbData); 83 if (rc != ERROR_SUCCESS) 84 { 85 HeapFree(GetProcessHeap(), 0, Value); 86 return rc; 87 } 88 /* NULL-terminate the string */ 89 Value[cbData / sizeof(WCHAR)] = '\0'; 90 91 *pValue = Value; 92 return ERROR_SUCCESS; 93 } 94 95 static LONG 96 ReadRegDwordValue( 97 IN HKEY hKey, 98 IN LPCWSTR pszValue, 99 OUT LPDWORD pValue) 100 { 101 LONG rc; 102 DWORD dwType; 103 DWORD cbData; 104 DWORD dwValue; 105 106 if (!pValue) 107 return ERROR_INVALID_PARAMETER; 108 109 cbData = sizeof(DWORD); 110 rc = RegQueryValueExW(hKey, pszValue, NULL, &dwType, (LPBYTE)&dwValue, &cbData); 111 if (rc == ERROR_SUCCESS && dwType == REG_DWORD) 112 *pValue = dwValue; 113 114 return ERROR_SUCCESS; 115 } 116 117 static VOID 118 ChooseGinaUI(VOID) 119 { 120 HKEY ControlKey = NULL; 121 LPWSTR SystemStartOptions = NULL; 122 LPWSTR CurrentOption, NextOption; /* Pointers into SystemStartOptions */ 123 BOOL ConsoleBoot = FALSE; 124 LONG rc; 125 126 rc = RegOpenKeyExW( 127 HKEY_LOCAL_MACHINE, 128 L"SYSTEM\\CurrentControlSet\\Control", 129 0, 130 KEY_QUERY_VALUE, 131 &ControlKey); 132 133 rc = ReadRegSzValue(ControlKey, L"SystemStartOptions", &SystemStartOptions); 134 if (rc != ERROR_SUCCESS) 135 goto cleanup; 136 137 /* Check for CONSOLE switch in SystemStartOptions */ 138 CurrentOption = SystemStartOptions; 139 while (CurrentOption) 140 { 141 NextOption = wcschr(CurrentOption, L' '); 142 if (NextOption) 143 *NextOption = L'\0'; 144 if (wcsicmp(CurrentOption, L"CONSOLE") == 0) 145 { 146 TRACE("Found %S. Switching to console boot\n", CurrentOption); 147 ConsoleBoot = TRUE; 148 goto cleanup; 149 } 150 CurrentOption = NextOption ? NextOption + 1 : NULL; 151 } 152 153 cleanup: 154 if (ConsoleBoot) 155 pGinaUI = &GinaTextUI; 156 else 157 pGinaUI = &GinaGraphicalUI; 158 159 if (ControlKey != NULL) 160 RegCloseKey(ControlKey); 161 HeapFree(GetProcessHeap(), 0, SystemStartOptions); 162 } 163 164 165 static 166 BOOL 167 GetRegistrySettings(PGINA_CONTEXT pgContext) 168 { 169 HKEY hKey = NULL; 170 LPWSTR lpAutoAdminLogon = NULL; 171 LPWSTR lpDontDisplayLastUserName = NULL; 172 LPWSTR lpShutdownWithoutLogon = NULL; 173 DWORD dwDisableCAD = 0; 174 DWORD dwSize; 175 LONG rc; 176 177 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, 178 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 179 0, 180 KEY_QUERY_VALUE, 181 &hKey); 182 if (rc != ERROR_SUCCESS) 183 { 184 WARN("RegOpenKeyExW() failed with error %lu\n", rc); 185 return FALSE; 186 } 187 188 rc = ReadRegSzValue(hKey, 189 L"AutoAdminLogon", 190 &lpAutoAdminLogon); 191 if (rc == ERROR_SUCCESS) 192 { 193 if (wcscmp(lpAutoAdminLogon, L"1") == 0) 194 pgContext->bAutoAdminLogon = TRUE; 195 } 196 197 TRACE("bAutoAdminLogon: %s\n", pgContext->bAutoAdminLogon ? "TRUE" : "FALSE"); 198 199 rc = ReadRegDwordValue(hKey, 200 L"DisableCAD", 201 &dwDisableCAD); 202 if (rc == ERROR_SUCCESS) 203 { 204 if (dwDisableCAD != 0) 205 pgContext->bDisableCAD = TRUE; 206 } 207 208 TRACE("bDisableCAD: %s\n", pgContext->bDisableCAD ? "TRUE" : "FALSE"); 209 210 pgContext->bShutdownWithoutLogon = TRUE; 211 rc = ReadRegSzValue(hKey, 212 L"ShutdownWithoutLogon", 213 &lpShutdownWithoutLogon); 214 if (rc == ERROR_SUCCESS) 215 { 216 if (wcscmp(lpShutdownWithoutLogon, L"0") == 0) 217 pgContext->bShutdownWithoutLogon = FALSE; 218 } 219 220 rc = ReadRegSzValue(hKey, 221 L"DontDisplayLastUserName", 222 &lpDontDisplayLastUserName); 223 if (rc == ERROR_SUCCESS) 224 { 225 if (wcscmp(lpDontDisplayLastUserName, L"1") == 0) 226 pgContext->bDontDisplayLastUserName = TRUE; 227 } 228 229 dwSize = sizeof(pgContext->UserName); 230 rc = RegQueryValueExW(hKey, 231 L"DefaultUserName", 232 NULL, 233 NULL, 234 (LPBYTE)&pgContext->UserName, 235 &dwSize); 236 237 dwSize = sizeof(pgContext->Domain); 238 rc = RegQueryValueExW(hKey, 239 L"DefaultDomain", 240 NULL, 241 NULL, 242 (LPBYTE)&pgContext->Domain, 243 &dwSize); 244 245 if (lpShutdownWithoutLogon != NULL) 246 HeapFree(GetProcessHeap(), 0, lpShutdownWithoutLogon); 247 248 if (lpDontDisplayLastUserName != NULL) 249 HeapFree(GetProcessHeap(), 0, lpDontDisplayLastUserName); 250 251 if (lpAutoAdminLogon != NULL) 252 HeapFree(GetProcessHeap(), 0, lpAutoAdminLogon); 253 254 if (hKey != NULL) 255 RegCloseKey(hKey); 256 257 return TRUE; 258 } 259 260 typedef DWORD (WINAPI *pThemeWait)(DWORD dwTimeout); 261 typedef BOOL (WINAPI *pThemeWatch)(void); 262 263 static void 264 InitThemeSupport(VOID) 265 { 266 HMODULE hDll = LoadLibraryW(L"shsvcs.dll"); 267 pThemeWait themeWait; 268 pThemeWatch themeWatch; 269 270 if(!hDll) 271 return; 272 273 themeWait = (pThemeWait) GetProcAddress(hDll, (LPCSTR)2); 274 themeWatch = (pThemeWatch) GetProcAddress(hDll, (LPCSTR)1); 275 276 if(themeWait && themeWatch) 277 { 278 themeWait(5000); 279 themeWatch(); 280 } 281 } 282 283 /* 284 * @implemented 285 */ 286 BOOL WINAPI 287 WlxInitialize( 288 LPWSTR lpWinsta, 289 HANDLE hWlx, 290 PVOID pvReserved, 291 PVOID pWinlogonFunctions, 292 PVOID *pWlxContext) 293 { 294 PGINA_CONTEXT pgContext; 295 296 UNREFERENCED_PARAMETER(pvReserved); 297 298 InitThemeSupport(); 299 300 pgContext = (PGINA_CONTEXT)LocalAlloc(LMEM_FIXED | LMEM_ZEROINIT, sizeof(GINA_CONTEXT)); 301 if(!pgContext) 302 { 303 WARN("LocalAlloc() failed\n"); 304 return FALSE; 305 } 306 307 if (!GetRegistrySettings(pgContext)) 308 { 309 WARN("GetRegistrySettings() failed\n"); 310 LocalFree(pgContext); 311 return FALSE; 312 } 313 314 /* Return the context to winlogon */ 315 *pWlxContext = (PVOID)pgContext; 316 pgContext->hDllInstance = hDllInstance; 317 318 /* Save pointer to dispatch table */ 319 pgContext->pWlxFuncs = (PWLX_DISPATCH_VERSION_1_3)pWinlogonFunctions; 320 321 /* Save the winlogon handle used to call the dispatch functions */ 322 pgContext->hWlx = hWlx; 323 324 /* Save window station */ 325 pgContext->station = lpWinsta; 326 327 /* Clear status window handle */ 328 pgContext->hStatusWindow = NULL; 329 330 /* Notify winlogon that we will use the default SAS */ 331 pgContext->pWlxFuncs->WlxUseCtrlAltDel(hWlx); 332 333 /* Locates the authentication package */ 334 //LsaRegisterLogonProcess(...); 335 336 /* Check autologon settings the first time */ 337 pgContext->AutoLogonState = AUTOLOGON_CHECK_REGISTRY; 338 339 pgContext->nShutdownAction = WLX_SAS_ACTION_SHUTDOWN_POWER_OFF; 340 341 ChooseGinaUI(); 342 return pGinaUI->Initialize(pgContext); 343 } 344 345 /* 346 * @implemented 347 */ 348 BOOL 349 WINAPI 350 WlxScreenSaverNotify( 351 PVOID pWlxContext, 352 BOOL *pSecure) 353 { 354 #if 0 355 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 356 WCHAR szBuffer[2]; 357 HKEY hKeyCurrentUser, hKey; 358 DWORD bufferSize = sizeof(szBuffer); 359 DWORD varType = REG_SZ; 360 LONG rc; 361 362 TRACE("(%p %p)\n", pWlxContext, pSecure); 363 364 *pSecure = TRUE; 365 366 /* 367 * Policy setting: 368 * HKLM\Software\Policies\Microsoft\Windows\Control Panel\Desktop : ScreenSaverIsSecure 369 * User setting: 370 * HKCU\Control Panel\Desktop : ScreenSaverIsSecure 371 */ 372 373 if (!ImpersonateLoggedOnUser(pgContext->UserToken)) 374 { 375 ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); 376 *pSecure = FALSE; 377 return TRUE; 378 } 379 380 /* Open the current user HKCU key */ 381 rc = RegOpenCurrentUser(MAXIMUM_ALLOWED, &hKeyCurrentUser); 382 TRACE("RegOpenCurrentUser: %ld\n", rc); 383 if (rc == ERROR_SUCCESS) 384 { 385 /* Open the subkey */ 386 rc = RegOpenKeyExW(hKeyCurrentUser, 387 L"Control Panel\\Desktop", 388 0, 389 KEY_QUERY_VALUE, 390 &hKey); 391 TRACE("RegOpenKeyExW: %ld\n", rc); 392 RegCloseKey(hKeyCurrentUser); 393 } 394 395 /* Read the value */ 396 if (rc == ERROR_SUCCESS) 397 { 398 rc = RegQueryValueExW(hKey, 399 L"ScreenSaverIsSecure", 400 NULL, 401 &varType, 402 (LPBYTE)szBuffer, 403 &bufferSize); 404 405 TRACE("RegQueryValueExW: %ld\n", rc); 406 407 if (rc == ERROR_SUCCESS) 408 { 409 TRACE("szBuffer: \"%S\"\n", szBuffer); 410 *pSecure = _wtoi(szBuffer); 411 } 412 413 RegCloseKey(hKey); 414 } 415 416 /* Revert the impersonation */ 417 RevertToSelf(); 418 419 TRACE("*pSecure: %ld\n", *pSecure); 420 #endif 421 422 *pSecure = FALSE; 423 424 return TRUE; 425 } 426 427 /* 428 * @implemented 429 */ 430 BOOL WINAPI 431 WlxStartApplication( 432 PVOID pWlxContext, 433 PWSTR pszDesktopName, 434 PVOID pEnvironment, 435 PWSTR pszCmdLine) 436 { 437 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 438 STARTUPINFOW StartupInfo; 439 PROCESS_INFORMATION ProcessInformation; 440 WCHAR CurrentDirectory[MAX_PATH]; 441 HANDLE hAppToken; 442 UINT len; 443 BOOL ret; 444 445 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH); 446 if (len == 0 || len > MAX_PATH) 447 { 448 ERR("GetWindowsDirectoryW() failed\n"); 449 return FALSE; 450 } 451 452 ret = DuplicateTokenEx(pgContext->UserToken, MAXIMUM_ALLOWED, NULL, SecurityImpersonation, TokenPrimary, &hAppToken); 453 if (!ret) 454 { 455 ERR("DuplicateTokenEx() failed with error %lu\n", GetLastError()); 456 return FALSE; 457 } 458 459 ZeroMemory(&StartupInfo, sizeof(StartupInfo)); 460 ZeroMemory(&ProcessInformation, sizeof(ProcessInformation)); 461 StartupInfo.cb = sizeof(StartupInfo); 462 StartupInfo.lpTitle = pszCmdLine; 463 StartupInfo.dwFlags = STARTF_USESHOWWINDOW; 464 StartupInfo.wShowWindow = SW_SHOW; 465 StartupInfo.lpDesktop = pszDesktopName; 466 467 len = GetWindowsDirectoryW(CurrentDirectory, MAX_PATH); 468 if (len == 0 || len > MAX_PATH) 469 { 470 ERR("GetWindowsDirectoryW() failed\n"); 471 return FALSE; 472 } 473 ret = CreateProcessAsUserW( 474 hAppToken, 475 pszCmdLine, 476 NULL, 477 NULL, 478 NULL, 479 FALSE, 480 CREATE_UNICODE_ENVIRONMENT, 481 pEnvironment, 482 CurrentDirectory, 483 &StartupInfo, 484 &ProcessInformation); 485 CloseHandle(ProcessInformation.hProcess); 486 CloseHandle(ProcessInformation.hThread); 487 CloseHandle(hAppToken); 488 if (!ret) 489 ERR("CreateProcessAsUserW() failed with error %lu\n", GetLastError()); 490 return ret; 491 } 492 493 /* 494 * @implemented 495 */ 496 BOOL WINAPI 497 WlxActivateUserShell( 498 PVOID pWlxContext, 499 PWSTR pszDesktopName, 500 PWSTR pszMprLogonScript, 501 PVOID pEnvironment) 502 { 503 HKEY hKey; 504 DWORD BufSize, ValueType; 505 WCHAR pszUserInitApp[MAX_PATH + 1]; 506 WCHAR pszExpUserInitApp[MAX_PATH]; 507 DWORD len; 508 LONG rc; 509 510 TRACE("WlxActivateUserShell()\n"); 511 512 UNREFERENCED_PARAMETER(pszMprLogonScript); 513 514 /* Get the path of userinit */ 515 rc = RegOpenKeyExW( 516 HKEY_LOCAL_MACHINE, 517 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon", 518 0, 519 KEY_QUERY_VALUE, 520 &hKey); 521 if (rc != ERROR_SUCCESS) 522 { 523 WARN("RegOpenKeyExW() failed with error %lu\n", rc); 524 return FALSE; 525 } 526 527 /* Query userinit application */ 528 BufSize = sizeof(pszUserInitApp) - sizeof(UNICODE_NULL); 529 rc = RegQueryValueExW( 530 hKey, 531 L"Userinit", 532 NULL, 533 &ValueType, 534 (LPBYTE)pszUserInitApp, 535 &BufSize); 536 RegCloseKey(hKey); 537 if (rc != ERROR_SUCCESS || (ValueType != REG_SZ && ValueType != REG_EXPAND_SZ)) 538 { 539 WARN("RegQueryValueExW() failed with error %lu\n", rc); 540 return FALSE; 541 } 542 pszUserInitApp[MAX_PATH] = UNICODE_NULL; 543 544 len = ExpandEnvironmentStringsW(pszUserInitApp, pszExpUserInitApp, MAX_PATH); 545 if (len > MAX_PATH) 546 { 547 WARN("ExpandEnvironmentStringsW() failed. Required size %lu\n", len); 548 return FALSE; 549 } 550 551 /* Start userinit app */ 552 return WlxStartApplication(pWlxContext, pszDesktopName, pEnvironment, pszExpUserInitApp); 553 } 554 555 /* 556 * @implemented 557 */ 558 int WINAPI 559 WlxLoggedOnSAS( 560 PVOID pWlxContext, 561 DWORD dwSasType, 562 PVOID pReserved) 563 { 564 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 565 INT SasAction = WLX_SAS_ACTION_NONE; 566 567 TRACE("WlxLoggedOnSAS(0x%lx)\n", dwSasType); 568 569 UNREFERENCED_PARAMETER(pReserved); 570 571 switch (dwSasType) 572 { 573 case WLX_SAS_TYPE_CTRL_ALT_DEL: 574 case WLX_SAS_TYPE_TIMEOUT: 575 { 576 SasAction = pGinaUI->LoggedOnSAS(pgContext, dwSasType); 577 break; 578 } 579 case WLX_SAS_TYPE_SC_INSERT: 580 { 581 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_INSERT not supported!\n"); 582 break; 583 } 584 case WLX_SAS_TYPE_SC_REMOVE: 585 { 586 FIXME("WlxLoggedOnSAS: SasType WLX_SAS_TYPE_SC_REMOVE not supported!\n"); 587 break; 588 } 589 default: 590 { 591 WARN("WlxLoggedOnSAS: Unknown SasType: 0x%x\n", dwSasType); 592 break; 593 } 594 } 595 596 return SasAction; 597 } 598 599 /* 600 * @implemented 601 */ 602 BOOL WINAPI 603 WlxDisplayStatusMessage( 604 IN PVOID pWlxContext, 605 IN HDESK hDesktop, 606 IN DWORD dwOptions, 607 IN PWSTR pTitle, 608 IN PWSTR pMessage) 609 { 610 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 611 612 TRACE("WlxDisplayStatusMessage(\"%S\")\n", pMessage); 613 614 return pGinaUI->DisplayStatusMessage(pgContext, hDesktop, dwOptions, pTitle, pMessage); 615 } 616 617 /* 618 * @implemented 619 */ 620 BOOL WINAPI 621 WlxRemoveStatusMessage( 622 IN PVOID pWlxContext) 623 { 624 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 625 626 TRACE("WlxRemoveStatusMessage()\n"); 627 628 return pGinaUI->RemoveStatusMessage(pgContext); 629 } 630 631 static PWSTR 632 DuplicationString(PWSTR Str) 633 { 634 DWORD cb; 635 PWSTR NewStr; 636 637 if (Str == NULL) return NULL; 638 639 cb = (wcslen(Str) + 1) * sizeof(WCHAR); 640 if ((NewStr = LocalAlloc(LMEM_FIXED, cb))) 641 memcpy(NewStr, Str, cb); 642 return NewStr; 643 } 644 645 646 BOOL 647 DoAdminUnlock( 648 IN PGINA_CONTEXT pgContext, 649 IN PWSTR UserName, 650 IN PWSTR Domain, 651 IN PWSTR Password) 652 { 653 HANDLE hToken = NULL; 654 PTOKEN_GROUPS Groups = NULL; 655 BOOL bIsAdmin = FALSE; 656 ULONG Size; 657 ULONG i; 658 NTSTATUS Status; 659 NTSTATUS SubStatus = STATUS_SUCCESS; 660 661 TRACE("(%S %S %S)\n", UserName, Domain, Password); 662 663 Status = ConnectToLsa(pgContext); 664 if (!NT_SUCCESS(Status)) 665 { 666 WARN("ConnectToLsa() failed\n"); 667 return FALSE; 668 } 669 670 Status = MyLogonUser(pgContext->LsaHandle, 671 pgContext->AuthenticationPackage, 672 UserName, 673 Domain, 674 Password, 675 &pgContext->UserToken, 676 &SubStatus); 677 if (!NT_SUCCESS(Status)) 678 { 679 WARN("MyLogonUser() failed\n"); 680 return FALSE; 681 } 682 683 Status = NtQueryInformationToken(hToken, 684 TokenGroups, 685 NULL, 686 0, 687 &Size); 688 if ((Status != STATUS_SUCCESS) && (Status != STATUS_BUFFER_TOO_SMALL)) 689 { 690 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status); 691 goto done; 692 } 693 694 Groups = HeapAlloc(GetProcessHeap(), 0, Size); 695 if (Groups == NULL) 696 { 697 TRACE("HeapAlloc() failed\n"); 698 goto done; 699 } 700 701 Status = NtQueryInformationToken(hToken, 702 TokenGroups, 703 Groups, 704 Size, 705 &Size); 706 if (!NT_SUCCESS(Status)) 707 { 708 TRACE("NtQueryInformationToken() failed (Status 0x%08lx)\n", Status); 709 goto done; 710 } 711 712 for (i = 0; i < Groups->GroupCount; i++) 713 { 714 if (RtlEqualSid(Groups->Groups[i].Sid, AdminSid)) 715 { 716 TRACE("Member of Admins group\n"); 717 bIsAdmin = TRUE; 718 break; 719 } 720 } 721 722 done: 723 if (Groups != NULL) 724 HeapFree(GetProcessHeap(), 0, Groups); 725 726 if (hToken != NULL) 727 CloseHandle(hToken); 728 729 return bIsAdmin; 730 } 731 732 733 NTSTATUS 734 DoLoginTasks( 735 IN OUT PGINA_CONTEXT pgContext, 736 IN PWSTR UserName, 737 IN PWSTR Domain, 738 IN PWSTR Password, 739 OUT PNTSTATUS SubStatus) 740 { 741 NTSTATUS Status; 742 743 Status = ConnectToLsa(pgContext); 744 if (!NT_SUCCESS(Status)) 745 { 746 WARN("ConnectToLsa() failed (Status 0x%08lx)\n", Status); 747 return Status; 748 } 749 750 Status = MyLogonUser(pgContext->LsaHandle, 751 pgContext->AuthenticationPackage, 752 UserName, 753 Domain, 754 Password, 755 &pgContext->UserToken, 756 SubStatus); 757 if (!NT_SUCCESS(Status)) 758 { 759 WARN("MyLogonUser() failed (Status 0x%08lx)\n", Status); 760 } 761 762 return Status; 763 } 764 765 766 BOOL 767 CreateProfile( 768 IN OUT PGINA_CONTEXT pgContext, 769 IN PWSTR UserName, 770 IN PWSTR Domain, 771 IN PWSTR Password) 772 { 773 LPWSTR ProfilePath = NULL; 774 LPWSTR lpEnvironment = NULL; 775 TOKEN_STATISTICS Stats; 776 PWLX_PROFILE_V2_0 pProfile = NULL; 777 DWORD cbStats, cbSize; 778 DWORD dwLength; 779 BOOL bResult; 780 781 /* Store the logon time in the context */ 782 GetLocalTime(&pgContext->LogonTime); 783 784 /* Store user and domain in the context */ 785 wcscpy(pgContext->UserName, UserName); 786 if (Domain == NULL || wcslen(Domain) == 0) 787 { 788 dwLength = _countof(pgContext->Domain); 789 GetComputerNameW(pgContext->Domain, &dwLength); 790 } 791 else 792 { 793 wcscpy(pgContext->Domain, Domain); 794 } 795 796 /* Get profile path */ 797 cbSize = 0; 798 bResult = GetProfilesDirectoryW(NULL, &cbSize); 799 if (!bResult && GetLastError() == ERROR_INSUFFICIENT_BUFFER) 800 { 801 ProfilePath = HeapAlloc(GetProcessHeap(), 0, cbSize * sizeof(WCHAR)); 802 if (!ProfilePath) 803 { 804 WARN("HeapAlloc() failed\n"); 805 goto cleanup; 806 } 807 bResult = GetProfilesDirectoryW(ProfilePath, &cbSize); 808 } 809 if (!bResult) 810 { 811 WARN("GetUserProfileDirectoryW() failed\n"); 812 goto cleanup; 813 } 814 815 /* Allocate memory for profile */ 816 pProfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(WLX_PROFILE_V2_0)); 817 if (!pProfile) 818 { 819 WARN("HeapAlloc() failed\n"); 820 goto cleanup; 821 } 822 pProfile->dwType = WLX_PROFILE_TYPE_V2_0; 823 pProfile->pszProfile = ProfilePath; 824 825 cbSize = sizeof(L"LOGONSERVER=\\\\") + 826 wcslen(pgContext->Domain) * sizeof(WCHAR) + 827 sizeof(UNICODE_NULL); 828 lpEnvironment = HeapAlloc(GetProcessHeap(), 0, cbSize); 829 if (!lpEnvironment) 830 { 831 WARN("HeapAlloc() failed\n"); 832 goto cleanup; 833 } 834 835 StringCbPrintfW(lpEnvironment, cbSize, L"LOGONSERVER=\\\\%ls", pgContext->Domain); 836 ASSERT(wcslen(lpEnvironment) == cbSize / sizeof(WCHAR) - 2); 837 lpEnvironment[cbSize / sizeof(WCHAR) - 1] = UNICODE_NULL; 838 839 pProfile->pszEnvironment = lpEnvironment; 840 841 if (!GetTokenInformation(pgContext->UserToken, 842 TokenStatistics, 843 &Stats, 844 sizeof(Stats), 845 &cbStats)) 846 { 847 WARN("Couldn't get Authentication id from user token!\n"); 848 goto cleanup; 849 } 850 851 *pgContext->pAuthenticationId = Stats.AuthenticationId; 852 pgContext->pMprNotifyInfo->pszUserName = DuplicationString(UserName); 853 pgContext->pMprNotifyInfo->pszDomain = DuplicationString(Domain); 854 pgContext->pMprNotifyInfo->pszPassword = DuplicationString(Password); 855 pgContext->pMprNotifyInfo->pszOldPassword = NULL; 856 *pgContext->pdwOptions = 0; 857 *pgContext->pProfile = pProfile; 858 return TRUE; 859 860 cleanup: 861 if (pProfile) 862 { 863 HeapFree(GetProcessHeap(), 0, pProfile->pszEnvironment); 864 } 865 HeapFree(GetProcessHeap(), 0, pProfile); 866 HeapFree(GetProcessHeap(), 0, ProfilePath); 867 return FALSE; 868 } 869 870 871 static BOOL 872 DoAutoLogon( 873 IN PGINA_CONTEXT pgContext) 874 { 875 HKEY WinLogonKey = NULL; 876 LPWSTR AutoLogon = NULL; 877 LPWSTR AutoCount = NULL; 878 LPWSTR IgnoreShiftOverride = NULL; 879 LPWSTR UserName = NULL; 880 LPWSTR Domain = NULL; 881 LPWSTR Password = NULL; 882 BOOL result = FALSE; 883 LONG rc; 884 NTSTATUS Status; 885 NTSTATUS SubStatus = STATUS_SUCCESS; 886 887 TRACE("DoAutoLogon(): AutoLogonState = %lu\n", 888 pgContext->AutoLogonState); 889 890 if (pgContext->AutoLogonState == AUTOLOGON_DISABLED) 891 return FALSE; 892 893 rc = RegOpenKeyExW( 894 HKEY_LOCAL_MACHINE, 895 L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\WinLogon", 896 0, 897 KEY_QUERY_VALUE, 898 &WinLogonKey); 899 if (rc != ERROR_SUCCESS) 900 goto cleanup; 901 902 if (pgContext->AutoLogonState == AUTOLOGON_CHECK_REGISTRY) 903 { 904 /* Set it by default to disabled, we might reenable it again later */ 905 pgContext->AutoLogonState = AUTOLOGON_DISABLED; 906 907 rc = ReadRegSzValue(WinLogonKey, L"AutoAdminLogon", &AutoLogon); 908 if (rc != ERROR_SUCCESS) 909 goto cleanup; 910 if (wcscmp(AutoLogon, L"1") != 0) 911 goto cleanup; 912 913 rc = ReadRegSzValue(WinLogonKey, L"AutoLogonCount", &AutoCount); 914 if (rc == ERROR_SUCCESS && wcscmp(AutoCount, L"0") == 0) 915 goto cleanup; 916 else if (rc != ERROR_FILE_NOT_FOUND) 917 goto cleanup; 918 919 rc = ReadRegSzValue(WinLogonKey, L"IgnoreShiftOverride", &UserName); 920 if (rc == ERROR_SUCCESS) 921 { 922 if (wcscmp(AutoLogon, L"1") != 0 && GetKeyState(VK_SHIFT) < 0) 923 goto cleanup; 924 } 925 else if (GetKeyState(VK_SHIFT) < 0) 926 { 927 /* User pressed SHIFT */ 928 goto cleanup; 929 } 930 931 pgContext->AutoLogonState = AUTOLOGON_ONCE; 932 result = TRUE; 933 } 934 else /* pgContext->AutoLogonState == AUTOLOGON_ONCE */ 935 { 936 pgContext->AutoLogonState = AUTOLOGON_DISABLED; 937 938 rc = ReadRegSzValue(WinLogonKey, L"DefaultUserName", &UserName); 939 if (rc != ERROR_SUCCESS) 940 goto cleanup; 941 rc = ReadRegSzValue(WinLogonKey, L"DefaultDomain", &Domain); 942 if (rc != ERROR_SUCCESS && rc != ERROR_FILE_NOT_FOUND) 943 goto cleanup; 944 rc = ReadRegSzValue(WinLogonKey, L"DefaultPassword", &Password); 945 if (rc != ERROR_SUCCESS) 946 goto cleanup; 947 948 Status = DoLoginTasks(pgContext, UserName, Domain, Password, &SubStatus); 949 if (!NT_SUCCESS(Status)) 950 { 951 /* FIXME: Handle errors!!! */ 952 result = FALSE; 953 goto cleanup; 954 } 955 956 result = CreateProfile(pgContext, UserName, Domain, Password); 957 if (result) 958 { 959 ZeroMemory(pgContext->Password, sizeof(pgContext->Password)); 960 wcscpy(pgContext->Password, Password); 961 962 NotifyBootConfigStatus(TRUE); 963 } 964 } 965 966 cleanup: 967 if (WinLogonKey != NULL) 968 RegCloseKey(WinLogonKey); 969 HeapFree(GetProcessHeap(), 0, AutoLogon); 970 HeapFree(GetProcessHeap(), 0, AutoCount); 971 HeapFree(GetProcessHeap(), 0, IgnoreShiftOverride); 972 HeapFree(GetProcessHeap(), 0, UserName); 973 HeapFree(GetProcessHeap(), 0, Domain); 974 HeapFree(GetProcessHeap(), 0, Password); 975 TRACE("DoAutoLogon(): AutoLogonState = %lu, returning %d\n", 976 pgContext->AutoLogonState, result); 977 return result; 978 } 979 980 /* 981 * @implemented 982 */ 983 VOID WINAPI 984 WlxDisplaySASNotice( 985 IN PVOID pWlxContext) 986 { 987 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 988 989 TRACE("WlxDisplaySASNotice(%p)\n", pWlxContext); 990 991 if (GetSystemMetrics(SM_REMOTESESSION)) 992 { 993 /* User is remotely logged on. Don't display a notice */ 994 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL); 995 return; 996 } 997 998 if (pgContext->bAutoAdminLogon) 999 { 1000 /* Don't display the window, we want to do an automatic logon */ 1001 pgContext->AutoLogonState = AUTOLOGON_ONCE; 1002 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL); 1003 return; 1004 } 1005 else 1006 pgContext->AutoLogonState = AUTOLOGON_DISABLED; 1007 1008 if (pgContext->bDisableCAD) 1009 { 1010 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL); 1011 return; 1012 } 1013 1014 pGinaUI->DisplaySASNotice(pgContext); 1015 1016 TRACE("WlxDisplaySASNotice() done\n"); 1017 } 1018 1019 /* 1020 * @implemented 1021 */ 1022 INT WINAPI 1023 WlxLoggedOutSAS( 1024 IN PVOID pWlxContext, 1025 IN DWORD dwSasType, 1026 OUT PLUID pAuthenticationId, 1027 IN OUT PSID pLogonSid, 1028 OUT PDWORD pdwOptions, 1029 OUT PHANDLE phToken, 1030 OUT PWLX_MPR_NOTIFY_INFO pMprNotifyInfo, 1031 OUT PVOID *pProfile) 1032 { 1033 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 1034 INT res; 1035 1036 TRACE("WlxLoggedOutSAS()\n"); 1037 1038 UNREFERENCED_PARAMETER(dwSasType); 1039 UNREFERENCED_PARAMETER(pLogonSid); 1040 1041 pgContext->pAuthenticationId = pAuthenticationId; 1042 pgContext->pdwOptions = pdwOptions; 1043 pgContext->pMprNotifyInfo = pMprNotifyInfo; 1044 pgContext->pProfile = pProfile; 1045 1046 if (0 == GetSystemMetrics(SM_REMOTESESSION) && 1047 DoAutoLogon(pgContext)) 1048 { 1049 /* User is local and registry contains information 1050 * to log on him automatically */ 1051 *phToken = pgContext->UserToken; 1052 return WLX_SAS_ACTION_LOGON; 1053 } 1054 1055 res = pGinaUI->LoggedOutSAS(pgContext); 1056 *phToken = pgContext->UserToken; 1057 return res; 1058 } 1059 1060 /* 1061 * @implemented 1062 */ 1063 int WINAPI 1064 WlxWkstaLockedSAS( 1065 PVOID pWlxContext, 1066 DWORD dwSasType) 1067 { 1068 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 1069 1070 TRACE("WlxWkstaLockedSAS()\n"); 1071 1072 UNREFERENCED_PARAMETER(dwSasType); 1073 1074 return pGinaUI->LockedSAS(pgContext); 1075 } 1076 1077 1078 /* 1079 * @implemented 1080 */ 1081 VOID 1082 WINAPI 1083 WlxDisplayLockedNotice(PVOID pWlxContext) 1084 { 1085 PGINA_CONTEXT pgContext = (PGINA_CONTEXT)pWlxContext; 1086 1087 TRACE("WlxDisplayLockedNotice()\n"); 1088 1089 if (pgContext->bDisableCAD) 1090 { 1091 pgContext->pWlxFuncs->WlxSasNotify(pgContext->hWlx, WLX_SAS_TYPE_CTRL_ALT_DEL); 1092 return; 1093 } 1094 1095 pGinaUI->DisplayLockedNotice(pgContext); 1096 } 1097 1098 1099 /* 1100 * @implemented 1101 */ 1102 BOOL WINAPI 1103 WlxIsLogoffOk( 1104 PVOID pWlxContext) 1105 { 1106 TRACE("WlxIsLogoffOk()\n"); 1107 UNREFERENCED_PARAMETER(pWlxContext); 1108 return TRUE; 1109 } 1110 1111 BOOL WINAPI 1112 DllMain( 1113 IN HINSTANCE hinstDLL, 1114 IN DWORD dwReason, 1115 IN LPVOID lpvReserved) 1116 { 1117 UNREFERENCED_PARAMETER(lpvReserved); 1118 1119 if (dwReason == DLL_PROCESS_ATTACH) 1120 { 1121 hDllInstance = hinstDLL; 1122 1123 RtlAllocateAndInitializeSid(&SystemAuthority, 1124 2, 1125 SECURITY_BUILTIN_DOMAIN_RID, 1126 DOMAIN_ALIAS_RID_ADMINS, 1127 SECURITY_NULL_RID, 1128 SECURITY_NULL_RID, 1129 SECURITY_NULL_RID, 1130 SECURITY_NULL_RID, 1131 SECURITY_NULL_RID, 1132 SECURITY_NULL_RID, 1133 &AdminSid); 1134 1135 } 1136 else if (dwReason == DLL_PROCESS_DETACH) 1137 { 1138 if (AdminSid != NULL) 1139 RtlFreeSid(AdminSid); 1140 } 1141 1142 return TRUE; 1143 } 1144