Index: dll/win32/wtsapi32/wtsapi32.c =================================================================== --- dll/win32/wtsapi32/wtsapi32.c (revision 41756) +++ dll/win32/wtsapi32/wtsapi32.c (working copy) @@ -15,14 +15,26 @@ * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA */ +#define WIN32_NO_STATUS #include "config.h" #include -#include #include "windef.h" + #include "winbase.h" #include "wtsapi32.h" -#include "wine/debug.h" +#include "winnls.h" +#include "aclapi.h" +#include "debug.h" +#if defined(_MSC_VER) + #include "ntstatus.h" +#endif + +#include "ketypes.h" +#include "extypes.h" +#include "exfuncs.h" +#include "rtlfuncs.h" + WINE_DEFAULT_DEBUG_CHANNEL(wtsapi); static HMODULE WTSAPI32_hModule; @@ -47,6 +59,8 @@ return TRUE; } +static PVOID WTSMallocMemory(SIZE_T nSize); + /************************************************************ * WTSCloseServer (WTSAPI32.@) */ @@ -65,19 +79,205 @@ } /************************************************************ +* QueryProcesses +* Helper function for getting processes list from NtQuerySystemInformation +*/ +static PSYSTEM_PROCESS_INFORMATION QueryProcesses() +{ + PSYSTEM_PROCESS_INFORMATION SysProcessesInfo = NULL; + NTSTATUS Status; + ULONG BufferSize = 0x8000; + ULONG ReturnedBufferSize = 0; + do + { + /* free the buffer, and reallocate it to the new size. RATIONALE: since we + ignore the buffer's contents at this point, there's no point in a realloc() + that could end up copying a large chunk of data we'd discard anyway */ + WTSFreeMemory(SysProcessesInfo); + SysProcessesInfo = (PSYSTEM_PROCESS_INFORMATION)WTSMallocMemory(BufferSize); + + if (SysProcessesInfo == NULL) + { + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + /* query the information */ + Status = NtQuerySystemInformation(SystemProcessInformation, + SysProcessesInfo, + BufferSize, + &ReturnedBufferSize); + + /* adjust necessary buffer size with returned value or double its size */ + BufferSize = ReturnedBufferSize; + } + while (Status == STATUS_INFO_LENGTH_MISMATCH); + return SysProcessesInfo; +} + +/************************************************************ +* GetNextProcess +* Helper function for iterating NtQuerySystemInformation response +*/ +static PSYSTEM_PROCESS_INFORMATION GetNextProcess(PSYSTEM_PROCESS_INFORMATION Process) +{ + if (Process->NextEntryOffset == 0) + { + return NULL; + } + return (PSYSTEM_PROCESS_INFORMATION)((LPBYTE)Process + Process->NextEntryOffset); +} + +/************************************************************ +* CountProcesses +* Helper function for calculating process count +* Also calculates necessary space for ImageName unicode strings +*/ +static DWORD CountProcesses(IN PSYSTEM_PROCESS_INFORMATION Process, OUT PDWORD pImageNameLength) +{ + DWORD ProcessCount = 0; + DWORD Length = 0; + *pImageNameLength = 0; + while (Process != NULL) + { + ++ProcessCount; + Length = Process->ImageName.Length + sizeof(WCHAR); + *pImageNameLength += ALIGN_UP(Length, 8); + Process = GetNextProcess(Process); + } + return ProcessCount; +} +/************************************************************ +* GetProcessOwner +* Helper function for getting owner SID for process +*/ +static BOOL GetProcessOwner(DWORD ProcessId, PSID pSid, DWORD BufferSize) +{ + BOOL Success = FALSE; + HANDLE hProcess = NULL; + PSID ProcessUser = NULL; + PSECURITY_DESCRIPTOR ProcessSD = NULL; + DWORD Error; + hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | READ_CONTROL, FALSE, ProcessId); + if (hProcess != NULL) + { + ProcessUser = NULL; + ProcessSD = NULL; + Error = GetSecurityInfo(hProcess, + SE_KERNEL_OBJECT, + OWNER_SECURITY_INFORMATION, + &ProcessUser, + NULL, + NULL, + NULL, + &ProcessSD); + if (!Error) + { + if (ProcessUser != NULL) + { + Success = !RtlCopySid(BufferSize, pSid, ProcessUser); + } + LocalFree(ProcessSD); + } + CloseHandle(hProcess); + } + return Success; +} + +/************************************************************ * WTSEnumerateProcessesA (WTSAPI32.@) */ BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount) + PWTS_PROCESS_INFOA* ppProcessInfo, DWORD* pCount) { - FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version, - ppProcessInfo, pCount); + PSYSTEM_PROCESS_INFORMATION SysProcessInfo = NULL; + PSYSTEM_PROCESS_INFORMATION SysProcess; + PBYTE Data; + PWTS_PROCESS_INFOA Process; + ULONG BufferSize = 0; + DWORD ProcessCount = 0; + DWORD Offset; + DWORD Length; + DWORD ProcessId; if (!ppProcessInfo || !pCount) return FALSE; *pCount = 0; - *ppProcessInfo = NULL; + if (Version != 1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (hServer != WTS_CURRENT_SERVER_HANDLE) + { + FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version, + ppProcessInfo, pCount); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + + SysProcessInfo = QueryProcesses(); + if (SysProcessInfo == NULL) + { + return FALSE; + } + // Calculates buffer size for processes information + ProcessCount = CountProcesses(SysProcessInfo, &BufferSize); + // Doubles space for strings (in case of UTF-8 or UTF-7 is used as default code page) + BufferSize *= 2; + // And count space for records and SIDs + BufferSize += ProcessCount * (sizeof(WTS_PROCESS_INFOA) + SECURITY_MAX_SID_SIZE); + + Data = (PBYTE)WTSMallocMemory(BufferSize); + if (Data == NULL) + { + WTSFreeMemory(SysProcessInfo); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + // WTS_PROCESS_INFOW structures are put in beginning of the buffer + // FileName paths and SIDs should be located later after this part + // That way user will be able to free buffer memory + // with single WTSFreeMemory call + for (SysProcess = SysProcessInfo, Process = (PWTS_PROCESS_INFOA)Data, + Offset = ProcessCount * sizeof(WTS_PROCESS_INFOA); + SysProcess != NULL; + SysProcess = GetNextProcess(SysProcess), ++Process) + { + ProcessId = PtrToUint(SysProcess->UniqueProcessId); + Process->SessionId = SysProcess->SessionId; + // Get unique process id + Process->ProcessId = ProcessId; + Process->pProcessName = (LPSTR)(Data + Offset); + RtlUnicodeToMultiByteN(Process->pProcessName, BufferSize - Offset, &Length, + SysProcess->ImageName.Buffer, SysProcess->ImageName.Length); + Process->pProcessName[Length++] = 0; + Offset += ALIGN_UP(Length, 8); + Process->pUserSid = NULL; + if (ProcessId > 0) + { + Process->pUserSid = (PSID)(Data + Offset); + if (GetProcessOwner(ProcessId, Process->pUserSid, BufferSize - Offset)) + { + Length = RtlLengthSid(Process->pUserSid); + Offset += ALIGN_UP(Length, 8); + } + else + { + Process->pUserSid = NULL; + } + } + } + + WTSFreeMemory(SysProcessInfo); + + // Now we may assign output values + *pCount = ProcessCount; + *ppProcessInfo = (PWTS_PROCESS_INFOA)Data; + return TRUE; } @@ -85,16 +285,100 @@ * WTSEnumerateProcessesW (WTSAPI32.@) */ BOOL WINAPI WTSEnumerateProcessesW(HANDLE hServer, DWORD Reserved, DWORD Version, - PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount) + PWTS_PROCESS_INFOW* ppProcessInfo, DWORD* pCount) { - FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version, - ppProcessInfo, pCount); + PSYSTEM_PROCESS_INFORMATION SysProcessInfo = NULL; + PSYSTEM_PROCESS_INFORMATION SysProcess; + PBYTE Data; + PWTS_PROCESS_INFOW Process; + ULONG BufferSize; + DWORD ProcessCount = 0; + DWORD Offset; + DWORD Length; + DWORD ProcessId; if (!ppProcessInfo || !pCount) return FALSE; *pCount = 0; - *ppProcessInfo = NULL; + if (Version != 1) + { + SetLastError(ERROR_INVALID_PARAMETER); + return FALSE; + } + + if (hServer != WTS_CURRENT_SERVER_HANDLE) + { + FIXME("Stub %p 0x%08x 0x%08x %p %p\n", hServer, Reserved, Version, + ppProcessInfo, pCount); + SetLastError(ERROR_CALL_NOT_IMPLEMENTED); + return FALSE; + } + + SysProcessInfo = QueryProcesses(); + if (SysProcessInfo == NULL) + { + return FALSE; + } + /* Calculating necessary buffer length */ + ProcessCount = CountProcesses(SysProcessInfo, &BufferSize); + BufferSize += ProcessCount * (sizeof(WTS_PROCESS_INFOW) + SECURITY_MAX_SID_SIZE); + + Data = (PBYTE)WTSMallocMemory(BufferSize); + if (Data == NULL) + { + WTSFreeMemory(SysProcessInfo); + SetLastError(ERROR_NOT_ENOUGH_MEMORY); + return FALSE; + } + + // WTS_PROCESS_INFOW structures are put in beginning of the buffer + // FileName paths and SIDs should be located later after this part + // That way user will be able to free buffer memory + // with single WTSFreeMemory call + for (SysProcess = SysProcessInfo, Process = (PWTS_PROCESS_INFOW)Data, + Offset = ProcessCount * sizeof(WTS_PROCESS_INFOW); + SysProcess != NULL; + SysProcess = GetNextProcess(SysProcess), ++Process) + { + ProcessId = PtrToUint(SysProcess->UniqueProcessId); + Process->SessionId = SysProcess->SessionId; + // Get unique process id + Process->ProcessId = ProcessId; + Process->pProcessName = (LPWSTR)(Data + Offset); + if (SysProcess->ImageName.Buffer != NULL) + { + Length = SysProcess->ImageName.Length + sizeof(WCHAR); + RtlCopyMemory(Process->pProcessName, SysProcess->ImageName.Buffer, Length); + } + else + { + *Process->pProcessName = L'\0'; + Length = sizeof(*Process->pProcessName); + } + Offset += ALIGN_UP(Length, 8); + Process->pUserSid = NULL; + if (ProcessId > 0) + { + Process->pUserSid = (PSID)(Data + Offset); + if (GetProcessOwner(ProcessId, Process->pUserSid, BufferSize - Offset)) + { + Length = RtlLengthSid(Process->pUserSid); + Offset += ALIGN_UP(Length, 8); + } + else + { + Process->pUserSid = NULL; + } + } + } + + WTSFreeMemory(SysProcessInfo); + + // Now we may assign output values + *pCount = ProcessCount; + *ppProcessInfo = (PWTS_PROCESS_INFOW)Data; + return TRUE; } @@ -133,12 +417,20 @@ } /************************************************************ +* WTSMallocMemory +* Complimentary function to WTSFreeMemory from API +*/ +static PVOID WTSMallocMemory(SIZE_T nSize) +{ + return HeapAlloc(GetProcessHeap(), 0, nSize); +} + +/************************************************************ * WTSFreeMemory (WTSAPI32.@) */ void WINAPI WTSFreeMemory(PVOID pMemory) { - FIXME("Stub %p\n", pMemory); - return; + HeapFree(GetProcessHeap(), 0, pMemory); } /************************************************************ Index: include/psdk/wtsapi32.h =================================================================== --- include/psdk/wtsapi32.h (revision 41756) +++ include/psdk/wtsapi32.h (working copy) @@ -23,6 +23,12 @@ extern "C" { #endif +/* +* Current server information +*/ +#define WTS_CURRENT_SERVER ((HANDLE)NULL) +#define WTS_CURRENT_SERVER_HANDLE ((HANDLE)NULL) +#define WTS_CURRENT_SERVER_NAME (NULL) typedef enum tagWTS_INFO_CLASS {