From dedd4506891a044ae9cd34df1e10c146460af036 Mon Sep 17 00:00:00 2001 From: Hans Leidekker Date: Wed, 11 Apr 2018 14:32:56 +0200 Subject: [PATCH] kernel32: Implement GetNamedPipeClient/ServerProcessId. Signed-off-by: Hans Leidekker Signed-off-by: Jacek Caban Signed-off-by: Alexandre Julliard --- ...pi-ms-win-core-kernel32-legacy-l1-1-0.spec | 4 +- ...pi-ms-win-core-kernel32-legacy-l1-1-1.spec | 4 +- 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 | 42 ++++ 8 files changed, 277 insertions(+), 12 deletions(-) diff --git a/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec b/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec index 7c196c932fd..e653ac6d212 100644 --- a/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec +++ b/dlls/api-ms-win-core-kernel32-legacy-l1-1-0/api-ms-win-core-kernel32-legacy-l1-1-0.spec @@ -22,8 +22,8 @@ @ stdcall GetConsoleWindow() kernel32.GetConsoleWindow @ stub GetDurationFormatEx @ stub GetMaximumProcessorGroupCount -@ stub GetNamedPipeClientProcessId -@ stub GetNamedPipeServerProcessId +@ stdcall GetNamedPipeClientProcessId(long ptr) kernel32.GetNamedPipeClientProcessId +@ stdcall GetNamedPipeServerProcessId(long ptr) kernel32.GetNamedPipeServerProcessId @ stdcall GetShortPathNameA(str ptr long) kernel32.GetShortPathNameA @ stdcall GetStartupInfoA(ptr) kernel32.GetStartupInfoA @ stdcall GetStringTypeExA(long long str long ptr) kernel32.GetStringTypeExA diff --git a/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec b/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec index 2850919985d..5531d2dbd71 100644 --- a/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec +++ b/dlls/api-ms-win-core-kernel32-legacy-l1-1-1/api-ms-win-core-kernel32-legacy-l1-1-1.spec @@ -27,8 +27,8 @@ @ stub GetFileAttributesTransactedW @ stub GetFirmwareType @ stub GetMaximumProcessorGroupCount -@ stub GetNamedPipeClientProcessId -@ stub GetNamedPipeServerProcessId +@ stdcall GetNamedPipeClientProcessId(long ptr) kernel32.GetNamedPipeClientProcessId +@ stdcall GetNamedPipeServerProcessId(long ptr) kernel32.GetNamedPipeServerProcessId @ stub GetNumaAvailableMemoryNodeEx @ stdcall GetNumaNodeProcessorMask(long ptr) kernel32.GetNumaNodeProcessorMask @ stub GetNumaProcessorNodeEx diff --git a/dlls/kernel32/kernel32.spec b/dlls/kernel32/kernel32.spec index 4a92913c4ee..fb8d4c023a6 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 fcf1be70901..04e9779664f 100644 --- a/dlls/kernel32/sync.c +++ b/dlls/kernel32/sync.c @@ -1786,6 +1786,46 @@ BOOL WINAPI GetNamedPipeInfo( return TRUE; } +/*********************************************************************** + * 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.@) */ diff --git a/dlls/kernel32/tests/pipe.c b/dlls/kernel32/tests/pipe.c index 72928ff371f..62f2ee3c2fd 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 02e4194a377..4cc2c7e28f6 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 269f771b57e..76995791830 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 3d260c792ba..a1f37237295 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,45 @@ 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 ) +{ + const char *attr = get_req_data(); + data_size_t value_size, attr_size = get_req_data_size(); + void *value; + + 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 (get_reply_max_size() < value_size) + { + set_error( STATUS_INFO_LENGTH_MISMATCH ); + return 0; + } + + set_reply_data( 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 +1100,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 +1126,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 +1209,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;