0
0
mirror of https://github.com/OpenVPN/openvpn.git synced 2024-09-19 19:42:30 +02:00

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
This commit is contained in:
james 2008-09-30 06:11:38 +00:00
parent b0cb50e7e7
commit bb564a5950
16 changed files with 695 additions and 47 deletions

View File

@ -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))

View 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

View File

@ -54,6 +54,32 @@
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
@ -175,6 +201,79 @@
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
@ -420,6 +519,26 @@
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
@ -518,6 +637,21 @@
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
@ -583,6 +717,22 @@
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
@ -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
}

View File

@ -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
/*

2
init.c
View File

@ -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,

168
manage.c
View File

@ -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);
/*
* lookup client UID/GID if specified
*/
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)
{
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);
/*
* 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;
}
#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,

View File

@ -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,

4
misc.c
View File

@ -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;

26
misc.h
View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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

122
socket.c
View File

@ -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

View File

@ -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
*/

View File

@ -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
@ -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
*/

View 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])