diff options
Diffstat (limited to 'vpn/vpn-provider.c')
-rwxr-xr-x | vpn/vpn-provider.c | 68 |
1 files changed, 57 insertions, 11 deletions
diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c index 925f6997..67239e40 100755 --- a/vpn/vpn-provider.c +++ b/vpn/vpn-provider.c @@ -501,6 +501,12 @@ static DBusMessage *do_connect(DBusConnection *conn, DBusMessage *msg, return NULL; } +static DBusMessage *do_connect2(DBusConnection *conn, DBusMessage *msg, + void *data) +{ + return do_connect(conn, msg, data); +} + static DBusMessage *do_disconnect(DBusConnection *conn, DBusMessage *msg, void *data) { @@ -527,6 +533,9 @@ static const GDBusMethodTable connection_methods[] = { GDBUS_ARGS({ "name", "s" }), NULL, clear_property) }, { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, do_connect) }, + { GDBUS_ASYNC_METHOD("Connect2", + GDBUS_ARGS({ "dbus_sender", "s" }), + NULL, do_connect2) }, { GDBUS_METHOD("Disconnect", NULL, NULL, do_disconnect) }, { }, }; @@ -549,6 +558,12 @@ static void resolv_result(GResolvResultStatus status, provider->host_ip = g_strdupv(results); vpn_provider_unref(provider); + + /* Remove the resolver here so that it will not be left + * hanging around and cause double free in unregister_provider() + */ + g_resolv_unref(provider->resolv); + provider->resolv = NULL; } static void provider_resolv_host_addr(struct vpn_provider *provider) @@ -680,14 +695,11 @@ static struct vpn_route *get_route(char *route_str) in_addr_t addr; struct in_addr netmask_in; unsigned char prefix_len = 32; + char *ptr; + long int value = strtol(netmask, &ptr, 10); - if (netmask) { - char *ptr; - long int value = strtol(netmask, &ptr, 10); - if (ptr != netmask && *ptr == '\0' && - value <= 32) - prefix_len = value; - } + if (ptr != netmask && *ptr == '\0' && value <= 32) + prefix_len = value; addr = 0xffffffff << (32 - prefix_len); netmask_in.s_addr = htonl(addr); @@ -796,16 +808,20 @@ static gchar **create_network_list(GSList *networks, gsize *count) { GSList *list; gchar **result = NULL; + gchar **prev_result; unsigned int num_elems = 0; for (list = networks; list; list = g_slist_next(list)) { struct vpn_route *route = list->data; int family; + prev_result = result; result = g_try_realloc(result, (num_elems + 1) * sizeof(gchar *)); - if (!result) + if (!result) { + g_free(prev_result); return NULL; + } switch (route->family) { case AF_INET: @@ -826,9 +842,12 @@ static gchar **create_network_list(GSList *networks, gsize *count) num_elems++; } + prev_result = result; result = g_try_realloc(result, (num_elems + 1) * sizeof(gchar *)); - if (!result) + if (!result) { + g_free(prev_result); return NULL; + } result[num_elems] = NULL; *count = num_elems; @@ -1081,10 +1100,22 @@ int __vpn_provider_connect(struct vpn_provider *provider, DBusMessage *msg) DBG("provider %p", provider); if (provider->driver && provider->driver->connect) { + const char *dbus_sender = dbus_message_get_sender(msg); + dbus_message_ref(msg); + + if (dbus_message_has_signature(msg, + DBUS_TYPE_STRING_AS_STRING)) { + const char *sender = NULL; + + dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, + &sender, DBUS_TYPE_INVALID); + if (sender && sender[0]) + dbus_sender = sender; + } + err = provider->driver->connect(provider, connect_cb, - dbus_message_get_sender(msg), - msg); + dbus_sender, msg); } else return -EOPNOTSUPP; @@ -1560,6 +1591,9 @@ int vpn_provider_indicate_error(struct vpn_provider *provider, break; } + if (provider->driver && provider->driver->set_state) + provider->driver->set_state(provider, provider->state); + return 0; } @@ -1605,6 +1639,18 @@ static void unregister_provider(gpointer data) connection_unregister(provider); + /* If the provider has any DNS resolver queries pending, + * they need to be cleared here because the unref will not + * be able to do that (because the provider_resolv_host_addr() + * has increased the ref count by 1). This is quite rare as + * normally the resolving either returns a value or has a + * timeout which clears the memory. Typically resolv_result() will + * unref the provider but in this case that call has not yet + * happened. + */ + if (provider->resolv) + vpn_provider_unref(provider); + vpn_provider_unref(provider); } |