Line data Source code
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 : #include "macros.hpp"
32 : #include "platform.hpp"
33 : #ifdef ZMQ_HAVE_WINDOWS
34 : #include "windows.hpp"
35 : #endif
36 :
37 : #include <string>
38 :
39 : #include "msg.hpp"
40 : #include "err.hpp"
41 : #include "plain_client.hpp"
42 :
43 6 : zmq::plain_client_t::plain_client_t (const options_t &options_) :
44 : mechanism_t (options_),
45 6 : state (sending_hello)
46 : {
47 6 : }
48 :
49 6 : zmq::plain_client_t::~plain_client_t ()
50 : {
51 6 : }
52 :
53 27 : int zmq::plain_client_t::next_handshake_command (msg_t *msg_)
54 : {
55 27 : int rc = 0;
56 :
57 27 : switch (state) {
58 : case sending_hello:
59 6 : rc = produce_hello (msg_);
60 6 : if (rc == 0)
61 6 : state = waiting_for_welcome;
62 : break;
63 : case sending_initiate:
64 3 : rc = produce_initiate (msg_);
65 3 : if (rc == 0)
66 3 : state = waiting_for_ready;
67 : break;
68 : default:
69 18 : errno = EAGAIN;
70 18 : rc = -1;
71 : }
72 27 : return rc;
73 : }
74 :
75 9 : int zmq::plain_client_t::process_handshake_command (msg_t *msg_)
76 : {
77 : const unsigned char *cmd_data =
78 9 : static_cast <unsigned char *> (msg_->data ());
79 9 : const size_t data_size = msg_->size ();
80 :
81 9 : int rc = 0;
82 9 : if (data_size >= 8 && !memcmp (cmd_data, "\7WELCOME", 8))
83 3 : rc = process_welcome (cmd_data, data_size);
84 : else
85 6 : if (data_size >= 6 && !memcmp (cmd_data, "\5READY", 6))
86 3 : rc = process_ready (cmd_data, data_size);
87 : else
88 3 : if (data_size >= 6 && !memcmp (cmd_data, "\5ERROR", 6))
89 3 : rc = process_error (cmd_data, data_size);
90 : else {
91 : // Temporary support for security debugging
92 0 : puts ("PLAIN I: invalid handshake command");
93 0 : errno = EPROTO;
94 0 : rc = -1;
95 : }
96 :
97 9 : if (rc == 0) {
98 9 : rc = msg_->close ();
99 9 : errno_assert (rc == 0);
100 9 : rc = msg_->init ();
101 9 : errno_assert (rc == 0);
102 : }
103 :
104 9 : return rc;
105 : }
106 :
107 69 : zmq::mechanism_t::status_t zmq::plain_client_t::status () const
108 : {
109 69 : if (state == ready)
110 : return mechanism_t::ready;
111 : else
112 66 : if (state == error_command_received)
113 : return mechanism_t::error;
114 : else
115 60 : return mechanism_t::handshaking;
116 : }
117 :
118 6 : int zmq::plain_client_t::produce_hello (msg_t *msg_) const
119 : {
120 6 : const std::string username = options.plain_username;
121 6 : zmq_assert (username.length () < 256);
122 :
123 6 : const std::string password = options.plain_password;
124 6 : zmq_assert (password.length () < 256);
125 :
126 6 : const size_t command_size = 6 + 1 + username.length ()
127 6 : + 1 + password.length ();
128 :
129 6 : const int rc = msg_->init_size (command_size);
130 6 : errno_assert (rc == 0);
131 :
132 6 : unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
133 : memcpy (ptr, "\x05HELLO", 6);
134 6 : ptr += 6;
135 :
136 12 : *ptr++ = static_cast <unsigned char> (username.length ());
137 6 : memcpy (ptr, username.c_str (), username.length ());
138 6 : ptr += username.length ();
139 :
140 12 : *ptr++ = static_cast <unsigned char> (password.length ());
141 6 : memcpy (ptr, password.c_str (), password.length ());
142 6 : ptr += password.length ();
143 :
144 12 : return 0;
145 : }
146 :
147 3 : int zmq::plain_client_t::process_welcome (
148 : const unsigned char *cmd_data, size_t data_size)
149 : {
150 : LIBZMQ_UNUSED (cmd_data);
151 :
152 3 : if (state != waiting_for_welcome) {
153 0 : errno = EPROTO;
154 0 : return -1;
155 : }
156 3 : if (data_size != 8) {
157 0 : errno = EPROTO;
158 0 : return -1;
159 : }
160 3 : state = sending_initiate;
161 3 : return 0;
162 : }
163 :
164 3 : int zmq::plain_client_t::produce_initiate (msg_t *msg_) const
165 : {
166 3 : unsigned char * const command_buffer = (unsigned char *) malloc (512);
167 3 : alloc_assert (command_buffer);
168 :
169 3 : unsigned char *ptr = command_buffer;
170 :
171 : // Add mechanism string
172 : memcpy (ptr, "\x08INITIATE", 9);
173 3 : ptr += 9;
174 :
175 : // Add socket type property
176 3 : const char *socket_type = socket_type_string (options.type);
177 3 : ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type));
178 :
179 : // Add identity property
180 3 : if (options.type == ZMQ_REQ
181 3 : || options.type == ZMQ_DEALER
182 0 : || options.type == ZMQ_ROUTER)
183 : ptr += add_property (
184 3 : ptr, "Identity", options.identity, options.identity_size);
185 :
186 3 : const size_t command_size = ptr - command_buffer;
187 3 : const int rc = msg_->init_size (command_size);
188 3 : errno_assert (rc == 0);
189 3 : memcpy (msg_->data (), command_buffer, command_size);
190 3 : free (command_buffer);
191 :
192 3 : return 0;
193 : }
194 :
195 3 : int zmq::plain_client_t::process_ready (
196 : const unsigned char *cmd_data, size_t data_size)
197 : {
198 3 : if (state != waiting_for_ready) {
199 0 : errno = EPROTO;
200 0 : return -1;
201 : }
202 3 : const int rc = parse_metadata (cmd_data + 6, data_size - 6);
203 3 : if (rc == 0)
204 3 : state = ready;
205 3 : return rc;
206 : }
207 :
208 3 : int zmq::plain_client_t::process_error (
209 : const unsigned char *cmd_data, size_t data_size)
210 : {
211 3 : if (state != waiting_for_welcome && state != waiting_for_ready) {
212 0 : errno = EPROTO;
213 0 : return -1;
214 : }
215 3 : if (data_size < 7) {
216 0 : errno = EPROTO;
217 0 : return -1;
218 : }
219 3 : const size_t error_reason_len = static_cast <size_t> (cmd_data [6]);
220 3 : if (error_reason_len > data_size - 7) {
221 0 : errno = EPROTO;
222 0 : return -1;
223 : }
224 3 : state = error_command_received;
225 3 : return 0;
226 : }
|