[wtsapi32]
authorAleksey Bragin <aleksey@reactos.org>
Sat, 10 Oct 2009 12:55:34 +0000 (12:55 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Sat, 10 Oct 2009 12:55:34 +0000 (12:55 +0000)
Andrey Ivanov <andrey.v.ivanov@gmail.com>
- Implement WTSEnumerateProcessesA and WTSEnumerateProcessesW.
See issue #4658 for more details.

svn path=/trunk/; revision=43360

reactos/dll/win32/wtsapi32/wtsapi32.c
reactos/dll/win32/wtsapi32/wtsapi32.rbuild
reactos/include/psdk/wtsapi32.h

index 9935d36..fc40494 100644 (file)
  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
  */
 
+#define WIN32_NO_STATUS
 #include "config.h"
 #include <stdarg.h>
-#include <stdlib.h>
 #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);
 
@@ -47,6 +59,8 @@ BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
     return TRUE;
 }
 
+static PVOID WTSMallocMemory(SIZE_T nSize);
+
 /************************************************************
  *                WTSCloseServer  (WTSAPI32.@)
  */
@@ -64,19 +78,205 @@ BOOL WINAPI WTSDisconnectSession(HANDLE hServer, DWORD SessionId, BOOL bWait)
     return TRUE;
 }
 
+/************************************************************
+*                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,15 +285,99 @@ BOOL WINAPI WTSEnumerateProcessesA(HANDLE hServer, DWORD Reserved, DWORD Version
  *                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;
 }
@@ -132,13 +416,21 @@ BOOL WINAPI WTSEnumerateSessionsW(HANDLE hServer, DWORD Reserved, DWORD Version,
     return TRUE;
 }
 
+/************************************************************
+*                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 247932f..594c97e 100644 (file)
@@ -8,6 +8,7 @@
        <define name="__WINESRC__" />
        <file>wtsapi32.c</file>
        <library>wine</library>
+       <library>advapi32</library>
        <library>kernel32</library>
        <library>ntdll</library>
 </module>
index e777e83..e2f6075 100644 (file)
 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
 {