[PATCH 2/3] kernel32: Implement GetNamedPipeClient/ServerProcessId.

Hans Leidekker hans at codeweavers.com
Wed Apr 11 05:08:09 CDT 2018


Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
 dlls/kernel32/kernel32.spec |   4 +-
 dlls/kernel32/sync.c        |  40 ++++++++++
 dlls/kernel32/tests/pipe.c  | 189 ++++++++++++++++++++++++++++++++++++++++++--
 include/winbase.h           |   5 +-
 include/winioctl.h          |   1 +
 server/named_pipe.c         |  45 +++++++++++
 6 files changed, 276 insertions(+), 8 deletions(-)

diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec
index 2291530ac7..a3ecdf9f2f 100644
--- a/dlls/kernel32/kernel32.spec
+++ b/dlls/kernel32/kernel32.spec
@@ -727,12 +727,12 @@
 # @ stub GetNamedPipeAttribute
 # @ stub GetNamedPipeClientComputerNameA
 # @ stub GetNamedPipeClientComputerNameW
-# @ stub GetNamedPipeClientProcessId
+@ stdcall GetNamedPipeClientProcessId(long ptr)
 # @ stub GetNamedPipeClientSessionId
 @ stdcall GetNamedPipeHandleStateA(long ptr ptr ptr ptr str long)
 @ stdcall GetNamedPipeHandleStateW(long ptr ptr ptr ptr wstr long)
 @ stdcall GetNamedPipeInfo(long ptr ptr ptr ptr)
-# @ stub GetNamedPipeServerProcessId
+@ stdcall GetNamedPipeServerProcessId(long ptr)
 # @ stub GetNamedPipeServerSessionId
 @ stdcall GetNativeSystemInfo(ptr)
 @ stdcall -arch=x86_64 GetNextUmsListItem(ptr)
diff --git a/dlls/kernel32/sync.c b/dlls/kernel32/sync.c
index fcf1be7090..04e9779664 100644
--- a/dlls/kernel32/sync.c
+++ b/dlls/kernel32/sync.c
@@ -1787,6 +1787,46 @@ BOOL WINAPI GetNamedPipeInfo(
 }
 
 /***********************************************************************
+ *           GetNamedPipeClientProcessId  (KERNEL32.@)
+ */
+BOOL WINAPI GetNamedPipeClientProcessId( HANDLE pipe, ULONG *id )
+{
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS status;
+
+    TRACE( "%p %p\n", pipe, id );
+
+    status = NtFsControlFile( pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
+                              (void *)"ClientProcessId", sizeof("ClientProcessId"), id, sizeof(*id) );
+    if (status)
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/***********************************************************************
+ *           GetNamedPipeServerProcessId  (KERNEL32.@)
+ */
+BOOL WINAPI GetNamedPipeServerProcessId( HANDLE pipe, ULONG *id )
+{
+    IO_STATUS_BLOCK iosb;
+    NTSTATUS status;
+
+    TRACE( "%p, %p\n", pipe, id );
+
+    status = NtFsControlFile( pipe, NULL, NULL, NULL, &iosb, FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE,
+                              (void *)"ServerProcessId", sizeof("ServerProcessId"), id, sizeof(*id) );
+    if (status)
+    {
+        SetLastError( RtlNtStatusToDosError(status) );
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/***********************************************************************
  *           GetNamedPipeHandleStateA  (KERNEL32.@)
  */
 BOOL WINAPI GetNamedPipeHandleStateA(
diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c
index 72928ff371..62f2ee3c2f 100644
--- a/dlls/kernel32/tests/pipe.c
+++ b/dlls/kernel32/tests/pipe.c
@@ -38,6 +38,8 @@ static BOOL (WINAPI *pDuplicateTokenEx)(HANDLE,DWORD,LPSECURITY_ATTRIBUTES,
                                         SECURITY_IMPERSONATION_LEVEL,TOKEN_TYPE,PHANDLE);
 static DWORD (WINAPI *pQueueUserAPC)(PAPCFUNC pfnAPC, HANDLE hThread, ULONG_PTR dwData);
 static BOOL (WINAPI *pCancelIoEx)(HANDLE handle, LPOVERLAPPED lpOverlapped);
+static BOOL (WINAPI *pGetNamedPipeClientProcessId)(HANDLE,ULONG*);
+static BOOL (WINAPI *pGetNamedPipeServerProcessId)(HANDLE,ULONG*);
 
 static BOOL user_apc_ran;
 static void CALLBACK user_apc(ULONG_PTR param)
@@ -3283,6 +3285,170 @@ static void test_TransactNamedPipe(void)
     CloseHandle(server);
 }
 
+static HANDLE create_overlapped_server( OVERLAPPED *overlapped )
+{
+    HANDLE pipe;
+    BOOL ret;
+
+    pipe = CreateNamedPipeA(PIPENAME, FILE_FLAG_OVERLAPPED | PIPE_ACCESS_DUPLEX, PIPE_READMODE_BYTE | PIPE_WAIT,
+                            1, 5000, 6000, NMPWAIT_USE_DEFAULT_WAIT, NULL);
+    ok(pipe != INVALID_HANDLE_VALUE, "got %u\n", GetLastError());
+    ret = ConnectNamedPipe(pipe, overlapped);
+    ok(!ret && GetLastError() == ERROR_IO_PENDING, "got %u\n", GetLastError());
+    return pipe;
+}
+
+static void child_process_check_pid(DWORD server_pid)
+{
+    DWORD current = GetProcessId(GetCurrentProcess());
+    HANDLE pipe;
+    ULONG pid;
+    BOOL ret;
+
+    pipe = CreateFileA(PIPENAME, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
+    ok(pipe != INVALID_HANDLE_VALUE, "got %u\n", GetLastError());
+
+    pid = 0;
+    ret = pGetNamedPipeClientProcessId(pipe, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x\n", pid);
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(pipe, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == server_pid, "got %04x expected %04x\n", pid, server_pid);
+    CloseHandle(pipe);
+}
+
+static HANDLE create_check_id_process(const char *verb, DWORD id)
+{
+    STARTUPINFOA si = {sizeof(si)};
+    PROCESS_INFORMATION info;
+    char **argv, buf[MAX_PATH];
+    BOOL ret;
+
+    winetest_get_mainargs(&argv);
+    sprintf(buf, "\"%s\" pipe %s %x", argv[0], verb, id);
+    ret = CreateProcessA(NULL, buf, NULL, NULL, TRUE, 0, NULL, NULL, &si, &info);
+    ok(ret, "got %u\n", GetLastError());
+    CloseHandle(info.hThread);
+    return info.hProcess;
+}
+
+static void test_namedpipe_process_id(void)
+{
+    HANDLE client, server, process;
+    DWORD current = GetProcessId(GetCurrentProcess());
+    OVERLAPPED overlapped;
+    ULONG pid;
+    BOOL ret;
+
+    if (!pGetNamedPipeClientProcessId)
+    {
+        win_skip("GetNamedPipeClientProcessId not available\n");
+        return;
+    }
+
+    create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server);
+
+    SetLastError(0xdeadbeef);
+    ret = pGetNamedPipeClientProcessId(server, NULL);
+    ok(!ret, "success\n");
+    todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %u\n", GetLastError());
+
+    pid = 0;
+    ret = pGetNamedPipeClientProcessId(server, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    pid = 0;
+    ret = pGetNamedPipeClientProcessId(client, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    SetLastError(0xdeadbeef);
+    ret = pGetNamedPipeServerProcessId(server, NULL);
+    ok(!ret, "success\n");
+    todo_wine ok(GetLastError() == ERROR_INSUFFICIENT_BUFFER, "got %u\n", GetLastError());
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(client, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(server, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    /* closed client handle */
+    CloseHandle(client);
+    pid = 0;
+    ret = pGetNamedPipeClientProcessId(server, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(server, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+    CloseHandle(server);
+
+    /* disconnected server */
+    create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server);
+    DisconnectNamedPipe(server);
+
+    SetLastError(0xdeadbeef);
+    ret = pGetNamedPipeClientProcessId(server, &pid);
+    todo_wine ok(!ret, "success\n");
+    todo_wine ok(GetLastError() == ERROR_NOT_FOUND, "got %u\n", GetLastError());
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(server, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    SetLastError(0xdeadbeef);
+    ret = pGetNamedPipeClientProcessId(client, &pid);
+    todo_wine ok(!ret, "success\n");
+    todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %u\n", GetLastError());
+
+    SetLastError(0xdeadbeef);
+    ret = pGetNamedPipeServerProcessId(client, &pid);
+    todo_wine ok(!ret, "success\n");
+    todo_wine ok(GetLastError() == ERROR_PIPE_NOT_CONNECTED, "got %u\n", GetLastError());
+    CloseHandle(client);
+    CloseHandle(server);
+
+    /* closed server handle */
+    create_overlapped_pipe(PIPE_TYPE_BYTE, &client, &server);
+    CloseHandle(server);
+
+    pid = 0;
+    ret = pGetNamedPipeClientProcessId(client, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+
+    pid = 0;
+    ret = pGetNamedPipeServerProcessId(client, &pid);
+    ok(ret, "got %u\n", GetLastError());
+    ok(pid == current, "got %04x expected %04x\n", pid, current);
+    CloseHandle(client);
+
+    /* different process */
+    memset(&overlapped, 0, sizeof(overlapped));
+    overlapped.hEvent = CreateEventW(NULL, TRUE, FALSE, NULL);
+    server = create_overlapped_server( &overlapped );
+    ok(server != INVALID_HANDLE_VALUE, "got %u\n", GetLastError());
+
+    process = create_check_id_process("checkpid", GetProcessId(GetCurrentProcess()));
+    winetest_wait_child_process(process);
+
+    CloseHandle(overlapped.hEvent);
+    CloseHandle(process);
+    CloseHandle(server);
+}
+
 START_TEST(pipe)
 {
     char **argv;
@@ -3294,15 +3460,27 @@ START_TEST(pipe)
     hmod = GetModuleHandleA("kernel32.dll");
     pQueueUserAPC = (void *) GetProcAddress(hmod, "QueueUserAPC");
     pCancelIoEx = (void *) GetProcAddress(hmod, "CancelIoEx");
+    pGetNamedPipeClientProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeClientProcessId");
+    pGetNamedPipeServerProcessId = (void *) GetProcAddress(hmod, "GetNamedPipeServerProcessId");
 
     argc = winetest_get_mainargs(&argv);
 
-    if (argc > 3 && !strcmp(argv[2], "writepipe"))
+    if (argc > 3)
     {
-        UINT_PTR handle;
-        sscanf(argv[3], "%lx", &handle);
-        child_process_write_pipe((HANDLE)handle);
-        return;
+        if (!strcmp(argv[2], "writepipe"))
+        {
+            UINT_PTR handle;
+            sscanf(argv[3], "%lx", &handle);
+            child_process_write_pipe((HANDLE)handle);
+            return;
+        }
+        if (!strcmp(argv[2], "checkpid"))
+        {
+            DWORD pid = GetProcessId(GetCurrentProcess());
+            sscanf(argv[3], "%x", &pid);
+            child_process_check_pid(pid);
+            return;
+        }
     }
 
     if (test_DisconnectNamedPipe())
@@ -3324,4 +3502,5 @@ START_TEST(pipe)
     test_overlapped_transport(TRUE, TRUE);
     test_overlapped_transport(FALSE, FALSE);
     test_TransactNamedPipe();
+    test_namedpipe_process_id();
 }
diff --git a/include/winbase.h b/include/winbase.h
index 02e4194a37..4cc2c7e28f 100644
--- a/include/winbase.h
+++ b/include/winbase.h
@@ -2141,11 +2141,14 @@ WINBASEAPI HMODULE     WINAPI GetModuleHandleW(LPCWSTR);
 WINBASEAPI BOOL        WINAPI GetModuleHandleExA(DWORD,LPCSTR,HMODULE*);
 WINBASEAPI BOOL        WINAPI GetModuleHandleExW(DWORD,LPCWSTR,HMODULE*);
 #define                       GetModuleHandleEx WINELIB_NAME_AW(GetModuleHandleEx)
+WINBASEAPI BOOL        WINAPI GetNamedPipeClientProcessId(HANDLE,PULONG);
+WINBASEAPI BOOL        WINAPI GetNamedPipeClientSessionId(HANDLE,PULONG);
 WINBASEAPI BOOL        WINAPI GetNamedPipeHandleStateA(HANDLE,LPDWORD,LPDWORD,LPDWORD,LPDWORD,LPSTR,DWORD);
 WINBASEAPI BOOL        WINAPI GetNamedPipeHandleStateW(HANDLE,LPDWORD,LPDWORD,LPDWORD,LPDWORD,LPWSTR,DWORD);
 #define                       GetNamedPipeHandleState WINELIB_NAME_AW(GetNamedPipeHandleState)
 WINBASEAPI BOOL        WINAPI GetNamedPipeInfo(HANDLE,LPDWORD,LPDWORD,LPDWORD,LPDWORD);
-WINBASEAPI BOOL        WINAPI GetNamedPipeClientProcessId(HANDLE,PULONG);
+WINBASEAPI BOOL        WINAPI GetNamedPipeServerProcessId(HANDLE,PULONG);
+WINBASEAPI BOOL        WINAPI GetNamedPipeServerSessionId(HANDLE,PULONG);
 WINBASEAPI VOID        WINAPI GetNativeSystemInfo(LPSYSTEM_INFO);
 WINBASEAPI PUMS_CONTEXT WINAPI GetNextUmsListItem(PUMS_CONTEXT);
 WINBASEAPI BOOL        WINAPI GetNumaProcessorNode(UCHAR,PUCHAR);
diff --git a/include/winioctl.h b/include/winioctl.h
index 269f771b57..7699579183 100644
--- a/include/winioctl.h
+++ b/include/winioctl.h
@@ -200,6 +200,7 @@
 #define FSCTL_PIPE_IMPERSONATE          CTL_CODE(FILE_DEVICE_NAMED_PIPE, 7, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define FSCTL_PIPE_SET_CLIENT_PROCESS   CTL_CODE(FILE_DEVICE_NAMED_PIPE, 8, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define FSCTL_PIPE_QUERY_CLIENT_PROCESS CTL_CODE(FILE_DEVICE_NAMED_PIPE, 9, METHOD_BUFFERED, FILE_ANY_ACCESS)
+#define FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE CTL_CODE(FILE_DEVICE_NAMED_PIPE, 12, METHOD_BUFFERED, FILE_ANY_ACCESS)
 #define FSCTL_PIPE_INTERNAL_READ        CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2045, METHOD_BUFFERED, FILE_READ_DATA)
 #define FSCTL_PIPE_INTERNAL_WRITE       CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2046, METHOD_BUFFERED, FILE_WRITE_DATA)
 #define FSCTL_PIPE_INTERNAL_TRANSCEIVE  CTL_CODE(FILE_DEVICE_NAMED_PIPE, 2047, METHOD_NEITHER, FILE_READ_DATA | FILE_WRITE_DATA)
diff --git a/server/named_pipe.c b/server/named_pipe.c
index 3d260c792b..c30fdcd299 100644
--- a/server/named_pipe.c
+++ b/server/named_pipe.c
@@ -40,6 +40,7 @@
 #include "thread.h"
 #include "request.h"
 #include "security.h"
+#include "process.h"
 
 enum pipe_state
 {
@@ -66,6 +67,8 @@ struct pipe_end
     struct fd           *fd;         /* pipe file descriptor */
     unsigned int         flags;      /* pipe flags */
     struct pipe_end     *connection; /* the other end of the pipe */
+    process_id_t         client_pid; /* process that created the client */
+    process_id_t         server_pid; /* process that created the server */
     data_size_t          buffer_size;/* size of buffered data that doesn't block caller */
     struct list          message_queue;
     struct async_queue   read_q;     /* read queue */
@@ -940,10 +943,48 @@ static int pipe_end_transceive( struct pipe_end *pipe_end, struct async *async )
     return 1;
 }
 
+static int pipe_end_get_connection_attribute( struct pipe_end *pipe_end )
+{
+    unsigned reply_size = get_reply_max_size();
+    const char *attr = get_req_data();
+    data_size_t value_size, attr_size = get_req_data_size();
+    void *value, *buffer;
+
+    if (attr_size == sizeof("ClientProcessId") && !memcmp( attr, "ClientProcessId", attr_size ))
+    {
+        value = &pipe_end->client_pid;
+        value_size = sizeof(pipe_end->client_pid);
+    }
+    else if (attr_size == sizeof("ServerProcessId") && !memcmp( attr, "ServerProcessId", attr_size ))
+    {
+        value = &pipe_end->server_pid;
+        value_size = sizeof(pipe_end->server_pid);
+    }
+    else
+    {
+        set_error( STATUS_ILLEGAL_FUNCTION );
+        return 0;
+    }
+
+    if (reply_size < value_size)
+    {
+        set_error( STATUS_INFO_LENGTH_MISMATCH );
+        return 0;
+    }
+
+    if (!(buffer = set_reply_data_size( value_size ))) return 0;
+    memcpy( buffer, value, value_size );
+
+    return 1;
+}
+
 static int pipe_end_ioctl( struct pipe_end *pipe_end, ioctl_code_t code, struct async *async )
 {
     switch(code)
     {
+    case FSCTL_PIPE_GET_CONNECTION_ATTRIBUTE:
+        return pipe_end_get_connection_attribute( pipe_end );
+
     case FSCTL_PIPE_PEEK:
         return pipe_end_peek( pipe_end );
 
@@ -1062,6 +1103,7 @@ static struct pipe_server *create_pipe_server( struct named_pipe *pipe, unsigned
     server->client = NULL;
     server->options = options;
     init_pipe_end( &server->pipe_end, pipe_flags, pipe->insize );
+    server->pipe_end.server_pid = get_process_id( current->process );
 
     list_add_head( &pipe->servers, &server->entry );
     grab_object( pipe );
@@ -1087,6 +1129,7 @@ static struct pipe_client *create_pipe_client( unsigned int flags, unsigned int
     client->server = NULL;
     client->flags = flags;
     init_pipe_end( &client->pipe_end, pipe_flags, buffer_size );
+    client->pipe_end.client_pid = get_process_id( current->process );
 
     client->pipe_end.fd = alloc_pseudo_fd( &pipe_client_fd_ops, &client->pipe_end.obj, options );
     if (!client->pipe_end.fd)
@@ -1169,6 +1212,8 @@ static struct object *named_pipe_open_file( struct object *obj, unsigned int acc
         client->server = server;
         server->pipe_end.connection = &client->pipe_end;
         client->pipe_end.connection = &server->pipe_end;
+        server->pipe_end.client_pid = client->pipe_end.client_pid;
+        client->pipe_end.server_pid = server->pipe_end.server_pid;
     }
     release_object( server );
     return &client->pipe_end.obj;
-- 
2.11.0




More information about the wine-devel mailing list