From 22d6a97403379d0c550a69471e44ffee1350d959 Mon Sep 17 00:00:00 2001 From: Martin Hurton Date: Mon, 12 May 2014 06:08:28 +0200 Subject: [PATCH] Split plain_mechanism into client and server part --- src/Makefile.am | 6 +- src/plain_client.cpp | 185 ++++++++++++++++++ src/plain_client.hpp | 64 ++++++ src/{plain_mechanism.cpp => plain_server.cpp} | 153 ++------------- src/{plain_mechanism.hpp => plain_server.hpp} | 22 +-- src/stream_engine.cpp | 11 +- 6 files changed, 289 insertions(+), 152 deletions(-) create mode 100644 src/plain_client.cpp create mode 100644 src/plain_client.hpp rename src/{plain_mechanism.cpp => plain_server.cpp} (68%) rename src/{plain_mechanism.hpp => plain_server.hpp} (74%) diff --git a/src/Makefile.am b/src/Makefile.am index 3551233e..dae104dd 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -59,7 +59,8 @@ libzmq_la_SOURCES = \ pgm_sender.hpp \ pgm_socket.hpp \ pipe.hpp \ - plain_mechanism.hpp \ + plain_client.hpp \ + plain_server.hpp \ platform.hpp \ poll.hpp \ poller.hpp \ @@ -132,7 +133,8 @@ libzmq_la_SOURCES = \ pgm_sender.cpp \ pgm_socket.cpp \ pipe.cpp \ - plain_mechanism.cpp \ + plain_client.cpp \ + plain_server.cpp \ poll.cpp \ poller_base.cpp \ pull.cpp \ diff --git a/src/plain_client.cpp b/src/plain_client.cpp new file mode 100644 index 00000000..8dead179 --- /dev/null +++ b/src/plain_client.cpp @@ -0,0 +1,185 @@ +/* + Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file + + This file is part of 0MQ. + + 0MQ is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 0MQ 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#include "platform.hpp" +#ifdef ZMQ_HAVE_WINDOWS +#include "windows.hpp" +#endif + +#include + +#include "msg.hpp" +#include "err.hpp" +#include "plain_client.hpp" + +zmq::plain_client_t::plain_client_t (const options_t &options_) : + mechanism_t (options_), + state (sending_hello) +{ +} + +zmq::plain_client_t::~plain_client_t () +{ +} + +int zmq::plain_client_t::next_handshake_command (msg_t *msg_) +{ + int rc = 0; + + switch (state) { + case sending_hello: + rc = produce_hello (msg_); + if (rc == 0) + state = waiting_for_welcome; + break; + case sending_initiate: + rc = produce_initiate (msg_); + if (rc == 0) + state = waiting_for_ready; + break; + default: + errno = EAGAIN; + rc = -1; + } + return rc; +} + +int zmq::plain_client_t::process_handshake_command (msg_t *msg_) +{ + int rc = 0; + + switch (state) { + case waiting_for_welcome: + rc = process_welcome (msg_); + if (rc == 0) + state = sending_initiate; + break; + case waiting_for_ready: + rc = process_ready (msg_); + if (rc == 0) + state = ready; + break; + default: + // Temporary support for security debugging + puts ("PLAIN I: invalid handshake command"); + errno = EPROTO; + rc = -1; + break; + } + if (rc == 0) { + rc = msg_->close (); + errno_assert (rc == 0); + rc = msg_->init (); + errno_assert (rc == 0); + } + return rc; +} + +zmq::mechanism_t::status_t zmq::plain_client_t::status () const +{ + return state == ready? mechanism_t::ready: mechanism_t::handshaking; +} + +int zmq::plain_client_t::produce_hello (msg_t *msg_) const +{ + const std::string username = options.plain_username; + zmq_assert (username.length () < 256); + + const std::string password = options.plain_password; + zmq_assert (password.length () < 256); + + const size_t command_size = 6 + 1 + username.length () + + 1 + password.length (); + + const int rc = msg_->init_size (command_size); + errno_assert (rc == 0); + + unsigned char *ptr = static_cast (msg_->data ()); + memcpy (ptr, "\x05HELLO", 6); + ptr += 6; + + *ptr++ = static_cast (username.length ()); + memcpy (ptr, username.c_str (), username.length ()); + ptr += username.length (); + + *ptr++ = static_cast (password.length ()); + memcpy (ptr, password.c_str (), password.length ()); + ptr += password.length (); + + return 0; +} + +int zmq::plain_client_t::process_welcome (msg_t *msg_) +{ + const unsigned char *ptr = static_cast (msg_->data ()); + const size_t bytes_left = msg_->size (); + + if (bytes_left != 8 || memcmp (ptr, "\x07WELCOME", 8)) { + // Temporary support for security debugging + puts ("PLAIN I: invalid PLAIN client, did not send WELCOME"); + errno = EPROTO; + return -1; + } + return 0; +} + +int zmq::plain_client_t::produce_initiate (msg_t *msg_) const +{ + unsigned char * const command_buffer = (unsigned char *) malloc (512); + alloc_assert (command_buffer); + + unsigned char *ptr = command_buffer; + + // Add mechanism string + memcpy (ptr, "\x08INITIATE", 9); + ptr += 9; + + // Add socket type property + const char *socket_type = socket_type_string (options.type); + ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type)); + + // Add identity property + if (options.type == ZMQ_REQ + || options.type == ZMQ_DEALER + || options.type == ZMQ_ROUTER) + ptr += add_property ( + ptr, "Identity", options.identity, options.identity_size); + + const size_t command_size = ptr - command_buffer; + const int rc = msg_->init_size (command_size); + errno_assert (rc == 0); + memcpy (msg_->data (), command_buffer, command_size); + free (command_buffer); + + return 0; +} + +int zmq::plain_client_t::process_ready (msg_t *msg_) +{ + const unsigned char *ptr = static_cast (msg_->data ()); + const size_t bytes_left = msg_->size (); + + if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) { + // Temporary support for security debugging + puts ("PLAIN I: invalid PLAIN client, did not send READY"); + errno = EPROTO; + return -1; + } + return parse_metadata (ptr + 6, bytes_left - 6); +} diff --git a/src/plain_client.hpp b/src/plain_client.hpp new file mode 100644 index 00000000..c5c56af7 --- /dev/null +++ b/src/plain_client.hpp @@ -0,0 +1,64 @@ +/* + Copyright (c) 2007-2014 Contributors as noted in the AUTHORS file + + This file is part of 0MQ. + + 0MQ is free software; you can redistribute it and/or modify it under + the terms of the GNU Lesser General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + 0MQ 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. + + You should have received a copy of the GNU Lesser General Public License + along with this program. If not, see . +*/ + +#ifndef __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__ +#define __ZMQ_PLAIN_CLIENT_HPP_INCLUDED__ + +#include "mechanism.hpp" +#include "options.hpp" + +namespace zmq +{ + + class msg_t; + + class plain_client_t : public mechanism_t + { + public: + + plain_client_t (const options_t &options_); + virtual ~plain_client_t (); + + // mechanism implementation + virtual int next_handshake_command (msg_t *msg_); + virtual int process_handshake_command (msg_t *msg_); + virtual status_t status () const; + + private: + + enum state_t { + sending_hello, + waiting_for_welcome, + sending_initiate, + waiting_for_ready, + ready + }; + + state_t state; + + int produce_hello (msg_t *msg_) const; + int produce_initiate (msg_t *msg_) const; + + int process_welcome (msg_t *msg); + int process_ready (msg_t *msg_); + }; + +} + +#endif diff --git a/src/plain_mechanism.cpp b/src/plain_server.cpp similarity index 68% rename from src/plain_mechanism.cpp rename to src/plain_server.cpp index 60857678..bfd61927 100644 --- a/src/plain_mechanism.cpp +++ b/src/plain_server.cpp @@ -27,44 +27,34 @@ #include "msg.hpp" #include "session_base.hpp" #include "err.hpp" -#include "plain_mechanism.hpp" +#include "plain_server.hpp" #include "wire.hpp" -zmq::plain_mechanism_t::plain_mechanism_t (session_base_t *session_, - const std::string &peer_address_, - const options_t &options_) : +zmq::plain_server_t::plain_server_t (session_base_t *session_, + const std::string &peer_address_, + const options_t &options_) : mechanism_t (options_), session (session_), peer_address (peer_address_), expecting_zap_reply (false), - state (options.as_server? waiting_for_hello: sending_hello) + state (waiting_for_hello) { } -zmq::plain_mechanism_t::~plain_mechanism_t () +zmq::plain_server_t::~plain_server_t () { } -int zmq::plain_mechanism_t::next_handshake_command (msg_t *msg_) +int zmq::plain_server_t::next_handshake_command (msg_t *msg_) { int rc = 0; switch (state) { - case sending_hello: - rc = produce_hello (msg_); - if (rc == 0) - state = waiting_for_welcome; - break; case sending_welcome: rc = produce_welcome (msg_); if (rc == 0) state = waiting_for_initiate; break; - case sending_initiate: - rc = produce_initiate (msg_); - if (rc == 0) - state = waiting_for_ready; - break; case sending_ready: rc = produce_ready (msg_); if (rc == 0) @@ -77,7 +67,7 @@ int zmq::plain_mechanism_t::next_handshake_command (msg_t *msg_) return rc; } -int zmq::plain_mechanism_t::process_handshake_command (msg_t *msg_) +int zmq::plain_server_t::process_handshake_command (msg_t *msg_) { int rc = 0; @@ -87,21 +77,11 @@ int zmq::plain_mechanism_t::process_handshake_command (msg_t *msg_) if (rc == 0) state = expecting_zap_reply? waiting_for_zap_reply: sending_welcome; break; - case waiting_for_welcome: - rc = process_welcome (msg_); - if (rc == 0) - state = sending_initiate; - break; case waiting_for_initiate: rc = process_initiate (msg_); if (rc == 0) state = sending_ready; break; - case waiting_for_ready: - rc = process_ready (msg_); - if (rc == 0) - state = ready; - break; default: // Temporary support for security debugging puts ("PLAIN I: invalid handshake command"); @@ -118,12 +98,12 @@ int zmq::plain_mechanism_t::process_handshake_command (msg_t *msg_) return rc; } -zmq::mechanism_t::status_t zmq::plain_mechanism_t::status () const +zmq::mechanism_t::status_t zmq::plain_server_t::status () const { return state == ready? mechanism_t::ready: mechanism_t::handshaking; } -int zmq::plain_mechanism_t::zap_msg_available () +int zmq::plain_server_t::zap_msg_available () { if (state != waiting_for_zap_reply) { errno = EFSM; @@ -135,37 +115,7 @@ int zmq::plain_mechanism_t::zap_msg_available () return rc; } -int zmq::plain_mechanism_t::produce_hello (msg_t *msg_) const -{ - const std::string username = options.plain_username; - zmq_assert (username.length () < 256); - - const std::string password = options.plain_password; - zmq_assert (password.length () < 256); - - const size_t command_size = 6 + 1 + username.length () - + 1 + password.length (); - - const int rc = msg_->init_size (command_size); - errno_assert (rc == 0); - - unsigned char *ptr = static_cast (msg_->data ()); - memcpy (ptr, "\x05HELLO", 6); - ptr += 6; - - *ptr++ = static_cast (username.length ()); - memcpy (ptr, username.c_str (), username.length ()); - ptr += username.length (); - - *ptr++ = static_cast (password.length ()); - memcpy (ptr, password.c_str (), password.length ()); - ptr += password.length (); - - return 0; -} - - -int zmq::plain_mechanism_t::process_hello (msg_t *msg_) +int zmq::plain_server_t::process_hello (msg_t *msg_) { const unsigned char *ptr = static_cast (msg_->data ()); size_t bytes_left = msg_->size (); @@ -238,7 +188,7 @@ int zmq::plain_mechanism_t::process_hello (msg_t *msg_) return 0; } -int zmq::plain_mechanism_t::produce_welcome (msg_t *msg_) const +int zmq::plain_server_t::produce_welcome (msg_t *msg_) const { const int rc = msg_->init_size (8); errno_assert (rc == 0); @@ -246,54 +196,10 @@ int zmq::plain_mechanism_t::produce_welcome (msg_t *msg_) const return 0; } -int zmq::plain_mechanism_t::process_welcome (msg_t *msg_) +int zmq::plain_server_t::process_initiate (msg_t *msg_) { const unsigned char *ptr = static_cast (msg_->data ()); - size_t bytes_left = msg_->size (); - - if (bytes_left != 8 || memcmp (ptr, "\x07WELCOME", 8)) { - // Temporary support for security debugging - puts ("PLAIN I: invalid PLAIN client, did not send WELCOME"); - errno = EPROTO; - return -1; - } - return 0; -} - -int zmq::plain_mechanism_t::produce_initiate (msg_t *msg_) const -{ - unsigned char * const command_buffer = (unsigned char *) malloc (512); - alloc_assert (command_buffer); - - unsigned char *ptr = command_buffer; - - // Add mechanism string - memcpy (ptr, "\x08INITIATE", 9); - ptr += 9; - - // Add socket type property - const char *socket_type = socket_type_string (options.type); - ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type)); - - // Add identity property - if (options.type == ZMQ_REQ - || options.type == ZMQ_DEALER - || options.type == ZMQ_ROUTER) - ptr += add_property (ptr, "Identity", options.identity, options.identity_size); - - const size_t command_size = ptr - command_buffer; - const int rc = msg_->init_size (command_size); - errno_assert (rc == 0); - memcpy (msg_->data (), command_buffer, command_size); - free (command_buffer); - - return 0; -} - -int zmq::plain_mechanism_t::process_initiate (msg_t *msg_) -{ - const unsigned char *ptr = static_cast (msg_->data ()); - size_t bytes_left = msg_->size (); + const size_t bytes_left = msg_->size (); if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) { // Temporary support for security debugging @@ -301,12 +207,10 @@ int zmq::plain_mechanism_t::process_initiate (msg_t *msg_) errno = EPROTO; return -1; } - ptr += 9; - bytes_left -= 9; - return parse_metadata (ptr, bytes_left); + return parse_metadata (ptr + 9, bytes_left - 9); } -int zmq::plain_mechanism_t::produce_ready (msg_t *msg_) const +int zmq::plain_server_t::produce_ready (msg_t *msg_) const { unsigned char * const command_buffer = (unsigned char *) malloc (512); alloc_assert (command_buffer); @@ -325,7 +229,8 @@ int zmq::plain_mechanism_t::produce_ready (msg_t *msg_) const if (options.type == ZMQ_REQ || options.type == ZMQ_DEALER || options.type == ZMQ_ROUTER) - ptr += add_property (ptr, "Identity", options.identity, options.identity_size); + ptr += add_property ( + ptr, "Identity", options.identity, options.identity_size); const size_t command_size = ptr - command_buffer; const int rc = msg_->init_size (command_size); @@ -336,24 +241,8 @@ int zmq::plain_mechanism_t::produce_ready (msg_t *msg_) const return 0; } -int zmq::plain_mechanism_t::process_ready (msg_t *msg_) -{ - const unsigned char *ptr = static_cast (msg_->data ()); - size_t bytes_left = msg_->size (); - - if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) { - // Temporary support for security debugging - puts ("PLAIN I: invalid PLAIN client, did not send READY"); - errno = EPROTO; - return -1; - } - ptr += 6; - bytes_left -= 6; - return parse_metadata (ptr, bytes_left); -} - -void zmq::plain_mechanism_t::send_zap_request (const std::string &username, - const std::string &password) +void zmq::plain_server_t::send_zap_request (const std::string &username, + const std::string &password) { int rc; msg_t msg; @@ -429,7 +318,7 @@ void zmq::plain_mechanism_t::send_zap_request (const std::string &username, errno_assert (rc == 0); } -int zmq::plain_mechanism_t::receive_and_process_zap_reply () +int zmq::plain_server_t::receive_and_process_zap_reply () { int rc = 0; msg_t msg [7]; // ZAP reply consists of 7 frames diff --git a/src/plain_mechanism.hpp b/src/plain_server.hpp similarity index 74% rename from src/plain_mechanism.hpp rename to src/plain_server.hpp index df44b817..cb7ba741 100644 --- a/src/plain_mechanism.hpp +++ b/src/plain_server.hpp @@ -17,8 +17,8 @@ along with this program. If not, see . */ -#ifndef __ZMQ_PLAIN_MECHANISM_HPP_INCLUDED__ -#define __ZMQ_PLAIN_MECHANISM_HPP_INCLUDED__ +#ifndef __ZMQ_PLAIN_SERVER_HPP_INCLUDED__ +#define __ZMQ_PLAIN_SERVER_HPP_INCLUDED__ #include "mechanism.hpp" #include "options.hpp" @@ -29,14 +29,14 @@ namespace zmq class msg_t; class session_base_t; - class plain_mechanism_t : public mechanism_t + class plain_server_t : public mechanism_t { public: - plain_mechanism_t (session_base_t *session_, - const std::string &peer_address_, - const options_t &options_); - virtual ~plain_mechanism_t (); + plain_server_t (session_base_t *session_, + const std::string &peer_address_, + const options_t &options_); + virtual ~plain_server_t (); // mechanism implementation virtual int next_handshake_command (msg_t *msg_); @@ -47,14 +47,10 @@ namespace zmq private: enum state_t { - sending_hello, waiting_for_hello, sending_welcome, - waiting_for_welcome, - sending_initiate, waiting_for_initiate, sending_ready, - waiting_for_ready, waiting_for_zap_reply, ready }; @@ -68,14 +64,10 @@ namespace zmq state_t state; - int produce_hello (msg_t *msg_) const; int produce_welcome (msg_t *msg_) const; - int produce_initiate (msg_t *msg_) const; int produce_ready (msg_t *msg_) const; int process_hello (msg_t *msg_); - int process_welcome (msg_t *msg); - int process_ready (msg_t *msg_); int process_initiate (msg_t *msg_); void send_zap_request (const std::string &username, diff --git a/src/stream_engine.cpp b/src/stream_engine.cpp index c703a0d2..c5827714 100644 --- a/src/stream_engine.cpp +++ b/src/stream_engine.cpp @@ -43,7 +43,8 @@ #include "v2_encoder.hpp" #include "v2_decoder.hpp" #include "null_mechanism.hpp" -#include "plain_mechanism.hpp" +#include "plain_client.hpp" +#include "plain_server.hpp" #include "gssapi_client.hpp" #include "gssapi_server.hpp" #include "curve_client.hpp" @@ -599,8 +600,12 @@ bool zmq::stream_engine_t::handshake () } else if (memcmp (greeting_recv + 12, "PLAIN\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0", 20) == 0) { - mechanism = new (std::nothrow) - plain_mechanism_t (session, peer_address, options); + if (options.as_server) + mechanism = new (std::nothrow) + plain_server_t (session, peer_address, options); + else + mechanism = new (std::nothrow) + plain_client_t (options); alloc_assert (mechanism); } #ifdef HAVE_LIBSODIUM