plain_server.cpp 8.77 KB
Newer Older
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 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq is distributed in the hope that it will be useful, but WITHOUT
    ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
    License for more details.
25 26 27 28 29

    You should have received a copy of the GNU Lesser General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

30
#include "precompiled.hpp"
31 32 33 34

#include <string>

#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 42 43
zmq::plain_server_t::plain_server_t (session_base_t *session_,
                                     const std::string &peer_address_,
                                     const options_t &options_) :
44
    mechanism_base_t (session_, options_),
45 46
    zap_client_common_handshake_t (
      session_, peer_address_, options_, sending_welcome)
47
{
48 49 50
    //  Note that there is no point to PLAIN if ZAP is not set up to handle the
    //  username and password, so if ZAP is not configured it is considered a
    //  failure.
51 52 53
    //  Given this is a backward-incompatible change, it's behind a socket
    //  option disabled by default.
    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 64 65
{
    int rc = 0;

    switch (state) {
66
        case sending_welcome:
67 68
            produce_welcome (msg_);
            state = waiting_for_initiate;
69 70
            break;
        case sending_ready:
71 72
            produce_ready (msg_);
            state = ready;
73
            break;
74
        case sending_error:
75 76
            produce_error (msg_);
            state = error_sent;
77
            break;
78 79 80
        default:
            errno = EAGAIN;
            rc = -1;
81 82 83 84
    }
    return rc;
}

85
int zmq::plain_server_t::process_handshake_command (msg_t *msg_)
86 87 88 89
{
    int rc = 0;

    switch (state) {
90
        case waiting_for_hello:
91
            rc = process_hello (msg_);
92 93
            break;
        case waiting_for_initiate:
94
            rc = process_initiate (msg_);
95 96
            break;
        default:
97 98 99
            //  TODO see comment in curve_server_t::process_handshake_command
            session->get_socket ()->event_handshake_failed_protocol (
              session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNSPECIFIED);
100
            errno = EPROTO;
101
            rc = -1;
102
            break;
103 104 105 106 107 108 109
    }
    if (rc == 0) {
        rc = msg_->close ();
        errno_assert (rc == 0);
        rc = msg_->init ();
        errno_assert (rc == 0);
    }
110
    return rc;
111 112
}

113
int zmq::plain_server_t::process_hello (msg_t *msg_)
114
{
115 116
    int rc = check_basic_command_structure (msg_);
    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 125
        session->get_socket ()->event_handshake_failed_protocol (
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
126 127 128
        errno = EPROTO;
        return -1;
    }
129 130
    ptr += hello_prefix_len;
    bytes_left -= hello_prefix_len;
131 132

    if (bytes_left < 1) {
133 134
        //  PLAIN I: invalid PLAIN client, did not send username
        session->get_socket ()->event_handshake_failed_protocol (
135 136
          session->get_endpoint (),
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
137 138 139
        errno = EPROTO;
        return -1;
    }
140
    const uint8_t username_length = *ptr++;
141
    bytes_left -= sizeof (username_length);
142

143
    if (bytes_left < username_length) {
144 145
        //  PLAIN I: invalid PLAIN client, sent malformed username
        session->get_socket ()->event_handshake_failed_protocol (
146 147
          session->get_endpoint (),
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
148 149 150
        errno = EPROTO;
        return -1;
    }
151
    const std::string username = std::string (ptr, username_length);
152 153 154
    ptr += username_length;
    bytes_left -= username_length;
    if (bytes_left < 1) {
155 156
        //  PLAIN I: invalid PLAIN client, did not send password
        session->get_socket ()->event_handshake_failed_protocol (
157 158
          session->get_endpoint (),
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
159 160 161
        errno = EPROTO;
        return -1;
    }
162

163
    const uint8_t password_length = *ptr++;
164 165 166 167
    bytes_left -= sizeof (password_length);
    if (bytes_left != password_length) {
        //  PLAIN I: invalid PLAIN client, sent malformed password or
        //  extraneous data
168
        session->get_socket ()->event_handshake_failed_protocol (
169 170
          session->get_endpoint (),
          ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_HELLO);
171 172 173
        errno = EPROTO;
        return -1;
    }
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 180 181
    if (rc != 0) {
        session->get_socket ()->event_handshake_failed_no_detail (
          session->get_endpoint (), EFAULT);
182
        return -1;
183
    }
184

185
    send_zap_request (username, password);
186 187
    state = waiting_for_zap_reply;

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 210
        session->get_socket ()->event_handshake_failed_protocol (
          session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
211 212 213
        errno = EPROTO;
        return -1;
    }
214 215
    const int rc = parse_metadata (ptr + initiate_prefix_len,
                                   bytes_left - initiate_prefix_len);
216 217 218
    if (rc == 0)
        state = sending_ready;
    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 229 230 231
    const char expected_status_code_len = 3;
    zmq_assert (status_code.length ()
                == static_cast<size_t> (expected_status_code_len));
    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 239
    memcpy (msg_data + error_prefix_len + status_code_len_size,
            status_code.c_str (), status_code.length ());
240 241
}

242 243
void zmq::plain_server_t::send_zap_request (const std::string &username_,
                                            const std::string &password_)
244
{
245
    const uint8_t *credentials[] = {
246 247 248
      reinterpret_cast<const uint8_t *> (username_.c_str ()),
      reinterpret_cast<const uint8_t *> (password_.c_str ())};
    size_t credentials_sizes[] = {username_.size (), password_.size ()};
249 250 251 252
    const char plain_mechanism_name[] = "PLAIN";
    zap_client_t::send_zap_request (
      plain_mechanism_name, sizeof (plain_mechanism_name) - 1, credentials,
      credentials_sizes, sizeof (credentials) / sizeof (credentials[0]));
253
}