mirror of
https://github.com/zeromq/libzmq.git
synced 2025-03-19 18:03:50 +00:00
Add IPC accept filter socket options.
Adds ZMQ_IPC_ACCEPT_FILTER_{PID,UID,GID} socket options to add processs, user, and group IDs to the IPC filter sets. Fixes LIBZMQ-568.
This commit is contained in:
parent
8662f44efa
commit
2252322acc
1
.gitignore
vendored
1
.gitignore
vendored
@ -72,6 +72,7 @@ tests/test_security_null
|
|||||||
tests/test_security_plain
|
tests/test_security_plain
|
||||||
tests/test_proxy
|
tests/test_proxy
|
||||||
tests/test_abstract_ipc
|
tests/test_abstract_ipc
|
||||||
|
tests/test_filter_ipc
|
||||||
tests/test_connect_delay_tipc
|
tests/test_connect_delay_tipc
|
||||||
tests/test_pair_tipc
|
tests/test_pair_tipc
|
||||||
tests/test_reqrep_device_tipc
|
tests/test_reqrep_device_tipc
|
||||||
|
@ -601,6 +601,68 @@ Default value:: no filters (allow from all)
|
|||||||
Applicable socket types:: all listening sockets, when using TCP transports.
|
Applicable socket types:: all listening sockets, when using TCP transports.
|
||||||
|
|
||||||
|
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_UID: Assign user ID filters to allow new IPC connections
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Assign an arbitrary number of filters that will be applied for each new IPC
|
||||||
|
transport connection on a listening socket. If no IPC filters are applied, then
|
||||||
|
the IPC transport allows connections from any process. If at least one UID,
|
||||||
|
GID, or PID filter is applied then new connection credentials should be
|
||||||
|
matched. To clear all UID filters call zmq_setsockopt(socket,
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_UID, NULL, 0).
|
||||||
|
|
||||||
|
NOTE: UID filters are only available on platforms supporting SO_PEERCRED or
|
||||||
|
LOCAL_PEERCRED socket options (currently only Linux and later versions of
|
||||||
|
OS X).
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
Option value type:: uid_t
|
||||||
|
Option value unit:: N/A
|
||||||
|
Default value:: no filters (allow from all)
|
||||||
|
Applicable socket types:: all listening sockets, when using IPC transports.
|
||||||
|
|
||||||
|
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_GID: Assign group ID filters to allow new IPC connections
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Assign an arbitrary number of filters that will be applied for each new IPC
|
||||||
|
transport connection on a listening socket. If no IPC filters are applied, then
|
||||||
|
the IPC transport allows connections from any process. If at least one UID,
|
||||||
|
GID, or PID filter is applied then new connection credentials should be
|
||||||
|
matched. To clear all GID filters call zmq_setsockopt(socket,
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_GID, NULL, 0).
|
||||||
|
|
||||||
|
NOTE: GID filters are only available on platforms supporting SO_PEERCRED or
|
||||||
|
LOCAL_PEERCRED socket options (currently only Linux and later versions of
|
||||||
|
OS X).
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
Option value type:: gid_t
|
||||||
|
Option value unit:: N/A
|
||||||
|
Default value:: no filters (allow from all)
|
||||||
|
Applicable socket types:: all listening sockets, when using IPC transports.
|
||||||
|
|
||||||
|
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_PID: Assign process ID filters to new IPC connections
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Assign an arbitrary number of filters that will be applied for each new IPC
|
||||||
|
transport connection on a listening socket. If no IPC filters are applied, then
|
||||||
|
the IPC transport allows connections from any process. If at least one UID,
|
||||||
|
GID, or PID filter is applied then new connection credentials should be
|
||||||
|
matched. To clear all PID filters call zmq_setsockopt(socket,
|
||||||
|
ZMQ_IPC_ACCEPT_FILTER_PID, NULL, 0).
|
||||||
|
|
||||||
|
NOTE: PID filters are only available on platforms supporting the SO_PEERCRED
|
||||||
|
socket option (currently only Linux).
|
||||||
|
|
||||||
|
[horizontal]
|
||||||
|
Option value type:: pid_t
|
||||||
|
Option value unit:: N/A
|
||||||
|
Default value:: no filters (allow from all)
|
||||||
|
Applicable socket types:: all listening sockets, when using IPC transports.
|
||||||
|
|
||||||
|
|
||||||
ZMQ_PLAIN_SERVER: Set PLAIN server role
|
ZMQ_PLAIN_SERVER: Set PLAIN server role
|
||||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
@ -290,6 +290,9 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
|
|||||||
#define ZMQ_ZAP_DOMAIN 55
|
#define ZMQ_ZAP_DOMAIN 55
|
||||||
#define ZMQ_ROUTER_HANDOVER 56
|
#define ZMQ_ROUTER_HANDOVER 56
|
||||||
#define ZMQ_TOS 57
|
#define ZMQ_TOS 57
|
||||||
|
#define ZMQ_IPC_ACCEPT_FILTER_PID 58
|
||||||
|
#define ZMQ_IPC_ACCEPT_FILTER_UID 59
|
||||||
|
#define ZMQ_IPC_ACCEPT_FILTER_GID 60
|
||||||
|
|
||||||
/* Message options */
|
/* Message options */
|
||||||
#define ZMQ_MORE 1
|
#define ZMQ_MORE 1
|
||||||
|
@ -257,6 +257,46 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
# if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||||
|
case ZMQ_IPC_ACCEPT_FILTER_UID:
|
||||||
|
if (optvallen_ == 0 && optval_ == NULL) {
|
||||||
|
ipc_uid_accept_filters.clear ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (optvallen_ == sizeof (uid_t) && optval_ != NULL) {
|
||||||
|
ipc_uid_accept_filters.insert (*((uid_t *) optval_));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ZMQ_IPC_ACCEPT_FILTER_GID:
|
||||||
|
if (optvallen_ == 0 && optval_ == NULL) {
|
||||||
|
ipc_gid_accept_filters.clear ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (optvallen_ == sizeof (gid_t) && optval_ != NULL) {
|
||||||
|
ipc_gid_accept_filters.insert (*((gid_t *) optval_));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
# endif
|
||||||
|
|
||||||
|
# if defined ZMQ_HAVE_SO_PEERCRED
|
||||||
|
case ZMQ_IPC_ACCEPT_FILTER_PID:
|
||||||
|
if (optvallen_ == 0 && optval_ == NULL) {
|
||||||
|
ipc_pid_accept_filters.clear ();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
if (optvallen_ == sizeof (pid_t) && optval_ != NULL) {
|
||||||
|
ipc_pid_accept_filters.insert (*((pid_t *) optval_));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
# endif
|
||||||
|
|
||||||
case ZMQ_PLAIN_SERVER:
|
case ZMQ_PLAIN_SERVER:
|
||||||
if (is_int && (value == 0 || value == 1)) {
|
if (is_int && (value == 0 || value == 1)) {
|
||||||
as_server = value;
|
as_server = value;
|
||||||
|
@ -50,7 +50,8 @@ noinst_PROGRAMS += test_shutdown_stress \
|
|||||||
test_pair_ipc \
|
test_pair_ipc \
|
||||||
test_reqrep_ipc \
|
test_reqrep_ipc \
|
||||||
test_timeo \
|
test_timeo \
|
||||||
test_fork
|
test_fork \
|
||||||
|
test_filter_ipc
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if BUILD_TIPC
|
if BUILD_TIPC
|
||||||
@ -111,6 +112,7 @@ test_pair_ipc_SOURCES = test_pair_ipc.cpp testutil.hpp
|
|||||||
test_reqrep_ipc_SOURCES = test_reqrep_ipc.cpp testutil.hpp
|
test_reqrep_ipc_SOURCES = test_reqrep_ipc.cpp testutil.hpp
|
||||||
test_timeo_SOURCES = test_timeo.cpp
|
test_timeo_SOURCES = test_timeo.cpp
|
||||||
test_fork_SOURCES = test_fork.cpp
|
test_fork_SOURCES = test_fork.cpp
|
||||||
|
test_filter_ipc_SOURCES = test_filter_ipc.cpp
|
||||||
endif
|
endif
|
||||||
if BUILD_TIPC
|
if BUILD_TIPC
|
||||||
test_connect_delay_tipc_SOURCES = test_connect_delay_tipc.cpp
|
test_connect_delay_tipc_SOURCES = test_connect_delay_tipc.cpp
|
||||||
|
141
tests/test_filter_ipc.cpp
Normal file
141
tests/test_filter_ipc.cpp
Normal file
@ -0,0 +1,141 @@
|
|||||||
|
/*
|
||||||
|
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
|
||||||
|
|
||||||
|
This file is part of 0MQ.
|
||||||
|
|
||||||
|
0MQ is free software; you can redistribute it and/or modify it under
|
||||||
|
the terms of the GNU Lesser General Public License as published by
|
||||||
|
the Free Software Foundation; either version 3 of the License, or
|
||||||
|
(at your option) any later version.
|
||||||
|
|
||||||
|
0MQ is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||||
|
GNU Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public License
|
||||||
|
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
|
||||||
|
#include "testutil.hpp"
|
||||||
|
|
||||||
|
static void bounce_fail (void *server, void *client)
|
||||||
|
{
|
||||||
|
const char *content = "12345678ABCDEFGH12345678abcdefgh";
|
||||||
|
char buffer [32];
|
||||||
|
|
||||||
|
// Send message from client to server
|
||||||
|
int rc = zmq_send (client, content, 32, ZMQ_SNDMORE);
|
||||||
|
assert (rc == 32);
|
||||||
|
rc = zmq_send (client, content, 32, 0);
|
||||||
|
assert (rc == 32);
|
||||||
|
|
||||||
|
// Receive message at server side (should not succeed)
|
||||||
|
int timeout = 150;
|
||||||
|
rc = zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (int));
|
||||||
|
assert (rc == 0);
|
||||||
|
rc = zmq_recv (server, buffer, 32, 0);
|
||||||
|
assert (rc == -1);
|
||||||
|
assert (zmq_errno () == EAGAIN);
|
||||||
|
|
||||||
|
// Send message from server to client to test other direction
|
||||||
|
rc = zmq_setsockopt (server, ZMQ_SNDTIMEO, &timeout, sizeof (int));
|
||||||
|
assert (rc == 0);
|
||||||
|
rc = zmq_send (server, content, 32, ZMQ_SNDMORE);
|
||||||
|
assert (rc == -1);
|
||||||
|
assert (zmq_errno () == EAGAIN);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class T>
|
||||||
|
static void run_test (int opt, T optval, int expected_error, int bounce_test)
|
||||||
|
{
|
||||||
|
void *ctx = zmq_ctx_new ();
|
||||||
|
assert (ctx);
|
||||||
|
|
||||||
|
void *sb = zmq_socket (ctx, ZMQ_PAIR);
|
||||||
|
assert (sb);
|
||||||
|
|
||||||
|
if (opt) {
|
||||||
|
int rc = zmq_setsockopt(sb, opt, &optval, sizeof (optval));
|
||||||
|
if (expected_error) {
|
||||||
|
assert (rc == -1);
|
||||||
|
assert (zmq_errno () == expected_error);
|
||||||
|
} else {
|
||||||
|
assert (rc == 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *sc = zmq_socket (ctx, ZMQ_PAIR);
|
||||||
|
assert (sc);
|
||||||
|
|
||||||
|
if (bounce_test) {
|
||||||
|
int rc = zmq_bind (sb, "ipc://@/tmp/test");
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
rc = zmq_connect (sc, "ipc://@/tmp/test");
|
||||||
|
assert (rc == 0);
|
||||||
|
|
||||||
|
if (bounce_test > 0)
|
||||||
|
bounce (sb, sc);
|
||||||
|
else
|
||||||
|
bounce_fail (sb, sc);
|
||||||
|
}
|
||||||
|
|
||||||
|
close_zero_linger (sc);
|
||||||
|
close_zero_linger (sb);
|
||||||
|
|
||||||
|
int rc = zmq_ctx_term (ctx);
|
||||||
|
assert (rc == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int main (void)
|
||||||
|
{
|
||||||
|
setup_test_environment();
|
||||||
|
|
||||||
|
// No filters
|
||||||
|
run_test<int> (0, 0, 0, 1);
|
||||||
|
|
||||||
|
#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||||
|
// Get the group and supplimental groups of the process owner
|
||||||
|
gid_t groups[100];
|
||||||
|
int ngroups = getgroups(100, groups);
|
||||||
|
assert (ngroups != -1);
|
||||||
|
gid_t group = getgid(), supgroup = groups[0], notgroup = groups[ngroups - 1] + 1;
|
||||||
|
for (int i = 0; i < ngroups; i++) {
|
||||||
|
if (supgroup == group && group != groups[i])
|
||||||
|
supgroup = groups[i];
|
||||||
|
if (notgroup <= groups[i])
|
||||||
|
notgroup = groups[i] + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Test filter with UID of process owner
|
||||||
|
run_test<uid_t> (ZMQ_IPC_ACCEPT_FILTER_UID, getuid(), 0, 1);
|
||||||
|
// Test filter with UID of another (possibly non-existent) user
|
||||||
|
run_test<uid_t> (ZMQ_IPC_ACCEPT_FILTER_UID, getuid() + 1, 0, -1);
|
||||||
|
// Test filter with GID of process owner
|
||||||
|
run_test<gid_t> (ZMQ_IPC_ACCEPT_FILTER_GID, group, 0, 1);
|
||||||
|
// Test filter with supplimental group of process owner
|
||||||
|
run_test<gid_t> (ZMQ_IPC_ACCEPT_FILTER_GID, supgroup, 0, 1);
|
||||||
|
// Test filter with GID of another (possibly non-existent) group
|
||||||
|
run_test<gid_t> (ZMQ_IPC_ACCEPT_FILTER_GID, notgroup, 0, -1);
|
||||||
|
# if defined ZMQ_HAVE_SO_PEERCRED
|
||||||
|
// Test filter with PID of current process
|
||||||
|
run_test<pid_t> (ZMQ_IPC_ACCEPT_FILTER_PID, getpid(), 0, 1);
|
||||||
|
// Test filter with PID of another (possibly non-existent) process
|
||||||
|
run_test<pid_t> (ZMQ_IPC_ACCEPT_FILTER_PID, getpid() + 1, 0, -1);
|
||||||
|
# else
|
||||||
|
// Setup of PID filter should fail with operation not supported error
|
||||||
|
run_test<pid_t> (ZMQ_IPC_ACCEPT_FILTER_PID, getpid(), EINVAL, 0);
|
||||||
|
# endif
|
||||||
|
#else
|
||||||
|
run_test<uid_t> (ZMQ_IPC_ACCEPT_FILTER_UID, 0, EINVAL, 0);
|
||||||
|
run_test<gid_t> (ZMQ_IPC_ACCEPT_FILTER_GID, 0, EINVAL, 0);
|
||||||
|
run_test<pid_t> (ZMQ_IPC_ACCEPT_FILTER_PID, 0, EINVAL, 0);
|
||||||
|
#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
|
||||||
|
|
||||||
|
return 0 ;
|
||||||
|
}
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user