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
41zmq::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
57zmq::plain_server_t::~plain_server_t ()
58{
59}
60
61int 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
85int 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
113int 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
195void 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
202int 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
221void 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
226void 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
242void 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