Fix -O3 -Werror=unused-result build in dcache.c (#420)
[heimdal.git] / appl / test / gssapi_server.c
blob5d2a39dd7c43d87c18bf2aa3c31c8bb16a8d478e
1 /*
2 * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan
3 * (Royal Institute of Technology, Stockholm, Sweden).
4 * All rights reserved.
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
17 * 3. Neither the name of the Institute nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
35 * A sample server that uses the GSSAPI.
38 #include "test_locl.h"
39 #include <gssapi/gssapi.h>
40 #include <gssapi/gssapi_krb5.h>
41 #include <gssapi/gssapi_spnego.h>
42 #include "gss_common.h"
44 static int
45 process_it(int sock,
46 gss_ctx_id_t context_hdl,
47 gss_name_t client_name
50 OM_uint32 maj_stat, min_stat;
51 gss_buffer_desc real_input_token, real_output_token;
52 gss_buffer_t input_token = &real_input_token,
53 output_token = &real_output_token;
54 gss_name_t server_name;
55 int conf_flag;
57 print_gss_name("User is", client_name);
59 maj_stat = gss_inquire_context(&min_stat,
60 context_hdl,
61 NULL,
62 &server_name,
63 NULL,
64 NULL,
65 NULL,
66 NULL,
67 NULL);
68 if (GSS_ERROR(maj_stat))
69 gss_err (1, min_stat, "gss_inquire_context");
71 print_gss_name("Server is", server_name);
73 maj_stat = gss_release_name(&min_stat, &server_name);
74 if (GSS_ERROR(maj_stat))
75 gss_err (1, min_stat, "gss_release_name");
77 /* gss_verify_mic */
79 read_token (sock, input_token);
80 read_token (sock, output_token);
82 maj_stat = gss_verify_mic (&min_stat,
83 context_hdl,
84 input_token,
85 output_token,
86 NULL);
87 if (GSS_ERROR(maj_stat))
88 gss_err (1, min_stat, "gss_verify_mic");
90 fprintf (stderr, "gss_verify_mic: %.*s\n", (int)input_token->length,
91 (char *)input_token->value);
93 gss_release_buffer (&min_stat, input_token);
94 gss_release_buffer (&min_stat, output_token);
96 /* create mic */
98 input_token->length = 6;
99 input_token->value = strdup("hejsan");
101 maj_stat = gss_get_mic(&min_stat,
102 context_hdl,
103 GSS_C_QOP_DEFAULT,
104 input_token,
105 output_token);
106 if (GSS_ERROR(maj_stat))
107 gss_err (1, min_stat, "gss_get_mic");
109 write_token (sock, input_token);
110 write_token (sock, output_token);
112 gss_release_buffer (&min_stat, output_token);
114 /* gss_unwrap */
116 read_token (sock, input_token);
118 maj_stat = gss_unwrap (&min_stat,
119 context_hdl,
120 input_token,
121 output_token,
122 &conf_flag,
123 NULL);
124 if(GSS_ERROR(maj_stat))
125 gss_err (1, min_stat, "gss_unwrap");
127 fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
128 (char *)output_token->value,
129 conf_flag ? "CONF" : "INT");
131 gss_release_buffer (&min_stat, input_token);
132 gss_release_buffer (&min_stat, output_token);
134 read_token (sock, input_token);
136 maj_stat = gss_unwrap (&min_stat,
137 context_hdl,
138 input_token,
139 output_token,
140 &conf_flag,
141 NULL);
142 if(GSS_ERROR(maj_stat))
143 gss_err (1, min_stat, "gss_unwrap");
145 fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
146 (char *)output_token->value,
147 conf_flag ? "CONF" : "INT");
149 gss_release_buffer (&min_stat, input_token);
150 gss_release_buffer (&min_stat, output_token);
152 input_token->value = "hejhej";
153 input_token->length = 6;
155 maj_stat = gss_wrap (&min_stat,
156 context_hdl,
158 GSS_C_QOP_DEFAULT,
159 input_token,
160 NULL,
161 output_token);
163 write_token (sock, output_token);
164 gss_release_buffer (&min_stat, output_token);
166 read_token (sock, input_token);
168 if (input_token->length != 6 && memcmp(input_token->value, "hejhej", 6) != 0)
169 errx(1, "invalid reply");
171 return 0;
174 static int
175 proto (int sock, const char *service)
177 struct sockaddr_in remote, local;
178 socklen_t addrlen;
179 gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
180 gss_buffer_desc real_input_token, real_output_token;
181 gss_buffer_t input_token = &real_input_token,
182 output_token = &real_output_token;
183 OM_uint32 maj_stat, min_stat;
184 gss_name_t client_name;
185 struct gss_channel_bindings_struct input_chan_bindings;
186 gss_cred_id_t delegated_cred_handle = NULL;
187 krb5_ccache ccache;
188 u_char init_buf[4];
189 u_char acct_buf[4];
190 gss_OID mech_oid;
191 char *mech, *p;
193 addrlen = sizeof(local);
194 if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
195 || addrlen != sizeof(local))
196 err (1, "getsockname)");
198 addrlen = sizeof(remote);
199 if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
200 || addrlen != sizeof(remote))
201 err (1, "getpeername");
203 input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
204 input_chan_bindings.initiator_address.length = 4;
205 init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
206 init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
207 init_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF;
208 init_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF;
210 input_chan_bindings.initiator_address.value = init_buf;
211 input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
213 input_chan_bindings.acceptor_address.length = 4;
214 acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
215 acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
216 acct_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF;
217 acct_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF;
218 input_chan_bindings.acceptor_address.value = acct_buf;
219 input_chan_bindings.application_data.value = emalloc(4);
220 #if 0
221 * (unsigned short *)input_chan_bindings.application_data.value =
222 remote.sin_port;
223 * ((unsigned short *)input_chan_bindings.application_data.value + 1) =
224 local.sin_port;
225 input_chan_bindings.application_data.length = 4;
226 #else
227 input_chan_bindings.application_data.length = 0;
228 input_chan_bindings.application_data.value = NULL;
229 #endif
231 delegated_cred_handle = GSS_C_NO_CREDENTIAL;
233 do {
234 read_token (sock, input_token);
235 maj_stat =
236 gss_accept_sec_context (&min_stat,
237 &context_hdl,
238 GSS_C_NO_CREDENTIAL,
239 input_token,
240 &input_chan_bindings,
241 &client_name,
242 &mech_oid,
243 output_token,
244 NULL,
245 NULL,
246 &delegated_cred_handle);
247 if(GSS_ERROR(maj_stat))
248 gss_err (1, min_stat, "gss_accept_sec_context");
249 if (output_token->length != 0)
250 write_token (sock, output_token);
251 if (GSS_ERROR(maj_stat)) {
252 if (context_hdl != GSS_C_NO_CONTEXT)
253 gss_delete_sec_context (&min_stat,
254 &context_hdl,
255 GSS_C_NO_BUFFER);
256 break;
258 } while(maj_stat & GSS_S_CONTINUE_NEEDED);
260 p = (char *)mech_oid->elements;
261 if (mech_oid->length == GSS_KRB5_MECHANISM->length
262 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0)
263 mech = "Kerberos 5";
264 else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length
265 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0)
266 mech = "SPNEGO"; /* XXX Silly, wont show up */
267 else
268 mech = "Unknown";
270 printf("Using mech: %s\n", mech);
272 if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
273 krb5_context context;
275 printf("Delegated cred found\n");
277 maj_stat = krb5_init_context(&context);
278 maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache);
279 maj_stat = gss_krb5_copy_ccache(&min_stat,
280 delegated_cred_handle,
281 ccache);
282 if (maj_stat == 0) {
283 krb5_principal p;
284 maj_stat = krb5_cc_get_principal(context, ccache, &p);
285 if (maj_stat == 0) {
286 char *name;
287 maj_stat = krb5_unparse_name(context, p, &name);
288 if (maj_stat == 0) {
289 printf("Delegated user is: `%s'\n", name);
290 free(name);
292 krb5_free_principal(context, p);
295 krb5_cc_close(context, ccache);
296 gss_release_cred(&min_stat, &delegated_cred_handle);
299 if (fork_flag) {
300 pid_t pid;
301 int pipefd[2];
303 if (pipe (pipefd) < 0)
304 err (1, "pipe");
306 pid = fork ();
307 if (pid < 0)
308 err (1, "fork");
309 if (pid != 0) {
310 gss_buffer_desc buf;
312 maj_stat = gss_export_sec_context (&min_stat,
313 &context_hdl,
314 &buf);
315 if (GSS_ERROR(maj_stat))
316 gss_err (1, min_stat, "gss_export_sec_context");
317 write_token (pipefd[1], &buf);
318 exit (0);
319 } else {
320 gss_ctx_id_t context_hdl;
321 gss_buffer_desc buf;
323 close (pipefd[1]);
324 read_token (pipefd[0], &buf);
325 close (pipefd[0]);
326 maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
327 if (GSS_ERROR(maj_stat))
328 gss_err (1, min_stat, "gss_import_sec_context");
329 gss_release_buffer (&min_stat, &buf);
330 return process_it (sock, context_hdl, client_name);
332 } else {
333 return process_it (sock, context_hdl, client_name);
337 static void
338 loop (int port, const char *service)
340 int sock, sock2;
341 struct sockaddr_in my_addr;
342 int one = 1;
344 if (keytab_str)
345 gsskrb5_register_acceptor_identity(keytab_str);
347 sock = socket (AF_INET, SOCK_STREAM, 0);
348 if (sock < 0)
349 err (1, "socket");
351 memset (&my_addr, 0, sizeof(my_addr));
352 my_addr.sin_family = AF_INET;
353 my_addr.sin_port = port;
354 my_addr.sin_addr.s_addr = INADDR_ANY;
356 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
357 (void *)&one, sizeof(one)) < 0)
358 warn ("setsockopt SO_REUSEADDR");
360 if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
361 err (1, "bind");
363 while (1) {
364 if (listen (sock, 1) < 0)
365 err (1, "listen");
367 sock2 = accept (sock, NULL, NULL);
368 if (sock2 < 0)
369 err (1, "accept");
371 proto (sock2, service);
376 * Iterative server; process one connection at a time.
379 main(int argc, char **argv)
381 krb5_context context = NULL; /* XXX */
382 krb5_error_code ret;
383 int port = server_setup(&context, argc, argv);
385 ret = krb5_kt_have_content(context, keytab);
386 if (ret)
387 krb5_err (context, 1, ret, "krb5_kt_have_content");
389 loop (port, service);
390 return 0;