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" 39 RCSID("$Id$"); 40 41 static int 42 process_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 /* gss_unwrap */ 94 95 read_token (sock, input_token); 96 97 maj_stat = gss_unwrap (&min_stat, 98 context_hdl, 99 input_token, 100 output_token, 101 &conf_flag, 102 NULL); 103 if(GSS_ERROR(maj_stat)) 104 gss_err (1, min_stat, "gss_unwrap"); 105 106 fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length, 107 (char *)output_token->value, 108 conf_flag ? "CONF" : "INT"); 109 110 gss_release_buffer (&min_stat, input_token); 111 gss_release_buffer (&min_stat, output_token); 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 return 0; 132 } 133 134 static int 135 proto (int sock, const char *service) 136 { 137 struct sockaddr_in remote, local; 138 socklen_t addrlen; 139 gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT; 140 gss_buffer_desc real_input_token, real_output_token; 141 gss_buffer_t input_token = &real_input_token, 142 output_token = &real_output_token; 143 OM_uint32 maj_stat, min_stat; 144 gss_name_t client_name; 145 struct gss_channel_bindings_struct input_chan_bindings; 146 gss_cred_id_t delegated_cred_handle = NULL; 147 krb5_ccache ccache; 148 u_char init_buf[4]; 149 u_char acct_buf[4]; 150 gss_OID mech_oid; 151 char *mech, *p; 152 153 addrlen = sizeof(local); 154 if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0 155 || addrlen != sizeof(local)) 156 err (1, "getsockname)"); 157 158 addrlen = sizeof(remote); 159 if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0 160 || addrlen != sizeof(remote)) 161 err (1, "getpeername"); 162 163 input_chan_bindings.initiator_addrtype = GSS_C_AF_INET; 164 input_chan_bindings.initiator_address.length = 4; 165 init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF; 166 init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF; 167 init_buf[2] = (remote.sin_addr.s_addr >> 8) & 0xFF; 168 init_buf[3] = (remote.sin_addr.s_addr >> 0) & 0xFF; 169 170 input_chan_bindings.initiator_address.value = init_buf; 171 input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET; 172 173 input_chan_bindings.acceptor_address.length = 4; 174 acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF; 175 acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF; 176 acct_buf[2] = (local.sin_addr.s_addr >> 8) & 0xFF; 177 acct_buf[3] = (local.sin_addr.s_addr >> 0) & 0xFF; 178 input_chan_bindings.acceptor_address.value = acct_buf; 179 input_chan_bindings.application_data.value = emalloc(4); 180 #if 0 181 * (unsigned short *)input_chan_bindings.application_data.value = 182 remote.sin_port; 183 * ((unsigned short *)input_chan_bindings.application_data.value + 1) = 184 local.sin_port; 185 input_chan_bindings.application_data.length = 4; 186 #else 187 input_chan_bindings.application_data.length = 0; 188 input_chan_bindings.application_data.value = NULL; 189 #endif 190 191 delegated_cred_handle = GSS_C_NO_CREDENTIAL; 192 193 do { 194 read_token (sock, input_token); 195 maj_stat = 196 gss_accept_sec_context (&min_stat, 197 &context_hdl, 198 GSS_C_NO_CREDENTIAL, 199 input_token, 200 &input_chan_bindings, 201 &client_name, 202 &mech_oid, 203 output_token, 204 NULL, 205 NULL, 206 &delegated_cred_handle); 207 if(GSS_ERROR(maj_stat)) 208 gss_err (1, min_stat, "gss_accept_sec_context"); 209 if (output_token->length != 0) 210 write_token (sock, output_token); 211 if (GSS_ERROR(maj_stat)) { 212 if (context_hdl != GSS_C_NO_CONTEXT) 213 gss_delete_sec_context (&min_stat, 214 &context_hdl, 215 GSS_C_NO_BUFFER); 216 break; 217 } 218 } while(maj_stat & GSS_S_CONTINUE_NEEDED); 219 220 p = (char *)mech_oid->elements; 221 if (mech_oid->length == GSS_KRB5_MECHANISM->length 222 && memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0) 223 mech = "Kerberos 5"; 224 else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length 225 && memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0) 226 mech = "SPNEGO"; /* XXX Silly, wont show up */ 227 else 228 mech = "Unknown"; 229 230 printf("Using mech: %s\n", mech); 231 232 if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) { 233 krb5_context context; 234 235 printf("Delegated cred found\n"); 236 237 maj_stat = krb5_init_context(&context); 238 maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache); 239 maj_stat = gss_krb5_copy_ccache(&min_stat, 240 delegated_cred_handle, 241 ccache); 242 if (maj_stat == 0) { 243 krb5_principal p; 244 maj_stat = krb5_cc_get_principal(context, ccache, &p); 245 if (maj_stat == 0) { 246 char *name; 247 maj_stat = krb5_unparse_name(context, p, &name); 248 if (maj_stat == 0) { 249 printf("Delegated user is: `%s'\n", name); 250 free(name); 251 } 252 krb5_free_principal(context, p); 253 } 254 } 255 krb5_cc_close(context, ccache); 256 gss_release_cred(&min_stat, &delegated_cred_handle); 257 } 258 259 if (fork_flag) { 260 pid_t pid; 261 int pipefd[2]; 262 263 if (pipe (pipefd) < 0) 264 err (1, "pipe"); 265 266 pid = fork (); 267 if (pid < 0) 268 err (1, "fork"); 269 if (pid != 0) { 270 gss_buffer_desc buf; 271 272 maj_stat = gss_export_sec_context (&min_stat, 273 &context_hdl, 274 &buf); 275 if (GSS_ERROR(maj_stat)) 276 gss_err (1, min_stat, "gss_export_sec_context"); 277 write_token (pipefd[1], &buf); 278 exit (0); 279 } else { 280 gss_ctx_id_t context_hdl; 281 gss_buffer_desc buf; 282 283 close (pipefd[1]); 284 read_token (pipefd[0], &buf); 285 close (pipefd[0]); 286 maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl); 287 if (GSS_ERROR(maj_stat)) 288 gss_err (1, min_stat, "gss_import_sec_context"); 289 gss_release_buffer (&min_stat, &buf); 290 return process_it (sock, context_hdl, client_name); 291 } 292 } else { 293 return process_it (sock, context_hdl, client_name); 294 } 295 } 296 297 static int 298 doit (int port, const char *service) 299 { 300 int sock, sock2; 301 struct sockaddr_in my_addr; 302 int one = 1; 303 int ret; 304 305 sock = socket (AF_INET, SOCK_STREAM, 0); 306 if (sock < 0) 307 err (1, "socket"); 308 309 memset (&my_addr, 0, sizeof(my_addr)); 310 my_addr.sin_family = AF_INET; 311 my_addr.sin_port = port; 312 my_addr.sin_addr.s_addr = INADDR_ANY; 313 314 if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR, 315 (void *)&one, sizeof(one)) < 0) 316 warn ("setsockopt SO_REUSEADDR"); 317 318 if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0) 319 err (1, "bind"); 320 321 while (1) { 322 if (listen (sock, 1) < 0) 323 err (1, "listen"); 324 325 sock2 = accept (sock, NULL, NULL); 326 if (sock2 < 0) 327 err (1, "accept"); 328 329 ret = proto (sock2, service); 330 } 331 return ret; 332 } 333 334 int 335 main(int argc, char **argv) 336 { 337 krb5_context context = NULL; /* XXX */ 338 int port = server_setup(&context, argc, argv); 339 return doit (port, service); 340 } 341 342