]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Allow OpenVPN to run completely unprivileged under Linux
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 21 Jan 2008 19:34:13 +0000 (19:34 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Mon, 21 Jan 2008 19:34:13 +0000 (19:34 +0000)
by allowing openvpn --mktun to be used with --user and --group
to set the UID/GID of the tun device node.  Also added --iproute
option to allow an alternative command to be executed in place
of the default iproute2 command (Alon Bar-Lev).

git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@2639 e7ae566f-a301-0410-adde-c780ea21d3b5

init.c
lladdr.c
misc.c
misc.h
openvpn.8
options.c
route.c
tun.c
tun.h

diff --git a/init.c b/init.c
index 211effdfebcc77bbfc777e386e19e53b1b037ad2..0651c2dd8673f2f366db7f506eb074753dc78071 100644 (file)
--- a/init.c
+++ b/init.c
@@ -426,7 +426,7 @@ do_persist_tuntap (const struct options *options)
             "options --mktun or --rmtun should only be used together with --dev");
       tuncfg (options->dev, options->dev_type, options->dev_node,
              options->tun_ipv6, options->persist_mode,
-             &options->tuntap_options);
+             options->username, options->groupname, &options->tuntap_options);
       if (options->persist_mode && options->lladdr)
         set_lladdr(options->dev, options->lladdr, NULL);
       return true;
index 1f02ba4f2b37c5cd48c9dca92b0a084aa95c2970..1daa37992b5f793bc979cf7185993265158432b7 100644 (file)
--- a/lladdr.c
+++ b/lladdr.c
@@ -24,8 +24,8 @@ int set_lladdr(const char *ifname, const char *lladdr,
 #if defined(TARGET_LINUX)
 #ifdef CONFIG_FEATURE_IPROUTE
   openvpn_snprintf (cmd, sizeof (cmd),
-                   IPROUTE_PATH " link set addr %s dev %s",
-                   lladdr, ifname);
+                   "%s link set addr %s dev %s",
+                   iproute_path, lladdr, ifname);
 #else
   openvpn_snprintf (cmd, sizeof (cmd),
                    IFCONFIG_PATH " %s hw ether %s",
diff --git a/misc.c b/misc.c
index 432971178741926f70ca198c73a863ac32cafd90..2821408a4433933af86b727f508bf57809436b1d 100644 (file)
--- a/misc.c
+++ b/misc.c
 
 #include "memdbg.h"
 
+#ifdef CONFIG_FEATURE_IPROUTE
+const char *iproute_path = IPROUTE_PATH;
+#endif
+
 /* Redefine the top level directory of the filesystem
    to restrict access to files for security */
 void
diff --git a/misc.h b/misc.h
index 09124e60ba329fd8fc95fd38d4fded407061e15a..5b7f227cb029e9e82aa91186311ca62fc72650fe 100644 (file)
--- a/misc.h
+++ b/misc.h
@@ -269,4 +269,11 @@ void configure_path (void);
 void get_user_pass_auto_userid (struct user_pass *up, const char *tag);
 #endif
 
+/*
+ * /sbin/ip path, may be overridden
+ */
+#ifdef CONFIG_FEATURE_IPROUTE
+extern const char *iproute_path;
+#endif
+
 #endif
index 6446c5b317db4945e99af9f990ec3febd72df119..df276e7d8a82ce0fe5235ee85e5408fcc819afab 100644 (file)
--- a/openvpn.8
+++ b/openvpn.8
@@ -71,6 +71,8 @@ openvpn \- secure IP tunnel daemon.
 [\ \fB\-\-dev\-type\fR\ \fIdevice\-type\fR\ ]
 [\ \fB\-\-dev\-node\fR\ \fInode\fR\ ]
 [\ \fB\-\-lladdr\fR\ \fIaddress\fR\ ]
+[\ \fB\-\-user\fR\ \fIuser\fR\ ]
+[\ \fB\-\-group\fR\ \fIgroup\fR\ ]
 .in -4
 .ti +4
 .hy
@@ -164,6 +166,7 @@ openvpn \- secure IP tunnel daemon.
 [\ \fB\-\-inetd\fR\ \fI[wait|nowait]\ [progname]\fR\ ]
 [\ \fB\-\-ip\-win32\fR\ \fImethod\fR\ ]
 [\ \fB\-\-ipchange\fR\ \fIcmd\fR\ ]
+[\ \fB\-\-iproute\fR\ \fIcmd\fR\ ]
 [\ \fB\-\-iroute\fR\ \fInetwork\ [netmask]\fR\ ]
 [\ \fB\-\-keepalive\fR\ \fIn\ m\fR\ ]
 [\ \fB\-\-key\-method\fR\ \fIm\fR\ ]
@@ -923,6 +926,11 @@ Specify the link layer address, more commonly known as the MAC address.
 Only applied to TAP devices.
 .\"*********************************************************
 .TP
+.B --iproute cmd
+Set alternate command to execute instead of default iproute2 command.
+May be used in order to execute OpenVPN in unprivileged environment.
+.\"*********************************************************
+.TP
 .B --ifconfig l rn
 Set TUN/TAP adapter parameters. 
 .B l
@@ -4306,6 +4314,14 @@ Remove a persistent tunnel.
 .B --dev tunX | tapX
 TUN/TAP device
 .\"*********************************************************
+.TP
+.B --user user
+Optional user to be owner of this tunnel.
+.\"*********************************************************
+.TP
+.B --group group
+Optional group to be owner of this tunnel.
+.\"*********************************************************
 .SS Windows-Specific Options:
 .\"*********************************************************
 .TP
index 8c5a268efb7dfe36616b0d89a4e112941e0421b9..a990fcd79b7bd84d1342e87338e81d32fe4f715c 100644 (file)
--- a/options.c
+++ b/options.c
@@ -156,6 +156,9 @@ static const char usage_message[] =
   "--lladdr hw     : Set the link layer address of the tap device.\n"
   "--topology t    : Set --dev tun topology: 'net30', 'p2p', or 'subnet'.\n"
   "--tun-ipv6      : Build tun link capable of forwarding IPv6 traffic.\n"
+#ifdef CONFIG_FEATURE_IPROUTE
+  "--iproute cmd   : Use this command instead of default " IPROUTE_PATH ".\n"
+#endif
   "--ifconfig l rn : TUN: configure device to use IP address l as a local\n"
   "                  endpoint and rn as a remote endpoint.  l & rn should be\n"
   "                  swapped on the other peer.  l & rn must be private\n"
@@ -591,6 +594,8 @@ static const char usage_message[] =
   "--rmtun         : Remove a persistent tunnel.\n"
   "--dev tunX|tapX : tun/tap device\n"
   "--dev-type dt   : Device type.  See tunnel options above for details.\n"
+  "--user user     : User to set privilege to.\n"
+  "--group group   : Group to set privilege to.\n"
 #endif
 #ifdef ENABLE_PKCS11
   "\n"
@@ -3225,6 +3230,13 @@ add_option (struct options *options,
       VERIFY_PERMISSION (OPT_P_UP);
       options->tun_ipv6 = true;
     }
+#ifdef CONFIG_FEATURE_IPROUTE
+  else if (streq (p[0], "iproute") && p[1])
+    {
+      VERIFY_PERMISSION (OPT_P_UP);
+      iproute_path = p[1];
+    }
+#endif
   else if (streq (p[0], "ifconfig") && p[1] && p[2])
     {
       VERIFY_PERMISSION (OPT_P_UP);
diff --git a/route.c b/route.c
index 36d41cd424c74b16fd0e8bcd17b7e882d8ba082c..507ef38f301bf530881adc67aa6bc5132706fd73 100644 (file)
--- a/route.c
+++ b/route.c
@@ -777,7 +777,8 @@ add_route (struct route *r, const struct tuntap *tt, unsigned int flags, const s
 
 #if defined(TARGET_LINUX)
 #ifdef CONFIG_FEATURE_IPROUTE
-  buf_printf (&buf, IPROUTE_PATH " route add %s/%d via %s",
+  buf_printf (&buf, "%s route add %s/%d via %s",
+             iproute_path,
              network,
              count_netmask_bits(netmask),
              gateway);
@@ -934,7 +935,8 @@ delete_route (const struct route *r, const struct tuntap *tt, unsigned int flags
 
 #if defined(TARGET_LINUX)
 #ifdef CONFIG_FEATURE_IPROUTE
-  buf_printf (&buf, IPROUTE_PATH " route del %s/%d",
+  buf_printf (&buf, "%s route del %s/%d",
+             iproute_path,
              network,
              count_netmask_bits(netmask));
 #else
diff --git a/tun.c b/tun.c
index 8c8616ab215d703f004a722870386b4d29c1ca64..3a740bff95027074a3d196b288b9b1a4b60814db 100644 (file)
--- a/tun.c
+++ b/tun.c
@@ -577,7 +577,8 @@ do_ifconfig (struct tuntap *tt,
         * Set the MTU for the device
         */
        openvpn_snprintf (command_line, sizeof (command_line),
-                         IPROUTE_PATH " link set dev %s up mtu %d",
+                         "%s link set dev %s up mtu %d",
+                         iproute_path,
                          actual,
                          tun_mtu
                          );
@@ -590,7 +591,8 @@ do_ifconfig (struct tuntap *tt,
                 * Set the address for the device
                 */
                openvpn_snprintf (command_line, sizeof (command_line),
-                                 IPROUTE_PATH " addr add dev %s local %s peer %s",
+                                 "%s addr add dev %s local %s peer %s",
+                                 iproute_path,
                                  actual,
                                  ifconfig_local,
                                  ifconfig_remote_netmask
@@ -599,7 +601,8 @@ do_ifconfig (struct tuntap *tt,
                  system_check (command_line, es, S_FATAL, "Linux ip addr add failed");
        } else {
                openvpn_snprintf (command_line, sizeof (command_line),
-                                 IPROUTE_PATH " addr add dev %s %s/%d broadcast %s",
+                                 "%s addr add dev %s %s/%d broadcast %s",
+                                 iproute_path,
                                  actual,
                                  ifconfig_local,
                                  count_netmask_bits(ifconfig_remote_netmask),
@@ -1162,8 +1165,20 @@ open_tun (const char *dev, const char *dev_type, const char *dev_node, bool ipv6
 
 #ifdef TUNSETPERSIST
 
+/*
+ * This can be removed in future
+ * when all systems will use newer
+ * linux-headers
+ */
+#ifndef TUNSETOWNER
+#define TUNSETOWNER    _IOW('T', 204, int)
+#endif
+#ifndef TUNSETGROUP
+#define TUNSETGROUP    _IOW('T', 206, int)
+#endif
+
 void
-tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode, const struct tuntap_options *options)
+tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6, int persist_mode, const char *username, const char *groupname, const struct tuntap_options *options)
 {
   struct tuntap *tt;
 
@@ -1174,6 +1189,26 @@ tuncfg (const char *dev, const char *dev_type, const char *dev_node, bool ipv6,
   open_tun (dev, dev_type, dev_node, ipv6, tt);
   if (ioctl (tt->fd, TUNSETPERSIST, persist_mode) < 0)
     msg (M_ERR, "Cannot ioctl TUNSETPERSIST(%d) %s", persist_mode, dev);
+  if (username != NULL)
+    {
+      struct user_state user_state;
+
+      if (!get_user (username, &user_state))
+        msg (M_ERR, "Cannot get user entry for %s", username);
+      else
+        if (ioctl (tt->fd, TUNSETOWNER, user_state.pw->pw_uid) < 0)
+          msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", username, dev);
+    }
+  if (groupname != NULL)
+    {
+      struct group_state group_state;
+
+      if (!get_group (groupname, &group_state))
+        msg (M_ERR, "Cannot get group entry for %s", groupname);
+      else
+        if (ioctl (tt->fd, TUNSETGROUP, group_state.gr->gr_gid) < 0)
+          msg (M_ERR, "Cannot ioctl TUNSETOWNER(%s) %s", groupname, dev);
+    }
   close_tun (tt);
   msg (M_INFO, "Persist state set to: %s", (persist_mode ? "ON" : "OFF"));
 }
@@ -1185,6 +1220,19 @@ close_tun (struct tuntap *tt)
 {
   if (tt)
     {
+#ifdef CONFIG_FEATURE_IPROUTE
+       char command_line[256];
+       /*
+        * Flush IP configuration for the device
+        */
+       openvpn_snprintf (command_line, sizeof (command_line),
+                         "%s addr flush dev %s",
+                         iproute_path,
+                         tt->actual_name
+                         );
+       msg (M_INFO, "%s", command_line);
+       system_check (command_line, NULL, S_FATAL, "Linux ip flush failed");
+#endif
       close_tun_generic (tt);
       free (tt);
     }
diff --git a/tun.h b/tun.h
index b25587c99d487640a7ec77d0bcafa50ea7cb858d..63e6ca81ed4e74a7a1b9448152d4c4efb11ace5f 100644 (file)
--- a/tun.h
+++ b/tun.h
@@ -204,7 +204,8 @@ int write_tun (struct tuntap* tt, uint8_t *buf, int len);
 int read_tun (struct tuntap* tt, uint8_t *buf, int len);
 
 void tuncfg (const char *dev, const char *dev_type, const char *dev_node,
-            bool ipv6, int persist_mode, const struct tuntap_options *options);
+            bool ipv6, int persist_mode, const char *username,
+            const char *groupname, const struct tuntap_options *options);
 
 const char *guess_tuntap_dev (const char *dev,
                              const char *dev_type,