mirror of
https://github.com/zeromq/libzmq.git
synced 2025-11-06 21:56:25 +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;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user