From 1c5a63e9394865ce01b91b4678d1932f7dd65087 Mon Sep 17 00:00:00 2001 From: Luca Boccassi Date: Thu, 22 Mar 2018 19:27:23 +0000 Subject: [PATCH] Problem: backward incompatible change to NULL with ZAP Solution: like for other mechanism, do not enforce strict ZAP protocol adherence unless the specific socket option is enabled with NULL auth. Add test to exercise this functionality, and fix ZAP test to set the socket option when it uses NULL auth. See: https://github.com/zeromq/pyzmq/pull/1152 --- src/null_mechanism.cpp | 29 +++++++++++---------- tests/test_security_null.cpp | 49 +++++++++++++++++++++++++++++++++--- tests/test_security_zap.cpp | 8 +++--- 3 files changed, 67 insertions(+), 19 deletions(-) diff --git a/src/null_mechanism.cpp b/src/null_mechanism.cpp index 61c353a6..70fa958b 100644 --- a/src/null_mechanism.cpp +++ b/src/null_mechanism.cpp @@ -69,24 +69,27 @@ int zmq::null_mechanism_t::next_handshake_command (msg_t *msg_) errno = EAGAIN; return -1; } + // Given this is a backward-incompatible change, it's behind a socket + // option disabled by default. int rc = session->zap_connect (); - if (rc == -1) { + if (rc == -1 && options.zap_enforce_domain) { session->get_socket ()->event_handshake_failed_no_detail ( session->get_endpoint (), EFAULT); return -1; + } else if (rc == 0) { + send_zap_request (); + zap_request_sent = true; + + // TODO actually, it is quite unlikely that we can read the ZAP + // reply already, but removing this has some strange side-effect + // (probably because the pipe's in_active flag is true until a read + // is attempted) + rc = receive_and_process_zap_reply (); + if (rc != 0) + return -1; + + zap_reply_received = true; } - send_zap_request (); - zap_request_sent = true; - - // TODO actually, it is quite unlikely that we can read the ZAP - // reply already, but removing this has some strange side-effect - // (probably because the pipe's in_active flag is true until a read - // is attempted) - rc = receive_and_process_zap_reply (); - if (rc != 0) - return -1; - - zap_reply_received = true; } if (zap_reply_received && status_code != "200") { diff --git a/tests/test_security_null.cpp b/tests/test_security_null.cpp index 94729ed8..90ad5caa 100644 --- a/tests/test_security_null.cpp +++ b/tests/test_security_null.cpp @@ -88,12 +88,55 @@ int main (void) void *ctx = zmq_ctx_new (); assert (ctx); + // We first test client/server with a ZAP domain but with no handler + // If there is no handler, libzmq should ignore the ZAP option unless + // ZMQ_ZAP_ENFORCE_DOMAIN is set + void *server = zmq_socket (ctx, ZMQ_DEALER); + assert (server); + void *client = zmq_socket (ctx, ZMQ_DEALER); + assert (client); + int rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 5); + assert (rc == 0); + rc = zmq_bind (server, "tcp://127.0.0.1:*"); + assert (rc == 0); + rc = zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, my_endpoint, &len); + assert (rc == 0); + rc = zmq_connect (client, my_endpoint); + assert (rc == 0); + bounce (server, client); + close_zero_linger (client); + close_zero_linger (server); + +#ifdef ZMQ_ZAP_ENFORCE_DOMAIN + // Now set ZMQ_ZAP_ENFORCE_DOMAIN which strictly enforces the ZAP + // RFC but is backward-incompatible, now it should fail + server = zmq_socket (ctx, ZMQ_DEALER); + assert (server); + client = zmq_socket (ctx, ZMQ_DEALER); + assert (client); + int required = 1; + rc = + zmq_setsockopt (server, ZMQ_ZAP_ENFORCE_DOMAIN, &required, sizeof (int)); + assert (rc == 0); + rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, "TEST", 5); + assert (rc == 0); + rc = zmq_bind (server, "tcp://127.0.0.1:*"); + assert (rc == 0); + rc = zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, my_endpoint, &len); + assert (rc == 0); + rc = zmq_connect (client, my_endpoint); + assert (rc == 0); + expect_bounce_fail (server, client); + close_zero_linger (client); + close_zero_linger (server); +#endif + // Spawn ZAP handler // We create and bind ZAP socket in main thread to avoid case // where child thread does not start up fast enough. void *handler = zmq_socket (ctx, ZMQ_REP); assert (handler); - int rc = zmq_bind (handler, "inproc://zeromq.zap.01"); + rc = zmq_bind (handler, "inproc://zeromq.zap.01"); assert (rc == 0); void *zap_thread = zmq_threadstart (&zap_handler, handler); @@ -101,9 +144,9 @@ int main (void) // We first test client/server with no ZAP domain // Libzmq does not call our ZAP handler, the connect must succeed - void *server = zmq_socket (ctx, ZMQ_DEALER); + server = zmq_socket (ctx, ZMQ_DEALER); assert (server); - void *client = zmq_socket (ctx, ZMQ_DEALER); + client = zmq_socket (ctx, ZMQ_DEALER); assert (client); rc = zmq_bind (server, "tcp://127.0.0.1:*"); assert (rc == 0); diff --git a/tests/test_security_zap.cpp b/tests/test_security_zap.cpp index f33f041a..fb76b381 100644 --- a/tests/test_security_zap.cpp +++ b/tests/test_security_zap.cpp @@ -326,10 +326,12 @@ void test_zap_errors (socket_config_fn server_socket_config_, #ifdef ZMQ_ZAP_ENFORCE_DOMAIN // no ZAP handler + int enforce = 1; fprintf (stderr, "test_zap_unsuccessful no ZAP handler started\n"); - setup_context_and_server_side (&ctx, &handler, &zap_thread, &server, - &server_mon, my_endpoint, NULL, - server_socket_config_); + setup_context_and_server_side ( + &ctx, &handler, &zap_thread, &server, &server_mon, my_endpoint, NULL, + server_socket_config_, + server_socket_config_data_ ? server_socket_config_data_ : &enforce); test_zap_unsuccessful_no_handler ( ctx, my_endpoint, server, server_mon, #ifdef ZMQ_BUILD_DRAFT_API