0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-27 15:41:05 +08:00

Added configuration for PLAIN security

* ZMQ_PLAIN_SERVER, ZMQ_PLAIN_USERNAME, ZMQ_PLAIN_PASSWORD options
* Man page changes to zmq_setsockopt and zmq_getsockopt
* Man pages for ZMQ_NULL, ZMQ_PLAIN, and ZMQ_CURVE
* Test program test_security
This commit is contained in:
Pieter Hintjens 2013-05-15 17:54:03 +02:00
parent 8ea779c8f7
commit e1f797b048
14 changed files with 693 additions and 309 deletions

1
.gitignore vendored
View File

@ -47,6 +47,7 @@ tests/test_raw_sock
tests/test_disconnect_inproc tests/test_disconnect_inproc
tests/test_ctx_options tests/test_ctx_options
tests/test_iov tests/test_iov
tests/test_security
src/platform.hpp* src/platform.hpp*
src/stamp-h1 src/stamp-h1
perf/local_lat perf/local_lat

View File

@ -8,9 +8,10 @@ MAN3 = zmq_bind.3 zmq_unbind.3 zmq_connect.3 zmq_disconnect.3 zmq_close.3 \
zmq_getsockopt.3 zmq_setsockopt.3 \ zmq_getsockopt.3 zmq_setsockopt.3 \
zmq_socket.3 zmq_socket_monitor.3 zmq_poll.3 \ zmq_socket.3 zmq_socket_monitor.3 zmq_poll.3 \
zmq_errno.3 zmq_strerror.3 zmq_version.3 zmq_proxy.3 \ zmq_errno.3 zmq_strerror.3 zmq_version.3 zmq_proxy.3 \
zmq_sendmsg.3 zmq_recvmsg.3 zmq_init.3 zmq_term.3 zmq_sendmsg.3 zmq_recvmsg.3 zmq_init.3 zmq_term.3
MAN7 = zmq.7 zmq_tcp.7 zmq_pgm.7 zmq_epgm.7 zmq_inproc.7 zmq_ipc.7 MAN7 = zmq.7 zmq_tcp.7 zmq_pgm.7 zmq_epgm.7 zmq_inproc.7 zmq_ipc.7 \
zmq_null.7 zmq_plain.7 zmq_curve.7
MAN_DOC = $(MAN1) $(MAN3) $(MAN7) MAN_DOC = $(MAN1) $(MAN3) $(MAN7)

View File

@ -177,6 +177,23 @@ two sockets, opaquely. A proxy may optionally capture all traffic to a third
socket. To start a proxy in an application thread, use linkzmq:zmq_proxy[3]. socket. To start a proxy in an application thread, use linkzmq:zmq_proxy[3].
Security
~~~~~~~~
A 0MQ socket can select a security mechanism. Both peers must use the same
security mechanism.
The following security mechanisms are provided for IPC and TCP connections:
Null security::
linkzmq:zmq_null[7]
Clear-text authentication using username and password::
linkzmq:zmq_clear[7]
Secure authentication and encryption::
linkzmq:zmq_curve[7]
ERROR HANDLING ERROR HANDLING
-------------- --------------
The 0MQ library functions handle errors using the standard conventions found on The 0MQ library functions handle errors using the standard conventions found on

40
doc/zmq_curve.txt Normal file
View File

@ -0,0 +1,40 @@
zmq_curve(7)
============
NAME
----
zmq_curve - clear-text authentication
SYNOPSIS
--------
The CURVE mechanism defines a mechanism for secure authentication and
confidentiality for communications between a client and a server. CURVE
is intended for use on public networks. The CURVE mechanism is defined
by this document: <http://rfc.zeromq.org/spec:25>.
SERVER AND CLIENT ROLES
-----------------------
To use CURVE, the server shall set the ZMQ_CURVE_SERVER option, and the
client shall set the ZMQ_CURVE_PUBLICKEY and ZMQ_CURVE_SERVERKEY socket
options. Which peer binds, and which connects, is not relevant.
NOTE: this isn't implemented and not fully defined. The server keypair
needs to be persistent, and it would be sensible to define a format for
this in CurveZMQ
SEE ALSO
--------
linkzmq:zmq_setsockopt[3]
linkzmq:zmq_null[7]
linkzmq:zmq_plain[7]
linkzmq:zmq[7]
AUTHORS
-------
This page was written by the 0MQ community. To make a change please
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.

View File

@ -431,7 +431,7 @@ a ZMQ DSN. Note that if the TCP host is INADDR_ANY, indicated by a *, then
the returned address will be 0.0.0.0 (for IPv4). the returned address will be 0.0.0.0 (for IPv4).
[horizontal] [horizontal]
Option value type:: character string Option value type:: NULL-terminated character string
Option value unit:: N/A Option value unit:: N/A
Default value:: NULL Default value:: NULL
Applicable socket types:: all, when binding TCP or IPC transports Applicable socket types:: all, when binding TCP or IPC transports
@ -451,8 +451,9 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS) ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option(where supported by OS). Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
The default value of `-1` means to skip any overrides and leave it to OS default. supported by OS). The default value of `-1` means to skip any overrides and
leave it to OS default.
[horizontal] [horizontal]
Option value type:: int Option value type:: int
@ -485,6 +486,57 @@ Default value:: -1 (leave to OS default)
Applicable socket types:: all, when using TCP transports. Applicable socket types:: all, when using TCP transports.
ZMQ_MECHANISM: Retrieve the current security mechanism
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_MECHANISM' option shall retrieve the current security mechanism
for the socket.
[horizontal]
Option value type:: int
Option value unit:: ZMQ_NULL, ZMQ_PLAIN, or ZMQ_CURVE
Default value:: ZMQ_NULL
Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_SERVER: Retrieve the PLAIN server role
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Returns the 'ZMQ_PLAIN_SERVER' option, if any, previously set on the socket.
[horizontal]
Option value type:: int
Option value unit:: 0, 1
Default value:: int
Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_USERNAME: Retrieve the last username set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_PLAIN_USERNAME' option shall retrieve the last username set for
the PLAIN security mechanism. 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:: NULL-terminated character string
Option value unit:: N/A
Default value:: null string
Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_PASSWORD: Retrieve the last password set
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The 'ZMQ_PLAIN_PASSWORD' option shall retrieve the last password set for
the PLAIN security mechanism. 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:: NULL-terminated character string
Option value unit:: N/A
Default value:: null string
Applicable socket types:: all, when using TCP or IPC transports
RETURN VALUE RETURN VALUE
------------ ------------
The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it The _zmq_getsockopt()_ function shall return zero if successful. Otherwise it

27
doc/zmq_null.txt Normal file
View File

@ -0,0 +1,27 @@
zmq_null(7)
===========
NAME
----
zmq_null - no security or confidentiality
SYNOPSIS
--------
The NULL mechanism is defined by the ZMTP 3.0 specification:
<http://rfc.zeromq.org/spec:23>. This is the default security mechanism
for ZeroMQ sockets.
SEE ALSO
--------
linkzmq:zmq_plain[7]
linkzmq:zmq_curve[7]
linkzmq:zmq[7]
AUTHORS
-------
This page was written by the 0MQ community. To make a change please
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.

37
doc/zmq_plain.txt Normal file
View File

@ -0,0 +1,37 @@
zmq_plain(7)
============
NAME
----
zmq_plain - clear-text authentication
SYNOPSIS
--------
The PLAIN mechanism defines a simple username/password mechanism that
lets a server authenticate a client. PLAIN makes no attempt at security
or confidentiality. It is intended for use on internal networks where
security requirements are low. The PLAIN mechanism is defined by this
document: <http://rfc.zeromq.org/spec:24>.
USAGE
-----
To use PLAIN, the server shall set the ZMQ_PLAIN_SERVER option, and the
client shall set the ZMQ_PLAIN_USERNAME and ZMQ_PLAIN_PASSWORD socket
options. Which peer binds, and which connects, is not relevant.
SEE ALSO
--------
linkzmq:zmq_setsockopt[3]
linkzmq:zmq_null[7]
linkzmq:zmq_curve[7]
linkzmq:zmq[7]
AUTHORS
-------
This page was written by the 0MQ community. To make a change please
read the 0MQ Contribution Policy at <http://www.zeromq.org/docs:contributing>.

View File

@ -437,6 +437,7 @@ Applicable socket types:: ZMQ_XPUB
ZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option ZMQ_TCP_KEEPALIVE: Override SO_KEEPALIVE socket option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'SO_KEEPALIVE' socket option(where supported by OS). Override 'SO_KEEPALIVE' socket option(where supported by OS).
The default value of `-1` means to skip any overrides and leave it to OS default. The default value of `-1` means to skip any overrides and leave it to OS default.
@ -449,8 +450,10 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS) ZMQ_TCP_KEEPALIVE_IDLE: Override TCP_KEEPCNT(or TCP_KEEPALIVE on some OS)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option(where supported by OS).
The default value of `-1` means to skip any overrides and leave it to OS default. Override 'TCP_KEEPCNT'(or 'TCP_KEEPALIVE' on some OS) socket option (where
supported by OS). The default value of `-1` means to skip any overrides and
leave it to OS default.
[horizontal] [horizontal]
Option value type:: int Option value type:: int
@ -461,8 +464,9 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option ZMQ_TCP_KEEPALIVE_CNT: Override TCP_KEEPCNT socket option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPCNT' socket option(where supported by OS).
The default value of `-1` means to skip any overrides and leave it to OS default. Override 'TCP_KEEPCNT' socket option(where supported by OS). The default
value of `-1` means to skip any overrides and leave it to OS default.
[horizontal] [horizontal]
Option value type:: int Option value type:: int
@ -473,8 +477,9 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option ZMQ_TCP_KEEPALIVE_INTVL: Override TCP_KEEPINTVL socket option
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Override 'TCP_KEEPINTVL' socket option(where supported by OS).
The default value of `-1` means to skip any overrides and leave it to OS default. Override 'TCP_KEEPINTVL' socket option(where supported by OS). The default
value of `-1` means to skip any overrides and leave it to OS default.
[horizontal] [horizontal]
Option value type:: int Option value type:: int
@ -485,11 +490,12 @@ Applicable socket types:: all, when using TCP transports.
ZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections ZMQ_TCP_ACCEPT_FILTER: Assign filters to allow new TCP connections
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assign arbitrary number of filters that will be applied for each new TCP transport
connection on a listening socket. Assign an arbitrary number of filters that will be applied for each new TCP
If no filters applied, then TCP transport allows connections from any ip. transport connection on a listening socket. If no filters are applied, then
If at least one filter is applied then new connection source ip should be matched. the TCP transport allows connections from any IP address. If at least one
To clear all filters call zmq_setsockopt(socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0). filter is applied then new connection source ip should be matched. To clear
all filters call zmq_setsockopt(socket, ZMQ_TCP_ACCEPT_FILTER, NULL, 0).
Filter is a null-terminated string with ipv6 or ipv4 CIDR. Filter is a null-terminated string with ipv6 or ipv4 CIDR.
[horizontal] [horizontal]
@ -499,6 +505,52 @@ Default value:: no filters (allow from all)
Applicable socket types:: all listening sockets, when using TCP transports. Applicable socket types:: all listening sockets, when using TCP transports.
ZMQ_PLAIN_SERVER: Set PLAIN server role
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Defines whether the socket will act as server for PLAIN security, see
linkzmq:zmq_plain[3]. A value of '1' means the socket will act as
PLAIN server. A value of '0' means the socket will not act as PLAIN
server, and its security role then depends on other option settings.
Setting this to '0' shall reset the socket security to NULL.
[horizontal]
Option value type:: int
Option value unit:: 0, 1
Default value:: 0
Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_USERNAME: Set PLAIN security username
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the username for outgoing connections over TCP or IPC. If you set this
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[3]. If you set this to a null value, the security
mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP or IPC transports
ZMQ_PLAIN_PASSWORD: Set PLAIN security password
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Sets the password for outgoing connections over TCP or IPC. If you set this
to a non-null value, the security mechanism used for connections shall be
PLAIN, see linkzmq:zmq_plain[7]. If you set this to a null value, the security
mechanism used for connections shall be NULL, see linkzmq:zmq_null[3].
[horizontal]
Option value type:: character string
Option value unit:: N/A
Default value:: not set
Applicable socket types:: all, when using TCP or IPC transports
RETURN VALUE RETURN VALUE
------------ ------------
The _zmq_setsockopt()_ function shall return zero if successful. Otherwise it The _zmq_setsockopt()_ function shall return zero if successful. Otherwise it
@ -550,6 +602,8 @@ SEE ALSO
-------- --------
linkzmq:zmq_getsockopt[3] linkzmq:zmq_getsockopt[3]
linkzmq:zmq_socket[3] linkzmq:zmq_socket[3]
linkzmq:zmq_plain[7]
linkzmq:zmq_curve[7]
linkzmq:zmq[7] linkzmq:zmq[7]

View File

@ -253,6 +253,13 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_XPUB_VERBOSE 40 #define ZMQ_XPUB_VERBOSE 40
#define ZMQ_ROUTER_RAW 41 #define ZMQ_ROUTER_RAW 41
#define ZMQ_IPV6 42 #define ZMQ_IPV6 42
#define ZMQ_MECHANISM 43
#define ZMQ_PLAIN_SERVER 44
#define ZMQ_PLAIN_USERNAME 45
#define ZMQ_PLAIN_PASSWORD 46
#define ZMQ_CURVE_SERVER 47
#define ZMQ_CURVE_PUBLICKEY 48
#define ZMQ_CURVE_SERVERKEY 49
/* Message options */ /* Message options */
#define ZMQ_MORE 1 #define ZMQ_MORE 1
@ -261,6 +268,11 @@ ZMQ_EXPORT int zmq_msg_set (zmq_msg_t *msg, int option, int optval);
#define ZMQ_DONTWAIT 1 #define ZMQ_DONTWAIT 1
#define ZMQ_SNDMORE 2 #define ZMQ_SNDMORE 2
/* Security mechanisms */
#define ZMQ_NULL 0
#define ZMQ_PLAIN 1
#define ZMQ_CURVE 2
/* Deprecated aliases */ /* Deprecated aliases */
#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE #define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE
#define ZMQ_NOBLOCK ZMQ_DONTWAIT #define ZMQ_NOBLOCK ZMQ_DONTWAIT

View File

@ -51,6 +51,8 @@ zmq::options_t::options_t () :
tcp_keepalive_cnt (-1), tcp_keepalive_cnt (-1),
tcp_keepalive_idle (-1), tcp_keepalive_idle (-1),
tcp_keepalive_intvl (-1), tcp_keepalive_intvl (-1),
mechanism (ZMQ_NULL),
plain_server (0),
socket_id (0) socket_id (0)
{ {
} }
@ -58,30 +60,29 @@ zmq::options_t::options_t () :
int zmq::options_t::setsockopt (int option_, const void *optval_, int zmq::options_t::setsockopt (int option_, const void *optval_,
size_t optvallen_) size_t optvallen_)
{ {
bool valid = true;
bool is_int = (optvallen_ == sizeof (int)); bool is_int = (optvallen_ == sizeof (int));
int value = is_int? *((int *) optval_): 0; int value = is_int? *((int *) optval_): 0;
switch (option_) { switch (option_) {
case ZMQ_SNDHWM: case ZMQ_SNDHWM:
if (is_int && value >= 0) if (is_int && value >= 0) {
sndhwm = value; sndhwm = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RCVHWM: case ZMQ_RCVHWM:
if (is_int && value >= 0) if (is_int && value >= 0) {
rcvhwm = value; rcvhwm = value;
else return 0;
valid = false; }
break; break;
case ZMQ_AFFINITY: case ZMQ_AFFINITY:
if (optvallen_ == sizeof (uint64_t)) if (optvallen_ == sizeof (uint64_t)) {
affinity = *((uint64_t*) optval_); affinity = *((uint64_t*) optval_);
else return 0;
valid = false; }
break; break;
case ZMQ_IDENTITY: case ZMQ_IDENTITY:
@ -92,405 +93,419 @@ int zmq::options_t::setsockopt (int option_, const void *optval_,
&& *((const unsigned char *) optval_) != 0) { && *((const unsigned char *) optval_) != 0) {
identity_size = optvallen_; identity_size = optvallen_;
memcpy (identity, optval_, identity_size); memcpy (identity, optval_, identity_size);
return 0;
} }
else
valid = false;
break; break;
case ZMQ_RATE: case ZMQ_RATE:
if (is_int && value > 0) if (is_int && value > 0) {
rate = value; rate = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RECOVERY_IVL: case ZMQ_RECOVERY_IVL:
if (is_int && value >= 0) if (is_int && value >= 0) {
recovery_ivl = value; recovery_ivl = value;
else return 0;
valid = false; }
break;
case ZMQ_SNDBUF: case ZMQ_SNDBUF:
if (is_int && value >= 0) if (is_int && value >= 0) {
sndbuf = value; sndbuf = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RCVBUF: case ZMQ_RCVBUF:
if (is_int && value >= 0) if (is_int && value >= 0) {
rcvbuf = value; rcvbuf = value;
else return 0;
valid = false; }
break; break;
case ZMQ_LINGER: case ZMQ_LINGER:
if (is_int && value >= -1) if (is_int && value >= -1) {
linger = value; linger = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RECONNECT_IVL: case ZMQ_RECONNECT_IVL:
if (is_int && value >= -1) if (is_int && value >= -1) {
reconnect_ivl = value; reconnect_ivl = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RECONNECT_IVL_MAX: case ZMQ_RECONNECT_IVL_MAX:
if (is_int && value >= 0) if (is_int && value >= 0) {
reconnect_ivl_max = value; reconnect_ivl_max = value;
else return 0;
valid = false; }
break; break;
case ZMQ_BACKLOG: case ZMQ_BACKLOG:
if (is_int && value >= 0) if (is_int && value >= 0) {
backlog = value; backlog = value;
else return 0;
valid = false; }
break; break;
case ZMQ_MAXMSGSIZE: case ZMQ_MAXMSGSIZE:
if (optvallen_ == sizeof (int64_t)) if (optvallen_ == sizeof (int64_t)) {
maxmsgsize = *((int64_t *) optval_); maxmsgsize = *((int64_t *) optval_);
else return 0;
valid = false; }
break; break;
case ZMQ_MULTICAST_HOPS: case ZMQ_MULTICAST_HOPS:
if (is_int && value > 0) if (is_int && value > 0) {
multicast_hops = value; multicast_hops = value;
else return 0;
valid = false; }
break; break;
case ZMQ_RCVTIMEO: case ZMQ_RCVTIMEO:
if (is_int && value >= -1) if (is_int && value >= -1) {
rcvtimeo = value; rcvtimeo = value;
else return 0;
valid = false; }
break; break;
case ZMQ_SNDTIMEO: case ZMQ_SNDTIMEO:
if (is_int && value >= -1) if (is_int && value >= -1) {
sndtimeo = value; sndtimeo = value;
else return 0;
valid = false; }
break; break;
/* Deprecated in favor of ZMQ_IPV6 */ /* Deprecated in favor of ZMQ_IPV6 */
case ZMQ_IPV4ONLY: case ZMQ_IPV4ONLY:
if (is_int && (value == 0 || value == 1)) if (is_int && (value == 0 || value == 1)) {
ipv6 = (value == 0); ipv6 = (value == 0);
else return 0;
valid = false; }
break; break;
/* To replace the somewhat surprising IPV4ONLY */ /* To replace the somewhat surprising IPV4ONLY */
case ZMQ_IPV6: case ZMQ_IPV6:
if (is_int && (value == 0 || value == 1)) if (is_int && (value == 0 || value == 1)) {
ipv6 = (value != 0); ipv6 = (value != 0);
else return 0;
valid = false; }
break; break;
case ZMQ_TCP_KEEPALIVE: case ZMQ_TCP_KEEPALIVE:
if (is_int && (value >= -1 || value <= 1)) if (is_int && (value >= -1 || value <= 1)) {
tcp_keepalive = value; tcp_keepalive = value;
else return 0;
valid = false; }
break; break;
case ZMQ_TCP_KEEPALIVE_CNT: case ZMQ_TCP_KEEPALIVE_CNT:
if (is_int && (value == -1 || value >= 0)) if (is_int && (value == -1 || value >= 0)) {
tcp_keepalive_cnt = value; tcp_keepalive_cnt = value;
else return 0;
valid = false; }
break; break;
case ZMQ_TCP_KEEPALIVE_IDLE: case ZMQ_TCP_KEEPALIVE_IDLE:
if (is_int && (value == -1 || value >= 0)) if (is_int && (value == -1 || value >= 0)) {
tcp_keepalive_idle = value; tcp_keepalive_idle = value;
else return 0;
valid = false; }
break; break;
case ZMQ_TCP_KEEPALIVE_INTVL: case ZMQ_TCP_KEEPALIVE_INTVL:
if (is_int && (value == -1 || value >= 0)) if (is_int && (value == -1 || value >= 0)) {
tcp_keepalive_intvl = value; tcp_keepalive_intvl = value;
else return 0;
valid = false; }
break; break;
case ZMQ_IMMEDIATE: case ZMQ_IMMEDIATE:
if (is_int && (value == 0 || value == 1)) if (is_int && (value == 0 || value == 1)) {
immediate = value; immediate = value;
else return 0;
valid = false; }
break; break;
case ZMQ_TCP_ACCEPT_FILTER: case ZMQ_TCP_ACCEPT_FILTER:
if (optvallen_ == 0 && optval_ == NULL) if (optvallen_ == 0 && optval_ == NULL) {
tcp_accept_filters.clear (); tcp_accept_filters.clear ();
return 0;
}
else else
if (optvallen_ < 1 || optvallen_ > 255 || optval_ == NULL || *((const char*) optval_) == 0) if (optvallen_ > 0 && optvallen_ < 256 && optval_ != NULL && *((const char*) optval_) != 0) {
valid = false;
else {
std::string filter_str ((const char *) optval_, optvallen_); std::string filter_str ((const char *) optval_, optvallen_);
tcp_address_mask_t mask; tcp_address_mask_t mask;
int rc = mask.resolve (filter_str.c_str (), ipv6); int rc = mask.resolve (filter_str.c_str (), ipv6);
if (rc == 0) if (rc == 0) {
tcp_accept_filters.push_back (mask); tcp_accept_filters.push_back (mask);
else return 0;
valid = false; }
}
break;
case ZMQ_PLAIN_SERVER:
if (is_int && (value == 0 || value == 1)) {
plain_server = value;
mechanism = value? ZMQ_PLAIN: ZMQ_NULL;
return 0;
}
break;
case ZMQ_PLAIN_USERNAME:
if (optvallen_ == 0 && optval_ == NULL) {
mechanism = ZMQ_NULL;
return 0;
}
else
if (optvallen_ >= 0 && optvallen_ < 256 && optval_ != NULL) {
plain_username.assign ((const char *) optval_, optvallen_);
plain_server = false;
mechanism = ZMQ_PLAIN;
return 0;
}
break;
case ZMQ_PLAIN_PASSWORD:
if (optvallen_ == 0 && optval_ == NULL) {
mechanism = ZMQ_NULL;
return 0;
}
else
if (optvallen_ >= 0 && optvallen_ < 256 && optval_ != NULL) {
plain_password.assign ((const char *) optval_, optvallen_);
plain_server = false;
mechanism = ZMQ_PLAIN;
return 0;
} }
break; break;
default: default:
valid = false;
break; break;
} }
if (valid) errno = EINVAL;
return 0; return -1;
else {
errno = EINVAL;
return -1;
}
} }
int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_) int zmq::options_t::getsockopt (int option_, void *optval_, size_t *optvallen_)
{ {
bool is_int = (*optvallen_ == sizeof (int));
int *value = (int *) optval_;
switch (option_) { switch (option_) {
case ZMQ_SNDHWM:
if (is_int) {
*value = sndhwm;
return 0;
}
break;
case ZMQ_SNDHWM: case ZMQ_RCVHWM:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = rcvhwm;
return -1; return 0;
} }
*((int*) optval_) = sndhwm; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RCVHWM: case ZMQ_AFFINITY:
if (*optvallen_ < sizeof (int)) { if (*optvallen_ == sizeof (uint64_t)) {
errno = EINVAL; *((uint64_t *) optval_) = affinity;
return -1; return 0;
} }
*((int*) optval_) = rcvhwm; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_AFFINITY: case ZMQ_IDENTITY:
if (*optvallen_ < sizeof (uint64_t)) { if (*optvallen_ >= identity_size) {
errno = EINVAL; memcpy (optval_, identity, identity_size);
return -1; *optvallen_ = identity_size;
} return 0;
*((uint64_t*) optval_) = affinity; }
*optvallen_ = sizeof (uint64_t); break;
return 0;
case ZMQ_IDENTITY: case ZMQ_RATE:
if (*optvallen_ < identity_size) { if (is_int) {
errno = EINVAL; *value = rate;
return -1; return 0;
} }
memcpy (optval_, identity, identity_size); break;
*optvallen_ = identity_size;
return 0;
case ZMQ_RATE: case ZMQ_RECOVERY_IVL:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = recovery_ivl;
return -1; return 0;
} }
*((int*) optval_) = rate; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RECOVERY_IVL: case ZMQ_SNDBUF:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = sndbuf;
return -1; return 0;
} }
*((int*) optval_) = recovery_ivl; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_SNDBUF: case ZMQ_RCVBUF:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = rcvbuf;
return -1; return 0;
} }
*((int*) optval_) = sndbuf; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RCVBUF: case ZMQ_TYPE:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = type;
return -1; return 0;
} }
*((int*) optval_) = rcvbuf; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_TYPE: case ZMQ_LINGER:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = linger;
return -1; return 0;
} }
*((int*) optval_) = type; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_LINGER: case ZMQ_RECONNECT_IVL:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = reconnect_ivl;
return -1; return 0;
} }
*((int*) optval_) = linger; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RECONNECT_IVL: case ZMQ_RECONNECT_IVL_MAX:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = reconnect_ivl_max;
return -1; return 0;
} }
*((int*) optval_) = reconnect_ivl; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RECONNECT_IVL_MAX: case ZMQ_BACKLOG:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = backlog;
return -1; return 0;
} }
*((int*) optval_) = reconnect_ivl_max; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_BACKLOG: case ZMQ_MAXMSGSIZE:
if (*optvallen_ < sizeof (int)) { if (*optvallen_ == sizeof (int64_t)) {
errno = EINVAL; *((int64_t *) optval_) = maxmsgsize;
return -1; *optvallen_ = sizeof (int64_t);
} return 0;
*((int*) optval_) = backlog; }
*optvallen_ = sizeof (int); break;
return 0;
case ZMQ_MAXMSGSIZE: case ZMQ_MULTICAST_HOPS:
if (*optvallen_ < sizeof (int64_t)) { if (is_int) {
errno = EINVAL; *value = multicast_hops;
return -1; return 0;
} }
*((int64_t*) optval_) = maxmsgsize; break;
*optvallen_ = sizeof (int64_t);
return 0;
case ZMQ_MULTICAST_HOPS: case ZMQ_RCVTIMEO:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = rcvtimeo;
return -1; return 0;
} }
*((int*) optval_) = multicast_hops; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_RCVTIMEO: case ZMQ_SNDTIMEO:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = sndtimeo;
return -1; return 0;
} }
*((int*) optval_) = rcvtimeo; break;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_SNDTIMEO: case ZMQ_IPV4ONLY:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = 1 - ipv6;
return -1; return 0;
} }
*((int*) optval_) = sndtimeo; break;
*optvallen_ = sizeof (int);
return 0; case ZMQ_IPV6:
if (is_int) {
*value = ipv6;
return 0;
}
break;
case ZMQ_IPV4ONLY: case ZMQ_IMMEDIATE:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = immediate;
return -1; return 0;
} }
*((int*) optval_) = 1 - ipv6; break;
*optvallen_ = sizeof (int);
return 0; case ZMQ_TCP_KEEPALIVE:
if (is_int) {
*value = tcp_keepalive;
return 0;
}
break;
case ZMQ_TCP_KEEPALIVE_CNT:
if (is_int) {
*value = tcp_keepalive_cnt;
return 0;
}
break;
case ZMQ_TCP_KEEPALIVE_IDLE:
if (is_int) {
*value = tcp_keepalive_idle;
return 0;
}
break;
case ZMQ_TCP_KEEPALIVE_INTVL:
if (is_int) {
*value = tcp_keepalive_intvl;
return 0;
}
break;
case ZMQ_LAST_ENDPOINT:
if (*optvallen_ >= last_endpoint.size () + 1) {
memcpy (optval_, last_endpoint.c_str (), last_endpoint.size () + 1);
*optvallen_ = last_endpoint.size () + 1;
return 0;
}
break;
case ZMQ_IPV6: case ZMQ_MECHANISM:
if (*optvallen_ < sizeof (int)) { if (is_int) {
errno = EINVAL; *value = mechanism;
return -1; return 0;
} }
*((int*) optval_) = ipv6; break;
*optvallen_ = sizeof (int);
return 0; case ZMQ_PLAIN_SERVER:
if (is_int) {
case ZMQ_IMMEDIATE: *value = plain_server;
if (*optvallen_ < sizeof (int)) { return 0;
errno = EINVAL; }
return -1; break;
}
*((int*) optval_) = immediate; case ZMQ_PLAIN_USERNAME:
*optvallen_ = sizeof (int); if (*optvallen_ >= plain_username.size () + 1) {
return 0; memcpy (optval_, plain_username.c_str (), plain_username.size () + 1);
*optvallen_ = plain_username.size () + 1;
case ZMQ_TCP_KEEPALIVE: return 0;
if (*optvallen_ < sizeof (int)) { }
errno = EINVAL; break;
return -1;
} case ZMQ_PLAIN_PASSWORD:
*((int*) optval_) = tcp_keepalive; if (*optvallen_ >= plain_password.size () + 1) {
*optvallen_ = sizeof (int); memcpy (optval_, plain_password.c_str (), plain_password.size () + 1);
return 0; *optvallen_ = plain_password.size () + 1;
return 0;
case ZMQ_TCP_KEEPALIVE_CNT: }
if (*optvallen_ < sizeof (int)) { break;
errno = EINVAL;
return -1;
}
*((int*) optval_) = tcp_keepalive_cnt;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_TCP_KEEPALIVE_IDLE:
if (*optvallen_ < sizeof (int)) {
errno = EINVAL;
return -1;
}
*((int*) optval_) = tcp_keepalive_idle;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_TCP_KEEPALIVE_INTVL:
if (*optvallen_ < sizeof (int)) {
errno = EINVAL;
return -1;
}
*((int*) optval_) = tcp_keepalive_intvl;
*optvallen_ = sizeof (int);
return 0;
case ZMQ_LAST_ENDPOINT:
/* don't allow string which cannot contain the entire message */
if (*optvallen_ < last_endpoint.size() + 1) {
errno = EINVAL;
return -1;
}
memcpy (optval_, last_endpoint.c_str(), last_endpoint.size()+1);
*optvallen_ = last_endpoint.size()+1;
return 0;
} }
errno = EINVAL; errno = EINVAL;
return -1; return -1;
} }

View File

@ -123,10 +123,17 @@ namespace zmq
typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t; typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t;
tcp_accept_filters_t tcp_accept_filters; tcp_accept_filters_t tcp_accept_filters;
// Security mechanism for all connections on this socket
int mechanism;
// Security credentials for PLAIN mechanism
std::string plain_username;
std::string plain_password;
int plain_server;
// ID of the socket. // ID of the socket.
int socket_id; int socket_id;
}; };
} }
#endif #endif

View File

@ -376,7 +376,9 @@ int zmq_send (void *s_, const void *buf_, size_t len_, int flags_)
return rc; return rc;
} }
// Send multiple messages. // Send multiple messages.
// TODO: this function has no man page
// //
// If flag bit ZMQ_SNDMORE is set the vector is treated as // If flag bit ZMQ_SNDMORE is set the vector is treated as
// a single multi-part message, i.e. the last message has // a single multi-part message, i.e. the last message has
@ -477,7 +479,7 @@ int zmq_recv (void *s_, void *buf_, size_t len_, int flags_)
// //
// The iov_base* buffers of each iovec *a_ filled in by this // The iov_base* buffers of each iovec *a_ filled in by this
// function may be freed using free(). // function may be freed using free().
// // TODO: this function has no man page
// //
int zmq_recviov (void *s_, iovec *a_, size_t *count_, int flags_) int zmq_recviov (void *s_, iovec *a_, size_t *count_, int flags_)
{ {

View File

@ -21,6 +21,7 @@ noinst_PROGRAMS = test_pair_inproc \
test_raw_sock \ test_raw_sock \
test_disconnect_inproc \ test_disconnect_inproc \
test_ctx_options \ test_ctx_options \
test_security \
test_iov test_iov
if !ON_MINGW if !ON_MINGW
@ -49,6 +50,7 @@ test_raw_sock_SOURCES = test_raw_sock.cpp
test_disconnect_inproc_SOURCES = test_disconnect_inproc.cpp test_disconnect_inproc_SOURCES = test_disconnect_inproc.cpp
test_ctx_options_SOURCES = test_ctx_options.cpp test_ctx_options_SOURCES = test_ctx_options.cpp
test_iov_SOURCES = test_iov.cpp test_iov_SOURCES = test_iov.cpp
test_security_SOURCES = test_security.cpp
if !ON_MINGW if !ON_MINGW
test_shutdown_stress_SOURCES = test_shutdown_stress.cpp test_shutdown_stress_SOURCES = test_shutdown_stress.cpp
test_pair_ipc_SOURCES = test_pair_ipc.cpp testutil.hpp test_pair_ipc_SOURCES = test_pair_ipc.cpp testutil.hpp

117
tests/test_security.cpp Normal file
View File

@ -0,0 +1,117 @@
/*
Copyright (c) 2007-2013 Contributors as noted in the AUTHORS file
This file is part of 0MQ.
0MQ is free software; you can redistribute it and/or modify it under
the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
0MQ is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "../include/zmq.h"
#include <string.h>
#include <stdbool.h>
#undef NDEBUG
#include <assert.h>
int main (void)
{
void *ctx = zmq_ctx_new ();
assert (ctx);
// Server socket will accept connections
void *server = zmq_socket (ctx, ZMQ_DEALER);
assert (server);
// Client socket that will try to connect to server
void *client = zmq_socket (ctx, ZMQ_DEALER);
assert (client);
// Check NULL security configuration
int rc;
size_t optsize;
int mechanism;
optsize = sizeof (int);
rc = zmq_getsockopt (client, ZMQ_MECHANISM, &mechanism, &optsize);
assert (rc == 0);
assert (mechanism == ZMQ_NULL);
optsize = sizeof (int);
rc = zmq_getsockopt (server, ZMQ_MECHANISM, &mechanism, &optsize);
assert (rc == 0);
assert (mechanism == ZMQ_NULL);
// Check PLAIN security
char username [256];
optsize = 256;
rc = zmq_getsockopt (client, ZMQ_PLAIN_USERNAME, username, &optsize);
assert (rc == 0);
assert (optsize == 1); // Null string is one byte long
char password [256];
optsize = 256;
rc = zmq_getsockopt (client, ZMQ_PLAIN_PASSWORD, password, &optsize);
assert (rc == 0);
assert (optsize == 1); // Null string is one byte long
strcpy (username, "admin");
strcpy (password, "password");
rc = zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username));
assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password));
assert (rc == 0);
optsize = 256;
rc = zmq_getsockopt (client, ZMQ_PLAIN_USERNAME, username, &optsize);
assert (rc == 0);
assert (optsize == 5 + 1);
optsize = 256;
rc = zmq_getsockopt (client, ZMQ_PLAIN_PASSWORD, password, &optsize);
assert (rc == 0);
assert (optsize == 8 + 1);
optsize = sizeof (int);
rc = zmq_getsockopt (client, ZMQ_MECHANISM, &mechanism, &optsize);
assert (rc == 0);
assert (mechanism == ZMQ_PLAIN);
int as_server = 1;
rc = zmq_setsockopt (server, ZMQ_PLAIN_SERVER, &as_server, sizeof (int));
assert (rc == 0);
optsize = sizeof (int);
rc = zmq_getsockopt (server, ZMQ_MECHANISM, &mechanism, &optsize);
assert (rc == 0);
assert (mechanism == ZMQ_PLAIN);
// Check we can switch back to NULL security
rc = zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, NULL, 0);
assert (rc == 0);
rc = zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, NULL, 0);
assert (rc == 0);
optsize = sizeof (int);
rc = zmq_getsockopt (client, ZMQ_MECHANISM, &mechanism, &optsize);
assert (rc == 0);
assert (mechanism == ZMQ_NULL);
rc = zmq_close (client);
assert (rc == 0);
rc = zmq_close (server);
assert (rc == 0);
rc = zmq_ctx_term (ctx);
assert (rc == 0);
return 0;
}