[network-manager-openvpn/jk/openvpn-unprivilege-user] service: allow running openvpn as an unprivilege user (bgo #555518)



commit bb8c1787d96d9a27f92e80009a3f7e9f5f282cc0
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.c |   91 ++++++++++++++++++++++++++++++++++++++++++++++
 src/nm-openvpn-service.h |    5 +++
 2 files changed, 96 insertions(+), 0 deletions(-)
---
diff --git a/src/nm-openvpn-service.c b/src/nm-openvpn-service.c
index 4912082..b36c8eb 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>
@@ -867,6 +869,62 @@ update_io_data_from_vpn_setting (NMOpenvpnPluginIOData *io_data,
 }
 
 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 & 0002)
+               return TRUE;
+       else if (sb.st_mode & 0020) {
+               /* Group has write access. Is user in that group? */
+               int i, ngroups;
+               gid_t groups[64];
+
+               getgrouplist(user, pw->pw_gid, groups, &ngroups);
+               for (i = 0; i < ngroups; i++) {
+                       if (groups[i] == sb.st_gid)
+                               return TRUE;
+               }
+       } else if (sb.st_mode & 0200) {
+               /* 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,
                                  const char *default_username,
@@ -881,6 +939,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 ();
@@ -1268,6 +1327,38 @@ 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 (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 (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 (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) {
diff --git a/src/nm-openvpn-service.h b/src/nm-openvpn-service.h
index 5493cf5..51e00a7 100644
--- a/src/nm-openvpn-service.h
+++ b/src/nm-openvpn-service.h
@@ -100,6 +100,11 @@
 #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";
+
 typedef struct {
        NMVPNPlugin parent;
 } NMOpenvpnPlugin;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]