https://git.reactos.org/?p=reactos.git;a=commitdiff;h=abb6fd83a482deeb9eefa3b31bd52d45217ef66d

commit abb6fd83a482deeb9eefa3b31bd52d45217ef66d
Author:     Pierre Schweitzer <pie...@reactos.org>
AuthorDate: Sun Dec 30 22:36:54 2018 +0100
Commit:     Pierre Schweitzer <pie...@reactos.org>
CommitDate: Mon Dec 31 11:19:29 2018 +0100

    [ADVAPI32_APITEST] Add tests showing that first field of OwningModuleInfo 
is the tag
    
    Also, show that querying owner information about a connection owned by a 
service
    returns the service name, and not the image nor its path.
    
    Obviously, that fails in ReactOS.
---
 modules/rostests/apitests/advapi32/CMakeLists.txt  |   3 +-
 .../rostests/apitests/advapi32/ServiceNetwork.c    | 449 +++++++++++++++++++++
 modules/rostests/apitests/advapi32/testlist.c      |   2 +
 3 files changed, 453 insertions(+), 1 deletion(-)

diff --git a/modules/rostests/apitests/advapi32/CMakeLists.txt 
b/modules/rostests/apitests/advapi32/CMakeLists.txt
index e34f682676..8d7e56084c 100644
--- a/modules/rostests/apitests/advapi32/CMakeLists.txt
+++ b/modules/rostests/apitests/advapi32/CMakeLists.txt
@@ -16,12 +16,13 @@ list(APPEND SOURCE
     SaferIdentifyLevel.c
     ServiceArgs.c
     ServiceEnv.c
+    ServiceNetwork.c
     svchlp.c
     precomp.h)
 
 add_executable(advapi32_apitest ${SOURCE} testlist.c)
 target_link_libraries(advapi32_apitest wine ${PSEH_LIB})
 set_module_type(advapi32_apitest win32cui)
-add_importlibs(advapi32_apitest advapi32 msvcrt kernel32 ntdll)
+add_importlibs(advapi32_apitest advapi32 iphlpapi ws2_32 msvcrt kernel32 ntdll)
 add_pch(advapi32_apitest precomp.h SOURCE)
 add_rostests_file(TARGET advapi32_apitest)
diff --git a/modules/rostests/apitests/advapi32/ServiceNetwork.c 
b/modules/rostests/apitests/advapi32/ServiceNetwork.c
new file mode 100644
index 0000000000..6b5a5676ac
--- /dev/null
+++ b/modules/rostests/apitests/advapi32/ServiceNetwork.c
@@ -0,0 +1,449 @@
+/*
+ * PROJECT:         ReactOS api tests
+ * LICENSE:         GPLv2+ - See COPYING in the top level directory
+ * PURPOSE:         Test for service networking
+ * PROGRAMMER:      Pierre Schweitzer
+ */
+
+#include "precomp.h"
+
+#include "svchlp.h"
+
+#define WIN32_NO_STATUS
+#include <iphlpapi.h>
+#include <winsock2.h>
+
+/*** Service part of the test ***/
+
+static SERVICE_STATUS_HANDLE status_handle;
+
+static void
+report_service_status(DWORD dwCurrentState,
+                      DWORD dwWin32ExitCode,
+                      DWORD dwWaitHint)
+{
+    BOOL res;
+    SERVICE_STATUS status;
+
+    status.dwServiceType   = SERVICE_WIN32_OWN_PROCESS;
+    status.dwCurrentState  = dwCurrentState;
+    status.dwWin32ExitCode = dwWin32ExitCode;
+    status.dwWaitHint      = dwWaitHint;
+
+    status.dwServiceSpecificExitCode = 0;
+    status.dwCheckPoint              = 0;
+
+    if ( (dwCurrentState == SERVICE_START_PENDING) ||
+         (dwCurrentState == SERVICE_STOP_PENDING)  ||
+         (dwCurrentState == SERVICE_STOPPED) )
+    {
+        status.dwControlsAccepted = 0;
+    }
+    else
+    {
+        status.dwControlsAccepted = SERVICE_ACCEPT_STOP | 
SERVICE_ACCEPT_SHUTDOWN;
+    }
+
+#if 0
+    if ( (dwCurrentState == SERVICE_RUNNING) || (dwCurrentState == 
SERVICE_STOPPED) )
+        status.dwCheckPoint = 0;
+    else
+        status.dwCheckPoint = dwCheckPoint++;
+#endif
+
+    res = SetServiceStatus(status_handle, &status);
+    service_ok(res, "SetServiceStatus(%d) failed: %lu\n", dwCurrentState, 
GetLastError());
+}
+
+static VOID WINAPI service_handler(DWORD ctrl)
+{
+    switch(ctrl)
+    {
+    case SERVICE_CONTROL_STOP:
+    case SERVICE_CONTROL_SHUTDOWN:
+        report_service_status(SERVICE_STOP_PENDING, NO_ERROR, 0);
+    default:
+        report_service_status(SERVICE_RUNNING, NO_ERROR, 0);
+    }
+}
+
+static DWORD GetExtendedTcpTableWithAlloc(PVOID *TcpTable, BOOL Order, DWORD 
Family, TCP_TABLE_CLASS Class)
+{
+    DWORD ret;
+    DWORD Size = 0;
+
+    *TcpTable = NULL;
+
+    ret = GetExtendedTcpTable(*TcpTable, &Size, Order, Family, Class, 0);
+    if (ret == ERROR_INSUFFICIENT_BUFFER)
+    {
+        *TcpTable = HeapAlloc(GetProcessHeap(), 0, Size);
+        if (*TcpTable == NULL)
+        {
+            return ERROR_OUTOFMEMORY;
+        }
+
+        ret = GetExtendedTcpTable(*TcpTable, &Size, Order, Family, Class, 0);
+        if (ret != NO_ERROR)
+        {
+            HeapFree(GetProcessHeap(), 0, *TcpTable);
+            *TcpTable = NULL;
+        }
+    }
+
+    return ret;
+}
+
+static DWORD GetExtendedUdpTableWithAlloc(PVOID *UdpTable, BOOL Order, DWORD 
Family, UDP_TABLE_CLASS Class)
+{
+    DWORD ret;
+    DWORD Size = 0;
+
+    *UdpTable = NULL;
+
+    ret = GetExtendedUdpTable(*UdpTable, &Size, Order, Family, Class, 0);
+    if (ret == ERROR_INSUFFICIENT_BUFFER)
+    {
+        *UdpTable = HeapAlloc(GetProcessHeap(), 0, Size);
+        if (*UdpTable == NULL)
+        {
+            return ERROR_OUTOFMEMORY;
+        }
+
+        ret = GetExtendedUdpTable(*UdpTable, &Size, Order, Family, Class, 0);
+        if (ret != NO_ERROR)
+        {
+            HeapFree(GetProcessHeap(), 0, *UdpTable);
+            *UdpTable = NULL;
+        }
+    }
+
+    return ret;
+}
+
+static void
+test_tcp(LPWSTR svc_name, DWORD service_tag)
+{
+    SOCKET sock;
+    SOCKADDR_IN server;
+    PMIB_TCPTABLE_OWNER_MODULE TcpTableOwnerMod;
+    DWORD i, ret;
+    BOOLEAN Found;
+    DWORD Pid = GetCurrentProcessId();
+
+    sock = socket(AF_INET, SOCK_STREAM, 0);
+    service_ok(sock != INVALID_SOCKET, "Socket creation failed!\n");
+
+    ZeroMemory(&server, sizeof(SOCKADDR_IN));
+    server.sin_family = AF_INET;
+    server.sin_addr.s_addr = htonl(INADDR_ANY);
+    server.sin_port = htons(9876);
+
+    ret = bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN));
+    service_ok(ret != SOCKET_ERROR, "binding failed\n");
+
+    ret = listen(sock, SOMAXCONN);
+    service_ok(ret != SOCKET_ERROR, "listening failed\n");
+
+    ret = GetExtendedTcpTableWithAlloc((PVOID *)&TcpTableOwnerMod, TRUE, 
AF_INET, TCP_TABLE_OWNER_MODULE_LISTENER);
+    service_ok(ret == ERROR_SUCCESS, "GetExtendedTcpTableWithAlloc failed: 
%x\n", ret);
+    if (ret == ERROR_SUCCESS)
+    {
+        service_ok(TcpTableOwnerMod->dwNumEntries > 0, "No TCP 
connections?!\n");
+
+        Found = FALSE;
+        for (i = 0; i < TcpTableOwnerMod->dwNumEntries; ++i)
+        {
+            if (TcpTableOwnerMod->table[i].dwState == MIB_TCP_STATE_LISTEN &&
+                TcpTableOwnerMod->table[i].dwLocalAddr == 0 &&
+                TcpTableOwnerMod->table[i].dwLocalPort == htons(9876) &&
+                TcpTableOwnerMod->table[i].dwRemoteAddr == 0)
+            {
+                Found = TRUE;
+                break;
+            }
+        }
+
+        service_ok(Found, "Our socket wasn't found!\n");
+        if (Found)
+        {
+            DWORD Size = 0;
+            PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo = NULL;
+
+            service_ok(TcpTableOwnerMod->table[i].dwOwningPid == Pid, "Invalid 
owner\n");
+            service_ok((DWORD)(TcpTableOwnerMod->table[i].OwningModuleInfo[0]) 
== service_tag, "Invalid tag: %x - %x\n", 
(DWORD)TcpTableOwnerMod->table[i].OwningModuleInfo[0], service_tag);
+
+            ret = GetOwnerModuleFromTcpEntry(&TcpTableOwnerMod->table[i], 
TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
+            service_ok(ret == ERROR_INSUFFICIENT_BUFFER, 
"GetOwnerModuleFromTcpEntry failed with: %x\n", ret);
+            if (ERROR_INSUFFICIENT_BUFFER == ERROR_INSUFFICIENT_BUFFER)
+            {
+                BasicInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
Size);
+                service_ok(BasicInfo != NULL, "HeapAlloc failed\n");
+
+                ret = GetOwnerModuleFromTcpEntry(&TcpTableOwnerMod->table[i], 
TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
+                service_ok(ret == ERROR_SUCCESS, "GetOwnerModuleFromTcpEntry 
failed with: %x\n", ret);
+                service_ok(_wcsicmp(svc_name, BasicInfo->pModulePath) == 0, 
"Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModulePath);
+                service_ok(_wcsicmp(svc_name, BasicInfo->pModuleName) == 0, 
"Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModuleName);
+            }
+        }
+
+        HeapFree(GetProcessHeap(), 0, TcpTableOwnerMod);
+    }
+
+    closesocket(sock);
+}
+
+static void
+test_udp(LPWSTR svc_name, DWORD service_tag)
+{
+    SOCKET sock;
+    SOCKADDR_IN server;
+    PMIB_UDPTABLE_OWNER_MODULE UdpTableOwnerMod;
+    DWORD i, ret;
+    BOOLEAN Found;
+    DWORD Pid = GetCurrentProcessId();
+
+    sock = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
+    service_ok(sock != INVALID_SOCKET, "Socket creation failed!\n");
+
+    ZeroMemory(&server, sizeof(SOCKADDR_IN));
+    server.sin_family = AF_INET;
+    server.sin_addr.s_addr = htonl(INADDR_ANY);
+    server.sin_port = htons(9876);
+
+    ret = bind(sock, (SOCKADDR*)&server, sizeof(SOCKADDR_IN));
+    service_ok(ret != SOCKET_ERROR, "binding failed\n");
+
+    ret = GetExtendedUdpTableWithAlloc((PVOID *)&UdpTableOwnerMod, TRUE, 
AF_INET, UDP_TABLE_OWNER_MODULE);
+    service_ok(ret == ERROR_SUCCESS, "GetExtendedUdpTableWithAlloc failed: 
%x\n", ret);
+    if (ret == ERROR_SUCCESS)
+    {
+        service_ok(UdpTableOwnerMod->dwNumEntries > 0, "No TCP 
connections?!\n");
+
+        Found = FALSE;
+        for (i = 0; i < UdpTableOwnerMod->dwNumEntries; ++i)
+        {
+            if (UdpTableOwnerMod->table[i].dwLocalAddr == 0 &&
+                UdpTableOwnerMod->table[i].dwLocalPort == htons(9876))
+            {
+                Found = TRUE;
+                break;
+            }
+        }
+
+        service_ok(Found, "Our socket wasn't found!\n");
+        if (Found)
+        {
+            DWORD Size = 0;
+            PTCPIP_OWNER_MODULE_BASIC_INFO BasicInfo = NULL;
+
+            service_ok(UdpTableOwnerMod->table[i].dwOwningPid == Pid, "Invalid 
owner\n");
+            service_ok((DWORD)(UdpTableOwnerMod->table[i].OwningModuleInfo[0]) 
== service_tag, "Invalid tag: %x - %x\n", 
(DWORD)UdpTableOwnerMod->table[i].OwningModuleInfo[0], service_tag);
+
+            ret = GetOwnerModuleFromUdpEntry(&UdpTableOwnerMod->table[i], 
TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
+            service_ok(ret == ERROR_INSUFFICIENT_BUFFER, 
"GetOwnerModuleFromUdpEntry failed with: %x\n", ret);
+            if (ret == ERROR_INSUFFICIENT_BUFFER)
+            {
+                BasicInfo = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
Size);
+                service_ok(BasicInfo != NULL, "HeapAlloc failed\n");
+
+                ret = GetOwnerModuleFromUdpEntry(&UdpTableOwnerMod->table[i], 
TCPIP_OWNER_MODULE_INFO_BASIC, BasicInfo, &Size);
+                service_ok(ret == ERROR_SUCCESS, "GetOwnerModuleFromUdpEntry 
failed with: %x\n", ret);
+                service_ok(_wcsicmp(svc_name, BasicInfo->pModulePath) == 0, 
"Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModulePath);
+                service_ok(_wcsicmp(svc_name, BasicInfo->pModuleName) == 0, 
"Mismatching names (%S, %S)\n", svc_name, BasicInfo->pModuleName);
+            }
+        }
+
+        HeapFree(GetProcessHeap(), 0, UdpTableOwnerMod);
+    }
+
+    closesocket(sock);
+}
+
+static void WINAPI
+service_main(DWORD dwArgc, LPWSTR* lpszArgv)
+{
+    // SERVICE_STATUS_HANDLE status_handle;
+    PTEB Teb;
+    WSADATA wsaData;
+
+    UNREFERENCED_PARAMETER(dwArgc);
+
+    /* Register our service for control (lpszArgv[0] holds the service name) */
+    status_handle = RegisterServiceCtrlHandlerW(lpszArgv[0], service_handler);
+    service_ok(status_handle != NULL, "RegisterServiceCtrlHandler failed: 
%lu\n", GetLastError());
+    if (!status_handle)
+        return;
+
+    /* Report SERVICE_RUNNING status */
+    report_service_status(SERVICE_RUNNING, NO_ERROR, 4000);
+
+    /* Check our tag is not 0 */
+    Teb = NtCurrentTeb();
+    service_ok(Teb->SubProcessTag != 0, "SubProcessTag is not defined!\n");
+
+    if (WSAStartup(MAKEWORD(2, 2), &wsaData) != 0)
+    {
+        skip("Failed to init WS2\n");
+        goto quit;
+    }
+
+    test_tcp(lpszArgv[0], (DWORD)Teb->SubProcessTag);
+    test_udp(lpszArgv[0], (DWORD)Teb->SubProcessTag);
+
+    WSACleanup();
+quit:
+    /* Work is done */
+    report_service_status(SERVICE_STOPPED, NO_ERROR, 0);
+}
+
+static BOOL start_service(PCSTR service_nameA, PCWSTR service_nameW)
+{
+    BOOL res;
+
+    SERVICE_TABLE_ENTRYW servtbl[] =
+    {
+        { (PWSTR)service_nameW, service_main },
+        { NULL, NULL }
+    };
+
+    res = StartServiceCtrlDispatcherW(servtbl);
+    service_ok(res, "StartServiceCtrlDispatcherW failed: %lu\n", 
GetLastError());
+    return res;
+}
+
+
+/*** Tester part of the test ***/
+
+static void
+my_test_server(PCSTR service_nameA,
+               PCWSTR service_nameW,
+               void *param)
+{
+    BOOL res;
+    SC_HANDLE hSC = NULL;
+    SC_HANDLE hService = NULL;
+    SERVICE_STATUS ServiceStatus;
+
+    /* Open the SCM */
+    hSC = OpenSCManagerW(NULL, NULL, SC_MANAGER_ALL_ACCESS);
+    if (!hSC)
+    {
+        skip("OpenSCManagerW failed with error %lu!\n", GetLastError());
+        return;
+    }
+
+    /* First create ourselves as a service running in the default LocalSystem 
account */
+    hService = register_service_exW(hSC, L"ServiceNetwork", service_nameW, 
NULL,
+                                    SERVICE_ALL_ACCESS,
+                                    SERVICE_WIN32_OWN_PROCESS | 
SERVICE_INTERACTIVE_PROCESS,
+                                    SERVICE_DEMAND_START,
+                                    SERVICE_ERROR_IGNORE,
+                                    NULL, NULL, NULL,
+                                    NULL, NULL);
+    if (!hService)
+    {
+        skip("CreateServiceW failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* Start it */
+    if (!StartServiceW(hService, 0, NULL))
+    {
+        skip("StartServiceW failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* Wait for the service to stop by itself */
+    do
+    {
+        Sleep(100);
+        ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
+        res = QueryServiceStatus(hService, &ServiceStatus);
+    } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
+    ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
+    ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, 
"ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
+
+    /* Be sure the service is really stopped */
+    res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
+    if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
+        ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
+        GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
+    {
+        skip("ControlService failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+#if 0
+    trace("Service stopped. Going to restart it...\n");
+
+    /* Now change the service configuration to make it start under the 
NetworkService account */
+    if (!ChangeServiceConfigW(hService,
+                              SERVICE_NO_CHANGE,
+                              SERVICE_NO_CHANGE,
+                              SERVICE_NO_CHANGE,
+                              NULL, NULL, NULL, NULL,
+                              L"NT AUTHORITY\\NetworkService", L"",
+                              NULL))
+    {
+        skip("ChangeServiceConfigW failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* Start it */
+    if (!StartServiceW(hService, 0, NULL))
+    {
+        skip("StartServiceW failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+
+    /* Wait for the service to stop by itself */
+    do
+    {
+        Sleep(100);
+        ZeroMemory(&ServiceStatus, sizeof(ServiceStatus));
+        res = QueryServiceStatus(hService, &ServiceStatus);
+    } while (res && ServiceStatus.dwCurrentState != SERVICE_STOPPED);
+    ok(res, "QueryServiceStatus failed: %lu\n", GetLastError());
+    ok(ServiceStatus.dwCurrentState == SERVICE_STOPPED, 
"ServiceStatus.dwCurrentState = %lx\n", ServiceStatus.dwCurrentState);
+
+    /* Be sure the service is really stopped */
+    res = ControlService(hService, SERVICE_CONTROL_STOP, &ServiceStatus);
+    if (!res && ServiceStatus.dwCurrentState != SERVICE_STOPPED &&
+        ServiceStatus.dwCurrentState != SERVICE_STOP_PENDING &&
+        GetLastError() != ERROR_SERVICE_NOT_ACTIVE)
+    {
+        skip("ControlService failed with error %lu!\n", GetLastError());
+        goto Cleanup;
+    }
+#endif
+
+Cleanup:
+    if (hService)
+    {
+        res = DeleteService(hService);
+        ok(res, "DeleteService failed: %lu\n", GetLastError());
+        CloseServiceHandle(hService);
+    }
+
+    if (hSC)
+        CloseServiceHandle(hSC);
+}
+
+START_TEST(ServiceNetwork)
+{
+    int argc;
+    char** argv;
+
+    /* Check whether this test is started as a separated service process */
+    argc = winetest_get_mainargs(&argv);
+    if (argc >= 3)
+    {
+        service_process(start_service, argc, argv);
+        return;
+    }
+
+    /* We are started as the real test */
+    test_runner(my_test_server, NULL);
+    // trace("Returned from test_runner\n");
+}
diff --git a/modules/rostests/apitests/advapi32/testlist.c 
b/modules/rostests/apitests/advapi32/testlist.c
index 536162388f..dadd2f6ac1 100644
--- a/modules/rostests/apitests/advapi32/testlist.c
+++ b/modules/rostests/apitests/advapi32/testlist.c
@@ -19,6 +19,7 @@ extern void func_RtlEncryptMemory(void);
 extern void func_SaferIdentifyLevel(void);
 extern void func_ServiceArgs(void);
 extern void func_ServiceEnv(void);
+extern void func_ServiceNetwork(void);
 
 const struct test winetest_testlist[] =
 {
@@ -38,6 +39,7 @@ const struct test winetest_testlist[] =
     { "SaferIdentifyLevel", func_SaferIdentifyLevel },
     { "ServiceArgs", func_ServiceArgs },
     { "ServiceEnv", func_ServiceEnv },
+    { "ServiceNetwork", func_ServiceNetwork },
     { 0, 0 }
 };
 

Reply via email to