24dedb5a69fba75443d917a0e3b24c640870053e
[reactos.git] / reactos / subsys / system / winlogon / sas.c
1 /* $Id$
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: services/winlogon/sas.c
6 * PURPOSE: Secure Attention Sequence
7 * PROGRAMMER: Thomas Weidenmueller (w3seek@users.sourceforge.net)
8 * UPDATE HISTORY:
9 * Created 28/03/2004
10 */
11
12 #include "winlogon.h"
13
14 #define NDEBUG
15 #include <debug.h>
16
17 #define HK_CTRL_ALT_DEL 0
18 #define HK_CTRL_SHIFT_ESC 1
19
20 #ifdef __USE_W32API
21 extern BOOL STDCALL SetLogonNotifyWindow(HWND Wnd, HWINSTA WinSta);
22 #endif
23
24 void
25 DispatchSAS(PWLSESSION Session, DWORD dwSasType)
26 {
27 Session->SASAction = dwSasType;
28
29 }
30
31 void
32 UninitSAS(PWLSESSION Session)
33 {
34 if(Session->SASWindow)
35 {
36 DestroyWindow(Session->SASWindow);
37 Session->SASWindow = NULL;
38 }
39 }
40
41 BOOL
42 SetupSAS(PWLSESSION Session, HWND hwndSAS)
43 {
44 /* Register Ctrl+Alt+Del Hotkey */
45 if(!RegisterHotKey(hwndSAS, HK_CTRL_ALT_DEL, MOD_CONTROL | MOD_ALT, VK_DELETE))
46 {
47 DPRINT1("WL-SAS: Unable to register Ctrl+Alt+Del hotkey!\n");
48 return FALSE;
49 }
50
51 /* Register Ctrl+Shift+Esc */
52 Session->TaskManHotkey = RegisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC, MOD_CONTROL | MOD_SHIFT, VK_ESCAPE);
53 if(!Session->TaskManHotkey)
54 {
55 DPRINT1("WL-SAS: Warning: Unable to register Ctrl+Alt+Esc hotkey!\n");
56 }
57 return TRUE;
58 }
59
60 BOOL
61 DestroySAS(PWLSESSION Session, HWND hwndSAS)
62 {
63 /* Unregister hotkeys */
64
65 UnregisterHotKey(hwndSAS, HK_CTRL_ALT_DEL);
66
67 if(Session->TaskManHotkey)
68 {
69 UnregisterHotKey(hwndSAS, HK_CTRL_SHIFT_ESC);
70 }
71
72 return TRUE;
73 }
74
75 #define EWX_ACTION_MASK 0x0b
76 static LRESULT
77 HandleExitWindows(DWORD RequestingProcessId, UINT Flags)
78 {
79 UINT Action;
80 HANDLE Process;
81 HANDLE Token;
82 BOOL CheckResult;
83 PPRIVILEGE_SET PrivSet;
84
85 /* Check parameters */
86 Action = Flags & EWX_ACTION_MASK;
87 if (EWX_LOGOFF != Action && EWX_SHUTDOWN != Action && EWX_REBOOT != Action
88 && EWX_POWEROFF != Action)
89 {
90 DPRINT1("Invalid ExitWindows action 0x%x\n", Action);
91 return STATUS_INVALID_PARAMETER;
92 }
93
94 /* Check privilege */
95 if (EWX_LOGOFF != Action)
96 {
97 Process = OpenProcess(PROCESS_QUERY_INFORMATION, FALSE, RequestingProcessId);
98 if (NULL == Process)
99 {
100 DPRINT1("OpenProcess failed with error %d\n", GetLastError());
101 return STATUS_INVALID_HANDLE;
102 }
103 if (! OpenProcessToken(Process, TOKEN_QUERY, &Token))
104 {
105 DPRINT1("OpenProcessToken failed with error %d\n", GetLastError());
106 CloseHandle(Process);
107 return STATUS_INVALID_HANDLE;
108 }
109 CloseHandle(Process);
110 PrivSet = HeapAlloc(GetProcessHeap(), 0, sizeof(PRIVILEGE_SET) + sizeof(LUID_AND_ATTRIBUTES));
111 if (NULL == PrivSet)
112 {
113 DPRINT1("Failed to allocate mem for privilege set\n");
114 CloseHandle(Token);
115 return STATUS_NO_MEMORY;
116 }
117 PrivSet->PrivilegeCount = 1;
118 PrivSet->Control = PRIVILEGE_SET_ALL_NECESSARY;
119 if (! LookupPrivilegeValue(NULL, SE_SHUTDOWN_NAME, &PrivSet->Privilege[0].Luid))
120 {
121 DPRINT1("LookupPrivilegeValue failed with error %d\n", GetLastError());
122 HeapFree(GetProcessHeap(), 0, PrivSet);
123 CloseHandle(Token);
124 return STATUS_UNSUCCESSFUL;
125 }
126 if (! PrivilegeCheck(Token, PrivSet, &CheckResult))
127 {
128 DPRINT1("PrivilegeCheck failed with error %d\n", GetLastError());
129 HeapFree(GetProcessHeap(), 0, PrivSet);
130 CloseHandle(Token);
131 return STATUS_ACCESS_DENIED;
132 }
133 HeapFree(GetProcessHeap(), 0, PrivSet);
134 CloseHandle(Token);
135 if (! CheckResult)
136 {
137 DPRINT1("SE_SHUTDOWN privilege not enabled\n");
138 return STATUS_ACCESS_DENIED;
139 }
140 }
141
142 /* FIXME actually start logoff/shutdown now */
143
144 return 1;
145 }
146
147 LRESULT CALLBACK
148 SASProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
149 {
150 PWLSESSION Session = (PWLSESSION)GetWindowLongPtr(hwnd, GWL_USERDATA);
151 if(!Session)
152 {
153 return DefWindowProc(hwnd, uMsg, wParam, lParam);
154 }
155 switch(uMsg)
156 {
157 case WM_HOTKEY:
158 {
159 switch(wParam)
160 {
161 case HK_CTRL_ALT_DEL:
162 DPRINT1("SAS: CTR+ALT+DEL\n");
163 break;
164 case HK_CTRL_SHIFT_ESC:
165 DPRINT1("SAS: CTR+SHIFT+ESC\n");
166 break;
167 }
168 return 0;
169 }
170 case WM_CREATE:
171 {
172 if(!SetupSAS(Session, hwnd))
173 {
174 /* Fail! */
175 return 1;
176 }
177 return 0;
178 }
179 case PM_WINLOGON_EXITWINDOWS:
180 {
181 return HandleExitWindows((DWORD) wParam, (UINT) lParam);
182 }
183 case WM_DESTROY:
184 {
185 DestroySAS(Session, hwnd);
186 return 0;
187 }
188 }
189 return DefWindowProc(hwnd, uMsg, wParam, lParam);
190 }
191
192 BOOL
193 InitializeSAS(PWLSESSION Session)
194 {
195 WNDCLASSEX swc;
196
197 /* register SAS window class.
198 WARNING! MAKE SURE WE ARE IN THE WINLOGON DESKTOP! */
199 swc.cbSize = sizeof(WNDCLASSEXW);
200 swc.style = CS_SAVEBITS;
201 swc.lpfnWndProc = SASProc;
202 swc.cbClsExtra = 0;
203 swc.cbWndExtra = 0;
204 swc.hInstance = hAppInstance;
205 swc.hIcon = NULL;
206 swc.hCursor = NULL;
207 swc.hbrBackground = NULL;
208 swc.lpszMenuName = NULL;
209 swc.lpszClassName = WINLOGON_SAS_CLASS;
210 swc.hIconSm = NULL;
211 RegisterClassEx(&swc);
212
213 /* create invisible SAS window */
214 Session->SASWindow = CreateWindowEx(0, WINLOGON_SAS_CLASS, WINLOGON_SAS_TITLE, WS_POPUP,
215 0, 0, 0, 0, 0, 0, hAppInstance, NULL);
216 if(!Session->SASWindow)
217 {
218 DPRINT1("WL: Failed to create SAS window\n");
219 return FALSE;
220 }
221
222 /* Save the Session pointer so the window proc can access it */
223 SetWindowLongPtr(Session->SASWindow, GWL_USERDATA, (DWORD_PTR)Session);
224
225 /* Register SAS window to receive SAS notifications */
226 if(!SetLogonNotifyWindow(Session->SASWindow, Session->InteractiveWindowStation))
227 {
228 UninitSAS(Session);
229 DPRINT1("WL: Failed to register SAS window\n");
230 return FALSE;
231 }
232
233 return TRUE;
234 }
235