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 <string> |
33 | |
34 | #include "msg.hpp" |
35 | #include "session_base.hpp" |
36 | #include "err.hpp" |
37 | #include "plain_server.hpp" |
38 | #include "wire.hpp" |
39 | #include "plain_common.hpp" |
40 | |
41 | zmq::plain_server_t::plain_server_t (session_base_t *session_, |
42 | const std::string &peer_address_, |
43 | const options_t &options_) : |
44 | mechanism_base_t (session_, options_), |
45 | zap_client_common_handshake_t ( |
46 | session_, peer_address_, options_, sending_welcome) |
47 | { |
48 | // Note that there is no point to PLAIN if ZAP is not set up to handle the |
49 | // username and password, so if ZAP is not configured it is considered a |
50 | // failure. |
51 | // Given this is a backward-incompatible change, it's behind a socket |
52 | // option disabled by default. |
53 | if (options.zap_enforce_domain) |
54 | zmq_assert (zap_required ()); |
55 | } |
56 | |
57 | zmq::plain_server_t::~plain_server_t () |
58 | { |
59 | } |
60 | |
61 | int zmq::plain_server_t::next_handshake_command (msg_t *msg_) |
62 | { |
63 | int rc = 0; |
64 | |
65 | switch (state) { |
66 | case sending_welcome: |
67 | produce_welcome (msg_); |
68 | state = waiting_for_initiate; |
69 | break; |
70 | case sending_ready: |
71 | produce_ready (msg_); |
72 | state = ready; |
73 | break; |
74 | case sending_error: |
75 | produce_error (msg_); |
76 | state = error_sent; |
77 | break; |
78 | default: |
79 | errno = EAGAIN; |
80 | rc = -1; |
81 | } |
82 | return rc; |
83 | } |
84 | |
85 | int zmq::plain_server_t::process_handshake_command (msg_t *msg_) |
86 | { |
87 | int rc = 0; |
88 | |
89 | switch (state) { |
90 | case waiting_for_hello: |
91 | rc = process_hello (msg_); |
92 | break; |
93 | case waiting_for_initiate: |
94 | rc = process_initiate (msg_); |
95 | break; |
96 | default: |
97 | // TODO see comment in curve_server_t::process_handshake_command |
98 | session->get_socket ()->event_handshake_failed_protocol ( |
99 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED); |
100 | errno = EPROTO; |
101 | rc = -1; |
102 | break; |
103 | } |
104 | if (rc == 0) { |
105 | rc = msg_->close (); |
106 | errno_assert (rc == 0); |
107 | rc = msg_->init (); |
108 | errno_assert (rc == 0); |
109 | } |
110 | return rc; |
111 | } |
112 | |
113 | int zmq::plain_server_t::process_hello (msg_t *msg_) |
114 | { |
115 | int rc = check_basic_command_structure (msg_); |
116 | if (rc == -1) |
117 | return -1; |
118 | |
119 | const char *ptr = static_cast<char *> (msg_->data ()); |
120 | size_t bytes_left = msg_->size (); |
121 | |
122 | if (bytes_left < hello_prefix_len |
123 | || memcmp (ptr, hello_prefix, hello_prefix_len) != 0) { |
124 | session->get_socket ()->event_handshake_failed_protocol ( |
125 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
126 | errno = EPROTO; |
127 | return -1; |
128 | } |
129 | ptr += hello_prefix_len; |
130 | bytes_left -= hello_prefix_len; |
131 | |
132 | if (bytes_left < 1) { |
133 | // PLAIN I: invalid PLAIN client, did not send username |
134 | session->get_socket ()->event_handshake_failed_protocol ( |
135 | session->get_endpoint (), |
136 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
137 | errno = EPROTO; |
138 | return -1; |
139 | } |
140 | const uint8_t username_length = *ptr++; |
141 | bytes_left -= sizeof (username_length); |
142 | |
143 | if (bytes_left < username_length) { |
144 | // PLAIN I: invalid PLAIN client, sent malformed username |
145 | session->get_socket ()->event_handshake_failed_protocol ( |
146 | session->get_endpoint (), |
147 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
148 | errno = EPROTO; |
149 | return -1; |
150 | } |
151 | const std::string username = std::string (ptr, username_length); |
152 | ptr += username_length; |
153 | bytes_left -= username_length; |
154 | if (bytes_left < 1) { |
155 | // PLAIN I: invalid PLAIN client, did not send password |
156 | session->get_socket ()->event_handshake_failed_protocol ( |
157 | session->get_endpoint (), |
158 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
159 | errno = EPROTO; |
160 | return -1; |
161 | } |
162 | |
163 | const uint8_t password_length = *ptr++; |
164 | bytes_left -= sizeof (password_length); |
165 | if (bytes_left != password_length) { |
166 | // PLAIN I: invalid PLAIN client, sent malformed password or |
167 | // extraneous data |
168 | session->get_socket ()->event_handshake_failed_protocol ( |
169 | session->get_endpoint (), |
170 | ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO); |
171 | errno = EPROTO; |
172 | return -1; |
173 | } |
174 | |
175 | const std::string password = std::string (ptr, password_length); |
176 | |
177 | // Use ZAP protocol (RFC 27) to authenticate the user. |
178 | rc = session->zap_connect (); |
179 | if (rc != 0) { |
180 | session->get_socket ()->event_handshake_failed_no_detail ( |
181 | session->get_endpoint (), EFAULT); |
182 | return -1; |
183 | } |
184 | |
185 | send_zap_request (username, password); |
186 | state = waiting_for_zap_reply; |
187 | |
188 | // TODO actually, it is quite unlikely that we can read the ZAP |
189 | // reply already, but removing this has some strange side-effect |
190 | // (probably because the pipe's in_active flag is true until a read |
191 | // is attempted) |
192 | return receive_and_process_zap_reply () == -1 ? -1 : 0; |
193 | } |
194 | |
195 | void zmq::plain_server_t::produce_welcome (msg_t *msg_) const |
196 | { |
197 | const int rc = msg_->init_size (welcome_prefix_len); |
198 | errno_assert (rc == 0); |
199 | memcpy (msg_->data (), welcome_prefix, welcome_prefix_len); |
200 | } |
201 | |
202 | int zmq::plain_server_t::process_initiate (msg_t *msg_) |
203 | { |
204 | const unsigned char *ptr = static_cast<unsigned char *> (msg_->data ()); |
205 | const size_t bytes_left = msg_->size (); |
206 | |
207 | if (bytes_left < initiate_prefix_len |
208 | || memcmp (ptr, initiate_prefix, initiate_prefix_len) != 0) { |
209 | session->get_socket ()->event_handshake_failed_protocol ( |
210 | session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND); |
211 | errno = EPROTO; |
212 | return -1; |
213 | } |
214 | const int rc = parse_metadata (ptr + initiate_prefix_len, |
215 | bytes_left - initiate_prefix_len); |
216 | if (rc == 0) |
217 | state = sending_ready; |
218 | return rc; |
219 | } |
220 | |
221 | void zmq::plain_server_t::produce_ready (msg_t *msg_) const |
222 | { |
223 | make_command_with_basic_properties (msg_, ready_prefix, ready_prefix_len); |
224 | } |
225 | |
226 | void zmq::plain_server_t::produce_error (msg_t *msg_) const |
227 | { |
228 | const char expected_status_code_len = 3; |
229 | zmq_assert (status_code.length () |
230 | == static_cast<size_t> (expected_status_code_len)); |
231 | const size_t status_code_len_size = sizeof (expected_status_code_len); |
232 | const int rc = msg_->init_size (error_prefix_len + status_code_len_size |
233 | + expected_status_code_len); |
234 | zmq_assert (rc == 0); |
235 | char *msg_data = static_cast<char *> (msg_->data ()); |
236 | memcpy (msg_data, error_prefix, error_prefix_len); |
237 | msg_data[error_prefix_len] = expected_status_code_len; |
238 | memcpy (msg_data + error_prefix_len + status_code_len_size, |
239 | status_code.c_str (), status_code.length ()); |
240 | } |
241 | |
242 | void zmq::plain_server_t::send_zap_request (const std::string &username_, |
243 | const std::string &password_) |
244 | { |
245 | const uint8_t *credentials[] = { |
246 | reinterpret_cast<const uint8_t *> (username_.c_str ()), |
247 | reinterpret_cast<const uint8_t *> (password_.c_str ())}; |
248 | size_t credentials_sizes[] = {username_.size (), password_.size ()}; |
249 | const char plain_mechanism_name[] = "PLAIN" ; |
250 | zap_client_t::send_zap_request ( |
251 | plain_mechanism_name, sizeof (plain_mechanism_name) - 1, credentials, |
252 | credentials_sizes, sizeof (credentials) / sizeof (credentials[0])); |
253 | } |
254 | |