| 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 |
|
|---|