This commit adds support for configurable user, group and supplementary
groups for VPNs. Common configuration is loaded from the main VPN config
file CONFIGDIR/connman-vpn.conf, which applies to all VPNs. This commit
also adds support for VPN specific configuration in
CONFIGDIR/vpn-plugin/ based on the plugin name + .conf suffix.
Both configs follow the name format:
- 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:
[VPNBinary]
User = username
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.
---
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..f37d1f61 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 "VPNBinary"
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