[network-manager-openvpn/jk/openvpn-unprivilege-user] service: allow running openvpn as an unprivilege user (bgo #555518)
- From: Jiří Klimeš <jklimes src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [network-manager-openvpn/jk/openvpn-unprivilege-user] service: allow running openvpn as an unprivilege user (bgo #555518)
- Date: Tue, 9 Jun 2015 07:24:49 +0000 (UTC)
commit b44c6ed02bbdb873aa823d7da420a9bf3aee6747
Author: Jiří Klimeš <jklimes redhat com>
Date: Wed Feb 25 14:02:40 2015 +0100
service: allow running openvpn as an unprivilege user (bgo #555518)
The patch uses --user, --group and --chroot command line parameteres
to do that.
spec change for RPM:
(http://fedoraproject.org/wiki/Packaging:UsersAndGroups)
Requires(pre): shadow-utils
[...]
%pre
getent group nm-openvpn >/dev/null || groupadd -r nm-openvpn
getent passwd nm-openvpn >/dev/null || \
useradd -r -g nm-openvpn -d / -s /sbin/nologin \
-c "Default user for running openvpn spawned by NetworkManager" nm-openvpn
exit 0
https://bugzilla.gnome.org/show_bug.cgi?id=555518
https://bugzilla.redhat.com/show_bug.cgi?id=1195057
src/nm-openvpn-service-defines.h | 5 ++
src/nm-openvpn-service.c | 98 ++++++++++++++++++++++++++++++++++++++
2 files changed, 103 insertions(+), 0 deletions(-)
---
diff --git a/src/nm-openvpn-service-defines.h b/src/nm-openvpn-service-defines.h
index 7c61218..b32775d 100644
--- a/src/nm-openvpn-service-defines.h
+++ b/src/nm-openvpn-service-defines.h
@@ -90,4 +90,9 @@
#define NM_OPENVPN_REM_CERT_TLS_CLIENT "client"
#define NM_OPENVPN_REM_CERT_TLS_SERVER "server"
+/* User name and group to run nm-openvpn-service under */
+#define NM_OPENVPN_USER "nm-openvpn"
+#define NM_OPENVPN_GROUP "nm-openvpn"
+#define NM_OPENVPN_CHROOT "/var/lib/openvpn/chroot"
+
#endif /* NM_OPENVPN_SERVICE_DEFINES_H */
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index 918490f..0e03cee 100644
--- a/src/nm-openvpn-service.c
+++ b/src/nm-openvpn-service.c
@@ -47,6 +47,8 @@
#include <ctype.h>
#include <errno.h>
#include <locale.h>
+#include <pwd.h>
+#include <grp.h>
#include <NetworkManager.h>
#include <NetworkManagerVPN.h>
@@ -875,6 +877,63 @@ update_io_data_from_vpn_setting (NMOpenvpnPluginIOData *io_data,
io_data->proxy_password = tmp ? g_strdup (tmp) : NULL;
}
+#define MAX_GROUPS 128
+static gboolean
+is_dir_writable (const char *dir, const char *user)
+{
+ struct stat sb;
+ struct passwd *pw;
+
+ if (stat (dir, &sb) == -1)
+ return FALSE;
+ pw = getpwnam (user);
+ if (!pw)
+ return FALSE;
+
+ if (pw->pw_uid == 0)
+ return TRUE;
+
+ if (sb.st_mode & S_IWOTH)
+ return TRUE;
+ else if (sb.st_mode & S_IWGRP) {
+ /* Group has write access. Is user in that group? */
+ int i, ngroups = MAX_GROUPS;
+ gid_t groups[MAX_GROUPS];
+
+ getgrouplist (user, pw->pw_gid, groups, &ngroups);
+ for (i = 0; i < ngroups && i < MAX_GROUPS; i++) {
+ if (groups[i] == sb.st_gid)
+ return TRUE;
+ }
+ } else if (sb.st_mode & S_IWUSR) {
+ /* The owner has write access. Does the user own the file? */
+ if (pw->pw_uid == sb.st_uid)
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/* Check existence of 'tmp' directory inside @chdir
+ * and write access in @chdir and @chdir/tmp for @user.
+ */
+static gboolean
+check_chroot_dir_usability (const char *chdir, const char *user)
+{
+ char *tmp_dir;
+ gboolean b1, b2;
+
+ tmp_dir = g_strdup_printf ("%s/tmp", chdir);
+ if (!g_file_test (tmp_dir, G_FILE_TEST_IS_DIR)) {
+ g_free (tmp_dir);
+ return FALSE;
+ }
+
+ b1 = is_dir_writable (chdir, user);
+ b2 = is_dir_writable (tmp_dir, user);
+ g_free (tmp_dir);
+ return b1 && b2;
+}
+
static gboolean
nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
NMSettingVPN *s_vpn,
@@ -890,6 +949,7 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
gboolean dev_type_is_tap;
char *stmp;
const char *defport, *proto_tcp;
+ const char *nm_openvpn_user, *nm_openvpn_group, *nm_openvpn_chroot;
/* Find openvpn */
openvpn_binary = nm_find_openvpn ();
@@ -1291,6 +1351,44 @@ nm_openvpn_start_openvpn_binary (NMOpenvpnPlugin *plugin,
return FALSE;
}
+ /* Allow openvpn to be run as a specified user:group and drop privileges. */
+ nm_openvpn_user = getenv ("NM_OPENVPN_USER");
+ nm_openvpn_group = getenv ("NM_OPENVPN_GROUP");
+ nm_openvpn_chroot = getenv ("NM_OPENVPN_CHROOT");
+ if (!nm_openvpn_user)
+ nm_openvpn_user = NM_OPENVPN_USER;
+ if (!nm_openvpn_group)
+ nm_openvpn_group = NM_OPENVPN_GROUP;
+ if (!nm_openvpn_chroot)
+ nm_openvpn_chroot = NM_OPENVPN_CHROOT;
+
+ if (*nm_openvpn_user) {
+ if (getpwnam (nm_openvpn_user)) {
+ add_openvpn_arg (args, "--user");
+ add_openvpn_arg (args, nm_openvpn_user);
+ } else {
+ g_warning ("User '%s' not found, openvpn will use 'root'.",
+ nm_openvpn_user);
+ nm_openvpn_user = "root";
+ }
+ }
+ if (*nm_openvpn_group) {
+ if (getgrnam (nm_openvpn_group)) {
+ add_openvpn_arg (args, "--group");
+ add_openvpn_arg (args, nm_openvpn_group);
+ } else
+ g_warning ("Group '%s' not found, openvpn will use 'root'.",
+ nm_openvpn_group);
+ }
+ if (*nm_openvpn_chroot) {
+ if (check_chroot_dir_usability (nm_openvpn_chroot, nm_openvpn_user)) {
+ add_openvpn_arg (args, "--chroot");
+ add_openvpn_arg (args, nm_openvpn_chroot);
+ } else
+ g_warning ("Directory '%s' not usable for chroot by '%s', openvpn will not be
chrooted.",
+ nm_openvpn_chroot, nm_openvpn_user);
+ }
+
g_ptr_array_add (args, NULL);
if (debug) {
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]