1 /*
2 * PROJECT: ReactOS user32.dll
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Window stations
5 * COPYRIGHT: Copyright 2001-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2011-2018 Giannis Adamopoulos
7 */
8
9 #include <user32.h>
10
11 WINE_DEFAULT_DEBUG_CHANNEL(winsta);
12
13 /*
14 * @implemented
15 */
16 HWINSTA
17 WINAPI
CreateWindowStationA(IN LPCSTR lpwinsta OPTIONAL,IN DWORD dwReserved,IN ACCESS_MASK dwDesiredAccess,IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL)18 CreateWindowStationA(
19 IN LPCSTR lpwinsta OPTIONAL,
20 IN DWORD dwReserved,
21 IN ACCESS_MASK dwDesiredAccess,
22 IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL)
23 {
24 HWINSTA hWinSta;
25 UNICODE_STRING WindowStationNameU;
26
27 if (lpwinsta)
28 {
29 /* After conversion, the buffer is zero-terminated */
30 RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpwinsta);
31 }
32 else
33 {
34 RtlInitUnicodeString(&WindowStationNameU, NULL);
35 }
36
37 hWinSta = CreateWindowStationW(WindowStationNameU.Buffer,
38 dwReserved,
39 dwDesiredAccess,
40 lpsa);
41
42 /* Free the string if it was allocated */
43 if (lpwinsta) RtlFreeUnicodeString(&WindowStationNameU);
44
45 return hWinSta;
46 }
47
48
49 /*
50 * @implemented
51 */
52 HWINSTA
53 WINAPI
CreateWindowStationW(IN LPCWSTR lpwinsta OPTIONAL,IN DWORD dwReserved,IN ACCESS_MASK dwDesiredAccess,IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL)54 CreateWindowStationW(
55 IN LPCWSTR lpwinsta OPTIONAL,
56 IN DWORD dwReserved,
57 IN ACCESS_MASK dwDesiredAccess,
58 IN LPSECURITY_ATTRIBUTES lpsa OPTIONAL)
59 {
60 NTSTATUS Status;
61 HWINSTA hWinSta;
62 UNICODE_STRING WindowStationName;
63 // FIXME: We should cache a per-session directory (see ntuser\winsta.c!UserCreateWinstaDirectory).
64 UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
65 OBJECT_ATTRIBUTES ObjectAttributes;
66 HANDLE hWindowStationsDir;
67
68 /*
69 * If provided, the window station name is always relative to the
70 * current user session's WindowStations directory.
71 * Otherwise (the window station name is NULL or an empty string),
72 * pass both an empty string and no WindowStations directory handle
73 * to win32k, so that it will create a window station whose name
74 * is based on the logon session identifier for the calling process.
75 */
76 if (lpwinsta && *lpwinsta)
77 {
78 /* Open WindowStations directory */
79 InitializeObjectAttributes(&ObjectAttributes,
80 &WindowStationsDir,
81 OBJ_CASE_INSENSITIVE,
82 NULL,
83 NULL);
84
85 Status = NtOpenDirectoryObject(&hWindowStationsDir,
86 DIRECTORY_CREATE_OBJECT,
87 &ObjectAttributes);
88 if (!NT_SUCCESS(Status))
89 {
90 ERR("Failed to open WindowStations directory\n");
91 return NULL;
92 }
93
94 RtlInitUnicodeString(&WindowStationName, lpwinsta);
95 }
96 else
97 {
98 lpwinsta = NULL;
99 hWindowStationsDir = NULL;
100 }
101
102 /* Create the window station object */
103 InitializeObjectAttributes(&ObjectAttributes,
104 lpwinsta ? &WindowStationName : NULL,
105 OBJ_CASE_INSENSITIVE | OBJ_OPENIF,
106 hWindowStationsDir,
107 lpsa ? lpsa->lpSecurityDescriptor : NULL);
108
109 /* Check if the handle should be inheritable */
110 if (lpsa && lpsa->bInheritHandle)
111 {
112 ObjectAttributes.Attributes |= OBJ_INHERIT;
113 }
114
115 hWinSta = NtUserCreateWindowStation(&ObjectAttributes,
116 dwDesiredAccess,
117 0, 0, 0, 0, 0);
118
119 if (hWindowStationsDir)
120 NtClose(hWindowStationsDir);
121
122 return hWinSta;
123 }
124
125 /*
126 * Common code for EnumDesktopsA/W and EnumWindowStationsA/W
127 */
128 BOOL
129 FASTCALL
EnumNamesW(HWINSTA WindowStation,NAMEENUMPROCW EnumFunc,LPARAM Context,BOOL Desktops)130 EnumNamesW(HWINSTA WindowStation,
131 NAMEENUMPROCW EnumFunc,
132 LPARAM Context,
133 BOOL Desktops)
134 {
135 CHAR Buffer[256];
136 PVOID NameList;
137 PWCHAR Name;
138 NTSTATUS Status;
139 ULONG RequiredSize;
140 ULONG CurrentEntry, EntryCount;
141 BOOL Ret;
142
143 /* Check parameters */
144 if (WindowStation == NULL && Desktops)
145 {
146 WindowStation = GetProcessWindowStation();
147 }
148
149 /* Try with fixed-size buffer */
150 Status = NtUserBuildNameList(WindowStation, sizeof(Buffer), Buffer, &RequiredSize);
151 if (NT_SUCCESS(Status))
152 {
153 /* Fixed-size buffer is large enough */
154 NameList = (PWCHAR) Buffer;
155 }
156 else if (Status == STATUS_BUFFER_TOO_SMALL)
157 {
158 /* Allocate a larger buffer */
159 NameList = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
160 if (NameList == NULL)
161 return FALSE;
162
163 /* Try again */
164 Status = NtUserBuildNameList(WindowStation, RequiredSize, NameList, NULL);
165 if (!NT_SUCCESS(Status))
166 {
167 HeapFree(GetProcessHeap(), 0, NameList);
168 SetLastError(RtlNtStatusToDosError(Status));
169 return FALSE;
170 }
171 }
172 else
173 {
174 /* Some unrecognized error occured */
175 SetLastError(RtlNtStatusToDosError(Status));
176 return FALSE;
177 }
178
179 /* Enum the names one by one */
180 EntryCount = *((DWORD *) NameList);
181 Name = (PWCHAR) ((PCHAR) NameList + sizeof(DWORD));
182 Ret = TRUE;
183 for (CurrentEntry = 0; CurrentEntry < EntryCount && Ret; ++CurrentEntry)
184 {
185 Ret = (*EnumFunc)(Name, Context);
186 Name += wcslen(Name) + 1;
187 }
188
189 /* Cleanup */
190 if (NameList != Buffer)
191 {
192 HeapFree(GetProcessHeap(), 0, NameList);
193 }
194
195 return Ret;
196 }
197
198 /* For W->A conversion */
199 typedef struct tagENUMNAMESASCIICONTEXT
200 {
201 NAMEENUMPROCA UserEnumFunc;
202 LPARAM UserContext;
203 } ENUMNAMESASCIICONTEXT, *PENUMNAMESASCIICONTEXT;
204
205 /*
206 * Callback used by Ascii versions. Converts the Unicode name to
207 * Ascii and then calls the user callback
208 */
209 BOOL
210 CALLBACK
EnumNamesCallback(LPWSTR Name,LPARAM Param)211 EnumNamesCallback(LPWSTR Name, LPARAM Param)
212 {
213 PENUMNAMESASCIICONTEXT Context = (PENUMNAMESASCIICONTEXT) Param;
214 CHAR FixedNameA[32];
215 LPSTR NameA;
216 INT Len;
217 BOOL Ret;
218
219 /*
220 * Determine required size of Ascii string and see
221 * if we can use fixed buffer.
222 */
223 Len = WideCharToMultiByte(CP_ACP, 0, Name, -1, NULL, 0, NULL, NULL);
224 if (Len <= 0)
225 {
226 /* Some strange error occured */
227 return FALSE;
228 }
229 else if (Len <= sizeof(FixedNameA))
230 {
231 /* Fixed-size buffer is large enough */
232 NameA = FixedNameA;
233 }
234 else
235 {
236 /* Allocate a larger buffer */
237 NameA = HeapAlloc(GetProcessHeap(), 0, Len);
238 if (NULL == NameA)
239 {
240 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
241 return FALSE;
242 }
243 }
244
245 /* Do the Unicode ->Ascii conversion */
246 if (0 == WideCharToMultiByte(CP_ACP, 0, Name, -1, NameA, Len, NULL, NULL))
247 {
248 /* Something went wrong, clean up */
249 if (NameA != FixedNameA)
250 {
251 HeapFree(GetProcessHeap(), 0, NameA);
252 }
253 return FALSE;
254 }
255
256 /* Call user callback */
257 Ret = Context->UserEnumFunc(NameA, Context->UserContext);
258
259 /* Cleanup */
260 if (NameA != FixedNameA)
261 {
262 HeapFree(GetProcessHeap(), 0, NameA);
263 }
264
265 return Ret;
266 }
267
268 /*
269 * Common code for EnumDesktopsA and EnumWindowStationsA
270 */
271 BOOL
272 FASTCALL
EnumNamesA(HWINSTA WindowStation,NAMEENUMPROCA EnumFunc,LPARAM Context,BOOL Desktops)273 EnumNamesA(HWINSTA WindowStation,
274 NAMEENUMPROCA EnumFunc,
275 LPARAM Context,
276 BOOL Desktops)
277 {
278 ENUMNAMESASCIICONTEXT PrivateContext;
279
280 PrivateContext.UserEnumFunc = EnumFunc;
281 PrivateContext.UserContext = Context;
282
283 return EnumNamesW(WindowStation, EnumNamesCallback, (LPARAM) &PrivateContext, Desktops);
284 }
285
286 /*
287 * @implemented
288 */
289 BOOL
290 WINAPI
EnumWindowStationsA(IN WINSTAENUMPROCA EnumFunc,IN LPARAM Context)291 EnumWindowStationsA(
292 IN WINSTAENUMPROCA EnumFunc,
293 IN LPARAM Context)
294 {
295 return EnumNamesA(NULL, EnumFunc, Context, FALSE);
296 }
297
298
299 /*
300 * @implemented
301 */
302 BOOL
303 WINAPI
EnumWindowStationsW(IN WINSTAENUMPROCW EnumFunc,IN LPARAM Context)304 EnumWindowStationsW(
305 IN WINSTAENUMPROCW EnumFunc,
306 IN LPARAM Context)
307 {
308 return EnumNamesW(NULL, EnumFunc, Context, FALSE);
309 }
310
311
312 /*
313 * @unimplemented on Win32k side
314 */
315 BOOL
316 WINAPI
GetWinStationInfo(PVOID pUnknown)317 GetWinStationInfo(PVOID pUnknown)
318 {
319 return (BOOL)NtUserCallOneParam((DWORD_PTR)pUnknown, ONEPARAM_ROUTINE_GETWINSTAINFO);
320 }
321
322
323 /*
324 * @implemented
325 */
326 HWINSTA
327 WINAPI
OpenWindowStationA(IN LPCSTR lpszWinSta,IN BOOL fInherit,IN ACCESS_MASK dwDesiredAccess)328 OpenWindowStationA(
329 IN LPCSTR lpszWinSta,
330 IN BOOL fInherit,
331 IN ACCESS_MASK dwDesiredAccess)
332 {
333 HWINSTA hWinSta;
334 UNICODE_STRING WindowStationNameU;
335
336 if (lpszWinSta)
337 {
338 /* After conversion, the buffer is zero-terminated */
339 RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpszWinSta);
340 }
341 else
342 {
343 RtlInitUnicodeString(&WindowStationNameU, NULL);
344 }
345
346 hWinSta = OpenWindowStationW(WindowStationNameU.Buffer,
347 fInherit,
348 dwDesiredAccess);
349
350 /* Free the string if it was allocated */
351 if (lpszWinSta) RtlFreeUnicodeString(&WindowStationNameU);
352
353 return hWinSta;
354 }
355
356
357 /*
358 * @implemented
359 */
360 HWINSTA
361 WINAPI
OpenWindowStationW(IN LPCWSTR lpszWinSta,IN BOOL fInherit,IN ACCESS_MASK dwDesiredAccess)362 OpenWindowStationW(
363 IN LPCWSTR lpszWinSta,
364 IN BOOL fInherit,
365 IN ACCESS_MASK dwDesiredAccess)
366 {
367 NTSTATUS Status;
368 HWINSTA hWinSta;
369 UNICODE_STRING WindowStationName;
370 // FIXME: We should cache a per-session directory (see ntuser\winsta.c!UserCreateWinstaDirectory).
371 UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
372 OBJECT_ATTRIBUTES ObjectAttributes;
373 HANDLE hWindowStationsDir;
374
375 /* Open WindowStations directory */
376 InitializeObjectAttributes(&ObjectAttributes,
377 &WindowStationsDir,
378 OBJ_CASE_INSENSITIVE,
379 NULL,
380 NULL);
381
382 Status = NtOpenDirectoryObject(&hWindowStationsDir,
383 DIRECTORY_TRAVERSE,
384 &ObjectAttributes);
385 if(!NT_SUCCESS(Status))
386 {
387 ERR("Failed to open WindowStations directory\n");
388 return NULL;
389 }
390
391 /* Open the window station object */
392 RtlInitUnicodeString(&WindowStationName, lpszWinSta);
393
394 InitializeObjectAttributes(&ObjectAttributes,
395 &WindowStationName,
396 OBJ_CASE_INSENSITIVE,
397 hWindowStationsDir,
398 NULL);
399
400 /* Check if the handle should be inheritable */
401 if (fInherit)
402 {
403 ObjectAttributes.Attributes |= OBJ_INHERIT;
404 }
405
406 hWinSta = NtUserOpenWindowStation(&ObjectAttributes, dwDesiredAccess);
407
408 NtClose(hWindowStationsDir);
409
410 return hWinSta;
411 }
412
413
414 /*
415 * @implemented
416 */
417 BOOL
418 WINAPI
SetWindowStationUser(IN HWINSTA hWindowStation,IN PLUID pluid,IN PSID psid OPTIONAL,IN DWORD size)419 SetWindowStationUser(
420 IN HWINSTA hWindowStation,
421 IN PLUID pluid,
422 IN PSID psid OPTIONAL,
423 IN DWORD size)
424 {
425 BOOL Success;
426
427 Success = NtUserSetWindowStationUser(hWindowStation, pluid, psid, size);
428 if (Success)
429 {
430 /* Signal log-on/off to WINSRV */
431
432 /* User is logging on if *pluid != LuidNone, otherwise it is a log-off */
433 LUID LuidNone = {0, 0};
434 BOOL IsLogon = (pluid && !RtlEqualLuid(pluid, &LuidNone));
435
436 Logon(IsLogon);
437 }
438
439 return Success;
440 }
441
442 /* EOF */
443