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