summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-09-30 06:11:38 +0000
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>2008-09-30 06:11:38 +0000
commitbb564a5950a14139f59305e549ca8665b8f31cb8 (patch)
tree62054c12921f4e364b607b1cf3fded0df5605632
parentb0cb50e7e776dce1f469b1d617d7260b8d483634 (diff)
downloadopenvpn-bb564a5950a14139f59305e549ca8665b8f31cb8.zip
openvpn-bb564a5950a14139f59305e549ca8665b8f31cb8.tar.gz
openvpn-bb564a5950a14139f59305e549ca8665b8f31cb8.tar.xz
Management interface can now listen on a unix
domain socket, for example: management /tmp/openvpn unix Also added management-client-user and management-client-group directives to control which processes are allowed to connect to the socket. git-svn-id: http://svn.openvpn.net/projects/openvpn/branches/BETA21/openvpn@3396 e7ae566f-a301-0410-adde-c780ea21d3b5
-rw-r--r--basic.h8
-rw-r--r--configure.ac4
-rw-r--r--debug/valgrind-suppress269
-rw-r--r--forward.c8
-rw-r--r--init.c2
-rw-r--r--manage.c164
-rw-r--r--manage.h9
-rw-r--r--misc.c4
-rw-r--r--misc.h26
-rw-r--r--openvpn.827
-rw-r--r--options.c50
-rw-r--r--options.h7
-rw-r--r--socket.c122
-rw-r--r--socket.h23
-rw-r--r--syshead.h13
-rw-r--r--version.m42
16 files changed, 693 insertions, 45 deletions
diff --git a/basic.h b/basic.h
index f03d507..7322fae 100644
--- a/basic.h
+++ b/basic.h
@@ -26,9 +26,17 @@
#define BASIC_H
/* bool definitions */
+#ifndef bool
#define bool int
+#endif
+
+#ifndef true
#define true 1
+#endif
+
+#ifndef false
#define false 0
+#endif
#define BOOL_CAST(x) ((x) ? (true) : (false))
diff --git a/configure.ac b/configure.ac
index bd256b1..282ed94 100644
--- a/configure.ac
+++ b/configure.ac
@@ -339,7 +339,7 @@ AC_CHECK_HEADERS(fcntl.h stdlib.h dnl
if test "${WIN32}" != "yes"; then
AC_HEADER_SYS_WAIT
- AC_CHECK_HEADERS(sys/time.h sys/socket.h sys/ioctl.h sys/stat.h dnl
+ AC_CHECK_HEADERS(sys/time.h sys/socket.h sys/un.h sys/ioctl.h sys/stat.h dnl
sys/mman.h fcntl.h sys/file.h stdlib.h stdint.h dnl
stdarg.h unistd.h signal.h stdio.h string.h dnl
strings.h ctype.h errno.h syslog.h pwd.h grp.h dnl
@@ -464,7 +464,7 @@ AC_CHECK_FUNCS(daemon chroot getpwnam setuid nice system getpid dup dup2 dnl
getpass strerror syslog openlog mlockall getgrnam setgid dnl
setgroups stat flock readv writev time dnl
setsid chdir putenv getpeername unlink dnl
- chsize ftruncate execve)
+ chsize ftruncate execve getpeereid umask)
# Windows use stdcall for winsock so we cannot auto detect these
m4_define([SOCKET_FUNCS], [socket recv recvfrom send sendto listen dnl
diff --git a/debug/valgrind-suppress b/debug/valgrind-suppress
index bf30959..2d57da0 100644
--- a/debug/valgrind-suppress
+++ b/debug/valgrind-suppress
@@ -64,6 +64,32 @@
obj:/lib/ld-2.5.so
obj:/lib/ld-2.5.so
obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/libc-2.5.so
+ obj:/lib/ld-2.5.so
+ fun:__libc_dlopen_mode
+ fun:__nss_lookup_function
+ obj:/lib/libc-2.5.so
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Addr8
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
obj:/lib/libc-2.5.so
obj:/lib/ld-2.5.so
fun:__libc_dlopen_mode
@@ -177,6 +203,79 @@
{
<insert a suppression name here>
+ Memcheck:Addr8
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/libc-2.7.so
+ obj:/lib/ld-2.7.so
+ fun:__libc_dlopen_mode
+ fun:__nss_lookup_function
+ obj:/lib/libc-2.7.so
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Cond
+ fun:BN_div
+ fun:BN_MONT_CTX_set
+ fun:BN_MONT_CTX_set_locked
+ obj:/usr/lib/libcrypto.so.0.9.8
+ fun:ssl3_ctx_ctrl
+ fun:init_ssl
+ fun:init_instance
+ fun:init_instance_handle_signals
+ fun:tunnel_server_udp
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Cond
+ fun:BN_div
+ fun:BN_nnmod
+ fun:BN_mod_inverse
+ fun:BN_MONT_CTX_set
+ fun:BN_MONT_CTX_set_locked
+ obj:/usr/lib/libcrypto.so.0.9.8
+ fun:ssl3_ctx_ctrl
+ fun:init_ssl
+ fun:init_instance
+ fun:init_instance_handle_signals
+ fun:tunnel_server_udp
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Cond
+ fun:BN_mod_inverse
+ fun:BN_MONT_CTX_set
+ fun:BN_MONT_CTX_set_locked
+ obj:/usr/lib/libcrypto.so.0.9.8
+ fun:ssl3_ctx_ctrl
+ fun:init_ssl
+ fun:init_instance
+ fun:init_instance_handle_signals
+ fun:tunnel_server_udp
+ fun:main
+}
+
+{
+ <insert a suppression name here>
Memcheck:Cond
obj:/lib/ld-2.5.so
obj:/lib/ld-2.5.so
@@ -428,6 +527,26 @@
obj:/lib/ld-2.5.so
obj:/lib/ld-2.5.so
obj:/lib/libc-2.5.so
+ obj:/lib/ld-2.5.so
+ fun:__libc_dlopen_mode
+ fun:__nss_lookup_function
+ obj:/lib/libc-2.5.so
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Cond
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/ld-2.5.so
+ obj:/lib/libc-2.5.so
obj:/lib/libdl-2.5.so
obj:/lib/ld-2.5.so
obj:/lib/libdl-2.5.so
@@ -522,6 +641,21 @@
<insert a suppression name here>
Memcheck:Leak
fun:malloc
+ fun:__nss_lookup_function
+ obj:*
+ obj:*
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
fun:getdelim
fun:getpass
fun:get_console_input
@@ -587,6 +721,22 @@
<insert a suppression name here>
Memcheck:Leak
fun:malloc
+ fun:tsearch
+ fun:__nss_lookup_function
+ obj:*
+ obj:*
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
obj:/lib/libc-2.5.so
fun:__nss_database_lookup
obj:*
@@ -636,3 +786,122 @@
fun:main
}
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ obj:/lib/libc-2.5.so
+ fun:__nss_database_lookup
+ obj:*
+ obj:*
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ obj:/lib/libc-2.7.so
+ fun:__nss_database_lookup
+ obj:*
+ obj:*
+ fun:getpwnam_r
+ fun:getpwnam
+ fun:get_user
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Addr8
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/libc-2.7.so
+ obj:/lib/ld-2.7.so
+ fun:__libc_dlopen_mode
+ fun:__nss_lookup_function
+ obj:/lib/libc-2.7.so
+ fun:getgrnam_r
+ fun:getgrnam
+ fun:get_group
+ fun:do_init_first_time
+ fun:init_instance
+ fun:init_instance_handle_signals
+ fun:tunnel_server_udp
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ obj:/lib/libc-2.7.so
+ fun:__nss_database_lookup
+ obj:*
+ obj:*
+ fun:getgrnam_r
+ fun:getgrnam
+ fun:get_group
+ fun:do_init_first_time
+ fun:init_instance
+ fun:init_instance_handle_signals
+ fun:tunnel_server_udp
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Addr8
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/ld-2.7.so
+ obj:/lib/libc-2.7.so
+ obj:/lib/ld-2.7.so
+ fun:__libc_dlopen_mode
+ fun:__nss_lookup_function
+ obj:/lib/libc-2.7.so
+ fun:getgrnam_r
+ fun:getgrnam
+ fun:get_group
+ fun:management_open
+ fun:open_management
+ fun:main
+}
+
+{
+ <insert a suppression name here>
+ Memcheck:Leak
+ fun:malloc
+ fun:tsearch
+ fun:__nss_lookup_function
+ obj:*
+ obj:*
+ fun:getgrnam_r
+ fun:getgrnam
+ fun:get_group
+ fun:management_open
+ fun:open_management
+ fun:main
+}
diff --git a/forward.c b/forward.c
index 8967e6e..119392f 100644
--- a/forward.c
+++ b/forward.c
@@ -1290,11 +1290,11 @@ io_wait_dowork (struct context *c, const unsigned int flags)
struct event_set_return esr[4];
/* These shifts all depend on EVENT_READ and EVENT_WRITE */
- static const int socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */
- static const int tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */
- static const int err_shift = 4; /* depends on ES_ERROR */
+ static int socket_shift = 0; /* depends on SOCKET_READ and SOCKET_WRITE */
+ static int tun_shift = 2; /* depends on TUN_READ and TUN_WRITE */
+ static int err_shift = 4; /* depends on ES_ERROR */
#ifdef ENABLE_MANAGEMENT
- static const int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
+ static int management_shift = 6; /* depends on MANAGEMENT_READ and MANAGEMENT_WRITE */
#endif
/*
diff --git a/init.c b/init.c
index 2aa1bd0..46f2b66 100644
--- a/init.c
+++ b/init.c
@@ -2670,6 +2670,8 @@ open_management (struct context *c)
c->options.management_addr,
c->options.management_port,
c->options.management_user_pass,
+ c->options.management_client_user,
+ c->options.management_client_group,
c->options.management_log_history_cache,
c->options.management_echo_buffer_size,
c->options.management_state_buffer_size,
diff --git a/manage.c b/manage.c
index 12ed97e..69bb36b 100644
--- a/manage.c
+++ b/manage.c
@@ -226,6 +226,15 @@ man_prompt (struct management *man)
}
static void
+man_delete_unix_socket (struct management *man)
+{
+#if UNIX_SOCK_SUPPORT
+ if (man->settings.flags & MF_LISTEN_UNIX)
+ socket_delete_unix (&man->settings.local_unix);
+#endif
+}
+
+static void
man_close_socket (struct management *man, const socket_descriptor_t sd)
{
#ifndef WIN32
@@ -1231,9 +1240,18 @@ man_new_connection_post (struct management *man, const char *description)
man_start_ne32 (man);
#endif
- msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
- description,
- print_sockaddr (&man->settings.local, &gc));
+#if UNIX_SOCK_SUPPORT
+ if (man->settings.flags & MF_LISTEN_UNIX)
+ {
+ msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
+ description,
+ sockaddr_unix_name (&man->settings.local_unix, "NULL"));
+ }
+ else
+#endif
+ msg (D_MANAGEMENT, "MANAGEMENT: %s %s",
+ description,
+ print_sockaddr (&man->settings.local, &gc));
buffer_list_reset (man->connection.out);
@@ -1249,11 +1267,46 @@ static void
man_accept (struct management *man)
{
struct link_socket_actual act;
+ CLEAR (act);
/*
- * Accept the TCP client.
+ * Accept the TCP or Unix domain socket client.
*/
- man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &act, false);
+#if UNIX_SOCK_SUPPORT
+ if (man->settings.flags & MF_LISTEN_UNIX)
+ {
+ struct sockaddr_un remote;
+ man->connection.sd_cli = socket_accept_unix (man->connection.sd_top, &remote);
+ if (socket_defined (man->connection.sd_cli) && (man->settings.client_uid != -1 || man->settings.client_gid != -1))
+ {
+ static const char err_prefix[] = "MANAGEMENT: unix domain socket client connection rejected --";
+ int uid, gid;
+ if (unix_socket_get_peer_uid_gid (man->connection.sd_cli, &uid, &gid))
+ {
+ if (man->settings.client_uid != -1 && man->settings.client_uid != uid)
+ {
+ msg (D_MANAGEMENT, "%s UID of socket peer (%d) doesn't match required value (%d) as given by --management-client-user",
+ err_prefix, uid, man->settings.client_uid);
+ sd_close (&man->connection.sd_cli);
+ }
+ if (man->settings.client_gid != -1 && man->settings.client_gid != gid)
+ {
+ msg (D_MANAGEMENT, "%s GID of socket peer (%d) doesn't match required value (%d) as given by --management-client-group",
+ err_prefix, gid, man->settings.client_gid);
+ sd_close (&man->connection.sd_cli);
+ }
+ }
+ else
+ {
+ msg (D_MANAGEMENT, "%s cannot get UID/GID of socket peer", err_prefix);
+ sd_close (&man->connection.sd_cli);
+ }
+ }
+ }
+ else
+#endif
+ man->connection.sd_cli = socket_do_accept (man->connection.sd_top, &act, false);
+
if (socket_defined (man->connection.sd_cli))
{
man->connection.remote = act.dest;
@@ -1285,12 +1338,19 @@ man_listen (struct management *man)
*/
if (man->connection.sd_top == SOCKET_UNDEFINED)
{
- man->connection.sd_top = create_socket_tcp ();
-
- /*
- * Bind socket
- */
- socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT");
+#if UNIX_SOCK_SUPPORT
+ if (man->settings.flags & MF_LISTEN_UNIX)
+ {
+ man_delete_unix_socket (man);
+ man->connection.sd_top = create_socket_unix ();
+ socket_bind_unix (man->connection.sd_top, &man->settings.local_unix, "MANAGEMENT");
+ }
+ else
+#endif
+ {
+ man->connection.sd_top = create_socket_tcp ();
+ socket_bind (man->connection.sd_top, &man->settings.local, "MANAGEMENT");
+ }
/*
* Listen for connection
@@ -1304,8 +1364,16 @@ man_listen (struct management *man)
set_nonblock (man->connection.sd_top);
set_cloexec (man->connection.sd_top);
- msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s",
- print_sockaddr (&man->settings.local, &gc));
+#if UNIX_SOCK_SUPPORT
+ if (man->settings.flags & MF_LISTEN_UNIX)
+ {
+ msg (D_MANAGEMENT, "MANAGEMENT: unix domain socket listening on %s",
+ sockaddr_unix_name (&man->settings.local_unix, "NULL"));
+ }
+ else
+#endif
+ msg (D_MANAGEMENT, "MANAGEMENT: TCP Socket listening on %s",
+ print_sockaddr (&man->settings.local, &gc));
}
#ifdef WIN32
@@ -1645,6 +1713,8 @@ man_settings_init (struct man_settings *ms,
const char *addr,
const int port,
const char *pass_file,
+ const char *client_user,
+ const char *client_group,
const int log_history_cache,
const int echo_buffer_size,
const int state_buffer_size,
@@ -1657,6 +1727,8 @@ man_settings_init (struct man_settings *ms,
CLEAR (*ms);
ms->flags = flags;
+ ms->client_uid = -1;
+ ms->client_gid = -1;
/*
* Get username/password
@@ -1664,27 +1736,54 @@ man_settings_init (struct man_settings *ms,
if (pass_file)
get_user_pass (&ms->up, pass_file, "Management", GET_USER_PASS_PASSWORD_ONLY);
- ms->write_peer_info_file = string_alloc (write_peer_info_file, NULL);
-
- /*
- * Initialize socket address
- */
- ms->local.sa.sin_family = AF_INET;
- ms->local.sa.sin_addr.s_addr = 0;
- ms->local.sa.sin_port = htons (port);
-
/*
- * Run management over tunnel, or
- * separate channel?
+ * lookup client UID/GID if specified
*/
- if (streq (addr, "tunnel") && !(flags & MF_CONNECT_AS_CLIENT))
+ if (client_user)
+ {
+ struct user_state s;
+ get_user (client_user, &s);
+ ms->client_uid = user_state_uid (&s);
+ msg (D_MANAGEMENT, "MANAGEMENT: client_uid=%d", ms->client_uid);
+ ASSERT (ms->client_uid >= 0);
+ }
+ if (client_group)
{
- ms->management_over_tunnel = true;
+ struct group_state s;
+ get_group (client_group, &s);
+ ms->client_gid = group_state_gid (&s);
+ msg (D_MANAGEMENT, "MANAGEMENT: client_gid=%d", ms->client_gid);
+ ASSERT (ms->client_gid >= 0);
}
+
+ ms->write_peer_info_file = string_alloc (write_peer_info_file, NULL);
+
+#if UNIX_SOCK_SUPPORT
+ if (ms->flags & MF_LISTEN_UNIX)
+ sockaddr_unix_init (&ms->local_unix, addr);
else
+#endif
{
- ms->local.sa.sin_addr.s_addr = getaddr
- (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
+ /*
+ * Initialize socket address
+ */
+ ms->local.sa.sin_family = AF_INET;
+ ms->local.sa.sin_addr.s_addr = 0;
+ ms->local.sa.sin_port = htons (port);
+
+ /*
+ * Run management over tunnel, or
+ * separate channel?
+ */
+ if (streq (addr, "tunnel") && !(flags & MF_CONNECT_AS_CLIENT))
+ {
+ ms->management_over_tunnel = true;
+ }
+ else
+ {
+ ms->local.sa.sin_addr.s_addr = getaddr
+ (GETADDR_RESOLVE|GETADDR_WARN_ON_SIGNAL|GETADDR_FATAL, addr, 0, NULL, NULL);
+ }
}
/*
@@ -1764,7 +1863,10 @@ man_connection_close (struct management *man)
net_event_win32_close (&mc->ne32);
#endif
if (socket_defined (mc->sd_top))
- man_close_socket (man, mc->sd_top);
+ {
+ man_close_socket (man, mc->sd_top);
+ man_delete_unix_socket (man);
+ }
if (socket_defined (mc->sd_cli))
man_close_socket (man, mc->sd_cli);
if (mc->in)
@@ -1798,6 +1900,8 @@ management_open (struct management *man,
const char *addr,
const int port,
const char *pass_file,
+ const char *client_user,
+ const char *client_group,
const int log_history_cache,
const int echo_buffer_size,
const int state_buffer_size,
@@ -1815,6 +1919,8 @@ management_open (struct management *man,
addr,
port,
pass_file,
+ client_user,
+ client_group,
log_history_cache,
echo_buffer_size,
state_buffer_size,
diff --git a/manage.h b/manage.h
index 6983ae8..0ad303e 100644
--- a/manage.h
+++ b/manage.h
@@ -202,12 +202,17 @@ struct man_settings {
bool defined;
unsigned int flags; /* MF_x flags */
struct openvpn_sockaddr local;
+#if UNIX_SOCK_SUPPORT
+ struct sockaddr_un local_unix;
+#endif
bool management_over_tunnel;
struct user_pass up;
int log_history_cache;
int echo_buffer_size;
int state_buffer_size;
char *write_peer_info_file;
+ int client_uid;
+ int client_gid;
/* flags for handling the management interface "signal" command */
# define MANSIG_IGNORE_USR1_HUP (1<<0)
@@ -295,10 +300,14 @@ struct management *management_init (void);
#ifdef MANAGEMENT_PF
# define MF_CLIENT_PF (1<<7)
#endif
+# define MF_LISTEN_UNIX (1<<8)
+
bool management_open (struct management *man,
const char *addr,
const int port,
const char *pass_file,
+ const char *client_user,
+ const char *client_group,
const int log_history_cache,
const int echo_buffer_size,
const int state_buffer_size,
diff --git a/misc.c b/misc.c
index 45356a6..5f5df45 100644
--- a/misc.c
+++ b/misc.c
@@ -82,7 +82,7 @@ get_user (const char *username, struct user_state *state)
state->username = username;
ret = true;
#else
- msg (M_FATAL, "Sorry but I can't setuid to '%s' because this operating system doesn't appear to support the getpwname() or setuid() system calls", username);
+ msg (M_FATAL, "cannot get UID for user %s -- platform lacks getpwname() or setuid() system calls", username);
#endif
}
return ret;
@@ -117,7 +117,7 @@ get_group (const char *groupname, struct group_state *state)
state->groupname = groupname;
ret = true;
#else
- msg (M_FATAL, "Sorry but I can't setgid to '%s' because this operating system doesn't appear to support the getgrnam() or setgid() system calls", groupname);
+ msg (M_FATAL, "cannot get GID for group %s -- platform lacks getgrnam() or setgid() system calls", groupname);
#endif
}
return ret;
diff --git a/misc.h b/misc.h
index dd81d82..9ee4bfe 100644
--- a/misc.h
+++ b/misc.h
@@ -119,7 +119,7 @@ void warn_if_group_others_accessible(const char* filename);
/* interpret the status code returned by system()/execve() */
bool system_ok(int);
-int system_executed (int stat);
+bool system_executed (int stat);
const char *system_error_message (int, struct gc_arena *gc);
/* wrapper around the execve() call */
@@ -330,4 +330,28 @@ void argv_printf_cat (struct argv *a, const char *format, ...)
#endif
;
+/*
+ * Extract UID or GID
+ */
+
+static inline int
+user_state_uid (const struct user_state *s)
+{
+#if defined(HAVE_GETPWNAM) && defined(HAVE_SETUID)
+ if (s->pw)
+ return s->pw->pw_uid;
+#endif
+ return -1;
+}
+
+static inline int
+group_state_gid (const struct group_state *s)
+{
+#if defined(HAVE_GETGRNAM) && defined(HAVE_SETGID)
+ if (s->gr)
+ return s->gr->gr_gid;
+#endif
+ return -1;
+}
+
#endif
diff --git a/openvpn.8 b/openvpn.8
index 7dc1ed1..5c6a9dc 100644
--- a/openvpn.8
+++ b/openvpn.8
@@ -181,7 +181,9 @@ openvpn \- secure IP tunnel daemon.
[\ \fB\-\-suppress-timestamps\fR\ ]
[\ \fB\-\-lport\fR\ \fIport\fR\ ]
[\ \fB\-\-management\-client\-auth\fR\ ]
+[\ \fB\-\-management\-client\-group\fR\ \fIg\fR\ ]
[\ \fB\-\-management\-client\-pf\fR\ ]
+[\ \fB\-\-management\-client\-user\fR\ \fIu\fR\ ]
[\ \fB\-\-management\-forget\-disconnect\fR\ ]
[\ \fB\-\-management\-hold\fR\ ]
[\ \fB\-\-management\-log\-cache\fR\ \fIn\fR\ ]
@@ -2455,6 +2457,19 @@ or "stdin" to prompt from standard input. The password
provided will set the password which TCP clients will need
to provide in order to access management functions.
+The management interface can also listen on a unix domain socket,
+for those platforms that support it. To use a unix domain socket, specify
+the unix socket pathname in place of
+.B IP
+and set
+.B port
+to 'unix'. While the default behavior is to create a unix domain socket
+that may be connected to by any process, the
+.B --management-client-user
+and
+.B --management-client-group
+directives can be used to restrict access.
+
The management interface provides a special mode where the TCP
management link can operate over the tunnel itself. To enable this mode,
set
@@ -2532,6 +2547,18 @@ filter file for each connecting client. See management-notes.txt
in OpenVPN distribution for detailed notes.
.\"*********************************************************
.TP
+.B --management-client-user u
+When the management interface is listening on a unix domain socket,
+only allow connections from user
+.B u.
+.\"*********************************************************
+.TP
+.B --management-client-group g
+When the management interface is listening on a unix domain socket,
+only allow connections from group
+.B g.
+.\"*********************************************************
+.TP
.B --plugin module-pathname [init-string]
Load plug-in module from the file
.B module-pathname,
diff --git a/options.c b/options.c
index ebccd7f..a233972 100644
--- a/options.c
+++ b/options.c
@@ -311,6 +311,10 @@ static const char usage_message[] =
"--management ip port [pass] : Enable a TCP server on ip:port to handle\n"
" management functions. pass is a password file\n"
" or 'stdin' to prompt from console.\n"
+#if UNIX_SOCK_SUPPORT
+ " To listen on a unix domain socket, specific the pathname\n"
+ " in place of ip and use 'unix' as the port number.\n"
+#endif
"--management-client : Management interface will connect as a TCP client to\n"
" ip/port rather than listen as a TCP server.\n"
"--management-query-passwords : Query management channel for private key\n"
@@ -322,6 +326,12 @@ static const char usage_message[] =
" event occurs.\n"
"--management-log-cache n : Cache n lines of log file history for usage\n"
" by the management channel.\n"
+#if UNIX_SOCK_SUPPORT
+ "--management-client-user u : When management interface is a unix socket, only\n"
+ " allow connections from user u.\n"
+ "--management-client-group g : When management interface is a unix socket, only\n"
+ " allow connections from group g.\n"
+#endif
#ifdef MANAGEMENT_DEF_AUTH
"--management-client-auth : gives management interface client the responsibility\n"
" to authenticate clients after their client certificate\n"
@@ -1240,6 +1250,8 @@ show_settings (const struct options *o)
SHOW_INT (management_log_history_cache);
SHOW_INT (management_echo_buffer_size);
SHOW_STR (management_write_peer_info_file);
+ SHOW_STR (management_client_user);
+ SHOW_STR (management_client_group);
SHOW_INT (management_flags);
#endif
#ifdef ENABLE_PLUGIN
@@ -1554,6 +1566,14 @@ options_postprocess_verify_ce (const struct options *options, const struct conne
|| options->management_write_peer_info_file
|| options->management_log_history_cache != defaults.management_log_history_cache))
msg (M_USAGE, "--management is not specified, however one or more options which modify the behavior of --management were specified");
+
+ if ((options->management_flags & (MF_LISTEN_UNIX|MF_CONNECT_AS_CLIENT))
+ == (MF_LISTEN_UNIX|MF_CONNECT_AS_CLIENT))
+ msg (M_USAGE, "--management-client does not support unix domain sockets");
+
+ if ((options->management_client_user || options->management_client_group)
+ && !(options->management_flags & MF_LISTEN_UNIX))
+ msg (M_USAGE, "--management-client-(user|group) can only be used on unix domain sockets");
#endif
/*
@@ -3319,14 +3339,26 @@ add_option (struct options *options,
#ifdef ENABLE_MANAGEMENT
else if (streq (p[0], "management") && p[1] && p[2])
{
- int port;
+ int port = 0;
VERIFY_PERMISSION (OPT_P_GENERAL);
- port = atoi (p[2]);
- if (!legal_ipv4_port (port))
+ if (streq (p[2], "unix"))
{
- msg (msglevel, "port number associated with --management directive is out of range");
+#if UNIX_SOCK_SUPPORT
+ options->management_flags |= MF_LISTEN_UNIX;
+#else
+ msg (msglevel, "MANAGEMENT: this platform does not support unix domain sockets");
goto err;
+#endif
+ }
+ else
+ {
+ port = atoi (p[2]);
+ if (!legal_ipv4_port (port))
+ {
+ msg (msglevel, "port number associated with --management directive is out of range");
+ goto err;
+ }
}
options->management_addr = p[1];
@@ -3336,6 +3368,16 @@ add_option (struct options *options,
options->management_user_pass = p[3];
}
}
+ else if (streq (p[0], "management-client-user") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->management_client_user = p[1];
+ }
+ else if (streq (p[0], "management-client-group") && p[1])
+ {
+ VERIFY_PERMISSION (OPT_P_GENERAL);
+ options->management_client_group = p[1];
+ }
else if (streq (p[0], "management-query-passwords"))
{
VERIFY_PERMISSION (OPT_P_GENERAL);
diff --git a/options.h b/options.h
index 30838ca..fcb9d41 100644
--- a/options.h
+++ b/options.h
@@ -319,6 +319,9 @@ struct options
int management_state_buffer_size;
const char *management_write_peer_info_file;
+ const char *management_client_user;
+ const char *management_client_group;
+
/* Mask of MF_ values of manage.h */
unsigned int management_flags;
#endif
@@ -610,9 +613,9 @@ char *options_string (const struct options *o,
bool remote,
struct gc_arena *gc);
-int options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n);
+bool options_cmp_equal_safe (char *actual, const char *expected, size_t actual_n);
void options_warning_safe (char *actual, const char *expected, size_t actual_n);
-int options_cmp_equal (char *actual, const char *expected);
+bool options_cmp_equal (char *actual, const char *expected);
void options_warning (char *actual, const char *expected);
#endif
diff --git a/socket.c b/socket.c
index fe58c3e..293d621 100644
--- a/socket.c
+++ b/socket.c
@@ -2627,3 +2627,125 @@ socket_set (struct link_socket *s,
}
return rwflags;
}
+
+void
+sd_close (socket_descriptor_t *sd)
+{
+ if (sd && socket_defined (*sd))
+ {
+ openvpn_close_socket (*sd);
+ *sd = SOCKET_UNDEFINED;
+ }
+}
+
+#if UNIX_SOCK_SUPPORT
+
+/*
+ * code for unix domain sockets
+ */
+
+const char *
+sockaddr_unix_name (const struct sockaddr_un *local, const char *null)
+{
+ if (local && local->sun_family == PF_UNIX)
+ return local->sun_path;
+ else
+ return null;
+}
+
+socket_descriptor_t
+create_socket_unix (void)
+{
+ socket_descriptor_t sd;
+
+ if ((sd = socket (PF_UNIX, SOCK_STREAM, 0)) < 0)
+ msg (M_SOCKERR, "Cannot create unix domain socket");
+ return sd;
+}
+
+void
+socket_bind_unix (socket_descriptor_t sd,
+ struct sockaddr_un *local,
+ const char *prefix)
+{
+ struct gc_arena gc = gc_new ();
+
+#ifdef HAVE_UMASK
+ const mode_t orig_umask = umask (0);
+#endif
+
+ if (bind (sd, (struct sockaddr *) local, sizeof (struct sockaddr_un)))
+ {
+ const int errnum = openvpn_errno_socket ();
+ msg (M_FATAL, "%s: Socket bind[%d] failed on unix domain socket %s: %s",
+ prefix,
+ (int)sd,
+ sockaddr_unix_name (local, "NULL"),
+ strerror_ts (errnum, &gc));
+ }
+
+#ifdef HAVE_UMASK
+ umask (orig_umask);
+#endif
+
+ gc_free (&gc);
+}
+
+socket_descriptor_t
+socket_accept_unix (socket_descriptor_t sd,
+ struct sockaddr_un *remote)
+{
+ socklen_t remote_len = sizeof (struct sockaddr_un);
+ socket_descriptor_t ret;
+
+ CLEAR (*remote);
+ ret = accept (sd, (struct sockaddr *) remote, &remote_len);
+ return ret;
+}
+
+void
+sockaddr_unix_init (struct sockaddr_un *local, const char *path)
+{
+ local->sun_family = PF_UNIX;
+ strncpynt (local->sun_path, path, sizeof (local->sun_path));
+}
+
+void
+socket_delete_unix (const struct sockaddr_un *local)
+{
+ const char *name = sockaddr_unix_name (local, NULL);
+#ifdef HAVE_UNLINK
+ if (name && strlen (name))
+ unlink (name);
+#endif
+}
+
+bool
+unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid)
+{
+#ifdef HAVE_GETPEEREID
+ uid_t u;
+ gid_t g;
+ if (getpeereid (sd, &u, &g) == -1)
+ return false;
+ if (uid)
+ *uid = u;
+ if (gid)
+ *gid = g;
+ return true;
+#elif defined(SO_PEERCRED)
+ struct ucred peercred;
+ socklen_t so_len = sizeof(peercred);
+ if (getsockopt(sd, SOL_SOCKET, SO_PEERCRED, &peercred, &so_len) == -1)
+ return false;
+ if (uid)
+ *uid = peercred.uid;
+ if (gid)
+ *gid = peercred.gid;
+ return true;
+#else
+ return false;
+#endif
+}
+
+#endif
diff --git a/socket.h b/socket.h
index 980322d..b36bd96 100644
--- a/socket.h
+++ b/socket.h
@@ -322,6 +322,8 @@ void frame_adjust_path_mtu (struct frame *frame, int pmtu, int proto);
void link_socket_close (struct link_socket *sock);
+void sd_close (socket_descriptor_t *sd);
+
#define PS_SHOW_PORT_IF_DEFINED (1<<0)
#define PS_SHOW_PORT (1<<1)
#define PS_SHOW_PKTINFO (1<<2)
@@ -408,6 +410,27 @@ socket_descriptor_t socket_do_accept (socket_descriptor_t sd,
struct link_socket_actual *act,
const bool nowait);
+#if UNIX_SOCK_SUPPORT
+
+socket_descriptor_t create_socket_unix (void);
+
+void socket_bind_unix (socket_descriptor_t sd,
+ struct sockaddr_un *local,
+ const char *prefix);
+
+socket_descriptor_t socket_accept_unix (socket_descriptor_t sd,
+ struct sockaddr_un *remote);
+
+void sockaddr_unix_init (struct sockaddr_un *local, const char *path);
+
+const char *sockaddr_unix_name (const struct sockaddr_un *local, const char *null);
+
+void socket_delete_unix (const struct sockaddr_un *local);
+
+bool unix_socket_get_peer_uid_gid (const socket_descriptor_t sd, int *uid, int *gid);
+
+#endif
+
/*
* DNS resolution
*/
diff --git a/syshead.h b/syshead.h
index e87814e..1bab029 100644
--- a/syshead.h
+++ b/syshead.h
@@ -88,6 +88,10 @@
#include <sys/socket.h>
#endif
+#ifdef HAVE_SYS_UN_H
+#include <sys/un.h>
+#endif
+
#ifdef HAVE_SYS_IOCTL_H
#include <sys/ioctl.h>
#endif
@@ -516,6 +520,15 @@ socket_defined (const socket_descriptor_t sd)
#endif
/*
+ * Do we support Unix domain sockets?
+ */
+#if defined(PF_UNIX) && !defined(WIN32)
+#define UNIX_SOCK_SUPPORT 1
+#else
+#define UNIX_SOCK_SUPPORT 0
+#endif
+
+/*
* Don't compile the struct buffer_list code unless something needs it
*/
#if defined(ENABLE_MANAGEMENT) || defined(ENABLE_PF)
diff --git a/version.m4 b/version.m4
index def55c9..4aba952 100644
--- a/version.m4
+++ b/version.m4
@@ -1,5 +1,5 @@
dnl define the OpenVPN version
-define(PRODUCT_VERSION,[2.1_rc12])
+define(PRODUCT_VERSION,[2.1_rc12a])
dnl define the TAP version
define(PRODUCT_TAP_ID,[tap0901])
define(PRODUCT_TAP_WIN32_MIN_MAJOR,[9])