Commit 3c414c4a authored by Mike Gatny's avatar Mike Gatny Committed by Chris Busbey

GSSAPI mechanism now fully working with encryption

parent eb286252
......@@ -69,6 +69,7 @@ McClain Looney <m@loonsoft.com>
Michael Compton <michael.compton@littleedge.co.uk>
Mika Fischer <mika.fischer@zoopnet.de>
Mikael Helbo Kjaer <mhk@designtech.dk>
Mike Gatny <mgatny@gmail.com>
Mikko Koppanen <mkoppanen@php.net>
Min Ragan-Kelley <benjaminrk@gmail.com>
Neale Ferguson <neale@sinenomine.net>
......
......@@ -34,13 +34,13 @@
zmq::gssapi_client_t::gssapi_client_t (const options_t &options_) :
gssapi_mechanism_base_t (),
mechanism_t (options_),
state (send_next_token),
state (call_next_init),
token_ptr (GSS_C_NO_BUFFER),
mechs (),
security_context_established (false)
{
maj_stat = GSS_S_COMPLETE;
service_name = strdup("host"); /// FIXME add service_name to options
service_name = strdup("host"); // TODO: add service_name to options
mechs.elements = NULL;
mechs.count = 0;
}
......@@ -49,80 +49,80 @@ zmq::gssapi_client_t::~gssapi_client_t ()
{
if(service_name)
free (service_name);
/// FIXME release this or not?
if(cred)
gss_release_cred(&min_stat, &cred);
}
int zmq::gssapi_client_t::next_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case send_next_token:
rc = produce_next_token (msg_);
if (rc == 0)
state = recv_next_token;
break;
case almost_ready:
state = ready;
break;
default:
errno = EAGAIN;
rc = -1;
break;
if (security_context_established) {
state = connected;
return 0;
}
return rc;
if (state != call_next_init) {
errno = EAGAIN;
return -1;
}
if (initialize_context () < 0)
return -1;
if (produce_next_token (msg_) < 0)
return -1;
if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
return -1;
if (maj_stat == GSS_S_COMPLETE)
security_context_established = true;
else
state = recv_next_token;
return 0;
}
int zmq::gssapi_client_t::process_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case recv_next_token:
rc = process_next_token (msg_);
if (rc == 0)
state = security_context_established? almost_ready: send_next_token;
break;
case almost_ready:
state = ready;
break;
default:
errno = EPROTO;
rc = -1;
break;
}
if (rc == 0) {
rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
if (state != recv_next_token) {
errno = EPROTO;
return -1;
}
return rc;
if (process_next_token (msg_) < 0)
return -1;
if (maj_stat == GSS_S_COMPLETE)
security_context_established = true;
else if (maj_stat == GSS_S_CONTINUE_NEEDED)
state = call_next_init;
else
return -1;
errno_assert (msg_->close () == 0);
errno_assert (msg_->init () == 0);
return 0;
}
int zmq::gssapi_client_t::encode (msg_t *msg_)
{
int rc = 0;
zmq_assert (state == ready);
return rc;
zmq_assert (state == connected);
return encode_message (msg_);
}
int zmq::gssapi_client_t::decode (msg_t *msg_)
{
int rc = 0;
zmq_assert (state == ready);
return rc;
zmq_assert (state == connected);
return decode_message (msg_);
}
bool zmq::gssapi_client_t::is_handshake_complete () const
{
fprintf(stderr, "%s:%d: is_handshake_complete=%d, security_context_established=%d\n", __FILE__, __LINE__, (state==ready), security_context_established); /// FIXME remove
return state == ready;
return state == connected;
}
int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
int zmq::gssapi_client_t::initialize_context ()
{
// First time through, import service_name into target_name
if (target_name == GSS_C_NO_NAME) {
......@@ -131,10 +131,8 @@ int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
OM_uint32 maj = gss_import_name(&min_stat, &send_tok,
gss_nt_service_name, &target_name);
if (maj != GSS_S_COMPLETE) {
fprintf(stderr, "%s:%d: failed to import service name\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("parsing name", maj_stat, min_stat);
if (maj != GSS_S_COMPLETE)
return -1;
}
}
maj_stat = gss_init_sec_context(&init_sec_min_stat, cred, &context,
......@@ -144,22 +142,22 @@ int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
if (token_ptr != GSS_C_NO_BUFFER)
free(recv_tok.value);
if (send_tok.length != 0) { // server expects another token
fprintf(stderr, "%s:%d: producing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("parsing name", maj_stat, min_stat);
if (produce_token (msg_, TOKEN_CONTEXT, send_tok.value, send_tok.length) < 0) {
return 0;
}
int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
{
if (send_tok.length != 0) { // Server expects another token
if (produce_initiate(msg_, send_tok.value, send_tok.length) < 0) {
gss_release_buffer(&min_stat, &send_tok);
gss_release_name(&min_stat, &target_name);
return -1;
}
}
else
fprintf(stderr, "%s:%d: skip producing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("parsing name", maj_stat, min_stat);
gss_release_buffer(&min_stat, &send_tok);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
fprintf(stderr, "%s:%d: failed to create GSSAPI security context\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
gss_release_name(&min_stat, &target_name);
if (context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
......@@ -172,18 +170,12 @@ int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
int zmq::gssapi_client_t::process_next_token (msg_t *msg_)
{
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
fprintf(stderr, "%s:%d: processing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("parsing name", maj_stat, min_stat);
if (process_token(msg_, token_flags, &recv_tok.value, recv_tok.length) < 0) {
if (process_initiate(msg_, &recv_tok.value, recv_tok.length) < 0) {
gss_release_name(&min_stat, &target_name);
return -1;
}
token_ptr = &recv_tok;
}
else
fprintf(stderr, "%s:%d: skip processing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("parsing name", maj_stat, min_stat);
if (maj_stat == GSS_S_COMPLETE)
security_context_established = true;
return 0;
}
......
......@@ -48,17 +48,26 @@ namespace zmq
private:
enum state_t {
call_next_init,
send_next_token,
recv_next_token,
almost_ready,
ready
connected
};
// Current FSM state
state_t state;
// Points to either send_tok or recv_tok
// during context initialization
gss_buffer_desc *token_ptr;
// The desired underlying mechanism
gss_OID_set_desc mechs;
// True iff client considers the server authenticated
bool security_context_established;
int initialize_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
};
......
......@@ -34,7 +34,7 @@
zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t () :
send_tok (),
recv_tok (),
in_buf (),
/// FIXME remove? in_buf (),
target_name (GSS_C_NO_NAME),
service_name (NULL),
maj_stat (GSS_S_COMPLETE),
......@@ -42,7 +42,6 @@ zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t () :
init_sec_min_stat (0),
ret_flags (0),
gss_flags (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG),
token_flags (0),
cred (GSS_C_NO_CREDENTIAL),
context (GSS_C_NO_CONTEXT)
{
......@@ -56,87 +55,106 @@ zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
}
int zmq::gssapi_mechanism_base_t::produce_token (msg_t *msg_, int flags_, void *token_value_, size_t token_length_)
int zmq::gssapi_mechanism_base_t::encode_message (msg_t *msg_)
{
zmq_assert (token_value_);
zmq_assert (token_length_ <= 0xFFFFFFFFUL);
const size_t cmd_len = 6 + 1 + 4 + token_length_;
uint8_t *cmd_buf = static_cast <uint8_t *> (malloc (cmd_len));
alloc_assert (cmd_buf);
// Wrap the token value
int state;
gss_buffer_desc plaintext;
gss_buffer_desc wrapped;
plaintext.value = msg_->data ();
plaintext.length = msg_->size ();
maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
&plaintext, &state, &wrapped);
zmq_assert (maj_stat == GSS_S_COMPLETE);
zmq_assert (state);
uint8_t *ptr = cmd_buf;
// Re-initialize msg_ for wrapped text
int rc = msg_->close ();
zmq_assert (rc == 0);
// Add command name
memcpy (ptr, "\x05TOKEN", 6);
ptr += 6;
rc = msg_->init_size (8 + 4 + wrapped.length);
zmq_assert (rc == 0);
// Add gss flags
put_uint8 (ptr, static_cast <uint8_t> (flags_));
ptr += 1;
uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
// Add command string
memcpy (ptr, "\x07MESSAGE", 8);
ptr += 8;
// Add token length
put_uint32 (ptr, static_cast <uint32_t> (token_length_));
put_uint32 (ptr, static_cast <uint32_t> (wrapped.length));
ptr += 4;
// Add token value
memcpy (ptr, token_value_, token_length_);
ptr += token_length_;
// Add wrapped token value
memcpy (ptr, wrapped.value, wrapped.length);
ptr += wrapped.length;
const int rc = msg_->init_size (cmd_len);
errno_assert (rc == 0);
memcpy (msg_->data (), cmd_buf, cmd_len);
free (cmd_buf);
gss_release_buffer (&min_stat, &wrapped);
return 0;
}
int zmq::gssapi_mechanism_base_t::process_token (msg_t *msg_, int &flags_, void **token_value_, size_t &token_length_)
int zmq::gssapi_mechanism_base_t::decode_message (msg_t *msg_)
{
zmq_assert (token_value_);
uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
const uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
size_t bytes_left = msg_->size ();
// Get command name
if (bytes_left < 6 || memcmp (ptr, "\x05TOKEN", 6)) {
errno = EPROTO;
return -1;
}
ptr += 6;
bytes_left -= 6;
// Get flags
if (bytes_left < 1) {
// Get command string
if (bytes_left < 8 || memcmp (ptr, "\x07MESSAGE", 8)) {
errno = EPROTO;
return -1;
}
flags_ = static_cast <int> (get_uint8 (ptr));
ptr += 1;
bytes_left -= 1;
ptr += 8;
bytes_left -= 8;
// Get token length
if (bytes_left < 4) {
errno = EPROTO;
return -1;
}
token_length_ = get_uint32 (ptr);
gss_buffer_desc wrapped;
wrapped.length = get_uint32 (ptr);
ptr += 4;
bytes_left -= 4;
// Get token value. TODO do unwrap here to prevent this extra memcpy.
if (bytes_left < token_length_) {
// Get token value
if (bytes_left < wrapped.length) {
errno = EPROTO;
return -1;
}
*token_value_ = static_cast <char *> (malloc (token_length_ ? token_length_ : 1));
if (token_length_) {
alloc_assert (*token_value_);
memcpy(*token_value_, ptr, token_length_);
ptr += token_length_;
bytes_left -= token_length_;
// TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;
const size_t alloc_length = wrapped.length? wrapped.length: 1;
wrapped.value = static_cast <char *> (malloc (alloc_length));
if (wrapped.length) {
alloc_assert (wrapped.value);
memcpy(wrapped.value, ptr, wrapped.length);
ptr += wrapped.length;
bytes_left -= wrapped.length;
}
// Unwrap the token value
int state;
gss_buffer_desc plaintext;
maj_stat = gss_unwrap(&min_stat, context, &wrapped, &plaintext,
&state, (gss_qop_t *) NULL);
zmq_assert(maj_stat == GSS_S_COMPLETE);
zmq_assert(state);
// Re-initialize msg_ for plaintext
int rc = msg_->close ();
zmq_assert (rc == 0);
rc = msg_->init_size (plaintext.length);
zmq_assert (rc == 0);
memcpy (msg_->data (), plaintext.value, plaintext.length);
gss_release_buffer (&min_stat, &plaintext);
gss_release_buffer (&min_stat, &wrapped);
if (bytes_left > 0) {
errno = EPROTO;
return -1;
......@@ -145,69 +163,75 @@ int zmq::gssapi_mechanism_base_t::process_token (msg_t *msg_, int &flags_, void
return 0;
}
/// TODO add support for TOKEN_SEND_MIC
/// TODO use gss_wrap_size_limit
int
zmq::gssapi_mechanism_base_t::produce_message (msg_t *msg_)
int zmq::gssapi_mechanism_base_t::produce_initiate (msg_t *msg_, void *token_value_, size_t token_length_)
{
// wrap it
int state;
gss_buffer_desc plaintext;
gss_buffer_desc wrapped;
plaintext.value = msg_->data ();
plaintext.length = msg_->size ();
maj_stat = gss_wrap(&min_stat, context, 1, GSS_C_QOP_DEFAULT,
&plaintext, &state, &wrapped);
zmq_assert (maj_stat == GSS_S_COMPLETE);
zmq_assert (state);
zmq_assert (token_value_);
zmq_assert (token_length_ <= 0xFFFFFFFFUL);
// prepare msg_ for wrapped text
int rc = msg_->close ();
zmq_assert (rc == 0);
const size_t command_size = 9 + 4 + token_length_;
// produce token
const int flags = (TOKEN_DATA | TOKEN_WRAPPED | TOKEN_ENCRYPTED);
rc = produce_token (msg_, flags, wrapped.value, wrapped.length);
zmq_assert (rc == 0);
gss_release_buffer (&min_stat, &wrapped);
const int rc = msg_->init_size (command_size);
errno_assert (rc == 0);
uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
// Add command string
memcpy (ptr, "\x08INITIATE", 9);
ptr += 9;
// Add token length
put_uint32 (ptr, static_cast <uint32_t> (token_length_));
ptr += 4;
// Add token value
memcpy (ptr, token_value_, token_length_);
ptr += token_length_;
return 0;
}
int
zmq::gssapi_mechanism_base_t::process_message (msg_t *msg_)
int zmq::gssapi_mechanism_base_t::process_initiate (msg_t *msg_, void **token_value_, size_t &token_length_)
{
// process token
int flags;
gss_buffer_desc wrapped;
int rc = process_token(msg_, flags, &wrapped.value, wrapped.length);
zmq_assert (rc == 0);
// ensure valid security context
zmq_assert (context != GSS_C_NO_CONTEXT);
zmq_assert (flags & TOKEN_WRAPPED);
zmq_assert (flags & TOKEN_ENCRYPTED);
// unwrap
int state;
gss_buffer_desc plaintext;
maj_stat = gss_unwrap(&min_stat, context, &wrapped, &plaintext,
&state, (gss_qop_t *) NULL);
zmq_assert (token_value_);
const uint8_t *ptr = static_cast <uint8_t *> (msg_->data ());
size_t bytes_left = msg_->size ();
zmq_assert(maj_stat == GSS_S_COMPLETE);
zmq_assert(state);
// Get command string
if (bytes_left < 9 || memcmp (ptr, "\x08INITIATE", 9)) {
errno = EPROTO;
return -1;
}
ptr += 9;
bytes_left -= 9;
// re-init msg_ with plaintext
rc = msg_->close ();
zmq_assert (rc == 0);
msg_->init_size (plaintext.length);
zmq_assert (rc == 0);
// Get token length
if (bytes_left < 4) {
errno = EPROTO;
return -1;
}
token_length_ = get_uint32 (ptr);
ptr += 4;
bytes_left -= 4;
memcpy (msg_->data (), plaintext.value, plaintext.length);
gss_release_buffer (&min_stat, &plaintext);
gss_release_buffer (&min_stat, &wrapped);
// Get token value
if (bytes_left < token_length_) {
errno = EPROTO;
return -1;
}
*token_value_ = static_cast <char *> (malloc (token_length_ ? token_length_ : 1));
if (token_length_) {
alloc_assert (*token_value_);
memcpy(*token_value_, ptr, token_length_);
ptr += token_length_;
bytes_left -= token_length_;
}
if (bytes_left > 0) {
errno = EPROTO;
return -1;
}
return 0;
}
......
......@@ -29,8 +29,9 @@ namespace zmq
class msg_t;
/// Both gssapi_server and gssapi_client need to produce and process
/// GSSAPI tokens. Common implementation is captured here.
/// Commonalities between clients and servers are captured here.
/// For example, clients and server both need to produce and
/// process INITIATE and MESSAGE commands.
class gssapi_mechanism_base_t
{
public:
......@@ -38,42 +39,55 @@ namespace zmq
virtual ~gssapi_mechanism_base_t () = 0;
protected:
/// Produce a security context initialization token
int produce_token (msg_t *msg_, int flags_, void *token_value_, size_t token_length_);
/// Process a security context initialization token
int process_token (msg_t *msg_, int &flags_, void **token_value_, size_t &token_length_);
/// Produce a wrapped message using the established security context
int produce_message (msg_t *msg_);
/// Process a wrapped message using the established security context
int process_message (msg_t *msg_);
/// Produce an INITIATE during security context initialization
int produce_initiate (msg_t *msg_, void *data_, size_t data_len_);
/// Process an INITIATE during security context initialization
int process_initiate (msg_t *msg_, void **data_, size_t &data_len_);
/// Encode a MESSAGE using the established security context
int encode_message (msg_t *msg_);
/// Decode a MESSAGE using the established security context
int decode_message (msg_t *msg_);
/// Acquire security context credentials
static int acquire_credentials (char * service_name_, gss_cred_id_t * cred_);
static int acquire_credentials (char * service_name_,
gss_cred_id_t * cred_);
protected:
const static int TOKEN_NOOP = (1<<0);
const static int TOKEN_CONTEXT = (1<<1);
const static int TOKEN_DATA = (1<<2);
const static int TOKEN_MIC = (1<<3);
const static int TOKEN_CONTEXT_NEXT = (1<<4);
const static int TOKEN_WRAPPED = (1<<5);
const static int TOKEN_ENCRYPTED = (1<<6);
const static int TOKEN_SEND_MIC = (1<<7);
/// Opaque GSSAPI token for outgoing data
gss_buffer_desc send_tok;
/// Opaque GSSAPI token for incoming data
gss_buffer_desc recv_tok;
gss_buffer_desc in_buf;
/// Opaque GSSAPI representation of service_name
gss_name_t target_name;
/// Human-readable service principal name
char * service_name;
/// Status code returned by GSSAPI functions
OM_uint32 maj_stat;
/// Status code returned by the underlying mechanism
OM_uint32 min_stat;
/// Status code returned by the underlying mechanism
/// during context initialization
OM_uint32 init_sec_min_stat;
/// Flags returned by GSSAPI (ignored)
OM_uint32 ret_flags;
/// Flags returned by GSSAPI (ignored)
OM_uint32 gss_flags;
int token_flags;
/// Credentials used to establish security context
gss_cred_id_t cred;
/// Opaque GSSAPI representation of the security context
gss_ctx_id_t context;
};
}
#endif
......@@ -41,16 +41,12 @@ zmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,
state (recv_next_token),
security_context_established (false)
{
service_name = (char *) "host"; /// FIXME add service_name to options
int rc = acquire_credentials (service_name, &cred); /// FIXME add creds to options too?
if (rc == 0) {
fprintf(stderr, "%s:%d: acquire creds successful\n", __FILE__, __LINE__); /// FIXME remove
service_name = (char *) "host"; // TODO: add service_name to options
int rc = acquire_credentials (service_name, &cred); // TODO: add creds to options too?
if (rc == 0)
maj_stat = GSS_S_CONTINUE_NEEDED;
}
else {
fprintf(stderr, "%s:%d: acquire creds failed\n", __FILE__, __LINE__); /// FIXME remove
else
maj_stat = GSS_S_FAILURE;
}
}
zmq::gssapi_server_t::~gssapi_server_t ()
......@@ -61,64 +57,58 @@ zmq::gssapi_server_t::~gssapi_server_t ()
int zmq::gssapi_server_t::next_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case send_next_token:
rc = produce_next_token (msg_);
if (rc == 0)
state = security_context_established? almost_ready: recv_next_token;
break;
case almost_ready:
state = ready;
break;
default:
errno = EPROTO;
rc = -1;
break;
if (state != send_next_token) {
errno = EAGAIN;
return -1;
}
if (produce_next_token (msg_) < 0)
return -1;
if (maj_stat != GSS_S_CONTINUE_NEEDED && maj_stat != GSS_S_COMPLETE)
return -1;
if (maj_stat == GSS_S_COMPLETE) {
gss_release_name(&min_stat, &target_name);
security_context_established = true;
state = connected;
}
else {
state = recv_next_token;
}
return rc;
return 0;
}
int zmq::gssapi_server_t::process_handshake_command (msg_t *msg_)
{
int rc = 0;
switch (state) {
case recv_next_token:
rc = process_next_token (msg_);
if (rc == 0)
state = send_next_token;
break;
case almost_ready:
state = ready;
break;
default:
errno = EAGAIN;
rc = -1;
break;
}
if (rc == 0) {
rc = msg_->close ();
errno_assert (rc == 0);
rc = msg_->init ();
errno_assert (rc == 0);
if (state != recv_next_token) {
errno = EPROTO;
return -1;
}
return rc;
if (process_next_token (msg_) < 0)
return -1;
accept_context ();
state = send_next_token;
errno_assert (msg_->close () == 0);
errno_assert (msg_->init () == 0);
return 0;
}
int zmq::gssapi_server_t::encode (msg_t *msg_)
{
int rc = 0;
zmq_assert (state == ready);
return rc;
zmq_assert (state == connected);
return encode_message (msg_);
}
int zmq::gssapi_server_t::decode (msg_t *msg_)
{
int rc = 0;
zmq_assert (state == ready);
return rc;
zmq_assert (state == connected);
return decode_message (msg_);
}
int zmq::gssapi_server_t::zap_msg_available ()
......@@ -128,53 +118,42 @@ int zmq::gssapi_server_t::zap_msg_available ()
bool zmq::gssapi_server_t::is_handshake_complete () const
{
fprintf(stderr, "%s:%d: is_handshake_complete=%d\n", __FILE__, __LINE__, (state==ready)); /// FIXME remove
return state == ready;
return state == connected;
}
int zmq::gssapi_server_t::produce_next_token (msg_t *msg_)
{
if (send_tok.length != 0) { // client expects another token
fprintf(stderr, "%s:%d: producing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
if (produce_token(msg_, TOKEN_CONTEXT, send_tok.value, send_tok.length) < 0) {
fprintf(stderr, "%s:%d: failed to produce token!\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
if (send_tok.length != 0) { // Client expects another token
if (produce_initiate(msg_, send_tok.value, send_tok.length) < 0)
return -1;
}
gss_release_buffer(&min_stat, &send_tok);
}
else
fprintf(stderr, "%s:%d: skip producing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
if (maj_stat != GSS_S_COMPLETE && maj_stat != GSS_S_CONTINUE_NEEDED) {
fprintf(stderr, "%s:%d: failed to create GSSAPI security context\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
gss_release_name(&min_stat, &target_name);
if (context != GSS_C_NO_CONTEXT)
gss_delete_sec_context(&min_stat, &context, GSS_C_NO_BUFFER);
return -1;
}
if (maj_stat == GSS_S_COMPLETE) {
gss_release_name(&min_stat, &target_name);
security_context_established = true;
}
return 0;
}
int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
{
if (maj_stat == GSS_S_CONTINUE_NEEDED) {
fprintf(stderr, "%s:%d: processing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
if (process_token(msg_, token_flags, &recv_tok.value, recv_tok.length) < 0) {
if (process_initiate(msg_, &recv_tok.value, recv_tok.length) < 0) {
if (target_name != GSS_C_NO_NAME)
gss_release_name(&min_stat, &target_name);
fprintf(stderr, "%s:%d: failed to process token!\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
return -1;
}
}
else
fprintf(stderr, "%s:%d: skip processing token\n", __FILE__, __LINE__); /// FIXME die("creating context", maj_stat, init_sec_min_stat); /// FIXME die("creating context", maj_stat, init_sec_min_stat);
return 0;
}
void zmq::gssapi_server_t::accept_context ()
{
maj_stat = gss_accept_sec_context(&init_sec_min_stat, &context, cred,
&recv_tok, GSS_C_NO_CHANNEL_BINDINGS,
&target_name, &doid, &send_tok,
......@@ -184,7 +163,5 @@ int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
free (recv_tok.value);
recv_tok.value = NULL;
}
return 0;
}
......@@ -54,19 +54,25 @@ namespace zmq
enum state_t {
send_next_token,
recv_next_token,
waiting_for_zap_reply,
almost_ready,
ready
connected
};
session_base_t * const session;
const std::string peer_address;
// Current FSM state
state_t state;
// True iff server considers the client authenticated
bool security_context_established;
// The underlying mechanism type (ignored)
gss_OID doid;
int produce_next_token(msg_t *msg_);
int process_next_token(msg_t *msg_);
void accept_context ();
int produce_next_token (msg_t *msg_);
int process_next_token (msg_t *msg_);
};
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment