libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
gssapi_mechanism_base.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 
33 #ifdef HAVE_LIBGSSAPI_KRB5
34 
35 #ifdef ZMQ_HAVE_WINDOWS
36 #include "windows.hpp"
37 #endif
38 
39 #include <string.h>
40 #include <string>
41 
42 #include "msg.hpp"
43 #include "session_base.hpp"
44 #include "err.hpp"
46 #include "wire.hpp"
47 
48 zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t (const options_t & options_) :
49  mechanism_t(options_),
50  send_tok (),
51  recv_tok (),
52  /// FIXME remove? in_buf (),
53  target_name (GSS_C_NO_NAME),
54  principal_name (NULL),
55  maj_stat (GSS_S_COMPLETE),
56  min_stat (0),
57  init_sec_min_stat (0),
58  ret_flags (0),
59  gss_flags (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG),
60  cred (GSS_C_NO_CREDENTIAL),
61  context (GSS_C_NO_CONTEXT),
62  do_encryption (!options_.gss_plaintext)
63 {
64 }
65 
66 zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
67 {
68  if(target_name)
69  gss_release_name(&min_stat, &target_name);
70  if(context)
71  gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
72 }
73 
74 int zmq::gssapi_mechanism_base_t::encode_message (msg_t *msg_)
75 {
76  // Wrap the token value
77  int state;
78  gss_buffer_desc plaintext;
79  gss_buffer_desc wrapped;
80 
81  uint8_t flags = 0;
82  if (msg_->flags () & msg_t::more)
83  flags |= 0x01;
84  if (msg_->flags () & msg_t::command)
85  flags |= 0x02;
86 
87  uint8_t *plaintext_buffer = static_cast <uint8_t *>(malloc(msg_->size ()+1));
88  plaintext_buffer[0] = flags;
89  memcpy (plaintext_buffer+1, msg_->data(), msg_->size());
90 
91  plaintext.value = plaintext_buffer;
92  plaintext.length = msg_->size ()+1;
93 
94  maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
95  &plaintext, &state, &wrapped);
96 
97  zmq_assert (maj_stat == GSS_S_COMPLETE);
98  zmq_assert (state);
99 
100  // Re-initialize msg_ for wrapped text
101  int rc = msg_->close ();
102  zmq_assert (rc == 0);
103 
104  rc = msg_->init_size (8 + 4 + wrapped.length);
105  zmq_assert (rc == 0);
106 
107  uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
108 
109  // Add command string
110  memcpy (ptr, "\x07MESSAGE", 8);
111  ptr += 8;
112 
113  // Add token length
114  put_uint32 (ptr, static_cast <uint32_t> (wrapped.length));
115  ptr += 4;
116 
117  // Add wrapped token value
118  memcpy (ptr, wrapped.value, wrapped.length);
119  ptr += wrapped.length;
120 
121  gss_release_buffer (&min_stat, &wrapped);
122 
123  return 0;
124 }
125 
126 int zmq::gssapi_mechanism_base_t::decode_message (msg_t *msg_)
127 {
128  const uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
129  size_t bytes_left = msg_->size ();
130 
131  // Get command string
132  if (bytes_left < 8 || memcmp (ptr, "\x07MESSAGE", 8)) {
133  errno = EPROTO;
134  return -1;
135  }
136  ptr += 8;
137  bytes_left -= 8;
138 
139  // Get token length
140  if (bytes_left < 4) {
141  errno = EPROTO;
142  return -1;
143  }
144  gss_buffer_desc wrapped;
145  wrapped.length = get_uint32 (ptr);
146  ptr += 4;
147  bytes_left -= 4;
148 
149  // Get token value
150  if (bytes_left < wrapped.length) {
151  errno = EPROTO;
152  return -1;
153  }
154  // TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;
155  const size_t alloc_length = wrapped.length? wrapped.length: 1;
156  wrapped.value = static_cast <char *> (malloc (alloc_length));
157  if (wrapped.length) {
158  alloc_assert (wrapped.value);
159  memcpy(wrapped.value, ptr, wrapped.length);
160  ptr += wrapped.length;
161  bytes_left -= wrapped.length;
162  }
163 
164  // Unwrap the token value
165  int state;
166  gss_buffer_desc plaintext;
167  maj_stat = gss_unwrap(&min_stat, context, &wrapped, &plaintext,
168  &state, (gss_qop_t *) NULL);
169 
170  zmq_assert(maj_stat == GSS_S_COMPLETE);
171  zmq_assert(state);
172 
173  // Re-initialize msg_ for plaintext
174  int rc = msg_->close ();
175  zmq_assert (rc == 0);
176 
177  rc = msg_->init_size (plaintext.length-1);
178  zmq_assert (rc == 0);
179 
180  const uint8_t flags = static_cast <char *> (plaintext.value)[0];
181  if (flags & 0x01)
182  msg_->set_flags (msg_t::more);
183  if (flags & 0x02)
184  msg_->set_flags (msg_t::command);
185 
186  memcpy (msg_->data (), static_cast <char *> (plaintext.value)+1, plaintext.length-1);
187 
188  gss_release_buffer (&min_stat, &plaintext);
189  gss_release_buffer (&min_stat, &wrapped);
190 
191  if (bytes_left > 0) {
192  errno = EPROTO;
193  return -1;
194  }
195 
196  return 0;
197 }
198 
199 int zmq::gssapi_mechanism_base_t::produce_initiate (msg_t *msg_, void *token_value_, size_t token_length_)
200 {
201  zmq_assert (token_value_);
202  zmq_assert (token_length_ <= 0xFFFFFFFFUL);
203 
204  const size_t command_size = 9 + 4 + token_length_;
205 
206  const int rc = msg_->init_size (command_size);
207  errno_assert (rc == 0);
208 
209  uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
210 
211  // Add command string
212  memcpy (ptr, "\x08INITIATE", 9);
213  ptr += 9;
214 
215  // Add token length
216  put_uint32 (ptr, static_cast <uint32_t> (token_length_));
217  ptr += 4;
218 
219  // Add token value
220  memcpy (ptr, token_value_, token_length_);
221  ptr += token_length_;
222 
223  return 0;
224 }
225 
226 int zmq::gssapi_mechanism_base_t::process_initiate (msg_t *msg_, void **token_value_, size_t &token_length_)
227 {
228  zmq_assert (token_value_);
229 
230  const uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
231  size_t bytes_left = msg_->size ();
232 
233  // Get command string
234  if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) {
235  errno = EPROTO;
236  return -1;
237  }
238  ptr += 9;
239  bytes_left -= 9;
240 
241  // Get token length
242  if (bytes_left < 4) {
243  errno = EPROTO;
244  return -1;
245  }
246  token_length_ = get_uint32 (ptr);
247  ptr += 4;
248  bytes_left -= 4;
249 
250  // Get token value
251  if (bytes_left < token_length_) {
252  errno = EPROTO;
253  return -1;
254  }
255  *token_value_ = static_cast <char *> (malloc (token_length_ ? token_length_ : 1));
256  if (token_length_) {
257  alloc_assert (*token_value_);
258  memcpy(*token_value_, ptr, token_length_);
259  ptr += token_length_;
260  bytes_left -= token_length_;
261  }
262 
263  if (bytes_left > 0) {
264  errno = EPROTO;
265  return -1;
266  }
267 
268  return 0;
269 }
270 
271 int zmq::gssapi_mechanism_base_t::produce_ready (msg_t *msg_)
272 {
273  unsigned char * const command_buffer = (unsigned char *) malloc (512);
274  alloc_assert (command_buffer);
275 
276  unsigned char *ptr = command_buffer;
277 
278  // Add command name
279  memcpy (ptr, "\x05READY", 6);
280  ptr += 6;
281 
282  // Add socket type property
283  const char *socket_type = socket_type_string (options.type);
284  ptr += add_property (ptr, "Socket-Type", socket_type, strlen (socket_type));
285 
286  // Add identity property
287  if (options.type == ZMQ_REQ
288  || options.type == ZMQ_DEALER
289  || options.type == ZMQ_ROUTER)
290  ptr += add_property (ptr, "Identity", options.identity, options.identity_size);
291 
292  const size_t command_size = ptr - command_buffer;
293  const int rc = msg_->init_size (command_size);
294  errno_assert (rc == 0);
295  memcpy (msg_->data (), command_buffer, command_size);
296  free (command_buffer);
297 
298  if (do_encryption)
299  return encode_message (msg_);
300 
301  return 0;
302 }
303 
304 int zmq::gssapi_mechanism_base_t::process_ready (msg_t *msg_)
305 {
306  if (do_encryption) {
307  const int rc = decode_message (msg_);
308  if (rc != 0)
309  return rc;
310  }
311 
312  const unsigned char *ptr = static_cast <unsigned char *> (msg_->data ());
313  size_t bytes_left = msg_->size ();
314 
315  if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) {
316  errno = EPROTO;
317  return -1;
318  }
319  ptr += 6;
320  bytes_left -= 6;
321  return parse_metadata (ptr, bytes_left);
322 }
323 
324 int zmq::gssapi_mechanism_base_t::acquire_credentials (char * service_name_, gss_cred_id_t * cred_)
325 {
326  OM_uint32 maj_stat;
327  OM_uint32 min_stat;
328  gss_name_t server_name;
329 
330  gss_buffer_desc name_buf;
331  name_buf.value = service_name_;
332  name_buf.length = strlen ((char *) name_buf.value) + 1;
333 
334  maj_stat = gss_import_name (&min_stat, &name_buf,
335  GSS_C_NT_HOSTBASED_SERVICE, &server_name);
336 
337  if (maj_stat != GSS_S_COMPLETE)
338  return -1;
339 
340  maj_stat = gss_acquire_cred (&min_stat, server_name, 0,
341  GSS_C_NO_OID_SET, GSS_C_ACCEPT,
342  cred_, NULL, NULL);
343 
344  if (maj_stat != GSS_S_COMPLETE)
345  return -1;
346 
347  gss_release_name(&min_stat, &server_name);
348 
349  return 0;
350 }
351 
352 #endif
#define ZMQ_DEALER
Definition: zmq.h:251
#define zmq_assert(x)
Definition: err.hpp:119
#define ZMQ_ROUTER
Definition: zmq.h:252
void put_uint32(unsigned char *buffer_, uint32_t value)
Definition: wire.hpp:64
uint32_t get_uint32(const unsigned char *buffer_)
Definition: wire.hpp:72
#define ZMQ_REQ
Definition: zmq.h:249
unsigned char identity[256]
Definition: options.hpp:74
#define EPROTO
Definition: err.hpp:58
#define alloc_assert(x)
Definition: err.hpp:159
#define errno_assert(x)
Definition: err.hpp:129
options_t options
Definition: own.hpp:109
unsigned char identity_size
Definition: options.hpp:73