Commit 8662f44e authored by Brandon Carpenter's avatar Brandon Carpenter

Intial IPC accept filter support.

Adds sets of process (Linux only), user, and group IDs for filtering
connections from peer processes over IPC transport.  If all of the
filter sets are empty, every connection is accepted.  Otherwise,
credentials for a connecting process are checked against the filter sets
and the connection is only accepted if a match is found.

This commit is part of LIBZMQ-568 and only adds the filter sets and
implements the filter in the IPC accept method.  The interface for
adding IDs to filter sets are included in a separate commit.

IPC accept filtering is supported only on Linux and OS X.
parent a9492a08
......@@ -170,6 +170,7 @@ case "${host_os}" in
fi
AC_DEFINE(ZMQ_HAVE_LINUX, 1, [Have Linux OS])
libzmq_on_linux="yes"
AC_CHECK_DECLS([SO_PEERCRED], [AC_DEFINE(ZMQ_HAVE_SO_PEERCRED, 1, [Have SO_PEERCRED socket option])], [], [#include <sys/socket.h>])
if test "x$libzmq_tipc_support" = "xyes"; then
AC_DEFINE(ZMQ_HAVE_TIPC, 1, [Have TIPC support])
......@@ -215,6 +216,7 @@ case "${host_os}" in
libzmq_pedantic="no"
libzmq_werror="no"
AC_DEFINE(ZMQ_HAVE_OSX, 1, [Have DarwinOSX OS])
AC_CHECK_DECLS([LOCAL_PEERCRED], [AC_DEFINE(ZMQ_HAVE_LOCAL_PEERCRED, 1, [Have LOCAL_PEERCRED socket option])], [], [#include <sys/socket.h>])
AC_LANG_PUSH([C++])
LIBZMQ_CHECK_LANG_FLAG_PREPEND([-Wno-uninitialized])
AC_LANG_POP([C++])
......
......@@ -39,6 +39,14 @@
#include <fcntl.h>
#include <sys/un.h>
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
# include <sys/types.h>
#endif
#ifdef ZMQ_HAVE_SO_PEERCRED
# include <pwd.h>
# include <grp.h>
#endif
zmq::ipc_listener_t::ipc_listener_t (io_thread_t *io_thread_,
socket_base_t *socket_, const options_t &options_) :
own_t (io_thread_, options_),
......@@ -192,6 +200,67 @@ int zmq::ipc_listener_t::close ()
return 0;
}
#if defined ZMQ_HAVE_SO_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock)
{
if (options.ipc_uid_accept_filters.empty () &&
options.ipc_pid_accept_filters.empty () &&
options.ipc_gid_accept_filters.empty ())
return true;
struct ucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock, SOL_SOCKET, SO_PEERCRED, &cred, &size))
return false;
if (options.ipc_uid_accept_filters.find (cred.uid) != options.ipc_uid_accept_filters.end () ||
options.ipc_pid_accept_filters.find (cred.pid) != options.ipc_pid_accept_filters.end ())
return true;
struct passwd *pw;
struct group *gr;
if (!(pw = getpwuid (cred.uid)))
return false;
for (options_t::ipc_gid_accept_filters_t::const_iterator it = options.ipc_gid_accept_filters.begin ();
it != options.ipc_gid_accept_filters.end (); it++) {
if (!(gr = getgrgid (*it)))
continue;
for (char **mem = gr->gr_mem; *mem; mem++)
if (!strcmp (*mem, pw->pw_name))
return true;
}
return false;
}
#elif defined ZMQ_HAVE_LOCAL_PEERCRED
bool zmq::ipc_listener_t::filter (fd_t sock)
{
if (options.ipc_uid_accept_filters.empty () &&
options.ipc_gid_accept_filters.empty ())
return true;
struct xucred cred;
socklen_t size = sizeof (cred);
if (getsockopt (sock, 0, LOCAL_PEERCRED, &cred, &size))
return false;
if (cred.cr_version != XUCRED_VERSION)
return false;
if (options.ipc_uid_accept_filters.find (cred.cr_uid) != options.ipc_uid_accept_filters.end ())
return true;
for (int i = 0; i < cred.cr_ngroups; i++) {
if (options.ipc_gid_accept_filters.find (cred.cr_groups[i]) != options.ipc_gid_accept_filters.end ())
return true;
}
return false;
}
#endif
zmq::fd_t zmq::ipc_listener_t::accept ()
{
// Accept one connection and deal with different failure modes.
......@@ -205,6 +274,16 @@ zmq::fd_t zmq::ipc_listener_t::accept ()
errno == ENFILE);
return retired_fd;
}
// IPC accept() filters
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
if (!filter (sock)) {
int rc = ::close (sock);
errno_assert (rc == 0);
return retired_fd;
}
#endif
return sock;
}
......
......@@ -63,6 +63,12 @@ namespace zmq
// Close the listening socket.
int close ();
// Filter new connections if the OS provides a mechanism to get
// the credentials of the peer process. Called from accept().
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
bool filter (fd_t sock);
# endif
// Accept the new connection. Returns the file descriptor of the
// newly created connection. The function may return retired_fd
// if the connection was dropped while waiting in the listen backlog.
......
......@@ -22,12 +22,17 @@
#include <string>
#include <vector>
#include <set>
#include "stddef.h"
#include "stdint.hpp"
#include "tcp_address.hpp"
#include "../include/zmq.h"
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
#include <sys/types.h>
#endif
// Normal base 256 key is 32 bytes
#define CURVE_KEYSIZE 32
// Key encoded using Z85 is 40 bytes
......@@ -120,6 +125,18 @@ namespace zmq
typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t;
tcp_accept_filters_t tcp_accept_filters;
// IPC accept() filters
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
typedef std::set <uid_t> ipc_uid_accept_filters_t;
ipc_uid_accept_filters_t ipc_uid_accept_filters;
typedef std::set <gid_t> ipc_gid_accept_filters_t;
ipc_gid_accept_filters_t ipc_gid_accept_filters;
# endif
# if defined ZMQ_HAVE_SO_PEERCRED
typedef std::set <pid_t> ipc_pid_accept_filters_t;
ipc_pid_accept_filters_t ipc_pid_accept_filters;
# endif
// Security mechanism for all connections on this socket
int mechanism;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment