0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-27 07:31:03 +08:00

Added ZMQ_ZAP_DOMAIN socket option

* This is passed to the ZAP handler in the 'domain' field

* If not set, or empty, then NULL security does not call the ZAP handler

* This resolves the phantom ZAP request syndrome seen with sockets where
  security was never intended (e.g. in test cases)

* This means if you install a ZAP handler, it will not get any requests
  for new connections until you take some explicit action, which can be
  setting a username/password for PLAIN, a key for CURVE, or the domain
  for NULL.
This commit is contained in:
Pieter Hintjens 2013-09-09 20:40:34 +02:00
parent c45d91a106
commit 6725c4644f
11 changed files with 171 additions and 112 deletions

View File

@ -579,6 +579,20 @@ Default value:: null
Applicable socket types:: all, when using TCP transport
ZMQ_ZAP_DOMAIN: Retrieve RFC 27 authentication domain
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_ZAP_DOMAIN' option shall retrieve the last ZAP domain set for
the socket. The returned value shall be a NULL-terminated string and MAY
be empty. The returned size SHALL include the terminating null byte.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
RETURN VALUE
------------
The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it

View File

@ -682,6 +682,22 @@ Default value:: NULL
Applicable socket types:: all, when using TCP transport
ZMQ_ZAP_DOMAIN: Set RFC 27 authentication domain
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the domain for ZAP (ZMQ RFC 27) authentication. For NULL security (the
default on all tcp:// connections), ZAP authentication only happens if you
set a non-empty domain. For PLAIN and CURVE security, ZAP requests are always
made, if there is a ZAP handler present. See http://rfc.zeromq.org/spec:27
for more details.
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP transport
ZMQ_CONFLATE: Keep only last message
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -279,6 +279,7 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_REQ_REQUEST_IDS 52
#define ZMQ_REQ_STRICT 53
#define ZMQ_CONFLATE 54
#define ZMQ_ZAP_DOMAIN 55
/* Message options */
#define ZMQ_MORE 1

View File

@ -523,8 +523,9 @@ void zmq::curve_server_t::send_zap_request (const uint8_t *key)
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
@ -539,7 +540,7 @@ void zmq::curve_server_t::send_zap_request (const uint8_t *key)
// Identity frame
rc = msg.init_size (options.identity_size);
errno_assert(rc == 0);
errno_assert (rc == 0);
memcpy (msg.data (), options.identity, options.identity_size);
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);

View File

@ -44,8 +44,10 @@ zmq::null_mechanism_t::null_mechanism_t (session_base_t *session_,
zap_request_sent (false),
zap_reply_received (false)
{
const int rc = session->zap_connect ();
if (rc == 0)
// NULL mechanism only uses ZAP if there's a domain defined
// This prevents ZAP requests on naive sockets
if (options.zap_domain.size () > 0
&& session->zap_connect () == 0)
zap_connected = true;
}
@ -182,8 +184,9 @@ void zmq::null_mechanism_t::send_zap_request ()
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);

View File

@ -285,6 +285,13 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
}
break;
case ZMQ_ZAP_DOMAIN:
if (optvallen_ >= 0 && optvallen_ < 256) {
zap_domain.assign ((const char *) optval_, optvallen_);
return 0;
}
break;
// If libsodium isn't installed, these options provoke EINVAL
# ifdef HAVE_LIBSODIUM
case ZMQ_CURVE_SERVER:
@ -560,6 +567,14 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
}
break;
case ZMQ_ZAP_DOMAIN:
if (*optvallen_ >= zap_domain.size () + 1) {
memcpy (optval_, zap_domain.c_str (), zap_domain.size () + 1);
*optvallen_ = zap_domain.size () + 1;
return 0;
}
break;
// If libsodium isn't installed, these options provoke EINVAL
# ifdef HAVE_LIBSODIUM
case ZMQ_CURVE_SERVER:

View File

@ -123,6 +123,9 @@ namespace zmq
// If peer is acting as server for PLAIN or CURVE mechanisms
int as_server;
// ZAP authentication domain
std::string zap_domain;
// Security credentials for PLAIN mechanism
std::string plain_username;
std::string plain_password;

View File

@ -368,8 +368,9 @@ void zmq::plain_mechanism_t::send_zap_request (const std::string &username,
errno_assert (rc == 0);
// Domain frame
rc = msg.init ();
rc = msg.init_size (options.zap_domain.length ());
errno_assert (rc == 0);
memcpy (msg.data (), options.zap_domain.c_str (), options.zap_domain.length ());
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);
errno_assert (rc == 0);
@ -384,7 +385,7 @@ void zmq::plain_mechanism_t::send_zap_request (const std::string &username,
// Identity frame
rc = msg.init_size (options.identity_size);
errno_assert(rc == 0);
errno_assert (rc == 0);
memcpy (msg.data (), options.identity, options.identity_size);
msg.set_flags (msg_t::more);
rc = session->write_zap_msg (&msg);

View File

@ -49,6 +49,8 @@ static void zap_handler (void *ctx)
char *address = s_recv (zap);
char *identity = s_recv (zap);
char *mechanism = s_recv (zap);
printf ("CURVE domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
uint8_t client_key [32];
int size = zmq_recv (zap, client_key, 32, 0);
assert (size == 32);

View File

@ -43,12 +43,11 @@ zap_handler (void *ctx)
char *identity = s_recv (zap);
char *mechanism = s_recv (zap);
printf ("domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
assert (streq (version, "1.0"));
assert (streq (mechanism, "NULL"));
// TODO: null_mechanism.cpp issues ZAP requests for connections other
// than the expected one. In these cases identity is not set, and the
// test fails. We'd expect one ZAP request per real client connection.
// assert (streq (identity, "IDENT"));
assert (streq (identity, "IDENT"));
s_sendmore (zap, version);
s_sendmore (zap, sequence);
@ -82,6 +81,8 @@ int main (void)
assert (server);
int rc = zmq_setsockopt (server, ZMQ_IDENTITY, "IDENT", 6);
assert (rc == 0);
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 4);
assert (rc == 0);
rc = zmq_bind (server, "tcp://*:9999");
assert (rc == 0);

View File

@ -43,6 +43,8 @@ zap_handler (void *ctx)
char *mechanism = s_recv (zap);
char *username = s_recv (zap);
char *password = s_recv (zap);
printf ("PLAIN domain=%s address=%s identity=%s mechanism=%s\n",
domain, address, identity, mechanism);
assert (streq (version, "1.0"));
assert (streq (mechanism, "PLAIN"));