libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
null_mechanism.cpp
Go to the documentation of this file.
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 "platform.hpp"
32 #ifdef ZMQ_HAVE_WINDOWS
33 #include "windows.hpp"
34 #endif
35 
36 #include <stddef.h>
37 #include <string.h>
38 #include <stdlib.h>
39 
40 #include "err.hpp"
41 #include "msg.hpp"
42 #include "session_base.hpp"
43 #include "wire.hpp"
44 #include "null_mechanism.hpp"
45 
47  const std::string &peer_address_,
48  const options_t &options_) :
49  mechanism_t (options_),
50  session (session_),
51  peer_address (peer_address_),
52  ready_command_sent (false),
53  error_command_sent (false),
54  ready_command_received (false),
55  error_command_received (false),
56  zap_connected (false),
57  zap_request_sent (false),
58  zap_reply_received (false)
59 {
60  // NULL mechanism only uses ZAP if there's a domain defined
61  // This prevents ZAP requests on naive sockets
62  if (options.zap_domain.size () > 0
63  && session->zap_connect () == 0)
64  zap_connected = true;
65 }
66 
68 {
69 }
70 
72 {
74  errno = EAGAIN;
75  return -1;
76  }
78  if (zap_request_sent) {
79  errno = EAGAIN;
80  return -1;
81  }
83  zap_request_sent = true;
84  const int rc = receive_and_process_zap_reply ();
85  if (rc != 0)
86  return -1;
87  zap_reply_received = true;
88  }
89 
91  && strncmp (status_code, "200", sizeof status_code) != 0) {
92  const int rc = msg_->init_size (6 + 1 + sizeof status_code);
93  zmq_assert (rc == 0);
94  unsigned char *msg_data =
95  static_cast <unsigned char *> (msg_->data ());
96  memcpy (msg_data, "\5ERROR", 6);
97  msg_data [6] = sizeof status_code;
98  memcpy (msg_data + 7, status_code, sizeof status_code);
99  error_command_sent = true;
100  return 0;
101  }
102 
103  unsigned char *const command_buffer = (unsigned char *) malloc (512);
104  alloc_assert (command_buffer);
105 
106  unsigned char *ptr = command_buffer;
107 
108  // Add mechanism string
109  memcpy (ptr, "\5READY", 6);
110  ptr += 6;
111 
112  // Add socket type property
113  const char *socket_type = socket_type_string (options.type);
114  ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type));
115 
116  // Add identity property
117  if (options.type == ZMQ_REQ
118  || options.type == ZMQ_DEALER
119  || options.type == ZMQ_ROUTER)
120  ptr += add_property (ptr, "Identity", options.identity, options.identity_size);
121 
122  const size_t command_size = ptr - command_buffer;
123  const int rc = msg_->init_size (command_size);
124  errno_assert (rc == 0);
125  memcpy (msg_->data (), command_buffer, command_size);
126  free (command_buffer);
127 
128  ready_command_sent = true;
129 
130  return 0;
131 }
132 
134 {
136  // Temporary support for security debugging
137  puts ("NULL I: client sent invalid NULL handshake (duplicate READY)");
138  errno = EPROTO;
139  return -1;
140  }
141 
142  const unsigned char *cmd_data =
143  static_cast <unsigned char *> (msg_->data ());
144  const size_t data_size = msg_->size ();
145 
146  int rc = 0;
147  if (data_size >= 6 && !memcmp (cmd_data, "\5READY", 6))
148  rc = process_ready_command (cmd_data, data_size);
149  else
150  if (data_size >= 6 && !memcmp (cmd_data, "\5ERROR", 6))
151  rc = process_error_command (cmd_data, data_size);
152  else {
153  // Temporary support for security debugging
154  puts ("NULL I: client sent invalid NULL handshake (not READY)");
155  errno = EPROTO;
156  rc = -1;
157  }
158 
159  if (rc == 0) {
160  rc = msg_->close ();
161  errno_assert (rc == 0);
162  rc = msg_->init ();
163  errno_assert (rc == 0);
164  }
165  return rc;
166 }
167 
169  const unsigned char *cmd_data, size_t data_size)
170 {
171  ready_command_received = true;
172  return parse_metadata (cmd_data + 6, data_size - 6);
173 }
174 
176  const unsigned char *cmd_data, size_t data_size)
177 {
178  if (data_size < 7) {
179  errno = EPROTO;
180  return -1;
181  }
182  const size_t error_reason_len = static_cast <size_t> (cmd_data [6]);
183  if (error_reason_len > data_size - 7) {
184  errno = EPROTO;
185  return -1;
186  }
187  error_command_received = true;
188  return 0;
189 }
190 
192 {
193  if (zap_reply_received) {
194  errno = EFSM;
195  return -1;
196  }
197  const int rc = receive_and_process_zap_reply ();
198  if (rc == 0)
199  zap_reply_received = true;
200  return rc;
201 }
202 
204 {
205  const bool command_sent =
207  const bool command_received =
209 
211  return ready;
212  else
213  if (command_sent && command_received)
214  return error;
215  else
216  return handshaking;
217 }
218 
220 {
221  int rc;
222  msg_t msg;
223 
224  // Address delimiter frame
225  rc = msg.init ();
226  errno_assert (rc == 0);
227  msg.set_flags (msg_t::more);
228  rc = session->write_zap_msg (&msg);
229  errno_assert (rc == 0);
230 
231  // Version frame
232  rc = msg.init_size (3);
233  errno_assert (rc == 0);
234  memcpy (msg.data (), "1.0", 3);
235  msg.set_flags (msg_t::more);
236  rc = session->write_zap_msg (&msg);
237  errno_assert (rc == 0);
238 
239  // Request id frame
240  rc = msg.init_size (1);
241  errno_assert (rc == 0);
242  memcpy (msg.data (), "1", 1);
243  msg.set_flags (msg_t::more);
244  rc = session->write_zap_msg (&msg);
245  errno_assert (rc == 0);
246 
247  // Domain frame
248  rc = msg.init_size (options.zap_domain.length ());
249  errno_assert (rc == 0);
250  memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
251  msg.set_flags (msg_t::more);
252  rc = session->write_zap_msg (&msg);
253  errno_assert (rc == 0);
254 
255  // Address frame
256  rc = msg.init_size (peer_address.length ());
257  errno_assert (rc == 0);
258  memcpy (msg.data (), peer_address.c_str (), peer_address.length ());
259  msg.set_flags (msg_t::more);
260  rc = session->write_zap_msg (&msg);
261  errno_assert (rc == 0);
262 
263  // Identity frame
264  rc = msg.init_size (options.identity_size);
265  errno_assert (rc == 0);
266  memcpy (msg.data (), options.identity, options.identity_size);
267  msg.set_flags (msg_t::more);
268  rc = session->write_zap_msg (&msg);
269  errno_assert (rc == 0);
270 
271  // Mechanism frame
272  rc = msg.init_size (4);
273  errno_assert (rc == 0);
274  memcpy (msg.data (), "NULL", 4);
275  rc = session->write_zap_msg (&msg);
276  errno_assert (rc == 0);
277 }
278 
280 {
281  int rc = 0;
282  msg_t msg [7]; // ZAP reply consists of 7 frames
283 
284  // Initialize all reply frames
285  for (int i = 0; i < 7; i++) {
286  rc = msg [i].init ();
287  errno_assert (rc == 0);
288  }
289 
290  for (int i = 0; i < 7; i++) {
291  rc = session->read_zap_msg (&msg [i]);
292  if (rc == -1)
293  break;
294  if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
295  // Temporary support for security debugging
296  puts ("NULL I: ZAP handler sent incomplete reply message");
297  errno = EPROTO;
298  rc = -1;
299  break;
300  }
301  }
302 
303  if (rc != 0)
304  goto error;
305 
306  // Address delimiter frame
307  if (msg [0].size () > 0) {
308  // Temporary support for security debugging
309  puts ("NULL I: ZAP handler sent malformed reply message");
310  errno = EPROTO;
311  rc = -1;
312  goto error;
313  }
314 
315  // Version frame
316  if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
317  // Temporary support for security debugging
318  puts ("NULL I: ZAP handler sent bad version number");
319  errno = EPROTO;
320  rc = -1;
321  goto error;
322  }
323 
324  // Request id frame
325  if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
326  // Temporary support for security debugging
327  puts ("NULL I: ZAP handler sent bad request ID");
328  errno = EPROTO;
329  rc = -1;
330  goto error;
331  }
332 
333  // Status code frame
334  if (msg [3].size () != 3) {
335  // Temporary support for security debugging
336  puts ("NULL I: ZAP handler rejected client authentication");
337  errno = EPROTO;
338  rc = -1;
339  goto error;
340  }
341 
342  // Save status code
343  memcpy (status_code, msg [3].data (), sizeof status_code);
344 
345  // Save user id
346  set_user_id (msg [5].data (), msg [5].size ());
347 
348  // Process metadata frame
349  rc = parse_metadata (static_cast <const unsigned char*> (msg [6].data ()),
350  msg [6].size (), true);
351 
352 error:
353  for (int i = 0; i < 7; i++) {
354  const int rc2 = msg [i].close ();
355  errno_assert (rc2 == 0);
356  }
357 
358  return rc;
359 }
#define size
#define EFSM
Definition: zmq.h:167
int close()
Definition: msg.cpp:217
virtual int next_handshake_command(msg_t *msg_)
virtual int process_handshake_command(msg_t *msg_)
#define ZMQ_DEALER
Definition: zmq.h:251
#define zmq_assert(x)
Definition: err.hpp:119
virtual int zap_msg_available()
int process_ready_command(const unsigned char *cmd_data, size_t data_size)
null_mechanism_t(session_base_t *session_, const std::string &peer_address, const options_t &options_)
#define ZMQ_ROUTER
Definition: zmq.h:252
unsigned char size
Definition: msg.hpp:188
int write_zap_msg(msg_t *msg_)
int init_size(size_t size_)
Definition: msg.cpp:93
options_t options
Definition: mechanism.hpp:124
#define ZMQ_REQ
Definition: zmq.h:249
int init()
Definition: msg.cpp:82
int parse_metadata(const unsigned char *ptr_, size_t length, bool zap_flag=false)
Definition: mechanism.cpp:102
unsigned char identity[256]
Definition: options.hpp:74
int read_zap_msg(msg_t *msg_)
#define EPROTO
Definition: err.hpp:58
const char * socket_type_string(int socket_type) const
Definition: mechanism.cpp:74
void set_flags(unsigned char flags_)
Definition: msg.cpp:384
virtual status_t status() const
const std::string peer_address
#define alloc_assert(x)
Definition: err.hpp:159
#define errno_assert(x)
Definition: err.hpp:129
session_base_t *const session
unsigned char data[max_vsm_size]
Definition: msg.hpp:187
std::string zap_domain
Definition: options.hpp:186
size_t add_property(unsigned char *ptr, const char *name, const void *value, size_t value_len) const
Definition: mechanism.cpp:86
unsigned char identity_size
Definition: options.hpp:73
int process_error_command(const unsigned char *cmd_data, size_t data_size)
void set_user_id(const void *user_id, size_t size)
Definition: mechanism.cpp:61