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
36namespace zmq
37{
38const char zap_version[] = "1.0";
39const size_t zap_version_len = sizeof (zap_version) - 1;
40
41const char id[] = "1";
42const size_t id_len = sizeof (id) - 1;
43
44zap_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
52void 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
61void 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
142int 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
236void 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
259zap_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
271zmq::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
281int 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
287void 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
309int 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