test_security_gssapi.cpp 12.1 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30
/*
    Copyright (c) 2007-2017 Contributors as noted in the AUTHORS file

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

    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
    (at your option) any later version.

    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.

    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 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
#endif

//  This test requires a KRB5 environment with the following
//  service principal (substitute your host.domain and REALM):
//
//    zmqtest2/host.domain@REALM   (host.domain should be host running test)
//
//  Export keys for this principal to a keytab file and set the environment
//  variables KRB5_KTNAME and KRB5_CLIENT_KTNAME to FILE:/path/to/your/keytab.
//  The test will use it both for client and server roles.
//
//  The test is derived in large part from test_security_curve.cpp

const char *name = "zmqtest2";

static volatile int zap_deny_all = 0;

//  Read one event off the monitor socket; return value and address
//  by reference, if not null, and event number by value. Returns -1
//  in case of error.
61
static int get_monitor_event (void *monitor_, int *value_, char **address_)
62 63 64 65
{
    //  First frame in message contains event number and value
    zmq_msg_t msg;
    zmq_msg_init (&msg);
66
    if (zmq_msg_recv (&msg, monitor_, 0) == -1)
67
        return -1; //  Interruped, presumably
68 69 70 71
    assert (zmq_msg_more (&msg));

    uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
    uint16_t event = *(uint16_t *) (data);
72 73
    if (value_)
        *value_ = *(uint32_t *) (data + 2);
74
    zmq_msg_close (&msg);
75 76 77

    //  Second frame in message contains event address
    zmq_msg_init (&msg);
78
    if (zmq_msg_recv (&msg, monitor_, 0) == -1)
79
        return -1; //  Interruped, presumably
80 81
    assert (!zmq_msg_more (&msg));

82
    if (address_) {
83 84
        uint8_t *data = (uint8_t *) zmq_msg_data (&msg);
        size_t size = zmq_msg_size (&msg);
85 86 87
        *address_ = (char *) malloc (size + 1);
        memcpy (*address_, data, size);
        *address_[size] = 0;
88
    }
89 90
    zmq_msg_close (&msg);

91 92 93 94 95 96 97 98
    return event;
}

//  --------------------------------------------------------------------------
//  This methods receives and validates ZAP requestes (allowing or denying
//  each client connection).
//  N.B. on failure, each crypto type in keytab will be tried

99
static void zap_handler (void *handler_)
100 101 102
{
    //  Process ZAP requests forever
    while (true) {
103
        char *version = s_recv (handler_);
104
        if (!version)
105
            break; //  Terminating
106

107 108 109 110 111 112
        char *sequence = s_recv (handler_);
        char *domain = s_recv (handler_);
        char *address = s_recv (handler_);
        char *routing_id = s_recv (handler_);
        char *mechanism = s_recv (handler_);
        char *principal = s_recv (handler_);
113 114 115 116

        assert (streq (version, "1.0"));
        assert (streq (mechanism, "GSSAPI"));

117 118
        s_sendmore (handler_, version);
        s_sendmore (handler_, sequence);
119 120

        if (!zap_deny_all) {
121 122 123 124
            s_sendmore (handler_, "200");
            s_sendmore (handler_, "OK");
            s_sendmore (handler_, "anonymous");
            s_send (handler_, "");
125 126
            //fprintf (stderr, "ALLOW %s\n", principal);
        } else {
127 128 129 130
            s_sendmore (handler_, "400");
            s_sendmore (handler_, "Denied");
            s_sendmore (handler_, "");
            s_send (handler_, "");
131
            //fprintf (stderr, "DENY %s\n", principal);
132 133 134 135 136
        }
        free (version);
        free (sequence);
        free (domain);
        free (address);
137
        free (routing_id);
138 139 140
        free (mechanism);
        free (principal);
    }
141
    zmq_close (handler_);
142 143
}

144 145 146 147
void test_valid_creds (void *ctx_,
                       void *server_,
                       void *server_mon_,
                       char *endpoint_)
148
{
149
    void *client = zmq_socket (ctx_, ZMQ_DEALER);
150
    assert (client);
151 152
    int rc = zmq_setsockopt (client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name,
                             strlen (name) + 1);
153
    assert (rc == 0);
154
    rc = zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1);
155 156
    assert (rc == 0);
    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
157 158
    rc = zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type,
                         sizeof (name_type));
159
    assert (rc == 0);
160
    rc = zmq_connect (client, endpoint_);
161 162
    assert (rc == 0);

163
    bounce (server_, client);
164 165 166
    rc = zmq_close (client);
    assert (rc == 0);

167
    int event = get_monitor_event (server_mon_, NULL, NULL);
168
    assert (event == ZMQ_EVENT_HANDSHAKE_SUCCEEDED);
169 170 171 172 173
}

//  Check security with valid but unauthorized credentials
//  Note: ZAP may see multiple requests - after a failure, client will
//  fall back to other crypto types for principal, if available.
174 175 176 177
void test_unauth_creds (void *ctx_,
                        void *server_,
                        void *server_mon_,
                        char *endpoint_)
178
{
179
    void *client = zmq_socket (ctx_, ZMQ_DEALER);
180
    assert (client);
181 182
    int rc = zmq_setsockopt (client, ZMQ_GSSAPI_SERVICE_PRINCIPAL, name,
                             strlen (name) + 1);
183
    assert (rc == 0);
184
    rc = zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1);
185 186
    assert (rc == 0);
    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
187 188
    rc = zmq_setsockopt (client, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type,
                         sizeof (name_type));
189 190
    assert (rc == 0);
    zap_deny_all = 1;
191
    rc = zmq_connect (client, endpoint_);
192 193
    assert (rc == 0);

194
    expect_bounce_fail (server_, client);
195 196
    close_zero_linger (client);

197
    int event = get_monitor_event (server_mon_, NULL, NULL);
198
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED_AUTH);
199 200 201 202
}

//  Check GSSAPI security with NULL client credentials
//  This must be caught by the gssapi_server class, not passed to ZAP
203 204 205 206
void test_null_creds (void *ctx_,
                      void *server_,
                      void *server_mon_,
                      char *endpoint_)
207
{
208
    void *client = zmq_socket (ctx_, ZMQ_DEALER);
209
    assert (client);
210
    int rc = zmq_connect (client, endpoint_);
211
    assert (rc == 0);
212
    expect_bounce_fail (server_, client);
213 214
    close_zero_linger (client);

215
    int error;
216
    int event = get_monitor_event (server_mon_, &error, NULL);
217 218
    assert (event == ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL);
    assert (error == ZMQ_PROTOCOL_ERROR_ZMTP_MECHANISM_MISMATCH);
219 220 221 222
}

//  Check GSSAPI security with PLAIN client credentials
//  This must be caught by the curve_server class, not passed to ZAP
223 224 225 226
void test_plain_creds (void *ctx_,
                       void *server_,
                       void *server_mon_,
                       char *endpoint_)
227
{
228
    void *client = zmq_socket (ctx_, ZMQ_DEALER);
229 230 231 232 233
    assert (client);
    int rc = zmq_setsockopt (client, ZMQ_PLAIN_USERNAME, "admin", 5);
    assert (rc == 0);
    rc = zmq_setsockopt (client, ZMQ_PLAIN_PASSWORD, "password", 8);
    assert (rc == 0);
234
    rc = zmq_connect (client, endpoint_);
235
    assert (rc == 0);
236
    expect_bounce_fail (server_, client);
237 238 239 240
    close_zero_linger (client);
}

// Unauthenticated messages from a vanilla socket shouldn't be received
241 242 243 244
void test_vanilla_socket (void *ctx_,
                          void *server_,
                          void *server_mon_,
                          char *endpoint_)
245 246 247
{
    struct sockaddr_in ip4addr;
    int s;
248
    unsigned short int port;
249
    int rc = sscanf (endpoint_, "tcp://127.0.0.1:%hu", &port);
250
    assert (rc == 1);
251
    ip4addr.sin_family = AF_INET;
252
    ip4addr.sin_port = htons (port);
253
#if defined(ZMQ_HAVE_WINDOWS) && (_WIN32_WINNT < 0x0600)
254 255
    ip4addr.sin_addr.s_addr = inet_addr ("127.0.0.1");
#else
256
    inet_pton (AF_INET, "127.0.0.1", &ip4addr.sin_addr);
257 258 259
#endif

    s = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP);
260
    rc = connect (s, (struct sockaddr *) &ip4addr, sizeof (ip4addr));
261 262 263 264 265 266
    assert (rc > -1);
    // 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);
    int timeout = 250;
267 268
    zmq_setsockopt (server_, ZMQ_RCVTIMEO, &timeout, sizeof (timeout));
    char *buf = s_recv (server_);
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288
    if (buf != NULL) {
        printf ("Received unauthenticated message: %s\n", buf);
        assert (buf == NULL);
    }
    close (s);
}

int main (void)
{
    if (!getenv ("KRB5_KTNAME") || !getenv ("KRB5_CLIENT_KTNAME")) {
        printf ("KRB5 environment unavailable, skipping test\n");
        return 77; // SKIP
    }
    // Avoid entanglements with user's credential cache
    setenv ("KRB5CCNAME", "MEMORY", 1);

    setup_test_environment ();
    void *ctx = zmq_ctx_new ();
    assert (ctx);

289 290 291
    size_t len = MAX_SOCKET_STRING;
    char my_endpoint[MAX_SOCKET_STRING];

292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
    //  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");
    assert (rc == 0);
    void *zap_thread = zmq_threadstart (&zap_handler, handler);

    //  Server socket will accept connections
    void *server = zmq_socket (ctx, ZMQ_DEALER);
    assert (server);
    int as_server = 1;
    rc = zmq_setsockopt (server, ZMQ_GSSAPI_SERVER, &as_server, sizeof (int));
    assert (rc == 0);
307
    rc = zmq_setsockopt (server, ZMQ_GSSAPI_PRINCIPAL, name, strlen (name) + 1);
308 309
    assert (rc == 0);
    int name_type = ZMQ_GSSAPI_NT_HOSTBASED;
310 311
    rc = zmq_setsockopt (server, ZMQ_GSSAPI_PRINCIPAL_NAMETYPE, &name_type,
                         sizeof (name_type));
312
    assert (rc == 0);
313 314 315
    rc = zmq_bind (server, "tcp://127.0.0.1:*");
    assert (rc == 0);
    rc = zmq_getsockopt (server, ZMQ_LAST_ENDPOINT, my_endpoint, &len);
316 317 318 319
    assert (rc == 0);

    //  Monitor handshake events on the server
    rc = zmq_socket_monitor (server, "inproc://monitor-server",
320 321 322
                             ZMQ_EVENT_HANDSHAKE_SUCCEEDED
                               | ZMQ_EVENT_HANDSHAKE_FAILED_AUTH
                               | ZMQ_EVENT_HANDSHAKE_FAILED_PROTOCOL);
323 324 325
    assert (rc == 0);

    //  Create socket for collecting monitor events
326 327
    void *server_mon = NULL;
    server_mon = zmq_socket (ctx, ZMQ_PAIR);
328 329 330 331 332 333 334
    assert (server_mon);

    //  Connect it to the inproc endpoints so they'll get events
    rc = zmq_connect (server_mon, "inproc://monitor-server");
    assert (rc == 0);

    //  Attempt various connections
335 336 337 338 339
    test_valid_creds (ctx, server, server_mon, my_endpoint);
    test_null_creds (ctx, server, server_mon, my_endpoint);
    test_plain_creds (ctx, server, server_mon, my_endpoint);
    test_vanilla_socket (ctx, server, server_mon, my_endpoint);
    test_unauth_creds (ctx, server, server_mon, my_endpoint);
340 341 342 343 344 345 346 347 348 349 350 351 352

    //  Shutdown
    close_zero_linger (server_mon);
    rc = zmq_close (server);
    assert (rc == 0);
    rc = zmq_ctx_term (ctx);
    assert (rc == 0);

    //  Wait until ZAP handler terminates
    zmq_threadclose (zap_thread);

    return 0;
}