Signed-off-by: Hans Leidekker hans@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