libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
gssapi_server.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"
45 #include "gssapi_server.hpp"
46 #include "wire.hpp"
47 
48 #include <gssapi/gssapi.h>
49 
50 zmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,
51  const std::string &peer_address_,
52  const options_t &options_) :
53  gssapi_mechanism_base_t (options_),
54  session (session_),
55  peer_address (peer_address_),
56  state (recv_next_token),
57  security_context_established (false)
58 {
59  maj_stat = GSS_S_CONTINUE_NEEDED;
60  if(!options_.gss_principal.empty())
61  {
62  const std::string::size_type principal_size = options_.gss_principal.size();
63  principal_name = static_cast <char *>(malloc(principal_size+1));
64  assert(principal_name);
65  memcpy(principal_name, options_.gss_principal.c_str(), principal_size+1 );
66 
67  if (acquire_credentials (principal_name, &cred) != 0)
68  maj_stat = GSS_S_FAILURE;
69  }
70 }
71 
72 zmq::gssapi_server_t::~gssapi_server_t ()
73 {
74  if(cred)
75  gss_release_cred(&min_stat, &cred);
76 
77  if(target_name)
78  gss_release_name(&min_stat, &target_name);
79 }
80 
81 int zmq::gssapi_server_t::next_handshake_command (msg_t *msg_)
82 {
83  if (state == send_ready) {
84  int rc = produce_ready(msg_);
85  if (rc == 0)
86  state = recv_ready;
87 
88  return rc;
89  }
90 
91  if (state != send_next_token) {
92  errno = EAGAIN;
93  return -1;
94  }
95 
96  if (produce_next_token (msg_) < 0)
97  return -1;
98 
99  if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
100  return -1;
101 
102  if (maj_stat == GSS_S_COMPLETE) {
103  security_context_established = true;
104  }
105 
106  state = recv_next_token;
107 
108  return 0;
109 }
110 
111 int zmq::gssapi_server_t::process_handshake_command (msg_t *msg_)
112 {
113  if (state == recv_ready) {
114  int rc = process_ready(msg_);
115  if (rc == 0)
116  state = connected;
117 
118  return rc;
119  }
120 
121  if (state != recv_next_token) {
122  errno = EPROTO;
123  return -1;
124  }
125 
126  if (security_context_established) {
127  // Use ZAP protocol (RFC 27) to authenticate the user.
128  bool expecting_zap_reply = false;
129  int rc = session->zap_connect ();
130  if (rc == 0) {
131  send_zap_request();
132  rc = receive_and_process_zap_reply ();
133  if (rc != 0) {
134  if (errno != EAGAIN)
135  return -1;
136  expecting_zap_reply = true;
137  }
138  }
139  state = expecting_zap_reply? expect_zap_reply: send_ready;
140  return 0;
141  }
142 
143  if (process_next_token (msg_) < 0)
144  return -1;
145 
146  accept_context ();
147  state = send_next_token;
148 
149  errno_assert (msg_->close () == 0);
150  errno_assert (msg_->init () == 0);
151 
152  return 0;
153 }
154 
155 void zmq::gssapi_server_t::send_zap_request ()
156 {
157  int rc;
158  msg_t msg;
159 
160  // Address delimiter frame
161  rc = msg.init ();
162  errno_assert (rc == 0);
163  msg.set_flags (msg_t::more);
164  rc = session->write_zap_msg (&msg);
165  errno_assert (rc == 0);
166 
167  // Version frame
168  rc = msg.init_size (3);
169  errno_assert (rc == 0);
170  memcpy (msg.data (), "1.0", 3);
171  msg.set_flags (msg_t::more);
172  rc = session->write_zap_msg (&msg);
173  errno_assert (rc == 0);
174 
175  // Request ID frame
176  rc = msg.init_size (1);
177  errno_assert (rc == 0);
178  memcpy (msg.data (), "1", 1);
179  msg.set_flags (msg_t::more);
180  rc = session->write_zap_msg (&msg);
181  errno_assert (rc == 0);
182 
183  // Domain frame
184  rc = msg.init_size (options.zap_domain.length ());
185  errno_assert (rc == 0);
186  memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
187  msg.set_flags (msg_t::more);
188  rc = session->write_zap_msg (&msg);
189  errno_assert (rc == 0);
190 
191  // Address frame
192  rc = msg.init_size (peer_address.length ());
193  errno_assert (rc == 0);
194  memcpy (msg.data (), peer_address.c_str (), peer_address.length ());
195  msg.set_flags (msg_t::more);
196  rc = session->write_zap_msg (&msg);
197  errno_assert (rc == 0);
198 
199  // Identity frame
200  rc = msg.init_size (options.identity_size);
201  errno_assert (rc == 0);
202  memcpy (msg.data (), options.identity, options.identity_size);
203  msg.set_flags (msg_t::more);
204  rc = session->write_zap_msg (&msg);
205  errno_assert (rc == 0);
206 
207  // Mechanism frame
208  rc = msg.init_size (6);
209  errno_assert (rc == 0);
210  memcpy (msg.data (), "GSSAPI", 6);
211  msg.set_flags (msg_t::more);
212  rc = session->write_zap_msg (&msg);
213  errno_assert (rc == 0);
214 
215  // Principal frame
216  gss_buffer_desc principal;
217  gss_display_name(&min_stat, target_name, &principal, NULL);
218 
219  rc = msg.init_size (principal.length);
220  errno_assert (rc == 0);
221  memcpy (msg.data (), principal.value, principal.length);
222  rc = session->write_zap_msg (&msg);
223  errno_assert (rc == 0);
224  gss_release_buffer(&min_stat, &principal);
225 }
226 
227 int zmq::gssapi_server_t::receive_and_process_zap_reply ()
228 {
229  int rc = 0;
230  msg_t msg [7]; // ZAP reply consists of 7 frames
231 
232  // Initialize all reply frames
233  for (int i = 0; i < 7; i++) {
234  rc = msg [i].init ();
235  errno_assert (rc == 0);
236  }
237 
238  for (int i = 0; i < 7; i++) {
239  rc = session->read_zap_msg (&msg [i]);
240  if (rc == -1)
241  break;
242  if ((msg [i].flags () & msg_t::more) == (i < 6? 0: msg_t::more)) {
243  errno = EPROTO;
244  rc = -1;
245  break;
246  }
247  }
248 
249  if (rc != 0)
250  goto error;
251 
252  // Address delimiter frame
253  if (msg [0].size () > 0) {
254  rc = -1;
255  errno = EPROTO;
256  goto error;
257  }
258 
259  // Version frame
260  if (msg [1].size () != 3 || memcmp (msg [1].data (), "1.0", 3)) {
261  rc = -1;
262  errno = EPROTO;
263  goto error;
264  }
265 
266  // Request id frame
267  if (msg [2].size () != 1 || memcmp (msg [2].data (), "1", 1)) {
268  rc = -1;
269  errno = EPROTO;
270  goto error;
271  }
272 
273  // Status code frame
274  if (msg [3].size () != 3 || memcmp (msg [3].data (), "200", 3)) {
275  rc = -1;
276  errno = EACCES;
277  goto error;
278  }
279 
280  // Save user id
281  set_user_id (msg [5].data (), msg [5].size ());
282 
283  // Process metadata frame
284  rc = parse_metadata (static_cast <const unsigned char*> (msg [6].data ()),
285  msg [6].size (), true);
286 
287 error:
288  for (int i = 0; i < 7; i++) {
289  const int rc2 = msg [i].close ();
290  errno_assert (rc2 == 0);
291  }
292 
293  return rc;
294 }
295 
296 
297 int zmq::gssapi_server_t::encode (msg_t *msg_)
298 {
299  zmq_assert (state == connected);
300 
301  if (do_encryption)
302  return encode_message (msg_);
303 
304  return 0;
305 }
306 
307 int zmq::gssapi_server_t::decode (msg_t *msg_)
308 {
309  zmq_assert (state == connected);
310 
311  if (do_encryption)
312  return decode_message (msg_);
313 
314  return 0;
315 }
316 
317 int zmq::gssapi_server_t::zap_msg_available ()
318 {
319  if (state != expect_zap_reply) {
320  errno = EFSM;
321  return -1;
322  }
323  const int rc = receive_and_process_zap_reply ();
324  if (rc == 0)
325  state = send_ready;
326  return rc;
327 }
328 
329 zmq::mechanism_t::status_t zmq::gssapi_server_t::status () const
330 {
331  return state == connected? mechanism_t::ready: mechanism_t::handshaking;
332 }
333 
334 int zmq::gssapi_server_t::produce_next_token (msg_t *msg_)
335 {
336  if (send_tok.length != 0) { // Client expects another token
337  if (produce_initiate(msg_, send_tok.value, send_tok.length) < 0)
338  return -1;
339  gss_release_buffer(&min_stat, &send_tok);
340  }
341 
342  if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
343  gss_release_name(&min_stat, &target_name);
344  if (context != GSS_C_NO_CONTEXT)
345  gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
346  return -1;
347  }
348 
349  return 0;
350 }
351 
352 int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
353 {
354  if (maj_stat == GSS_S_CONTINUE_NEEDED) {
355  if (process_initiate(msg_, &recv_tok.value, recv_tok.length) < 0) {
356  if (target_name != GSS_C_NO_NAME)
357  gss_release_name(&min_stat, &target_name);
358  return -1;
359  }
360  }
361 
362  return 0;
363 }
364 
365 void zmq::gssapi_server_t::accept_context ()
366 {
367  maj_stat = gss_accept_sec_context(&init_sec_min_stat, &context, cred,
368  &recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
369  &target_name, &doid, &send_tok,
370  &ret_flags, NULL, NULL);
371 
372  if (recv_tok.value) {
373  free (recv_tok.value);
374  recv_tok.value = NULL;
375  }
376 }
377 
378 #endif
#define size
#define EFSM
Definition: zmq.h:167
#define zmq_assert(x)
Definition: err.hpp:119
unsigned char identity[256]
Definition: options.hpp:74
#define EPROTO
Definition: err.hpp:58
#define errno_assert(x)
Definition: err.hpp:129
std::string zap_domain
Definition: options.hpp:186
options_t options
Definition: own.hpp:109
unsigned char identity_size
Definition: options.hpp:73