[PATCH 2/4] mountmgr.sys: Add support for querying DHCP parameters on Linux.
Hans Leidekker
hans at codeweavers.com
Tue Nov 19 07:44:58 CST 2019
Signed-off-by: Hans Leidekker <hans at codeweavers.com>
---
dlls/mountmgr.sys/Makefile.in | 2 +-
dlls/mountmgr.sys/dbus.c | 271 ++++++++++++++++++++++++++++++++++
dlls/mountmgr.sys/mountmgr.c | 40 +++++
dlls/mountmgr.sys/mountmgr.h | 3 +
include/ddk/mountmgr.h | 21 +++
5 files changed, 336 insertions(+), 1 deletion(-)
diff --git a/dlls/mountmgr.sys/Makefile.in b/dlls/mountmgr.sys/Makefile.in
index 511484b10b..738f071390 100644
--- a/dlls/mountmgr.sys/Makefile.in
+++ b/dlls/mountmgr.sys/Makefile.in
@@ -1,6 +1,6 @@
MODULE = mountmgr.sys
IMPORTS = uuid advapi32 ntoskrnl
-DELAYIMPORTS = user32
+DELAYIMPORTS = user32 iphlpapi
EXTRADLLFLAGS = -Wl,--subsystem,native
EXTRAINCL = $(DBUS_CFLAGS) $(HAL_CFLAGS)
EXTRALIBS = $(DISKARBITRATION_LIBS)
diff --git a/dlls/mountmgr.sys/dbus.c b/dlls/mountmgr.sys/dbus.c
index 7e373e6f91..b96cb0df4c 100644
--- a/dlls/mountmgr.sys/dbus.c
+++ b/dlls/mountmgr.sys/dbus.c
@@ -36,6 +36,13 @@
#include "mountmgr.h"
#include "winnls.h"
#include "excpt.h"
+#include "winsock2.h"
+#include "ws2ipdef.h"
+#include "nldef.h"
+#include "netioapi.h"
+#include "inaddr.h"
+#include "ip2string.h"
+#include "dhcpcsdk.h"
#include "wine/library.h"
#include "wine/exception.h"
@@ -48,6 +55,7 @@ WINE_DEFAULT_DEBUG_CHANNEL(mountmgr);
#define DBUS_FUNCS \
DO_FUNC(dbus_bus_add_match); \
DO_FUNC(dbus_bus_get); \
+ DO_FUNC(dbus_bus_get_private); \
DO_FUNC(dbus_bus_remove_match); \
DO_FUNC(dbus_connection_add_filter); \
DO_FUNC(dbus_connection_read_write_dispatch); \
@@ -762,6 +770,269 @@ void initialize_dbus(void)
CloseHandle( handle );
}
+/* The udisks dispatch loop will block all threads using the same connection, so we'll
+ use a private connection. Multiple threads can make methods calls at the same time
+ on the same connection, according to the documentation.
+ */
+static DBusConnection *dhcp_connection;
+static DBusConnection *get_dhcp_connection(void)
+{
+ if (!dhcp_connection)
+ {
+ DBusError error;
+ p_dbus_error_init( &error );
+ if (!(dhcp_connection = p_dbus_bus_get_private( DBUS_BUS_SYSTEM, &error )))
+ {
+ WARN( "failed to get system dbus connection: %s\n", error.message );
+ p_dbus_error_free( &error );
+ }
+ }
+ return dhcp_connection;
+}
+
+static DBusMessage *device_by_iface_request( const char *iface )
+{
+ DBusMessage *request, *reply;
+ DBusMessageIter iter;
+ DBusError error;
+
+ request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", "/org/freedesktop/NetworkManager",
+ "org.freedesktop.NetworkManager", "GetDeviceByIpIface" );
+ if (!request) return NULL;
+
+ p_dbus_message_iter_init_append( request, &iter );
+ p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &iface );
+
+ p_dbus_error_init( &error );
+ reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+ p_dbus_message_unref( request );
+ if (!reply)
+ {
+ WARN( "failed: %s\n", error.message );
+ p_dbus_error_free( &error );
+ return NULL;
+ }
+
+ p_dbus_error_free( &error );
+ return reply;
+}
+
+#define IF_NAMESIZE 16
+static BOOL map_adapter_name( const WCHAR *name, char *unix_name, DWORD len )
+{
+ WCHAR unix_nameW[IF_NAMESIZE];
+ UNICODE_STRING str;
+ GUID guid;
+
+ RtlInitUnicodeString( &str, name );
+ if (!RtlGUIDFromString( &str, &guid ))
+ {
+ NET_LUID luid;
+ if (ConvertInterfaceGuidToLuid( &guid, &luid ) ||
+ ConvertInterfaceLuidToNameW( &luid, unix_nameW, ARRAY_SIZE(unix_nameW) )) return FALSE;
+
+ name = unix_nameW;
+ }
+ return WideCharToMultiByte( CP_UNIXCP, 0, name, -1, unix_name, len, NULL, NULL ) != 0;
+}
+
+static DBusMessage *dhcp4_config_request( const WCHAR *adapter )
+{
+ static const char *device = "org.freedesktop.NetworkManager.Device";
+ static const char *dhcp4_config = "Dhcp4Config";
+ char iface[IF_NAMESIZE];
+ DBusMessage *request, *reply;
+ DBusMessageIter iter;
+ DBusError error;
+ const char *path = NULL;
+
+ if (!map_adapter_name( adapter, iface, sizeof(iface) )) return NULL;
+ if (!(reply = device_by_iface_request( iface ))) return NULL;
+
+ p_dbus_message_iter_init( reply, &iter );
+ if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_OBJECT_PATH) p_dbus_message_iter_get_basic( &iter, &path );
+ p_dbus_message_unref( reply );
+ if (!path) return NULL;
+
+ request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
+ "org.freedesktop.DBus.Properties", "Get" );
+ if (!request) return NULL;
+
+ p_dbus_message_iter_init_append( request, &iter );
+ p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &device );
+ p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
+
+ p_dbus_error_init( &error );
+ reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+ p_dbus_message_unref( request );
+ if (!reply)
+ {
+ WARN( "failed: %s\n", error.message );
+ p_dbus_error_free( &error );
+ return NULL;
+ }
+
+ p_dbus_error_free( &error );
+ return reply;
+}
+
+static DBusMessage *dhcp4_config_options_request( const WCHAR *adapter )
+{
+ static const char *dhcp4_config = "org.freedesktop.NetworkManager.DHCP4Config";
+ static const char *options = "Options";
+ DBusMessage *request, *reply;
+ DBusMessageIter iter, sub;
+ DBusError error;
+ const char *path = NULL;
+
+ if (!(reply = dhcp4_config_request( adapter ))) return NULL;
+
+ p_dbus_message_iter_init( reply, &iter );
+ if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
+ {
+ p_dbus_message_iter_recurse( &iter, &sub );
+ p_dbus_message_iter_get_basic( &sub, &path );
+ }
+ if (!path)
+ {
+ p_dbus_message_unref( reply );
+ return NULL;
+ }
+
+ request = p_dbus_message_new_method_call( "org.freedesktop.NetworkManager", path,
+ "org.freedesktop.DBus.Properties", "Get" );
+ p_dbus_message_unref( reply );
+ if (!request) return NULL;
+
+ p_dbus_message_iter_init_append( request, &iter );
+ p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &dhcp4_config );
+ p_dbus_message_iter_append_basic( &iter, DBUS_TYPE_STRING, &options );
+
+ p_dbus_error_init( &error );
+ reply = p_dbus_connection_send_with_reply_and_block( get_dhcp_connection(), request, -1, &error );
+ p_dbus_message_unref( request );
+ if (!reply)
+ {
+ p_dbus_error_free( &error );
+ return NULL;
+ }
+
+ p_dbus_error_free( &error );
+ return reply;
+}
+
+static const char *dhcp4_config_option_next_dict_entry( DBusMessageIter *iter, DBusMessageIter *variant )
+{
+ DBusMessageIter sub;
+ const char *name;
+
+ if (p_dbus_message_iter_get_arg_type( iter ) != DBUS_TYPE_DICT_ENTRY) return NULL;
+ p_dbus_message_iter_recurse( iter, &sub );
+ p_dbus_message_iter_next( iter );
+ p_dbus_message_iter_get_basic( &sub, &name );
+ p_dbus_message_iter_next( &sub );
+ p_dbus_message_iter_recurse( &sub, variant );
+ return name;
+}
+
+static DBusMessage *dhcp4_config_option_request( const WCHAR *adapter, const char *option, const char **value )
+{
+ DBusMessage *reply;
+ DBusMessageIter iter, variant;
+ const char *name;
+
+ if (!(reply = dhcp4_config_options_request( adapter ))) return NULL;
+
+ *value = NULL;
+ p_dbus_message_iter_init( reply, &iter );
+ if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_VARIANT)
+ {
+ p_dbus_message_iter_recurse( &iter, &iter );
+ if (p_dbus_message_iter_get_arg_type( &iter ) == DBUS_TYPE_ARRAY)
+ {
+ p_dbus_message_iter_recurse( &iter, &iter );
+ while ((name = dhcp4_config_option_next_dict_entry( &iter, &variant )))
+ {
+ if (!strcmp( name, option ))
+ {
+ p_dbus_message_iter_get_basic( &variant, value );
+ break;
+ }
+ }
+ }
+ }
+
+ return reply;
+}
+
+static const char *map_option( ULONG option )
+{
+ switch (option)
+ {
+ case OPTION_SUBNET_MASK: return "subnet_mask";
+ case OPTION_ROUTER_ADDRESS: return "next_server";
+ case OPTION_HOST_NAME: return "host_name";
+ case OPTION_DOMAIN_NAME: return "domain_name";
+ case OPTION_BROADCAST_ADDRESS: return "broadcast_address";
+ case OPTION_MSFT_IE_PROXY: return "wpad";
+ default:
+ FIXME( "unhandled option %u\n", option );
+ return "";
+ }
+}
+
+ULONG get_dhcp_request_param( const WCHAR *adapter, struct mountmgr_dhcp_request_param *param, char *buf, ULONG offset,
+ ULONG size )
+{
+ DBusMessage *reply;
+ const char *value;
+ ULONG ret = 0;
+
+ param->offset = param->size = 0;
+
+ if (!(reply = dhcp4_config_option_request( adapter, map_option(param->id), &value ))) return 0;
+
+ switch (param->id)
+ {
+ case OPTION_SUBNET_MASK:
+ case OPTION_ROUTER_ADDRESS:
+ case OPTION_BROADCAST_ADDRESS:
+ {
+ IN_ADDR *ptr = (IN_ADDR *)(buf + offset);
+ if (value && size >= sizeof(IN_ADDR) && !RtlIpv4StringToAddressA( value, TRUE, NULL, ptr ))
+ {
+ param->offset = offset;
+ param->size = sizeof(*ptr);
+ TRACE( "returning %08x\n", *(DWORD *)ptr );
+ }
+ ret = sizeof(*ptr);
+ break;
+ }
+ case OPTION_HOST_NAME:
+ case OPTION_DOMAIN_NAME:
+ case OPTION_MSFT_IE_PROXY:
+ {
+ char *ptr = buf + offset;
+ int len = value ? strlen( value ) : 0;
+ if (len && size >= len)
+ {
+ memcpy( ptr, value, len );
+ param->offset = offset;
+ param->size = len;
+ TRACE( "returning %s\n", debugstr_an(ptr, len) );
+ }
+ ret = len;
+ break;
+ }
+ default:
+ FIXME( "option %u not supported\n", param->id );
+ break;
+ }
+
+ p_dbus_message_unref( reply );
+ return ret;
+}
+
#else /* SONAME_LIBDBUS_1 */
void initialize_dbus(void)
diff --git a/dlls/mountmgr.sys/mountmgr.c b/dlls/mountmgr.sys/mountmgr.c
index 2f43a227dc..bc2b776a92 100644
--- a/dlls/mountmgr.sys/mountmgr.c
+++ b/dlls/mountmgr.sys/mountmgr.c
@@ -359,6 +359,35 @@ done:
return status;
}
+/* implementation of IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS */
+static NTSTATUS query_dhcp_request_params( void *buff, SIZE_T insize,
+ SIZE_T outsize, IO_STATUS_BLOCK *iosb )
+{
+ struct mountmgr_dhcp_request_params *query = buff;
+ ULONG i, offset;
+
+ /* sanity checks */
+ if (FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]) > insize ||
+ !memchrW( query->adapter, 0, ARRAY_SIZE(query->adapter) )) return STATUS_INVALID_PARAMETER;
+ for (i = 0; i < query->count; i++)
+ if (query->params[i].offset + query->params[i].size > insize) return STATUS_INVALID_PARAMETER;
+
+ offset = FIELD_OFFSET(struct mountmgr_dhcp_request_params, params[query->count]);
+ for (i = 0; i < query->count; i++)
+ {
+ offset += get_dhcp_request_param( query->adapter, &query->params[i], buff, offset, outsize - offset );
+ if (offset > outsize)
+ {
+ if (offset >= sizeof(query->size)) query->size = offset;
+ iosb->Information = sizeof(query->size);
+ return STATUS_MORE_ENTRIES;
+ }
+ }
+
+ iosb->Information = offset;
+ return STATUS_SUCCESS;
+}
+
/* handler for ioctls on the mount manager device */
static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
{
@@ -403,6 +432,17 @@ static NTSTATUS WINAPI mountmgr_ioctl( DEVICE_OBJECT *device, IRP *irp )
irpsp->Parameters.DeviceIoControl.OutputBufferLength,
&irp->IoStatus );
break;
+ case IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS:
+ if (irpsp->Parameters.DeviceIoControl.InputBufferLength < sizeof(struct mountmgr_dhcp_request_params))
+ {
+ irp->IoStatus.u.Status = STATUS_INVALID_PARAMETER;
+ break;
+ }
+ irp->IoStatus.u.Status = query_dhcp_request_params( irp->AssociatedIrp.SystemBuffer,
+ irpsp->Parameters.DeviceIoControl.InputBufferLength,
+ irpsp->Parameters.DeviceIoControl.OutputBufferLength,
+ &irp->IoStatus );
+ break;
default:
FIXME( "ioctl %x not supported\n", irpsp->Parameters.DeviceIoControl.IoControlCode );
irp->IoStatus.u.Status = STATUS_NOT_SUPPORTED;
diff --git a/dlls/mountmgr.sys/mountmgr.h b/dlls/mountmgr.sys/mountmgr.h
index 79f72a3c83..95386a44f8 100644
--- a/dlls/mountmgr.sys/mountmgr.h
+++ b/dlls/mountmgr.sys/mountmgr.h
@@ -70,3 +70,6 @@ extern struct mount_point *add_volume_mount_point( DEVICE_OBJECT *device, UNICOD
const GUID *guid ) DECLSPEC_HIDDEN;
extern void delete_mount_point( struct mount_point *mount ) DECLSPEC_HIDDEN;
extern void set_mount_point_id( struct mount_point *mount, const void *id, unsigned int id_len ) DECLSPEC_HIDDEN;
+
+extern ULONG get_dhcp_request_param( const WCHAR *adapter, struct mountmgr_dhcp_request_param *param, char *buf,
+ ULONG offset, ULONG size ) DECLSPEC_HIDDEN;
diff --git a/include/ddk/mountmgr.h b/include/ddk/mountmgr.h
index fc3199c5ca..cb5822bf3d 100644
--- a/include/ddk/mountmgr.h
+++ b/include/ddk/mountmgr.h
@@ -61,6 +61,27 @@ struct mountmgr_unix_drive
USHORT device_offset;
};
+#define IOCTL_MOUNTMGR_QUERY_DHCP_REQUEST_PARAMS CTL_CODE(MOUNTMGRCONTROLTYPE, 64, METHOD_BUFFERED, FILE_READ_ACCESS | FILE_WRITE_ACCESS)
+
+struct mountmgr_dhcp_request_param
+{
+ ULONG id;
+ ULONG offset;
+ ULONG size;
+};
+
+#ifndef IF_MAX_STRING_SIZE
+#define IF_MAX_STRING_SIZE 256
+#endif
+
+struct mountmgr_dhcp_request_params
+{
+ ULONG size;
+ ULONG count;
+ WCHAR adapter[IF_MAX_STRING_SIZE + 1];
+ struct mountmgr_dhcp_request_param params[1];
+};
+
#endif
typedef struct _MOUNTMGR_CREATE_POINT_INPUT
--
2.20.1
More information about the wine-devel
mailing list