diff options
author | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-09-30 06:11:38 +0000 |
---|---|---|
committer | james <james@e7ae566f-a301-0410-adde-c780ea21d3b5> | 2008-09-30 06:11:38 +0000 |
commit | bb564a5950a14139f59305e549ca8665b8f31cb8 (patch) | |
tree | 62054c12921f4e364b607b1cf3fded0df5605632 | |
parent | Version 2.1_rc12 (diff) | |
download | 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.h | 8 | ||||
-rw-r--r-- | configure.ac | 4 | ||||
-rw-r--r-- | debug/valgrind-suppress | 269 | ||||
-rw-r--r-- | forward.c | 8 | ||||
-rw-r--r-- | init.c | 2 | ||||
-rw-r--r-- | manage.c | 164 | ||||
-rw-r--r-- | manage.h | 9 | ||||
-rw-r--r-- | misc.c | 4 | ||||
-rw-r--r-- | misc.h | 26 | ||||
-rw-r--r-- | openvpn.8 | 27 | ||||
-rw-r--r-- | options.c | 50 | ||||
-rw-r--r-- | options.h | 7 | ||||
-rw-r--r-- | socket.c | 122 | ||||
-rw-r--r-- | socket.h | 23 | ||||
-rw-r--r-- | syshead.h | 13 | ||||
-rw-r--r-- | version.m4 | 2 |
16 files changed, 693 insertions, 45 deletions
@@ -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 +} @@ -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 /* @@ -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, @@ -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, @@ -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, @@ -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; @@ -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 @@ -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, @@ -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); @@ -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 @@ -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 @@ -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 */ @@ -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) @@ -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]) |