mirror of
https://github.com/zeromq/libzmq.git
synced 2024-12-27 07:31:03 +08: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_proxy
|
||||
tests/test_abstract_ipc
|
||||
tests/test_filter_ipc
|
||||
tests/test_connect_delay_tipc
|
||||
tests/test_pair_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.
|
||||
|
||||
|
||||
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
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
|
@ -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_ROUTER_HANDOVER 56
|
||||
#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 */
|
||||
#define ZMQ_MORE 1
|
||||
|
@ -257,6 +257,46 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
|
||||
}
|
||||
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:
|
||||
if (is_int && (value == 0 || value == 1)) {
|
||||
as_server = value;
|
||||
|
@ -50,7 +50,8 @@ noinst_PROGRAMS += test_shutdown_stress \
|
||||
test_pair_ipc \
|
||||
test_reqrep_ipc \
|
||||
test_timeo \
|
||||
test_fork
|
||||
test_fork \
|
||||
test_filter_ipc
|
||||
endif
|
||||
|
||||
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_timeo_SOURCES = test_timeo.cpp
|
||||
test_fork_SOURCES = test_fork.cpp
|
||||
test_filter_ipc_SOURCES = test_filter_ipc.cpp
|
||||
endif
|
||||
if BUILD_TIPC
|
||||
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