Skip to content

Commit

Permalink
Problem: strict ZAP protocol adherence is backward incompatible
Browse files Browse the repository at this point in the history
Solution: add ZMQ_ZAP_DOMAIN_REQUIRED to hide backward incompatible
change and make it disabled by default.
In a future release that breaks API compatibility we can then switch
the default to enabled in order to achieve full RFC compatibility.

Fixes zeromq#2762
  • Loading branch information
bluca committed Oct 9, 2017
1 parent 50bddba commit 0800772
Show file tree
Hide file tree
Showing 10 changed files with 73 additions and 4 deletions.
12 changes: 12 additions & 0 deletions doc/zmq_getsockopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -838,6 +838,18 @@ Default value:: not set
Applicable socket types:: all, when using TCP transport


ZMQ_ZAP_DOMAIN_REQUIRED: Retrieve ZAP domain handling mode
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_ZAP_DOMAIN_REQUIRED' option shall retrive the flag that determines
whether a ZAP domain is strictly required by the library or not.

[horizontal]
Option value type:: int
Option value unit:: 0, 1
Default value:: 0
Applicable socket types:: all, when using ZAP


ZMQ_VMCI_BUFFER_SIZE: Retrieve buffer size of the VMCI socket
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The `ZMQ_VMCI_BUFFER_SIZE` option shall retrieve the size of the underlying
Expand Down
20 changes: 19 additions & 1 deletion doc/zmq_setsockopt.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1081,7 +1081,9 @@ ZMQ_ZAP_DOMAIN: Set RFC 27 authentication domain
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the domain for ZAP (ZMQ RFC 27) authentication. A ZAP domain must be
specified to enable authentication. When the ZAP domain is empty, which is
the default, ZAP authentication is disabled.
the default, ZAP authentication is disabled. This is not compatible with
previous versions of libzmq, so it can be controlled by ZMQ_ZAP_DOMAIN_REQUIRED
which for now is disabled by default.
See http://rfc.zeromq.org/spec:27 for more details.

[horizontal]
Expand All @@ -1091,6 +1093,22 @@ Default value:: empty
Applicable socket types:: all, when using TCP transport


ZMQ_ZAP_DOMAIN_REQUIRED: Set ZAP domain handling to strictly adhere the RFC
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The ZAP (ZMQ RFC 27) authentication protocol specifies that a domain must
always be set. Older versions of libzmq did not follow the spec and allowed
an empty domain to be set.
This option can be used to enabled or disable the stricter, backward
incompatible behaviour. For now it is disabled by default, but in a future
version it will be set to enabled by default.

[horizontal]
Option value type:: int
Option value unit:: 0, 1
Default value:: 0
Applicable socket types:: all, when using ZAP


ZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assign an arbitrary number of filters that will be applied for each new TCP
Expand Down
1 change: 1 addition & 0 deletions include/zmq.h
Original file line number Diff line number Diff line change
Expand Up @@ -570,6 +570,7 @@ ZMQ_EXPORT void zmq_threadclose (void* thread);
#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91
#define ZMQ_BINDTODEVICE 92
#define ZMQ_ZAP_DOMAIN_REQUIRED 93

/* DRAFT 0MQ socket events and monitoring */
/* Unspecified system errors during handshake. Event value is an errno. */
Expand Down
8 changes: 7 additions & 1 deletion src/curve_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -390,7 +390,9 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
rc = crypto_box_beforenm (cn_precom, cn_client, cn_secret);
zmq_assert (rc == 0);

if (zap_required ()) {
// Given this is a backward-incompatible change, it's behind a socket
// option disabled by default.
if (zap_required () || !options.zap_domain_required) {
// Use ZAP protocol (RFC 27) to authenticate the user.
rc = session->zap_connect ();
if (rc == 0) {
Expand All @@ -404,6 +406,10 @@ int zmq::curve_server_t::process_initiate (msg_t *msg_)
rc = receive_and_process_zap_reply ();
if (rc == -1)
return -1;
} else if (!options.zap_domain_required) {
// This supports the Stonehouse pattern (encryption without
// authentication) in legacy mode (domain set but no handler).
state = sending_ready;
} else {
session->get_socket ()->event_handshake_failed_no_detail (
session->get_endpoint (), EFAULT);
Expand Down
18 changes: 17 additions & 1 deletion src/options.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,8 @@ zmq::options_t::options_t () :
heartbeat_ttl (0),
heartbeat_interval (0),
heartbeat_timeout (-1),
use_fd (-1)
use_fd (-1),
zap_domain_required (false)
{
memset (curve_public_key, 0, CURVE_KEYSIZE);
memset (curve_secret_key, 0, CURVE_KEYSIZE);
Expand Down Expand Up @@ -628,6 +629,14 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
}
break;

case ZMQ_ZAP_DOMAIN_REQUIRED:
if (is_int) {
zap_domain_required = (value != 0);
return 0;
}
break;


default:
#if defined (ZMQ_ACT_MILITANT)
// There are valid scenarios for probing with unknown socket option
Expand Down Expand Up @@ -1052,6 +1061,13 @@ int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
}
break;

case ZMQ_ZAP_DOMAIN_REQUIRED:
if (is_int) {
*value = zap_domain_required;
return 0;
}
break;

default:
#if defined (ZMQ_ACT_MILITANT)
malformed = false;
Expand Down
3 changes: 3 additions & 0 deletions src/options.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,9 @@ namespace zmq

// Device to bind the underlying socket to, eg. VRF or interface
std::string bound_device;

// Enforce a non-empty ZAP domain requirement for PLAIN auth
bool zap_domain_required;
};
}

Expand Down
5 changes: 4 additions & 1 deletion src/plain_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,10 @@ zmq::plain_server_t::plain_server_t (session_base_t *session_,
// Note that there is no point to PLAIN if ZAP is not set up to handle the
// username and password, so if ZAP is not configured it is considered a
// failure.
zmq_assert (zap_required());
// Given this is a backward-incompatible change, it's behind a socket
// option disabled by default.
if (options.zap_domain_required)
zmq_assert (zap_required());
}

zmq::plain_server_t::~plain_server_t ()
Expand Down
1 change: 1 addition & 0 deletions src/zmq_draft.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
#define ZMQ_GSSAPI_PRINCIPAL_NAMETYPE 90
#define ZMQ_GSSAPI_SERVICE_PRINCIPAL_NAMETYPE 91
#define ZMQ_BINDTODEVICE 92
#define ZMQ_ZAP_DOMAIN_REQUIRED 93

/* DRAFT 0MQ socket events and monitoring */
/* Unspecified system errors during handshake. Event value is an errno. */
Expand Down
2 changes: 2 additions & 0 deletions tests/test_security_zap.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -324,6 +324,7 @@ void test_zap_errors (socket_config_fn server_socket_config_,
shutdown_context_and_server_side (ctx, zap_thread, server, server_mon,
handler);

#ifdef ZMQ_ZAP_DOMAIN_REQUIRED
// no ZAP handler
fprintf (stderr, "test_zap_unsuccessful no ZAP handler started\n");
setup_context_and_server_side (&ctx, &handler, &zap_thread, &server,
Expand All @@ -339,6 +340,7 @@ void test_zap_errors (socket_config_fn server_socket_config_,
client_socket_config_, client_socket_config_data_);
shutdown_context_and_server_side (ctx, zap_thread, server, server_mon,
handler);
#endif

// ZAP handler disconnecting on first message
fprintf(stderr, "test_zap_unsuccessful ZAP handler disconnects\n");
Expand Down
7 changes: 7 additions & 0 deletions tests/testutil_security.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,13 @@ void socket_config_curve_server (void *server, void *server_secret)
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, test_zap_domain,
strlen (test_zap_domain));
assert (rc == 0);

#ifdef ZMQ_ZAP_DOMAIN_REQUIRED
int required = 1;
rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN_REQUIRED, &required,
sizeof (int));
assert (rc == 0);
#endif
}

struct curve_client_data_t
Expand Down

0 comments on commit 0800772

Please sign in to comment.