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 
36 SETUP_TEARDOWN_TESTCONTEXT
37 
bounce_fail(void * server_,void * client_)38 static 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 
60 template <class T>
61 static void
run_test(int opt_,T optval_,int expected_error_,int bounce_test_)62 run_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
108 gid_t group, supgroup, notgroup;
109 
init_groups()110 void 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 
test_no_filters()130 void 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
test_filter_with_process_owner_uid()136 void test_filter_with_process_owner_uid ()
137 {
138     run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid (), 0, 1);
139 }
test_filter_with_possibly_nonexistent_uid()140 void test_filter_with_possibly_nonexistent_uid ()
141 {
142     run_test<uid_t> (ZMQ_IPC_FILTER_UID, getuid () + 1, 0, -1);
143 }
test_filter_with_process_owner_gid()144 void test_filter_with_process_owner_gid ()
145 {
146     run_test<gid_t> (ZMQ_IPC_FILTER_GID, group, 0, 1);
147 }
test_filter_with_supplemental_process_owner_gid()148 void test_filter_with_supplemental_process_owner_gid ()
149 {
150     run_test<gid_t> (ZMQ_IPC_FILTER_GID, supgroup, 0, 1);
151 }
test_filter_with_possibly_nonexistent_gid()152 void 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
test_filter_with_current_process_pid()157 void test_filter_with_current_process_pid ()
158 {
159     run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid (), 0, 1);
160 }
test_filter_with_possibly_nonexistent_pid()161 void test_filter_with_possibly_nonexistent_pid ()
162 {
163     run_test<pid_t> (ZMQ_IPC_FILTER_PID, getpid () + 1, 0, -1);
164 }
165 #else
test_filter_with_pid_fails()166 void 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
test_filter_with_zero_uid_fails()174 void test_filter_with_zero_uid_fails ()
175 {
176     run_test<uid_t> (ZMQ_IPC_FILTER_UID, 0, EINVAL, 0);
177 }
test_filter_with_zero_gid_fails()178 void test_filter_with_zero_gid_fails ()
179 {
180     run_test<gid_t> (ZMQ_IPC_FILTER_GID, 0, EINVAL, 0);
181 }
test_filter_with_zero_pid_fails()182 void 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 
main(void)188 int 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