1/*
2 Copyright (c) 2007-2016 Contributors as noted in the AUTHORS file
3
4 This file is part of libzmq, the ZeroMQ core engine in C++.
5
6 libzmq is free software; you can redistribute it and/or modify it under
7 the terms of the GNU Lesser General Public License (LGPL) as published
8 by the Free Software Foundation; either version 3 of the License, or
9 (at your option) any later version.
10
11 As a special exception, the Contributors give you permission to link
12 this library with independent modules to produce an executable,
13 regardless of the license terms of these independent modules, and to
14 copy and distribute the resulting executable under terms of your choice,
15 provided that you also meet, for each linked independent module, the
16 terms and conditions of the license of that module. An independent
17 module is a module which is not derived from or based on this library.
18 If you modify this library, you must extend this exception to your
19 version of the library.
20
21 libzmq is distributed in the hope that it will be useful, but WITHOUT
22 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
23 FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
24 License for more details.
25
26 You should have received a copy of the GNU Lesser General Public License
27 along with this program. If not, see <http://www.gnu.org/licenses/>.
28*/
29
30#include "testutil.hpp"
31#include "testutil_unity.hpp"
32
33#include <unistd.h>
34#include <grp.h>
35
36SETUP_TEARDOWN_TESTCONTEXT
37
38static void bounce_fail (void *server_, void *client_)
39{
40 const char *content = "12345678ABCDEFGH12345678abcdefgh";
41 char buffer[32];
42
43 // Send message from client to server
44 send_string_expect_success (client_, content, ZMQ_SNDMORE);
45 send_string_expect_success (client_, content, 0);
46
47 // Receive message at server side (should not succeed)
48 int timeout = SETTLE_TIME;
49 TEST_ASSERT_SUCCESS_ERRNO (
50 zmq_setsockopt (server_, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
51 TEST_ASSERT_FAILURE_ERRNO (EAGAIN, zmq_recv (server_, buffer, 32, 0));
52
53 // Send message from server to client to test other direction
54 TEST_ASSERT_SUCCESS_ERRNO (
55 zmq_setsockopt (server_, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
56 TEST_ASSERT_FAILURE_ERRNO (EAGAIN,
57 zmq_send (server_, content, 32, ZMQ_SNDMORE));
58}
59
60template <class T>
61static void
62run_test (int opt_, T optval_, int expected_error_, int bounce_test_)
63{
64 void *sb = test_context_socket (ZMQ_DEALER);
65
66 if (opt_) {
67 const int rc = zmq_setsockopt (sb, opt_, &optval_, sizeof (optval_));
68 if (expected_error_) {
69 TEST_ASSERT_FAILURE_ERRNO (expected_error_, rc);
70 } else {
71 TEST_ASSERT_SUCCESS_ERRNO (rc);
72 }
73 }
74
75 void *sc = test_context_socket (ZMQ_DEALER);
76
77 // If a test fails, don't hang for too long
78 int timeout = 2500;
79 TEST_ASSERT_SUCCESS_ERRNO (
80 zmq_setsockopt (sb, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
81 TEST_ASSERT_SUCCESS_ERRNO (
82 zmq_setsockopt (sb, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
83 TEST_ASSERT_SUCCESS_ERRNO (
84 zmq_setsockopt (sc, ZMQ_RCVTIMEO, &timeout, sizeof (int)));
85 TEST_ASSERT_SUCCESS_ERRNO (
86 zmq_setsockopt (sc, ZMQ_SNDTIMEO, &timeout, sizeof (int)));
87 int interval = -1;
88 TEST_ASSERT_SUCCESS_ERRNO (
89 zmq_setsockopt (sc, ZMQ_RECONNECT_IVL, &interval, sizeof (int)));
90
91 if (bounce_test_) {
92 const char *endpoint = "ipc://test_filter_ipc.sock";
93 TEST_ASSERT_SUCCESS_ERRNO (zmq_bind (sb, endpoint));
94 TEST_ASSERT_SUCCESS_ERRNO (zmq_connect (sc, endpoint));
95
96 if (bounce_test_ > 0)
97 bounce (sb, sc);
98 else
99 bounce_fail (sb, sc);
100 }
101
102 // TODO only use zero linger when bounce_test_ < 0?
103 test_context_socket_close_zero_linger (sc);
104 test_context_socket_close_zero_linger (sb);
105}
106
107#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
108gid_t group, supgroup, notgroup;
109
110void init_groups ()
111{
112 // Get the group and supplemental groups of the process owner
113 gid_t groups[100];
114 int ngroups = getgroups (100, groups);
115 TEST_ASSERT_NOT_EQUAL (-1, ngroups);
116 group = getgid ();
117 supgroup = group;
118 notgroup = group + 1;
119 for (int i = 0; i < ngroups; i++) {
120 if (supgroup == group && group != groups[i]) {
121 if (getgrgid (groups[i]))
122 supgroup = groups[i];
123 }
124 if (notgroup <= groups[i])
125 notgroup = groups[i] + 1;
126 }
127}
128#endif
129
130void test_no_filters ()
131{
132 run_test<int> (0, 0, 0, 1);
133}
134
135#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
136void test_filter_with_process_owner_uid ()
137{
138 run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid (), 0, 1);
139}
140void test_filter_with_possibly_nonexistent_uid ()
141{
142 run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid () + 1, 0, -1);
143}
144void test_filter_with_process_owner_gid ()
145{
146 run_test<gid_t> (ZMQ_IPC_FILTER_GID, group, 0, 1);
147}
148void test_filter_with_supplemental_process_owner_gid ()
149{
150 run_test<gid_t> (ZMQ_IPC_FILTER_GID, supgroup, 0, 1);
151}
152void test_filter_with_possibly_nonexistent_gid ()
153{
154 run_test<gid_t> (ZMQ_IPC_FILTER_GID, notgroup, 0, -1);
155}
156#if defined ZMQ_HAVE_SO_PEERCRED
157void test_filter_with_current_process_pid ()
158{
159 run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), 0, 1);
160}
161void test_filter_with_possibly_nonexistent_pid ()
162{
163 run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid () + 1, 0, -1);
164}
165#else
166void test_filter_with_pid_fails ()
167{
168 // Setup of PID filter should fail with operation not supported error
169 // TODO EINVAL is not ENOTSUP (!)
170 run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), EINVAL, 0);
171}
172#endif
173#else
174void test_filter_with_zero_uid_fails ()
175{
176 run_test<uid_t> (ZMQ_IPC_FILTER_UID, 0, EINVAL, 0);
177}
178void test_filter_with_zero_gid_fails ()
179{
180 run_test<gid_t> (ZMQ_IPC_FILTER_GID, 0, EINVAL, 0);
181}
182void test_filter_with_zero_pid_fails ()
183{
184 run_test<pid_t> (ZMQ_IPC_FILTER_PID, 0, EINVAL, 0);
185}
186#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
187
188int main (void)
189{
190#if !defined(ZMQ_HAVE_WINDOWS)
191 setup_test_environment ();
192
193#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
194 init_groups ();
195#endif
196
197 UNITY_BEGIN ();
198 RUN_TEST (test_no_filters);
199#if defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
200 RUN_TEST (test_filter_with_process_owner_uid);
201 RUN_TEST (test_filter_with_possibly_nonexistent_uid);
202 RUN_TEST (test_filter_with_process_owner_gid);
203 RUN_TEST (test_filter_with_supplemental_process_owner_gid);
204 RUN_TEST (test_filter_with_possibly_nonexistent_gid);
205#if defined ZMQ_HAVE_SO_PEERCRED
206 RUN_TEST (test_filter_with_current_process_pid);
207 RUN_TEST (test_filter_with_possibly_nonexistent_pid);
208#else
209 RUN_TEST (test_filter_with_pid_fails);
210#endif
211#else
212 RUN_TEST (test_filter_with_zero_uid_fails);
213 RUN_TEST (test_filter_with_zero_gid_fails);
214 RUN_TEST (test_filter_with_zero_pid_fails);
215#endif // defined ZMQ_HAVE_SO_PEERCRED || defined ZMQ_HAVE_LOCAL_PEERCRED
216 return UNITY_END ();
217#else
218 return 0;
219#endif
220}
221