From 0aee9ca7e76887fb5752c15ef63bfb7a356df06e Mon Sep 17 00:00:00 2001 From: james Date: Mon, 21 Jan 2008 19:34:13 +0000 Subject: Allow OpenVPN to run completely unprivileged under Linux 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 | 2 +- lladdr.c | 4 ++-- misc.c | 4 ++++ misc.h | 7 +++++++ openvpn.8 | 16 ++++++++++++++++ options.c | 12 ++++++++++++ route.c | 6 ++++-- tun.c | 56 ++++++++++++++++++++++++++++++++++++++++++++++++++++---- tun.h | 3 ++- 9 files changed, 100 insertions(+), 10 deletions(-) diff --git a/init.c b/init.c index 211effd..0651c2d 100644 --- 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; diff --git a/lladdr.c b/lladdr.c index 1f02ba4..1daa379 100644 --- 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 4329711..2821408 100644 --- a/misc.c +++ b/misc.c @@ -44,6 +44,10 @@ #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 09124e6..5b7f227 100644 --- 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 diff --git a/openvpn.8 b/openvpn.8 index 6446c5b..df276e7 100644 --- 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 diff --git a/options.c b/options.c index 8c5a268..a990fcd 100644 --- 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 36d41cd..507ef38 100644 --- 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 8c8616a..3a740bf 100644 --- 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 b25587c..63e6ca8 100644 --- 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, -- cgit