155682Smarkm/*
2233294Sstas * Copyright (c) 1997 - 2000 Kungliga Tekniska H��gskolan
3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden).
4233294Sstas * All rights reserved.
555682Smarkm *
6233294Sstas * Redistribution and use in source and binary forms, with or without
7233294Sstas * modification, are permitted provided that the following conditions
8233294Sstas * are met:
955682Smarkm *
10233294Sstas * 1. Redistributions of source code must retain the above copyright
11233294Sstas *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright
14233294Sstas *    notice, this list of conditions and the following disclaimer in the
15233294Sstas *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors
18233294Sstas *    may be used to endorse or promote products derived from this software
19233294Sstas *    without specific prior written permission.
2055682Smarkm *
21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24233294Sstas * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31233294Sstas * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "test_locl.h"
35233294Sstas#include <gssapi/gssapi.h>
36233294Sstas#include <gssapi/gssapi_krb5.h>
37233294Sstas#include <gssapi/gssapi_spnego.h>
3855682Smarkm#include "gss_common.h"
39233294SstasRCSID("$Id$");
4055682Smarkm
4155682Smarkmstatic int
4257419Smarkmprocess_it(int sock,
4357419Smarkm	   gss_ctx_id_t context_hdl,
4457419Smarkm	   gss_name_t client_name
4557419Smarkm	   )
4657419Smarkm{
4757419Smarkm    OM_uint32 maj_stat, min_stat;
4857419Smarkm    gss_buffer_desc real_input_token, real_output_token;
4957419Smarkm    gss_buffer_t input_token = &real_input_token,
5057419Smarkm	output_token = &real_output_token;
51178825Sdfr    gss_name_t server_name;
52178825Sdfr    int conf_flag;
5357419Smarkm
54178825Sdfr    print_gss_name("User is", client_name);
55178825Sdfr
56178825Sdfr    maj_stat = gss_inquire_context(&min_stat,
57178825Sdfr				   context_hdl,
58178825Sdfr				   NULL,
59178825Sdfr				   &server_name,
60178825Sdfr				   NULL,
61178825Sdfr				   NULL,
62178825Sdfr				   NULL,
63178825Sdfr				   NULL,
64178825Sdfr				   NULL);
6557419Smarkm    if (GSS_ERROR(maj_stat))
66178825Sdfr	gss_err (1, min_stat, "gss_inquire_context");
6757419Smarkm
68178825Sdfr    print_gss_name("Server is", server_name);
6957419Smarkm
70178825Sdfr    maj_stat = gss_release_name(&min_stat, &server_name);
71178825Sdfr    if (GSS_ERROR(maj_stat))
72178825Sdfr	gss_err (1, min_stat, "gss_release_name");
7357419Smarkm
7457419Smarkm    /* gss_verify_mic */
7557419Smarkm
7657419Smarkm    read_token (sock, input_token);
7757419Smarkm    read_token (sock, output_token);
7857419Smarkm
7957419Smarkm    maj_stat = gss_verify_mic (&min_stat,
8057419Smarkm			       context_hdl,
8157419Smarkm			       input_token,
8257419Smarkm			       output_token,
8357419Smarkm			       NULL);
8457419Smarkm    if (GSS_ERROR(maj_stat))
8557419Smarkm	gss_err (1, min_stat, "gss_verify_mic");
8657419Smarkm
8757419Smarkm    fprintf (stderr, "gss_verify_mic: %.*s\n", (int)input_token->length,
8857419Smarkm	    (char *)input_token->value);
8957419Smarkm
9057419Smarkm    gss_release_buffer (&min_stat, input_token);
9157419Smarkm    gss_release_buffer (&min_stat, output_token);
9257419Smarkm
9357419Smarkm    /* gss_unwrap */
9457419Smarkm
9557419Smarkm    read_token (sock, input_token);
9657419Smarkm
9757419Smarkm    maj_stat = gss_unwrap (&min_stat,
9857419Smarkm			   context_hdl,
9957419Smarkm			   input_token,
10057419Smarkm			   output_token,
101178825Sdfr			   &conf_flag,
10257419Smarkm			   NULL);
10357419Smarkm    if(GSS_ERROR(maj_stat))
10457419Smarkm	gss_err (1, min_stat, "gss_unwrap");
10557419Smarkm
106178825Sdfr    fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
107178825Sdfr	    (char *)output_token->value,
108178825Sdfr	     conf_flag ? "CONF" : "INT");
10957419Smarkm
11057419Smarkm    gss_release_buffer (&min_stat, input_token);
11157419Smarkm    gss_release_buffer (&min_stat, output_token);
11257419Smarkm
113178825Sdfr    read_token (sock, input_token);
114178825Sdfr
115178825Sdfr    maj_stat = gss_unwrap (&min_stat,
116178825Sdfr			   context_hdl,
117178825Sdfr			   input_token,
118178825Sdfr			   output_token,
119178825Sdfr			   &conf_flag,
120178825Sdfr			   NULL);
121178825Sdfr    if(GSS_ERROR(maj_stat))
122178825Sdfr	gss_err (1, min_stat, "gss_unwrap");
123178825Sdfr
124178825Sdfr    fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
125178825Sdfr	     (char *)output_token->value,
126178825Sdfr	     conf_flag ? "CONF" : "INT");
127178825Sdfr
128178825Sdfr    gss_release_buffer (&min_stat, input_token);
129178825Sdfr    gss_release_buffer (&min_stat, output_token);
130178825Sdfr
13157419Smarkm    return 0;
13257419Smarkm}
13357419Smarkm
13457419Smarkmstatic int
13555682Smarkmproto (int sock, const char *service)
13655682Smarkm{
13755682Smarkm    struct sockaddr_in remote, local;
13872445Sassar    socklen_t addrlen;
13955682Smarkm    gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
14055682Smarkm    gss_buffer_desc real_input_token, real_output_token;
14157419Smarkm    gss_buffer_t input_token = &real_input_token,
14257419Smarkm	output_token = &real_output_token;
14355682Smarkm    OM_uint32 maj_stat, min_stat;
14455682Smarkm    gss_name_t client_name;
14572445Sassar    struct gss_channel_bindings_struct input_chan_bindings;
14672445Sassar    gss_cred_id_t delegated_cred_handle = NULL;
14772445Sassar    krb5_ccache ccache;
14872445Sassar    u_char init_buf[4];
14972445Sassar    u_char acct_buf[4];
150178825Sdfr    gss_OID mech_oid;
151178825Sdfr    char *mech, *p;
15255682Smarkm
15355682Smarkm    addrlen = sizeof(local);
15455682Smarkm    if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
15555682Smarkm	|| addrlen != sizeof(local))
15655682Smarkm	err (1, "getsockname)");
15755682Smarkm
15855682Smarkm    addrlen = sizeof(remote);
15955682Smarkm    if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
16055682Smarkm	|| addrlen != sizeof(remote))
16155682Smarkm	err (1, "getpeername");
16255682Smarkm
16372445Sassar    input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
16472445Sassar    input_chan_bindings.initiator_address.length = 4;
16572445Sassar    init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
16672445Sassar    init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
16772445Sassar    init_buf[2] = (remote.sin_addr.s_addr >>  8) & 0xFF;
16872445Sassar    init_buf[3] = (remote.sin_addr.s_addr >>  0) & 0xFF;
16972445Sassar
17072445Sassar    input_chan_bindings.initiator_address.value = init_buf;
17172445Sassar    input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
17272445Sassar
17372445Sassar    input_chan_bindings.acceptor_address.length = 4;
17472445Sassar    acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
17572445Sassar    acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
17672445Sassar    acct_buf[2] = (local.sin_addr.s_addr >>  8) & 0xFF;
17772445Sassar    acct_buf[3] = (local.sin_addr.s_addr >>  0) & 0xFF;
17872445Sassar    input_chan_bindings.acceptor_address.value = acct_buf;
17972445Sassar    input_chan_bindings.application_data.value = emalloc(4);
18072445Sassar#if 0
18172445Sassar    * (unsigned short *)input_chan_bindings.application_data.value =
18272445Sassar                          remote.sin_port;
18372445Sassar    * ((unsigned short *)input_chan_bindings.application_data.value + 1) =
18472445Sassar                          local.sin_port;
18572445Sassar    input_chan_bindings.application_data.length = 4;
18672445Sassar#else
18772445Sassar    input_chan_bindings.application_data.length = 0;
18872445Sassar    input_chan_bindings.application_data.value = NULL;
18972445Sassar#endif
190233294Sstas
191178825Sdfr    delegated_cred_handle = GSS_C_NO_CREDENTIAL;
192233294Sstas
19355682Smarkm    do {
19455682Smarkm	read_token (sock, input_token);
19555682Smarkm	maj_stat =
19655682Smarkm	    gss_accept_sec_context (&min_stat,
19755682Smarkm				    &context_hdl,
19855682Smarkm				    GSS_C_NO_CREDENTIAL,
19955682Smarkm				    input_token,
20072445Sassar				    &input_chan_bindings,
20155682Smarkm				    &client_name,
202178825Sdfr				    &mech_oid,
20355682Smarkm				    output_token,
20455682Smarkm				    NULL,
20555682Smarkm				    NULL,
206178825Sdfr				    &delegated_cred_handle);
20755682Smarkm	if(GSS_ERROR(maj_stat))
20855682Smarkm	    gss_err (1, min_stat, "gss_accept_sec_context");
20955682Smarkm	if (output_token->length != 0)
21055682Smarkm	    write_token (sock, output_token);
21155682Smarkm	if (GSS_ERROR(maj_stat)) {
21255682Smarkm	    if (context_hdl != GSS_C_NO_CONTEXT)
21355682Smarkm		gss_delete_sec_context (&min_stat,
21455682Smarkm					&context_hdl,
21555682Smarkm					GSS_C_NO_BUFFER);
21655682Smarkm	    break;
21755682Smarkm	}
21855682Smarkm    } while(maj_stat & GSS_S_CONTINUE_NEEDED);
219233294Sstas
220178825Sdfr    p = (char *)mech_oid->elements;
221178825Sdfr    if (mech_oid->length == GSS_KRB5_MECHANISM->length
222178825Sdfr	&& memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0)
223178825Sdfr	mech = "Kerberos 5";
224178825Sdfr    else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length
225178825Sdfr	&& memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0)
226178825Sdfr	mech = "SPNEGO"; /* XXX Silly, wont show up */
227178825Sdfr    else
228178825Sdfr	mech = "Unknown";
229178825Sdfr
230178825Sdfr    printf("Using mech: %s\n", mech);
231178825Sdfr
232178825Sdfr    if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
23372445Sassar       krb5_context context;
23455682Smarkm
235178825Sdfr       printf("Delegated cred found\n");
236178825Sdfr
23772445Sassar       maj_stat = krb5_init_context(&context);
23872445Sassar       maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache);
239178825Sdfr       maj_stat = gss_krb5_copy_ccache(&min_stat,
240178825Sdfr				       delegated_cred_handle,
241178825Sdfr				       ccache);
242178825Sdfr       if (maj_stat == 0) {
243178825Sdfr	   krb5_principal p;
244178825Sdfr	   maj_stat = krb5_cc_get_principal(context, ccache, &p);
245178825Sdfr	   if (maj_stat == 0) {
246178825Sdfr	       char *name;
247178825Sdfr	       maj_stat = krb5_unparse_name(context, p, &name);
248178825Sdfr	       if (maj_stat == 0) {
249178825Sdfr		   printf("Delegated user is: `%s'\n", name);
250178825Sdfr		   free(name);
251178825Sdfr	       }
252178825Sdfr	       krb5_free_principal(context, p);
253178825Sdfr	   }
254178825Sdfr       }
25572445Sassar       krb5_cc_close(context, ccache);
256178825Sdfr       gss_release_cred(&min_stat, &delegated_cred_handle);
25772445Sassar    }
25872445Sassar
25957419Smarkm    if (fork_flag) {
26057419Smarkm	pid_t pid;
26157419Smarkm	int pipefd[2];
26255682Smarkm
26357419Smarkm	if (pipe (pipefd) < 0)
26457419Smarkm	    err (1, "pipe");
26555682Smarkm
26657419Smarkm	pid = fork ();
26757419Smarkm	if (pid < 0)
26857419Smarkm	    err (1, "fork");
26957419Smarkm	if (pid != 0) {
27057419Smarkm	    gss_buffer_desc buf;
27155682Smarkm
27257419Smarkm	    maj_stat = gss_export_sec_context (&min_stat,
27357419Smarkm					       &context_hdl,
27457419Smarkm					       &buf);
27557419Smarkm	    if (GSS_ERROR(maj_stat))
27657419Smarkm		gss_err (1, min_stat, "gss_export_sec_context");
27757419Smarkm	    write_token (pipefd[1], &buf);
27857419Smarkm	    exit (0);
27957419Smarkm	} else {
28057419Smarkm	    gss_ctx_id_t context_hdl;
28157419Smarkm	    gss_buffer_desc buf;
28255682Smarkm
28357419Smarkm	    close (pipefd[1]);
28457419Smarkm	    read_token (pipefd[0], &buf);
28557419Smarkm	    close (pipefd[0]);
28657419Smarkm	    maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
28757419Smarkm	    if (GSS_ERROR(maj_stat))
28857419Smarkm		gss_err (1, min_stat, "gss_import_sec_context");
28957419Smarkm	    gss_release_buffer (&min_stat, &buf);
29057419Smarkm	    return process_it (sock, context_hdl, client_name);
29157419Smarkm	}
29257419Smarkm    } else {
29357419Smarkm	return process_it (sock, context_hdl, client_name);
29457419Smarkm    }
29555682Smarkm}
29655682Smarkm
29755682Smarkmstatic int
29855682Smarkmdoit (int port, const char *service)
29955682Smarkm{
30055682Smarkm    int sock, sock2;
30155682Smarkm    struct sockaddr_in my_addr;
30255682Smarkm    int one = 1;
303233294Sstas    int ret;
30455682Smarkm
30555682Smarkm    sock = socket (AF_INET, SOCK_STREAM, 0);
30655682Smarkm    if (sock < 0)
30755682Smarkm	err (1, "socket");
30855682Smarkm
30955682Smarkm    memset (&my_addr, 0, sizeof(my_addr));
31055682Smarkm    my_addr.sin_family      = AF_INET;
31155682Smarkm    my_addr.sin_port        = port;
31255682Smarkm    my_addr.sin_addr.s_addr = INADDR_ANY;
31355682Smarkm
31455682Smarkm    if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
31555682Smarkm		    (void *)&one, sizeof(one)) < 0)
31655682Smarkm	warn ("setsockopt SO_REUSEADDR");
31755682Smarkm
31855682Smarkm    if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
31955682Smarkm	err (1, "bind");
32055682Smarkm
321233294Sstas    while (1) {
322233294Sstas        if (listen (sock, 1) < 0)
323233294Sstas	    err (1, "listen");
32455682Smarkm
325233294Sstas        sock2 = accept (sock, NULL, NULL);
326233294Sstas        if (sock2 < 0)
327233294Sstas	    err (1, "accept");
32855682Smarkm
329233294Sstas        ret = proto (sock2, service);
330233294Sstas    }
331233294Sstas    return ret;
33255682Smarkm}
33355682Smarkm
33455682Smarkmint
33555682Smarkmmain(int argc, char **argv)
33655682Smarkm{
33755682Smarkm    krb5_context context = NULL; /* XXX */
33855682Smarkm    int port = server_setup(&context, argc, argv);
33955682Smarkm    return doit (port, service);
34055682Smarkm}
341233294Sstas
342