reactos/dll/win32/lsasrv/notify.c

217 lines
5.9 KiB
C

/*
* PROJECT: Local Security Authority Server DLL
* LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
* PURPOSE: LSA policy change notifications
* COPYRIGHT: Eric Kohl 2018
*/
#include "lsasrv.h"
typedef struct _LSA_NOTIFICATION_ENTRY
{
LIST_ENTRY Entry;
POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass;
CLIENT_ID ClientId;
HANDLE EventHandle;
HANDLE MappedEventHandle;
} LSA_NOTIFICATION_ENTRY, *PLSA_NOTIFICATION_ENTRY;
/* GLOBALS *****************************************************************/
static LIST_ENTRY NotificationListHead;
static RTL_RESOURCE NotificationListLock;
/* FUNCTIONS ***************************************************************/
VOID
LsapInitNotificationList(VOID)
{
InitializeListHead(&NotificationListHead);
RtlInitializeResource(&NotificationListLock);
}
static
PLSA_NOTIFICATION_ENTRY
LsapGetNotificationEntry(
PLSA_API_MSG pRequestMsg)
{
PLIST_ENTRY NotificationEntry;
PLSA_NOTIFICATION_ENTRY CurrentNotification;
NotificationEntry = NotificationListHead.Flink;
while (NotificationEntry != &NotificationListHead)
{
CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
if ((CurrentNotification->ClientId.UniqueProcess == pRequestMsg->h.ClientId.UniqueProcess) &&
(CurrentNotification->ClientId.UniqueThread == pRequestMsg->h.ClientId.UniqueThread) &&
(CurrentNotification->InformationClass == pRequestMsg->PolicyChangeNotify.Request.InformationClass) &&
(CurrentNotification->EventHandle == pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle))
return CurrentNotification;
NotificationEntry = NotificationEntry->Flink;
}
return NULL;
}
static
NTSTATUS
LsapAddNotification(
PLSA_API_MSG pRequestMsg)
{
PLSA_NOTIFICATION_ENTRY pEntry;
HANDLE hProcess = NULL;
NTSTATUS Status = STATUS_SUCCESS;
TRACE("LsapAddNotification(%p)\n", pRequestMsg);
/* Allocate a new notification list entry */
pEntry = RtlAllocateHeap(RtlGetProcessHeap(),
HEAP_ZERO_MEMORY,
sizeof(LSA_NOTIFICATION_ENTRY));
if (pEntry == NULL)
{
Status = STATUS_INSUFFICIENT_RESOURCES;
goto done;
}
/* Copy the notification data */
pEntry->InformationClass = pRequestMsg->PolicyChangeNotify.Request.InformationClass;
pEntry->EventHandle = pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle;
pEntry->ClientId = pRequestMsg->h.ClientId;
/* Open the client process */
Status = NtOpenProcess(&hProcess,
PROCESS_DUP_HANDLE,
NULL,
pEntry->ClientId.UniqueProcess);
if (!NT_SUCCESS(Status))
{
ERR("NtOpenProcess() failed (Status 0x%08lx)\n", Status);
goto done;
}
/* Duplicate the event handle into the current process */
Status = NtDuplicateObject(hProcess,
pEntry->EventHandle,
NtCurrentProcess(),
&pEntry->MappedEventHandle,
0,
0,
DUPLICATE_SAME_ACCESS);
if (!NT_SUCCESS(Status))
{
ERR("NtDuplicateObject() failed (Status 0x%08lx)\n", Status);
goto done;
}
/* Insert the new entry into the notification list */
InsertHeadList(&NotificationListHead,
&pEntry->Entry);
done:
if (hProcess != NULL)
NtClose(hProcess);
if (!NT_SUCCESS(Status))
{
if (pEntry != NULL)
RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
}
return Status;
}
static
NTSTATUS
LsapRemoveNotification(
PLSA_API_MSG pRequestMsg)
{
PLSA_NOTIFICATION_ENTRY pEntry;
TRACE("LsapRemoveNotification(%p)\n", pRequestMsg);
pEntry = LsapGetNotificationEntry(pRequestMsg);
if (pEntry == NULL)
{
return STATUS_INVALID_HANDLE;
}
/* Remove the notification entry from the notification list */
RemoveEntryList(&pEntry->Entry);
/* Close the mapped event handle */
NtClose(pEntry->MappedEventHandle);
/* Release the notification entry */
RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
return STATUS_SUCCESS;
}
NTSTATUS
LsapRegisterNotification(
PLSA_API_MSG pRequestMsg)
{
NTSTATUS Status;
TRACE("LsapRegisterNotification(%p)\n", pRequestMsg);
/* Acquire the notification list lock exclusively */
RtlAcquireResourceExclusive(&NotificationListLock, TRUE);
if (pRequestMsg->PolicyChangeNotify.Request.Register)
{
/* Register the notification event */
Status = LsapAddNotification(pRequestMsg);
}
else
{
/* Unregister the notification event */
Status = LsapRemoveNotification(pRequestMsg);
}
/* Release the notification list lock */
RtlReleaseResource(&NotificationListLock);
return Status;
}
VOID
LsapNotifyPolicyChange(
POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass)
{
PLIST_ENTRY NotificationEntry;
PLSA_NOTIFICATION_ENTRY CurrentNotification;
TRACE("LsapNotifyPolicyChange(%lu)\n", InformationClass);
/* Acquire the notification list lock shared */
RtlAcquireResourceShared(&NotificationListLock, TRUE);
NotificationEntry = NotificationListHead.Flink;
while (NotificationEntry != &NotificationListHead)
{
CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
if (CurrentNotification->InformationClass == InformationClass)
{
TRACE("Notify event %p\n", CurrentNotification->MappedEventHandle);
NtSetEvent(CurrentNotification->MappedEventHandle, NULL);
}
NotificationEntry = NotificationEntry->Flink;
}
/* Release the notification list lock */
RtlReleaseResource(&NotificationListLock);
}
/* EOF */