xref: /reactos/base/system/winlogon/notify.c (revision 682f85ad)
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 = 80 * sizeof(WCHAR);
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     HKEY hDllKey = NULL;
316     HMODULE hModule = NULL;
317     CHAR szFuncBuffer[128];
318     DWORD dwSize;
319     DWORD dwType;
320     DWORD dwError = ERROR_SUCCESS;
321     PWLX_NOTIFY_HANDLER pNotifyHandler;
322 
323     if (NotificationDll->bSfcNotification)
324     {
325         switch (Type)
326         {
327             case LogonHandler:
328                 strcpy(szFuncBuffer, "SfcWLEventLogon");
329                 break;
330 
331             case LogoffHandler:
332                 strcpy(szFuncBuffer, "SfcWLEventLogoff");
333                 break;
334 
335             default:
336                 return;
337         }
338     }
339     else
340     {
341         dwError = RegOpenKeyExW(hNotifyKey,
342                                 NotificationDll->pszKeyName,
343                                 0,
344                                 KEY_READ,
345                                 &hDllKey);
346         if (dwError != ERROR_SUCCESS)
347         {
348             TRACE("RegOpenKeyExW()\n");
349             return;
350         }
351 
352         dwSize = sizeof(szFuncBuffer);
353         dwError = RegQueryValueExA(hDllKey,
354                                    FuncNames[Type],
355                                    NULL,
356                                    &dwType,
357                                    (PBYTE)szFuncBuffer,
358                                    &dwSize);
359     }
360 
361     if (dwError == ERROR_SUCCESS)
362     {
363         hModule = LoadLibraryW(NotificationDll->pszDllName);
364         if (hModule != NULL)
365         {
366             pNotifyHandler = (PWLX_NOTIFY_HANDLER)GetProcAddress(hModule, szFuncBuffer);
367             if (pNotifyHandler != NULL)
368                 pNotifyHandler(pInfo);
369 
370             FreeLibrary(hModule);
371         }
372     }
373 
374     if (hDllKey != NULL)
375         RegCloseKey(hDllKey);
376 }
377 
378 
379 VOID
380 CallNotificationDlls(
381     PWLSESSION pSession,
382     NOTIFICATION_TYPE Type)
383 {
384     PLIST_ENTRY ListEntry;
385     PNOTIFICATION_ITEM NotificationDll;
386     WLX_NOTIFICATION_INFO Info;
387     HKEY hNotifyKey = NULL;
388     DWORD dwError;
389 
390     TRACE("CallNotificationDlls()\n");
391 
392     dwError = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
393                             L"Software\\Microsoft\\Windows NT\\CurrentVersion\\Winlogon\\Notify",
394                             0,
395                             KEY_READ | KEY_ENUMERATE_SUB_KEYS,
396                             &hNotifyKey);
397     if (dwError != ERROR_SUCCESS)
398     {
399         TRACE("RegOpenKeyExW()\n");
400         return;
401     }
402 
403     Info.Size = sizeof(WLX_NOTIFICATION_INFO);
404 
405     switch (Type)
406     {
407         case LogoffHandler:
408         case ShutdownHandler:
409             Info.Flags = 3;
410             break;
411 
412         default:
413             Info.Flags = 0;
414             break;
415     }
416 
417     Info.UserName = NULL; //UserName;
418     Info.Domain = NULL; //Domain;
419     Info.WindowStation = pSession->InteractiveWindowStationName;
420     Info.hToken = pSession->UserToken;
421 
422     switch (Type)
423     {
424         case LogonHandler:
425         case StartShellHandler:
426             Info.hDesktop = pSession->ApplicationDesktop;
427             break;
428 
429         case StartScreenSaverHandler:
430             Info.hDesktop = pSession->ApplicationDesktop;
431             break;
432 
433         default:
434             Info.hDesktop = pSession->WinlogonDesktop;
435             break;
436     }
437 
438     Info.pStatusCallback = NULL;
439 
440     ListEntry = NotificationDllListHead.Flink;
441     while (ListEntry != &NotificationDllListHead)
442     {
443 TRACE("ListEntry %p\n", ListEntry);
444 
445         NotificationDll = CONTAINING_RECORD(ListEntry,
446                                             NOTIFICATION_ITEM,
447                                             ListEntry);
448 TRACE("NotificationDll: %p\n", NotificationDll);
449         if (NotificationDll != NULL && NotificationDll->bEnabled)
450             CallNotificationDll(hNotifyKey, NotificationDll, Type, &Info);
451 
452         ListEntry = ListEntry->Flink;
453     }
454 
455     RegCloseKey(hNotifyKey);
456 }
457 
458 
459 VOID
460 CleanupNotifications(VOID)
461 {
462     PLIST_ENTRY ListEntry;
463     PNOTIFICATION_ITEM NotificationDll;
464 
465     ListEntry = NotificationDllListHead.Flink;
466     while (ListEntry != &NotificationDllListHead)
467     {
468         NotificationDll = CONTAINING_RECORD(ListEntry,
469                                             NOTIFICATION_ITEM,
470                                             ListEntry);
471         if (NotificationDll != NULL)
472         {
473             if (NotificationDll->pszKeyName != NULL)
474                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszKeyName);
475 
476             if (NotificationDll->pszDllName != NULL)
477                 RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll->pszDllName);
478         }
479 
480         ListEntry = ListEntry->Flink;
481 
482         RemoveEntryList(&NotificationDll->ListEntry);
483 
484         RtlFreeHeap(RtlGetProcessHeap(), 0, NotificationDll);
485     }
486 }
487 
488 /* EOF */
489