From: Paul Gofman pgofman@codeweavers.com
--- dlls/iphlpapi/iphlpapi.spec | 2 +- dlls/iphlpapi/iphlpapi_main.c | 50 +++++++++++++++++ dlls/iphlpapi/tests/iphlpapi.c | 100 ++++++++++++++++++++++++++++++++- include/iphlpapi.h | 1 + include/iprtrmib.h | 10 ++++ 5 files changed, 160 insertions(+), 3 deletions(-)
diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec index 81aeecd004e..9dad2be88ce 100644 --- a/dlls/iphlpapi/iphlpapi.spec +++ b/dlls/iphlpapi/iphlpapi.spec @@ -124,7 +124,7 @@ @ stdcall GetNumberOfInterfaces( ptr ) #@ stub GetOwnerModuleFromPidAndInfo #@ stub GetOwnerModuleFromTcp6Entry -#@ stub GetOwnerModuleFromTcpEntry +@ stdcall GetOwnerModuleFromTcpEntry( ptr long ptr ptr ) #@ stub GetOwnerModuleFromUdp6Entry #@ stub GetOwnerModuleFromUdpEntry @ stdcall GetPerAdapterInfo( long ptr ptr ) diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index 5ca8bf9d3f1..d833c88d8a4 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -38,6 +38,7 @@ #include "ip2string.h" #include "netiodef.h" #include "icmpapi.h" +#include "psapi.h"
#include "wine/nsi.h" #include "wine/debug.h" @@ -3271,6 +3272,55 @@ DWORD WINAPI GetExtendedTcpTable( void *table, DWORD *size, BOOL sort, ULONG fam return get_extended_tcp_table( table, size, sort, family, table_class ); }
+static DWORD get_owner_module_from_pid( TCPIP_OWNER_MODULE_INFO_CLASS class, void *buffer, DWORD *size, DWORD pid ) +{ + WCHAR path[(MAX_PATH + 1) * sizeof(WCHAR)], *name; + TCPIP_OWNER_MODULE_BASIC_INFO *info = buffer; + DWORD len, ret_size; + HANDLE process; + + if (class != TCPIP_OWNER_MODULE_INFO_BASIC) + { + FIXME( "Unsupported class %d.\n", class ); + return ERROR_INVALID_PARAMETER; + } + + if (!size) return ERROR_INVALID_PARAMETER; + if (!pid) return ERROR_NOT_FOUND; + if (!(process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, pid ))) return GetLastError(); + len = GetModuleFileNameExW( process, NULL, path, ARRAY_SIZE(path) ); + CloseHandle( process ); + if (!len) return ERROR_NOT_FOUND; + if (len == ARRAY_SIZE(path)) return ERROR_PATH_NOT_FOUND; + if (!(name = wcsrchr( path, '\' ))) return ERROR_PATH_NOT_FOUND; + ++name; + len = wcslen( name ) + 1; + ret_size = sizeof(*info) + (len + wcslen( path ) + 1) * sizeof(WCHAR); + if (*size < ret_size) + { + *size = ret_size; + return ERROR_INSUFFICIENT_BUFFER; + } + info->pModuleName = (WCHAR *)(info + 1); + info->pModulePath = info->pModuleName + len; + memcpy( info->pModuleName, name, len * sizeof(WCHAR) ); + wcscpy( info->pModulePath, path ); + return ERROR_SUCCESS; +} + +/****************************************************************** + * GetOwnerModuleFromTcpEntry (IPHLPAPI.@) + */ +DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, + void *buffer, DWORD *size ) +{ + TRACE( "entry %p, class %d, buffer %p, size %p.\n", entry, class, buffer, size ); + + if (!entry) return ERROR_INVALID_PARAMETER; + + return get_owner_module_from_pid( class, buffer, size, entry->dwOwningPid ); +} + /****************************************************************** * GetTcpTable (IPHLPAPI.@) * diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index 587289a6124..7f98d322991 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -2211,6 +2211,7 @@ static void test_GetExtendedTcpTable(void) we make, and associates it with our process. */ static void test_GetExtendedTcpTable_owner( int family ) { + BOOL found_it; SOCKET sock; int port; DWORD i, ret; @@ -2266,7 +2267,7 @@ static void test_GetExtendedTcpTable_owner( int family ) if (family == AF_INET) { MIB_TCPTABLE_OWNER_PID *table = raw_table; - BOOL found_it = FALSE; + found_it = FALSE; for (i = 0; i < table->dwNumEntries; i++) { MIB_TCPROW_OWNER_PID *row = &table->table[i]; @@ -2283,7 +2284,7 @@ static void test_GetExtendedTcpTable_owner( int family ) else { MIB_TCP6TABLE_OWNER_PID *table = raw_table; - BOOL found_it = FALSE; + found_it = FALSE; for (i = 0; i < table->dwNumEntries; i++) { MIB_TCP6ROW_OWNER_PID *row = &table->table[i]; @@ -2298,6 +2299,101 @@ static void test_GetExtendedTcpTable_owner( int family ) ok( found_it, "no table entry for socket\n" ); }
+ free( raw_table ); + raw_table = NULL; + ret = get_extended_tcp_table( family, TCP_TABLE_OWNER_MODULE_ALL, &raw_table ); + if (ret != ERROR_SUCCESS) + { + skip( "error %lu getting TCP table\n", ret ); + goto done; + } + + if (family == AF_INET) + { + MIB_TCPTABLE_OWNER_MODULE *t = raw_table; + TCPIP_OWNER_MODULE_BASIC_INFO *info; + MIB_TCPROW_OWNER_MODULE entry; + WCHAR mod[MAX_PATH], *name; + DWORD sz, expected, name_len; + BYTE buf[MAX_PATH + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 128]; + HANDLE process; + char *p; + + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + mod[0] = 0; + GetModuleFileNameW( NULL, mod, ARRAY_SIZE(mod) ); + name = wcsrchr( mod, '\' ); + ok( !!name, "could not get name, mod %s.\n", debugstr_w(mod) ); + ++name; + name_len = (wcslen( name ) + 1) * sizeof(WCHAR); + expected = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + name_len + (wcslen( mod ) + 1) * sizeof(WCHAR); + memset( &entry, 0, sizeof(entry) ); + + sz = sizeof(buf); + ret = GetOwnerModuleFromTcpEntry( NULL, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = 0; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + + entry.dwOwningPid = 0xffff; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = GetCurrentProcessId(); + sz = 1; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %lu.\n", ret ); + ok( sz == expected, "got %lu, expected %lu.\n", sz, expected ); + + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( !ret, "got %lu.\n", ret ); + + p = (char *)(info + 1); + ok( (char *)info->pModuleName == p, "got %p, %p.\n", info, p ); + p += name_len; + ok( (char *)info->pModulePath == p, "got %p, %p.\n", info, p); + ok( !wcscmp( info->pModuleName, name ), "got %s, %s.\n", debugstr_w(info->pModuleName), debugstr_w(name) ); + + found_it = FALSE; + for (i = 0; i < t->dwNumEntries; ++i) + { + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + memset(buf, 0xcc, sizeof(buf)); + sz = sizeof(buf) + 1; + ret = GetOwnerModuleFromTcpEntry( &t->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok(sz == sizeof(buf) + 1, "got %ld.\n", sz); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED + || ret == ERROR_MOD_NOT_FOUND, + /* This is weird, newer Windows seems to return non-zero OwningModuleInfo[0] sometimes but then + * GetOwnerModuleFromTcp6Entry always fails with ERROR_MOD_NOT_FOUND, while that succeeds for the + * same PID in MIB_TCPTABLE_OWNER_MODULE and zeroed OwningModuleInfo */ + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + + memset( &entry, 0, sizeof(entry) ); + entry.dwOwningPid = t->table[i].dwOwningPid; + if (entry.dwOwningPid == GetCurrentProcessId()) + found_it = TRUE; + ret = GetOwnerModuleFromTcpEntry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED, + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + if (!ret && !wcscmp( info->pModuleName, L"System" )) + { + ok( !wcscmp( info->pModulePath, L"System" ), "got %s.\n", debugstr_w(info->pModulePath) ); + } + else if (ret == ERROR_ACCESS_DENIED) + { + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !process && GetLastError() == ERROR_ACCESS_DENIED, "got process %p, err %lu.\n", process, GetLastError() ); + } + } + ok( found_it, "no table entry for socket\n" ); + } + done: closesocket( sock ); free( raw_table ); diff --git a/include/iphlpapi.h b/include/iphlpapi.h index d8fc36a5f72..0dbc034e556 100644 --- a/include/iphlpapi.h +++ b/include/iphlpapi.h @@ -66,6 +66,7 @@ IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats, DWORD dwFamily); +IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetOwnerModuleFromTcpEntry(PMIB_TCPROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, void *info, DWORD *size); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily); IPHLPAPI_DLL_LINKAGE ULONG WINAPI GetPerTcpConnectionEStats(MIB_TCPROW *row, TCP_ESTATS_TYPE stats, UCHAR *rw, ULONG rw_version, diff --git a/include/iprtrmib.h b/include/iprtrmib.h index 977b117957b..83042333f0b 100644 --- a/include/iprtrmib.h +++ b/include/iprtrmib.h @@ -45,4 +45,14 @@ typedef enum _UDP_TABLE_CLASS UDP_TABLE_OWNER_MODULE } UDP_TABLE_CLASS, *PUDP_TABLE_CLASS;
+typedef struct _TCPIP_OWNER_MODULE_BASIC_INFO +{ + WCHAR *pModuleName; + WCHAR *pModulePath; +} TCPIP_OWNER_MODULE_BASIC_INFO, *PTCPIP_OWNER_MODULE_BASIC_INFO; + +typedef enum _TCPIP_OWNER_MODULE_INFO_CLASS +{ + TCPIP_OWNER_MODULE_INFO_BASIC +} TCPIP_OWNER_MODULE_INFO_CLASS, *PTCPIP_OWNER_MODULE_INFO_CLASS; #endif /* WINE_IPRTRMIB_H__ */
From: Paul Gofman pgofman@codeweavers.com
--- dlls/iphlpapi/iphlpapi.spec | 2 +- dlls/iphlpapi/iphlpapi_main.c | 13 ++++++ dlls/iphlpapi/tests/iphlpapi.c | 85 ++++++++++++++++++++++++++++++++++ include/iphlpapi.h | 1 + 4 files changed, 100 insertions(+), 1 deletion(-)
diff --git a/dlls/iphlpapi/iphlpapi.spec b/dlls/iphlpapi/iphlpapi.spec index 9dad2be88ce..9da2a26f29f 100644 --- a/dlls/iphlpapi/iphlpapi.spec +++ b/dlls/iphlpapi/iphlpapi.spec @@ -123,7 +123,7 @@ @ stdcall GetNetworkParams( ptr ptr ) @ stdcall GetNumberOfInterfaces( ptr ) #@ stub GetOwnerModuleFromPidAndInfo -#@ stub GetOwnerModuleFromTcp6Entry +@ stdcall GetOwnerModuleFromTcp6Entry( ptr long ptr ptr ) @ stdcall GetOwnerModuleFromTcpEntry( ptr long ptr ptr ) #@ stub GetOwnerModuleFromUdp6Entry #@ stub GetOwnerModuleFromUdpEntry diff --git a/dlls/iphlpapi/iphlpapi_main.c b/dlls/iphlpapi/iphlpapi_main.c index d833c88d8a4..262fd0dca82 100644 --- a/dlls/iphlpapi/iphlpapi_main.c +++ b/dlls/iphlpapi/iphlpapi_main.c @@ -3321,6 +3321,19 @@ DWORD WINAPI GetOwnerModuleFromTcpEntry( PMIB_TCPROW_OWNER_MODULE entry, TCPIP_O return get_owner_module_from_pid( class, buffer, size, entry->dwOwningPid ); }
+/****************************************************************** + * GetOwnerModuleFromTcp6Entry (IPHLPAPI.@) + */ +DWORD WINAPI GetOwnerModuleFromTcp6Entry( PMIB_TCP6ROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, + void *buffer, DWORD *size ) +{ + TRACE( "entry %p, class %d, buffer %p, size %p.\n", entry, class, buffer, size ); + + if (!entry) return ERROR_INVALID_PARAMETER; + + return get_owner_module_from_pid( class, buffer, size, entry->dwOwningPid ); +} + /****************************************************************** * GetTcpTable (IPHLPAPI.@) * diff --git a/dlls/iphlpapi/tests/iphlpapi.c b/dlls/iphlpapi/tests/iphlpapi.c index 7f98d322991..982880fdb9d 100644 --- a/dlls/iphlpapi/tests/iphlpapi.c +++ b/dlls/iphlpapi/tests/iphlpapi.c @@ -2393,6 +2393,91 @@ static void test_GetExtendedTcpTable_owner( int family ) } ok( found_it, "no table entry for socket\n" ); } + else + { + MIB_TCP6TABLE_OWNER_MODULE *t = raw_table; + TCPIP_OWNER_MODULE_BASIC_INFO *info; + MIB_TCP6ROW_OWNER_MODULE entry; + WCHAR mod[MAX_PATH], *name; + DWORD sz, expected, name_len; + BYTE buf[MAX_PATH + sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + 128]; + HANDLE process; + char *p; + + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + mod[0] = 0; + GetModuleFileNameW( NULL, mod, ARRAY_SIZE(mod) ); + name = wcsrchr( mod, '\' ); + ok( !!name, "could not get name, mod %s.\n", debugstr_w(mod) ); + ++name; + name_len = (wcslen( name ) + 1) * sizeof(WCHAR); + expected = sizeof(TCPIP_OWNER_MODULE_BASIC_INFO) + name_len + (wcslen( mod ) + 1) * sizeof(WCHAR); + memset( &entry, 0, sizeof(entry) ); + + sz = sizeof(buf); + ret = GetOwnerModuleFromTcp6Entry( NULL, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = 0; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_NOT_FOUND, "got %lu.\n", ret ); + + entry.dwOwningPid = 0xffff; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INVALID_PARAMETER, "got %lu.\n", ret ); + + entry.dwOwningPid = GetCurrentProcessId(); + sz = 1; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( ret == ERROR_INSUFFICIENT_BUFFER, "got %lu.\n", ret ); + ok( sz == expected, "got %lu, expected %lu.\n", sz, expected ); + + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok( !ret, "got %lu.\n", ret ); + + p = (char *)(info + 1); + ok( (char *)info->pModuleName == p, "got %p, %p.\n", info, p ); + p += name_len; + ok( (char *)info->pModulePath == p, "got %p, %p.\n", info, p); + ok( !wcscmp( info->pModuleName, name ), "got %s, %s.\n", debugstr_w(info->pModuleName), debugstr_w(name) ); + + found_it = FALSE; + for (i = 0; i < t->dwNumEntries; ++i) + { + info = (TCPIP_OWNER_MODULE_BASIC_INFO *)buf; + + memset(buf, 0xcc, sizeof(buf)); + sz = sizeof(buf) + 1; + ret = GetOwnerModuleFromTcp6Entry( &t->table[i], TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + ok(sz == sizeof(buf) + 1, "got %ld.\n", sz); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED + || ret == ERROR_MOD_NOT_FOUND, + /* This is weird, newer Windows seems to return non-zero OwningModuleInfo[0] sometimes but then + * GetOwnerModuleFromTcp6Entry always fails with ERROR_MOD_NOT_FOUND, while that succeeds for the + * same PID in MIB_TCPTABLE_OWNER_MODULE and zeroed OwningModuleInfo */ + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + + memset( &entry, 0, sizeof(entry) ); + entry.dwOwningPid = t->table[i].dwOwningPid; + if (entry.dwOwningPid == GetCurrentProcessId()) + found_it = TRUE; + ret = GetOwnerModuleFromTcp6Entry( &entry, TCPIP_OWNER_MODULE_INFO_BASIC, buf, &sz ); + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !ret || ret == ERROR_NOT_FOUND || ret == ERROR_ACCESS_DENIED, + "got %#lx, pid %ld, info %#I64x.\n", ret, t->table[i].dwOwningPid, t->table[i].OwningModuleInfo[0] ); + if (!ret && !wcscmp( info->pModuleName, L"System" )) + { + ok( !wcscmp( info->pModulePath, L"System" ), "got %s.\n", debugstr_w(info->pModulePath) ); + } + else if (ret == ERROR_ACCESS_DENIED) + { + process = OpenProcess( PROCESS_QUERY_LIMITED_INFORMATION, FALSE, entry.dwOwningPid ); + ok( !process && GetLastError() == ERROR_ACCESS_DENIED, "got process %p, err %lu.\n", process, GetLastError() ); + } + } + ok( found_it, "no table entry for socket\n" ); + }
done: closesocket( sock ); diff --git a/include/iphlpapi.h b/include/iphlpapi.h index 0dbc034e556..ca280a65806 100644 --- a/include/iphlpapi.h +++ b/include/iphlpapi.h @@ -66,6 +66,7 @@ IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIpStatistics(PMIB_IPSTATS pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIpStatisticsEx(PMIB_IPSTATS pStats, DWORD dwFamily); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIcmpStatistics(PMIB_ICMP pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetIcmpStatisticsEx(PMIB_ICMP_EX pStats, DWORD dwFamily); +IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetOwnerModuleFromTcp6Entry(PMIB_TCP6ROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, void *info, DWORD *size); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetOwnerModuleFromTcpEntry(PMIB_TCPROW_OWNER_MODULE entry, TCPIP_OWNER_MODULE_INFO_CLASS class, void *info, DWORD *size); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetTcpStatistics(PMIB_TCPSTATS pStats); IPHLPAPI_DLL_LINKAGE DWORD WINAPI GetTcpStatisticsEx(PMIB_TCPSTATS pStats, DWORD dwFamily);