libzmq  master
ZeroMQ C++ Core Engine (LIBZMQ)
gssapi_client.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_client.hpp"
46 #include "wire.hpp"
47 
48 zmq::gssapi_client_t::gssapi_client_t (const options_t &options_) :
49  gssapi_mechanism_base_t (options_),
50  state (call_next_init),
51  token_ptr (GSS_C_NO_BUFFER),
52  mechs (),
53  security_context_established (false)
54 {
55  const std::string::size_type service_size = options_.gss_service_principal.size();
56  service_name = static_cast <char *>(malloc(service_size+1));
57  assert(service_name);
58  memcpy(service_name, options_.gss_service_principal.c_str(), service_size+1 );
59 
60  maj_stat = GSS_S_COMPLETE;
61  if(!options_.gss_principal.empty())
62  {
63  const std::string::size_type principal_size = options_.gss_principal.size();
64  principal_name = static_cast <char *>(malloc(principal_size+1));
65  assert(principal_name);
66  memcpy(principal_name, options_.gss_principal.c_str(), principal_size+1 );
67 
68  if (acquire_credentials (principal_name, &cred) != 0)
69  maj_stat = GSS_S_FAILURE;
70  }
71 
72  mechs.elements = NULL;
73  mechs.count = 0;
74 }
75 
76 zmq::gssapi_client_t::~gssapi_client_t ()
77 {
78  if(service_name)
79  free (service_name);
80  if(cred)
81  gss_release_cred(&min_stat, &cred);
82 }
83 
84 int zmq::gssapi_client_t::next_handshake_command (msg_t *msg_)
85 {
86  if (state == send_ready) {
87  int rc = produce_ready(msg_);
88  if (rc == 0)
89  state = connected;
90 
91  return rc;
92  }
93 
94  if (state != call_next_init) {
95  errno = EAGAIN;
96  return -1;
97  }
98 
99  if (initialize_context () < 0)
100  return -1;
101 
102  if (produce_next_token (msg_) < 0)
103  return -1;
104 
105  if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
106  return -1;
107 
108  if (maj_stat == GSS_S_COMPLETE) {
109  security_context_established = true;
110  state = recv_ready;
111  }
112  else
113  state = recv_next_token;
114 
115  return 0;
116 }
117 
118 int zmq::gssapi_client_t::process_handshake_command (msg_t *msg_)
119 {
120  if (state == recv_ready) {
121  int rc = process_ready(msg_);
122  if (rc == 0)
123  state = send_ready;
124 
125  return rc;
126  }
127 
128  if (state != recv_next_token) {
129  errno = EPROTO;
130  return -1;
131  }
132 
133  if (process_next_token (msg_) < 0)
134  return -1;
135 
136  if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED)
137  return -1;
138 
139  state = call_next_init;
140 
141  errno_assert (msg_->close () == 0);
142  errno_assert (msg_->init () == 0);
143 
144  return 0;
145 }
146 
147 int zmq::gssapi_client_t::encode (msg_t *msg_)
148 {
149  zmq_assert (state == connected);
150 
151  if (do_encryption)
152  return encode_message (msg_);
153 
154  return 0;
155 }
156 
157 int zmq::gssapi_client_t::decode (msg_t *msg_)
158 {
159  zmq_assert (state == connected);
160 
161  if (do_encryption)
162  return decode_message (msg_);
163 
164  return 0;
165 }
166 
167 zmq::mechanism_t::status_t zmq::gssapi_client_t::status () const
168 {
169  return state == connected? mechanism_t::ready: mechanism_t::handshaking;
170 }
171 
172 int zmq::gssapi_client_t::initialize_context ()
173 {
174  // First time through, import service_name into target_name
175  if (target_name == GSS_C_NO_NAME) {
176  send_tok.value = service_name;
177  send_tok.length = strlen(service_name);
178  OM_uint32 maj = gss_import_name(&min_stat, &send_tok,
179  GSS_C_NT_HOSTBASED_SERVICE,
180  &target_name);
181 
182  if (maj != GSS_S_COMPLETE)
183  return -1;
184  }
185 
186  maj_stat = gss_init_sec_context(&init_sec_min_stat, cred, &context,
187  target_name, mechs.elements,
188  gss_flags, 0, NULL, token_ptr, NULL,
189  &send_tok, &ret_flags, NULL);
190 
191  if (token_ptr != GSS_C_NO_BUFFER)
192  free(recv_tok.value);
193 
194  return 0;
195 }
196 
197 int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
198 {
199  if (send_tok.length != 0) { // Server expects another token
200  if (produce_initiate(msg_, send_tok.value, send_tok.length) < 0) {
201  gss_release_buffer(&min_stat, &send_tok);
202  gss_release_name(&min_stat, &target_name);
203  return -1;
204  }
205  }
206  gss_release_buffer(&min_stat, &send_tok);
207 
208  if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
209  gss_release_name(&min_stat, &target_name);
210  if (context != GSS_C_NO_CONTEXT)
211  gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
212  return -1;
213  }
214 
215  return 0;
216 }
217 
218 int zmq::gssapi_client_t::process_next_token (msg_t *msg_)
219 {
220  if (maj_stat == GSS_S_CONTINUE_NEEDED) {
221  if (process_initiate(msg_, &recv_tok.value, recv_tok.length) < 0) {
222  gss_release_name(&min_stat, &target_name);
223  return -1;
224  }
225  token_ptr = &recv_tok;
226  }
227 
228  return 0;
229 }
230 
231 #endif
#define zmq_assert(x)
Definition: err.hpp:119
#define EPROTO
Definition: err.hpp:58
#define errno_assert(x)
Definition: err.hpp:129