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. Re: [PATCH 5/5] man: Document VPN config file privilege
      configuration in connman-vpn.conf (Daniel Wagner)
   2. Re: [PATCH 2/5] vpn: Add support for configurable user and
      groups in settings (Jussi Laakkonen)
   3. [PATCH v2 0/5] VPN settings and configurable VPN DAC
      privileges (Jussi Laakkonen)
   4. [PATCH v2 2/5] vpn: Add support for configurable DAC
      privileges in settings. (Jussi Laakkonen)
   5. [PATCH v2 3/5] task: Add support for a custom setup function
      (Jussi Laakkonen)
   6. [PATCH v2 4/5] vpn: Run VPN plugin binaries with configurable
      DAC privileges (Jussi Laakkonen)


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

Message: 1
Date: Thu, 2 May 2019 10:29:22 +0200
From: Daniel Wagner <[email protected]>
To: Jussi Laakkonen <[email protected]>
Cc: [email protected]
Subject: Re: [PATCH 5/5] man: Document VPN config file privilege
        configuration in connman-vpn.conf
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8

Hi Jussi,

>> One thing I haven't understood so far, is why is the VPN API so
>> different to the ConnMan API that we need to handle the access control
>> directly. I must miss something. I though with polkit or even D-Bus
>> config files you can do this kind of things.
>>
> 
> Hm, maybe the other parts need a bit of clarifying then. This is not
> about providing access to anything but enabling connman-vpnd to run the
> VPN binaries with different DAC permissions.
> 
> For example, in our case, connmand and connman-vpnd are run as root, so
> the VPN binaries (openvpn) are run with same privileges. This series
> allows to change the privileges to something else, as there are cases
> where it is desired to have the VPN running with less privileges as the
> connman-vpnd. The openvpn run by OpenVPN plugin does not have to have
> access to everything that connman-vpnd/root has.
> 
> I'll update the series + descriptions and send them later today.

After pondering on it my bike ride to work, I got the idea behind the
changes! Obviously, first thinking and then typing would be right
solution :)

If you could updating the description/documentation accordingly, it
would be awesome!

Thanks,
Daniel


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

Message: 2
Date: Thu, 2 May 2019 13:47:28 +0300
From: Jussi Laakkonen <[email protected]>
To: Daniel Wagner <[email protected]>
Cc: [email protected]
Subject: Re: [PATCH 2/5] vpn: Add support for configurable user and
        groups in settings
Message-ID: <[email protected]>
Content-Type: text/plain; charset=utf-8; format=flowed

Hi Daniel,

On 5/2/19 11:24 AM, Daniel Wagner wrote:
> Hi Jussi,
> 
> On 02.05.19 09:41, Jussi Laakkonen wrote:
>>>> An example config is:
>>>> [VPNBinary]
>>>
>>> So if you want to do a group, it tell what it is about, maybe
>>> Permission/AccessControl or something along this. I wouldn't mind to
>>> have the User/Group/SupmentaryGroups in the general section
>>> either. VPNBinary seems not really fitting here.
>>>
>>
>> The naming for the group was not perfect, I agree. I think these could
>> be in own group to have a clear separation of the configuration purposes.
>>
>> I'll think renaming VPNBinary to Privileges as it would be the most
>> descriptive (or DACPrivileges, or DAC_Privileges), since this is solely
>> about changing the privileges of the binary ran by connman-vpnd when
>> connecting a VPN plugin. What do you say Daniel?
> 
> I slowly understand why I didn't understand the purpose of the series
> (last mail). Brains starts to work...
> 
> Indeed I think DACPrivileges or alike would be a better name. Just
> wondering if we want to ponder on the idea if we want to support more
> then one global configuration, e.g. two different configuration (not
> active at the same time). Would that be overkill?
> 

I'll use DACPrivileges then. I did not even think about introducing more 
than one global configuration with this. It might be too much as there 
is support for each VPN type, which overrides the global configuration 
values.

It is possible to have the groups defined in the global config and each 
VPN type has then different user. The flexibility could be increased, 
though, if there is a real need. It can be worked later on I think.

> Thanks,
> Daniel
> 

Cheers,
Jussi


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

Message: 3
Date: Thu,  2 May 2019 13:51:16 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH v2 0/5] VPN settings and configurable VPN DAC
        privileges
Message-ID: <[email protected]>

Changes since V2:
 * Patch 0/5: Update description a bit to clarify the purpose.
 * Patch 2/5:
   * Change VPNBinary group to DACPrivileges.
   * Update commit message header.
 * Patch 3/5:
   * Rename custom_setup_func to setup_func
   * Rename user_data to setup_data to follow same naming convention
 * Patch 4/5:
   * Remove NOTE/TODO comment on privilege change not working. Privilege
     change does work with both builtin and external plugins. Different
     systems may require testing with supplementary groups.
   * Minor formatting fix.
   * Update commit message and header to be more undestandable.
 * Patch 5/5:
   * Update manual page to be more descriptive and clear.
   * Change VPNBinary to DACPrivileges in manual page.
   * Update commit message header.

This set of commits moves the VPN configuration from vpn/main.c into
vpn/vpn-settings.c. The configuration is amended with the option to
define DAC privileges (user, group and supplementary groups) for the VPN
binary ran by connman-vpnd for a VPN plugin. By default the VPN binaries
are ran with the same privileges as connman-vpnd. If the config has no
privileges configured no changes are made to the privileges.

Main purpose of this is to allow to limit the access of ran VPN binaries
to the underlying systems. In systems where connman-vpnd is ran as root
this brings the benefit of having the possibility to limit the access to
other system resources than the VPN binary actually needs.

For all VPNs the settings can be defined in CONFIGDIR/connman-vpn.conf
or separately for each VPN using the plugin name in group DACPrivileges.
For example, OpenVPN configuration is in
CONFIGDIR/vpn-plugins/openvpn.conf. Setting a plugin specific
configuration overrides main connman-vpn.conf settings. If there is no
configuration or some parameter is not set, the default value is used
and if the default value is also missing, nothing is done. Documentation
of this is added to connman-vpn.conf manual pages.

When registering a VPN plugin (vpn_register()) vpn/plugins/vpn.c loads
the plugin specific config (struct vpn_plugin_data). If configuration
exists the returned content is used when connecting the VPN. Config is
loaded only once and is free'd when plugin calls vpn_unregister().

task.c is modified to support a custom task setup function and user
data for it when new task is to be created. This custom task setup
function is executed prior to running the task. The given user data is
passed for the custom task setup function.

vpn/plugins/vpn.c utilizes this by adding vpn_task_setup() function to
be run at VPN setup prior to starting the task. The vpn_task_setup()
takes the config and sets group, supplementary groups and user for the
VPN plugin binary (in this order). setgid(), setgroups() and setuid()
are used and CAP_SETGID and CAP_SETUID are, therefore, required.

Setting up groups is a system specific problem, but in general,
following should work at least with OpenVPN:
[DACPrivileges]
User = <user for VPN>
Group = vpn
SupplementaryGroups = inet, net_admin

The configuration also supports defining only the groups in the main VPN
configuration and then providing separate configs for each VPN type,
which change only the user for the VPN binary.

Jussi Laakkonen (5):
  vpn: Move settings from main.c to vpn-settings.c
  vpn: Add support for configurable DAC privileges in settings.
  task: Add support for a custom setup function
  vpn: Run VPN plugin binaries with configurable DAC privileges
  man: Document DAC privilege configuration in VPN configuration file

 Makefile.am                |   2 +-
 doc/connman-vpn.conf.5.in  |  33 ++++-
 include/task.h             |   6 +-
 src/task.c                 |  13 +-
 vpn/connman-vpn.service.in |   2 +-
 vpn/main.c                 |  68 +---------
 vpn/plugins/vpn.c          | 136 +++++++++++++++++++-
 vpn/vpn-settings.c         | 254 +++++++++++++++++++++++++++++++++++++
 vpn/vpn.h                  |  16 +++
 9 files changed, 459 insertions(+), 71 deletions(-)
 create mode 100644 vpn/vpn-settings.c

-- 
2.20.1



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

Message: 4
Date: Thu,  2 May 2019 13:51:17 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH v2 2/5] vpn: Add support for configurable DAC
        privileges in settings.
Message-ID: <[email protected]>

This adds support for configurable DAC privileges (user, group and
supplementary groups) set by connman-vpnd when running VPN binary for a
VPN plugin.

Common configuration, which applies to all VPNs, is loaded from the main
VPN config file CONFIGDIR/connman-vpn.conf. Configuring DAC privileges
for each VPN type separately is also supported: VPN specific
configuration is to be placed into CONFIGDIR/vpn-plugin/ using the
plugin name + .conf suffix. For example, configuration for OpenVPN goes
to CONFIGDIR/vpn-plugin/openvpn.conf.

Both configs follow the same format in group [DACPrivileges]:
 - User = user to use for running VPN binary (username or uid)
 - Group = the main group to use for running VPN binary (groupname or
   gid)
 - SupplementaryGroups = supplementary groups used (separator: comma,
   groupnames or gids)

An example config is:
[DACPrivileges]
User = vpn_user
Group = vpn
SupplementaryGroups = inet,net_admin

Common config for VPNs is loaded at initialization. The VPN specific
configuration is loaded and stored into hash table when
vpn_settings_parse_vpn_plugin_config() is called. If the config was
already loaded, -EALREADY is returned, if the config was invalid or did
not exist -ENOENT is returned.

Configuration for a VPN is to be retrieved with
vpn_settings_get_plugin_config(), which will return a pointer to
struct vpn_plugin_data or NULL. Each configuration (user, group and
supplementary groups) can be retrieved by passing the returned pointer
or NULL to functions:
 - vpn_settings_get_binary_user()
 - vpn_settings_get_binary_group()
 - vpn_settings_get_binary_supplementary_groups()

In case the struct pointer is NULL then the default value set in common
config will be returned. Otherwise the value within the struct is
returned.
---

Changes since V2:
 * Change VPN_GROUP from VPNBinary to DACPrivileges

 vpn/vpn-settings.c | 156 ++++++++++++++++++++++++++++++++++++++++++++-
 vpn/vpn.h          |  11 ++++
 2 files changed, 166 insertions(+), 1 deletion(-)

diff --git a/vpn/vpn-settings.c b/vpn/vpn-settings.c
index 40d2905a..fd372e40 100644
--- a/vpn/vpn-settings.c
+++ b/vpn/vpn-settings.c
@@ -22,24 +22,89 @@
 
 #include <stdlib.h>
 #include <string.h>
+#include <errno.h>
 
 #include <connman/log.h>
 
 #include "vpn.h"
 
 #define DEFAULT_INPUT_REQUEST_TIMEOUT 300 * 1000
+#define PLUGIN_CONFIGDIR CONFIGDIR "/vpn-plugin"
+#define VPN_GROUP "DACPrivileges"
 
 static struct {
        unsigned int timeout_inputreq;
+       char *binary_user;
+       char *binary_group;
+       char **binary_supplementary_groups;
 } connman_vpn_settings  = {
        .timeout_inputreq               = DEFAULT_INPUT_REQUEST_TIMEOUT,
+       .binary_user                    = NULL,
+       .binary_group                   = NULL,
+       .binary_supplementary_groups    = NULL,
 };
 
+struct vpn_plugin_data {
+       char *binary_user;
+       char *binary_group;
+       char **binary_supplementary_groups;
+};
+
+GHashTable *plugin_hash = NULL;
+
+const char *vpn_settings_get_binary_user(struct vpn_plugin_data *data)
+{
+       if (data && data->binary_user)
+               return data->binary_user;
+
+       return connman_vpn_settings.binary_user;
+}
+
+const char *vpn_settings_get_binary_group(struct vpn_plugin_data *data)
+{
+       if (data && data->binary_group)
+               return data->binary_group;
+
+       return connman_vpn_settings.binary_group;
+}
+
+char **vpn_settings_get_binary_supplementary_groups
+                                               (struct vpn_plugin_data *data)
+{
+       if (data && data->binary_supplementary_groups)
+               return data->binary_supplementary_groups;
+
+       return connman_vpn_settings.binary_supplementary_groups;
+}
+
 unsigned int __vpn_settings_get_timeout_inputreq()
 {
        return connman_vpn_settings.timeout_inputreq;
 }
 
+static char *get_string(GKeyFile *config, const char *group, const char *key)
+{
+       char *str = g_key_file_get_string(config, group, key, NULL);
+       return str ? g_strstrip(str) : NULL;
+}
+
+static char **get_string_list(GKeyFile *config, const char *group,
+                                                               const char *key)
+{
+       gsize len = 0;
+       char **str = g_key_file_get_string_list(config, group, key, &len, NULL);
+
+       if (str) {
+               guint i = 0;
+
+               for (i = 0; i < len ; i++) {
+                       str[i] = g_strstrip(str[i]);
+               }
+       }
+
+       return str;
+}
+
 static void parse_config(GKeyFile *config, const char *file)
 {
        const char *group = "General";
@@ -57,6 +122,88 @@ static void parse_config(GKeyFile *config, const char *file)
                connman_vpn_settings.timeout_inputreq = timeout * 1000;
 
        g_clear_error(&error);
+
+       connman_vpn_settings.binary_user = get_string(config, VPN_GROUP,
+                                               "User");
+       connman_vpn_settings.binary_group = get_string(config, VPN_GROUP,
+                                               "Group");
+       connman_vpn_settings.binary_supplementary_groups = get_string_list(
+                                               config, VPN_GROUP,
+                                               "SupplementaryGroups");
+}
+
+struct vpn_plugin_data *vpn_settings_get_vpn_plugin_config(const char *name)
+{
+       struct vpn_plugin_data *data = NULL;
+
+       if (plugin_hash)
+               data = g_hash_table_lookup(plugin_hash, name);
+
+       return data;
+}
+
+static void vpn_plugin_data_free(gpointer data)
+{
+       struct vpn_plugin_data *plugin_data = (struct vpn_plugin_data*)data;
+
+       g_free(plugin_data->binary_user);
+       g_free(plugin_data->binary_group);
+       g_strfreev(plugin_data->binary_supplementary_groups);
+
+       g_free(data);
+}
+
+int vpn_settings_parse_vpn_plugin_config(const char *name)
+{
+       struct vpn_plugin_data *data;
+       gchar *file;
+       gchar *ext = ".conf";
+       GKeyFile *config;
+       gint err = 0;
+
+       if (!name || !*name)
+               return -EINVAL;
+
+       if (vpn_settings_get_vpn_plugin_config(name))
+               return -EALREADY;
+
+       file = g_strconcat(PLUGIN_CONFIGDIR, "/", name, ext, NULL);
+
+       config =  __vpn_settings_load_config(file);
+
+       if (!config) {
+               err = -ENOENT;
+               DBG("Cannot load config %s for %s", file, name);
+               goto out;
+       }
+
+       data = g_try_new0(struct vpn_plugin_data, 1);
+
+       data->binary_user = get_string(config, VPN_GROUP, "User");
+       data->binary_group = get_string(config, VPN_GROUP, "Group");
+       data->binary_supplementary_groups = get_string_list(config, VPN_GROUP,
+                                               "SupplementaryGroups");
+
+       DBG("Loaded settings for %s: %s - %s",
+               name, data->binary_user, data->binary_group);
+
+       if (!plugin_hash)
+               plugin_hash = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               g_free, vpn_plugin_data_free);
+
+       g_hash_table_replace(plugin_hash, g_strdup(name), data);
+
+       g_key_file_unref(config);
+
+out:
+       g_free(file);
+       return err;
+}
+
+void vpn_settings_delete_vpn_plugin_config(const char *name)
+{
+       if (plugin_hash && name)
+               g_hash_table_remove(plugin_hash, name);
 }
 
 GKeyFile *__vpn_settings_load_config(const char *file)
@@ -96,5 +243,12 @@ int __vpn_settings_init(const char *file)
 
 void __vpn_settings_cleanup()
 {
-       return;
+       g_free(connman_vpn_settings.binary_user);
+       g_free(connman_vpn_settings.binary_group);
+       g_strfreev(connman_vpn_settings.binary_supplementary_groups);
+
+       if (plugin_hash) {
+               g_hash_table_destroy(plugin_hash);
+               plugin_hash = NULL;
+       }
 }
diff --git a/vpn/vpn.h b/vpn/vpn.h
index 01e6aab1..126f5e10 100644
--- a/vpn/vpn.h
+++ b/vpn/vpn.h
@@ -121,3 +121,14 @@ int __vpn_settings_init(const char *file);
 void __vpn_settings_cleanup(void);
 GKeyFile *__vpn_settings_load_config(const char *file);
 unsigned int __vpn_settings_get_timeout_inputreq(void);
+
+struct vpn_plugin_data;
+
+int vpn_settings_parse_vpn_plugin_config(const char* plugin_name);
+void vpn_settings_delete_vpn_plugin_config(const char *name);
+struct vpn_plugin_data* vpn_settings_get_vpn_plugin_config(const char *name);
+
+const char * vpn_settings_get_binary_user(struct vpn_plugin_data *data);
+const char * vpn_settings_get_binary_group(struct vpn_plugin_data *data);
+char ** vpn_settings_get_binary_supplementary_groups(
+       struct vpn_plugin_data *data);
-- 
2.20.1



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

Message: 5
Date: Thu,  2 May 2019 13:51:18 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH v2 3/5] task: Add support for a custom setup function
Message-ID: <[email protected]>

This commit adds support for a custom setup function for a task with an
additional user data. The callback function prototype is simple:
void (* connman_task_setup_t) (void *setup_data);

Purpose of this is to do custom work when task is being setup. Callback
function is registered at connman_task_create() and is executed as final
step in task_setup() using the additional task setup user data.
---

Changes since V2:
 * Rename custom_setup_func to setup_func
 * Rename user_data to setup_data to follow same naming convention

 include/task.h    |  6 +++++-
 src/task.c        | 13 ++++++++++++-
 vpn/plugins/vpn.c |  2 +-
 3 files changed, 18 insertions(+), 3 deletions(-)

diff --git a/include/task.h b/include/task.h
index 9977d634..dd67e7d2 100644
--- a/include/task.h
+++ b/include/task.h
@@ -42,7 +42,11 @@ typedef void (* connman_task_exit_t) (struct connman_task 
*task,
 typedef DBusMessage * (* connman_task_notify_t) (struct connman_task *task,
                                DBusMessage *message, void *user_data);
 
-struct connman_task *connman_task_create(const char *program);
+typedef void (* connman_task_setup_t) (void *setup_data);
+
+struct connman_task *connman_task_create(const char *program,
+                               connman_task_setup_t custom_task_setup,
+                               void *setup_data);
 void connman_task_destroy(struct connman_task *task);
 
 const char *connman_task_get_path(struct connman_task *task);
diff --git a/src/task.c b/src/task.c
index 953cc409..89de05b7 100644
--- a/src/task.c
+++ b/src/task.c
@@ -45,8 +45,10 @@ struct connman_task {
        GPtrArray *argv;
        GPtrArray *envp;
        connman_task_exit_t exit_func;
+       connman_task_setup_t setup_func;
        void *exit_data;
        GHashTable *notify;
+       void *setup_data;
 };
 
 static GHashTable *task_hash = NULL;
@@ -93,7 +95,9 @@ static void free_task(gpointer data)
  *
  * Returns: a newly-allocated #connman_task structure
  */
-struct connman_task *connman_task_create(const char *program)
+struct connman_task *connman_task_create(const char *program,
+                                       connman_task_setup_t custom_task_setup,
+                                       void *setup_data)
 {
        struct connman_task *task;
        gint counter;
@@ -116,9 +120,13 @@ struct connman_task *connman_task_create(const char 
*program)
        str = g_strdup(program);
        g_ptr_array_add(task->argv, str);
 
+       task->setup_func = custom_task_setup;
+
        task->notify = g_hash_table_new_full(g_str_hash, g_str_equal,
                                                        g_free, g_free);
 
+       task->setup_data = setup_data;
+
        DBG("task %p", task);
 
        g_hash_table_insert(task_hash, task->path, task);
@@ -277,6 +285,9 @@ static void task_setup(gpointer setup_data)
        sigemptyset(&mask);
        if (sigprocmask(SIG_SETMASK, &mask, NULL) < 0)
                connman_error("Failed to clean signal mask");
+
+       if (task->setup_func)
+               task->setup_func(task->setup_data);
 }
 
 /**
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index ddf4a6c6..9919928b 100644
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -478,7 +478,7 @@ static int vpn_connect(struct vpn_provider *provider,
                        goto exist_err;
        }
 
-       data->task = connman_task_create(vpn_driver_data->program);
+       data->task = connman_task_create(vpn_driver_data->program, NULL);
 
        if (!data->task) {
                ret = -ENOMEM;
-- 
2.20.1



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

Message: 6
Date: Thu,  2 May 2019 13:51:19 +0300
From: Jussi Laakkonen <[email protected]>
To: [email protected]
Subject: [PATCH v2 4/5] vpn: Run VPN plugin binaries with configurable
        DAC privileges
Message-ID: <[email protected]>

This enables to support running VPN plugin binaries with configurable
DAC privileges. Function vpn_task_setup() is registered as a custom
setup callback function into task.c and is called when the task setup
function is called prior to running the task.

When a VPN plugin registers itself (with vpn_register()) the DAC
privilege configuration for it is loaded from config with
vpn_settings_parse_vpn_plugin_config(). This configuration is stored by
vpn-settings.c and is free'd when the VPN plugin is unregistered with
vpn_unregister(). DAC privilege configuration of a plugin is passed as
custom setup user data to connman_task_create() when vpn_connect() is
called.

DAC privilege configuration is set when a VPN plugin is to be connected
(vpn_task_setup() is called). Function vpn_task_setup() sets the DAC
privileges in following order: change group, set supplementary groups
and change user id. Use of setgid(), setgroups() and setuid() needs
CAP_SETGID and CAP_SETUID capabilities.
---

Changes since V2:
 * Update commit message to be more descriptive and undestandable.
 * Fix formatting of if(!list) in get_supplementary_gids()

 vpn/connman-vpn.service.in |   2 +-
 vpn/plugins/vpn.c          | 136 ++++++++++++++++++++++++++++++++++++-
 2 files changed, 136 insertions(+), 2 deletions(-)

diff --git a/vpn/connman-vpn.service.in b/vpn/connman-vpn.service.in
index e98fb714..dd15bab4 100644
--- a/vpn/connman-vpn.service.in
+++ b/vpn/connman-vpn.service.in
@@ -6,7 +6,7 @@ Type=dbus
 BusName=net.connman.vpn
 ExecStart=@sbindir@/connman-vpnd -n
 StandardOutput=null
-CapabilityBoundingSet=CAP_KILL CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
+CapabilityBoundingSet=CAP_KILL CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW 
CAP_SETGID CAP_SETUID
 ProtectHome=read-only
 ProtectSystem=full
 
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index 9919928b..a051cc75 100644
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -33,6 +33,9 @@
 #include <sys/types.h>
 #include <linux/if_tun.h>
 #include <net/if.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <dbus/dbus.h>
 
@@ -47,6 +50,7 @@
 #include "../vpn-provider.h"
 
 #include "vpn.h"
+#include "../vpn.h"
 
 struct vpn_data {
        struct vpn_provider *provider;
@@ -415,12 +419,134 @@ exist_err:
        return ret;
 }
 
+static gboolean is_numeric(const char *str)
+{
+       gint i;
+
+       if(!str || !(*str))
+               return false;
+
+       for(i = 0; str[i] ; i++) {
+               if(!g_ascii_isdigit(str[i]))
+                       return false;
+       }
+
+       return true;
+}
+
+static gint get_gid(const char *group_name)
+{
+       gint gid = -1;
+       struct group *grp;
+
+       if(!group_name || !(*group_name))
+               return gid;
+
+       if (is_numeric(group_name)) {
+               gid_t group_id = (gid_t)g_ascii_strtoull(group_name, NULL, 10);
+               grp = getgrgid(group_id);
+       } else {
+               grp = getgrnam(group_name);
+       }
+
+       if (grp)
+               gid = grp->gr_gid;
+
+       return gid;
+}
+
+static gint get_uid(const char *user_name)
+{
+       gint uid = -1;
+       struct passwd *pw;
+
+       if(!user_name || !(*user_name))
+               return uid;
+
+       if (is_numeric(user_name)) {
+               uid_t user_id = (uid_t)g_ascii_strtoull(user_name, NULL, 10);
+               pw = getpwuid(user_id);
+       } else {
+               pw = getpwnam(user_name);
+       }
+
+       if (pw)
+               uid = pw->pw_uid;
+
+       return uid;
+}
+
+static gint get_supplementary_gids(gchar **groups, gid_t **gid_list)
+{
+       gint group_count = 0;
+       gid_t *list = NULL;
+       int i;
+
+       if (groups) {
+               for(i = 0; groups[i]; i++) {
+                       group_count++;
+
+                       list = (gid_t*)g_try_realloc(list,
+                                               sizeof(gid_t) * group_count);
+
+                       if (!list) {
+                               DBG("cannot allocate supplementary group list");
+                               break;
+                       }
+
+                       list[i] = get_gid(groups[i]);
+               }
+       }
+
+       *gid_list = list;
+
+       return group_count;
+}
+
+static void vpn_task_setup(gpointer user_data)
+{
+       struct vpn_plugin_data *data;
+       gint uid;
+       gint gid;
+       gid_t *gid_list = NULL;
+       size_t gid_list_size;
+       const gchar *user;
+       const gchar *group;
+       gchar **suppl_groups;
+
+       data = user_data;
+       user = vpn_settings_get_binary_user(data);
+       group = vpn_settings_get_binary_group(data);
+       suppl_groups = vpn_settings_get_binary_supplementary_groups(data);
+
+       uid = get_uid(user);
+       gid = get_gid(group);
+       gid_list_size = get_supplementary_gids(suppl_groups, &gid_list);
+
+       DBG("vpn_task_setup uid:%d gid:%d supplementary group list size:%lu",
+                                       uid, gid, gid_list_size);
+
+
+       /* Change group if proper group name was set, requires CAP_SETGID.*/
+       if (gid > 0 && setgid(gid))
+               connman_error("error setting gid %d %s", gid, strerror(errno));
+
+       /* Set the supplementary groups if list exists, requires CAP_SETGID. */
+       if (gid_list_size && gid_list && setgroups(gid_list_size, gid_list))
+               connman_error("error setting gid list %s", strerror(errno));
+
+       /* Change user for the task if set, requires CAP_SETUID */
+       if (uid > 0 && setuid(uid))
+               connman_error("error setting uid %d %s", uid, strerror(errno));
+}
+
 static int vpn_connect(struct vpn_provider *provider,
                        vpn_provider_connect_cb_t cb,
                        const char *dbus_sender, void *user_data)
 {
        struct vpn_data *data = vpn_provider_get_data(provider);
        struct vpn_driver_data *vpn_driver_data;
+       struct vpn_plugin_data *vpn_plugin_data;
        const char *name;
        int ret = 0, tun_flags = IFF_TUN;
        enum vpn_state state = VPN_STATE_UNKNOWN;
@@ -478,7 +604,11 @@ static int vpn_connect(struct vpn_provider *provider,
                        goto exist_err;
        }
 
-       data->task = connman_task_create(vpn_driver_data->program, NULL);
+       vpn_plugin_data = vpn_settings_get_vpn_plugin_config(
+                                               vpn_driver_data->name);
+
+       data->task = connman_task_create(vpn_driver_data->program,
+                                       vpn_task_setup, vpn_plugin_data);
 
        if (!data->task) {
                ret = -ENOMEM;
@@ -650,6 +780,9 @@ int vpn_register(const char *name, struct vpn_driver 
*vpn_driver,
        data->name = name;
        data->program = program;
 
+       if (vpn_settings_parse_vpn_plugin_config(data->name) != 0)
+               DBG("No configuration provided for VPN plugin %s", data->name);
+
        data->vpn_driver = vpn_driver;
 
        data->provider_driver.name = name;
@@ -688,6 +821,7 @@ void vpn_unregister(const char *name)
                return;
 
        vpn_provider_driver_unregister(&data->provider_driver);
+       vpn_settings_delete_vpn_plugin_config(name);
 
        g_hash_table_remove(driver_hash, name);
 
-- 
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 4
**************************************

Reply via email to