1/* 2 * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 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. 16 * 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. 20 * 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. 32 */ 33 34#include "test_locl.h" 35#include <gssapi/gssapi.h> 36#include <gssapi/gssapi_krb5.h> 37#include <gssapi/gssapi_spnego.h> 38#include "gss_common.h" 39RCSID("$Id$"); 40 41static int 42process_it(int sock, 43 gss_ctx_id_t context_hdl, 44 gss_name_t client_name 45 ) 46{ 47 OM_uint32 maj_stat, min_stat; 48 gss_buffer_desc real_input_token, real_output_token; 49 gss_buffer_t input_token = &real_input_token, 50 output_token = &real_output_token; 51 gss_name_t server_name; 52 int conf_flag; 53 54 print_gss_name("User is", client_name); 55 56 maj_stat = gss_inquire_context(&min_stat, 57 context_hdl, 58 NULL, 59 &server_name, 60 NULL, 61 NULL, 62 NULL, 63 NULL, 64 NULL); 65 if (GSS_ERROR(maj_stat)) 66 gss_err (1, min_stat, "gss_inquire_context"); 67 68 print_gss_name("Server is", server_name); 69 70 maj_stat = gss_release_name(&min_stat, &server_name); 71 if (GSS_ERROR(maj_stat)) 72 gss_err (1, min_stat, "gss_release_name"); 73 74 /* gss_verify_mic */ 75 76 read_token (sock, input_token); 77 read_token (sock, output_token); 78 79 maj_stat = gss_verify_mic (&min_stat, 80 context_hdl, 81 input_token, 82 output_token, 83 NULL); 84 if (GSS_ERROR(maj_stat)) 85 gss_err (1, min_stat, "gss_verify_mic"); 86 87 fprintf (stderr, "gss_verify_mic: %.*s\n", (int)input_token->length, 88 (char *)input_token->value); 89 90 gss_release_buffer (&min_stat, input_token); 91 gss_release_buffer (&min_stat, output_token); 92 93 /* create mic */ 94 95 input_token->length = 6; 96 input_token->value = strdup("hejsan"); 97 98 maj_stat = gss_get_mic(&min_stat, 99 context_hdl, 100 GSS_C_QOP_DEFAULT, 101 input_token, 102 output_token); 103 if (GSS_ERROR(maj_stat)) 104 gss_err (1, min_stat, "gss_get_mic"); 105 106 write_token (sock, input_token); 107 write_token (sock, output_token); 108 109 gss_release_buffer (&min_stat, output_token); 110 111 /* gss_unwrap */ 112 113 read_token (sock, input_token); 114 115 maj_stat = gss_unwrap (&min_stat, 116 context_hdl, 117 input_token, 118 output_token, 119 &conf_flag, 120 NULL); 121 if(GSS_ERROR(maj_stat)) 122 gss_err (1, min_stat, "gss_unwrap"); 123 124 fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length, 125 (char *)output_token->value, 126 conf_flag ? "CONF" : "INT"); 127 128 gss_release_buffer (&min_stat, input_token); 129 gss_release_buffer (&min_stat, output_token); 130 131 read_token (sock, input_token); 132 133 maj_stat = gss_unwrap (&min_stat, 134 context_hdl, 135 input_token, 136 output_token, 137 &conf_flag, 138 NULL); 139 if(GSS_ERROR(maj_stat)) 140 gss_err (1, min_stat, "gss_unwrap"); 141 142 fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length, 143 (char *)output_token->value, 144 conf_flag ? "CONF" : "INT"); 145 146 gss_release_buffer (&min_stat, input_token); 147 gss_release_buffer (&min_stat, output_token); 148 149 input_token->value = "hejhej"; 150 input_token->length = 6; 151 152 maj_stat = gss_wrap (&min_stat, 153 context_hdl, 154 1, 155 GSS_C_QOP_DEFAULT, 156 input_token, 157 NULL, 158 output_token); 159 160 write_token (sock, output_token); 161 gss_release_buffer (&min_stat, output_token); 162 163 read_token (sock, input_token); 164 165 if (input_token->length != 6 && memcmp(input_token->value, "hejhej", 6) != 0) 166 errx(1, "invalid reply"); 167 168 return 0; 169} 170 171static int 172proto (int sock, const char *service) 173{ 174 struct sockaddr_in remote, local; 175 socklen_t addrlen; 176 gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; 177 gss_buffer_desc real_input_token, real_output_token; 178 gss_buffer_t input_token = &real_input_token, 179 output_token = &real_output_token; 180 OM_uint32 maj_stat, min_stat; 181 gss_name_t client_name; 182 struct gss_channel_bindings_struct input_chan_bindings; 183 gss_cred_id_t delegated_cred_handle = NULL; 184 krb5_ccache ccache; 185 u_char init_buf[4]; 186 u_char acct_buf[4]; 187 gss_OID mech_oid; 188 char *mech, *p; 189 190 addrlen = sizeof(local); 191 if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 192 || addrlen != sizeof(local)) 193 err (1, "getsockname)"); 194 195 addrlen = sizeof(remote); 196 if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 197 || addrlen != sizeof(remote)) 198 err (1, "getpeername"); 199 200 input_chan_bindings.initiator_addrtype = GSS_C_AF_INET; 201 input_chan_bindings.initiator_address.length = 4; 202 init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF; 203 init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF; 204 init_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF; 205 init_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF; 206 207 input_chan_bindings.initiator_address.value = init_buf; 208 input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET; 209 210 input_chan_bindings.acceptor_address.length = 4; 211 acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF; 212 acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF; 213 acct_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF; 214 acct_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF; 215 input_chan_bindings.acceptor_address.value = acct_buf; 216 input_chan_bindings.application_data.value = emalloc(4); 217#if 0 218 * (unsigned short *)input_chan_bindings.application_data.value = 219 remote.sin_port; 220 * ((unsigned short *)input_chan_bindings.application_data.value + 1) = 221 local.sin_port; 222 input_chan_bindings.application_data.length = 4; 223#else 224 input_chan_bindings.application_data.length = 0; 225 input_chan_bindings.application_data.value = NULL; 226#endif 227 228 delegated_cred_handle = GSS_C_NO_CREDENTIAL; 229 230 do { 231 read_token (sock, input_token); 232 maj_stat = 233 gss_accept_sec_context (&min_stat, 234 &context_hdl, 235 GSS_C_NO_CREDENTIAL, 236 input_token, 237 &input_chan_bindings, 238 &client_name, 239 &mech_oid, 240 output_token, 241 NULL, 242 NULL, 243 &delegated_cred_handle); 244 if(GSS_ERROR(maj_stat)) 245 gss_err (1, min_stat, "gss_accept_sec_context"); 246 if (output_token->length != 0) 247 write_token (sock, output_token); 248 if (GSS_ERROR(maj_stat)) { 249 if (context_hdl != GSS_C_NO_CONTEXT) 250 gss_delete_sec_context (&min_stat, 251 &context_hdl, 252 GSS_C_NO_BUFFER); 253 break; 254 } 255 } while(maj_stat & GSS_S_CONTINUE_NEEDED); 256 257 p = (char *)mech_oid->elements; 258 if (mech_oid->length == GSS_KRB5_MECHANISM->length 259 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0) 260 mech = "Kerberos 5"; 261 else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length 262 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0) 263 mech = "SPNEGO"; /* XXX Silly, wont show up */ 264 else 265 mech = "Unknown"; 266 267 printf("Using mech: %s\n", mech); 268 269 if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) { 270 krb5_context context; 271 272 printf("Delegated cred found\n"); 273 274 maj_stat = krb5_init_context(&context); 275 maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); 276 maj_stat = gss_krb5_copy_ccache(&min_stat, 277 delegated_cred_handle, 278 ccache); 279 if (maj_stat == 0) { 280 krb5_principal p; 281 maj_stat = krb5_cc_get_principal(context, ccache, &p); 282 if (maj_stat == 0) { 283 char *name; 284 maj_stat = krb5_unparse_name(context, p, &name); 285 if (maj_stat == 0) { 286 printf("Delegated user is: `%s'\n", name); 287 free(name); 288 } 289 krb5_free_principal(context, p); 290 } 291 } 292 krb5_cc_close(context, ccache); 293 gss_release_cred(&min_stat, &delegated_cred_handle); 294 } 295 296 if (fork_flag) { 297 pid_t pid; 298 int pipefd[2]; 299 300 if (pipe (pipefd) < 0) 301 err (1, "pipe"); 302 303 pid = fork (); 304 if (pid < 0) 305 err (1, "fork"); 306 if (pid != 0) { 307 gss_buffer_desc buf; 308 309 maj_stat = gss_export_sec_context (&min_stat, 310 &context_hdl, 311 &buf); 312 if (GSS_ERROR(maj_stat)) 313 gss_err (1, min_stat, "gss_export_sec_context"); 314 write_token (pipefd[1], &buf); 315 exit (0); 316 } else { 317 gss_ctx_id_t context_hdl; 318 gss_buffer_desc buf; 319 320 close (pipefd[1]); 321 read_token (pipefd[0], &buf); 322 close (pipefd[0]); 323 maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl); 324 if (GSS_ERROR(maj_stat)) 325 gss_err (1, min_stat, "gss_import_sec_context"); 326 gss_release_buffer (&min_stat, &buf); 327 return process_it (sock, context_hdl, client_name); 328 } 329 } else { 330 return process_it (sock, context_hdl, client_name); 331 } 332} 333 334static int 335doit (int port, const char *service) 336{ 337 int sock, sock2; 338 struct sockaddr_in my_addr; 339 int one = 1; 340 int ret; 341 342 if (keytab_str) 343 gsskrb5_register_acceptor_identity(keytab_str); 344 345 sock = socket (AF_INET, SOCK_STREAM, 0); 346 if (sock < 0) 347 err (1, "socket"); 348 349 memset (&my_addr, 0, sizeof(my_addr)); 350 my_addr.sin_family = AF_INET; 351 my_addr.sin_port = port; 352 my_addr.sin_addr.s_addr = INADDR_ANY; 353 354 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 355 (void *)&one, sizeof(one)) < 0) 356 warn ("setsockopt SO_REUSEADDR"); 357 358 if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) 359 err (1, "bind"); 360 361 while (1) { 362 if (listen (sock, 1) < 0) 363 err (1, "listen"); 364 365 sock2 = accept (sock, NULL, NULL); 366 if (sock2 < 0) 367 err (1, "accept"); 368 369 ret = proto (sock2, service); 370 } 371 return ret; 372} 373 374int 375main(int argc, char **argv) 376{ 377 krb5_context context = NULL; /* XXX */ 378 int port = server_setup(&context, argc, argv); 379 return doit (port, service_str); 380} 381