xref: /reactos/dll/win32/lsasrv/notify.c (revision dd1f0d02)
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