Skip to content
Projects
Groups
Snippets
Help
Loading...
Sign in / Register
Toggle navigation
L
libzmq
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Packages
Packages
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
submodule
libzmq
Commits
3c414c4a
Commit
3c414c4a
authored
Oct 08, 2013
by
Mike Gatny
Committed by
Chris Busbey
Apr 24, 2014
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
GSSAPI mechanism now fully working with encryption
parent
eb286252
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
299 additions
and
276 deletions
+299
-276
AUTHORS
AUTHORS
+1
-0
gssapi_client.cpp
src/gssapi_client.cpp
+60
-68
gssapi_client.hpp
src/gssapi_client.hpp
+11
-2
gssapi_mechanism_base.cpp
src/gssapi_mechanism_base.cpp
+127
-103
gssapi_mechanism_base.hpp
src/gssapi_mechanism_base.hpp
+37
-23
gssapi_server.cpp
src/gssapi_server.cpp
+52
-75
gssapi_server.hpp
src/gssapi_server.hpp
+11
-5
No files found.
AUTHORS
View file @
3c414c4a
...
@@ -69,6 +69,7 @@ McClain Looney <m@loonsoft.com>
...
@@ -69,6 +69,7 @@ McClain Looney <m@loonsoft.com>
Michael Compton <michael.compton@littleedge.co.uk>
Michael Compton <michael.compton@littleedge.co.uk>
Mika Fischer <mika.fischer@zoopnet.de>
Mika Fischer <mika.fischer@zoopnet.de>
Mikael Helbo Kjaer <mhk@designtech.dk>
Mikael Helbo Kjaer <mhk@designtech.dk>
Mike Gatny <mgatny@gmail.com>
Mikko Koppanen <mkoppanen@php.net>
Mikko Koppanen <mkoppanen@php.net>
Min Ragan-Kelley <benjaminrk@gmail.com>
Min Ragan-Kelley <benjaminrk@gmail.com>
Neale Ferguson <neale@sinenomine.net>
Neale Ferguson <neale@sinenomine.net>
...
...
src/gssapi_client.cpp
View file @
3c414c4a
...
@@ -34,13 +34,13 @@
...
@@ -34,13 +34,13 @@
zmq
::
gssapi_client_t
::
gssapi_client_t
(
const
options_t
&
options_
)
:
zmq
::
gssapi_client_t
::
gssapi_client_t
(
const
options_t
&
options_
)
:
gssapi_mechanism_base_t
(),
gssapi_mechanism_base_t
(),
mechanism_t
(
options_
),
mechanism_t
(
options_
),
state
(
send_next_token
),
state
(
call_next_init
),
token_ptr
(
GSS_C_NO_BUFFER
),
token_ptr
(
GSS_C_NO_BUFFER
),
mechs
(),
mechs
(),
security_context_established
(
false
)
security_context_established
(
false
)
{
{
maj_stat
=
GSS_S_COMPLETE
;
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
.
elements
=
NULL
;
mechs
.
count
=
0
;
mechs
.
count
=
0
;
}
}
...
@@ -49,80 +49,80 @@ zmq::gssapi_client_t::~gssapi_client_t ()
...
@@ -49,80 +49,80 @@ zmq::gssapi_client_t::~gssapi_client_t ()
{
{
if
(
service_name
)
if
(
service_name
)
free
(
service_name
);
free
(
service_name
);
/// FIXME release this or not?
if
(
cred
)
if
(
cred
)
gss_release_cred
(
&
min_stat
,
&
cred
);
gss_release_cred
(
&
min_stat
,
&
cred
);
}
}
int
zmq
::
gssapi_client_t
::
next_handshake_command
(
msg_t
*
msg_
)
int
zmq
::
gssapi_client_t
::
next_handshake_command
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
if
(
security_context_established
)
{
state
=
connected
;
switch
(
state
)
{
return
0
;
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
;
}
}
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
zmq
::
gssapi_client_t
::
process_handshake_command
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
if
(
state
!=
recv_next_token
)
{
errno
=
EPROTO
;
switch
(
state
)
{
return
-
1
;
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
);
}
}
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
zmq
::
gssapi_client_t
::
encode
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
zmq_assert
(
state
==
connected
);
zmq_assert
(
state
==
ready
);
return
encode_message
(
msg_
);
return
rc
;
}
}
int
zmq
::
gssapi_client_t
::
decode
(
msg_t
*
msg_
)
int
zmq
::
gssapi_client_t
::
decode
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
zmq_assert
(
state
==
connected
);
zmq_assert
(
state
==
ready
);
return
decode_message
(
msg_
);
return
rc
;
}
}
bool
zmq
::
gssapi_client_t
::
is_handshake_complete
()
const
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
==
connected
;
return
state
==
ready
;
}
}
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
// First time through, import service_name into target_name
if
(
target_name
==
GSS_C_NO_NAME
)
{
if
(
target_name
==
GSS_C_NO_NAME
)
{
...
@@ -131,10 +131,8 @@ int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
...
@@ -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
,
OM_uint32
maj
=
gss_import_name
(
&
min_stat
,
&
send_tok
,
gss_nt_service_name
,
&
target_name
);
gss_nt_service_name
,
&
target_name
);
if
(
maj
!=
GSS_S_COMPLETE
)
{
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);
return
-
1
;
return
-
1
;
}
}
}
maj_stat
=
gss_init_sec_context
(
&
init_sec_min_stat
,
cred
,
&
context
,
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_)
...
@@ -144,22 +142,22 @@ int zmq::gssapi_client_t::produce_next_token (msg_t *msg_)
if
(
token_ptr
!=
GSS_C_NO_BUFFER
)
if
(
token_ptr
!=
GSS_C_NO_BUFFER
)
free
(
recv_tok
.
value
);
free
(
recv_tok
.
value
);
if
(
send_tok
.
length
!=
0
)
{
// server expects another token
return
0
;
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
)
{
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_buffer
(
&
min_stat
,
&
send_tok
);
gss_release_name
(
&
min_stat
,
&
target_name
);
gss_release_name
(
&
min_stat
,
&
target_name
);
return
-
1
;
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
);
gss_release_buffer
(
&
min_stat
,
&
send_tok
);
if
(
maj_stat
!=
GSS_S_COMPLETE
&&
maj_stat
!=
GSS_S_CONTINUE_NEEDED
)
{
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
);
gss_release_name
(
&
min_stat
,
&
target_name
);
if
(
context
!=
GSS_C_NO_CONTEXT
)
if
(
context
!=
GSS_C_NO_CONTEXT
)
gss_delete_sec_context
(
&
min_stat
,
&
context
,
GSS_C_NO_BUFFER
);
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_)
...
@@ -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_
)
int
zmq
::
gssapi_client_t
::
process_next_token
(
msg_t
*
msg_
)
{
{
if
(
maj_stat
==
GSS_S_CONTINUE_NEEDED
)
{
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_initiate
(
msg_
,
&
recv_tok
.
value
,
recv_tok
.
length
)
<
0
)
{
if
(
process_token
(
msg_
,
token_flags
,
&
recv_tok
.
value
,
recv_tok
.
length
)
<
0
)
{
gss_release_name
(
&
min_stat
,
&
target_name
);
gss_release_name
(
&
min_stat
,
&
target_name
);
return
-
1
;
return
-
1
;
}
}
token_ptr
=
&
recv_tok
;
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
;
return
0
;
}
}
...
...
src/gssapi_client.hpp
View file @
3c414c4a
...
@@ -48,17 +48,26 @@ namespace zmq
...
@@ -48,17 +48,26 @@ namespace zmq
private
:
private
:
enum
state_t
{
enum
state_t
{
call_next_init
,
send_next_token
,
send_next_token
,
recv_next_token
,
recv_next_token
,
almost_ready
,
connected
ready
};
};
// Current FSM state
state_t
state
;
state_t
state
;
// Points to either send_tok or recv_tok
// during context initialization
gss_buffer_desc
*
token_ptr
;
gss_buffer_desc
*
token_ptr
;
// The desired underlying mechanism
gss_OID_set_desc
mechs
;
gss_OID_set_desc
mechs
;
// True iff client considers the server authenticated
bool
security_context_established
;
bool
security_context_established
;
int
initialize_context
();
int
produce_next_token
(
msg_t
*
msg_
);
int
produce_next_token
(
msg_t
*
msg_
);
int
process_next_token
(
msg_t
*
msg_
);
int
process_next_token
(
msg_t
*
msg_
);
};
};
...
...
src/gssapi_mechanism_base.cpp
View file @
3c414c4a
...
@@ -34,7 +34,7 @@
...
@@ -34,7 +34,7 @@
zmq
::
gssapi_mechanism_base_t
::
gssapi_mechanism_base_t
()
:
zmq
::
gssapi_mechanism_base_t
::
gssapi_mechanism_base_t
()
:
send_tok
(),
send_tok
(),
recv_tok
(),
recv_tok
(),
in_buf
(),
/// FIXME remove?
in_buf (),
target_name
(
GSS_C_NO_NAME
),
target_name
(
GSS_C_NO_NAME
),
service_name
(
NULL
),
service_name
(
NULL
),
maj_stat
(
GSS_S_COMPLETE
),
maj_stat
(
GSS_S_COMPLETE
),
...
@@ -42,7 +42,6 @@ zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t () :
...
@@ -42,7 +42,6 @@ zmq::gssapi_mechanism_base_t::gssapi_mechanism_base_t () :
init_sec_min_stat
(
0
),
init_sec_min_stat
(
0
),
ret_flags
(
0
),
ret_flags
(
0
),
gss_flags
(
GSS_C_MUTUAL_FLAG
|
GSS_C_REPLAY_FLAG
),
gss_flags
(
GSS_C_MUTUAL_FLAG
|
GSS_C_REPLAY_FLAG
),
token_flags
(
0
),
cred
(
GSS_C_NO_CREDENTIAL
),
cred
(
GSS_C_NO_CREDENTIAL
),
context
(
GSS_C_NO_CONTEXT
)
context
(
GSS_C_NO_CONTEXT
)
{
{
...
@@ -56,87 +55,106 @@ zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
...
@@ -56,87 +55,106 @@ zmq::gssapi_mechanism_base_t::~gssapi_mechanism_base_t ()
gss_delete_sec_context
(
&
min_stat
,
&
context
,
GSS_C_NO_BUFFER
);
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_
);
// Wrap the token value
zmq_assert
(
token_length_
<=
0xFFFFFFFFUL
);
int
state
;
gss_buffer_desc
plaintext
;
const
size_t
cmd_len
=
6
+
1
+
4
+
token_length_
;
gss_buffer_desc
wrapped
;
uint8_t
*
cmd_buf
=
static_cast
<
uint8_t
*>
(
malloc
(
cmd_len
));
plaintext
.
value
=
msg_
->
data
();
alloc_assert
(
cmd_buf
);
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
rc
=
msg_
->
init_size
(
8
+
4
+
wrapped
.
length
);
memcpy
(
ptr
,
"
\x05
TOKEN"
,
6
);
zmq_assert
(
rc
==
0
);
ptr
+=
6
;
// Add gss flags
uint8_t
*
ptr
=
static_cast
<
uint8_t
*>
(
msg_
->
data
());
put_uint8
(
ptr
,
static_cast
<
uint8_t
>
(
flags_
));
ptr
+=
1
;
// Add command string
memcpy
(
ptr
,
"
\x07
MESSAGE"
,
8
);
ptr
+=
8
;
// Add token length
// Add token length
put_uint32
(
ptr
,
static_cast
<
uint32_t
>
(
token_length_
));
put_uint32
(
ptr
,
static_cast
<
uint32_t
>
(
wrapped
.
length
));
ptr
+=
4
;
ptr
+=
4
;
// Add token value
// Add
wrapped
token value
memcpy
(
ptr
,
token_value_
,
token_length_
);
memcpy
(
ptr
,
wrapped
.
value
,
wrapped
.
length
);
ptr
+=
token_length_
;
ptr
+=
wrapped
.
length
;
const
int
rc
=
msg_
->
init_size
(
cmd_len
);
gss_release_buffer
(
&
min_stat
,
&
wrapped
);
errno_assert
(
rc
==
0
);
memcpy
(
msg_
->
data
(),
cmd_buf
,
cmd_len
);
free
(
cmd_buf
);
return
0
;
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_
);
const
uint8_t
*
ptr
=
static_cast
<
uint8_t
*>
(
msg_
->
data
());
uint8_t
*
ptr
=
static_cast
<
uint8_t
*>
(
msg_
->
data
());
size_t
bytes_left
=
msg_
->
size
();
size_t
bytes_left
=
msg_
->
size
();
// Get command name
// Get command string
if
(
bytes_left
<
6
||
memcmp
(
ptr
,
"
\x05
TOKEN"
,
6
))
{
if
(
bytes_left
<
8
||
memcmp
(
ptr
,
"
\x07
MESSAGE"
,
8
))
{
errno
=
EPROTO
;
return
-
1
;
}
ptr
+=
6
;
bytes_left
-=
6
;
// Get flags
if
(
bytes_left
<
1
)
{
errno
=
EPROTO
;
errno
=
EPROTO
;
return
-
1
;
return
-
1
;
}
}
flags_
=
static_cast
<
int
>
(
get_uint8
(
ptr
));
ptr
+=
8
;
ptr
+=
1
;
bytes_left
-=
8
;
bytes_left
-=
1
;
// Get token length
// Get token length
if
(
bytes_left
<
4
)
{
if
(
bytes_left
<
4
)
{
errno
=
EPROTO
;
errno
=
EPROTO
;
return
-
1
;
return
-
1
;
}
}
token_length_
=
get_uint32
(
ptr
);
gss_buffer_desc
wrapped
;
wrapped
.
length
=
get_uint32
(
ptr
);
ptr
+=
4
;
ptr
+=
4
;
bytes_left
-=
4
;
bytes_left
-=
4
;
// Get token value
. TODO do unwrap here to prevent this extra memcpy.
// Get token value
if
(
bytes_left
<
token_length_
)
{
if
(
bytes_left
<
wrapped
.
length
)
{
errno
=
EPROTO
;
errno
=
EPROTO
;
return
-
1
;
return
-
1
;
}
}
*
token_value_
=
static_cast
<
char
*>
(
malloc
(
token_length_
?
token_length_
:
1
));
// TODO: instead of malloc/memcpy, can we just do: wrapped.value = ptr;
if
(
token_length_
)
{
const
size_t
alloc_length
=
wrapped
.
length
?
wrapped
.
length
:
1
;
alloc_assert
(
*
token_value_
);
wrapped
.
value
=
static_cast
<
char
*>
(
malloc
(
alloc_length
));
memcpy
(
*
token_value_
,
ptr
,
token_length_
);
if
(
wrapped
.
length
)
{
ptr
+=
token_length_
;
alloc_assert
(
wrapped
.
value
);
bytes_left
-=
token_length_
;
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
)
{
if
(
bytes_left
>
0
)
{
errno
=
EPROTO
;
errno
=
EPROTO
;
return
-
1
;
return
-
1
;
...
@@ -145,69 +163,75 @@ int zmq::gssapi_mechanism_base_t::process_token (msg_t *msg_, int &flags_, void
...
@@ -145,69 +163,75 @@ int zmq::gssapi_mechanism_base_t::process_token (msg_t *msg_, int &flags_, void
return
0
;
return
0
;
}
}
/// TODO add support for TOKEN_SEND_MIC
int
zmq
::
gssapi_mechanism_base_t
::
produce_initiate
(
msg_t
*
msg_
,
void
*
token_value_
,
size_t
token_length_
)
/// TODO use gss_wrap_size_limit
int
zmq
::
gssapi_mechanism_base_t
::
produce_message
(
msg_t
*
msg_
)
{
{
// wrap it
zmq_assert
(
token_value_
);
int
state
;
zmq_assert
(
token_length_
<=
0xFFFFFFFFUL
);
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
);
// prepare msg_ for wrapped text
const
size_t
command_size
=
9
+
4
+
token_length_
;
int
rc
=
msg_
->
close
();
zmq_assert
(
rc
==
0
);
// produce token
const
int
rc
=
msg_
->
init_size
(
command_size
);
const
int
flags
=
(
TOKEN_DATA
|
TOKEN_WRAPPED
|
TOKEN_ENCRYPTED
);
errno_assert
(
rc
==
0
);
rc
=
produce_token
(
msg_
,
flags
,
wrapped
.
value
,
wrapped
.
length
);
zmq_assert
(
rc
==
0
);
uint8_t
*
ptr
=
static_cast
<
uint8_t
*>
(
msg_
->
data
());
gss_release_buffer
(
&
min_stat
,
&
wrapped
);
// Add command string
memcpy
(
ptr
,
"
\x08
INITIATE"
,
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
;
return
0
;
}
}
int
int
zmq
::
gssapi_mechanism_base_t
::
process_initiate
(
msg_t
*
msg_
,
void
**
token_value_
,
size_t
&
token_length_
)
zmq
::
gssapi_mechanism_base_t
::
process_message
(
msg_t
*
msg_
)
{
{
// process token
zmq_assert
(
token_value_
);
int
flags
;
gss_buffer_desc
wrapped
;
const
uint8_t
*
ptr
=
static_cast
<
uint8_t
*>
(
msg_
->
data
());
int
rc
=
process_token
(
msg_
,
flags
,
&
wrapped
.
value
,
wrapped
.
length
);
size_t
bytes_left
=
msg_
->
size
();
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
(
maj_stat
==
GSS_S_COMPLETE
);
// Get command string
zmq_assert
(
state
);
if
(
bytes_left
<
9
||
memcmp
(
ptr
,
"
\x08
INITIATE"
,
9
))
{
errno
=
EPROTO
;
return
-
1
;
}
ptr
+=
9
;
bytes_left
-=
9
;
// re-init msg_ with plaintext
// Get token length
rc
=
msg_
->
close
();
if
(
bytes_left
<
4
)
{
zmq_assert
(
rc
==
0
);
errno
=
EPROTO
;
msg_
->
init_size
(
plaintext
.
length
);
return
-
1
;
zmq_assert
(
rc
==
0
);
}
token_length_
=
get_uint32
(
ptr
);
ptr
+=
4
;
bytes_left
-=
4
;
memcpy
(
msg_
->
data
(),
plaintext
.
value
,
plaintext
.
length
);
// Get token value
gss_release_buffer
(
&
min_stat
,
&
plaintext
);
if
(
bytes_left
<
token_length_
)
{
gss_release_buffer
(
&
min_stat
,
&
wrapped
);
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
;
return
0
;
}
}
...
...
src/gssapi_mechanism_base.hpp
View file @
3c414c4a
...
@@ -29,8 +29,9 @@ namespace zmq
...
@@ -29,8 +29,9 @@ namespace zmq
class
msg_t
;
class
msg_t
;
/// Both gssapi_server and gssapi_client need to produce and process
/// Commonalities between clients and servers are captured here.
/// GSSAPI tokens. Common implementation is captured here.
/// For example, clients and server both need to produce and
/// process INITIATE and MESSAGE commands.
class
gssapi_mechanism_base_t
class
gssapi_mechanism_base_t
{
{
public
:
public
:
...
@@ -38,42 +39,55 @@ namespace zmq
...
@@ -38,42 +39,55 @@ namespace zmq
virtual
~
gssapi_mechanism_base_t
()
=
0
;
virtual
~
gssapi_mechanism_base_t
()
=
0
;
protected
:
protected
:
/// Produce a
security context initialization toke
n
/// Produce a
n INITIATE during security context initializatio
n
int
produce_
token
(
msg_t
*
msg_
,
int
flags_
,
void
*
token_value_
,
size_t
token_length
_
);
int
produce_
initiate
(
msg_t
*
msg_
,
void
*
data_
,
size_t
data_len
_
);
/// Process a
security context initialization toke
n
/// Process a
n INITIATE during security context initializatio
n
int
process_
token
(
msg_t
*
msg_
,
int
&
flags_
,
void
**
token_value_
,
size_t
&
token_length
_
);
int
process_
initiate
(
msg_t
*
msg_
,
void
**
data_
,
size_t
&
data_len
_
);
///
Produce a wrapped message
using the established security context
///
Encode a MESSAGE
using the established security context
int
produc
e_message
(
msg_t
*
msg_
);
int
encod
e_message
(
msg_t
*
msg_
);
///
Process a wrapped message
using the established security context
///
Decode a MESSAGE
using the established security context
int
process
_message
(
msg_t
*
msg_
);
int
decode
_message
(
msg_t
*
msg_
);
/// Acquire security context credentials
/// 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
:
protected
:
const
static
int
TOKEN_NOOP
=
(
1
<<
0
);
/// Opaque GSSAPI token for outgoing data
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
);
gss_buffer_desc
send_tok
;
gss_buffer_desc
send_tok
;
/// Opaque GSSAPI token for incoming data
gss_buffer_desc
recv_tok
;
gss_buffer_desc
recv_tok
;
gss_buffer_desc
in_buf
;
/// Opaque GSSAPI representation of service_name
gss_name_t
target_name
;
gss_name_t
target_name
;
/// Human-readable service principal name
char
*
service_name
;
char
*
service_name
;
/// Status code returned by GSSAPI functions
OM_uint32
maj_stat
;
OM_uint32
maj_stat
;
/// Status code returned by the underlying mechanism
OM_uint32
min_stat
;
OM_uint32
min_stat
;
/// Status code returned by the underlying mechanism
/// during context initialization
OM_uint32
init_sec_min_stat
;
OM_uint32
init_sec_min_stat
;
/// Flags returned by GSSAPI (ignored)
OM_uint32
ret_flags
;
OM_uint32
ret_flags
;
/// Flags returned by GSSAPI (ignored)
OM_uint32
gss_flags
;
OM_uint32
gss_flags
;
int
token_flags
;
/// Credentials used to establish security context
gss_cred_id_t
cred
;
gss_cred_id_t
cred
;
/// Opaque GSSAPI representation of the security context
gss_ctx_id_t
context
;
gss_ctx_id_t
context
;
};
};
}
}
#endif
#endif
src/gssapi_server.cpp
View file @
3c414c4a
...
@@ -41,16 +41,12 @@ zmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,
...
@@ -41,16 +41,12 @@ zmq::gssapi_server_t::gssapi_server_t (session_base_t *session_,
state
(
recv_next_token
),
state
(
recv_next_token
),
security_context_established
(
false
)
security_context_established
(
false
)
{
{
service_name
=
(
char
*
)
"host"
;
/// FIXME add service_name to options
service_name
=
(
char
*
)
"host"
;
// TODO: add service_name to options
int
rc
=
acquire_credentials
(
service_name
,
&
cred
);
/// FIXME add creds to options too?
int
rc
=
acquire_credentials
(
service_name
,
&
cred
);
// TODO: add creds to options too?
if
(
rc
==
0
)
{
if
(
rc
==
0
)
fprintf
(
stderr
,
"%s:%d: acquire creds successful
\n
"
,
__FILE__
,
__LINE__
);
/// FIXME remove
maj_stat
=
GSS_S_CONTINUE_NEEDED
;
maj_stat
=
GSS_S_CONTINUE_NEEDED
;
}
else
else
{
fprintf
(
stderr
,
"%s:%d: acquire creds failed
\n
"
,
__FILE__
,
__LINE__
);
/// FIXME remove
maj_stat
=
GSS_S_FAILURE
;
maj_stat
=
GSS_S_FAILURE
;
}
}
}
zmq
::
gssapi_server_t
::~
gssapi_server_t
()
zmq
::
gssapi_server_t
::~
gssapi_server_t
()
...
@@ -61,64 +57,58 @@ 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
zmq
::
gssapi_server_t
::
next_handshake_command
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
if
(
state
!=
send_next_token
)
{
errno
=
EAGAIN
;
switch
(
state
)
{
return
-
1
;
case
send_next_token
:
}
rc
=
produce_next_token
(
msg_
);
if
(
rc
==
0
)
if
(
produce_next_token
(
msg_
)
<
0
)
state
=
security_context_established
?
almost_ready
:
recv_next_token
;
return
-
1
;
break
;
case
almost_ready
:
if
(
maj_stat
!=
GSS_S_CONTINUE_NEEDED
&&
maj_stat
!=
GSS_S_COMPLETE
)
state
=
ready
;
return
-
1
;
break
;
default
:
if
(
maj_stat
==
GSS_S_COMPLETE
)
{
errno
=
EPROTO
;
gss_release_name
(
&
min_stat
,
&
target_name
);
rc
=
-
1
;
security_context_established
=
true
;
break
;
state
=
connected
;
}
else
{
state
=
recv_next_token
;
}
}
return
rc
;
return
0
;
}
}
int
zmq
::
gssapi_server_t
::
process_handshake_command
(
msg_t
*
msg_
)
int
zmq
::
gssapi_server_t
::
process_handshake_command
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
if
(
state
!=
recv_next_token
)
{
errno
=
EPROTO
;
switch
(
state
)
{
return
-
1
;
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
);
}
}
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
zmq
::
gssapi_server_t
::
encode
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
zmq_assert
(
state
==
connected
);
zmq_assert
(
state
==
ready
);
return
encode_message
(
msg_
);
return
rc
;
}
}
int
zmq
::
gssapi_server_t
::
decode
(
msg_t
*
msg_
)
int
zmq
::
gssapi_server_t
::
decode
(
msg_t
*
msg_
)
{
{
int
rc
=
0
;
zmq_assert
(
state
==
connected
);
zmq_assert
(
state
==
ready
);
return
decode_message
(
msg_
);
return
rc
;
}
}
int
zmq
::
gssapi_server_t
::
zap_msg_available
()
int
zmq
::
gssapi_server_t
::
zap_msg_available
()
...
@@ -128,53 +118,42 @@ 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
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
==
connected
;
return
state
==
ready
;
}
}
int
zmq
::
gssapi_server_t
::
produce_next_token
(
msg_t
*
msg_
)
int
zmq
::
gssapi_server_t
::
produce_next_token
(
msg_t
*
msg_
)
{
{
if
(
send_tok
.
length
!=
0
)
{
// client expects another token
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_initiate
(
msg_
,
send_tok
.
value
,
send_tok
.
length
)
<
0
)
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);
return
-
1
;
return
-
1
;
}
gss_release_buffer
(
&
min_stat
,
&
send_tok
);
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
)
{
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
);
gss_release_name
(
&
min_stat
,
&
target_name
);
if
(
context
!=
GSS_C_NO_CONTEXT
)
if
(
context
!=
GSS_C_NO_CONTEXT
)
gss_delete_sec_context
(
&
min_stat
,
&
context
,
GSS_C_NO_BUFFER
);
gss_delete_sec_context
(
&
min_stat
,
&
context
,
GSS_C_NO_BUFFER
);
return
-
1
;
return
-
1
;
}
}
if
(
maj_stat
==
GSS_S_COMPLETE
)
{
gss_release_name
(
&
min_stat
,
&
target_name
);
security_context_established
=
true
;
}
return
0
;
return
0
;
}
}
int
zmq
::
gssapi_server_t
::
process_next_token
(
msg_t
*
msg_
)
int
zmq
::
gssapi_server_t
::
process_next_token
(
msg_t
*
msg_
)
{
{
if
(
maj_stat
==
GSS_S_CONTINUE_NEEDED
)
{
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_initiate
(
msg_
,
&
recv_tok
.
value
,
recv_tok
.
length
)
<
0
)
{
if
(
process_token
(
msg_
,
token_flags
,
&
recv_tok
.
value
,
recv_tok
.
length
)
<
0
)
{
if
(
target_name
!=
GSS_C_NO_NAME
)
if
(
target_name
!=
GSS_C_NO_NAME
)
gss_release_name
(
&
min_stat
,
&
target_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
;
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
,
maj_stat
=
gss_accept_sec_context
(
&
init_sec_min_stat
,
&
context
,
cred
,
&
recv_tok
,
GSS_C_NO_CHANNEL_BINDINGS
,
&
recv_tok
,
GSS_C_NO_CHANNEL_BINDINGS
,
&
target_name
,
&
doid
,
&
send_tok
,
&
target_name
,
&
doid
,
&
send_tok
,
...
@@ -184,7 +163,5 @@ int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
...
@@ -184,7 +163,5 @@ int zmq::gssapi_server_t::process_next_token (msg_t *msg_)
free
(
recv_tok
.
value
);
free
(
recv_tok
.
value
);
recv_tok
.
value
=
NULL
;
recv_tok
.
value
=
NULL
;
}
}
return
0
;
}
}
src/gssapi_server.hpp
View file @
3c414c4a
...
@@ -54,19 +54,25 @@ namespace zmq
...
@@ -54,19 +54,25 @@ namespace zmq
enum
state_t
{
enum
state_t
{
send_next_token
,
send_next_token
,
recv_next_token
,
recv_next_token
,
waiting_for_zap_reply
,
connected
almost_ready
,
ready
};
};
session_base_t
*
const
session
;
session_base_t
*
const
session
;
const
std
::
string
peer_address
;
const
std
::
string
peer_address
;
// Current FSM state
state_t
state
;
state_t
state
;
// True iff server considers the client authenticated
bool
security_context_established
;
bool
security_context_established
;
// The underlying mechanism type (ignored)
gss_OID
doid
;
gss_OID
doid
;
int
produce_next_token
(
msg_t
*
msg_
);
void
accept_context
();
int
process_next_token
(
msg_t
*
msg_
);
int
produce_next_token
(
msg_t
*
msg_
);
int
process_next_token
(
msg_t
*
msg_
);
};
};
}
}
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment