]> git.ipfire.org Git - thirdparty/openvpn.git/commitdiff
Management interface can now listen on a unix
authorjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 30 Sep 2008 06:11:38 +0000 (06:11 +0000)
committerjames <james@e7ae566f-a301-0410-adde-c780ea21d3b5>
Tue, 30 Sep 2008 06:11:38 +0000 (06:11 +0000)
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

16 files changed:
basic.h
configure.ac
debug/valgrind-suppress
forward.c
init.c
manage.c
manage.h
misc.c
misc.h
openvpn.8
options.c
options.h
socket.c
socket.h
syshead.h
version.m4

diff --git a/basic.h b/basic.h
index f03d507b3980dd21b6240e1ca1264f663c9fa2fc..7322fae7cd44513712367de684bae1e80a05cfd3 100644 (file)
--- a/basic.h
+++ b/basic.h
 #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))
 
index bd256b1f9c75afeaffadfeb6693503514df1cba5..282ed9470f45a2a71e5fef946b6b508c7c9f9978 100644 (file)
@@ -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
index bf30959cdafe0ec286a6ac80a2df934d7904a7f9..2d57da0c1aa37f35c43acf1c2790abfb207cbb9f 100644 (file)
    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/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
    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: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
    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/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
    fun:main
 }
 
+{
+   <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:main
 }
 
+{
+   <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: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
+}
index 8967e6ec5134e7d39fd2def1783482a2c92319df..119392fa89d4a06edcd7c767494760aa0395471b 100644 (file)
--- 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 2aa1bd036c33c61ff7e8f2b7a5258d8fa9e15be4..46f2b6664e75531e7e4788ced32f99e0e582c935 100644 (file)
--- 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,
index 12ed97ec52c7cd7dbde67a3b4ad0473770069aac..69bb36bfd46818cacd99307f8f4c67d506d10b80 100644 (file)
--- a/manage.c
+++ b/manage.c
@@ -225,6 +225,15 @@ man_prompt (struct management *man)
 #endif
 }
 
+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)
 {
@@ -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,
index 6983ae8c799b2da4ddfa85433adbccb4343d3415..0ad303ef2e76a4c03d9c085e0513511618590652 100644 (file)
--- 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 45356a68952c525101cfc1074366bb8dc5582157..5f5df4573c3474319ee6aecf76cae971880f073c 100644 (file)
--- 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 dd81d8281b6c2bfea099b63d0b730cdb00c50692..9ee4bfe5161b664713c3e7da18fc019b334523c5 100644 (file)
--- 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
index 7dc1ed18ee1aea8e3c0b43999f7f1f495f64435a..5c6a9dc79d2be9afc979c0766bf46ddff2f3ab55 100644 (file)
--- 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,
index ebccd7f82efad68dc922c022883c96580d6f4ea1..a23397202f1fe6970ebd8306e917387950d605d1 100644 (file)
--- 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);
index 30838ca74bcc5e719011e58ce6e0a511e34eda1f..fcb9d41c83d19ad40293a60a9e8d7ff3e2f52c17 100644 (file)
--- 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
index fe58c3e3158a85806ba0e7f43f6c7daea9a4b011..293d621dc3e53fa17e26ff7fbf6408f6939f78fe 100644 (file)
--- 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
index 980322d3be72f4951929d26f6d70865e263a79e8..b36bd966893231997d8740fdeb3647e7593379eb 100644 (file)
--- 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
  */
index e87814eecb7d598bcdd3f18a80808d1c94171148..1bab029a736bc594c3a6d4533d1af0fa822a952e 100644 (file)
--- a/syshead.h
+++ b/syshead.h
 #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
@@ -515,6 +519,15 @@ socket_defined (const socket_descriptor_t sd)
 #define ENABLE_PF
 #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
  */
index def55c993ab78ac6e7474663fd520289eb48fc28..4aba952bb34af58d15dae15e73839f96274506b4 100644 (file)
@@ -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])