xref: /reactos/win32ss/user/user32/misc/winsta.c (revision 84344399)
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
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
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
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
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
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
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
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
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
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
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
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