gssapi/mech: -Wcalloc-transposed args
[heimdal.git] / appl / test / gssapi_server.c
blob74ceb3bee2e7a1209fc06e5cc5b049b69266a515
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);
162 if (GSS_ERROR(maj_stat))
163 gss_err(1, min_stat, "gss_wrap");
165 write_token (sock, output_token);
166 gss_release_buffer (&min_stat, output_token);
168 read_token (sock, input_token);
170 if (input_token->length != 6 && memcmp(input_token->value, "hejhej", 6) != 0)
171 errx(1, "invalid reply");
173 return 0;
176 static int
177 proto (int sock, const char *service)
179 struct sockaddr_in remote, local;
180 socklen_t addrlen;
181 gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
182 gss_buffer_desc real_input_token, real_output_token;
183 gss_buffer_t input_token = &real_input_token,
184 output_token = &real_output_token;
185 OM_uint32 maj_stat, min_stat;
186 gss_name_t client_name;
187 struct gss_channel_bindings_struct input_chan_bindings;
188 gss_cred_id_t delegated_cred_handle = NULL;
189 krb5_ccache ccache = NULL;
190 u_char init_buf[4];
191 u_char acct_buf[4];
192 gss_OID mech_oid;
193 char *mech, *p;
195 memset(&remote, 0, sizeof(remote));
196 local = remote;
198 addrlen = sizeof(local);
199 if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
200 || addrlen != sizeof(local))
201 err (1, "getsockname)");
203 addrlen = sizeof(remote);
204 if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
205 || addrlen != sizeof(remote))
206 err (1, "getpeername");
208 input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
209 input_chan_bindings.initiator_address.length = 4;
210 init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
211 init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
212 init_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF;
213 init_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF;
215 input_chan_bindings.initiator_address.value = init_buf;
216 input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
218 input_chan_bindings.acceptor_address.length = 4;
219 acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
220 acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
221 acct_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF;
222 acct_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF;
223 input_chan_bindings.acceptor_address.value = acct_buf;
224 input_chan_bindings.application_data.value = emalloc(4);
225 #if 0
226 * (unsigned short *)input_chan_bindings.application_data.value =
227 remote.sin_port;
228 * ((unsigned short *)input_chan_bindings.application_data.value + 1) =
229 local.sin_port;
230 input_chan_bindings.application_data.length = 4;
231 #else
232 input_chan_bindings.application_data.length = 0;
233 input_chan_bindings.application_data.value = NULL;
234 #endif
236 delegated_cred_handle = GSS_C_NO_CREDENTIAL;
238 do {
239 read_token (sock, input_token);
240 maj_stat =
241 gss_accept_sec_context (&min_stat,
242 &context_hdl,
243 GSS_C_NO_CREDENTIAL,
244 input_token,
245 &input_chan_bindings,
246 &client_name,
247 &mech_oid,
248 output_token,
249 NULL,
250 NULL,
251 &delegated_cred_handle);
252 if(GSS_ERROR(maj_stat))
253 gss_err (1, min_stat, "gss_accept_sec_context");
254 if (output_token->length != 0)
255 write_token (sock, output_token);
256 if (GSS_ERROR(maj_stat)) {
257 if (context_hdl != GSS_C_NO_CONTEXT)
258 gss_delete_sec_context (&min_stat,
259 &context_hdl,
260 GSS_C_NO_BUFFER);
261 break;
263 } while(maj_stat & GSS_S_CONTINUE_NEEDED);
265 p = (char *)mech_oid->elements;
266 if (mech_oid->length == GSS_KRB5_MECHANISM->length
267 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0)
268 mech = "Kerberos 5";
269 else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length
270 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0)
271 mech = "SPNEGO"; /* XXX Silly, wont show up */
272 else
273 mech = "Unknown";
275 printf("Using mech: %s\n", mech);
277 if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
278 krb5_context context = NULL;
280 printf("Delegated cred found\n");
282 min_stat = krb5_init_context(&context);
283 if (min_stat)
284 gss_err(1, min_stat, "krb5_init_context");
285 if (min_stat == 0)
286 min_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache);
287 if (min_stat == 0)
288 maj_stat = gss_krb5_copy_ccache(&min_stat,
289 delegated_cred_handle,
290 ccache);
291 else
292 maj_stat = GSS_S_FAILURE;
293 if (maj_stat == 0) {
294 krb5_principal p;
295 maj_stat = krb5_cc_get_principal(context, ccache, &p);
296 if (maj_stat == 0) {
297 char *name;
298 maj_stat = krb5_unparse_name(context, p, &name);
299 if (maj_stat == 0) {
300 printf("Delegated user is: `%s'\n", name);
301 free(name);
303 krb5_free_principal(context, p);
306 krb5_cc_close(context, ccache);
307 krb5_free_context(context);
308 gss_release_cred(&min_stat, &delegated_cred_handle);
311 if (fork_flag) {
312 pid_t pid;
313 int pipefd[2];
315 if (pipe (pipefd) < 0)
316 err (1, "pipe");
318 pid = fork ();
319 if (pid < 0)
320 err (1, "fork");
321 if (pid != 0) {
322 gss_buffer_desc buf;
324 maj_stat = gss_export_sec_context (&min_stat,
325 &context_hdl,
326 &buf);
327 if (GSS_ERROR(maj_stat))
328 gss_err (1, min_stat, "gss_export_sec_context");
329 write_token (pipefd[1], &buf);
330 exit (0);
331 } else {
332 gss_ctx_id_t context_hdl;
333 gss_buffer_desc buf;
335 close (pipefd[1]);
336 read_token (pipefd[0], &buf);
337 close (pipefd[0]);
338 maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
339 if (GSS_ERROR(maj_stat))
340 gss_err (1, min_stat, "gss_import_sec_context");
341 gss_release_buffer (&min_stat, &buf);
342 return process_it (sock, context_hdl, client_name);
344 } else {
345 return process_it (sock, context_hdl, client_name);
349 static void
350 loop (int port, const char *service)
352 int sock, sock2;
353 struct sockaddr_in my_addr;
354 int one = 1;
356 if (keytab_str)
357 gsskrb5_register_acceptor_identity(keytab_str);
359 sock = socket (AF_INET, SOCK_STREAM, 0);
360 if (sock < 0)
361 err (1, "socket");
363 memset (&my_addr, 0, sizeof(my_addr));
364 my_addr.sin_family = AF_INET;
365 my_addr.sin_port = port;
366 my_addr.sin_addr.s_addr = INADDR_ANY;
368 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
369 (void *)&one, sizeof(one)) < 0)
370 warn ("setsockopt SO_REUSEADDR");
372 if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
373 err (1, "bind");
375 while (1) {
376 if (listen (sock, 1) < 0)
377 err (1, "listen");
379 sock2 = accept (sock, NULL, NULL);
380 if (sock2 < 0)
381 err (1, "accept");
383 proto (sock2, service);
388 * Iterative server; process one connection at a time.
391 main(int argc, char **argv)
393 krb5_context context = NULL; /* XXX */
394 krb5_error_code ret;
395 int port = server_setup(&context, argc, argv);
397 ret = krb5_kt_have_content(context, keytab);
398 if (ret)
399 krb5_err (context, 1, ret, "krb5_kt_have_content");
401 loop (port, service);
402 return 0;