Send connman mailing list submissions to
[email protected]
To subscribe or unsubscribe 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 1/5] vpn-util: Create utility file for VPN core and plugins
(Jussi Laakkonen)
2. [PATCH 0/5] Add VPN utility functions and system user list to
DACPrivileges
(Jussi Laakkonen)
3. [PATCH 2/5] vpn: Add CAP_CHOWN CAP_FOWNER capabilities for path creation
(Jussi Laakkonen)
4. [PATCH 3/5] vpn-settings: Add SystemBinaryUsers conf option and system
user check
(Jussi Laakkonen)
5. [PATCH 4/5] vpnc: Support setting the pid file path to /var/run/user
(Jussi Laakkonen)
6. [PATCH 5/5] vpn: Use util functions for getting uid and gid
(Jussi Laakkonen)
----------------------------------------------------------------------
Date: Tue, 20 Oct 2020 17:29:34 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 1/5] vpn-util: Create utility file for VPN core and
plugins
To: [email protected]
Message-ID: <[email protected]>
Create vpn-util.c for VPN core and plugins to use. This is a first step
in establishing some sort of lib for them.
Add functionality to get the user struct passwd and struct group using
the username and groupname:
- vpn_util_get_passwd()
- vpn_util_get_group()
Add function vpn_util_create_path() to create dir for a VPN plugin.
The dirname is extracted with g_path_get_dirname() and it must have a
prefix of "/var/run/connman-vpn/", "/var/run/user/" or "/tmp/" and must
not contain ".." or "./". One directory element must be provided after
the prefix, e.g. "/tmp/dir/". If the basename path is an existing dir
permissions and ownership is changed according to the request ones,
otherwise the file is removed and then created, as if it never existed.
g_unlink() is used to handle safe removals of symlink, which also enables
detection of parent dir write permissions - error is returned unless the
dir exists, in which case ownership and permissions are attempted to be
set accordingly.
---
Makefile.am | 2 +-
vpn/vpn-util.c | 213 +++++++++++++++++++++++++++++++++++++++++++++++++
vpn/vpn.h | 5 ++
3 files changed, 219 insertions(+), 1 deletion(-)
create mode 100644 vpn/vpn-util.c
diff --git a/Makefile.am b/Makefile.am
index 5971ca9b..8b4b4996 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -181,7 +181,7 @@ vpn_connman_vpnd_SOURCES = $(builtin_vpn_sources)
$(backtrace_sources) \
vpn/vpn-ipconfig.c src/inet.c vpn/vpn-rtnl.c \
src/dbus.c src/storage.c src/ipaddress.c src/agent.c \
vpn/vpn-agent.c vpn/vpn-agent.h src/inotify.c \
- vpn/vpn-config.c vpn/vpn-settings.c
+ vpn/vpn-config.c vpn/vpn-settings.c vpn/vpn-util.c
vpn_connman_vpnd_LDADD = gdbus/libgdbus-internal.la $(builtin_vpn_libadd) \
@GLIB_LIBS@ @DBUS_LIBS@ @GNUTLS_LIBS@ \
diff --git a/vpn/vpn-util.c b/vpn/vpn-util.c
new file mode 100644
index 00000000..72b24f43
--- /dev/null
+++ b/vpn/vpn-util.c
@@ -0,0 +1,213 @@
+/*
+ * ConnMan VPN daemon utils
+ *
+ * Copyright (C) 2020 Jolla Ltd. All rights reserved.
+ * Copyright (C) 2020 Open Mobile Platform LLC.
+ * Contact: [email protected]
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <unistd.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+
+#include <glib/gstdio.h>
+
+#include <connman/log.h>
+
+#include "vpn.h"
+
+static bool is_string_digits(const char *str)
+{
+ int i;
+
+ if (!str || !*str)
+ return false;
+
+ for (i = 0; str[i]; i++) {
+ if (!g_ascii_isdigit(str[i]))
+ return false;
+ }
+
+ return true;
+}
+
+static uid_t get_str_id(const char *username)
+{
+ if (!username || !*username)
+ return 0;
+
+ return (uid_t)g_ascii_strtoull(username, NULL, 10);
+}
+
+struct passwd *vpn_util_get_passwd(const char *username)
+{
+ struct passwd *pwd;
+ uid_t uid;
+
+ if (!username || !*username)
+ return NULL;
+
+ if (is_string_digits(username)) {
+ uid = get_str_id(username);
+ pwd = getpwuid(uid);
+ } else {
+ pwd = getpwnam(username);
+ }
+
+ return pwd;
+}
+
+struct group *vpn_util_get_group(const char *groupname)
+{
+ struct group *grp;
+ gid_t gid;
+
+ if (!groupname || !*groupname)
+ return NULL;
+
+ if (is_string_digits(groupname)) {
+ gid = get_str_id(groupname);
+ grp = getgrgid(gid);
+ } else {
+ grp = getgrnam(groupname);
+ }
+
+ return grp;
+}
+
+static const char *allowed_prefixes[] = { "/var/run/connman-vpn/",
+ "/var/run/user/", "/tmp/", NULL };
+
+static int is_path_allowed(const char *path)
+{
+ int err = -EPERM;
+ int i;
+
+ if (!path || !*path || !g_path_is_absolute(path))
+ return -EINVAL;
+
+ if (g_strrstr(path, "..") || g_strrstr(path, "./"))
+ return -EPERM;
+
+ for (i = 0; allowed_prefixes[i]; i++) {
+ if (g_str_has_prefix(path, allowed_prefixes[i])) {
+ const char *suffix = path +
+ strlen(allowed_prefixes[i]);
+
+ /*
+ * Don't allow plain prefixes, an additional dir must
+ * be included after the prexix in the requested path.
+ */
+ if (suffix && *suffix != G_DIR_SEPARATOR &&
+ g_strrstr(suffix,
+ G_DIR_SEPARATOR_S)) {
+ DBG("allowed %s, has suffix %s", path, suffix);
+ err = 0;
+ }
+
+ break;
+ }
+ }
+
+ return err;
+}
+
+int vpn_util_create_path(const char *path, uid_t uid, gid_t grp, int mode)
+{
+ mode_t old_umask;
+ char *dir_p;
+ int err;
+
+ err = is_path_allowed(path);
+ if (err)
+ return err;
+
+ dir_p = g_path_get_dirname(path);
+ if (!dir_p)
+ return -ENOMEM;
+
+ err = g_unlink(dir_p);
+ if (err)
+ err = -errno;
+
+ switch (err) {
+ case 0:
+ /* Removed */
+ case -ENOENT:
+ /* Did not exist */
+ break;
+ case -EACCES:
+ /*
+ * Cannot get write access to the containing directory, check
+ * if the path exists.
+ */
+ if (!g_file_test(dir_p, G_FILE_TEST_EXISTS))
+ goto out;
+
+ /* If the dir does not exist new one cannot be created */
+ if (!g_file_test(dir_p, G_FILE_TEST_IS_DIR))
+ goto out;
+
+ /* Fall through to chmod as the dir exists */
+ case -EISDIR:
+ /* Exists as dir, just chmod and change owner */
+ err = g_chmod(dir_p, mode);
+ if (err) {
+ connman_warn("chmod %s failed, err %d", dir_p, err);
+ err = -errno;
+ }
+
+ goto chown;
+ default:
+ /* Any other error that is not handled here */
+ connman_warn("remove %s failed, err %d", dir_p, err);
+ goto out;
+ }
+
+ /* Set dir creation mask to correspond to the mode */
+ old_umask = umask(~mode & 0777);
+
+ DBG("mkdir %s", dir_p);
+ err = g_mkdir_with_parents(dir_p, mode);
+
+ umask(old_umask);
+
+ if (err) {
+ connman_warn("mkdir %s failed, err %d", dir_p, err);
+ err = -errno;
+ goto out;
+ }
+
+chown:
+ if (uid && grp) {
+ err = chown(dir_p, uid, grp);
+ if (err) {
+ err = -errno;
+ connman_warn("chown %s failed for %d/%d, err %d",
+ dir_p, uid, grp, err);
+ }
+ }
+
+out:
+ g_free(dir_p);
+
+ return err;
+}
+
diff --git a/vpn/vpn.h b/vpn/vpn.h
index 3356d53e..8d7c63d6 100644
--- a/vpn/vpn.h
+++ b/vpn/vpn.h
@@ -131,3 +131,8 @@ 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);
+bool vpn_settings_is_system_user(const char *user);
+
+struct passwd *vpn_util_get_passwd(const char *username);
+struct group *vpn_util_get_group(const char *groupname);
+int vpn_util_create_path(const char *path, uid_t uid, gid_t grp, int mode);
--
2.20.1
------------------------------
Date: Tue, 20 Oct 2020 17:29:33 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 0/5] Add VPN utility functions and system user list to
DACPrivileges
To: [email protected]
Message-ID: <[email protected]>
Add vpn-util.c for utility functions for VPN core and plugins to use.
Implemented:
- vpn_util_get_passwd() to get struct passwd using user/uid as string
- vpn_util_get_group() to get struct group using group/gid as string
- vpn_util_create_path() to create the path for the requested file, and to
set the ownership and permissions thus, requiring additional capabilities
With the help of vpn_util_create_path() VPNC now can set the pid file to a
location where the running user can create it. Also, replaced some code in
vpn.c in favor of using vpn-util.c functions.
Added "SystemBinaryUsers" string list to DACPrivileges group for vpnd main
config only. This, with the help of the added vpn_settings_is_system_user(),
a plugin, for example, can check if the user set to run the VPN binary is root
or other pre-defined system user to determine appropriate action, like it is
the case with VPNC.
Jussi Laakkonen (5):
vpn-util: Create utility file for VPN core and plugins
vpn: Add CAP_CHOWN CAP_FOWNER capabilities for path creation
vpn-settings: Add SystemBinaryUsers conf option and system user check
vpnc: Support setting the pid file path to /var/run/user
vpn: Use util functions for getting uid and gid
Makefile.am | 2 +-
vpn/connman-vpn.service.in | 2 +-
vpn/plugins/vpn.c | 55 ++--------
vpn/plugins/vpnc.c | 54 ++++++++++
vpn/vpn-settings.c | 63 ++++++++++-
vpn/vpn-util.c | 213 +++++++++++++++++++++++++++++++++++++
vpn/vpn.h | 5 +
7 files changed, 346 insertions(+), 48 deletions(-)
create mode 100644 vpn/vpn-util.c
--
2.20.1
------------------------------
Date: Tue, 20 Oct 2020 17:29:35 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 2/5] vpn: Add CAP_CHOWN CAP_FOWNER capabilities for
path creation
To: [email protected]
Message-ID: <[email protected]>
vpnd needs these permissions because of vpn-util.c needs to change the
owner/group and permissions for the created/existing dir.
---
vpn/connman-vpn.service.in | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/vpn/connman-vpn.service.in b/vpn/connman-vpn.service.in
index dd15bab4..3bb52e12 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
CAP_SETGID CAP_SETUID
+CapabilityBoundingSet=CAP_KILL CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
CAP_SETGID CAP_SETUID CAP_CHOWN CAP_FOWNER
ProtectHome=read-only
ProtectSystem=full
--
2.20.1
------------------------------
Date: Tue, 20 Oct 2020 17:29:36 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 3/5] vpn-settings: Add SystemBinaryUsers conf option
and system user check
To: [email protected]
Message-ID: <[email protected]>
Add "SystemBinaryUsers" user list to vpnd main config only to allow
defining which users should be regarded as system wide "privileged"
users. The user list is read as a string list from DACPrivileges group.
Add function for checking if the user is a system user, either root,
effective uid of the process or one in the "SystemBinaryUsers":
vpn_settings_is_system_user(). This function can be used by VPN plugins
to check if the user set to run the VPN binary is a regular or system
user since different behavior can be expected for run-time file
creation.
---
vpn/vpn-settings.c | 63 +++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/vpn/vpn-settings.c b/vpn/vpn-settings.c
index 0eca2bc8..e78e5019 100644
--- a/vpn/vpn-settings.c
+++ b/vpn/vpn-settings.c
@@ -2,7 +2,7 @@
* ConnMan VPN daemon settings
*
* Copyright (C) 2012-2013 Intel Corporation. All rights reserved.
- * Copyright (C) 2018-2019 Jolla Ltd. All rights reserved.
+ * Copyright (C) 2018-2020 Jolla Ltd. All rights reserved.
* Contact: [email protected]
*
* This program is free software; you can redistribute it and/or modify
@@ -23,6 +23,9 @@
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include <pwd.h>
+#include <unistd.h>
+#include <sys/types.h>
#include <connman/log.h>
@@ -37,11 +40,13 @@ static struct {
char *binary_user;
char *binary_group;
char **binary_supplementary_groups;
+ char **system_binary_users;
} connman_vpn_settings = {
.timeout_inputreq = DEFAULT_INPUT_REQUEST_TIMEOUT,
.binary_user = NULL,
.binary_group = NULL,
.binary_supplementary_groups = NULL,
+ .system_binary_users = NULL,
};
struct vpn_plugin_data {
@@ -52,6 +57,58 @@ struct vpn_plugin_data {
GHashTable *plugin_hash = NULL;
+bool vpn_settings_is_system_user(const char *user)
+{
+ struct passwd *pwd;
+ struct passwd *system_pwd;
+ int i;
+
+ /*
+ * The username is not set = override should not be used. This is the
+ * case after the override is reset.
+ */
+ if (!user)
+ return true;
+
+ DBG("check user \"%s\"", user);
+
+ /*
+ * Ignore errors if no entry was found. Treat as system user to
+ * prevent using an invalid override.
+ */
+ pwd = vpn_util_get_passwd(user);
+ if (!pwd)
+ return true;
+
+ if (!connman_vpn_settings.system_binary_users) {
+ DBG("no binary users set");
+
+ /*
+ * Check if the user is root, or the uid equals to process
+ * effective uid.
+ */
+ return !pwd->pw_uid || pwd->pw_uid == geteuid();
+ }
+
+ /* Root set as user or the effective user id */
+ if (!pwd->pw_uid || pwd->pw_uid == geteuid())
+ return true;
+
+ for (i = 0; connman_vpn_settings.system_binary_users[i]; i++) {
+ const char *system_user =
+ connman_vpn_settings.system_binary_users[i];
+
+ system_pwd = vpn_util_get_passwd(system_user);
+ if (!system_pwd)
+ continue;
+
+ if (pwd->pw_uid == system_pwd->pw_uid)
+ return true;
+ }
+
+ return false;
+}
+
const char *vpn_settings_get_binary_user(struct vpn_plugin_data *data)
{
if (data && data->binary_user)
@@ -129,6 +186,9 @@ static void parse_config(GKeyFile *config, const char *file)
connman_vpn_settings.binary_supplementary_groups = get_string_list(
config, VPN_GROUP,
"SupplementaryGroups");
+ connman_vpn_settings.system_binary_users = get_string_list(
+ config, VPN_GROUP,
+ "SystemBinaryUsers");
}
struct vpn_plugin_data *vpn_settings_get_vpn_plugin_config(const char *name)
@@ -245,6 +305,7 @@ void __vpn_settings_cleanup()
g_free(connman_vpn_settings.binary_user);
g_free(connman_vpn_settings.binary_group);
g_strfreev(connman_vpn_settings.binary_supplementary_groups);
+ g_strfreev(connman_vpn_settings.system_binary_users);
if (plugin_hash) {
g_hash_table_destroy(plugin_hash);
--
2.20.1
------------------------------
Date: Tue, 20 Oct 2020 17:29:37 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 4/5] vpnc: Support setting the pid file path to
/var/run/user
To: [email protected]
Message-ID: <[email protected]>
Use the new util and settings functions to get the user that is used to
run the VPNC plugin in order to set a correct pid file path. If system
user is used utilize the default path.
Path prefix is set to /var/run/user, and suffix vpnc/pid is added as
well. With user 1000 this results to pid file path of
/var/run/user/1000/vpnc/pid.
---
vpn/plugins/vpnc.c | 54 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 54 insertions(+)
diff --git a/vpn/plugins/vpnc.c b/vpn/plugins/vpnc.c
index 8350fc3c..db4b5c04 100644
--- a/vpn/plugins/vpnc.c
+++ b/vpn/plugins/vpnc.c
@@ -30,6 +30,10 @@
#include <stdio.h>
#include <net/if.h>
#include <linux/if_tun.h>
+#include <sys/types.h>
+#include <pwd.h>
+#include <grp.h>
+#include <fcntl.h>
#include <glib.h>
@@ -50,6 +54,7 @@
#include "../vpn.h"
#define ARRAY_SIZE(a) (sizeof(a)/sizeof(a[0]))
+#define PID_PATH_ROOT "/var/run/user"
enum {
OPT_STRING = 1,
@@ -430,14 +435,49 @@ static gboolean io_channel_cb(GIOChannel *source,
GIOCondition condition,
return G_SOURCE_CONTINUE;
}
+static char *create_pid_path(const char *user, const char *group)
+{
+ struct passwd *pwd;
+ struct group *grp;
+ char *uid_str;
+ char *pid_path = NULL;
+ int mode = S_IRWXU|S_IRWXG;
+ gid_t gid;
+
+ if (!user || !*user)
+ return NULL;
+
+ if (vpn_settings_is_system_user(user))
+ return NULL;
+
+ pwd = vpn_util_get_passwd(user);
+ uid_str = g_strdup_printf("%d", pwd->pw_uid);
+
+ grp = vpn_util_get_group(group);
+ gid = grp ? grp->gr_gid : pwd->pw_gid;
+
+ pid_path = g_build_filename(PID_PATH_ROOT, uid_str, "vpnc", "pid",
+ NULL);
+ if (vpn_util_create_path(pid_path, pwd->pw_uid, gid, mode)) {
+ g_free(pid_path);
+ pid_path = NULL;
+ }
+
+ g_free(uid_str);
+
+ return pid_path;
+}
+
static int run_connect(struct vc_private_data *data)
{
struct vpn_provider *provider;
struct connman_task *task;
+ struct vpn_plugin_data *plugin_data;
const char *credentials[] = {"VPNC.IPSec.Secret", "VPNC.Xauth.Username",
"VPNC.Xauth.Password", NULL};
const char *if_name;
const char *option;
+ char *pid_path;
int err;
int fd_in;
int fd_err;
@@ -473,6 +513,20 @@ static int run_connect(struct vc_private_data *data)
connman_task_add_argument(task, "--ifmode", "tun");
}
+ plugin_data = vpn_settings_get_vpn_plugin_config("vpnc");
+
+ option = vpn_settings_get_binary_user(plugin_data);
+ if (option) {
+ pid_path = create_pid_path(option,
+ vpn_settings_get_binary_group(
+ plugin_data));
+ if (pid_path)
+ connman_task_add_argument(task, "--pid-file",
+ pid_path);
+
+ g_free(pid_path);
+ }
+
connman_task_add_argument(task, "--script", SCRIPTDIR "/vpn-script");
option = vpn_provider_get_string(provider, "VPNC.Debug");
--
2.20.1
------------------------------
Date: Tue, 20 Oct 2020 17:29:38 +0300
From: Jussi Laakkonen <[email protected]>
Subject: [PATCH 5/5] vpn: Use util functions for getting uid and gid
To: [email protected]
Message-ID: <[email protected]>
Change to use vpn-util.c functions for getting struct passwd and struct
group using the username/uid as string. Change gint to respective uid_t
and gid_t.
---
vpn/plugins/vpn.c | 55 +++++++++--------------------------------------
1 file changed, 10 insertions(+), 45 deletions(-)
diff --git a/vpn/plugins/vpn.c b/vpn/plugins/vpn.c
index 67e7b30b..cb0d304b 100644
--- a/vpn/plugins/vpn.c
+++ b/vpn/plugins/vpn.c
@@ -421,61 +421,26 @@ exist_err:
return ret;
}
-static gboolean is_numeric(const char *str)
+static gid_t get_gid(const char *group_name)
{
- 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);
- }
-
+ grp = vpn_util_get_group(group_name);
if (grp)
- gid = grp->gr_gid;
+ return grp->gr_gid;
- return gid;
+ return -1;
}
-static gint get_uid(const char *user_name)
+static uid_t 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);
- }
-
+ pw = vpn_util_get_passwd(user_name);
if (pw)
- uid = pw->pw_uid;
+ return pw->pw_uid;
- return uid;
+ return -1;
}
static gint get_supplementary_gids(gchar **groups, gid_t **gid_list)
@@ -508,8 +473,8 @@ static gint get_supplementary_gids(gchar **groups, gid_t
**gid_list)
static void vpn_task_setup(gpointer user_data)
{
struct vpn_plugin_data *data;
- gint uid;
- gint gid;
+ uid_t uid;
+ gid_t gid;
gid_t *gid_list = NULL;
size_t gid_list_size;
const gchar *user;
--
2.20.1
------------------------------
Subject: Digest Footer
_______________________________________________
connman mailing list -- [email protected]
To unsubscribe send an email to [email protected]
------------------------------
End of connman Digest, Vol 60, Issue 19
***************************************