155682Smarkm/*
2178825Sdfr * Copyright (c) 1997 - 2006 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 "krb5_locl.h"
3555682Smarkm
36178825SdfrRCSID("$Id: sendauth.c 17442 2006-05-05 09:31:15Z lha $");
3755682Smarkm
3855682Smarkm/*
3955682Smarkm * The format seems to be:
4055682Smarkm * client -> server
4155682Smarkm *
4255682Smarkm * 4 bytes - length
4355682Smarkm * KRB5_SENDAUTH_V1.0 (including zero)
4455682Smarkm * 4 bytes - length
4555682Smarkm * protocol string (with terminating zero)
4655682Smarkm *
4755682Smarkm * server -> client
4855682Smarkm * 1 byte - (0 = OK, else some kind of error)
4955682Smarkm *
5055682Smarkm * client -> server
5155682Smarkm * 4 bytes - length
5255682Smarkm * AP-REQ
5355682Smarkm *
5455682Smarkm * server -> client
5555682Smarkm * 4 bytes - length (0 = OK, else length of error)
5655682Smarkm * (error)
5755682Smarkm *
5855682Smarkm * if(mutual) {
5955682Smarkm * server -> client
6055682Smarkm * 4 bytes - length
6155682Smarkm * AP-REP
6255682Smarkm * }
6355682Smarkm */
6455682Smarkm
65178825Sdfrkrb5_error_code KRB5_LIB_FUNCTION
6655682Smarkmkrb5_sendauth(krb5_context context,
6755682Smarkm	      krb5_auth_context *auth_context,
6855682Smarkm	      krb5_pointer p_fd,
6955682Smarkm	      const char *appl_version,
7055682Smarkm	      krb5_principal client,
7155682Smarkm	      krb5_principal server,
7255682Smarkm	      krb5_flags ap_req_options,
7355682Smarkm	      krb5_data *in_data,
7455682Smarkm	      krb5_creds *in_creds,
7555682Smarkm	      krb5_ccache ccache,
7655682Smarkm	      krb5_error **ret_error,
7755682Smarkm	      krb5_ap_rep_enc_part **rep_result,
7855682Smarkm	      krb5_creds **out_creds)
7955682Smarkm{
8055682Smarkm    krb5_error_code ret;
81178825Sdfr    uint32_t len, net_len;
8255682Smarkm    const char *version = KRB5_SENDAUTH_VERSION;
8355682Smarkm    u_char repl;
8455682Smarkm    krb5_data ap_req, error_data;
8555682Smarkm    krb5_creds this_cred;
8655682Smarkm    krb5_principal this_client = NULL;
8755682Smarkm    krb5_creds *creds;
8855682Smarkm    ssize_t sret;
89103423Snectar    krb5_boolean my_ccache = FALSE;
9055682Smarkm
9155682Smarkm    len = strlen(version) + 1;
9255682Smarkm    net_len = htonl(len);
9355682Smarkm    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
9478527Sassar	|| krb5_net_write (context, p_fd, version, len) != len) {
9578527Sassar	ret = errno;
9678527Sassar	krb5_set_error_string (context, "write: %s", strerror(ret));
9778527Sassar	return ret;
9878527Sassar    }
9955682Smarkm
10055682Smarkm    len = strlen(appl_version) + 1;
10155682Smarkm    net_len = htonl(len);
10255682Smarkm    if (krb5_net_write (context, p_fd, &net_len, 4) != 4
10378527Sassar	|| krb5_net_write (context, p_fd, appl_version, len) != len) {
10478527Sassar	ret = errno;
10578527Sassar	krb5_set_error_string (context, "write: %s", strerror(ret));
10678527Sassar	return ret;
10778527Sassar    }
10855682Smarkm
10955682Smarkm    sret = krb5_net_read (context, p_fd, &repl, sizeof(repl));
11078527Sassar    if (sret < 0) {
11178527Sassar	ret = errno;
11278527Sassar	krb5_set_error_string (context, "read: %s", strerror(ret));
11378527Sassar	return ret;
11478527Sassar    } else if (sret != sizeof(repl)) {
11578527Sassar	krb5_clear_error_string (context);
11655682Smarkm	return KRB5_SENDAUTH_BADRESPONSE;
11778527Sassar    }
11855682Smarkm
11978527Sassar    if (repl != 0) {
12078527Sassar	krb5_clear_error_string (context);
12155682Smarkm	return KRB5_SENDAUTH_REJECTED;
12278527Sassar    }
12355682Smarkm
12455682Smarkm    if (in_creds == NULL) {
12555682Smarkm	if (ccache == NULL) {
12655682Smarkm	    ret = krb5_cc_default (context, &ccache);
12755682Smarkm	    if (ret)
12855682Smarkm		return ret;
129103423Snectar	    my_ccache = TRUE;
13055682Smarkm	}
13155682Smarkm
13255682Smarkm	if (client == NULL) {
13355682Smarkm	    ret = krb5_cc_get_principal (context, ccache, &this_client);
134103423Snectar	    if (ret) {
135103423Snectar		if(my_ccache)
136103423Snectar		    krb5_cc_close(context, ccache);
13755682Smarkm		return ret;
138103423Snectar	    }
13955682Smarkm	    client = this_client;
14055682Smarkm	}
14155682Smarkm	memset(&this_cred, 0, sizeof(this_cred));
14255682Smarkm	this_cred.client = client;
14355682Smarkm	this_cred.server = server;
14455682Smarkm	this_cred.times.endtime = 0;
14555682Smarkm	this_cred.ticket.length = 0;
14655682Smarkm	in_creds = &this_cred;
14755682Smarkm    }
14855682Smarkm    if (in_creds->ticket.length == 0) {
14955682Smarkm	ret = krb5_get_credentials (context, 0, ccache, in_creds, &creds);
150103423Snectar	if (ret) {
151103423Snectar	    if(my_ccache)
152103423Snectar		krb5_cc_close(context, ccache);
15355682Smarkm	    return ret;
154103423Snectar	}
15555682Smarkm    } else {
15655682Smarkm	creds = in_creds;
15755682Smarkm    }
158103423Snectar    if(my_ccache)
159103423Snectar	krb5_cc_close(context, ccache);
16055682Smarkm    ret = krb5_mk_req_extended (context,
16155682Smarkm				auth_context,
16255682Smarkm				ap_req_options,
16355682Smarkm				in_data,
16455682Smarkm				creds,
16555682Smarkm				&ap_req);
16655682Smarkm
16755682Smarkm    if (out_creds)
16855682Smarkm	*out_creds = creds;
16955682Smarkm    else
17055682Smarkm	krb5_free_creds(context, creds);
17155682Smarkm    if(this_client)
17255682Smarkm	krb5_free_principal(context, this_client);
17355682Smarkm
17455682Smarkm    if (ret)
17555682Smarkm	return ret;
17655682Smarkm
17755682Smarkm    ret = krb5_write_message (context,
17855682Smarkm			      p_fd,
17955682Smarkm			      &ap_req);
18055682Smarkm    if (ret)
18155682Smarkm	return ret;
18255682Smarkm
18355682Smarkm    krb5_data_free (&ap_req);
18455682Smarkm
18555682Smarkm    ret = krb5_read_message (context, p_fd, &error_data);
18655682Smarkm    if (ret)
18755682Smarkm	return ret;
18855682Smarkm
18955682Smarkm    if (error_data.length != 0) {
19055682Smarkm	KRB_ERROR error;
19155682Smarkm
19255682Smarkm	ret = krb5_rd_error (context, &error_data, &error);
19355682Smarkm	krb5_data_free (&error_data);
19455682Smarkm	if (ret == 0) {
19578527Sassar	    ret = krb5_error_from_rd_error(context, &error, NULL);
19655682Smarkm	    if (ret_error != NULL) {
19755682Smarkm		*ret_error = malloc (sizeof(krb5_error));
19855682Smarkm		if (*ret_error == NULL) {
19978527Sassar		    krb5_free_error_contents (context, &error);
20055682Smarkm		} else {
20155682Smarkm		    **ret_error = error;
20255682Smarkm		}
20355682Smarkm	    } else {
20478527Sassar		krb5_free_error_contents (context, &error);
20555682Smarkm	    }
20655682Smarkm	    return ret;
20778527Sassar	} else {
20878527Sassar	    krb5_clear_error_string(context);
20978527Sassar	    return ret;
21078527Sassar	}
21155682Smarkm    }
21255682Smarkm
21355682Smarkm    if (ap_req_options & AP_OPTS_MUTUAL_REQUIRED) {
21455682Smarkm	krb5_data ap_rep;
21555682Smarkm	krb5_ap_rep_enc_part *ignore;
21655682Smarkm
21755682Smarkm	krb5_data_zero (&ap_rep);
21855682Smarkm	ret = krb5_read_message (context,
21955682Smarkm				 p_fd,
22055682Smarkm				 &ap_rep);
22155682Smarkm	if (ret)
22255682Smarkm	    return ret;
22355682Smarkm
22455682Smarkm	ret = krb5_rd_rep (context, *auth_context, &ap_rep,
22555682Smarkm			   rep_result ? rep_result : &ignore);
226178825Sdfr	krb5_data_free (&ap_rep);
22755682Smarkm	if (ret)
22855682Smarkm	    return ret;
22955682Smarkm	if (rep_result == NULL)
23055682Smarkm	    krb5_free_ap_rep_enc_part (context, ignore);
23155682Smarkm    }
23255682Smarkm    return 0;
23355682Smarkm}
234