155682Smarkm/*
257419Smarkm * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan
355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden).
455682Smarkm * All rights reserved.
555682Smarkm *
655682Smarkm * Redistribution and use in source and binary forms, with or without
755682Smarkm * modification, are permitted provided that the following conditions
855682Smarkm * are met:
955682Smarkm *
1055682Smarkm * 1. Redistributions of source code must retain the above copyright
1155682Smarkm *    notice, this list of conditions and the following disclaimer.
1255682Smarkm *
1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright
1455682Smarkm *    notice, this list of conditions and the following disclaimer in the
1555682Smarkm *    documentation and/or other materials provided with the distribution.
1655682Smarkm *
1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors
1855682Smarkm *    may be used to endorse or promote products derived from this software
1955682Smarkm *    without specific prior written permission.
2055682Smarkm *
2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2455682Smarkm * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3155682Smarkm * SUCH DAMAGE.
3255682Smarkm */
3355682Smarkm
3455682Smarkm#include "test_locl.h"
3555682Smarkm#include <gssapi.h>
3655682Smarkm#include "gss_common.h"
37178825SdfrRCSID("$Id: gssapi_server.c 14762 2005-04-10 14:47:41Z lha $");
3855682Smarkm
3955682Smarkmstatic int
4057419Smarkmprocess_it(int sock,
4157419Smarkm	   gss_ctx_id_t context_hdl,
4257419Smarkm	   gss_name_t client_name
4357419Smarkm	   )
4457419Smarkm{
4557419Smarkm    OM_uint32 maj_stat, min_stat;
4657419Smarkm    gss_buffer_desc real_input_token, real_output_token;
4757419Smarkm    gss_buffer_t input_token = &real_input_token,
4857419Smarkm	output_token = &real_output_token;
49178825Sdfr    gss_name_t server_name;
50178825Sdfr    int conf_flag;
5157419Smarkm
52178825Sdfr    print_gss_name("User is", client_name);
53178825Sdfr
54178825Sdfr    maj_stat = gss_inquire_context(&min_stat,
55178825Sdfr				   context_hdl,
56178825Sdfr				   NULL,
57178825Sdfr				   &server_name,
58178825Sdfr				   NULL,
59178825Sdfr				   NULL,
60178825Sdfr				   NULL,
61178825Sdfr				   NULL,
62178825Sdfr				   NULL);
6357419Smarkm    if (GSS_ERROR(maj_stat))
64178825Sdfr	gss_err (1, min_stat, "gss_inquire_context");
6557419Smarkm
66178825Sdfr    print_gss_name("Server is", server_name);
6757419Smarkm
68178825Sdfr    maj_stat = gss_release_name(&min_stat, &server_name);
69178825Sdfr    if (GSS_ERROR(maj_stat))
70178825Sdfr	gss_err (1, min_stat, "gss_release_name");
7157419Smarkm
7257419Smarkm    /* gss_verify_mic */
7357419Smarkm
7457419Smarkm    read_token (sock, input_token);
7557419Smarkm    read_token (sock, output_token);
7657419Smarkm
7757419Smarkm    maj_stat = gss_verify_mic (&min_stat,
7857419Smarkm			       context_hdl,
7957419Smarkm			       input_token,
8057419Smarkm			       output_token,
8157419Smarkm			       NULL);
8257419Smarkm    if (GSS_ERROR(maj_stat))
8357419Smarkm	gss_err (1, min_stat, "gss_verify_mic");
8457419Smarkm
8557419Smarkm    fprintf (stderr, "gss_verify_mic: %.*s\n", (int)input_token->length,
8657419Smarkm	    (char *)input_token->value);
8757419Smarkm
8857419Smarkm    gss_release_buffer (&min_stat, input_token);
8957419Smarkm    gss_release_buffer (&min_stat, output_token);
9057419Smarkm
9157419Smarkm    /* gss_unwrap */
9257419Smarkm
9357419Smarkm    read_token (sock, input_token);
9457419Smarkm
9557419Smarkm    maj_stat = gss_unwrap (&min_stat,
9657419Smarkm			   context_hdl,
9757419Smarkm			   input_token,
9857419Smarkm			   output_token,
99178825Sdfr			   &conf_flag,
10057419Smarkm			   NULL);
10157419Smarkm    if(GSS_ERROR(maj_stat))
10257419Smarkm	gss_err (1, min_stat, "gss_unwrap");
10357419Smarkm
104178825Sdfr    fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
105178825Sdfr	    (char *)output_token->value,
106178825Sdfr	     conf_flag ? "CONF" : "INT");
10757419Smarkm
10857419Smarkm    gss_release_buffer (&min_stat, input_token);
10957419Smarkm    gss_release_buffer (&min_stat, output_token);
11057419Smarkm
111178825Sdfr    read_token (sock, input_token);
112178825Sdfr
113178825Sdfr    maj_stat = gss_unwrap (&min_stat,
114178825Sdfr			   context_hdl,
115178825Sdfr			   input_token,
116178825Sdfr			   output_token,
117178825Sdfr			   &conf_flag,
118178825Sdfr			   NULL);
119178825Sdfr    if(GSS_ERROR(maj_stat))
120178825Sdfr	gss_err (1, min_stat, "gss_unwrap");
121178825Sdfr
122178825Sdfr    fprintf (stderr, "gss_unwrap: %.*s %s\n", (int)output_token->length,
123178825Sdfr	     (char *)output_token->value,
124178825Sdfr	     conf_flag ? "CONF" : "INT");
125178825Sdfr
126178825Sdfr    gss_release_buffer (&min_stat, input_token);
127178825Sdfr    gss_release_buffer (&min_stat, output_token);
128178825Sdfr
12957419Smarkm    return 0;
13057419Smarkm}
13157419Smarkm
13257419Smarkmstatic int
13355682Smarkmproto (int sock, const char *service)
13455682Smarkm{
13555682Smarkm    struct sockaddr_in remote, local;
13672445Sassar    socklen_t addrlen;
13755682Smarkm    gss_ctx_id_t context_hdl = GSS_C_NO_CONTEXT;
13855682Smarkm    gss_buffer_desc real_input_token, real_output_token;
13957419Smarkm    gss_buffer_t input_token = &real_input_token,
14057419Smarkm	output_token = &real_output_token;
14155682Smarkm    OM_uint32 maj_stat, min_stat;
14255682Smarkm    gss_name_t client_name;
14372445Sassar    struct gss_channel_bindings_struct input_chan_bindings;
14472445Sassar    gss_cred_id_t delegated_cred_handle = NULL;
14572445Sassar    krb5_ccache ccache;
14672445Sassar    u_char init_buf[4];
14772445Sassar    u_char acct_buf[4];
148178825Sdfr    gss_OID mech_oid;
149178825Sdfr    char *mech, *p;
15055682Smarkm
15155682Smarkm    addrlen = sizeof(local);
15255682Smarkm    if (getsockname (sock, (struct sockaddr *)&local, &addrlen) < 0
15355682Smarkm	|| addrlen != sizeof(local))
15455682Smarkm	err (1, "getsockname)");
15555682Smarkm
15655682Smarkm    addrlen = sizeof(remote);
15755682Smarkm    if (getpeername (sock, (struct sockaddr *)&remote, &addrlen) < 0
15855682Smarkm	|| addrlen != sizeof(remote))
15955682Smarkm	err (1, "getpeername");
16055682Smarkm
16172445Sassar    input_chan_bindings.initiator_addrtype = GSS_C_AF_INET;
16272445Sassar    input_chan_bindings.initiator_address.length = 4;
16372445Sassar    init_buf[0] = (remote.sin_addr.s_addr >> 24) & 0xFF;
16472445Sassar    init_buf[1] = (remote.sin_addr.s_addr >> 16) & 0xFF;
16572445Sassar    init_buf[2] = (remote.sin_addr.s_addr >>  8) & 0xFF;
16672445Sassar    init_buf[3] = (remote.sin_addr.s_addr >>  0) & 0xFF;
16772445Sassar
16872445Sassar    input_chan_bindings.initiator_address.value = init_buf;
16972445Sassar    input_chan_bindings.acceptor_addrtype = GSS_C_AF_INET;
17072445Sassar
17172445Sassar    input_chan_bindings.acceptor_address.length = 4;
17272445Sassar    acct_buf[0] = (local.sin_addr.s_addr >> 24) & 0xFF;
17372445Sassar    acct_buf[1] = (local.sin_addr.s_addr >> 16) & 0xFF;
17472445Sassar    acct_buf[2] = (local.sin_addr.s_addr >>  8) & 0xFF;
17572445Sassar    acct_buf[3] = (local.sin_addr.s_addr >>  0) & 0xFF;
17672445Sassar    input_chan_bindings.acceptor_address.value = acct_buf;
17772445Sassar    input_chan_bindings.application_data.value = emalloc(4);
17872445Sassar#if 0
17972445Sassar    * (unsigned short *)input_chan_bindings.application_data.value =
18072445Sassar                          remote.sin_port;
18172445Sassar    * ((unsigned short *)input_chan_bindings.application_data.value + 1) =
18272445Sassar                          local.sin_port;
18372445Sassar    input_chan_bindings.application_data.length = 4;
18472445Sassar#else
18572445Sassar    input_chan_bindings.application_data.length = 0;
18672445Sassar    input_chan_bindings.application_data.value = NULL;
18772445Sassar#endif
18872445Sassar
189178825Sdfr    delegated_cred_handle = GSS_C_NO_CREDENTIAL;
19072445Sassar
19155682Smarkm    do {
19255682Smarkm	read_token (sock, input_token);
19355682Smarkm	maj_stat =
19455682Smarkm	    gss_accept_sec_context (&min_stat,
19555682Smarkm				    &context_hdl,
19655682Smarkm				    GSS_C_NO_CREDENTIAL,
19755682Smarkm				    input_token,
19872445Sassar				    &input_chan_bindings,
19955682Smarkm				    &client_name,
200178825Sdfr				    &mech_oid,
20155682Smarkm				    output_token,
20255682Smarkm				    NULL,
20355682Smarkm				    NULL,
204178825Sdfr				    &delegated_cred_handle);
20555682Smarkm	if(GSS_ERROR(maj_stat))
20655682Smarkm	    gss_err (1, min_stat, "gss_accept_sec_context");
20755682Smarkm	if (output_token->length != 0)
20855682Smarkm	    write_token (sock, output_token);
20955682Smarkm	if (GSS_ERROR(maj_stat)) {
21055682Smarkm	    if (context_hdl != GSS_C_NO_CONTEXT)
21155682Smarkm		gss_delete_sec_context (&min_stat,
21255682Smarkm					&context_hdl,
21355682Smarkm					GSS_C_NO_BUFFER);
21455682Smarkm	    break;
21555682Smarkm	}
21655682Smarkm    } while(maj_stat & GSS_S_CONTINUE_NEEDED);
21772445Sassar
218178825Sdfr    p = (char *)mech_oid->elements;
219178825Sdfr    if (mech_oid->length == GSS_KRB5_MECHANISM->length
220178825Sdfr	&& memcmp(p, GSS_KRB5_MECHANISM->elements, mech_oid->length) == 0)
221178825Sdfr	mech = "Kerberos 5";
222178825Sdfr    else if (mech_oid->length == GSS_SPNEGO_MECHANISM->length
223178825Sdfr	&& memcmp(p, GSS_SPNEGO_MECHANISM->elements, mech_oid->length) == 0)
224178825Sdfr	mech = "SPNEGO"; /* XXX Silly, wont show up */
225178825Sdfr    else
226178825Sdfr	mech = "Unknown";
227178825Sdfr
228178825Sdfr    printf("Using mech: %s\n", mech);
229178825Sdfr
230178825Sdfr    if (delegated_cred_handle != GSS_C_NO_CREDENTIAL) {
23172445Sassar       krb5_context context;
23255682Smarkm
233178825Sdfr       printf("Delegated cred found\n");
234178825Sdfr
23572445Sassar       maj_stat = krb5_init_context(&context);
23672445Sassar       maj_stat = krb5_cc_resolve(context, "FILE:/tmp/krb5cc_test", &ccache);
237178825Sdfr       maj_stat = gss_krb5_copy_ccache(&min_stat,
238178825Sdfr				       delegated_cred_handle,
239178825Sdfr				       ccache);
240178825Sdfr       if (maj_stat == 0) {
241178825Sdfr	   krb5_principal p;
242178825Sdfr	   maj_stat = krb5_cc_get_principal(context, ccache, &p);
243178825Sdfr	   if (maj_stat == 0) {
244178825Sdfr	       char *name;
245178825Sdfr	       maj_stat = krb5_unparse_name(context, p, &name);
246178825Sdfr	       if (maj_stat == 0) {
247178825Sdfr		   printf("Delegated user is: `%s'\n", name);
248178825Sdfr		   free(name);
249178825Sdfr	       }
250178825Sdfr	       krb5_free_principal(context, p);
251178825Sdfr	   }
252178825Sdfr       }
25372445Sassar       krb5_cc_close(context, ccache);
254178825Sdfr       gss_release_cred(&min_stat, &delegated_cred_handle);
25572445Sassar    }
25672445Sassar
25757419Smarkm    if (fork_flag) {
25857419Smarkm	pid_t pid;
25957419Smarkm	int pipefd[2];
26055682Smarkm
26157419Smarkm	if (pipe (pipefd) < 0)
26257419Smarkm	    err (1, "pipe");
26355682Smarkm
26457419Smarkm	pid = fork ();
26557419Smarkm	if (pid < 0)
26657419Smarkm	    err (1, "fork");
26757419Smarkm	if (pid != 0) {
26857419Smarkm	    gss_buffer_desc buf;
26955682Smarkm
27057419Smarkm	    maj_stat = gss_export_sec_context (&min_stat,
27157419Smarkm					       &context_hdl,
27257419Smarkm					       &buf);
27357419Smarkm	    if (GSS_ERROR(maj_stat))
27457419Smarkm		gss_err (1, min_stat, "gss_export_sec_context");
27557419Smarkm	    write_token (pipefd[1], &buf);
27657419Smarkm	    exit (0);
27757419Smarkm	} else {
27857419Smarkm	    gss_ctx_id_t context_hdl;
27957419Smarkm	    gss_buffer_desc buf;
28055682Smarkm
28157419Smarkm	    close (pipefd[1]);
28257419Smarkm	    read_token (pipefd[0], &buf);
28357419Smarkm	    close (pipefd[0]);
28457419Smarkm	    maj_stat = gss_import_sec_context (&min_stat, &buf, &context_hdl);
28557419Smarkm	    if (GSS_ERROR(maj_stat))
28657419Smarkm		gss_err (1, min_stat, "gss_import_sec_context");
28757419Smarkm	    gss_release_buffer (&min_stat, &buf);
28857419Smarkm	    return process_it (sock, context_hdl, client_name);
28957419Smarkm	}
29057419Smarkm    } else {
29157419Smarkm	return process_it (sock, context_hdl, client_name);
29257419Smarkm    }
29355682Smarkm}
29455682Smarkm
29555682Smarkmstatic int
29655682Smarkmdoit (int port, const char *service)
29755682Smarkm{
29855682Smarkm    int sock, sock2;
29955682Smarkm    struct sockaddr_in my_addr;
30055682Smarkm    int one = 1;
30155682Smarkm
30255682Smarkm    sock = socket (AF_INET, SOCK_STREAM, 0);
30355682Smarkm    if (sock < 0)
30455682Smarkm	err (1, "socket");
30555682Smarkm
30655682Smarkm    memset (&my_addr, 0, sizeof(my_addr));
30755682Smarkm    my_addr.sin_family      = AF_INET;
30855682Smarkm    my_addr.sin_port        = port;
30955682Smarkm    my_addr.sin_addr.s_addr = INADDR_ANY;
31055682Smarkm
31155682Smarkm    if (setsockopt (sock, SOL_SOCKET, SO_REUSEADDR,
31255682Smarkm		    (void *)&one, sizeof(one)) < 0)
31355682Smarkm	warn ("setsockopt SO_REUSEADDR");
31455682Smarkm
31555682Smarkm    if (bind (sock, (struct sockaddr *)&my_addr, sizeof(my_addr)) < 0)
31655682Smarkm	err (1, "bind");
31755682Smarkm
31855682Smarkm    if (listen (sock, 1) < 0)
31955682Smarkm	err (1, "listen");
32055682Smarkm
32155682Smarkm    sock2 = accept (sock, NULL, NULL);
32255682Smarkm    if (sock2 < 0)
32355682Smarkm	err (1, "accept");
32455682Smarkm
32555682Smarkm    return proto (sock2, service);
32655682Smarkm}
32755682Smarkm
32855682Smarkmint
32955682Smarkmmain(int argc, char **argv)
33055682Smarkm{
33155682Smarkm    krb5_context context = NULL; /* XXX */
33255682Smarkm    int port = server_setup(&context, argc, argv);
33355682Smarkm    return doit (port, service);
33455682Smarkm}
335