xref: /reactos/win32ss/user/user32/misc/winsta.c (revision 80733143)
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     UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
64     OBJECT_ATTRIBUTES ObjectAttributes;
65     HANDLE hWindowStationsDir;
66 
67     /* Open WindowStations directory */
68     InitializeObjectAttributes(&ObjectAttributes,
69                                &WindowStationsDir,
70                                OBJ_CASE_INSENSITIVE,
71                                NULL,
72                                NULL);
73 
74     Status = NtOpenDirectoryObject(&hWindowStationsDir,
75                                    DIRECTORY_CREATE_OBJECT,
76                                    &ObjectAttributes);
77     if (!NT_SUCCESS(Status))
78     {
79         ERR("Failed to open WindowStations directory\n");
80         return NULL;
81     }
82 
83     RtlInitUnicodeString(&WindowStationName, lpwinsta);
84 
85     /* Create the window station object */
86     InitializeObjectAttributes(&ObjectAttributes,
87                                &WindowStationName,
88                                OBJ_CASE_INSENSITIVE,
89                                hWindowStationsDir,
90                                NULL);
91 
92     /* Check if the handle should be inheritable */
93     if (lpsa && lpsa->bInheritHandle)
94     {
95         ObjectAttributes.Attributes |= OBJ_INHERIT;
96     }
97 
98     hWinSta = NtUserCreateWindowStation(&ObjectAttributes,
99                                         dwDesiredAccess,
100                                         0, 0, 0, 0, 0);
101 
102     NtClose(hWindowStationsDir);
103 
104     return hWinSta;
105 }
106 
107 /*
108  * Common code for EnumDesktopsA/W and EnumWindowStationsA/W
109  */
110 BOOL
111 FASTCALL
112 EnumNamesW(HWINSTA WindowStation,
113            NAMEENUMPROCW EnumFunc,
114            LPARAM Context,
115            BOOL Desktops)
116 {
117     CHAR Buffer[256];
118     PVOID NameList;
119     PWCHAR Name;
120     NTSTATUS Status;
121     ULONG RequiredSize;
122     ULONG CurrentEntry, EntryCount;
123     BOOL Ret;
124 
125     /* Check parameters */
126     if (WindowStation == NULL && Desktops)
127     {
128         WindowStation = GetProcessWindowStation();
129     }
130 
131     /* Try with fixed-size buffer */
132     Status = NtUserBuildNameList(WindowStation, sizeof(Buffer), Buffer, &RequiredSize);
133     if (NT_SUCCESS(Status))
134     {
135         /* Fixed-size buffer is large enough */
136         NameList = (PWCHAR) Buffer;
137     }
138     else if (Status == STATUS_BUFFER_TOO_SMALL)
139     {
140         /* Allocate a larger buffer */
141         NameList = HeapAlloc(GetProcessHeap(), 0, RequiredSize);
142         if (NameList == NULL)
143             return FALSE;
144 
145         /* Try again */
146         Status = NtUserBuildNameList(WindowStation, RequiredSize, NameList, NULL);
147         if (!NT_SUCCESS(Status))
148         {
149             HeapFree(GetProcessHeap(), 0, NameList);
150             SetLastError(RtlNtStatusToDosError(Status));
151             return FALSE;
152         }
153     }
154     else
155     {
156         /* Some unrecognized error occured */
157         SetLastError(RtlNtStatusToDosError(Status));
158         return FALSE;
159     }
160 
161     /* Enum the names one by one */
162     EntryCount = *((DWORD *) NameList);
163     Name = (PWCHAR) ((PCHAR) NameList + sizeof(DWORD));
164     Ret = TRUE;
165     for (CurrentEntry = 0; CurrentEntry < EntryCount && Ret; ++CurrentEntry)
166     {
167         Ret = (*EnumFunc)(Name, Context);
168         Name += wcslen(Name) + 1;
169     }
170 
171     /* Cleanup */
172     if (NameList != Buffer)
173     {
174         HeapFree(GetProcessHeap(), 0, NameList);
175     }
176 
177     return Ret;
178 }
179 
180 /* For W->A conversion */
181 typedef struct tagENUMNAMESASCIICONTEXT
182 {
183     NAMEENUMPROCA UserEnumFunc;
184     LPARAM UserContext;
185 } ENUMNAMESASCIICONTEXT, *PENUMNAMESASCIICONTEXT;
186 
187 /*
188  * Callback used by Ascii versions. Converts the Unicode name to
189  * Ascii and then calls the user callback
190  */
191 BOOL
192 CALLBACK
193 EnumNamesCallback(LPWSTR Name, LPARAM Param)
194 {
195     PENUMNAMESASCIICONTEXT Context = (PENUMNAMESASCIICONTEXT) Param;
196     CHAR FixedNameA[32];
197     LPSTR NameA;
198     INT Len;
199     BOOL Ret;
200 
201     /*
202      * Determine required size of Ascii string and see
203      * if we can use fixed buffer.
204      */
205     Len = WideCharToMultiByte(CP_ACP, 0, Name, -1, NULL, 0, NULL, NULL);
206     if (Len <= 0)
207     {
208         /* Some strange error occured */
209         return FALSE;
210     }
211     else if (Len <= sizeof(FixedNameA))
212     {
213         /* Fixed-size buffer is large enough */
214         NameA = FixedNameA;
215     }
216     else
217     {
218         /* Allocate a larger buffer */
219         NameA = HeapAlloc(GetProcessHeap(), 0, Len);
220         if (NULL == NameA)
221         {
222             SetLastError(ERROR_NOT_ENOUGH_MEMORY);
223             return FALSE;
224         }
225     }
226 
227     /* Do the Unicode ->Ascii conversion */
228     if (0 == WideCharToMultiByte(CP_ACP, 0, Name, -1, NameA, Len, NULL, NULL))
229     {
230         /* Something went wrong, clean up */
231         if (NameA != FixedNameA)
232         {
233             HeapFree(GetProcessHeap(), 0, NameA);
234         }
235         return FALSE;
236     }
237 
238     /* Call user callback */
239     Ret = Context->UserEnumFunc(NameA, Context->UserContext);
240 
241     /* Cleanup */
242     if (NameA != FixedNameA)
243     {
244         HeapFree(GetProcessHeap(), 0, NameA);
245     }
246 
247     return Ret;
248 }
249 
250 /*
251  * Common code for EnumDesktopsA and EnumWindowStationsA
252  */
253 BOOL
254 FASTCALL
255 EnumNamesA(HWINSTA WindowStation,
256            NAMEENUMPROCA EnumFunc,
257            LPARAM Context,
258            BOOL Desktops)
259 {
260     ENUMNAMESASCIICONTEXT PrivateContext;
261 
262     PrivateContext.UserEnumFunc = EnumFunc;
263     PrivateContext.UserContext = Context;
264 
265     return EnumNamesW(WindowStation, EnumNamesCallback, (LPARAM) &PrivateContext, Desktops);
266 }
267 
268 /*
269  * @implemented
270  */
271 BOOL
272 WINAPI
273 EnumWindowStationsA(
274     IN WINSTAENUMPROCA EnumFunc,
275     IN LPARAM Context)
276 {
277     return EnumNamesA(NULL, EnumFunc, Context, FALSE);
278 }
279 
280 
281 /*
282  * @implemented
283  */
284 BOOL
285 WINAPI
286 EnumWindowStationsW(
287     IN WINSTAENUMPROCW EnumFunc,
288     IN LPARAM Context)
289 {
290     return EnumNamesW(NULL, EnumFunc, Context, FALSE);
291 }
292 
293 
294 /*
295  * @unimplemented on Win32k side
296  */
297 BOOL
298 WINAPI
299 GetWinStationInfo(PVOID pUnknown)
300 {
301     return (BOOL)NtUserCallOneParam((DWORD_PTR)pUnknown, ONEPARAM_ROUTINE_GETWINSTAINFO);
302 }
303 
304 
305 /*
306  * @implemented
307  */
308 HWINSTA
309 WINAPI
310 OpenWindowStationA(
311     IN LPCSTR lpszWinSta,
312     IN BOOL fInherit,
313     IN ACCESS_MASK dwDesiredAccess)
314 {
315     HWINSTA hWinSta;
316     UNICODE_STRING WindowStationNameU;
317 
318     if (lpszWinSta)
319     {
320         /* After conversion, the buffer is zero-terminated */
321         RtlCreateUnicodeStringFromAsciiz(&WindowStationNameU, lpszWinSta);
322     }
323     else
324     {
325         RtlInitUnicodeString(&WindowStationNameU, NULL);
326     }
327 
328     hWinSta = OpenWindowStationW(WindowStationNameU.Buffer,
329                                  fInherit,
330                                  dwDesiredAccess);
331 
332     /* Free the string if it was allocated */
333     if (lpszWinSta) RtlFreeUnicodeString(&WindowStationNameU);
334 
335     return hWinSta;
336 }
337 
338 
339 /*
340  * @implemented
341  */
342 HWINSTA
343 WINAPI
344 OpenWindowStationW(
345     IN LPCWSTR lpszWinSta,
346     IN BOOL fInherit,
347     IN ACCESS_MASK dwDesiredAccess)
348 {
349     NTSTATUS Status;
350     HWINSTA hWinSta;
351     UNICODE_STRING WindowStationName;
352     UNICODE_STRING WindowStationsDir = RTL_CONSTANT_STRING(L"\\Windows\\WindowStations");
353     OBJECT_ATTRIBUTES ObjectAttributes;
354     HANDLE hWindowStationsDir;
355 
356     /* Open WindowStations directory */
357     InitializeObjectAttributes(&ObjectAttributes,
358                                &WindowStationsDir,
359                                OBJ_CASE_INSENSITIVE,
360                                NULL,
361                                NULL);
362 
363     Status = NtOpenDirectoryObject(&hWindowStationsDir,
364                                    DIRECTORY_TRAVERSE,
365                                    &ObjectAttributes);
366     if(!NT_SUCCESS(Status))
367     {
368         ERR("Failed to open WindowStations directory\n");
369         return NULL;
370     }
371 
372     /* Open the window station object */
373     RtlInitUnicodeString(&WindowStationName, lpszWinSta);
374 
375     InitializeObjectAttributes(&ObjectAttributes,
376                                &WindowStationName,
377                                OBJ_CASE_INSENSITIVE,
378                                hWindowStationsDir,
379                                NULL);
380 
381     /* Check if the handle should be inheritable */
382     if (fInherit)
383     {
384         ObjectAttributes.Attributes |= OBJ_INHERIT;
385     }
386 
387     hWinSta = NtUserOpenWindowStation(&ObjectAttributes, dwDesiredAccess);
388 
389     NtClose(hWindowStationsDir);
390 
391     return hWinSta;
392 }
393 
394 
395 /*
396  * @implemented
397  */
398 BOOL
399 WINAPI
400 SetWindowStationUser(
401     IN HWINSTA hWindowStation,
402     IN PLUID pluid,
403     IN PSID psid OPTIONAL,
404     IN DWORD size)
405 {
406     BOOL Success;
407 
408     Success = NtUserSetWindowStationUser(hWindowStation, pluid, psid, size);
409     if (Success)
410     {
411         /* Signal log-on/off to WINSRV */
412 
413         /* User is logging on if *pluid != LuidNone, otherwise it is a log-off */
414         LUID LuidNone = {0, 0};
415         BOOL IsLogon = (pluid && !RtlEqualLuid(pluid, &LuidNone));
416 
417         Logon(IsLogon);
418     }
419 
420     return Success;
421 }
422 
423 /* EOF */
424