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 28 LsapInitNotificationList(VOID) 29 { 30 InitializeListHead(&NotificationListHead); 31 RtlInitializeResource(&NotificationListLock); 32 } 33 34 35 static 36 PLSA_NOTIFICATION_ENTRY 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 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 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 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 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