0
0
mirror of https://github.com/zeromq/libzmq.git synced 2024-12-26 23:01:04 +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_ctx_options
tests/test_iov
tests/test_security
src/platform.hpp*
src/stamp-h1
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_socket.3 zmq_socket_monitor.3 zmq_poll.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)

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].
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
--------------
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).
[horizontal]
Option value type:: character string
Option value type:: NULL-terminated character string
Option value unit:: N/A
Default value:: NULL
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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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]
Option value type:: int
@ -485,6 +486,57 @@ Default value:: -1 (leave to OS default)
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
------------
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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.
@ -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)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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]
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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]
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
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]
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
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Assign arbitrary number of filters that will be applied for each new TCP transport
connection on a listening socket.
If no filters applied, then TCP transport allows connections from any ip.
If at least one 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).
Assign an arbitrary number of filters that will be applied for each new TCP
transport connection on a listening socket. If no filters are applied, then
the TCP transport allows connections from any IP address. If at least one
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.
[horizontal]
@ -499,6 +505,52 @@ Default value:: no filters (allow from all)
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
------------
The _zmq_setsockopt()_ function shall return zero if successful. Otherwise it
@ -550,6 +602,8 @@ SEE ALSO
--------
linkzmq:zmq_getsockopt[3]
linkzmq:zmq_socket[3]
linkzmq:zmq_plain[7]
linkzmq:zmq_curve[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_ROUTER_RAW 41
#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 */
#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_SNDMORE 2
/* Security mechanisms */
#define ZMQ_NULL 0
#define ZMQ_PLAIN 1
#define ZMQ_CURVE 2
/* Deprecated aliases */
#define ZMQ_DELAY_ATTACH_ON_CONNECT ZMQ_IMMEDIATE
#define ZMQ_NOBLOCK ZMQ_DONTWAIT

View File

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

View File

@ -123,10 +123,17 @@ namespace zmq
typedef std::vector <tcp_address_mask_t> tcp_accept_filters_t;
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.
int socket_id;
};
}
#endif

View File

@ -376,7 +376,9 @@ int zmq_send (void *s_, const void *buf_, size_t len_, int flags_)
return rc;
}
// Send multiple messages.
// TODO: this function has no man page
//
// If flag bit ZMQ_SNDMORE is set the vector is treated as
// 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
// 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_)
{

View File

@ -21,6 +21,7 @@ noinst_PROGRAMS = test_pair_inproc \
test_raw_sock \
test_disconnect_inproc \
test_ctx_options \
test_security \
test_iov
if !ON_MINGW
@ -49,6 +50,7 @@ test_raw_sock_SOURCES = test_raw_sock.cpp
test_disconnect_inproc_SOURCES = test_disconnect_inproc.cpp
test_ctx_options_SOURCES = test_ctx_options.cpp
test_iov_SOURCES = test_iov.cpp
test_security_SOURCES = test_security.cpp
if !ON_MINGW
test_shutdown_stress_SOURCES = test_shutdown_stress.cpp
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;
}