1 | /* |
---|
2 | * Test suite for the server 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 <sys/wait.h> |
---|
17 | |
---|
18 | #include <server/internal.h> |
---|
19 | #include <tests/tap/basic.h> |
---|
20 | #include <tests/tap/kerberos.h> |
---|
21 | #include <util/util.h> |
---|
22 | |
---|
23 | |
---|
24 | /* |
---|
25 | * Open a new connection to a server, taking the protocol version and |
---|
26 | * principal to use. 1 indicates protocol version 1 the whole way, 2 |
---|
27 | * indicates version 2 from the start, and 0 starts with version 2, goes back |
---|
28 | * to version 1, and then goes to version 2. |
---|
29 | */ |
---|
30 | static void |
---|
31 | make_connection(int protocol, const char *principal) |
---|
32 | { |
---|
33 | struct sockaddr_in saddr; |
---|
34 | int fd, flags; |
---|
35 | gss_buffer_desc send_tok, recv_tok, name_buffer, *token_ptr; |
---|
36 | gss_buffer_desc empty_token = { 0, (void *) "" }; |
---|
37 | gss_name_t name; |
---|
38 | gss_ctx_id_t gss_context; |
---|
39 | OM_uint32 major, minor, init_minor, gss_flags; |
---|
40 | static const OM_uint32 req_gss_flags |
---|
41 | = (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG | GSS_C_CONF_FLAG |
---|
42 | | GSS_C_INTEG_FLAG); |
---|
43 | |
---|
44 | /* Connect. */ |
---|
45 | saddr.sin_family = AF_INET; |
---|
46 | saddr.sin_port = htons(14373); |
---|
47 | saddr.sin_addr.s_addr = INADDR_ANY; |
---|
48 | fd = socket(AF_INET, SOCK_STREAM, 0); |
---|
49 | if (fd < 0) |
---|
50 | sysdie("error creating socket"); |
---|
51 | if (connect(fd, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) |
---|
52 | sysdie("error connecting"); |
---|
53 | |
---|
54 | /* Import the name into target_name. */ |
---|
55 | name_buffer.value = (char *) principal; |
---|
56 | name_buffer.length = strlen(principal) + 1; |
---|
57 | major = gss_import_name(&minor, &name_buffer, GSS_C_NT_USER_NAME, &name); |
---|
58 | if (major != GSS_S_COMPLETE) |
---|
59 | die("cannot import name"); |
---|
60 | |
---|
61 | /* Send the initial negotiation token. */ |
---|
62 | flags = TOKEN_NOOP | TOKEN_CONTEXT_NEXT; |
---|
63 | if (protocol == 0 || protocol > 1) |
---|
64 | flags |= TOKEN_PROTOCOL; |
---|
65 | if (token_send(fd, flags, &empty_token) != TOKEN_OK) |
---|
66 | sysdie("failure sending token"); |
---|
67 | |
---|
68 | /* Perform the context-establishment loop. */ |
---|
69 | token_ptr = GSS_C_NO_BUFFER; |
---|
70 | gss_context = GSS_C_NO_CONTEXT; |
---|
71 | do { |
---|
72 | major = gss_init_sec_context(&init_minor, GSS_C_NO_CREDENTIAL, |
---|
73 | &gss_context, name, (const gss_OID) GSS_KRB5_MECHANISM, |
---|
74 | req_gss_flags, 0, NULL, token_ptr, NULL, &send_tok, |
---|
75 | &gss_flags, NULL); |
---|
76 | if (token_ptr != GSS_C_NO_BUFFER) |
---|
77 | gss_release_buffer(&minor, &recv_tok); |
---|
78 | if (send_tok.length != 0) { |
---|
79 | flags = TOKEN_CONTEXT; |
---|
80 | if (protocol > 1) |
---|
81 | flags |= TOKEN_PROTOCOL; |
---|
82 | if (protocol == 0) |
---|
83 | protocol = 2; |
---|
84 | if (token_send(fd, flags, &send_tok) != TOKEN_OK) |
---|
85 | sysdie("failure sending token"); |
---|
86 | } |
---|
87 | gss_release_buffer(&minor, &send_tok); |
---|
88 | if (major != GSS_S_COMPLETE && major != GSS_S_CONTINUE_NEEDED) |
---|
89 | die("failure initializing context"); |
---|
90 | if (major == GSS_S_CONTINUE_NEEDED) { |
---|
91 | if (token_recv(fd, &flags, &recv_tok, 64 * 1024) != TOKEN_OK) |
---|
92 | sysdie("failure receiving token"); |
---|
93 | token_ptr = &recv_tok; |
---|
94 | } |
---|
95 | } while (major == GSS_S_CONTINUE_NEEDED); |
---|
96 | |
---|
97 | /* All done. Don't bother cleaning up, just exit. */ |
---|
98 | exit(0); |
---|
99 | } |
---|
100 | |
---|
101 | |
---|
102 | int |
---|
103 | main(void) |
---|
104 | { |
---|
105 | char *principal; |
---|
106 | int s, fd, protocol; |
---|
107 | pid_t child; |
---|
108 | struct sockaddr_in saddr; |
---|
109 | struct client *client; |
---|
110 | int on = 1; |
---|
111 | |
---|
112 | /* Unless we have Kerberos available, we can't really do anything. */ |
---|
113 | principal = kerberos_setup(); |
---|
114 | if (principal == NULL) |
---|
115 | skip_all("Kerberos tests not configured"); |
---|
116 | plan(2 * 3); |
---|
117 | |
---|
118 | /* Set up address to which we're going to bind and start listening.. */ |
---|
119 | saddr.sin_family = AF_INET; |
---|
120 | saddr.sin_port = htons(14373); |
---|
121 | saddr.sin_addr.s_addr = INADDR_ANY; |
---|
122 | s = socket(AF_INET, SOCK_STREAM, 0); |
---|
123 | if (s < 0) |
---|
124 | sysbail("error creating socket"); |
---|
125 | setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char *) &on, sizeof(on)); |
---|
126 | if (bind(s, (struct sockaddr *) &saddr, sizeof(saddr)) < 0) |
---|
127 | sysbail("error binding socket"); |
---|
128 | if (listen(s, 1) < 0) |
---|
129 | sysbail("error listening to socket"); |
---|
130 | |
---|
131 | /* |
---|
132 | * We're going to try this three times, for each of the three possible |
---|
133 | * different protocol negotiation behaviors that accept_connection can |
---|
134 | * test. Each time, we're going to check that we got a context and that |
---|
135 | * we negotiated the appropriate protocol. |
---|
136 | */ |
---|
137 | for (protocol = 0; protocol <= 2; protocol++) { |
---|
138 | child = fork(); |
---|
139 | if (child < 0) |
---|
140 | sysbail("cannot fork"); |
---|
141 | else if (child == 0) |
---|
142 | make_connection(protocol, principal); |
---|
143 | alarm(1); |
---|
144 | fd = accept(s, NULL, 0); |
---|
145 | if (fd < 0) |
---|
146 | sysbail("error accepting connection"); |
---|
147 | alarm(0); |
---|
148 | client = server_new_client(fd, GSS_C_NO_CREDENTIAL); |
---|
149 | ok(client != NULL, "accept client with protocol %d", protocol); |
---|
150 | if (client == NULL) |
---|
151 | ok(0, "negotiated right protocol"); |
---|
152 | else |
---|
153 | is_int((protocol < 2) ? 1 : 2, client->protocol, |
---|
154 | "negotiated right protocol"); |
---|
155 | server_free_client(client); |
---|
156 | waitpid(child, NULL, 0); |
---|
157 | } |
---|
158 | |
---|
159 | return 0; |
---|
160 | } |
---|