Send connman mailing list submissions to
        [email protected]

To subscribe or unsubscribe via the World Wide Web, visit
        https://lists.01.org/mailman/listinfo/connman
or, via email, send a message with subject or body 'help' to
        [email protected]

You can reach the person managing the list at
        [email protected]

When replying, please edit your Subject line so it is more specific
than "Re: Contents of connman digest..."


Today's Topics:

   1. [PATCH 0/6] VPN provider fixes and VPNC VPN agent support
      (Jussi Laakkonen)
   2. [PATCH 1/6] vpn-provider: Add support for plugin specific
      data (Jussi Laakkonen)
   3. [PATCH 2/6] vpn-provider: Check D-Bus message arg type in
      set_property() (Jussi Laakkonen)
   4. [PATCH 3/6] vpn-provider: Add function to get immutable state
      of provider string (Jussi Laakkonen)
   5. [PATCH 4/6] vpnc: Check for D-Bus arg types in notify
      (Jussi Laakkonen)
   6. [PATCH 5/6] vpnc: Implement VPN agent support (Jussi Laakkonen)


----------------------------------------------------------------------

Message: 1
Date: Tue, 28 May 2019 15:47:28 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 0/6] VPN provider fixes and VPNC VPN agent support
Message-ID: <[email protected]>

This set of patches improves and fixes some issues with vpn-provider.c
and implements VPN agent support for VPNC.

vpn-provider.c changes:
 * Support plugin specific data in provider. Plugins may set pointer to
   data for latter use, e.g., in case notify needs additional data.
 * Support retrieval of setting string immutable status. The main
   values within provider have the same status as the provider as other
   strings have individual statuses. Some VPN plugins need to
   temporarily cache credentials, but immutable ones should not be
   cleared.
 * Allow only DBUS_TYPE_STRING values in set_property()

VPNC changes:
 * Support VPN agent for setting authentication credentials. VPNC now
   is able to retrieve credentials using agent, if any, and clears them
   after writing the credentials to VPNC process, so VPN agent is used
   also with next connect attempt and credentials are not stored in
   provider.
 * Detect authentication and connection errors which VPNC outputs to
   stderr. If these are detected provider is notified with appropriate
   error code.
 * Check the D-Bus message arg types in notify. With invalid types
   crash would be expected.

Jussi Laakkonen (6):
  vpn-provider: Add support for plugin specific data
  vpn-provider: Check D-Bus message arg type in set_property()
  vpn-provider: Add function to get immutable state of provider string
  vpnc: Check for D-Bus arg types in notify
  vpnc: Implement VPN agent support
  vpnc: Detect authentication and connection errors

 vpn/plugins/vpnc.c | 531 ++++++++++++++++++++++++++++++++++++++++++---
 vpn/vpn-provider.c |  40 ++++
 vpn/vpn-provider.h |   4 +
 3 files changed, 545 insertions(+), 30 deletions(-)

-- 
2.20.1



------------------------------

Message: 2
Date: Tue, 28 May 2019 15:47:29 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 1/6] vpn-provider: Add support for plugin specific
        data
Message-ID: <[email protected]>

Support plugin specific data in provider. Setting internal data of a
plugin to provider is useful in case the VPN plugin needs to perform any
action based on the data when notify is called. For example, failure
counters can be incremented based on the sent notify information, which
may be later used for sending additional information to VPN provider.
---
 vpn/vpn-provider.c | 11 +++++++++++
 vpn/vpn-provider.h |  2 ++
 2 files changed, 13 insertions(+)

diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index ce8dc29d..4204cb78 100644
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -87,6 +87,7 @@ struct vpn_provider {
        bool immutable;
        struct connman_ipaddress *prev_ipv4_addr;
        struct connman_ipaddress *prev_ipv6_addr;
+       void *plugin_data;
 };
 
 static void append_properties(DBusMessageIter *iter,
@@ -2325,6 +2326,16 @@ void vpn_provider_set_data(struct vpn_provider 
*provider, void *data)
        provider->driver_data = data;
 }
 
+void *vpn_provider_get_plugin_data(struct vpn_provider *provider)
+{
+       return provider->plugin_data;
+}
+
+void vpn_provider_set_plugin_data(struct vpn_provider *provider, void *data)
+{
+       provider->plugin_data = data;
+}
+
 void vpn_provider_set_index(struct vpn_provider *provider, int index)
 {
        DBG("index %d provider %p", index, provider);
diff --git a/vpn/vpn-provider.h b/vpn/vpn-provider.h
index 96452c11..f1e99a24 100644
--- a/vpn/vpn-provider.h
+++ b/vpn/vpn-provider.h
@@ -97,6 +97,8 @@ int vpn_provider_get_index(struct vpn_provider *provider);
 
 void vpn_provider_set_data(struct vpn_provider *provider, void *data);
 void *vpn_provider_get_data(struct vpn_provider *provider);
+void vpn_provider_set_plugin_data(struct vpn_provider *provider, void *data);
+void *vpn_provider_get_plugin_data(struct vpn_provider *provider);
 int vpn_provider_set_ipaddress(struct vpn_provider *provider,
                                        struct connman_ipaddress *ipaddress);
 int vpn_provider_set_pac(struct vpn_provider *provider,
-- 
2.20.1



------------------------------

Message: 3
Date: Tue, 28 May 2019 15:47:30 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 2/6] vpn-provider: Check D-Bus message arg type in
        set_property()
Message-ID: <[email protected]>

By not checking the D-Bus message argument type in vpn-provider.c
set_property() connman-vpnd could be crashed with invalid D-Bus message
content. If the given argument has key other than "UserRoutes" then the
value must be DBUS_TYPE_STRING, otherwise invalid argument message is
sent to sender.
---
 vpn/vpn-provider.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index 4204cb78..25f685af 100644
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -453,6 +453,9 @@ static DBusMessage *set_property(DBusConnection *conn, 
DBusMessage *msg,
        } else {
                const char *str;
 
+               if (type != DBUS_TYPE_STRING)
+                       return __connman_error_invalid_arguments(msg);
+
                dbus_message_iter_get_basic(&value, &str);
                vpn_provider_set_string(provider, name, str);
        }
-- 
2.20.1



------------------------------

Message: 4
Date: Tue, 28 May 2019 15:47:31 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 3/6] vpn-provider: Add function to get immutable state
        of provider string
Message-ID: <[email protected]>

Add function to get immutable state of a string stored by provider.
Values of "Type", "Name", "Host", "HostIP", "VPN.Domain" and "Domain"
have the same status as the provider - these can be changed only if the
provider is non-immutable. Other values have individual immutable
statuses.
---
 vpn/vpn-provider.c | 26 ++++++++++++++++++++++++++
 vpn/vpn-provider.h |  2 ++
 2 files changed, 28 insertions(+)

diff --git a/vpn/vpn-provider.c b/vpn/vpn-provider.c
index 25f685af..053c1a9a 100644
--- a/vpn/vpn-provider.c
+++ b/vpn/vpn-provider.c
@@ -2303,6 +2303,32 @@ const char *vpn_provider_get_string(struct vpn_provider 
*provider,
        return setting->value;
 }
 
+bool vpn_provider_get_string_immutable(struct vpn_provider *provider,
+                                                       const char *key)
+{
+       struct vpn_setting *setting;
+
+       /* These values can be changed if the provider is not immutable */
+       if (g_str_equal(key, "Type")) {
+               return provider->immutable;
+       } else if (g_str_equal(key, "Name")) {
+               return provider->immutable;
+       } else if (g_str_equal(key, "Host")) {
+               return provider->immutable;
+       } else if (g_str_equal(key, "HostIP")) {
+               return provider->immutable;
+       } else if (g_str_equal(key, "VPN.Domain") ||
+                       g_str_equal(key, "Domain")) {
+               return provider->immutable;
+       }
+
+       setting = g_hash_table_lookup(provider->setting_strings, key);
+       if (!setting)
+               return true; /* Not found, regard as immutable - no changes */
+
+       return setting->immutable;
+}
+
 bool __vpn_provider_check_routes(struct vpn_provider *provider)
 {
        if (!provider)
diff --git a/vpn/vpn-provider.h b/vpn/vpn-provider.h
index f1e99a24..9aaff583 100644
--- a/vpn/vpn-provider.h
+++ b/vpn/vpn-provider.h
@@ -85,6 +85,8 @@ int vpn_provider_set_string_hide_value(struct vpn_provider 
*provider,
                                        const char *key, const char *value);
 const char *vpn_provider_get_string(struct vpn_provider *provider,
                                                        const char *key);
+bool vpn_provider_get_string_immutable(struct vpn_provider *provider,
+                                                       const char *key);
 
 int vpn_provider_set_state(struct vpn_provider *provider,
                                        enum vpn_provider_state state);
-- 
2.20.1



------------------------------

Message: 5
Date: Tue, 28 May 2019 15:47:32 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 4/6] vpnc: Check for D-Bus arg types in notify
Message-ID: <[email protected]>

Avoid crashing if invalid content is being processed in VPNC plugin
vc_notify(). Types of the D-Bus message args should be always checked.
---
 vpn/plugins/vpnc.c | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/vpn/plugins/vpnc.c b/vpn/plugins/vpnc.c
index cd9ff688..87a746cc 100644
--- a/vpn/plugins/vpnc.c
+++ b/vpn/plugins/vpnc.c
@@ -89,9 +89,16 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider 
*provider)
        char *address = NULL, *netmask = NULL, *gateway = NULL;
        struct connman_ipaddress *ipaddress;
        const char *reason, *key, *value;
+       int type;
 
        dbus_message_iter_init(msg, &iter);
 
+       type = dbus_message_iter_get_arg_type(&iter);
+       if (type != DBUS_TYPE_STRING) {
+               DBG("invalid D-Bus arg type %d", type);
+               return VPN_STATE_FAILURE;
+       }
+
        dbus_message_iter_get_basic(&iter, &reason);
        dbus_message_iter_next(&iter);
 
@@ -109,8 +116,18 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider 
*provider)
                DBusMessageIter entry;
 
                dbus_message_iter_recurse(&dict, &entry);
+
+               type = dbus_message_iter_get_arg_type(&entry);
+               if (type != DBUS_TYPE_STRING)
+                       continue;
+
                dbus_message_iter_get_basic(&entry, &key);
                dbus_message_iter_next(&entry);
+
+               type = dbus_message_iter_get_arg_type(&entry);
+               if (type != DBUS_TYPE_STRING)
+                       continue;
+
                dbus_message_iter_get_basic(&entry, &value);
 
                DBG("%s = %s", key, value);
-- 
2.20.1



------------------------------

Message: 6
Date: Tue, 28 May 2019 15:47:33 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH 5/6] vpnc: Implement VPN agent support
Message-ID: <[email protected]>

This adds VPN agent support for VPNC plugin. IPSec.Secret,
Xauth.Username and Xauth.Password are queried from agent if not set in
.config of the VPN provider.

By default, VPNC does not save the credentials to provider config. The
VPNC credentials stored by vpn-provider.c in the provider settings
strings are cleared after run_connect() has finished.

The values of IPSec.Secret, Xauth.Username and Xauth.Password are set to
"-" in order to get them retrieved via VPN agent at next connect request.
The credentials read from .config file are not being reset as the
immutable value of them is checked first. This approach supports also
partially defined credentials in .config, leaving some of them to be
retrieved using a VPN agent.

The approach for setting the credentials to "-" follows the approach of
OpenVPN plugin, where credential set as "-" is retrieved over management
interface.

If the credential has something else than "-" set it is forwarded to VPN
agent as old information, if at least one of the credentials is missing.
In this case request_input_credentials() is called and a message is sent
to VPN agent if any. request_input_credentials_reply() handles the
message sent by VPN agent, or errors (Error.Canceled = ECONNABORTED and
Error.Timeout = ETIMEDOUT) from VPN_AGENT_INTERFACE. vc_connect_done()
is invoked to call the callback function, which is executed only once,
with the error code, if any. In case of success, run_connect() is called
and VPN is attempted to connect.

When vc_notify() is called, it retrieves the plugin data from provider
and utilizes its callback by calling vc_connect_done() with the proper
error code, 0 being success.

If plugin dies or is disconnected, vc_died() handles the shutdown by
canceling all agent requests and calls vpn_died(). Last, the data
allocated for the connection is free'd.
---
 vpn/plugins/vpnc.c | 429 +++++++++++++++++++++++++++++++++++++++++----
 1 file changed, 399 insertions(+), 30 deletions(-)

diff --git a/vpn/plugins/vpnc.c b/vpn/plugins/vpnc.c
index 87a746cc..7808c3d8 100644
--- a/vpn/plugins/vpnc.c
+++ b/vpn/plugins/vpnc.c
@@ -39,15 +39,18 @@
 #include <connman/task.h>
 #include <connman/ipconfig.h>
 #include <connman/dbus.h>
+#include <connman/agent.h>
+#include <connman/setting.h>
+#include <connman/vpn-dbus.h>
 
 #include "../vpn-provider.h"
+#include "../vpn-agent.h"
 
 #include "vpn.h"
+#include "../vpn.h"
 
 #define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
 
-static DBusConnection *connection;
-
 enum {
        OPT_STRING = 1,
        OPT_BOOLEAN = 2,
@@ -83,14 +86,58 @@ struct {
                                                                        true },
 };
 
+struct vc_private_data {
+       struct vpn_provider *provider;
+       struct connman_task *task;
+       char *if_name;
+       vpn_provider_connect_cb_t cb;
+       void *user_data;
+};
+
+static void vc_connect_done(struct vc_private_data *data, int err)
+{
+       DBG("data %p err %d", data, err);
+
+       if (data && data->cb) {
+               vpn_provider_connect_cb_t cb = data->cb;
+               void *user_data = data->user_data;
+
+               /* Make sure we don't invoke this callback twice */
+               data->cb = NULL;
+               data->user_data = NULL;
+               cb(data->provider, user_data, err);
+       }
+}
+
+static void free_private_data(struct vc_private_data *data)
+{
+       DBG("data %p", data);
+
+       if (!data || !data->provider)
+               return;
+
+       DBG("provider %p", data->provider);
+
+       if (vpn_provider_get_plugin_data(data->provider) == data)
+               vpn_provider_set_plugin_data(data->provider, NULL);
+
+       vpn_provider_unref(data->provider);
+
+       g_free(data->if_name);
+       g_free(data);
+}
+
 static int vc_notify(DBusMessage *msg, struct vpn_provider *provider)
 {
        DBusMessageIter iter, dict;
        char *address = NULL, *netmask = NULL, *gateway = NULL;
        struct connman_ipaddress *ipaddress;
        const char *reason, *key, *value;
+       struct vc_private_data *data;
        int type;
 
+       data = vpn_provider_get_plugin_data(provider);
+
        dbus_message_iter_init(msg, &iter);
 
        type = dbus_message_iter_get_arg_type(&iter);
@@ -104,11 +151,14 @@ static int vc_notify(DBusMessage *msg, struct 
vpn_provider *provider)
 
        if (!provider) {
                connman_error("No provider found");
+               vc_connect_done(data, ENOENT);
                return VPN_STATE_FAILURE;
        }
 
-       if (strcmp(reason, "connect"))
+       if (g_strcmp0(reason, "connect")) {
+               vc_connect_done(data, EIO);
                return VPN_STATE_DISCONNECT;
+       }
 
        dbus_message_iter_recurse(&iter, &dict);
 
@@ -160,7 +210,7 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider 
*provider)
                g_free(address);
                g_free(netmask);
                g_free(gateway);
-
+               vc_connect_done(data, EIO);
                return VPN_STATE_FAILURE;
        }
 
@@ -172,6 +222,7 @@ static int vc_notify(DBusMessage *msg, struct vpn_provider 
*provider)
        g_free(gateway);
        connman_ipaddress_free(ipaddress);
 
+       vc_connect_done(data, 0);
        return VPN_STATE_CONNECT;
 }
 
@@ -280,27 +331,45 @@ static int vc_save(struct vpn_provider *provider, 
GKeyFile *keyfile)
        return 0;
 }
 
-static int vc_connect(struct vpn_provider *provider,
-                       struct connman_task *task, const char *if_name,
-                       vpn_provider_connect_cb_t cb, const char *dbus_sender,
-                       void *user_data)
+static void vc_died(struct connman_task *task, int exit_code, void *user_data)
 {
-       const char *option;
-       int err = 0, fd;
+       struct vc_private_data *data = user_data;
 
-       option = vpn_provider_get_string(provider, "Host");
-       if (!option) {
-               connman_error("Host not set; cannot enable VPN");
-               err = -EINVAL;
-               goto done;
-       }
-       option = vpn_provider_get_string(provider, "VPNC.IPSec.ID");
-       if (!option) {
-               connman_error("Group not set; cannot enable VPN");
-               err = -EINVAL;
-               goto done;
+       DBG("task %p data %p exit_code %d user_data %p", task, data, exit_code,
+                               user_data);
+
+       if (!data)
+               return;
+
+       if (data->provider) {
+               connman_agent_cancel(data->provider);
+
+               if (task)
+                       vpn_died(task, exit_code, data->provider);
        }
 
+       free_private_data(data);
+}
+
+static int run_connect(struct vc_private_data *data)
+{
+       struct vpn_provider *provider;
+       struct connman_task *task;
+       const char *credentials[] = {"VPNC.IPSec.Secret", "VPNC.Xauth.Username",
+                               "VPNC.Xauth.Password", NULL};
+       const char *if_name;
+       const char *option;
+       int err;
+       int fd;
+       int i;
+
+       provider = data->provider;
+       task = data->task;
+       if_name = data->if_name;
+
+       DBG("provider %p task %p interface %s user_data %p", provider, task,
+                               if_name, data->user_data);
+
        connman_task_add_argument(task, "--non-inter", NULL);
        connman_task_add_argument(task, "--no-detach", NULL);
 
@@ -323,8 +392,7 @@ static int vc_connect(struct vpn_provider *provider,
 
        connman_task_add_argument(task, "-", NULL);
 
-       err = connman_task_run(task, vpn_died, provider,
-                               &fd, NULL, NULL);
+       err = connman_task_run(data->task, vc_died, data, &fd, NULL, NULL);
        if (err < 0) {
                connman_error("vpnc failed to start");
                err = -EIO;
@@ -333,15 +401,320 @@ static int vc_connect(struct vpn_provider *provider,
 
        err = vc_write_config_data(provider, fd);
 
-       close(fd);
+       if (err) {
+               DBG("config write error %s", strerror(err));
+               goto done;
+       }
+
+       err = -EINPROGRESS;
 
 done:
-       if (cb)
-               cb(provider, user_data, err);
+       close(fd);
+
+       /*
+        * Clear out credentials if they are non-immutable. If this is called
+        * directly from vc_connect() all credentials are read from config and
+        * are set as immutable, so no change is done. In case a VPN agent is
+        * used these values should be reset to "-" in order to retrieve them
+        * from VPN agent next time VPN connection is established. This supports
+        * then partially defined credentials in .config and some can be
+        * retrieved using an agent.
+        */
+       for (i = 0; credentials[i]; i++) {
+               const char *key = credentials[i];
+               if (!vpn_provider_get_string_immutable(provider, key))
+                       vpn_provider_set_string(provider, key, "-");
+       }
 
        return err;
 }
 
+static void request_input_append_mandatory(DBusMessageIter *iter,
+               void *user_data)
+{
+       char *str = "string";
+
+       connman_dbus_dict_append_basic(iter, "Type",
+                               DBUS_TYPE_STRING, &str);
+       str = "mandatory";
+       connman_dbus_dict_append_basic(iter, "Requirement",
+                               DBUS_TYPE_STRING, &str);
+
+       if (!user_data)
+               return;
+
+       str = user_data;
+       connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_append_password(DBusMessageIter *iter,
+               void *user_data)
+{
+       char *str = "password";
+
+       connman_dbus_dict_append_basic(iter, "Type",
+                               DBUS_TYPE_STRING, &str);
+       str = "mandatory";
+       connman_dbus_dict_append_basic(iter, "Requirement",
+                               DBUS_TYPE_STRING, &str);
+
+       if (!user_data)
+               return;
+
+       str = user_data;
+       connman_dbus_dict_append_basic(iter, "Value", DBUS_TYPE_STRING, &str);
+}
+
+static void request_input_credentials_reply(DBusMessage *reply, void 
*user_data)
+{
+       struct vc_private_data *data = user_data;
+       char *secret = NULL, *username = NULL, *password = NULL;
+       const char *key;
+       DBusMessageIter iter, dict;
+       DBusError error;
+       int err_int = 0;
+
+       DBG("provider %p", data->provider);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply)) {
+               if (!g_strcmp0(error.name, VPN_AGENT_INTERFACE
+                                                       ".Error.Canceled"))
+                       err_int = ECONNABORTED;
+
+               if (!g_strcmp0(error.name, VPN_AGENT_INTERFACE
+                                                       ".Error.Timeout"))
+                       err_int = ETIMEDOUT;
+
+               dbus_error_free(&error);
+               goto abort;
+       }
+
+       if (!vpn_agent_check_reply_has_dict(reply))
+               goto err;
+
+       dbus_message_iter_init(reply, &iter);
+       dbus_message_iter_recurse(&iter, &dict);
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       break;
+
+               dbus_message_iter_get_basic(&entry, &key);
+
+               if (g_str_equal(key, "VPNC.IPSec.Secret")) {
+                       dbus_message_iter_next(&entry);
+                       if (dbus_message_iter_get_arg_type(&entry)
+                                                       != DBUS_TYPE_VARIANT)
+                               break;
+                       dbus_message_iter_recurse(&entry, &value);
+                       if (dbus_message_iter_get_arg_type(&value)
+                                                       != DBUS_TYPE_STRING)
+                               break;
+                       dbus_message_iter_get_basic(&value, &secret);
+                       vpn_provider_set_string_hide_value(data->provider,
+                                       key, secret);
+
+               } else if (g_str_equal(key, "VPNC.Xauth.Username")) {
+                       dbus_message_iter_next(&entry);
+                       if (dbus_message_iter_get_arg_type(&entry)
+                                                       != DBUS_TYPE_VARIANT)
+                               break;
+                       dbus_message_iter_recurse(&entry, &value);
+                       if (dbus_message_iter_get_arg_type(&value)
+                                                       != DBUS_TYPE_STRING)
+                               break;
+                       dbus_message_iter_get_basic(&value, &username);
+                       vpn_provider_set_string(data->provider, key, username);
+
+               } else if (g_str_equal(key, "VPNC.Xauth.Password")) {
+                       dbus_message_iter_next(&entry);
+                       if (dbus_message_iter_get_arg_type(&entry)
+                                                       != DBUS_TYPE_VARIANT)
+                               break;
+                       dbus_message_iter_recurse(&entry, &value);
+                       if (dbus_message_iter_get_arg_type(&value)
+                                                       != DBUS_TYPE_STRING)
+                               break;
+                       dbus_message_iter_get_basic(&value, &password);
+                       vpn_provider_set_string_hide_value(data->provider, key,
+                                               password);
+               }
+
+               dbus_message_iter_next(&dict);
+       }
+
+       if (!secret || !username || !password)
+               goto err;
+
+       err_int = run_connect(data);
+       if (err_int != -EINPROGRESS)
+               goto err;
+
+       return;
+
+err:
+       err_int = EACCES;
+
+abort:
+       vc_connect_done(data, err_int);
+
+       switch (err_int) {
+       case EACCES:
+               vpn_provider_indicate_error(data->provider,
+                                       VPN_PROVIDER_ERROR_AUTH_FAILED);
+               break;
+       case ECONNABORTED:
+       case ETIMEDOUT:
+               vpn_provider_indicate_error(data->provider,
+                                       VPN_PROVIDER_ERROR_UNKNOWN);
+       }
+}
+
+static int request_input_credentials(struct vc_private_data *data,
+                                       const char* dbus_sender)
+{
+       struct vpn_provider *provider = data->provider;
+       DBusMessage *message;
+       const char *path, *agent_sender, *agent_path;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       const char *str;
+       int err;
+       void *agent;
+
+       DBG("provider %p data %p sender %s", provider, data, dbus_sender);
+
+       agent = connman_agent_get_info(dbus_sender, &agent_sender,
+                                                       &agent_path);
+       if (!provider || !agent || !agent_path)
+               return -ESRCH;
+
+       message = dbus_message_new_method_call(agent_sender, agent_path,
+                                       VPN_AGENT_INTERFACE,
+                                       "RequestInput");
+       if (!message)
+               return -ENOMEM;
+
+       dbus_message_iter_init_append(message, &iter);
+
+       path = vpn_provider_get_path(provider);
+       dbus_message_iter_append_basic(&iter,
+                               DBUS_TYPE_OBJECT_PATH, &path);
+
+       connman_dbus_dict_open(&iter, &dict);
+
+       str = vpn_provider_get_string(provider, "VPNC.IPSec.Secret");
+       if (!g_strcmp0(str, "-"))
+               str = NULL;
+
+       connman_dbus_dict_append_dict(&dict, "VPNC.IPSec.Secret",
+                               request_input_append_password, (void *)str);
+
+       str = vpn_provider_get_string(provider, "VPNC.Xauth.Username");
+       if (!g_strcmp0(str, "-"))
+               str = NULL;
+
+       connman_dbus_dict_append_dict(&dict, "VPNC.Xauth.Username",
+                               request_input_append_mandatory, (void *)str);
+
+       str = vpn_provider_get_string(provider, "VPNC.Xauth.Password");
+       if (!g_strcmp0(str, "-"))
+               str = NULL;
+
+       connman_dbus_dict_append_dict(&dict, "VPNC.Xauth.Password",
+                               request_input_append_password, (void *)str);
+
+       vpn_agent_append_host_and_name(&dict, provider);
+
+       connman_dbus_dict_close(&iter, &dict);
+
+       err = connman_agent_queue_message(provider, message,
+                       connman_timeout_input_request(),
+                       request_input_credentials_reply, data, agent);
+
+       if (err < 0 && err != -EBUSY) {
+               DBG("error %d sending agent request", err);
+               dbus_message_unref(message);
+
+               return err;
+       }
+
+       dbus_message_unref(message);
+
+       return -EINPROGRESS;
+}
+
+static int vc_connect(struct vpn_provider *provider,
+                       struct connman_task *task, const char *if_name,
+                       vpn_provider_connect_cb_t cb, const char *dbus_sender,
+                       void *user_data)
+{
+       struct vc_private_data *data;
+       const char *option;
+       bool username_set = false;
+       bool password_set = false;
+       bool ipsec_secret_set = false;
+       int err;
+
+       DBG("provider %p if_name %s user_data %p", provider, if_name, 
user_data);
+
+       option = vpn_provider_get_string(provider, "Host");
+       if (!option) {
+               connman_error("Host not set; cannot enable VPN");
+               return -EINVAL;
+       }
+
+       option = vpn_provider_get_string(provider, "VPNC.IPSec.ID");
+       if (!option) {
+               connman_error("Group not set; cannot enable VPN");
+               return -EINVAL;
+       }
+
+       option = vpn_provider_get_string(provider, "VPNC.IPSec.Secret");
+       if (option && *option && g_strcmp0(option, "-"))
+               ipsec_secret_set = true;
+       DBG("VPNC.IPSec.Secret %s", option);
+
+       option = vpn_provider_get_string(provider, "VPNC.Xauth.Username");
+       if (option && *option && g_strcmp0(option, "-"))
+               username_set = true;
+       DBG("VPNC.Xauth.Username %s", option);
+
+       option = vpn_provider_get_string(provider, "VPNC.Xauth.Password");
+       if (option && *option && g_strcmp0(option, "-"))
+               password_set = true;
+       DBG("VPNC.Xauth.Password %s", option);
+
+       data = g_try_new0(struct vc_private_data, 1);
+       if (!data)
+               return -ENOMEM;
+
+       vpn_provider_set_plugin_data(provider, data);
+       data->provider = vpn_provider_ref(provider);
+       data->task = task;
+       data->if_name = g_strdup(if_name);
+       data->cb = cb;
+       data->user_data = user_data;
+
+       if (!ipsec_secret_set || !username_set || !password_set) {
+               err = request_input_credentials(data, dbus_sender);
+               if (err != -EINPROGRESS) {
+                       vc_connect_done(data, ECONNABORTED);
+                       vpn_provider_indicate_error(data->provider,
+                                       VPN_PROVIDER_ERROR_LOGIN_FAILED);
+                       free_private_data(data);
+               }
+
+               return err;
+       }
+
+       return run_connect(data);
+}
+
 static int vc_error_code(struct vpn_provider *provider, int exit_code)
 {
        switch (exit_code) {
@@ -384,16 +757,12 @@ static struct vpn_driver vpn_driver = {
 
 static int vpnc_init(void)
 {
-       connection = connman_dbus_get_connection();
-
        return vpn_register("vpnc", &vpn_driver, VPNC);
 }
 
 static void vpnc_exit(void)
 {
        vpn_unregister("vpnc");
-
-       dbus_connection_unref(connection);
 }
 
 CONNMAN_PLUGIN_DEFINE(vpnc, "vpnc plugin", VERSION,
-- 
2.20.1



------------------------------

Subject: Digest Footer

_______________________________________________
connman mailing list
[email protected]
https://lists.01.org/mailman/listinfo/connman


------------------------------

End of connman Digest, Vol 43, Issue 22
***************************************

Reply via email to