gssapi_mechanism_base.cpp
Go to the documentation of this file.
1 /* SPDX-License-Identifier: MPL-2.0 */
2 
3 #include "precompiled.hpp"
4 
5 #ifdef HAVE_LIBGSSAPI_KRB5
6 
7 #include <string.h>
8 #include <string>
9 
10 #include "msg.hpp"
11 #include "session_base.hpp"
12 #include "err.hpp"
14 #include "wire.hpp"
15 
16 zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t (
17  session_base_t *session_, const options_t &options_) :
18  mechanism_base_t (session_, options_),
19  send_tok (),
20  recv_tok (),
22  target_name (GSS_C_NO_NAME),
23  principal_name (NULL),
24  maj_stat (GSS_S_COMPLETE),
25  min_stat (0),
26  init_sec_min_stat (0),
27  ret_flags (0),
28  gss_flags (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG),
29  cred (GSS_C_NO_CREDENTIAL),
30  context (GSS_C_NO_CONTEXT),
31  do_encryption (!options_.gss_plaintext)
32 {
33 }
34 
35 zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
36 {
37  if (target_name)
38  gss_release_name (&min_stat, &target_name);
39  if (context)
40  gss_delete_sec_context (&min_stat, &context, GSS_C_NO_BUFFER);
41 }
42 
43 int zmq::gssapi_mechanism_base_t::encode_message (msg_t *msg_)
44 {
45  // Wrap the token value
46  int state;
47  gss_buffer_desc plaintext;
48  gss_buffer_desc wrapped;
49 
50  uint8_t flags = 0;
51  if (msg_->flags () & msg_t::more)
52  flags |= 0x01;
53  if (msg_->flags () & msg_t::command)
54  flags |= 0x02;
55 
56  uint8_t *plaintext_buffer =
57  static_cast<uint8_t *> (malloc (msg_->size () + 1));
58  alloc_assert (plaintext_buffer);
59 
60  plaintext_buffer[0] = flags;
61  memcpy (plaintext_buffer + 1, msg_->data (), msg_->size ());
62 
63  plaintext.value = plaintext_buffer;
64  plaintext.length = msg_->size () + 1;
65 
66  maj_stat = gss_wrap (&min_stat, context, 1, GSS_C_QOP_DEFAULT, &plaintext,
67  &state, &wrapped);
68 
69  zmq_assert (maj_stat == GSS_S_COMPLETE);
70  zmq_assert (state);
71 
72  // Re-initialize msg_ for wrapped text
73  int rc = msg_->close ();
74  zmq_assert (rc == 0);
75 
76  rc = msg_->init_size (8 + 4 + wrapped.length);
77  zmq_assert (rc == 0);
78 
79  uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
80 
81  // Add command string
82  memcpy (ptr, "\x07MESSAGE", 8);
83  ptr += 8;
84 
85  // Add token length
86  put_uint32 (ptr, static_cast<uint32_t> (wrapped.length));
87  ptr += 4;
88 
89  // Add wrapped token value
90  memcpy (ptr, wrapped.value, wrapped.length);
91  ptr += wrapped.length;
92 
93  gss_release_buffer (&min_stat, &wrapped);
94 
95  return 0;
96 }
97 
98 int zmq::gssapi_mechanism_base_t::decode_message (msg_t *msg_)
99 {
100  const uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
101  size_t bytes_left = msg_->size ();
102 
103  int rc = check_basic_command_structure (msg_);
104  if (rc == -1)
105  return rc;
106 
107  // Get command string
108  if (bytes_left < 8 || memcmp (ptr, "\x07MESSAGE", 8)) {
109  session->get_socket ()->event_handshake_failed_protocol (
110  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
111  errno = EPROTO;
112  return -1;
113  }
114  ptr += 8;
115  bytes_left -= 8;
116 
117  // Get token length
118  if (bytes_left < 4) {
119  session->get_socket ()->event_handshake_failed_protocol (
120  session->get_endpoint (),
122  errno = EPROTO;
123  return -1;
124  }
125  gss_buffer_desc wrapped;
126  wrapped.length = get_uint32 (ptr);
127  ptr += 4;
128  bytes_left -= 4;
129 
130  // Get token value
131  if (bytes_left < wrapped.length) {
132  session->get_socket ()->event_handshake_failed_protocol (
133  session->get_endpoint (),
135  errno = EPROTO;
136  return -1;
137  }
138  // TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;
139  const size_t alloc_length = wrapped.length ? wrapped.length : 1;
140  wrapped.value = static_cast<char *> (malloc (alloc_length));
141  alloc_assert (wrapped.value);
142 
143  if (wrapped.length) {
144  memcpy (wrapped.value, ptr, wrapped.length);
145  ptr += wrapped.length;
146  bytes_left -= wrapped.length;
147  }
148 
149  // Unwrap the token value
150  int state;
151  gss_buffer_desc plaintext;
152  maj_stat = gss_unwrap (&min_stat, context, &wrapped, &plaintext, &state,
153  (gss_qop_t *) NULL);
154 
155  if (maj_stat != GSS_S_COMPLETE) {
156  gss_release_buffer (&min_stat, &plaintext);
157  free (wrapped.value);
158  session->get_socket ()->event_handshake_failed_protocol (
159  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC);
160  errno = EPROTO;
161  return -1;
162  }
163  zmq_assert (state);
164 
165  // Re-initialize msg_ for plaintext
166  rc = msg_->close ();
167  zmq_assert (rc == 0);
168 
169  rc = msg_->init_size (plaintext.length - 1);
170  zmq_assert (rc == 0);
171 
172  const uint8_t flags = static_cast<char *> (plaintext.value)[0];
173  if (flags & 0x01)
174  msg_->set_flags (msg_t::more);
175  if (flags & 0x02)
176  msg_->set_flags (msg_t::command);
177 
178  memcpy (msg_->data (), static_cast<char *> (plaintext.value) + 1,
179  plaintext.length - 1);
180 
181  gss_release_buffer (&min_stat, &plaintext);
182  free (wrapped.value);
183 
184  if (bytes_left > 0) {
185  session->get_socket ()->event_handshake_failed_protocol (
186  session->get_endpoint (),
188  errno = EPROTO;
189  return -1;
190  }
191 
192  return 0;
193 }
194 
195 int zmq::gssapi_mechanism_base_t::produce_initiate (msg_t *msg_,
196  void *token_value_,
197  size_t token_length_)
198 {
199  zmq_assert (token_value_);
200  zmq_assert (token_length_ <= 0xFFFFFFFFUL);
201 
202  const size_t command_size = 9 + 4 + token_length_;
203 
204  const int rc = msg_->init_size (command_size);
205  errno_assert (rc == 0);
206 
207  uint8_t *ptr = static_cast<uint8_t *> (msg_->data ());
208 
209  // Add command string
210  memcpy (ptr, "\x08INITIATE", 9);
211  ptr += 9;
212 
213  // Add token length
214  put_uint32 (ptr, static_cast<uint32_t> (token_length_));
215  ptr += 4;
216 
217  // Add token value
218  memcpy (ptr, token_value_, token_length_);
219  ptr += token_length_;
220 
221  return 0;
222 }
223 
224 int zmq::gssapi_mechanism_base_t::process_initiate (msg_t *msg_,
225  void **token_value_,
226  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  int rc = check_basic_command_structure (msg_);
234  if (rc == -1)
235  return rc;
236 
237  // Get command string
238  if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) {
239  session->get_socket ()->event_handshake_failed_protocol (
240  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
241  errno = EPROTO;
242  return -1;
243  }
244  ptr += 9;
245  bytes_left -= 9;
246 
247  // Get token length
248  if (bytes_left < 4) {
249  session->get_socket ()->event_handshake_failed_protocol (
250  session->get_endpoint (),
252  errno = EPROTO;
253  return -1;
254  }
255  token_length_ = get_uint32 (ptr);
256  ptr += 4;
257  bytes_left -= 4;
258 
259  // Get token value
260  if (bytes_left < token_length_) {
261  session->get_socket ()->event_handshake_failed_protocol (
262  session->get_endpoint (),
264  errno = EPROTO;
265  return -1;
266  }
267 
268  *token_value_ =
269  static_cast<char *> (malloc (token_length_ ? token_length_ : 1));
270  alloc_assert (*token_value_);
271 
272  if (token_length_) {
273  memcpy (*token_value_, ptr, token_length_);
274  ptr += token_length_;
275  bytes_left -= token_length_;
276  }
277 
278  if (bytes_left > 0) {
279  session->get_socket ()->event_handshake_failed_protocol (
280  session->get_endpoint (),
282  errno = EPROTO;
283  return -1;
284  }
285 
286  return 0;
287 }
288 
289 int zmq::gssapi_mechanism_base_t::produce_ready (msg_t *msg_)
290 {
291  make_command_with_basic_properties (msg_, "\5READY", 6);
292 
293  if (do_encryption)
294  return encode_message (msg_);
295 
296  return 0;
297 }
298 
299 int zmq::gssapi_mechanism_base_t::process_ready (msg_t *msg_)
300 {
301  if (do_encryption) {
302  const int rc = decode_message (msg_);
303  if (rc != 0)
304  return rc;
305  }
306 
307  const unsigned char *ptr = static_cast<unsigned char *> (msg_->data ());
308  size_t bytes_left = msg_->size ();
309 
310  int rc = check_basic_command_structure (msg_);
311  if (rc == -1)
312  return rc;
313 
314  if (bytes_left < 6 || memcmp (ptr, "\x05READY", 6)) {
315  session->get_socket ()->event_handshake_failed_protocol (
316  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND);
317  errno = EPROTO;
318  return -1;
319  }
320  ptr += 6;
321  bytes_left -= 6;
322  rc = parse_metadata (ptr, bytes_left);
323  if (rc == -1)
324  session->get_socket ()->event_handshake_failed_protocol (
325  session->get_endpoint (), ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA);
326 
327  return rc;
328 }
329 
330 const gss_OID zmq::gssapi_mechanism_base_t::convert_nametype (int zmq_nametype)
331 {
332  switch (zmq_nametype) {
334  return GSS_C_NT_HOSTBASED_SERVICE;
336  return GSS_C_NT_USER_NAME;
338 #ifdef GSS_KRB5_NT_PRINCIPAL_NAME
339  return (gss_OID) GSS_KRB5_NT_PRINCIPAL_NAME;
340 #else
341  return GSS_C_NT_USER_NAME;
342 #endif
343  }
344  return NULL;
345 }
346 
347 int zmq::gssapi_mechanism_base_t::acquire_credentials (char *service_name_,
348  gss_cred_id_t *cred_,
349  gss_OID name_type_)
350 {
351  OM_uint32 maj_stat;
352  OM_uint32 min_stat;
353  gss_name_t server_name;
354 
355  gss_buffer_desc name_buf;
356  name_buf.value = service_name_;
357  name_buf.length = strlen ((char *) name_buf.value) + 1;
358 
359  maj_stat = gss_import_name (&min_stat, &name_buf, name_type_, &server_name);
360 
361  if (maj_stat != GSS_S_COMPLETE)
362  return -1;
363 
364  maj_stat = gss_acquire_cred (&min_stat, server_name, 0, GSS_C_NO_OID_SET,
365  GSS_C_BOTH, cred_, NULL, NULL);
366 
367  if (maj_stat != GSS_S_COMPLETE)
368  return -1;
369 
370  gss_release_name (&min_stat, &server_name);
371 
372  return 0;
373 }
374 
375 #endif
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_INITIATE
Definition: zmq.h:431
ZMQ_GSSAPI_NT_KRB5_PRINCIPAL
#define ZMQ_GSSAPI_NT_KRB5_PRINCIPAL
Definition: zmq.h:393
ZMQ_GSSAPI_NT_USER_NAME
#define ZMQ_GSSAPI_NT_USER_NAME
Definition: zmq.h:392
NULL
NULL
Definition: test_security_zap.cpp:405
ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
#define ZMQ_PROTOCOL_ERROR_ZMTP_UNEXPECTED_COMMAND
Definition: zmq.h:425
zmq::put_uint32
void put_uint32(unsigned char *buffer_, uint32_t value_)
Definition: wire.hpp:35
ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
#define ZMQ_PROTOCOL_ERROR_ZMTP_CRYPTOGRAPHIC
Definition: zmq.h:437
precompiled.hpp
zmq_assert
#define zmq_assert(x)
Definition: err.hpp:102
errno
int errno
flags
GLbitfield flags
Definition: glcorearb.h:3585
wire.hpp
EPROTO
#define EPROTO
Definition: err.hpp:26
gssapi_mechanism_base.hpp
alloc_assert
#define alloc_assert(x)
Definition: err.hpp:146
ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
#define ZMQ_PROTOCOL_ERROR_ZMTP_INVALID_METADATA
Definition: zmq.h:435
errno_assert
#define errno_assert(x)
Definition: err.hpp:113
ZMQ_GSSAPI_NT_HOSTBASED
#define ZMQ_GSSAPI_NT_HOSTBASED
Definition: zmq.h:391
plaintext
const char * plaintext
Definition: strutil_unittest.cc:85
msg.hpp
ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
#define ZMQ_PROTOCOL_ERROR_ZMTP_MALFORMED_COMMAND_MESSAGE
Definition: zmq.h:429
err.hpp
session_base.hpp
zmq::get_uint32
uint32_t get_uint32(const unsigned char *buffer_)
Definition: wire.hpp:43
options_
DebugStringOptions options_
Definition: src/google/protobuf/descriptor.cc:2410


libaditof
Author(s):
autogenerated on Wed May 21 2025 02:06:53