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 
plain_server_t(session_base_t * session_,const std::string & peer_address_,const options_t & options_)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 
~plain_server_t()57 zmq::plain_server_t::~plain_server_t ()
58 {
59 }
60 
next_handshake_command(msg_t * msg_)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 
process_handshake_command(msg_t * msg_)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 
process_hello(msg_t * msg_)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 
produce_welcome(msg_t * msg_)195 void zmq::plain_server_t::produce_welcome (msg_t *msg_)
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 
process_initiate(msg_t * msg_)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 
produce_ready(msg_t * msg_) const221 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 
produce_error(msg_t * msg_) const226 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 
send_zap_request(const std::string & username_,const std::string & password_)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