mirror of
https://github.com/reactos/reactos.git
synced 2026-06-01 00:40:26 +08:00
CORE-20279 PRELIMINARY REMARK: The described bug and code workaround only applies for x86 32-bit builds. ---- While the Winlogon notification handlers[^1] actually use a `STDCALL` calling convention, which can be trivially verified by debugging the official Windows <= 2003 winlogon.exe and its notification extensions, there exist 3rd-party Winlogon notification DLLs, like the `Ati2evxx.dll` one from AMD/ATI XP video drivers, that use a `CDECL` calling convention, or an invalid number (zero) of parameters. I think the reason why this happens is as follows. The official documentation[^1] indicates that the handlers have the following prototype: ```c void Event_Handler_Function_Name( _In_ PWLX_NOTIFICATION_INFO pInfo ); ``` The documentation (and possibly the internal header Windows is using for Winlogon) is sloppy, because it doesn't tell whether the convention is `STDCALL` or `CDECL`. When compiling routines with such a signature, the compiler will employ whatever default convention it is set to use. Windows code is typically compiled with `STDCALL` convention as the default (see e.g. how the Windows Development Kit is set up), thus, such a function signature would default to `STDCALL`. Observation (with debugger) shows that it is what Windows' winlogon.exe is indeed expecting. However, 3rd-party code using a different development environment, could set the compiler to use `CDECL` as the default calling convention. As a result, the function signature from above would use `CDECL` instead. The difference between the `STDCALL` and `CDECL` conventions is how the function parameters are passed on the stack and how the stack is cleaned at the end (`STDCALL`: the function unwinds the stack; `CDECL`: the caller does it). A calling convention mismatch would therefore corrupt the stack, and this is exactly what happens with the `Ati2evxx.dll` from the AMD/ATI drivers, see CORE-20279. The ReactOS Winlogon crashes from the `_RTC_Failure()` handler just after the 3rd-party handler returns, since we compile our code with runtime checks enabled. Windows' winlogon.exe doesn't apparently crash, because neither in Release nor in Checked/Debug mode did they compile winlogon.exe with RTC enabled. However, its stack would become more corrupt with time. In order to alleviate this in ReactOS' winlogon.exe, I decided to use a "generic" workaround, manually calling the handler with inline ASM (which is OK since the problem and solution is x86-specific only). It does something similar to what the RTC support does: it checks the stack pointer after the call and restores it if needed. An informative message is then emitted in the debugger telling which DLL is buggy and needs to be fixed. [^1]: https://learn.microsoft.com/en-us/windows/win32/secauthn/event-handler-function-prototype
647 lines
19 KiB
C
647 lines
19 KiB
C
/*
|
|
* 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.
|
|
**/
|
|
static
|
|
PWLX_NOTIFY_HANDLER
|
|
GetNotificationHandler(
|
|
_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.
|
|
**/
|
|
static
|
|
BOOL
|
|
LoadNotifyDll(
|
|
_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.
|
|
**/
|
|
static
|
|
VOID
|
|
DeleteNotification(
|
|
_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.
|
|
**/
|
|
static
|
|
VOID
|
|
AddSfcNotification(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);
|
|
}
|
|
|
|
static
|
|
VOID
|
|
AddNotificationDll(
|
|
_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);
|
|
}
|
|
|
|
BOOL
|
|
InitNotifications(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;
|
|
}
|
|
|
|
static
|
|
VOID
|
|
CallNotificationDll(
|
|
_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();
|
|
}
|
|
|
|
VOID
|
|
CallNotificationDlls(
|
|
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);
|
|
}
|
|
}
|
|
|
|
VOID
|
|
CleanupNotifications(VOID)
|
|
{
|
|
while (!IsListEmpty(&NotificationDllListHead))
|
|
{
|
|
PLIST_ENTRY ListEntry = RemoveHeadList(&NotificationDllListHead);
|
|
PNOTIFICATION_ITEM Notification =
|
|
CONTAINING_RECORD(ListEntry, NOTIFICATION_ITEM, ListEntry);
|
|
DeleteNotification(Notification);
|
|
}
|
|
}
|
|
|
|
/* EOF */
|