xref: /reactos/base/system/winlogon/notify.c (revision dfb7e2d6)
1 /*
2  * COPYRIGHT:       See COPYING in the top level directory
3  * PROJECT:         ReactOS Winlogon
4  * FILE:            base/system/winlogon/notify.c
5  * PURPOSE:         Logon notifications
6  * PROGRAMMERS:     Eric Kohl
7  */
8 
9 /* INCLUDES *****************************************************************/
10 
11 #include "winlogon.h"
12 
13 /* GLOBALS ******************************************************************/
14 
15 
16 // void Event_Handler_Function_Name(PWLX_NOTIFICATION_INFO pInfo);
17 typedef VOID (WINAPI *PWLX_NOTIFY_HANDLER)(PWLX_NOTIFICATION_INFO pInfo);
18 
19 static PSTR FuncNames[LastHandler] =
20 {
21     "Logon",
22     "Logoff",
23     "Lock",
24     "Unlock",
25     "Startup",
26     "Shutdown",
27     "StartScreenSaver",
28     "StopScreenSaver",
29     "Disconnect",
30     "Reconnect",
31     "StartShell",
32     "PostShell"
33 };
34 
35 typedef struct _NOTIFICATION_ITEM
36 {
37     LIST_ENTRY ListEntry;
38     PWSTR pszKeyName;
39     PWSTR pszDllName;
40     BOOL bEnabled;
41     BOOL bAsynchronous;
42     BOOL bSafe;
43     BOOL bImpersonate;
44     BOOL bSmartCardLogon;
45     DWORD dwMaxWait;
46     BOOL bSfcNotification;
47 } NOTIFICATION_ITEM, *PNOTIFICATION_ITEM;
48 
49 
50 static LIST_ENTRY NotificationDllListHead;
51 
52 
53 /* FUNCTIONS *****************************************************************/
54 
55 static
56 VOID
57 AddSfcNotification(VOID)
58 {
59     WCHAR szSfcFileName[MAX_PATH];
60     PNOTIFICATION_ITEM NotificationDll;
61     DWORD dwError = ERROR_SUCCESS;
62 
63     ExpandEnvironmentStringsW(L"%windir%\\system32\\sfc.dll",
64                               szSfcFileName,
65                               ARRAYSIZE(szSfcFileName));
66 
67     NotificationDll = RtlAllocateHeap(RtlGetProcessHeap(),
68                                       HEAP_ZERO_MEMORY,
69                                       sizeof(NOTIFICATION_ITEM));
70     if (NotificationDll == NULL)
71     {
72         dwError = ERROR_OUTOFMEMORY;
73         goto done;
74     }
75 
76     NotificationDll->pszDllName = RtlAllocateHeap(RtlGetProcessHeap(),
77                                                   HEAP_ZERO_MEMORY,
78                                                   (wcslen(szSfcFileName) + 1) * sizeof(WCHAR));
79     if (NotificationDll->pszDllName == NULL)
80     {
81         dwError = ERROR_OUTOFMEMORY;
82         goto done;
83     }
84 
85     wcscpy(NotificationDll->pszDllName, szSfcFileName);
86 
87     NotificationDll->bEnabled = TRUE;
88     NotificationDll->dwMaxWait = 30; /* FIXME: ??? */
89     NotificationDll->bSfcNotification = TRUE;
90 
91     InsertHeadList(&NotificationDllListHead,
92                    &NotificationDll->ListEntry);
93 
94 done:
95     if (dwError != ERROR_SUCCESS)
96     {
97         if (NotificationDll != NULL)
98         {
99             if (NotificationDll->pszDllName != NULL)
100                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszDllName);
101 
102             RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll);
103         }
104     }
105 }
106 
107 static
108 VOID
109 AddNotificationDll(
110     HKEY hNotifyKey,
111     PWSTR pszKeyName)
112 {
113     HKEY hDllKey = NULL;
114     PNOTIFICATION_ITEM NotificationDll = NULL;
115     DWORD dwSize, dwType;
116     DWORD dwError;
117 
118     TRACE("AddNotificationDll(%p %S)\n", hNotifyKey, pszKeyName);
119 
120     dwError = RegOpenKeyExW(hNotifyKey,
121                             pszKeyName,
122                             0,
123                             KEY_READ,
124                             &hDllKey);
125     if (dwError != ERROR_SUCCESS)
126         return;
127 
128     NotificationDll = RtlAllocateHeap(RtlGetProcessHeap(),
129                                       HEAP_ZERO_MEMORY,
130                                       sizeof(NOTIFICATION_ITEM));
131     if (NotificationDll == NULL)
132     {
133         dwError = ERROR_OUTOFMEMORY;
134         goto done;
135     }
136 
137     NotificationDll->pszKeyName = RtlAllocateHeap(RtlGetProcessHeap(),
138                                                   HEAP_ZERO_MEMORY,
139                                                   (wcslen(pszKeyName) + 1) * sizeof(WCHAR));
140     if (NotificationDll->pszKeyName == NULL)
141     {
142         dwError = ERROR_OUTOFMEMORY;
143         goto done;
144     }
145 
146     wcscpy(NotificationDll->pszKeyName, pszKeyName);
147 
148     dwSize = 0;
149     RegQueryValueExW(hDllKey,
150                      L"DllName",
151                      NULL,
152                      &dwType,
153                      NULL,
154                      &dwSize);
155     if (dwSize == 0)
156     {
157         dwError = ERROR_FILE_NOT_FOUND;
158         goto done;
159     }
160 
161     NotificationDll->pszDllName = RtlAllocateHeap(RtlGetProcessHeap(),
162                                                   HEAP_ZERO_MEMORY,
163                                                   dwSize);
164     if (NotificationDll->pszDllName == NULL)
165     {
166         dwError = ERROR_OUTOFMEMORY;
167         goto done;
168     }
169 
170     dwError = RegQueryValueExW(hDllKey,
171                                L"DllName",
172                                NULL,
173                                &dwType,
174                                (PBYTE)NotificationDll->pszDllName,
175                                &dwSize);
176     if (dwError != ERROR_SUCCESS)
177         goto done;
178 
179     NotificationDll->bEnabled = TRUE;
180     NotificationDll->dwMaxWait = 30; /* FIXME: ??? */
181 
182     dwSize = sizeof(BOOL);
183     RegQueryValueExW(hDllKey,
184                      L"Asynchronous",
185                      NULL,
186                      &dwType,
187                      (PBYTE)&NotificationDll->bAsynchronous,
188                      &dwSize);
189 
190     dwSize = sizeof(BOOL);
191     RegQueryValueExW(hDllKey,
192                      L"Enabled",
193                      NULL,
194                      &dwType,
195                      (PBYTE)&NotificationDll->bEnabled,
196                      &dwSize);
197 
198     dwSize = sizeof(BOOL);
199     RegQueryValueExW(hDllKey,
200                      L"Impersonate",
201                      NULL,
202                      &dwType,
203                      (PBYTE)&NotificationDll->bImpersonate,
204                      &dwSize);
205 
206     dwSize = sizeof(BOOL);
207     RegQueryValueExW(hDllKey,
208                      L"Safe",
209                      NULL,
210                      &dwType,
211                      (PBYTE)&NotificationDll->bSafe,
212                      &dwSize);
213 
214     dwSize = sizeof(BOOL);
215     RegQueryValueExW(hDllKey,
216                      L"SmartCardLogonNotify",
217                      NULL,
218                      &dwType,
219                      (PBYTE)&NotificationDll->bSmartCardLogon,
220                      &dwSize);
221 
222     dwSize = sizeof(DWORD);
223     RegQueryValueExW(hDllKey,
224                      L"MaxWait",
225                      NULL,
226                      &dwType,
227                      (PBYTE)&NotificationDll->dwMaxWait,
228                      &dwSize);
229 
230     InsertHeadList(&NotificationDllListHead,
231                    &NotificationDll->ListEntry);
232 
233 done:
234     if (dwError != ERROR_SUCCESS)
235     {
236         if (NotificationDll != NULL)
237         {
238             if (NotificationDll->pszKeyName != NULL)
239                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszKeyName);
240 
241             if (NotificationDll->pszDllName != NULL)
242                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszDllName);
243 
244             RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll);
245         }
246     }
247 
248     RegCloseKey(hDllKey);
249 }
250 
251 
252 BOOL
253 InitNotifications(VOID)
254 {
255     HKEY hNotifyKey = NULL;
256     LONG lError;
257     DWORD dwIndex;
258     WCHAR szKeyName[80];
259     DWORD dwKeyName;
260 
261     TRACE("InitNotifications()\n");
262 
263     InitializeListHead(&NotificationDllListHead);
264 
265     AddSfcNotification();
266 
267     lError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
268                            L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify",
269                            0,
270                            KEY_READ | KEY_ENUMERATE_SUB_KEYS,
271                            &hNotifyKey);
272     if (lError != ERROR_SUCCESS)
273     {
274         TRACE("RegOpenKeyExW()\n");
275         return TRUE;
276     }
277 
278     dwIndex = 0;
279     for(;;)
280     {
281         dwKeyName = ARRAYSIZE(szKeyName);
282         lError = RegEnumKeyExW(hNotifyKey,
283                                dwIndex,
284                                szKeyName,
285                                &dwKeyName,
286                                NULL,
287                                NULL,
288                                NULL,
289                                NULL);
290         if (lError != ERROR_SUCCESS)
291             break;
292 
293         TRACE("Notification DLL: %S\n", szKeyName);
294         AddNotificationDll(hNotifyKey, szKeyName);
295 
296         dwIndex++;
297     }
298 
299     RegCloseKey(hNotifyKey);
300 
301     TRACE("InitNotifications() done\n");
302 
303     return TRUE;
304 }
305 
306 
307 static
308 VOID
309 CallNotificationDll(
310     HKEY hNotifyKey,
311     PNOTIFICATION_ITEM NotificationDll,
312     NOTIFICATION_TYPE Type,
313     PWLX_NOTIFICATION_INFO pInfo)
314 {
315     HMODULE hModule;
316     CHAR szFuncBuffer[128];
317     DWORD dwError = ERROR_SUCCESS;
318     PWLX_NOTIFY_HANDLER pNotifyHandler;
319 
320     if (NotificationDll->bSfcNotification)
321     {
322         switch (Type)
323         {
324             case LogonHandler:
325                 strcpy(szFuncBuffer, "SfcWLEventLogon");
326                 break;
327 
328             case LogoffHandler:
329                 strcpy(szFuncBuffer, "SfcWLEventLogoff");
330                 break;
331 
332             default:
333                 return;
334         }
335     }
336     else
337     {
338         HKEY hDllKey;
339         DWORD dwSize;
340         DWORD dwType;
341 
342         dwError = RegOpenKeyExW(hNotifyKey,
343                                 NotificationDll->pszKeyName,
344                                 0,
345                                 KEY_READ,
346                                 &hDllKey);
347         if (dwError != ERROR_SUCCESS)
348         {
349             TRACE("RegOpenKeyExW()\n");
350             return;
351         }
352 
353         dwSize = sizeof(szFuncBuffer);
354         dwError = RegQueryValueExA(hDllKey,
355                                    FuncNames[Type],
356                                    NULL,
357                                    &dwType,
358                                    (PBYTE)szFuncBuffer,
359                                    &dwSize);
360 
361         RegCloseKey(hDllKey);
362     }
363 
364     if (dwError != ERROR_SUCCESS)
365         return;
366 
367     hModule = LoadLibraryW(NotificationDll->pszDllName);
368     if (!hModule)
369         return;
370 
371     pNotifyHandler = (PWLX_NOTIFY_HANDLER)GetProcAddress(hModule, szFuncBuffer);
372 
373     _SEH2_TRY
374     {
375         if (pNotifyHandler)
376             pNotifyHandler(pInfo);
377     }
378     _SEH2_EXCEPT(EXCEPTION_EXECUTE_HANDLER)
379     {
380         ERR("WL: Exception while running notification %S!%s, Status 0x%08lx\n",
381             NotificationDll->pszDllName, szFuncBuffer, _SEH2_GetExceptionCode());
382     }
383     _SEH2_END;
384 
385     FreeLibrary(hModule);
386 }
387 
388 
389 VOID
390 CallNotificationDlls(
391     PWLSESSION pSession,
392     NOTIFICATION_TYPE Type)
393 {
394     PLIST_ENTRY ListEntry;
395     PNOTIFICATION_ITEM NotificationDll;
396     WLX_NOTIFICATION_INFO Info;
397     HKEY hNotifyKey = NULL;
398     DWORD dwError;
399 
400     TRACE("CallNotificationDlls()\n");
401 
402     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
403                             L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify",
404                             0,
405                             KEY_READ | KEY_ENUMERATE_SUB_KEYS,
406                             &hNotifyKey);
407     if (dwError != ERROR_SUCCESS)
408     {
409         TRACE("RegOpenKeyExW()\n");
410         return;
411     }
412 
413     Info.Size = sizeof(WLX_NOTIFICATION_INFO);
414 
415     switch (Type)
416     {
417         case LogoffHandler:
418         case ShutdownHandler:
419             Info.Flags = 3;
420             break;
421 
422         default:
423             Info.Flags = 0;
424             break;
425     }
426 
427     Info.UserName = NULL; //UserName;
428     Info.Domain = NULL; //Domain;
429     Info.WindowStation = pSession->InteractiveWindowStationName;
430     Info.hToken = pSession->UserToken;
431 
432     switch (Type)
433     {
434         case LogonHandler:
435         case StartShellHandler:
436             Info.hDesktop = pSession->ApplicationDesktop;
437             break;
438 
439         case StartScreenSaverHandler:
440             Info.hDesktop = pSession->ApplicationDesktop;
441             break;
442 
443         default:
444             Info.hDesktop = pSession->WinlogonDesktop;
445             break;
446     }
447 
448     Info.pStatusCallback = NULL;
449 
450     ListEntry = NotificationDllListHead.Flink;
451     while (ListEntry != &NotificationDllListHead)
452     {
453 TRACE("ListEntry %p\n", ListEntry);
454 
455         NotificationDll = CONTAINING_RECORD(ListEntry,
456                                             NOTIFICATION_ITEM,
457                                             ListEntry);
458 TRACE("NotificationDll: %p\n", NotificationDll);
459         if (NotificationDll != NULL && NotificationDll->bEnabled)
460             CallNotificationDll(hNotifyKey, NotificationDll, Type, &Info);
461 
462         ListEntry = ListEntry->Flink;
463     }
464 
465     RegCloseKey(hNotifyKey);
466 }
467 
468 
469 VOID
470 CleanupNotifications(VOID)
471 {
472     PLIST_ENTRY ListEntry;
473     PNOTIFICATION_ITEM NotificationDll;
474 
475     ListEntry = NotificationDllListHead.Flink;
476     while (ListEntry != &NotificationDllListHead)
477     {
478         NotificationDll = CONTAINING_RECORD(ListEntry,
479                                             NOTIFICATION_ITEM,
480                                             ListEntry);
481         if (NotificationDll != NULL)
482         {
483             if (NotificationDll->pszKeyName != NULL)
484                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszKeyName);
485 
486             if (NotificationDll->pszDllName != NULL)
487                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszDllName);
488         }
489 
490         ListEntry = ListEntry->Flink;
491 
492         RemoveEntryList(&NotificationDll->ListEntry);
493 
494         RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll);
495     }
496 }
497 
498 /* EOF */
499