1 /*
2 * PROJECT: Local Security Authority Server DLL
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: LSA policy change notifications
5 * COPYRIGHT: Eric Kohl 2018
6 */
7
8 #include "lsasrv.h"
9
10 typedef struct _LSA_NOTIFICATION_ENTRY
11 {
12 LIST_ENTRY Entry;
13 POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass;
14 CLIENT_ID ClientId;
15 HANDLE EventHandle;
16 HANDLE MappedEventHandle;
17 } LSA_NOTIFICATION_ENTRY, *PLSA_NOTIFICATION_ENTRY;
18
19 /* GLOBALS *****************************************************************/
20
21 static LIST_ENTRY NotificationListHead;
22 static RTL_RESOURCE NotificationListLock;
23
24
25 /* FUNCTIONS ***************************************************************/
26
27 VOID
LsapInitNotificationList(VOID)28 LsapInitNotificationList(VOID)
29 {
30 InitializeListHead(&NotificationListHead);
31 RtlInitializeResource(&NotificationListLock);
32 }
33
34
35 static
36 PLSA_NOTIFICATION_ENTRY
LsapGetNotificationEntry(PLSA_API_MSG pRequestMsg)37 LsapGetNotificationEntry(
38 PLSA_API_MSG pRequestMsg)
39 {
40 PLIST_ENTRY NotificationEntry;
41 PLSA_NOTIFICATION_ENTRY CurrentNotification;
42
43 NotificationEntry = NotificationListHead.Flink;
44 while (NotificationEntry != &NotificationListHead)
45 {
46 CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
47
48 if ((CurrentNotification->ClientId.UniqueProcess == pRequestMsg->h.ClientId.UniqueProcess) &&
49 (CurrentNotification->ClientId.UniqueThread == pRequestMsg->h.ClientId.UniqueThread) &&
50 (CurrentNotification->InformationClass == pRequestMsg->PolicyChangeNotify.Request.InformationClass) &&
51 (CurrentNotification->EventHandle == pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle))
52 return CurrentNotification;
53
54 NotificationEntry = NotificationEntry->Flink;
55 }
56
57 return NULL;
58 }
59
60
61 static
62 NTSTATUS
LsapAddNotification(PLSA_API_MSG pRequestMsg)63 LsapAddNotification(
64 PLSA_API_MSG pRequestMsg)
65 {
66 PLSA_NOTIFICATION_ENTRY pEntry;
67 HANDLE hProcess = NULL;
68 NTSTATUS Status = STATUS_SUCCESS;
69
70 TRACE("LsapAddNotification(%p)\n", pRequestMsg);
71
72 /* Allocate a new notification list entry */
73 pEntry = RtlAllocateHeap(RtlGetProcessHeap(),
74 HEAP_ZERO_MEMORY,
75 sizeof(LSA_NOTIFICATION_ENTRY));
76 if (pEntry == NULL)
77 {
78 Status = STATUS_INSUFFICIENT_RESOURCES;
79 goto done;
80 }
81
82 /* Copy the notification data */
83 pEntry->InformationClass = pRequestMsg->PolicyChangeNotify.Request.InformationClass;
84 pEntry->EventHandle = pRequestMsg->PolicyChangeNotify.Request.NotificationEventHandle;
85 pEntry->ClientId = pRequestMsg->h.ClientId;
86
87 /* Open the client process */
88 Status = NtOpenProcess(&hProcess,
89 PROCESS_DUP_HANDLE,
90 NULL,
91 pEntry->ClientId.UniqueProcess);
92 if (!NT_SUCCESS(Status))
93 {
94 ERR("NtOpenProcess() failed (Status 0x%08lx)\n", Status);
95 goto done;
96 }
97
98 /* Duplicate the event handle into the current process */
99 Status = NtDuplicateObject(hProcess,
100 pEntry->EventHandle,
101 NtCurrentProcess(),
102 &pEntry->MappedEventHandle,
103 0,
104 0,
105 DUPLICATE_SAME_ACCESS);
106 if (!NT_SUCCESS(Status))
107 {
108 ERR("NtDuplicateObject() failed (Status 0x%08lx)\n", Status);
109 goto done;
110 }
111
112 /* Insert the new entry into the notification list */
113 InsertHeadList(&NotificationListHead,
114 &pEntry->Entry);
115
116 done:
117 if (hProcess != NULL)
118 NtClose(hProcess);
119
120 if (!NT_SUCCESS(Status))
121 {
122 if (pEntry != NULL)
123 RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
124 }
125
126 return Status;
127 }
128
129
130 static
131 NTSTATUS
LsapRemoveNotification(PLSA_API_MSG pRequestMsg)132 LsapRemoveNotification(
133 PLSA_API_MSG pRequestMsg)
134 {
135 PLSA_NOTIFICATION_ENTRY pEntry;
136
137 TRACE("LsapRemoveNotification(%p)\n", pRequestMsg);
138
139 pEntry = LsapGetNotificationEntry(pRequestMsg);
140 if (pEntry == NULL)
141 {
142 return STATUS_INVALID_HANDLE;
143 }
144
145 /* Remove the notification entry from the notification list */
146 RemoveEntryList(&pEntry->Entry);
147
148 /* Close the mapped event handle */
149 NtClose(pEntry->MappedEventHandle);
150
151 /* Release the notification entry */
152 RtlFreeHeap(RtlGetProcessHeap(), 0, pEntry);
153
154 return STATUS_SUCCESS;
155 }
156
157
158 NTSTATUS
LsapRegisterNotification(PLSA_API_MSG pRequestMsg)159 LsapRegisterNotification(
160 PLSA_API_MSG pRequestMsg)
161 {
162 NTSTATUS Status;
163
164 TRACE("LsapRegisterNotification(%p)\n", pRequestMsg);
165
166 /* Acquire the notification list lock exclusively */
167 RtlAcquireResourceExclusive(&NotificationListLock, TRUE);
168
169 if (pRequestMsg->PolicyChangeNotify.Request.Register)
170 {
171 /* Register the notification event */
172 Status = LsapAddNotification(pRequestMsg);
173 }
174 else
175 {
176 /* Unregister the notification event */
177 Status = LsapRemoveNotification(pRequestMsg);
178 }
179
180 /* Release the notification list lock */
181 RtlReleaseResource(&NotificationListLock);
182
183 return Status;
184 }
185
186
187 VOID
LsapNotifyPolicyChange(POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass)188 LsapNotifyPolicyChange(
189 POLICY_NOTIFICATION_INFORMATION_CLASS InformationClass)
190 {
191 PLIST_ENTRY NotificationEntry;
192 PLSA_NOTIFICATION_ENTRY CurrentNotification;
193
194 TRACE("LsapNotifyPolicyChange(%lu)\n", InformationClass);
195
196 /* Acquire the notification list lock shared */
197 RtlAcquireResourceShared(&NotificationListLock, TRUE);
198
199 NotificationEntry = NotificationListHead.Flink;
200 while (NotificationEntry != &NotificationListHead)
201 {
202 CurrentNotification = CONTAINING_RECORD(NotificationEntry, LSA_NOTIFICATION_ENTRY, Entry);
203
204 if (CurrentNotification->InformationClass == InformationClass)
205 {
206 TRACE("Notify event %p\n", CurrentNotification->MappedEventHandle);
207 NtSetEvent(CurrentNotification->MappedEventHandle, NULL);
208 }
209
210 NotificationEntry = NotificationEntry->Flink;
211 }
212
213 /* Release the notification list lock */
214 RtlReleaseResource(&NotificationListLock);
215 }
216
217 /* EOF */
218