Stubplement WTSQueryUserToken.
[reactos.git] / reactos / dll / win32 / wtsapi32 / wtsapi32.c
1 /* Copyright 2005 Ulrich Czekalla
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
15 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
16 */
17
18 #define WIN32_NO_STATUS
19 #include "config.h"
20 #include <stdarg.h>
21 #include "windef.h"
22
23 #include "winbase.h"
24 #include "wtsapi32.h"
25 #include "winnls.h"
26 #include "aclapi.h"
27 #include "debug.h"
28
29 #if defined(_MSC_VER)
30 #include "ntstatus.h"
31 #endif
32
33 #include "ketypes.h"
34 #include "extypes.h"
35 #include "exfuncs.h"
36 #include "rtlfuncs.h"
37
38 WINE_DEFAULT_DEBUG_CHANNEL(wtsapi);
39
40 static HMODULE WTSAPI32_hModule;
41
42 BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
43 {
44 TRACE("%p,%x,%p\n", hinstDLL, fdwReason, lpvReserved);
45
46 switch (fdwReason) {
47 case DLL_PROCESS_ATTACH:
48 {
49 DisableThreadLibraryCalls(hinstDLL);
50 WTSAPI32_hModule = hinstDLL;
51 break;
52 }
53 case DLL_PROCESS_DETACH:
54 {
55 break;
56 }
57 }
58
59 return TRUE;
60 }
61
62 static PVOID WTSMallocMemory(SIZE_T nSize);
63
64 /************************************************************
65 * WTSCloseServer (WTSAPI32.@)
66 */
67 void WINAPI WTSCloseServer(HANDLE hServer)
68 {
69 FIXME("Stub %p\n", hServer);
70 }
71
72 /************************************************************
73 * WTSDisconnectSession (WTSAPI32.@)
74 */
75 BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
76 {
77 FIXME("Stub %p 0x%08x %d\n", hServer, SessionId, bWait);
78 return TRUE;
79 }
80
81 /************************************************************
82 * QueryProcesses
83 * Helper function for getting processes list from NtQuerySystemInformation
84 */
85 static PSYSTEM_PROCESS_INFORMATION QueryProcesses()
86 {
87 PSYSTEM_PROCESS_INFORMATION SysProcessesInfo = NULL;
88 NTSTATUS Status;
89 ULONG BufferSize = 0x8000;
90 ULONG ReturnedBufferSize = 0;
91 do
92 {
93 /* free the buffer, and reallocate it to the new size. RATIONALE: since we
94 ignore the buffer's contents at this point, there's no point in a realloc()
95 that could end up copying a large chunk of data we'd discard anyway */
96 WTSFreeMemory(SysProcessesInfo);
97 SysProcessesInfo = (PSYSTEM_PROCESS_INFORMATION)WTSMallocMemory(BufferSize);
98
99 if (SysProcessesInfo == NULL)
100 {
101 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
102 return FALSE;
103 }
104
105 /* query the information */
106 Status = NtQuerySystemInformation(SystemProcessInformation,
107 SysProcessesInfo,
108 BufferSize,
109 &ReturnedBufferSize);
110
111 /* adjust necessary buffer size with returned value or double its size */
112 BufferSize = ReturnedBufferSize;
113 }
114 while (Status == STATUS_INFO_LENGTH_MISMATCH);
115 return SysProcessesInfo;
116 }
117
118 /************************************************************
119 * GetNextProcess
120 * Helper function for iterating NtQuerySystemInformation response
121 */
122 static PSYSTEM_PROCESS_INFORMATION GetNextProcess(PSYSTEM_PROCESS_INFORMATION Process)
123 {
124 if (Process->NextEntryOffset == 0)
125 {
126 return NULL;
127 }
128 return (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)Process + Process->NextEntryOffset);
129 }
130
131 /************************************************************
132 * CountProcesses
133 * Helper function for calculating process count
134 * Also calculates necessary space for ImageName unicode strings
135 */
136 static DWORD CountProcesses(IN PSYSTEM_PROCESS_INFORMATION Process, OUT PDWORD pImageNameLength)
137 {
138 DWORD ProcessCount = 0;
139 DWORD Length = 0;
140 *pImageNameLength = 0;
141 while (Process != NULL)
142 {
143 ++ProcessCount;
144 Length = Process->ImageName.Length + sizeof(WCHAR);
145 *pImageNameLength += ALIGN_UP(Length, 8);
146 Process = GetNextProcess(Process);
147 }
148 return ProcessCount;
149 }
150 /************************************************************
151 * GetProcessOwner
152 * Helper function for getting owner SID for process
153 */
154 static BOOL GetProcessOwner(DWORD ProcessId, PSID pSid, DWORD BufferSize)
155 {
156 BOOL Success = FALSE;
157 HANDLE hProcess = NULL;
158 PSID ProcessUser = NULL;
159 PSECURITY_DESCRIPTOR ProcessSD = NULL;
160 DWORD Error;
161 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | READ_CONTROL, FALSE, ProcessId);
162 if (hProcess != NULL)
163 {
164 ProcessUser = NULL;
165 ProcessSD = NULL;
166 Error = GetSecurityInfo(hProcess,
167 SE_KERNEL_OBJECT,
168 OWNER_SECURITY_INFORMATION,
169 &ProcessUser,
170 NULL,
171 NULL,
172 NULL,
173 &ProcessSD);
174 if (!Error)
175 {
176 if (ProcessUser != NULL)
177 {
178 Success = !RtlCopySid(BufferSize, pSid, ProcessUser);
179 }
180 LocalFree(ProcessSD);
181 }
182 CloseHandle(hProcess);
183 }
184 return Success;
185 }
186
187 /************************************************************
188 * WTSEnumerateProcessesA (WTSAPI32.@)
189 */
190 BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version,
191 PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount)
192 {
193 PSYSTEM_PROCESS_INFORMATION SysProcessInfo = NULL;
194 PSYSTEM_PROCESS_INFORMATION SysProcess;
195 PBYTE Data;
196 PWTS_PROCESS_INFOA Process;
197 ULONG BufferSize = 0;
198 DWORD ProcessCount = 0;
199 DWORD Offset;
200 DWORD Length;
201 DWORD ProcessId;
202
203 if (!ppProcessInfo || !pCount) return FALSE;
204
205 *pCount = 0;
206
207 if (Version != 1)
208 {
209 SetLastError(ERROR_INVALID_PARAMETER);
210 return FALSE;
211 }
212
213 if (hServer != WTS_CURRENT_SERVER_HANDLE)
214 {
215 FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
216 ppProcessInfo, pCount);
217 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
218 return FALSE;
219 }
220
221 SysProcessInfo = QueryProcesses();
222 if (SysProcessInfo == NULL)
223 {
224 return FALSE;
225 }
226 // Calculates buffer size for processes information
227 ProcessCount = CountProcesses(SysProcessInfo, &BufferSize);
228 // Doubles space for strings (in case of UTF-8 or UTF-7 is used as default code page)
229 BufferSize *= 2;
230 // And count space for records and SIDs
231 BufferSize += ProcessCount * (sizeof(WTS_PROCESS_INFOA) + SECURITY_MAX_SID_SIZE);
232
233 Data = (PBYTE)WTSMallocMemory(BufferSize);
234 if (Data == NULL)
235 {
236 WTSFreeMemory(SysProcessInfo);
237 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
238 return FALSE;
239 }
240
241 // WTS_PROCESS_INFOW structures are put in beginning of the buffer
242 // FileName paths and SIDs should be located later after this part
243 // That way user will be able to free buffer memory
244 // with single WTSFreeMemory call
245 for (SysProcess = SysProcessInfo, Process = (PWTS_PROCESS_INFOA)Data,
246 Offset = ProcessCount * sizeof(WTS_PROCESS_INFOA);
247 SysProcess != NULL;
248 SysProcess = GetNextProcess(SysProcess), ++Process)
249 {
250 ProcessId = PtrToUint(SysProcess->UniqueProcessId);
251 Process->SessionId = SysProcess->SessionId;
252 // Get unique process id
253 Process->ProcessId = ProcessId;
254 Process->pProcessName = (LPSTR)(Data + Offset);
255 RtlUnicodeToMultiByteN(Process->pProcessName, BufferSize - Offset, &Length,
256 SysProcess->ImageName.Buffer, SysProcess->ImageName.Length);
257 Process->pProcessName[Length++] = 0;
258 Offset += ALIGN_UP(Length, 8);
259 Process->pUserSid = NULL;
260 if (ProcessId > 0)
261 {
262 Process->pUserSid = (PSID)(Data + Offset);
263 if (GetProcessOwner(ProcessId, Process->pUserSid, BufferSize - Offset))
264 {
265 Length = RtlLengthSid(Process->pUserSid);
266 Offset += ALIGN_UP(Length, 8);
267 }
268 else
269 {
270 Process->pUserSid = NULL;
271 }
272 }
273 }
274
275 WTSFreeMemory(SysProcessInfo);
276
277 // Now we may assign output values
278 *pCount = ProcessCount;
279 *ppProcessInfo = (PWTS_PROCESS_INFOA)Data;
280
281 return TRUE;
282 }
283
284 /************************************************************
285 * WTSEnumerateProcessesW (WTSAPI32.@)
286 */
287 BOOL WINAPI WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version,
288 PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount)
289 {
290 PSYSTEM_PROCESS_INFORMATION SysProcessInfo = NULL;
291 PSYSTEM_PROCESS_INFORMATION SysProcess;
292 PBYTE Data;
293 PWTS_PROCESS_INFOW Process;
294 ULONG BufferSize;
295 DWORD ProcessCount = 0;
296 DWORD Offset;
297 DWORD Length;
298 DWORD ProcessId;
299
300 if (!ppProcessInfo || !pCount) return FALSE;
301
302 *pCount = 0;
303
304 if (Version != 1)
305 {
306 SetLastError(ERROR_INVALID_PARAMETER);
307 return FALSE;
308 }
309
310 if (hServer != WTS_CURRENT_SERVER_HANDLE)
311 {
312 FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
313 ppProcessInfo, pCount);
314 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
315 return FALSE;
316 }
317
318 SysProcessInfo = QueryProcesses();
319 if (SysProcessInfo == NULL)
320 {
321 return FALSE;
322 }
323 /* Calculating necessary buffer length */
324 ProcessCount = CountProcesses(SysProcessInfo, &BufferSize);
325 BufferSize += ProcessCount * (sizeof(WTS_PROCESS_INFOW) + SECURITY_MAX_SID_SIZE);
326
327 Data = (PBYTE)WTSMallocMemory(BufferSize);
328 if (Data == NULL)
329 {
330 WTSFreeMemory(SysProcessInfo);
331 SetLastError(ERROR_NOT_ENOUGH_MEMORY);
332 return FALSE;
333 }
334
335 // WTS_PROCESS_INFOW structures are put in beginning of the buffer
336 // FileName paths and SIDs should be located later after this part
337 // That way user will be able to free buffer memory
338 // with single WTSFreeMemory call
339 for (SysProcess = SysProcessInfo, Process = (PWTS_PROCESS_INFOW)Data,
340 Offset = ProcessCount * sizeof(WTS_PROCESS_INFOW);
341 SysProcess != NULL;
342 SysProcess = GetNextProcess(SysProcess), ++Process)
343 {
344 ProcessId = PtrToUint(SysProcess->UniqueProcessId);
345 Process->SessionId = SysProcess->SessionId;
346 // Get unique process id
347 Process->ProcessId = ProcessId;
348 Process->pProcessName = (LPWSTR)(Data + Offset);
349 if (SysProcess->ImageName.Buffer != NULL)
350 {
351 Length = SysProcess->ImageName.Length + sizeof(WCHAR);
352 RtlCopyMemory(Process->pProcessName, SysProcess->ImageName.Buffer, Length);
353 }
354 else
355 {
356 *Process->pProcessName = L'\0';
357 Length = sizeof(*Process->pProcessName);
358 }
359 Offset += ALIGN_UP(Length, 8);
360 Process->pUserSid = NULL;
361 if (ProcessId > 0)
362 {
363 Process->pUserSid = (PSID)(Data + Offset);
364 if (GetProcessOwner(ProcessId, Process->pUserSid, BufferSize - Offset))
365 {
366 Length = RtlLengthSid(Process->pUserSid);
367 Offset += ALIGN_UP(Length, 8);
368 }
369 else
370 {
371 Process->pUserSid = NULL;
372 }
373 }
374 }
375
376 WTSFreeMemory(SysProcessInfo);
377
378 // Now we may assign output values
379 *pCount = ProcessCount;
380 *ppProcessInfo = (PWTS_PROCESS_INFOW)Data;
381
382 return TRUE;
383 }
384
385 /************************************************************
386 * WTSEnumerateEnumerateSessionsA (WTSAPI32.@)
387 */
388 BOOL WINAPI WTSEnumerateSessionsA(HANDLE hServer, DWORD Reserved, DWORD Version,
389 PWTS_SESSION_INFOA* ppSessionInfo, DWORD* pCount)
390 {
391 FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
392 ppSessionInfo, pCount);
393
394 if (!ppSessionInfo || !pCount) return FALSE;
395
396 *pCount = 0;
397 *ppSessionInfo = NULL;
398
399 return TRUE;
400 }
401
402 /************************************************************
403 * WTSEnumerateEnumerateSessionsW (WTSAPI32.@)
404 */
405 BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
406 PWTS_SESSION_INFOW* ppSessionInfo, DWORD* pCount)
407 {
408 FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version,
409 ppSessionInfo, pCount);
410
411 if (!ppSessionInfo || !pCount) return FALSE;
412
413 *pCount = 0;
414 *ppSessionInfo = NULL;
415
416 return TRUE;
417 }
418
419 /************************************************************
420 * WTSMallocMemory
421 * Complimentary function to WTSFreeMemory from API
422 */
423 static PVOID WTSMallocMemory(SIZE_T nSize)
424 {
425 return HeapAlloc(GetProcessHeap(), 0, nSize);
426 }
427
428 /************************************************************
429 * WTSFreeMemory (WTSAPI32.@)
430 */
431 void WINAPI WTSFreeMemory(PVOID pMemory)
432 {
433 HeapFree(GetProcessHeap(), 0, pMemory);
434 }
435
436 /************************************************************
437 * WTSOpenServerA (WTSAPI32.@)
438 */
439 HANDLE WINAPI WTSOpenServerA(LPSTR pServerName)
440 {
441 FIXME("(%s) stub\n", debugstr_a(pServerName));
442 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
443 return NULL;
444 }
445
446 /************************************************************
447 * WTSOpenServerW (WTSAPI32.@)
448 */
449 HANDLE WINAPI WTSOpenServerW(LPWSTR pServerName)
450 {
451 FIXME("(%s) stub\n", debugstr_w(pServerName));
452 SetLastError(ERROR_CALL_NOT_IMPLEMENTED);
453 return NULL;
454 }
455
456 /************************************************************
457 * WTSQuerySessionInformationA (WTSAPI32.@)
458 */
459 BOOL WINAPI WTSQuerySessionInformationA(
460 HANDLE hServer,
461 DWORD SessionId,
462 WTS_INFO_CLASS WTSInfoClass,
463 LPSTR* Buffer,
464 DWORD* BytesReturned)
465 {
466 /* FIXME: Forward request to winsta.dll::WinStationQueryInformationA */
467 FIXME("Stub %p 0x%08x %d %p %p\n", hServer, SessionId, WTSInfoClass,
468 Buffer, BytesReturned);
469
470 return FALSE;
471 }
472
473 /************************************************************
474 * WTSQuerySessionInformationW (WTSAPI32.@)
475 */
476 BOOL WINAPI WTSQuerySessionInformationW(
477 HANDLE hServer,
478 DWORD SessionId,
479 WTS_INFO_CLASS WTSInfoClass,
480 LPWSTR* Buffer,
481 DWORD* BytesReturned)
482 {
483 /* FIXME: Forward request to winsta.dll::WinStationQueryInformationW */
484 FIXME("Stub %p 0x%08x %d %p %p\n", hServer, SessionId, WTSInfoClass,
485 Buffer, BytesReturned);
486
487 return FALSE;
488 }
489
490 /************************************************************
491 * WTSQueryUserToken (WTSAPI32.@)
492 *
493 * Obtains the primary access token of the logged-on user specified by the session ID.
494 *
495 * PARAMS
496 * SessionId [in] -- RDP session identifier
497 * phToken [out] -- pointer to the token handle for the logged-on user
498 *
499 *
500 * RETURNS
501 * - On success - pointer to the primary token of the user
502 * - On failure - zero
503 *
504 *
505 * NOTES
506 * - token handle should be closed after use with CloseHandle
507 * - on Failure, extended error information is available via GetLastError
508 *
509 */
510 BOOL WINAPI WTSQueryUserToken(
511 ULONG SessionId,
512 PHANDLE phToken)
513 {
514 *phToken = (HANDLE)0;
515 SetLastError(ERROR_NO_TOKEN);
516 FIXME("Stub %d\n", SessionId);
517 return FALSE;
518 }
519
520 /************************************************************
521 * WTSWaitSystemEvent (WTSAPI32.@)
522 */
523 BOOL WINAPI WTSWaitSystemEvent(HANDLE hServer, DWORD Mask, DWORD* Flags)
524 {
525 /* FIXME: Forward request to winsta.dll::WinStationWaitSystemEvent */
526 FIXME("Stub %p 0x%08x %p\n", hServer, Mask, Flags);
527 return FALSE;
528 }
529
530 /************************************************************
531 * WTSRegisterSessionNotification (WTSAPI32.@)
532 */
533 BOOL WINAPI WTSRegisterSessionNotification(HWND hWnd, DWORD dwFlags)
534 {
535 FIXME("Stub %p 0x%08x\n", hWnd, dwFlags);
536 return FALSE;
537 }
538
539 /************************************************************
540 * WTSUnRegisterSessionNotification (WTSAPI32.@)
541 */
542 BOOL WINAPI WTSUnRegisterSessionNotification(HWND hWnd)
543 {
544 FIXME("Stub %p\n", hWnd);
545 return FALSE;
546 }