test_security_plain.cpp 6.9 KB
Newer Older
1
/*
2
    Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file
3

4
    This file is part of libzmq, the ZeroMQ core engine in C++.
5

6 7 8
    libzmq is free software; you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License (LGPL) as published
    by the Free Software Foundation; either version 3 of the License, or
9 10
    (at your option) any later version.

11 12 13 14 15 16 17 18 19 20 21 22 23 24
    As a special exception, the Contributors give you permission to link
    this library with independent modules to produce an executable,
    regardless of the license terms of these independent modules, and to
    copy and distribute the resulting executable under terms of your choice,
    provided that you also meet, for each linked independent module, the
    terms and conditions of the license of that module. An independent
    module is a module which is not derived from or based on this library.
    If you modify this library, you must extend this exception to your
    version of the library.

    libzmq 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.
25 26 27 28 29 30

    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 "testutil.hpp"
31 32 33 34 35
#if defined(ZMQ_HAVE_WINDOWS)
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdexcept>
#define close closesocket
36
#else
37 38 39 40
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>
41
#endif
42

43
static void zap_handler (void *ctx)
44 45 46 47 48 49 50 51 52 53 54
{
    //  Create and bind ZAP socket
    void *zap = zmq_socket (ctx, ZMQ_REP);
    assert (zap);
    int rc = zmq_bind (zap, "inproc://zeromq.zap.01");
    assert (rc == 0);

    //  Process ZAP requests forever
    while (true) {
        char *version = s_recv (zap);
        if (!version)
55
            break; //  Terminating
56 57 58
        char *sequence = s_recv (zap);
        char *domain = s_recv (zap);
        char *address = s_recv (zap);
59
        char *routing_id = s_recv (zap);
60 61 62
        char *mechanism = s_recv (zap);
        char *username = s_recv (zap);
        char *password = s_recv (zap);
63

64 65
        assert (streq (version, "1.0"));
        assert (streq (mechanism, "PLAIN"));
66
        assert (streq (routing_id, "IDENT"));
67 68 69

        s_sendmore (zap, version);
        s_sendmore (zap, sequence);
70
        if (streq (username, "admin") && streq (password, "password")) {
71 72 73 74
            s_sendmore (zap, "200");
            s_sendmore (zap, "OK");
            s_sendmore (zap, "anonymous");
            s_send (zap, "");
75
        } else {
76 77 78 79 80 81 82 83 84
            s_sendmore (zap, "400");
            s_sendmore (zap, "Invalid username or password");
            s_sendmore (zap, "");
            s_send (zap, "");
        }
        free (version);
        free (sequence);
        free (domain);
        free (address);
85
        free (routing_id);
86 87 88 89 90 91 92 93 94 95
        free (mechanism);
        free (username);
        free (password);
    }
    rc = zmq_close (zap);
    assert (rc == 0);
}

int main (void)
{
96
    setup_test_environment ();
97 98
    size_t len = MAX_SOCKET_STRING;
    char my_endpoint[MAX_SOCKET_STRING];
99 100
    void *ctx = zmq_ctx_new ();
    assert (ctx);
101

102 103 104 105 106 107
    //  Spawn ZAP handler
    void *zap_thread = zmq_threadstart (&zap_handler, ctx);

    //  Server socket will accept connections
    void *server = zmq_socket (ctx, ZMQ_DEALER);
    assert (server);
108
    int rc = zmq_setsockopt (server, ZMQ_ROUTING_ID, "IDENT", 6);
109 110 111
    const char domain[] = "test";
    assert (rc == 0);
    rc = zmq_setsockopt (server, ZMQ_ZAP_DOMAIN, domain, strlen (domain));
112
    assert (rc == 0);
113 114
    int as_server = 1;
    rc = zmq_setsockopt (server, ZMQ_PLAIN_SERVER, &as_server, sizeof (int));
115
    assert (rc == 0);
116 117 118
    rc = zmq_bind (server, "tcp://127.0.0.1:*");
    assert (rc == 0);
    rc = zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, my_endpoint, &len);
119
    assert (rc == 0);
120

121 122
    char username[256];
    char password[256];
123

124 125 126 127
    //  Check PLAIN security with correct username/password
    void *client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    strcpy (username, "admin");
128 129
    rc =
      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username));
130 131
    assert (rc == 0);
    strcpy (password, "password");
132 133
    rc =
      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password));
134
    assert (rc == 0);
135
    rc = zmq_connect (client, my_endpoint);
136 137 138 139 140
    assert (rc == 0);
    bounce (server, client);
    rc = zmq_close (client);
    assert (rc == 0);

141 142 143 144 145
    //  Check PLAIN security with badly configured client (as_server)
    //  This will be caught by the plain_server class, not passed to ZAP
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    as_server = 1;
146
    rc = zmq_setsockopt (client, ZMQ_ZAP_DOMAIN, domain, strlen (domain));
147
    assert (rc == 0);
148
    rc = zmq_setsockopt (client, ZMQ_PLAIN_SERVER, &as_server, sizeof (int));
149
    assert (rc == 0);
150
    rc = zmq_connect (client, my_endpoint);
151 152 153
    assert (rc == 0);
    expect_bounce_fail (server, client);
    close_zero_linger (client);
154

155 156 157 158 159
    //  Check PLAIN security -- failed authentication
    client = zmq_socket (ctx, ZMQ_DEALER);
    assert (client);
    strcpy (username, "wronguser");
    strcpy (password, "wrongpass");
160 161
    rc =
      zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, username, strlen (username));
162
    assert (rc == 0);
163 164
    rc =
      zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, password, strlen (password));
165
    assert (rc == 0);
166
    rc = zmq_connect (client, my_endpoint);
167
    assert (rc == 0);
168
    expect_bounce_fail (server, client);
169 170
    close_zero_linger (client);

171 172 173 174
    // Unauthenticated messages from a vanilla socket shouldn't be received
    struct sockaddr_in ip4addr;
    int s;

175
    unsigned short int port;
176
    rc = sscanf (my_endpoint, "tcp://127.0.0.1:%hu", &port);
177 178
    assert (rc == 1);

179
    ip4addr.sin_family = AF_INET;
180
    ip4addr.sin_port = htons (port);
181
#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
182 183
    ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
#else
184
    inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr);
185
#endif
186 187

    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
188
    rc = connect (s, (struct sockaddr *) &ip4addr, sizeof (ip4addr));
189
    assert (rc > -1);
190 191 192 193
    // send anonymous ZMTP/1.0 greeting
    send (s, "\x01\x00", 2, 0);
    // send sneaky message that shouldn't be received
    send (s, "\x08\x00sneaky\0", 9, 0);
194
    int timeout = 250;
195 196
    zmq_setsockopt (server, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
    char *buf = s_recv (server);
197 198 199 200
    if (buf != NULL) {
        printf ("Received unauthenticated message: %s\n", buf);
        assert (buf == NULL);
    }
201 202
    close (s);

203 204 205 206 207
    //  Shutdown
    rc = zmq_close (server);
    assert (rc == 0);
    rc = zmq_ctx_term (ctx);
    assert (rc == 0);
208

209 210 211 212 213
    //  Wait until ZAP handler terminates
    zmq_threadclose (zap_thread);

    return 0;
}