mirror of
https://github.com/zeromq/libzmq.git
synced 2025-11-01 11:52:57 +01:00
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.
This commit is contained in:
@@ -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;
|
||||
|
||||
|
||||
Reference in New Issue
Block a user