source: web/old/remctl-2.14/tests/client/open-t.c @ f6f3e91

web
Last change on this file since f6f3e91 was f6f3e91, checked in by Jessica B. Hamrick <jhamrick@…>, 15 years ago

Preserve directory hierarchy (not sure what happened to it)

  • Property mode set to 100644
File size: 6.0 KB
Line 
1/*
2 * Test suite for the client connection negotiation code.
3 *
4 * Written by Russ Allbery <rra@stanford.edu>
5 * Copyright 2006, 2007, 2009
6 *     Board of Trustees, Leland Stanford Jr. University
7 *
8 * See LICENSE for licensing terms.
9 */
10
11#include <config.h>
12#include <portable/system.h>
13#include <portable/gssapi.h>
14#include <portable/socket.h>
15
16#include <fcntl.h>
17#ifdef HAVE_SYS_SELECT_H
18# include <sys/select.h>
19#endif
20#include <sys/time.h>
21#include <sys/wait.h>
22
23#include <client/internal.h>
24#include <client/remctl.h>
25#include <tests/tap/basic.h>
26#include <tests/tap/kerberos.h>
27#include <tests/tap/remctl.h>
28#include <util/util.h>
29
30
31/*
32 * Create a socket, accept a single connection, try to establish a context,
33 * and then close the connection and exit.  We run this in a subprocess to
34 * provide the foil against which to test our connection negotiation.  Takes a
35 * flag saying what protocol version to use.  1 indicates protocol version 1
36 * the whole way, 2 indicates version 2 from the start, and 0 starts with
37 * version 1 and then goes back to version 2.
38 */
39static void
40accept_connection(int protocol)
41{
42    struct sockaddr_in saddr;
43    int s, conn, fd;
44    int on = 1;
45    int flags, wanted_flags;
46    gss_buffer_desc send_tok, recv_tok;
47    OM_uint32 major, minor, ret_flags;
48    gss_ctx_id_t context;
49    gss_name_t client;
50    gss_OID doid;
51
52    /* Create the socket and accept the connection. */
53    saddr.sin_family = AF_INET;
54    saddr.sin_port = htons(14373);
55    saddr.sin_addr.s_addr = INADDR_ANY;
56    s = socket(AF_INET, SOCK_STREAM, 0);
57    if (s < 0)
58        sysdie("error creating socket");
59    setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on));
60    if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0)
61        sysdie("error binding socket");
62    if (listen(s, 1) < 0)
63        sysdie("error listening to socket");
64    fd = open("data/pid", O_CREAT | O_TRUNC, 0666);
65    if (fd < 0)
66        sysdie("cannot create sentinal");
67    close(fd);
68    conn = accept(s, NULL, 0);
69    if (conn < 0)
70        sysdie("error accepting connection");
71
72    /* Now do the context negotiation. */
73    if (token_recv(conn, &flags, &recv_tok, 64 * 1024) != TOKEN_OK)
74        die("cannot recv initial token");
75    if (flags != (TOKEN_NOOP | TOKEN_CONTEXT_NEXT | TOKEN_PROTOCOL))
76        die("bad flags on initial token");
77    wanted_flags = TOKEN_CONTEXT | TOKEN_PROTOCOL;
78    context = GSS_C_NO_CONTEXT;
79    do {
80        if (token_recv(conn, &flags, &recv_tok, 64 * 1024) != TOKEN_OK)
81            die("cannot recv subsequent token");
82        if (flags != wanted_flags)
83            die("bad flags on subsequent token");
84        major = gss_accept_sec_context(&minor, &context, GSS_C_NO_CREDENTIAL,
85                       &recv_tok, GSS_C_NO_CHANNEL_BINDINGS, &client, &doid,
86                       &send_tok, &ret_flags, NULL, NULL);
87        if (major != GSS_S_COMPLETE && major != GSS_S_CONTINUE_NEEDED)
88            die("GSS-API failure: %ld %ld\n", (long) major, (long) minor);
89        gss_release_buffer(&minor, &recv_tok);
90        if (send_tok.length != 0) {
91            flags = TOKEN_CONTEXT;
92            if (protocol == 2)
93                flags |= TOKEN_PROTOCOL;
94            else if (protocol == 0)
95                protocol = 2;
96            if (token_send(conn, flags, &send_tok) != TOKEN_OK)
97                die("cannot send subsequent token");
98            gss_release_buffer(&minor, &send_tok);
99        }
100    } while (major == GSS_S_CONTINUE_NEEDED);
101
102    /* All done.  Don't bother cleaning up, just exit. */
103    exit(0);
104}
105
106
107int
108main(void)
109{
110    char *principal, *p;
111    const char *error;
112    struct remctl *r;
113    int protocol;
114    pid_t child;
115    struct timeval tv;
116
117    plan(5 * 3 + 3);
118    if (chdir(getenv("BUILD")) < 0)
119        sysbail("can't chdir to BUILD");
120
121    /*
122     * Now, check that the right thing happens when we try to connect to a
123     * port where nothing is listening.  Modifying the returned error is not
124     * actually allowed, but we know enough about the internals to know that
125     * we can get away with it.
126     */
127    r = remctl_new();
128    ok(!remctl_open(r, "127.0.0.1", 14445, NULL),
129       "correct connection failure");
130    error = remctl_error(r);
131    ok(error != NULL, "...with error");
132    if (error != NULL && strchr(error, ':') != NULL) {
133        p = strchr(error, ':');
134        *p = '\0';
135        is_string("cannot connect to 127.0.0.1 (port 14445)", error,
136                  "...and the correct error");
137    } else {
138        ok(0, "...and the correct error");
139    }
140    remctl_close(r);
141
142    /* Unless we have Kerberos available, we can't really do anything else. */
143    principal = kerberos_setup();
144    if (principal == NULL) {
145        skip_block(5 * 3, "Kerberos tests not configured");
146        return 0;
147    }
148
149    /*
150     * We're going to try this three times, for each of the three possible
151     * different protocol negotiation behaviors that accept_connection can
152     * test.  Each time, we're going to check that we got a context and that
153     * we negotiated the appropriate protocol.
154     */
155    for (protocol = 0; protocol <= 2; protocol++) {
156        r = remctl_new();
157        child = fork();
158        if (child < 0)
159            sysbail("cannot fork");
160        else if (child == 0)
161            accept_connection(protocol);
162        alarm(1);
163        while (access("data/pid", F_OK) < 0) {
164            tv.tv_sec = 0;
165            tv.tv_usec = 50000;
166            select(0, NULL, NULL, NULL, &tv);
167        }
168        alarm(0);
169        if (!remctl_open(r, "127.0.0.1", 14373, principal)) {
170            notice("# open error: %s", remctl_error(r));
171            ok_block(5, 0, "protocol %d", protocol);
172        } else {
173            ok(1, "remctl_open with protocol %d", protocol);
174            is_int((protocol < 2) ? 1 : 2, r->protocol,
175                   "negotiated correct protocol");
176            is_string(r->host, "127.0.0.1", "host is correct");
177            is_int(r->port, 14373, "port is correct");
178            is_string(r->principal, principal, "principal is correct");
179        }
180        remctl_close(r);
181        waitpid(child, NULL, 0);
182        unlink("data/pid");
183    }
184
185    return 0;
186}
Note: See TracBrowser for help on using the repository browser.