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 "precompiled.hpp" |
31 | |
32 | #include "zap_client.hpp" |
33 | #include "msg.hpp" |
34 | #include "session_base.hpp" |
35 | |
36 | namespace zmq |
37 | { |
38 | const char zap_version[] = "1.0" ; |
39 | const size_t zap_version_len = sizeof (zap_version) - 1; |
40 | |
41 | const char id[] = "1" ; |
42 | const size_t id_len = sizeof (id) - 1; |
43 | |
44 | zap_client_t::zap_client_t (session_base_t *const session_, |
45 | const std::string &peer_address_, |
46 | const options_t &options_) : |
47 | mechanism_base_t (session_, options_), |
48 | peer_address (peer_address_) |
49 | { |
50 | } |
51 | |
52 | void zap_client_t::send_zap_request (const char *mechanism_, |
53 | size_t mechanism_length_, |
54 | const uint8_t *credentials_, |
55 | size_t credentials_size_) |
56 | { |
57 | send_zap_request (mechanism_, mechanism_length_, &credentials_, |
58 | &credentials_size_, 1); |
59 | } |
60 | |
61 | void zap_client_t::send_zap_request (const char *mechanism_, |
62 | size_t mechanism_length_, |
63 | const uint8_t **credentials_, |
64 | size_t *credentials_sizes_, |
65 | size_t credentials_count_) |
66 | { |
67 | // write_zap_msg cannot fail. It could only fail if the HWM was exceeded, |
68 | // but on the ZAP socket, the HWM is disabled. |
69 | |
70 | int rc; |
71 | msg_t msg; |
72 | |
73 | // Address delimiter frame |
74 | rc = msg.init (); |
75 | errno_assert (rc == 0); |
76 | msg.set_flags (msg_t::more); |
77 | rc = session->write_zap_msg (&msg); |
78 | errno_assert (rc == 0); |
79 | |
80 | // Version frame |
81 | rc = msg.init_size (zap_version_len); |
82 | errno_assert (rc == 0); |
83 | memcpy (msg.data (), zap_version, zap_version_len); |
84 | msg.set_flags (msg_t::more); |
85 | rc = session->write_zap_msg (&msg); |
86 | errno_assert (rc == 0); |
87 | |
88 | // Request ID frame |
89 | rc = msg.init_size (id_len); |
90 | errno_assert (rc == 0); |
91 | memcpy (msg.data (), id, id_len); |
92 | msg.set_flags (msg_t::more); |
93 | rc = session->write_zap_msg (&msg); |
94 | errno_assert (rc == 0); |
95 | |
96 | // Domain frame |
97 | rc = msg.init_size (options.zap_domain.length ()); |
98 | errno_assert (rc == 0); |
99 | memcpy (msg.data (), options.zap_domain.c_str (), |
100 | options.zap_domain.length ()); |
101 | msg.set_flags (msg_t::more); |
102 | rc = session->write_zap_msg (&msg); |
103 | errno_assert (rc == 0); |
104 | |
105 | // Address frame |
106 | rc = msg.init_size (peer_address.length ()); |
107 | errno_assert (rc == 0); |
108 | memcpy (msg.data (), peer_address.c_str (), peer_address.length ()); |
109 | msg.set_flags (msg_t::more); |
110 | rc = session->write_zap_msg (&msg); |
111 | errno_assert (rc == 0); |
112 | |
113 | // Routing id frame |
114 | rc = msg.init_size (options.routing_id_size); |
115 | errno_assert (rc == 0); |
116 | memcpy (msg.data (), options.routing_id, options.routing_id_size); |
117 | msg.set_flags (msg_t::more); |
118 | rc = session->write_zap_msg (&msg); |
119 | errno_assert (rc == 0); |
120 | |
121 | // Mechanism frame |
122 | rc = msg.init_size (mechanism_length_); |
123 | errno_assert (rc == 0); |
124 | memcpy (msg.data (), mechanism_, mechanism_length_); |
125 | if (credentials_count_) |
126 | msg.set_flags (msg_t::more); |
127 | rc = session->write_zap_msg (&msg); |
128 | errno_assert (rc == 0); |
129 | |
130 | // Credentials frames |
131 | for (size_t i = 0; i < credentials_count_; ++i) { |
132 | rc = msg.init_size (credentials_sizes_[i]); |
133 | errno_assert (rc == 0); |
134 | if (i < credentials_count_ - 1) |
135 | msg.set_flags (msg_t::more); |
136 | memcpy (msg.data (), credentials_[i], credentials_sizes_[i]); |
137 | rc = session->write_zap_msg (&msg); |
138 | errno_assert (rc == 0); |
139 | } |
140 | } |
141 | |
142 | int zap_client_t::receive_and_process_zap_reply () |
143 | { |
144 | int rc = 0; |
145 | const size_t zap_reply_frame_count = 7; |
146 | msg_t msg[zap_reply_frame_count]; |
147 | |
148 | // Initialize all reply frames |
149 | for (size_t i = 0; i < zap_reply_frame_count; i++) { |
150 | rc = msg[i].init (); |
151 | errno_assert (rc == 0); |
152 | } |
153 | |
154 | for (size_t i = 0; i < zap_reply_frame_count; i++) { |
155 | rc = session->read_zap_msg (&msg[i]); |
156 | if (rc == -1) { |
157 | if (errno == EAGAIN) { |
158 | return 1; |
159 | } |
160 | return close_and_return (msg, -1); |
161 | } |
162 | if ((msg[i].flags () & msg_t::more) |
163 | == (i < zap_reply_frame_count - 1 ? 0 : msg_t::more)) { |
164 | session->get_socket ()->event_handshake_failed_protocol ( |
165 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_MALFORMED_REPLY); |
166 | errno = EPROTO; |
167 | return close_and_return (msg, -1); |
168 | } |
169 | } |
170 | |
171 | // Address delimiter frame |
172 | if (msg[0].size () > 0) { |
173 | // TODO can a ZAP handler produce such a message at all? |
174 | session->get_socket ()->event_handshake_failed_protocol ( |
175 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_UNSPECIFIED); |
176 | errno = EPROTO; |
177 | return close_and_return (msg, -1); |
178 | } |
179 | |
180 | // Version frame |
181 | if (msg[1].size () != zap_version_len |
182 | || memcmp (msg[1].data (), zap_version, zap_version_len)) { |
183 | session->get_socket ()->event_handshake_failed_protocol ( |
184 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_VERSION); |
185 | errno = EPROTO; |
186 | return close_and_return (msg, -1); |
187 | } |
188 | |
189 | // Request id frame |
190 | if (msg[2].size () != id_len || memcmp (msg[2].data (), id, id_len)) { |
191 | session->get_socket ()->event_handshake_failed_protocol ( |
192 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_BAD_REQUEST_ID); |
193 | errno = EPROTO; |
194 | return close_and_return (msg, -1); |
195 | } |
196 | |
197 | // Status code frame, only 200, 300, 400 and 500 are valid status codes |
198 | const char *status_code_data = static_cast<const char *> (msg[3].data ()); |
199 | if (msg[3].size () != 3 || status_code_data[0] < '2' |
200 | || status_code_data[0] > '5' || status_code_data[1] != '0' |
201 | || status_code_data[2] != '0') { |
202 | session->get_socket ()->event_handshake_failed_protocol ( |
203 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_STATUS_CODE); |
204 | errno = EPROTO; |
205 | return close_and_return (msg, -1); |
206 | } |
207 | |
208 | // Save status code |
209 | status_code.assign (static_cast<char *> (msg[3].data ()), 3); |
210 | |
211 | // Save user id |
212 | set_user_id (msg[5].data (), msg[5].size ()); |
213 | |
214 | // Process metadata frame |
215 | rc = parse_metadata (static_cast<const unsigned char *> (msg[6].data ()), |
216 | msg[6].size (), true); |
217 | |
218 | if (rc != 0) { |
219 | session->get_socket ()->event_handshake_failed_protocol ( |
220 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZAP_INVALID_METADATA); |
221 | errno = EPROTO; |
222 | return close_and_return (msg, -1); |
223 | } |
224 | |
225 | // Close all reply frames |
226 | for (size_t i = 0; i < zap_reply_frame_count; i++) { |
227 | const int rc2 = msg[i].close (); |
228 | errno_assert (rc2 == 0); |
229 | } |
230 | |
231 | handle_zap_status_code (); |
232 | |
233 | return 0; |
234 | } |
235 | |
236 | void zap_client_t::handle_zap_status_code () |
237 | { |
238 | // we can assume here that status_code is a valid ZAP status code, |
239 | // i.e. 200, 300, 400 or 500 |
240 | int status_code_numeric = 0; |
241 | switch (status_code[0]) { |
242 | case '2': |
243 | return; |
244 | case '3': |
245 | status_code_numeric = 300; |
246 | break; |
247 | case '4': |
248 | status_code_numeric = 400; |
249 | break; |
250 | case '5': |
251 | status_code_numeric = 500; |
252 | break; |
253 | } |
254 | |
255 | session->get_socket ()->event_handshake_failed_auth ( |
256 | session->get_endpoint (), status_code_numeric); |
257 | } |
258 | |
259 | zap_client_common_handshake_t::zap_client_common_handshake_t ( |
260 | session_base_t *const session_, |
261 | const std::string &peer_address_, |
262 | const options_t &options_, |
263 | state_t zap_reply_ok_state_) : |
264 | mechanism_base_t (session_, options_), |
265 | zap_client_t (session_, peer_address_, options_), |
266 | state (waiting_for_hello), |
267 | _zap_reply_ok_state (zap_reply_ok_state_) |
268 | { |
269 | } |
270 | |
271 | zmq::mechanism_t::status_t zap_client_common_handshake_t::status () const |
272 | { |
273 | if (state == ready) |
274 | return mechanism_t::ready; |
275 | if (state == error_sent) |
276 | return mechanism_t::error; |
277 | |
278 | return mechanism_t::handshaking; |
279 | } |
280 | |
281 | int zap_client_common_handshake_t::zap_msg_available () |
282 | { |
283 | zmq_assert (state == waiting_for_zap_reply); |
284 | return receive_and_process_zap_reply () == -1 ? -1 : 0; |
285 | } |
286 | |
287 | void zap_client_common_handshake_t::handle_zap_status_code () |
288 | { |
289 | zap_client_t::handle_zap_status_code (); |
290 | |
291 | // we can assume here that status_code is a valid ZAP status code, |
292 | // i.e. 200, 300, 400 or 500 |
293 | switch (status_code[0]) { |
294 | case '2': |
295 | state = _zap_reply_ok_state; |
296 | break; |
297 | case '3': |
298 | // a 300 error code (temporary failure) |
299 | // should NOT result in an ERROR message, but instead the |
300 | // client should be silently disconnected (see CURVEZMQ RFC) |
301 | // therefore, go immediately to state error_sent |
302 | state = error_sent; |
303 | break; |
304 | default: |
305 | state = sending_error; |
306 | } |
307 | } |
308 | |
309 | int zap_client_common_handshake_t::receive_and_process_zap_reply () |
310 | { |
311 | zmq_assert (state == waiting_for_zap_reply); |
312 | return zap_client_t::receive_and_process_zap_reply (); |
313 | } |
314 | } |
315 | |