1620217ceSEric Kohl /*
2620217ceSEric Kohl * PROJECT: Local Security Authority Server DLL
3620217ceSEric Kohl * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4620217ceSEric Kohl * PURPOSE: LSA policy change notifications
5620217ceSEric Kohl * COPYRIGHT: Eric Kohl 2018
6620217ceSEric Kohl */
7620217ceSEric Kohl
8620217ceSEric Kohl #include "lsasrv.h"
9620217ceSEric Kohl
10620217ceSEric Kohl typedef struct _LSA_NOTIFICATION_ENTRY
11620217ceSEric Kohl {
12620217ceSEric Kohl LIST_ENTRY Entry;
13620217ceSEric Kohl POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass;
14*dd1f0d02SEric Kohl CLIENT_ID ClientId;
15620217ceSEric Kohl HANDLE EventHandle;
16*dd1f0d02SEric Kohl HANDLE MappedEventHandle;
17620217ceSEric Kohl } LSA_NOTIFICATION_ENTRY, *PLSA_NOTIFICATION_ENTRY;
18620217ceSEric Kohl
19620217ceSEric Kohl /* GLOBALS *****************************************************************/
20620217ceSEric Kohl
21620217ceSEric Kohl static LIST_ENTRY NotificationListHead;
22620217ceSEric Kohl static RTL_RESOURCE NotificationListLock;
23620217ceSEric Kohl
24620217ceSEric Kohl
25620217ceSEric Kohl /* FUNCTIONS ***************************************************************/
26620217ceSEric Kohl
27620217ceSEric Kohl VOID
LsapInitNotificationList(VOID)28620217ceSEric Kohl LsapInitNotificationList(VOID)
29620217ceSEric Kohl {
30620217ceSEric Kohl InitializeListHead(&NotificationListHead);
31620217ceSEric Kohl RtlInitializeResource(&NotificationListLock);
32620217ceSEric Kohl }
33620217ceSEric Kohl
34620217ceSEric Kohl
35620217ceSEric Kohl static
36620217ceSEric Kohl PLSA_NOTIFICATION_ENTRY
LsapGetNotificationEntry(PLSA_API_MSG pRequestMsg)374e32ad36SEric Kohl LsapGetNotificationEntry(
38*dd1f0d02SEric Kohl PLSA_API_MSG pRequestMsg)
39620217ceSEric Kohl {
40620217ceSEric Kohl PLIST_ENTRY NotificationEntry;
41620217ceSEric Kohl PLSA_NOTIFICATION_ENTRY CurrentNotification;
42620217ceSEric Kohl
43620217ceSEric Kohl NotificationEntry = NotificationListHead.Flink;
44620217ceSEric Kohl while (NotificationEntry != &NotificationListHead)
45620217ceSEric Kohl {
46620217ceSEric Kohl CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
47620217ceSEric Kohl
48*dd1f0d02SEric Kohl if ((CurrentNotification->ClientId.UniqueProcess == pRequestMsg->h.ClientId.UniqueProcess) &&
49*dd1f0d02SEric Kohl (CurrentNotification->ClientId.UniqueThread == pRequestMsg->h.ClientId.UniqueThread) &&
50*dd1f0d02SEric Kohl (CurrentNotification->InformationClass == pRequestMsg->PolicyChangeNotify.Request.InformationClass) &&
51*dd1f0d02SEric Kohl (CurrentNotification->EventHandle == pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle))
52620217ceSEric Kohl return CurrentNotification;
53620217ceSEric Kohl
54620217ceSEric Kohl NotificationEntry = NotificationEntry->Flink;
55620217ceSEric Kohl }
56620217ceSEric Kohl
57620217ceSEric Kohl return NULL;
58620217ceSEric Kohl }
59620217ceSEric Kohl
60620217ceSEric Kohl
61*dd1f0d02SEric Kohl static
62620217ceSEric Kohl NTSTATUS
LsapAddNotification(PLSA_API_MSG pRequestMsg)63*dd1f0d02SEric Kohl LsapAddNotification(
64620217ceSEric Kohl PLSA_API_MSG pRequestMsg)
65620217ceSEric Kohl {
66620217ceSEric Kohl PLSA_NOTIFICATION_ENTRY pEntry;
67*dd1f0d02SEric Kohl HANDLE hProcess = NULL;
68620217ceSEric Kohl NTSTATUS Status = STATUS_SUCCESS;
69620217ceSEric Kohl
70*dd1f0d02SEric Kohl TRACE("LsapAddNotification(%p)\n", pRequestMsg);
71620217ceSEric Kohl
72*dd1f0d02SEric Kohl /* Allocate a new notification list entry */
73620217ceSEric Kohl pEntry = RtlAllocateHeap(RtlGetProcessHeap(),
74620217ceSEric Kohl HEAP_ZERO_MEMORY,
75620217ceSEric Kohl sizeof(LSA_NOTIFICATION_ENTRY));
76620217ceSEric Kohl if (pEntry == NULL)
77620217ceSEric Kohl {
78620217ceSEric Kohl Status = STATUS_INSUFFICIENT_RESOURCES;
79620217ceSEric Kohl goto done;
80620217ceSEric Kohl }
81620217ceSEric Kohl
82*dd1f0d02SEric Kohl /* Copy the notification data */
83620217ceSEric Kohl pEntry->InformationClass = pRequestMsg->PolicyChangeNotify.Request.InformationClass;
84620217ceSEric Kohl pEntry->EventHandle = pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle;
85*dd1f0d02SEric Kohl pEntry->ClientId = pRequestMsg->h.ClientId;
86620217ceSEric Kohl
87*dd1f0d02SEric Kohl /* Open the client process */
88*dd1f0d02SEric Kohl Status = NtOpenProcess(&hProcess,
89*dd1f0d02SEric Kohl PROCESS_DUP_HANDLE,
90*dd1f0d02SEric Kohl NULL,
91*dd1f0d02SEric Kohl pEntry->ClientId.UniqueProcess);
92*dd1f0d02SEric Kohl if (!NT_SUCCESS(Status))
93*dd1f0d02SEric Kohl {
94*dd1f0d02SEric Kohl ERR("NtOpenProcess() failed (Status 0x%08lx)\n", Status);
95*dd1f0d02SEric Kohl goto done;
96*dd1f0d02SEric Kohl }
97*dd1f0d02SEric Kohl
98*dd1f0d02SEric Kohl /* Duplicate the event handle into the current process */
99*dd1f0d02SEric Kohl Status = NtDuplicateObject(hProcess,
100*dd1f0d02SEric Kohl pEntry->EventHandle,
101*dd1f0d02SEric Kohl NtCurrentProcess(),
102*dd1f0d02SEric Kohl &pEntry->MappedEventHandle,
103*dd1f0d02SEric Kohl 0,
104*dd1f0d02SEric Kohl 0,
105*dd1f0d02SEric Kohl DUPLICATE_SAME_ACCESS);
106*dd1f0d02SEric Kohl if (!NT_SUCCESS(Status))
107*dd1f0d02SEric Kohl {
108*dd1f0d02SEric Kohl ERR("NtDuplicateObject() failed (Status 0x%08lx)\n", Status);
109*dd1f0d02SEric Kohl goto done;
110*dd1f0d02SEric Kohl }
111*dd1f0d02SEric Kohl
112*dd1f0d02SEric Kohl /* Insert the new entry into the notification list */
113620217ceSEric Kohl InsertHeadList(&NotificationListHead,
114620217ceSEric Kohl &pEntry->Entry);
115*dd1f0d02SEric Kohl
116*dd1f0d02SEric Kohl done:
117*dd1f0d02SEric Kohl if (hProcess != NULL)
118*dd1f0d02SEric Kohl NtClose(hProcess);
119*dd1f0d02SEric Kohl
120*dd1f0d02SEric Kohl if (!NT_SUCCESS(Status))
121*dd1f0d02SEric Kohl {
122*dd1f0d02SEric Kohl if (pEntry != NULL)
123*dd1f0d02SEric Kohl RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
124*dd1f0d02SEric Kohl }
125*dd1f0d02SEric Kohl
126*dd1f0d02SEric Kohl return Status;
127*dd1f0d02SEric Kohl }
128*dd1f0d02SEric Kohl
129*dd1f0d02SEric Kohl
130*dd1f0d02SEric Kohl static
131*dd1f0d02SEric Kohl NTSTATUS
LsapRemoveNotification(PLSA_API_MSG pRequestMsg)132*dd1f0d02SEric Kohl LsapRemoveNotification(
133*dd1f0d02SEric Kohl PLSA_API_MSG pRequestMsg)
134*dd1f0d02SEric Kohl {
135*dd1f0d02SEric Kohl PLSA_NOTIFICATION_ENTRY pEntry;
136*dd1f0d02SEric Kohl
137*dd1f0d02SEric Kohl TRACE("LsapRemoveNotification(%p)\n", pRequestMsg);
138*dd1f0d02SEric Kohl
139*dd1f0d02SEric Kohl pEntry = LsapGetNotificationEntry(pRequestMsg);
140*dd1f0d02SEric Kohl if (pEntry == NULL)
141*dd1f0d02SEric Kohl {
142*dd1f0d02SEric Kohl return STATUS_INVALID_HANDLE;
143*dd1f0d02SEric Kohl }
144*dd1f0d02SEric Kohl
145*dd1f0d02SEric Kohl /* Remove the notification entry from the notification list */
146*dd1f0d02SEric Kohl RemoveEntryList(&pEntry->Entry);
147*dd1f0d02SEric Kohl
148*dd1f0d02SEric Kohl /* Close the mapped event handle */
149*dd1f0d02SEric Kohl NtClose(pEntry->MappedEventHandle);
150*dd1f0d02SEric Kohl
151*dd1f0d02SEric Kohl /* Release the notification entry */
152*dd1f0d02SEric Kohl RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
153*dd1f0d02SEric Kohl
154*dd1f0d02SEric Kohl return STATUS_SUCCESS;
155*dd1f0d02SEric Kohl }
156*dd1f0d02SEric Kohl
157*dd1f0d02SEric Kohl
158*dd1f0d02SEric Kohl NTSTATUS
LsapRegisterNotification(PLSA_API_MSG pRequestMsg)159*dd1f0d02SEric Kohl LsapRegisterNotification(
160*dd1f0d02SEric Kohl PLSA_API_MSG pRequestMsg)
161*dd1f0d02SEric Kohl {
162*dd1f0d02SEric Kohl NTSTATUS Status;
163*dd1f0d02SEric Kohl
164*dd1f0d02SEric Kohl TRACE("LsapRegisterNotification(%p)\n", pRequestMsg);
165*dd1f0d02SEric Kohl
166*dd1f0d02SEric Kohl /* Acquire the notification list lock exclusively */
167*dd1f0d02SEric Kohl RtlAcquireResourceExclusive(&NotificationListLock, TRUE);
168*dd1f0d02SEric Kohl
169*dd1f0d02SEric Kohl if (pRequestMsg->PolicyChangeNotify.Request.Register)
170*dd1f0d02SEric Kohl {
171*dd1f0d02SEric Kohl /* Register the notification event */
172*dd1f0d02SEric Kohl Status = LsapAddNotification(pRequestMsg);
173620217ceSEric Kohl }
174620217ceSEric Kohl else
175620217ceSEric Kohl {
1764e32ad36SEric Kohl /* Unregister the notification event */
177*dd1f0d02SEric Kohl Status = LsapRemoveNotification(pRequestMsg);
1784e32ad36SEric Kohl }
1794e32ad36SEric Kohl
180620217ceSEric Kohl /* Release the notification list lock */
181620217ceSEric Kohl RtlReleaseResource(&NotificationListLock);
182620217ceSEric Kohl
183620217ceSEric Kohl return Status;
184620217ceSEric Kohl }
185620217ceSEric Kohl
1864e32ad36SEric Kohl
1874e32ad36SEric Kohl VOID
LsapNotifyPolicyChange(POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass)1884e32ad36SEric Kohl LsapNotifyPolicyChange(
1894e32ad36SEric Kohl POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass)
1904e32ad36SEric Kohl {
1914e32ad36SEric Kohl PLIST_ENTRY NotificationEntry;
1924e32ad36SEric Kohl PLSA_NOTIFICATION_ENTRY CurrentNotification;
1934e32ad36SEric Kohl
194*dd1f0d02SEric Kohl TRACE("LsapNotifyPolicyChange(%lu)\n", InformationClass);
1954e32ad36SEric Kohl
1964e32ad36SEric Kohl /* Acquire the notification list lock shared */
1974e32ad36SEric Kohl RtlAcquireResourceShared(&NotificationListLock, TRUE);
1984e32ad36SEric Kohl
1994e32ad36SEric Kohl NotificationEntry = NotificationListHead.Flink;
2004e32ad36SEric Kohl while (NotificationEntry != &NotificationListHead)
2014e32ad36SEric Kohl {
2024e32ad36SEric Kohl CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
2034e32ad36SEric Kohl
2044e32ad36SEric Kohl if (CurrentNotification->InformationClass == InformationClass)
2054e32ad36SEric Kohl {
206*dd1f0d02SEric Kohl TRACE("Notify event %p\n", CurrentNotification->MappedEventHandle);
207*dd1f0d02SEric Kohl NtSetEvent(CurrentNotification->MappedEventHandle, NULL);
2084e32ad36SEric Kohl }
2094e32ad36SEric Kohl
2104e32ad36SEric Kohl NotificationEntry = NotificationEntry->Flink;
2114e32ad36SEric Kohl }
2124e32ad36SEric Kohl
2134e32ad36SEric Kohl /* Release the notification list lock */
2144e32ad36SEric Kohl RtlReleaseResource(&NotificationListLock);
2154e32ad36SEric Kohl }
2164e32ad36SEric Kohl
217620217ceSEric Kohl /* EOF */
218