Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647/* * COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS Winlogon * FILE: base/system/winlogon/notify.c * PURPOSE: Logon notifications * PROGRAMMERS: Eric Kohl */
/* INCLUDES ******************************************************************/
#include "winlogon.h"
/* GLOBALS *******************************************************************/
typedef VOID (WINAPI *PWLX_NOTIFY_HANDLER)(PWLX_NOTIFICATION_INFO pInfo);
static PSTR FuncNames[LastHandler] ={ "Logon", "Logoff", "Lock", "Unlock", "Startup", "Shutdown", "StartScreenSaver", "StopScreenSaver", "Disconnect", "Reconnect", "StartShell", "PostShell"};
typedef struct _NOTIFICATION_ITEM{ LIST_ENTRY ListEntry; HMODULE hModule; PWSTR pszKeyName; PWSTR pszDllName; BOOL bEnabled; BOOL bAsynchronous; BOOL bImpersonate; BOOL bSmartCardLogon; DWORD dwMaxWait; BOOL bSfcNotification; PWLX_NOTIFY_HANDLER Handler[LastHandler];} NOTIFICATION_ITEM, *PNOTIFICATION_ITEM;
static LIST_ENTRY NotificationDllListHead;
/* FUNCTIONS *****************************************************************/
/** * @brief * Retrieves the address of the exported notification handler, * specified in the registry entry for the notification DLL. **/staticPWLX_NOTIFY_HANDLERGetNotificationHandler( _In_ HKEY hDllKey, _In_ HMODULE hModule, _In_ PCSTR pNotification){ LONG lError; DWORD dwType, dwSize; CHAR szFuncBuffer[128];
dwSize = sizeof(szFuncBuffer); lError = RegQueryValueExA(hDllKey, pNotification, NULL, &dwType, (PBYTE)szFuncBuffer, &dwSize); if ((lError != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || (dwSize == 0)) { return NULL; }
/* NUL-terminate */ szFuncBuffer[dwSize / sizeof(CHAR) - 1] = ANSI_NULL;
return (PWLX_NOTIFY_HANDLER)GetProcAddress(hModule, szFuncBuffer);}
/** * @brief * Loads the notification DLL and retrieves its exported notification handlers. **/staticBOOLLoadNotifyDll( _Inout_ PNOTIFICATION_ITEM NotificationDll){ HKEY hNotifyKey, hDllKey; HMODULE hModule; LONG lError; NOTIFICATION_TYPE Type;
if (NotificationDll->bSfcNotification) return TRUE; // Already loaded.
lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify", 0, KEY_READ, &hNotifyKey); if (lError != ERROR_SUCCESS) { ERR("RegOpenKeyExW(Winlogon\\Notify) failed, Error %lu\n", lError); return FALSE; }
lError = RegOpenKeyExW(hNotifyKey, NotificationDll->pszKeyName, 0, KEY_READ, &hDllKey); RegCloseKey(hNotifyKey);
if (lError != ERROR_SUCCESS) { ERR("RegOpenKeyExW(%S) failed, Error %lu\n", NotificationDll->pszKeyName, lError); return FALSE; }
hModule = LoadLibraryW(NotificationDll->pszDllName); if (!hModule) { ERR("LoadLibraryW(%S) failed, Error %lu\n", NotificationDll->pszDllName, GetLastError()); RegCloseKey(hDllKey); return FALSE; } NotificationDll->hModule = hModule;
for (Type = LogonHandler; Type < LastHandler; ++Type) { NotificationDll->Handler[Type] = GetNotificationHandler(hDllKey, hModule, FuncNames[Type]); TRACE("%s: %p\n", FuncNames[Type], NotificationDll->Handler[Type]); }
RegCloseKey(hDllKey); return TRUE;}
/** * @brief * Frees the resources associated to a notification. **/staticVOIDDeleteNotification( _In_ PNOTIFICATION_ITEM Notification){ if (Notification->hModule) FreeLibrary(Notification->hModule);
if (Notification->pszKeyName) RtlFreeHeap(RtlGetProcessHeap(), 0, Notification->pszKeyName);
if (Notification->pszDllName) RtlFreeHeap(RtlGetProcessHeap(), 0, Notification->pszDllName);
RtlFreeHeap(RtlGetProcessHeap(), 0, Notification);}
/** * @brief * Initializes the internal SFC notifications. **/staticVOIDAddSfcNotification(VOID){ PNOTIFICATION_ITEM NotificationDll; HMODULE hModule; DWORD dwError; WCHAR szSfcPath[MAX_PATH];
ExpandEnvironmentStringsW(L"%SystemRoot%\\system32\\sfc.dll", szSfcPath, ARRAYSIZE(szSfcPath));
NotificationDll = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*NotificationDll)); if (!NotificationDll) return; // If needed: dwError = ERROR_OUTOFMEMORY;
NotificationDll->pszDllName = WlStrDup(szSfcPath); if (NotificationDll->pszDllName == NULL) { dwError = ERROR_OUTOFMEMORY; goto done; }
NotificationDll->bEnabled = TRUE; NotificationDll->dwMaxWait = 30; /* FIXME: ??? */ NotificationDll->bSfcNotification = TRUE;
/* Load sfc.dll, and also sfc_os.dll on systems where it forwards to */ hModule = LoadLibraryW(szSfcPath); if (!hModule) { dwError = GetLastError(); ERR("LoadLibraryW(%S) failed, Error %lu\n", szSfcPath, dwError); goto done; } NotificationDll->hModule = hModule;
NotificationDll->Handler[LogonHandler] = (PWLX_NOTIFY_HANDLER)GetProcAddress(hModule, "SfcWLEventLogon"); NotificationDll->Handler[LogoffHandler] = (PWLX_NOTIFY_HANDLER)GetProcAddress(hModule, "SfcWLEventLogoff"); if (!NotificationDll->Handler[LogonHandler] || !NotificationDll->Handler[LogoffHandler]) { dwError = ERROR_PROC_NOT_FOUND; ERR("Couldn't snap SfcWLEventLogon/SfcWLEventLogoff\n"); goto done; }
InsertHeadList(&NotificationDllListHead, &NotificationDll->ListEntry);
dwError = ERROR_SUCCESS;
done: if (dwError != ERROR_SUCCESS) DeleteNotification(NotificationDll);}
staticVOIDAddNotificationDll( _In_ HKEY hNotifyKey, _In_ PCWSTR pszKeyName){ HKEY hDllKey = NULL; PNOTIFICATION_ITEM NotificationDll; PWSTR pszDllName; DWORD dwValue, dwSize, dwType; LONG lError;
TRACE("AddNotificationDll(0x%p, %S)\n", hNotifyKey, pszKeyName);
lError = RegOpenKeyExW(hNotifyKey, pszKeyName, 0, KEY_READ, &hDllKey); if (lError != ERROR_SUCCESS) return;
/* In safe-boot mode, load the notification DLL only if it is enabled there */ if (GetSystemMetrics(SM_CLEANBOOT) != 0) // TODO: Cache when Winlogon starts { BOOL bSafeMode = FALSE; // Default to NOT loading the DLL in SafeMode.
dwSize = sizeof(dwValue); lError = RegQueryValueExW(hDllKey, L"SafeMode", NULL, &dwType, (PBYTE)&dwValue, &dwSize); if ((lError == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSize == sizeof(dwValue))) bSafeMode = !!dwValue;
/* Bail out if the DLL should not be loaded in safe-boot mode. * NOTE: On Win2000 and later, the value is always overridden * to TRUE, and the DLL is loaded unconditionally. This defeats * the whole purpose of this feature... In ReactOS we restore it! */ if (!bSafeMode) { RegCloseKey(hDllKey); return; } }
NotificationDll = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(*NotificationDll)); if (!NotificationDll) { lError = ERROR_OUTOFMEMORY; goto done; }
NotificationDll->pszKeyName = WlStrDup(pszKeyName); if (NotificationDll->pszKeyName == NULL) { lError = ERROR_OUTOFMEMORY; goto done; }
dwSize = 0; lError = RegQueryValueExW(hDllKey, L"DllName", NULL, &dwType, NULL, &dwSize); if ((lError != ERROR_SUCCESS) || (dwType != REG_SZ && dwType != REG_EXPAND_SZ) || (dwSize == 0) || (dwSize % sizeof(WCHAR))) { lError = ERROR_FILE_NOT_FOUND; goto done; } /* Ensure the string can be NUL-terminated */ dwSize += sizeof(WCHAR);
pszDllName = RtlAllocateHeap(RtlGetProcessHeap(), 0, dwSize); if (!pszDllName) { lError = ERROR_OUTOFMEMORY; goto done; }
lError = RegQueryValueExW(hDllKey, L"DllName", NULL, &dwType, (PBYTE)pszDllName, &dwSize); if (lError != ERROR_SUCCESS) { RtlFreeHeap(RtlGetProcessHeap(), 0, pszDllName); goto done; } /* NUL-terminate */ pszDllName[dwSize / sizeof(WCHAR) - 1] = UNICODE_NULL;
/* Expand the path if applicable. Note that Windows always does the * expansion, independently of the REG_SZ or REG_EXPAND_SZ type. */ if (wcschr(pszDllName, L'%') != NULL) { dwSize = ExpandEnvironmentStringsW(pszDllName, NULL, 0); if (dwSize) { PWSTR pszDllPath = RtlAllocateHeap(RtlGetProcessHeap(), 0, dwSize * sizeof(WCHAR)); if (!pszDllPath) { RtlFreeHeap(RtlGetProcessHeap(), 0, pszDllName); lError = ERROR_OUTOFMEMORY; goto done; } ExpandEnvironmentStringsW(pszDllName, pszDllPath, dwSize);
/* Free the old buffer and replace it with the expanded path */ RtlFreeHeap(RtlGetProcessHeap(), 0, pszDllName); pszDllName = pszDllPath; } }
NotificationDll->pszDllName = pszDllName;
NotificationDll->bEnabled = TRUE; NotificationDll->dwMaxWait = 30; /* FIXME: ??? */
dwSize = sizeof(dwValue); lError = RegQueryValueExW(hDllKey, L"Asynchronous", NULL, &dwType, (PBYTE)&dwValue, &dwSize); if ((lError == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSize == sizeof(dwValue))) NotificationDll->bAsynchronous = !!dwValue;
dwSize = sizeof(dwValue); lError = RegQueryValueExW(hDllKey, L"Impersonate", NULL, &dwType, (PBYTE)&dwValue, &dwSize); if ((lError == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSize == sizeof(dwValue))) NotificationDll->bImpersonate = !!dwValue;
dwSize = sizeof(dwValue); lError = RegQueryValueExW(hDllKey, L"SmartCardLogonNotify", NULL, &dwType, (PBYTE)&dwValue, &dwSize); if ((lError == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSize == sizeof(dwValue))) NotificationDll->bSmartCardLogon = !!dwValue;
dwSize = sizeof(dwValue); lError = RegQueryValueExW(hDllKey, L"MaxWait", NULL, &dwType, (PBYTE)&dwValue, &dwSize); if ((lError == ERROR_SUCCESS) && (dwType == REG_DWORD) && (dwSize == sizeof(dwValue))) NotificationDll->dwMaxWait = dwValue;
InsertHeadList(&NotificationDllListHead, &NotificationDll->ListEntry);
lError = ERROR_SUCCESS;
done: if (lError != ERROR_SUCCESS) { if (NotificationDll) DeleteNotification(NotificationDll); }
RegCloseKey(hDllKey);}
BOOLInitNotifications(VOID){ HKEY hNotifyKey = NULL; LONG lError; DWORD dwIndex; DWORD dwKeyName; WCHAR szKeyName[80];
TRACE("InitNotifications()\n");
InitializeListHead(&NotificationDllListHead);
AddSfcNotification();
lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify", 0, KEY_READ, &hNotifyKey); if (lError != ERROR_SUCCESS) { TRACE("RegOpenKeyExW()\n"); return TRUE; }
for (dwIndex = 0; ; ++dwIndex) { dwKeyName = ARRAYSIZE(szKeyName); lError = RegEnumKeyExW(hNotifyKey, dwIndex, szKeyName, &dwKeyName, NULL, NULL, NULL, NULL); if (lError != ERROR_SUCCESS) break;
TRACE("Notification DLL: %S\n", szKeyName); AddNotificationDll(hNotifyKey, szKeyName); }
RegCloseKey(hNotifyKey);
TRACE("InitNotifications() done\n");
return TRUE;}
staticVOIDCallNotificationDll( _In_ PNOTIFICATION_ITEM NotificationDll, _In_ NOTIFICATION_TYPE Type, _In_ PWLX_NOTIFICATION_INFO pInfo){ PWLX_NOTIFY_HANDLER pNotifyHandler; WLX_NOTIFICATION_INFO Info; HANDLE UserToken;
/* Delay-load the DLL if needed */ if (!NotificationDll->hModule) { if (!LoadNotifyDll(NotificationDll)) { /* We failed, disable it */ NotificationDll->bEnabled = FALSE; return; } ASSERT(NotificationDll->hModule); }
/* Retrieve the notification handler; bail out if none is specified */ pNotifyHandler = NotificationDll->Handler[Type]; if (!pNotifyHandler) return;
/* Capture the notification info structure, since * the notification handler might mess with it */ Info = *pInfo;
/* Impersonate the logged-on user if necessary */ UserToken = (NotificationDll->bImpersonate ? Info.hToken : NULL); if (UserToken && !ImpersonateLoggedOnUser(UserToken)) { ERR("WL: ImpersonateLoggedOnUser() failed with error %lu\n", GetLastError()); return; }
/* Call the notification handler in SEH to prevent any Winlogon crashes */ _SEH2_TRY {#ifdef _M_IX86 // CORE-20279 /* Workaround for buggy 3rd-party notification DLLs: Handle broken ones * that use a CDECL calling convention instead of the correct STDCALL */ BOOLEAN Success; #if defined(__GNUC__) register ULONG_PTR StackPtr; __asm__ __volatile__ ( "movl %%esp, %[StackPtr]\n\t" // Save current ESP /*"leal %[Info], %%eax\n\t" // Push parameter "pushl %%eax\n\t"*/ "pushl %[Info]\n\t" "call *%[pNotifyHandler]\n\t" // Invoke STDCALL notification handler "cmpl %%esp, %[StackPtr]\n\t" // Check whether ESP is messed up "je 1f\n\t" // Exit if everything is fine "movl %[StackPtr], %%esp\n\t" // Restore correct ESP "1:\n\t" //"seteb %[Success]" // Set success or failure : [StackPtr]"=&S"(StackPtr), [Success]/*"=rm"*/"=@cce"(Success) : [pNotifyHandler]"m"(pNotifyHandler), [Info]/*"m"(Info)*/"r"(&Info) : /*"%esp", "%eax",*/ "cc", "memory" ); #elif defined(_MSC_VER) // && !defined(__clang__) __asm { mov esi, esp // Save current ESP lea eax, dword ptr [Info] // Push parameter push eax call [pNotifyHandler] // Invoke STDCALL notification handler cmp esi, esp // Check whether ESP is messed up je l1f // Exit if everything is fine mov esp, esi // Restore correct ESP l1f: sete byte ptr [Success] // Set success or failure } #else #error Unsupported compiler #endif if (!Success) { ERR("WL: The notification DLL '%ws' uses a wrong calling convention or number of parameters. " "Please contact your software vendor for a fixed DLL!\n", NotificationDll->pszDllName); }#else pNotifyHandler(&Info);#endif // _M_IX86 } _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER) { ERR("WL: Exception 0x%08lx hit by notification DLL %ws while executing %s notify function\n", _SEH2_GetExceptionCode(), NotificationDll->pszDllName, FuncNames[Type]); } _SEH2_END;
/* Revert impersonation */ if (UserToken) RevertToSelf();}
VOIDCallNotificationDlls( PWLSESSION pSession, NOTIFICATION_TYPE Type){ PLIST_ENTRY ListEntry; WLX_NOTIFICATION_INFO Info;
/* Check for invalid notification type */ ASSERT(Type < LastHandler);
TRACE("CallNotificationDlls(%s)\n", FuncNames[Type]);
/* Set up the notification info structure template */ Info.Size = sizeof(Info);
switch (Type) { case LogoffHandler: case ShutdownHandler: Info.Flags = 3; break;
default: Info.Flags = 0; break; }
Info.UserName = pSession->UserName; Info.Domain = pSession->Domain; Info.WindowStation = pSession->InteractiveWindowStationName; Info.hToken = pSession->UserToken;
switch (Type) { case LogonHandler: case StartShellHandler: Info.hDesktop = pSession->ApplicationDesktop; break;
case StartScreenSaverHandler: Info.hDesktop = pSession->ApplicationDesktop; break;
default: Info.hDesktop = pSession->WinlogonDesktop; break; }
Info.pStatusCallback = NULL;
for (ListEntry = NotificationDllListHead.Flink; ListEntry != &NotificationDllListHead; ListEntry = ListEntry->Flink) { PNOTIFICATION_ITEM Notification = CONTAINING_RECORD(ListEntry, NOTIFICATION_ITEM, ListEntry); if (Notification->bEnabled) CallNotificationDll(Notification, Type, &Info); }}
VOIDCleanupNotifications(VOID){ while (!IsListEmpty(&NotificationDllListHead)) { PLIST_ENTRY ListEntry = RemoveHeadList(&NotificationDllListHead); PNOTIFICATION_ITEM Notification = CONTAINING_RECORD(ListEntry, NOTIFICATION_ITEM, ListEntry); DeleteNotification(Notification); }}
/* EOF */