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