17c478bd9Sstevel@tonic-gate /*
25e01956fSGlenn Barry  * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
37c478bd9Sstevel@tonic-gate  */
47c478bd9Sstevel@tonic-gate /*
5ab9b2e15Sgtb  * Copyright 2000,2002, 2003 by the Massachusetts Institute of Technology.
67c478bd9Sstevel@tonic-gate  * All Rights Reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
97c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
107c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
117c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
12ab9b2e15Sgtb  *
137c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
147c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
157c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
167c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
177c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
187c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
197c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
207c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
217c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
227c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
237c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
247c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
257c478bd9Sstevel@tonic-gate  * or implied warranty.
26ab9b2e15Sgtb  *
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
30ab9b2e15Sgtb  *
317c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
327c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
337c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
347c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
357c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
367c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
377c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
387c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
397c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
40ab9b2e15Sgtb  *
417c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
427c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
437c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
447c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
457c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
467c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
477c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
487c478bd9Sstevel@tonic-gate  */
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate /*
517c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
52ab9b2e15Sgtb  *
537c478bd9Sstevel@tonic-gate  * All rights reserved.
54ab9b2e15Sgtb  *
557c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
567c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
577c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
587c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
59ab9b2e15Sgtb  *
607c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
617c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
627c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
637c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
647c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
657c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
667c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
677c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
687c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
697c478bd9Sstevel@tonic-gate  * or implied warranty.
70ab9b2e15Sgtb  *
717c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
727c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
737c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
747c478bd9Sstevel@tonic-gate  */
757c478bd9Sstevel@tonic-gate 
76db02be57S /* Solaris Kerberos */
77db02be57S #include <libintl.h>
78db02be57S #include <locale.h>
79db02be57S 
80ab9b2e15Sgtb #include "k5-int.h"
81ab9b2e15Sgtb #include "gss_libinit.h"
82159d09a2SMark Phalan #include "gssapiP_krb5.h"
83ab9b2e15Sgtb #include "mglueP.h"
84ab9b2e15Sgtb #ifdef HAVE_MEMORY_H
857c478bd9Sstevel@tonic-gate #include <memory.h>
86ab9b2e15Sgtb #endif
877c478bd9Sstevel@tonic-gate #include <stdlib.h>
887c478bd9Sstevel@tonic-gate #include <assert.h>
897c478bd9Sstevel@tonic-gate 
90ab9b2e15Sgtb /* Solaris Kerberos start */
91ab9b2e15Sgtb static OM_uint32 get_default_cred(OM_uint32 *, void *, gss_cred_id_t *);
92ab9b2e15Sgtb /* Solaris Kerberos end */
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
95159d09a2SMark Phalan  * $Id: init_sec_context.c 18721 2006-10-16 16:18:29Z epeisach $
967c478bd9Sstevel@tonic-gate  */
97ab9b2e15Sgtb 
98ab9b2e15Sgtb /* XXX This is for debugging only!!!  Should become a real bitfield
99ab9b2e15Sgtb    at some point */
1007c478bd9Sstevel@tonic-gate int krb5_gss_dbg_client_expcreds = 0;
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate /*
1037c478bd9Sstevel@tonic-gate  * Common code which fetches the correct krb5 credentials from the
1047c478bd9Sstevel@tonic-gate  * ccache.
1057c478bd9Sstevel@tonic-gate  */
get_credentials(context,cred,server,now,endtime,out_creds)1067c478bd9Sstevel@tonic-gate static krb5_error_code get_credentials(context, cred, server, now,
1077c478bd9Sstevel@tonic-gate 				       endtime, out_creds)
1087c478bd9Sstevel@tonic-gate     krb5_context context;
1097c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
1107c478bd9Sstevel@tonic-gate     krb5_principal server;
1117c478bd9Sstevel@tonic-gate     krb5_timestamp now;
1127c478bd9Sstevel@tonic-gate     krb5_timestamp endtime;
1137c478bd9Sstevel@tonic-gate     krb5_creds **out_creds;
1147c478bd9Sstevel@tonic-gate {
1157c478bd9Sstevel@tonic-gate     krb5_error_code	code;
1167c478bd9Sstevel@tonic-gate     krb5_creds 		in_creds;
1177c478bd9Sstevel@tonic-gate 
118ab9b2e15Sgtb     k5_mutex_assert_locked(&cred->lock);
1197c478bd9Sstevel@tonic-gate     memset((char *) &in_creds, 0, sizeof(krb5_creds));
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
1227c478bd9Sstevel@tonic-gate 	goto cleanup;
1237c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, server, &in_creds.server)))
1247c478bd9Sstevel@tonic-gate 	goto cleanup;
1257c478bd9Sstevel@tonic-gate     in_creds.times.endtime = endtime;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate     in_creds.keyblock.enctype = 0;
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate     code = krb5_get_credentials(context, 0, cred->ccache,
1307c478bd9Sstevel@tonic-gate 				&in_creds, out_creds);
1317c478bd9Sstevel@tonic-gate     if (code)
1327c478bd9Sstevel@tonic-gate 	goto cleanup;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate     /*
1357c478bd9Sstevel@tonic-gate      * Enforce a stricter limit (without timeskew forgiveness at the
1367c478bd9Sstevel@tonic-gate      * boundaries) because accept_sec_context code is also similarly
1377c478bd9Sstevel@tonic-gate      * non-forgiving.
1387c478bd9Sstevel@tonic-gate      */
1397c478bd9Sstevel@tonic-gate     if (!krb5_gss_dbg_client_expcreds && *out_creds != NULL &&
1407c478bd9Sstevel@tonic-gate 	(*out_creds)->times.endtime < now) {
1417c478bd9Sstevel@tonic-gate 	code = KRB5KRB_AP_ERR_TKT_EXPIRED;
1427c478bd9Sstevel@tonic-gate 	goto cleanup;
1437c478bd9Sstevel@tonic-gate     }
144ab9b2e15Sgtb 
1457c478bd9Sstevel@tonic-gate cleanup:
1467c478bd9Sstevel@tonic-gate     if (in_creds.client)
1477c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.client);
1487c478bd9Sstevel@tonic-gate     if (in_creds.server)
1497c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.server);
1507c478bd9Sstevel@tonic-gate     return code;
1517c478bd9Sstevel@tonic-gate }
1527c478bd9Sstevel@tonic-gate struct gss_checksum_data {
1537c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
1547c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
1557c478bd9Sstevel@tonic-gate     krb5_checksum md5;
1567c478bd9Sstevel@tonic-gate     krb5_data checksum_data;
1577c478bd9Sstevel@tonic-gate };
1587c478bd9Sstevel@tonic-gate 
159ab9b2e15Sgtb #ifdef CFX_EXERCISE
160ab9b2e15Sgtb #include "../../krb5/krb/auth_con.h"
161ab9b2e15Sgtb #endif
1627c478bd9Sstevel@tonic-gate static krb5_error_code KRB5_CALLCONV
make_gss_checksum(krb5_context context,krb5_auth_context auth_context,void * cksum_data,krb5_data ** out)1637c478bd9Sstevel@tonic-gate make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
164ab9b2e15Sgtb 		   void *cksum_data, krb5_data **out)
1657c478bd9Sstevel@tonic-gate {
1667c478bd9Sstevel@tonic-gate     krb5_error_code code;
1677c478bd9Sstevel@tonic-gate     krb5_int32 con_flags;
1687c478bd9Sstevel@tonic-gate     unsigned char *ptr;
1697c478bd9Sstevel@tonic-gate     struct gss_checksum_data *data = cksum_data;
1707c478bd9Sstevel@tonic-gate     krb5_data credmsg;
171ab9b2e15Sgtb     unsigned int junk;
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate     data->checksum_data.data = 0;
1747c478bd9Sstevel@tonic-gate     credmsg.data = 0;
1757c478bd9Sstevel@tonic-gate     /* build the checksum field */
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate     if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
1787c478bd9Sstevel@tonic-gate 	/* first get KRB_CRED message, so we know its length */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* clear the time check flag that was set in krb5_auth_con_init() */
1817c478bd9Sstevel@tonic-gate 	krb5_auth_con_getflags(context, auth_context, &con_flags);
1827c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context,
183ab9b2e15Sgtb 			       con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	code = krb5_fwd_tgt_creds(context, auth_context, 0,
186ab9b2e15Sgtb 				  data->cred->princ, data->ctx->there,
187ab9b2e15Sgtb 				  data->cred->ccache, 1,
188ab9b2e15Sgtb 				  &credmsg);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate 	/* turn KRB5_AUTH_CONTEXT_DO_TIME back on */
1917c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context, con_flags);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	if (code) {
1947c478bd9Sstevel@tonic-gate 	    /* don't fail here; just don't accept/do the delegation
195ab9b2e15Sgtb                request */
1967c478bd9Sstevel@tonic-gate 	    data->ctx->gss_flags &= ~GSS_C_DELEG_FLAG;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	    data->checksum_data.length = 24;
1997c478bd9Sstevel@tonic-gate 	} else {
2007c478bd9Sstevel@tonic-gate 	    if (credmsg.length+28 > KRB5_INT16_MAX) {
2017c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &credmsg);
2027c478bd9Sstevel@tonic-gate 		return(KRB5KRB_ERR_FIELD_TOOLONG);
203ab9b2e15Sgtb 	    }
2047c478bd9Sstevel@tonic-gate 
205ab9b2e15Sgtb 	    data->checksum_data.length = 28+credmsg.length;
2067c478bd9Sstevel@tonic-gate 	}
2077c478bd9Sstevel@tonic-gate     } else {
2087c478bd9Sstevel@tonic-gate 	data->checksum_data.length = 24;
2097c478bd9Sstevel@tonic-gate     }
2107c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
211ab9b2e15Sgtb     if (data->ctx->auth_context->keyblock != NULL
212ab9b2e15Sgtb 	&& data->ctx->auth_context->keyblock->enctype == 18) {
2137c478bd9Sstevel@tonic-gate 	srand(time(0) ^ getpid());
2147c478bd9Sstevel@tonic-gate 	/* Our ftp client code stupidly assumes a base64-encoded
2157c478bd9Sstevel@tonic-gate 	   version of the token will fit in 10K, so don't make this
2167c478bd9Sstevel@tonic-gate 	   too big.  */
2177c478bd9Sstevel@tonic-gate 	junk = rand() & 0xff;
2187c478bd9Sstevel@tonic-gate     } else
219ab9b2e15Sgtb 	junk = 0;
2207c478bd9Sstevel@tonic-gate #else
2217c478bd9Sstevel@tonic-gate     junk = 0;
2227c478bd9Sstevel@tonic-gate #endif
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate     data->checksum_data.length += junk;
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate     /* now allocate a buffer to hold the checksum data and
227ab9b2e15Sgtb        (maybe) KRB_CRED msg */
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate     if ((data->checksum_data.data =
2307c478bd9Sstevel@tonic-gate 	 (char *) xmalloc(data->checksum_data.length)) == NULL) {
2317c478bd9Sstevel@tonic-gate 	if (credmsg.data)
232ab9b2e15Sgtb 	    krb5_free_data_contents(context, &credmsg);
2337c478bd9Sstevel@tonic-gate 	return(ENOMEM);
2347c478bd9Sstevel@tonic-gate     }
235159d09a2SMark Phalan     /* Solaris Kerberos */
236ab9b2e15Sgtb     ptr = (uchar_t *)data->checksum_data.data; /* SUNW15resync */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->md5.length, 0);
2397c478bd9Sstevel@tonic-gate     TWRITE_STR(ptr, (unsigned char *) data->md5.contents, data->md5.length);
2407c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->ctx->gss_flags, 0);
2417c478bd9Sstevel@tonic-gate 
2427c478bd9Sstevel@tonic-gate     /* done with this, free it */
2437c478bd9Sstevel@tonic-gate     xfree(data->md5.contents);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate     if (credmsg.data) {
2467c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
2477c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, credmsg.length, 0);
2487c478bd9Sstevel@tonic-gate 	TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length);
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate 	/* free credmsg data */
2517c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &credmsg);
2527c478bd9Sstevel@tonic-gate     }
2537c478bd9Sstevel@tonic-gate     if (junk)
2547c478bd9Sstevel@tonic-gate 	memset(ptr, 'i', junk);
2557c478bd9Sstevel@tonic-gate     *out = &data->checksum_data;
2567c478bd9Sstevel@tonic-gate     return 0;
2577c478bd9Sstevel@tonic-gate }
258ab9b2e15Sgtb 
2597c478bd9Sstevel@tonic-gate static krb5_error_code
make_ap_req_v1(context,ctx,cred,k_cred,chan_bindings,mech_type,token)2607c478bd9Sstevel@tonic-gate make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token)
2617c478bd9Sstevel@tonic-gate     krb5_context context;
2627c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
2637c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
2647c478bd9Sstevel@tonic-gate     krb5_creds *k_cred;
2657c478bd9Sstevel@tonic-gate     gss_channel_bindings_t chan_bindings;
2667c478bd9Sstevel@tonic-gate     gss_OID mech_type;
2677c478bd9Sstevel@tonic-gate     gss_buffer_t token;
2687c478bd9Sstevel@tonic-gate {
2697c478bd9Sstevel@tonic-gate     krb5_flags mk_req_flags = 0;
2707c478bd9Sstevel@tonic-gate     krb5_error_code code;
2717c478bd9Sstevel@tonic-gate     struct gss_checksum_data cksum_struct;
2727c478bd9Sstevel@tonic-gate     krb5_checksum md5;
2737c478bd9Sstevel@tonic-gate     krb5_data ap_req;
2747c478bd9Sstevel@tonic-gate     krb5_data *checksum_data = NULL;
2757c478bd9Sstevel@tonic-gate     unsigned char *ptr;
2767c478bd9Sstevel@tonic-gate     unsigned char *t;
277ab9b2e15Sgtb     unsigned int tlen;
2787c478bd9Sstevel@tonic-gate 
279ab9b2e15Sgtb     k5_mutex_assert_locked(&cred->lock);
2807c478bd9Sstevel@tonic-gate     ap_req.data = 0;
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate     /* compute the hash of the channel bindings */
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate     if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
2857c478bd9Sstevel@tonic-gate         return(code);
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate     krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
2887c478bd9Sstevel@tonic-gate 				    CKSUMTYPE_KG_CB);
2897c478bd9Sstevel@tonic-gate     cksum_struct.md5 = md5;
2907c478bd9Sstevel@tonic-gate     cksum_struct.ctx = ctx;
2917c478bd9Sstevel@tonic-gate     cksum_struct.cred = cred;
2927c478bd9Sstevel@tonic-gate     cksum_struct.checksum_data.data = NULL;
2937c478bd9Sstevel@tonic-gate     switch (k_cred->keyblock.enctype) {
2947c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_CRC:
2957c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD4:
2967c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD5:
2977c478bd9Sstevel@tonic-gate     case ENCTYPE_DES3_CBC_SHA1:
298ab9b2e15Sgtb       code = make_gss_checksum(context, ctx->auth_context, &cksum_struct,
299ab9b2e15Sgtb 				 &checksum_data);
300ab9b2e15Sgtb 	    if (code)
3017c478bd9Sstevel@tonic-gate 		goto cleanup;
302ab9b2e15Sgtb 	break;
3037c478bd9Sstevel@tonic-gate     default:
3047c478bd9Sstevel@tonic-gate 	krb5_auth_con_set_checksum_func(context, ctx->auth_context,
305ab9b2e15Sgtb 					make_gss_checksum, &cksum_struct);
306ab9b2e15Sgtb 	    break;
3077c478bd9Sstevel@tonic-gate     }
3087c478bd9Sstevel@tonic-gate 
309ab9b2e15Sgtb 
3107c478bd9Sstevel@tonic-gate     /* call mk_req.  subkey and ap_req need to be used or destroyed */
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate     mk_req_flags = AP_OPTS_USE_SUBKEY;
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
3157c478bd9Sstevel@tonic-gate 	mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
3167c478bd9Sstevel@tonic-gate 
317ab9b2e15Sgtb     code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
318ab9b2e15Sgtb 				checksum_data, k_cred, &ap_req);
319ab9b2e15Sgtb     krb5_free_data_contents(context, &cksum_struct.checksum_data);
320ab9b2e15Sgtb     if (code)
3217c478bd9Sstevel@tonic-gate 	goto cleanup;
3227c478bd9Sstevel@tonic-gate 
3237c478bd9Sstevel@tonic-gate    /* store the interesting stuff from creds and authent */
3247c478bd9Sstevel@tonic-gate    ctx->endtime = k_cred->times.endtime;
3257c478bd9Sstevel@tonic-gate    ctx->krb_flags = k_cred->ticket_flags;
3267c478bd9Sstevel@tonic-gate 
3277c478bd9Sstevel@tonic-gate    /* build up the token */
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate    /* allocate space for the token */
3307c478bd9Sstevel@tonic-gate    tlen = g_token_size((gss_OID) mech_type, ap_req.length);
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate    if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
3337c478bd9Sstevel@tonic-gate       code = ENOMEM;
3347c478bd9Sstevel@tonic-gate       goto cleanup;
3357c478bd9Sstevel@tonic-gate    }
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate    /* fill in the buffer */
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate    ptr = t;
3407c478bd9Sstevel@tonic-gate 
341ab9b2e15Sgtb    g_make_token_header(mech_type, ap_req.length,
3427c478bd9Sstevel@tonic-gate 		       &ptr, KG_TOK_CTX_AP_REQ);
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate    TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length);
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate    /* pass it back */
3477c478bd9Sstevel@tonic-gate 
3487c478bd9Sstevel@tonic-gate    token->length = tlen;
3497c478bd9Sstevel@tonic-gate    token->value = (void *) t;
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate    code = 0;
352ab9b2e15Sgtb 
353ab9b2e15Sgtb  cleanup:
354ab9b2e15Sgtb    if (checksum_data && checksum_data->data)
355ab9b2e15Sgtb        krb5_free_data_contents(context, checksum_data);
3567c478bd9Sstevel@tonic-gate    if (ap_req.data)
357ab9b2e15Sgtb        krb5_free_data_contents(context, &ap_req);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate    return (code);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
362ab9b2e15Sgtb /*
363ab9b2e15Sgtb  * setup_enc
364ab9b2e15Sgtb  *
365ab9b2e15Sgtb  * Fill in the encryption descriptors.  Called after AP-REQ is made.
366ab9b2e15Sgtb  */
367ab9b2e15Sgtb static OM_uint32
setup_enc(OM_uint32 * minor_status,krb5_gss_ctx_id_rec * ctx,krb5_context context)368ab9b2e15Sgtb setup_enc(
369ab9b2e15Sgtb    OM_uint32 *minor_status,
370ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx,
371ab9b2e15Sgtb    krb5_context context)
372ab9b2e15Sgtb {
373ab9b2e15Sgtb    krb5_error_code code;
374ab9b2e15Sgtb    int i;
375ab9b2e15Sgtb    krb5int_access kaccess;
3767c478bd9Sstevel@tonic-gate 
377ab9b2e15Sgtb    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
378ab9b2e15Sgtb    if (code)
379ab9b2e15Sgtb        goto fail;
3807c478bd9Sstevel@tonic-gate 
381ab9b2e15Sgtb    ctx->have_acceptor_subkey = 0;
382ab9b2e15Sgtb    ctx->proto = 0;
383ab9b2e15Sgtb    ctx->cksumtype = 0;
384ab9b2e15Sgtb    switch(ctx->subkey->enctype) {
385ab9b2e15Sgtb    case ENCTYPE_DES_CBC_MD5:
386ab9b2e15Sgtb    case ENCTYPE_DES_CBC_MD4:
387ab9b2e15Sgtb    case ENCTYPE_DES_CBC_CRC:
388ab9b2e15Sgtb       ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
389ab9b2e15Sgtb       ctx->signalg = SGN_ALG_DES_MAC_MD5;
390ab9b2e15Sgtb       ctx->cksum_size = 8;
391ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_DES;
3927c478bd9Sstevel@tonic-gate 
393ab9b2e15Sgtb       /* The encryption key is the session key XOR
394ab9b2e15Sgtb 	 0xf0f0f0f0f0f0f0f0.  */
395ab9b2e15Sgtb       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc)))
396ab9b2e15Sgtb 	 goto fail;
3977c478bd9Sstevel@tonic-gate 
398ab9b2e15Sgtb       for (i=0; i<ctx->enc->length; i++)
399ab9b2e15Sgtb 	 ctx->enc->contents[i] ^= 0xf0;
4007c478bd9Sstevel@tonic-gate 
401ab9b2e15Sgtb       goto copy_subkey_to_seq;
4027c478bd9Sstevel@tonic-gate 
403ab9b2e15Sgtb    case ENCTYPE_DES3_CBC_SHA1:
404ab9b2e15Sgtb        /* MIT extension */
405ab9b2e15Sgtb       ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
406ab9b2e15Sgtb       ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
407ab9b2e15Sgtb       ctx->cksum_size = 20;
408ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_DES3KD;
409ab9b2e15Sgtb 
410ab9b2e15Sgtb    copy_subkey:
411ab9b2e15Sgtb       code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
412ab9b2e15Sgtb       if (code)
413ab9b2e15Sgtb 	 goto fail;
414ab9b2e15Sgtb    copy_subkey_to_seq:
415ab9b2e15Sgtb       code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
416ab9b2e15Sgtb       if (code) {
417ab9b2e15Sgtb 	 krb5_free_keyblock (context, ctx->enc);
418ab9b2e15Sgtb 	 goto fail;
419ab9b2e15Sgtb       }
420ab9b2e15Sgtb       goto success;
421ab9b2e15Sgtb 
422ab9b2e15Sgtb    case ENCTYPE_ARCFOUR_HMAC:
423ab9b2e15Sgtb        /* Microsoft extension */
424ab9b2e15Sgtb       ctx->signalg = SGN_ALG_HMAC_MD5 ;
425ab9b2e15Sgtb       ctx->cksum_size = 8;
426ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
427ab9b2e15Sgtb 
428ab9b2e15Sgtb       goto copy_subkey;
429ab9b2e15Sgtb 
430ab9b2e15Sgtb    default:
431ab9b2e15Sgtb        /* Fill some fields we shouldn't be using on this path
432ab9b2e15Sgtb 	  with garbage.  */
433ab9b2e15Sgtb        ctx->signalg = -10;
434ab9b2e15Sgtb        ctx->sealalg = -10;
435ab9b2e15Sgtb 
436ab9b2e15Sgtb        ctx->proto = 1;
437ab9b2e15Sgtb        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
438ab9b2e15Sgtb 					    &ctx->cksumtype);
439ab9b2e15Sgtb        if (code)
440ab9b2e15Sgtb 	   goto fail;
441ab9b2e15Sgtb        code = krb5_c_checksum_length(context, ctx->cksumtype,
442ab9b2e15Sgtb 				     &ctx->cksum_size);
443ab9b2e15Sgtb        if (code)
444ab9b2e15Sgtb 	   goto fail;
445ab9b2e15Sgtb        goto copy_subkey;
446ab9b2e15Sgtb    }
447ab9b2e15Sgtb fail:
448ab9b2e15Sgtb    /* SUNW15resync - (as in prev snv code) add if-code and success label fix */
449ab9b2e15Sgtb   if (code) {
450ab9b2e15Sgtb       *minor_status = code;
451ab9b2e15Sgtb       return GSS_S_FAILURE;
452ab9b2e15Sgtb   }
453ab9b2e15Sgtb 
454ab9b2e15Sgtb success:
455159d09a2SMark Phalan    return (GSS_S_COMPLETE);
4567c478bd9Sstevel@tonic-gate }
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate /*
459ab9b2e15Sgtb  * new_connection
460ab9b2e15Sgtb  *
461ab9b2e15Sgtb  * Do the grunt work of setting up a new context.
4627c478bd9Sstevel@tonic-gate  */
463ab9b2e15Sgtb static OM_uint32
new_connection(OM_uint32 * minor_status,krb5_gss_cred_id_t cred,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,krb5_context context,int default_mech)464ab9b2e15Sgtb new_connection(
465ab9b2e15Sgtb    OM_uint32 *minor_status,
466ab9b2e15Sgtb    krb5_gss_cred_id_t cred,
467ab9b2e15Sgtb    gss_ctx_id_t *context_handle,
468ab9b2e15Sgtb    gss_name_t target_name,
469ab9b2e15Sgtb    gss_OID mech_type,
470ab9b2e15Sgtb    OM_uint32 req_flags,
471ab9b2e15Sgtb    OM_uint32 time_req,
472ab9b2e15Sgtb    gss_channel_bindings_t input_chan_bindings,
473ab9b2e15Sgtb    gss_buffer_t input_token,
474ab9b2e15Sgtb    gss_OID *actual_mech_type,
475ab9b2e15Sgtb    gss_buffer_t output_token,
476ab9b2e15Sgtb    OM_uint32 *ret_flags,
477ab9b2e15Sgtb    OM_uint32 *time_rec,
478ab9b2e15Sgtb    krb5_context context,
479ab9b2e15Sgtb    int default_mech)
4807c478bd9Sstevel@tonic-gate {
481ab9b2e15Sgtb    OM_uint32 major_status;
482ab9b2e15Sgtb    krb5_error_code code;
483ab9b2e15Sgtb    krb5_creds *k_cred;
484ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx, *ctx_free;
485ab9b2e15Sgtb    krb5_timestamp now;
486ab9b2e15Sgtb    gss_buffer_desc token;
4877c478bd9Sstevel@tonic-gate 
488ab9b2e15Sgtb    k5_mutex_assert_locked(&cred->lock);
489ab9b2e15Sgtb    major_status = GSS_S_FAILURE;
490ab9b2e15Sgtb    token.length = 0;
491ab9b2e15Sgtb    token.value = NULL;
4927c478bd9Sstevel@tonic-gate 
493ab9b2e15Sgtb    /* make sure the cred is usable for init */
4947c478bd9Sstevel@tonic-gate 
495ab9b2e15Sgtb    if ((cred->usage != GSS_C_INITIATE) &&
496ab9b2e15Sgtb        (cred->usage != GSS_C_BOTH)) {
497ab9b2e15Sgtb       *minor_status = 0;
498ab9b2e15Sgtb       return(GSS_S_NO_CRED);
499ab9b2e15Sgtb    }
5007c478bd9Sstevel@tonic-gate 
501ab9b2e15Sgtb    /* complain if the input token is non-null */
5027c478bd9Sstevel@tonic-gate 
503ab9b2e15Sgtb    if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
504ab9b2e15Sgtb        *minor_status = 0;
505ab9b2e15Sgtb        return(GSS_S_DEFECTIVE_TOKEN);
506ab9b2e15Sgtb    }
5077c478bd9Sstevel@tonic-gate 
508ab9b2e15Sgtb    /* create the ctx */
5097c478bd9Sstevel@tonic-gate 
510ab9b2e15Sgtb    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
511ab9b2e15Sgtb        == NULL) {
512ab9b2e15Sgtb       *minor_status = ENOMEM;
513ab9b2e15Sgtb       return(GSS_S_FAILURE);
514ab9b2e15Sgtb    }
5157c478bd9Sstevel@tonic-gate 
516ab9b2e15Sgtb    /* fill in the ctx */
517ab9b2e15Sgtb    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
518ab9b2e15Sgtb    ctx_free = ctx;
519ab9b2e15Sgtb    if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
520ab9b2e15Sgtb       goto fail;
521ab9b2e15Sgtb    krb5_auth_con_setflags(context, ctx->auth_context,
522ab9b2e15Sgtb 			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
5237c478bd9Sstevel@tonic-gate 
524ab9b2e15Sgtb    /* limit the encryption types negotiated (if requested) */
525ab9b2e15Sgtb    if (cred->req_enctypes) {
526ab9b2e15Sgtb 	if ((code = krb5_set_default_tgs_enctypes(context,
527ab9b2e15Sgtb 						  cred->req_enctypes))) {
528ab9b2e15Sgtb 	    goto fail;
5297c478bd9Sstevel@tonic-gate 	}
530ab9b2e15Sgtb    }
5317c478bd9Sstevel@tonic-gate 
532ab9b2e15Sgtb    ctx->initiate = 1;
533ab9b2e15Sgtb    ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
534ab9b2e15Sgtb                      GSS_C_TRANS_FLAG |
535ab9b2e15Sgtb                      ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
536ab9b2e15Sgtb                                      GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
537ab9b2e15Sgtb    ctx->seed_init = 0;
538ab9b2e15Sgtb    ctx->big_endian = 0;  /* all initiators do little-endian, as per spec */
539ab9b2e15Sgtb    ctx->seqstate = 0;
5407c478bd9Sstevel@tonic-gate 
541ab9b2e15Sgtb    if ((code = krb5_timeofday(context, &now)))
542ab9b2e15Sgtb       goto fail;
5437c478bd9Sstevel@tonic-gate 
544ab9b2e15Sgtb    if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
545ab9b2e15Sgtb       ctx->endtime = 0;
546ab9b2e15Sgtb    } else {
547ab9b2e15Sgtb       ctx->endtime = now + time_req;
548ab9b2e15Sgtb    }
5497c478bd9Sstevel@tonic-gate 
550ab9b2e15Sgtb    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here)))
551ab9b2e15Sgtb       goto fail;
552ab9b2e15Sgtb 
553ab9b2e15Sgtb    if ((code = krb5_copy_principal(context, (krb5_principal) target_name,
554ab9b2e15Sgtb 				   &ctx->there)))
555ab9b2e15Sgtb       goto fail;
5567c478bd9Sstevel@tonic-gate 
557ab9b2e15Sgtb    code = get_credentials(context, cred, ctx->there, now,
558ab9b2e15Sgtb 			  ctx->endtime, &k_cred);
559ab9b2e15Sgtb    if (code)
560ab9b2e15Sgtb       goto fail;
5617c478bd9Sstevel@tonic-gate 
562ab9b2e15Sgtb    if (default_mech) {
563ab9b2e15Sgtb       mech_type = (gss_OID) gss_mech_krb5;
564ab9b2e15Sgtb    }
5657c478bd9Sstevel@tonic-gate 
566ab9b2e15Sgtb    if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
567ab9b2e15Sgtb        != GSS_S_COMPLETE) {
568ab9b2e15Sgtb       code = *minor_status;
569ab9b2e15Sgtb       goto fail;
570ab9b2e15Sgtb    }
571ab9b2e15Sgtb    /*
572ab9b2e15Sgtb     * Now try to make it static if at all possible....
573ab9b2e15Sgtb     */
574ab9b2e15Sgtb    ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
5757c478bd9Sstevel@tonic-gate 
576ab9b2e15Sgtb    {
577ab9b2e15Sgtb       /* gsskrb5 v1 */
578ab9b2e15Sgtb       krb5_ui_4 seq_temp;
579ab9b2e15Sgtb       if ((code = make_ap_req_v1(context, ctx,
580ab9b2e15Sgtb 				 cred, k_cred, input_chan_bindings,
581ab9b2e15Sgtb 				 mech_type, &token))) {
582ab9b2e15Sgtb 	 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
583ab9b2e15Sgtb 	     (code == KG_EMPTY_CCACHE))
584ab9b2e15Sgtb 	    major_status = GSS_S_NO_CRED;
585ab9b2e15Sgtb 	 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
586ab9b2e15Sgtb 	    major_status = GSS_S_CREDENTIALS_EXPIRED;
587ab9b2e15Sgtb 	 goto fail;
588ab9b2e15Sgtb       }
5897c478bd9Sstevel@tonic-gate 
590ab9b2e15Sgtb       krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
591ab9b2e15Sgtb 			    (krb5_int32 *)&seq_temp); /* SUNW15resync */
592ab9b2e15Sgtb       ctx->seq_send = seq_temp;
593ab9b2e15Sgtb       krb5_auth_con_getsendsubkey(context, ctx->auth_context,
594ab9b2e15Sgtb 				  &ctx->subkey);
595ab9b2e15Sgtb    }
5967c478bd9Sstevel@tonic-gate 
597ab9b2e15Sgtb    major_status = setup_enc(minor_status, ctx, context);
5987c478bd9Sstevel@tonic-gate 
599ab9b2e15Sgtb    if (k_cred) {
600ab9b2e15Sgtb       krb5_free_creds(context, k_cred);
601ab9b2e15Sgtb       k_cred = 0;
602ab9b2e15Sgtb    }
603ab9b2e15Sgtb 
604ab9b2e15Sgtb    /* at this point, the context is constructed and valid,
605ab9b2e15Sgtb       hence, releaseable */
6067c478bd9Sstevel@tonic-gate 
607ab9b2e15Sgtb    /* intern the context handle */
6087c478bd9Sstevel@tonic-gate 
609ab9b2e15Sgtb    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
610ab9b2e15Sgtb       code = G_VALIDATE_FAILED;
611ab9b2e15Sgtb       goto fail;
612ab9b2e15Sgtb    }
613ab9b2e15Sgtb    *context_handle = (gss_ctx_id_t) ctx;
614ab9b2e15Sgtb    ctx_free = 0;
6157c478bd9Sstevel@tonic-gate 
616ab9b2e15Sgtb    /* compute time_rec */
617ab9b2e15Sgtb    if (time_rec) {
618ab9b2e15Sgtb       if ((code = krb5_timeofday(context, &now)))
619ab9b2e15Sgtb 	 goto fail;
620ab9b2e15Sgtb       *time_rec = ctx->endtime - now;
621ab9b2e15Sgtb    }
6227c478bd9Sstevel@tonic-gate 
623ab9b2e15Sgtb    /* set the other returns */
624ab9b2e15Sgtb    *output_token = token;
6257c478bd9Sstevel@tonic-gate 
626ab9b2e15Sgtb    if (ret_flags)
627ab9b2e15Sgtb       *ret_flags = ctx->gss_flags;
6287c478bd9Sstevel@tonic-gate 
629ab9b2e15Sgtb    if (actual_mech_type)
630ab9b2e15Sgtb       *actual_mech_type = mech_type;
6317c478bd9Sstevel@tonic-gate 
632ab9b2e15Sgtb    /* return successfully */
6337c478bd9Sstevel@tonic-gate 
634ab9b2e15Sgtb    *minor_status = 0;
635ab9b2e15Sgtb    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
636ab9b2e15Sgtb       ctx->established = 0;
637ab9b2e15Sgtb       return(GSS_S_CONTINUE_NEEDED);
638ab9b2e15Sgtb    } else {
639ab9b2e15Sgtb       ctx->seq_recv = ctx->seq_send;
640ab9b2e15Sgtb       g_order_init(&(ctx->seqstate), ctx->seq_recv,
641ab9b2e15Sgtb 		   (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
642ab9b2e15Sgtb 		   (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
643ab9b2e15Sgtb       ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
644ab9b2e15Sgtb       ctx->established = 1;
645ab9b2e15Sgtb       return(GSS_S_COMPLETE);
646ab9b2e15Sgtb    }
6477c478bd9Sstevel@tonic-gate 
648ab9b2e15Sgtb fail:
649ab9b2e15Sgtb    if (ctx_free) {
650ab9b2e15Sgtb        if (ctx_free->auth_context)
651ab9b2e15Sgtb 	   krb5_auth_con_free(context, ctx_free->auth_context);
652ab9b2e15Sgtb        if (ctx_free->here)
653ab9b2e15Sgtb 	   krb5_free_principal(context, ctx_free->here);
654ab9b2e15Sgtb        if (ctx_free->there)
655ab9b2e15Sgtb 	   krb5_free_principal(context, ctx_free->there);
656ab9b2e15Sgtb        if (ctx_free->subkey)
657ab9b2e15Sgtb 	   krb5_free_keyblock(context, ctx_free->subkey);
658ab9b2e15Sgtb        xfree(ctx_free);
659ab9b2e15Sgtb    } else
660ab9b2e15Sgtb 	(void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
661ab9b2e15Sgtb 
662ab9b2e15Sgtb    *minor_status = code;
663ab9b2e15Sgtb    return (major_status);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
666ab9b2e15Sgtb /*
667ab9b2e15Sgtb  * mutual_auth
668ab9b2e15Sgtb  *
669ab9b2e15Sgtb  * Handle the reply from the acceptor, if we're doing mutual auth.
670ab9b2e15Sgtb  */
6717c478bd9Sstevel@tonic-gate static OM_uint32
mutual_auth(OM_uint32 * minor_status,gss_ctx_id_t * context_handle,gss_name_t target_name,gss_OID mech_type,OM_uint32 req_flags,OM_uint32 time_req,gss_channel_bindings_t input_chan_bindings,gss_buffer_t input_token,gss_OID * actual_mech_type,gss_buffer_t output_token,OM_uint32 * ret_flags,OM_uint32 * time_rec,krb5_context context)672ab9b2e15Sgtb mutual_auth(
673ab9b2e15Sgtb    OM_uint32 *minor_status,
674ab9b2e15Sgtb    gss_ctx_id_t *context_handle,
675ab9b2e15Sgtb    gss_name_t target_name,
676ab9b2e15Sgtb    gss_OID mech_type,
677ab9b2e15Sgtb    OM_uint32 req_flags,
678ab9b2e15Sgtb    OM_uint32 time_req,
679ab9b2e15Sgtb    gss_channel_bindings_t input_chan_bindings,
680ab9b2e15Sgtb    gss_buffer_t input_token,
681ab9b2e15Sgtb    gss_OID *actual_mech_type,
682ab9b2e15Sgtb    gss_buffer_t output_token,
683ab9b2e15Sgtb    OM_uint32 *ret_flags,
684ab9b2e15Sgtb    OM_uint32 *time_rec,
685ab9b2e15Sgtb    krb5_context context)
6867c478bd9Sstevel@tonic-gate {
687ab9b2e15Sgtb    OM_uint32 major_status;
688ab9b2e15Sgtb    unsigned char *ptr;
689ab9b2e15Sgtb    char *sptr;
690ab9b2e15Sgtb    krb5_data ap_rep;
691ab9b2e15Sgtb    krb5_ap_rep_enc_part *ap_rep_data;
692ab9b2e15Sgtb    krb5_timestamp now;
693ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx;
694ab9b2e15Sgtb    krb5_error *krb_error;
695ab9b2e15Sgtb    krb5_error_code code;
696ab9b2e15Sgtb    krb5int_access kaccess;
6977c478bd9Sstevel@tonic-gate 
698ab9b2e15Sgtb    major_status = GSS_S_FAILURE;
6997c478bd9Sstevel@tonic-gate 
700ab9b2e15Sgtb    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
701ab9b2e15Sgtb    if (code)
702ab9b2e15Sgtb        goto fail;
7037c478bd9Sstevel@tonic-gate 
704ab9b2e15Sgtb    /* validate the context handle */
705ab9b2e15Sgtb    /*SUPPRESS 29*/
706ab9b2e15Sgtb    if (! kg_validate_ctx_id(*context_handle)) {
707ab9b2e15Sgtb       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
708ab9b2e15Sgtb       return(GSS_S_NO_CONTEXT);
709ab9b2e15Sgtb    }
7107c478bd9Sstevel@tonic-gate 
711159d09a2SMark Phalan    ctx = (krb5_gss_ctx_id_t) *context_handle;
7127c478bd9Sstevel@tonic-gate 
713ab9b2e15Sgtb    /* make sure the context is non-established, and that certain
714ab9b2e15Sgtb       arguments are unchanged */
7157c478bd9Sstevel@tonic-gate 
716ab9b2e15Sgtb    if ((ctx->established) ||
717ab9b2e15Sgtb        ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
718ab9b2e15Sgtb       code = KG_CONTEXT_ESTABLISHED;
719ab9b2e15Sgtb       goto fail;
720ab9b2e15Sgtb    }
721fe598cdcSmp 
722ab9b2e15Sgtb    if (! krb5_principal_compare(context, ctx->there,
723ab9b2e15Sgtb 				(krb5_principal) target_name)) {
7245e01956fSGlenn Barry        /* Solaris Kerberos: spruce-up the err msg */
7255e01956fSGlenn Barry        krb5_principal tname = (krb5_principal) target_name;
7265e01956fSGlenn Barry        char *s_name = NULL, *s_princ= NULL;
7275e01956fSGlenn Barry        int kret = krb5_unparse_name(context, tname, &s_name);
7285e01956fSGlenn Barry        int kret1 = krb5_unparse_name(context, ctx->there, &s_princ);
7295e01956fSGlenn Barry        code = KRB5_PRINC_NOMATCH;
7305e01956fSGlenn Barry        if (kret == 0 && kret1 == 0) {
7315e01956fSGlenn Barry 	   krb5_set_error_message(context, code,
7325e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
7335e01956fSGlenn Barry 					"Target name principal '%s' does not match '%s'"),
7345e01956fSGlenn Barry 				s_name, s_princ);
7355e01956fSGlenn Barry 	   save_error_info(code, context);
7365e01956fSGlenn Barry        }
7375e01956fSGlenn Barry        if (s_name)
7385e01956fSGlenn Barry 	   krb5_free_unparsed_name(context, s_name);
7395e01956fSGlenn Barry        if (s_princ)
7405e01956fSGlenn Barry 	   krb5_free_unparsed_name(context, s_princ);
7415e01956fSGlenn Barry 
7425e01956fSGlenn Barry        (void)krb5_gss_delete_sec_context(minor_status,
743ab9b2e15Sgtb 					context_handle, NULL);
7445e01956fSGlenn Barry        major_status = GSS_S_BAD_NAME;
7455e01956fSGlenn Barry        goto fail;
746ab9b2e15Sgtb    }
747fe598cdcSmp 
748ab9b2e15Sgtb    /* verify the token and leave the AP_REP message in ap_rep */
749fe598cdcSmp 
750ab9b2e15Sgtb    if (input_token == GSS_C_NO_BUFFER) {
751ab9b2e15Sgtb       (void)krb5_gss_delete_sec_context(minor_status,
752ab9b2e15Sgtb 					context_handle, NULL);
753ab9b2e15Sgtb       code = 0;
754ab9b2e15Sgtb       major_status = GSS_S_DEFECTIVE_TOKEN;
755ab9b2e15Sgtb       goto fail;
756ab9b2e15Sgtb    }
757fe598cdcSmp 
758ab9b2e15Sgtb    ptr = (unsigned char *) input_token->value;
7597c478bd9Sstevel@tonic-gate 
760ab9b2e15Sgtb    if (g_verify_token_header(ctx->mech_used,
761ab9b2e15Sgtb 			     &(ap_rep.length),
762ab9b2e15Sgtb 			     &ptr, KG_TOK_CTX_AP_REP,
763ab9b2e15Sgtb 			     input_token->length, 1)) {
764ab9b2e15Sgtb       if (g_verify_token_header((gss_OID) ctx->mech_used,
765ab9b2e15Sgtb 				&(ap_rep.length),
766ab9b2e15Sgtb 				&ptr, KG_TOK_CTX_ERROR,
767ab9b2e15Sgtb 				input_token->length, 1) == 0) {
7687c478bd9Sstevel@tonic-gate 
769ab9b2e15Sgtb 	 /* Handle a KRB_ERROR message from the server */
7707c478bd9Sstevel@tonic-gate 
771ab9b2e15Sgtb 	 sptr = (char *) ptr;           /* PC compiler bug */
772ab9b2e15Sgtb 	 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
773ab9b2e15Sgtb 
774ab9b2e15Sgtb 	 code = krb5_rd_error(context, &ap_rep, &krb_error);
775ab9b2e15Sgtb 	 if (code)
776ab9b2e15Sgtb 	    goto fail;
777ab9b2e15Sgtb 	 if (krb_error->error)
778ab9b2e15Sgtb 	    code = krb_error->error + ERROR_TABLE_BASE_krb5;
779ab9b2e15Sgtb 	 else
780ab9b2e15Sgtb 	    code = 0;
781ab9b2e15Sgtb 	 krb5_free_error(context, krb_error);
782ab9b2e15Sgtb 	 goto fail;
783ab9b2e15Sgtb       } else {
784ab9b2e15Sgtb 	 *minor_status = 0;
785ab9b2e15Sgtb 	 return(GSS_S_DEFECTIVE_TOKEN);
786ab9b2e15Sgtb       }
787ab9b2e15Sgtb    }
7887c478bd9Sstevel@tonic-gate 
789ab9b2e15Sgtb    sptr = (char *) ptr;                      /* PC compiler bug */
790ab9b2e15Sgtb    TREAD_STR(sptr, ap_rep.data, ap_rep.length);
7917c478bd9Sstevel@tonic-gate 
792ab9b2e15Sgtb    /* decode the ap_rep */
793ab9b2e15Sgtb    if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
794ab9b2e15Sgtb 			   &ap_rep_data))) {
795ab9b2e15Sgtb       /*
796ab9b2e15Sgtb        * XXX A hack for backwards compatiblity.
797ab9b2e15Sgtb        * To be removed in 1999 -- proven
798ab9b2e15Sgtb        */
799ab9b2e15Sgtb       krb5_auth_con_setuseruserkey(context, ctx->auth_context,
800ab9b2e15Sgtb 				   ctx->subkey);
801ab9b2e15Sgtb       if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
802ab9b2e15Sgtb 		       &ap_rep_data)))
803ab9b2e15Sgtb 	 goto fail;
804ab9b2e15Sgtb    }
8057c478bd9Sstevel@tonic-gate 
806ab9b2e15Sgtb    /* store away the sequence number */
807ab9b2e15Sgtb    ctx->seq_recv = ap_rep_data->seq_number;
808ab9b2e15Sgtb    g_order_init(&(ctx->seqstate), ctx->seq_recv,
809ab9b2e15Sgtb 		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
810ab9b2e15Sgtb 		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
8117c478bd9Sstevel@tonic-gate 
812ab9b2e15Sgtb    if (ctx->proto == 1 && ap_rep_data->subkey) {
813ab9b2e15Sgtb        /* Keep acceptor's subkey.  */
814ab9b2e15Sgtb        ctx->have_acceptor_subkey = 1;
815ab9b2e15Sgtb        code = krb5_copy_keyblock(context, ap_rep_data->subkey,
816ab9b2e15Sgtb 				 &ctx->acceptor_subkey);
817ab9b2e15Sgtb        if (code)
818ab9b2e15Sgtb 	   goto fail;
819ab9b2e15Sgtb        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
820ab9b2e15Sgtb 					    ctx->acceptor_subkey->enctype,
821ab9b2e15Sgtb 					    &ctx->acceptor_subkey_cksumtype);
822ab9b2e15Sgtb        if (code)
823ab9b2e15Sgtb 	   goto fail;
824ab9b2e15Sgtb    }
8257c478bd9Sstevel@tonic-gate 
826ab9b2e15Sgtb    /* free the ap_rep_data */
827ab9b2e15Sgtb    krb5_free_ap_rep_enc_part(context, ap_rep_data);
8287c478bd9Sstevel@tonic-gate 
829ab9b2e15Sgtb    /* set established */
830ab9b2e15Sgtb    ctx->established = 1;
8317c478bd9Sstevel@tonic-gate 
832ab9b2e15Sgtb    /* set returns */
8337c478bd9Sstevel@tonic-gate 
834ab9b2e15Sgtb    if (time_rec) {
835ab9b2e15Sgtb       if ((code = krb5_timeofday(context, &now)))
836ab9b2e15Sgtb 	 goto fail;
837ab9b2e15Sgtb       *time_rec = ctx->endtime - now;
838ab9b2e15Sgtb    }
8397c478bd9Sstevel@tonic-gate 
840ab9b2e15Sgtb    if (ret_flags)
841ab9b2e15Sgtb       *ret_flags = ctx->gss_flags;
8427c478bd9Sstevel@tonic-gate 
843ab9b2e15Sgtb    if (actual_mech_type)
844ab9b2e15Sgtb       *actual_mech_type = mech_type;
8457c478bd9Sstevel@tonic-gate 
846ab9b2e15Sgtb    /* success */
8477c478bd9Sstevel@tonic-gate 
848ab9b2e15Sgtb    *minor_status = 0;
849ab9b2e15Sgtb    return GSS_S_COMPLETE;
8507c478bd9Sstevel@tonic-gate 
851ab9b2e15Sgtb fail:
852ab9b2e15Sgtb    (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
8537c478bd9Sstevel@tonic-gate 
854ab9b2e15Sgtb    *minor_status = code;
855ab9b2e15Sgtb    return (major_status);
8567c478bd9Sstevel@tonic-gate }
8577c478bd9Sstevel@tonic-gate 
858ab9b2e15Sgtb OM_uint32
krb5_gss_init_sec_context(minor_status,claimant_cred_handle,context_handle,target_name,mech_type,req_flags,time_req,input_chan_bindings,input_token,actual_mech_type,output_token,ret_flags,time_rec)859ab9b2e15Sgtb krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
860ab9b2e15Sgtb 			  context_handle, target_name, mech_type,
861ab9b2e15Sgtb 			  req_flags, time_req, input_chan_bindings,
862ab9b2e15Sgtb 			  input_token, actual_mech_type, output_token,
863ab9b2e15Sgtb 			  ret_flags, time_rec)
864ab9b2e15Sgtb     OM_uint32 *minor_status;
865ab9b2e15Sgtb     gss_cred_id_t claimant_cred_handle;
866ab9b2e15Sgtb     gss_ctx_id_t *context_handle;
867ab9b2e15Sgtb     gss_name_t target_name;
868ab9b2e15Sgtb     gss_OID mech_type;
869ab9b2e15Sgtb     OM_uint32 req_flags;
870ab9b2e15Sgtb     OM_uint32 time_req;
871ab9b2e15Sgtb     gss_channel_bindings_t input_chan_bindings;
872ab9b2e15Sgtb     gss_buffer_t input_token;
873ab9b2e15Sgtb     gss_OID *actual_mech_type;
874ab9b2e15Sgtb     gss_buffer_t output_token;
875ab9b2e15Sgtb     OM_uint32 *ret_flags;
876ab9b2e15Sgtb     OM_uint32 *time_rec;
8777c478bd9Sstevel@tonic-gate {
878ab9b2e15Sgtb    krb5_context context;
879ab9b2e15Sgtb    krb5_gss_cred_id_t cred;
880ab9b2e15Sgtb    int err;
881ab9b2e15Sgtb    krb5_error_code kerr;
882ab9b2e15Sgtb    int default_mech = 0;
883ab9b2e15Sgtb    OM_uint32 major_status;
884ab9b2e15Sgtb    OM_uint32 tmp_min_stat;
8857c478bd9Sstevel@tonic-gate 
886ab9b2e15Sgtb    if (*context_handle == GSS_C_NO_CONTEXT) {
887ab9b2e15Sgtb        kerr = krb5_gss_init_context(&context);
888ab9b2e15Sgtb        if (kerr) {
889ab9b2e15Sgtb 	   *minor_status = kerr;
890ab9b2e15Sgtb 	   return GSS_S_FAILURE;
891ab9b2e15Sgtb        }
8925e01956fSGlenn Barry        if (GSS_ERROR(kg_sync_ccache_name(context, minor_status))) {
8935e01956fSGlenn Barry 	   save_error_info(*minor_status, context);
8945e01956fSGlenn Barry 	   krb5_free_context(context);
895ab9b2e15Sgtb 	   return GSS_S_FAILURE;
8965e01956fSGlenn Barry        }
897ab9b2e15Sgtb    } else {
898ab9b2e15Sgtb        context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
899ab9b2e15Sgtb    }
9007c478bd9Sstevel@tonic-gate 
901ab9b2e15Sgtb    /* set up return values so they can be "freed" successfully */
9027c478bd9Sstevel@tonic-gate 
903ab9b2e15Sgtb    major_status = GSS_S_FAILURE; /* Default major code */
904ab9b2e15Sgtb    output_token->length = 0;
905ab9b2e15Sgtb    output_token->value = NULL;
906ab9b2e15Sgtb    if (actual_mech_type)
907ab9b2e15Sgtb       *actual_mech_type = NULL;
9087c478bd9Sstevel@tonic-gate 
909ab9b2e15Sgtb    /* verify that the target_name is valid and usable */
9107c478bd9Sstevel@tonic-gate 
911ab9b2e15Sgtb    if (! kg_validate_name(target_name)) {
9125e01956fSGlenn Barry        /* Solaris Kerberos: spruce-up the err msg */
9135e01956fSGlenn Barry        krb5_principal princ = (krb5_principal) target_name;
9145e01956fSGlenn Barry        char *s_name = NULL;
9155e01956fSGlenn Barry        int kret = krb5_unparse_name(context, princ, &s_name);
9165e01956fSGlenn Barry        *minor_status = (OM_uint32) G_VALIDATE_FAILED;
9175e01956fSGlenn Barry        if (kret == 0) {
9185e01956fSGlenn Barry 	   krb5_set_error_message(context, *minor_status,
9195e01956fSGlenn Barry 				dgettext(TEXT_DOMAIN,
9205e01956fSGlenn Barry 					"Target name principal '%s' is invalid"),
9215e01956fSGlenn Barry 				s_name);
9225e01956fSGlenn Barry 	   krb5_free_unparsed_name(context, s_name);
9235e01956fSGlenn Barry 	   save_error_info(*minor_status, context);
9245e01956fSGlenn Barry 	}
9255e01956fSGlenn Barry 
9265e01956fSGlenn Barry         if (*context_handle == GSS_C_NO_CONTEXT)
9275e01956fSGlenn Barry 	    krb5_free_context(context);
9285e01956fSGlenn Barry         return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
929ab9b2e15Sgtb    }
9307c478bd9Sstevel@tonic-gate 
931ab9b2e15Sgtb    /* verify the credential, or use the default */
932ab9b2e15Sgtb    /*SUPPRESS 29*/
933ab9b2e15Sgtb    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
934ab9b2e15Sgtb       /*
935ab9b2e15Sgtb        * Solaris Kerberos: here we are using the Solaris specific
936ab9b2e15Sgtb        * function get_default_cred() to handle the special case of a
937ab9b2e15Sgtb        * root principal
938ab9b2e15Sgtb        */
939ab9b2e15Sgtb       major_status = get_default_cred(minor_status, context,
940ab9b2e15Sgtb 				    (gss_cred_id_t *)&cred);
941ab9b2e15Sgtb       if (major_status && GSS_ERROR(major_status)) {
9425e01956fSGlenn Barry 	  save_error_info(*minor_status, context);
9435e01956fSGlenn Barry 	  if (*context_handle == GSS_C_NO_CONTEXT)
9445e01956fSGlenn Barry 	      krb5_free_context(context);
945ab9b2e15Sgtb 	 return(major_status);
946ab9b2e15Sgtb       }
947ab9b2e15Sgtb    } else {
948ab9b2e15Sgtb       major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle);
949ab9b2e15Sgtb       if (GSS_ERROR(major_status)) {
9505e01956fSGlenn Barry           save_error_info(*minor_status, context);
951ab9b2e15Sgtb 	  if (*context_handle == GSS_C_NO_CONTEXT)
952ab9b2e15Sgtb 	      krb5_free_context(context);
953ab9b2e15Sgtb 	  return(major_status);
954ab9b2e15Sgtb       }
955ab9b2e15Sgtb       cred = (krb5_gss_cred_id_t) claimant_cred_handle;
956ab9b2e15Sgtb    }
957ab9b2e15Sgtb    kerr = k5_mutex_lock(&cred->lock);
958ab9b2e15Sgtb    if (kerr) {
959ab9b2e15Sgtb        krb5_free_context(context);
960ab9b2e15Sgtb        *minor_status = kerr;
961ab9b2e15Sgtb        return GSS_S_FAILURE;
962ab9b2e15Sgtb    }
9637c478bd9Sstevel@tonic-gate 
964ab9b2e15Sgtb    /* verify the mech_type */
9657c478bd9Sstevel@tonic-gate 
966ab9b2e15Sgtb    err = 0;
967ab9b2e15Sgtb    if (mech_type == GSS_C_NULL_OID) {
968ab9b2e15Sgtb        default_mech = 1;
969ab9b2e15Sgtb        if (cred->rfc_mech) {
970ab9b2e15Sgtb 	   mech_type = (gss_OID) gss_mech_krb5;
971ab9b2e15Sgtb        } else if (cred->prerfc_mech) {
972ab9b2e15Sgtb 	   mech_type = (gss_OID) gss_mech_krb5_old;
973ab9b2e15Sgtb        } else {
974ab9b2e15Sgtb 	   err = 1;
975ab9b2e15Sgtb        }
976