17c478bd9Sstevel@tonic-gate /*
2*db02be57S  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate 
77c478bd9Sstevel@tonic-gate /*
8ab9b2e15Sgtb  * Copyright 2000,2002, 2003 by the Massachusetts Institute of Technology.
97c478bd9Sstevel@tonic-gate  * All Rights Reserved.
107c478bd9Sstevel@tonic-gate  *
117c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may
127c478bd9Sstevel@tonic-gate  *   require a specific license from the United States Government.
137c478bd9Sstevel@tonic-gate  *   It is the responsibility of any person or organization contemplating
147c478bd9Sstevel@tonic-gate  *   export to obtain such a license before exporting.
15ab9b2e15Sgtb  *
167c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
177c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
187c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
197c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
207c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
217c478bd9Sstevel@tonic-gate  * the name of M.I.T. not be used in advertising or publicity pertaining
227c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
237c478bd9Sstevel@tonic-gate  * permission.  Furthermore if you modify this software you must label
247c478bd9Sstevel@tonic-gate  * your software as modified software and not distribute it in such a
257c478bd9Sstevel@tonic-gate  * fashion that it might be confused with the original M.I.T. software.
267c478bd9Sstevel@tonic-gate  * M.I.T. makes no representations about the suitability of
277c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
287c478bd9Sstevel@tonic-gate  * or implied warranty.
29ab9b2e15Sgtb  *
307c478bd9Sstevel@tonic-gate  */
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * Copyright 1993 by OpenVision Technologies, Inc.
33ab9b2e15Sgtb  *
347c478bd9Sstevel@tonic-gate  * Permission to use, copy, modify, distribute, and sell this software
357c478bd9Sstevel@tonic-gate  * and its documentation for any purpose is hereby granted without fee,
367c478bd9Sstevel@tonic-gate  * provided that the above copyright notice appears in all copies and
377c478bd9Sstevel@tonic-gate  * that both that copyright notice and this permission notice appear in
387c478bd9Sstevel@tonic-gate  * supporting documentation, and that the name of OpenVision not be used
397c478bd9Sstevel@tonic-gate  * in advertising or publicity pertaining to distribution of the software
407c478bd9Sstevel@tonic-gate  * without specific, written prior permission. OpenVision makes no
417c478bd9Sstevel@tonic-gate  * representations about the suitability of this software for any
427c478bd9Sstevel@tonic-gate  * purpose.  It is provided "as is" without express or implied warranty.
43ab9b2e15Sgtb  *
447c478bd9Sstevel@tonic-gate  * OPENVISION DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
457c478bd9Sstevel@tonic-gate  * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO
467c478bd9Sstevel@tonic-gate  * EVENT SHALL OPENVISION BE LIABLE FOR ANY SPECIAL, INDIRECT OR
477c478bd9Sstevel@tonic-gate  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
487c478bd9Sstevel@tonic-gate  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
497c478bd9Sstevel@tonic-gate  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
507c478bd9Sstevel@tonic-gate  * PERFORMANCE OF THIS SOFTWARE.
517c478bd9Sstevel@tonic-gate  */
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate /*
547c478bd9Sstevel@tonic-gate  * Copyright (C) 1998 by the FundsXpress, INC.
55ab9b2e15Sgtb  *
567c478bd9Sstevel@tonic-gate  * All rights reserved.
57ab9b2e15Sgtb  *
587c478bd9Sstevel@tonic-gate  * Export of this software from the United States of America may require
597c478bd9Sstevel@tonic-gate  * a specific license from the United States Government.  It is the
607c478bd9Sstevel@tonic-gate  * responsibility of any person or organization contemplating export to
617c478bd9Sstevel@tonic-gate  * obtain such a license before exporting.
62ab9b2e15Sgtb  *
637c478bd9Sstevel@tonic-gate  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
647c478bd9Sstevel@tonic-gate  * distribute this software and its documentation for any purpose and
657c478bd9Sstevel@tonic-gate  * without fee is hereby granted, provided that the above copyright
667c478bd9Sstevel@tonic-gate  * notice appear in all copies and that both that copyright notice and
677c478bd9Sstevel@tonic-gate  * this permission notice appear in supporting documentation, and that
687c478bd9Sstevel@tonic-gate  * the name of FundsXpress. not be used in advertising or publicity pertaining
697c478bd9Sstevel@tonic-gate  * to distribution of the software without specific, written prior
707c478bd9Sstevel@tonic-gate  * permission.  FundsXpress makes no representations about the suitability of
717c478bd9Sstevel@tonic-gate  * this software for any purpose.  It is provided "as is" without express
727c478bd9Sstevel@tonic-gate  * or implied warranty.
73ab9b2e15Sgtb  *
747c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
757c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
767c478bd9Sstevel@tonic-gate  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
777c478bd9Sstevel@tonic-gate  */
787c478bd9Sstevel@tonic-gate 
79*db02be57S /* Solaris Kerberos */
80*db02be57S #include <libintl.h>
81*db02be57S #include <locale.h>
82*db02be57S 
83ab9b2e15Sgtb #include "k5-int.h"
84ab9b2e15Sgtb #include "gss_libinit.h"
85159d09a2SMark Phalan #include "gssapiP_krb5.h"
86ab9b2e15Sgtb #include "mglueP.h"
87ab9b2e15Sgtb #ifdef HAVE_MEMORY_H
887c478bd9Sstevel@tonic-gate #include <memory.h>
89ab9b2e15Sgtb #endif
907c478bd9Sstevel@tonic-gate #include <stdlib.h>
917c478bd9Sstevel@tonic-gate #include <assert.h>
927c478bd9Sstevel@tonic-gate 
93ab9b2e15Sgtb /* Solaris Kerberos start */
94ab9b2e15Sgtb static OM_uint32 get_default_cred(OM_uint32 *, void *, gss_cred_id_t *);
95ab9b2e15Sgtb /* Solaris Kerberos end */
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate /*
98159d09a2SMark Phalan  * $Id: init_sec_context.c 18721 2006-10-16 16:18:29Z epeisach $
997c478bd9Sstevel@tonic-gate  */
100ab9b2e15Sgtb 
101ab9b2e15Sgtb /* XXX This is for debugging only!!!  Should become a real bitfield
102ab9b2e15Sgtb    at some point */
1037c478bd9Sstevel@tonic-gate int krb5_gss_dbg_client_expcreds = 0;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Common code which fetches the correct krb5 credentials from the
1077c478bd9Sstevel@tonic-gate  * ccache.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static krb5_error_code get_credentials(context, cred, server, now,
1107c478bd9Sstevel@tonic-gate 				       endtime, out_creds)
1117c478bd9Sstevel@tonic-gate     krb5_context context;
1127c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
1137c478bd9Sstevel@tonic-gate     krb5_principal server;
1147c478bd9Sstevel@tonic-gate     krb5_timestamp now;
1157c478bd9Sstevel@tonic-gate     krb5_timestamp endtime;
1167c478bd9Sstevel@tonic-gate     krb5_creds **out_creds;
1177c478bd9Sstevel@tonic-gate {
1187c478bd9Sstevel@tonic-gate     krb5_error_code	code;
1197c478bd9Sstevel@tonic-gate     krb5_creds 		in_creds;
1207c478bd9Sstevel@tonic-gate 
121ab9b2e15Sgtb     k5_mutex_assert_locked(&cred->lock);
1227c478bd9Sstevel@tonic-gate     memset((char *) &in_creds, 0, sizeof(krb5_creds));
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, cred->princ, &in_creds.client)))
1257c478bd9Sstevel@tonic-gate 	goto cleanup;
1267c478bd9Sstevel@tonic-gate     if ((code = krb5_copy_principal(context, server, &in_creds.server)))
1277c478bd9Sstevel@tonic-gate 	goto cleanup;
1287c478bd9Sstevel@tonic-gate     in_creds.times.endtime = endtime;
1297c478bd9Sstevel@tonic-gate 
1307c478bd9Sstevel@tonic-gate     in_creds.keyblock.enctype = 0;
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate     code = krb5_get_credentials(context, 0, cred->ccache,
1337c478bd9Sstevel@tonic-gate 				&in_creds, out_creds);
1347c478bd9Sstevel@tonic-gate     if (code)
1357c478bd9Sstevel@tonic-gate 	goto cleanup;
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate     /*
1387c478bd9Sstevel@tonic-gate      * Enforce a stricter limit (without timeskew forgiveness at the
1397c478bd9Sstevel@tonic-gate      * boundaries) because accept_sec_context code is also similarly
1407c478bd9Sstevel@tonic-gate      * non-forgiving.
1417c478bd9Sstevel@tonic-gate      */
1427c478bd9Sstevel@tonic-gate     if (!krb5_gss_dbg_client_expcreds && *out_creds != NULL &&
1437c478bd9Sstevel@tonic-gate 	(*out_creds)->times.endtime < now) {
1447c478bd9Sstevel@tonic-gate 	code = KRB5KRB_AP_ERR_TKT_EXPIRED;
1457c478bd9Sstevel@tonic-gate 	goto cleanup;
1467c478bd9Sstevel@tonic-gate     }
147ab9b2e15Sgtb 
1487c478bd9Sstevel@tonic-gate cleanup:
1497c478bd9Sstevel@tonic-gate     if (in_creds.client)
1507c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.client);
1517c478bd9Sstevel@tonic-gate     if (in_creds.server)
1527c478bd9Sstevel@tonic-gate 	    krb5_free_principal(context, in_creds.server);
1537c478bd9Sstevel@tonic-gate     return code;
1547c478bd9Sstevel@tonic-gate }
1557c478bd9Sstevel@tonic-gate struct gss_checksum_data {
1567c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
1577c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
1587c478bd9Sstevel@tonic-gate     krb5_checksum md5;
1597c478bd9Sstevel@tonic-gate     krb5_data checksum_data;
1607c478bd9Sstevel@tonic-gate };
1617c478bd9Sstevel@tonic-gate 
162ab9b2e15Sgtb #ifdef CFX_EXERCISE
163ab9b2e15Sgtb #include "../../krb5/krb/auth_con.h"
164ab9b2e15Sgtb #endif
1657c478bd9Sstevel@tonic-gate static krb5_error_code KRB5_CALLCONV
1667c478bd9Sstevel@tonic-gate make_gss_checksum (krb5_context context, krb5_auth_context auth_context,
167ab9b2e15Sgtb 		   void *cksum_data, krb5_data **out)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate     krb5_error_code code;
1707c478bd9Sstevel@tonic-gate     krb5_int32 con_flags;
1717c478bd9Sstevel@tonic-gate     unsigned char *ptr;
1727c478bd9Sstevel@tonic-gate     struct gss_checksum_data *data = cksum_data;
1737c478bd9Sstevel@tonic-gate     krb5_data credmsg;
174ab9b2e15Sgtb     unsigned int junk;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate     data->checksum_data.data = 0;
1777c478bd9Sstevel@tonic-gate     credmsg.data = 0;
1787c478bd9Sstevel@tonic-gate     /* build the checksum field */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate     if (data->ctx->gss_flags & GSS_C_DELEG_FLAG) {
1817c478bd9Sstevel@tonic-gate 	/* first get KRB_CRED message, so we know its length */
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	/* clear the time check flag that was set in krb5_auth_con_init() */
1847c478bd9Sstevel@tonic-gate 	krb5_auth_con_getflags(context, auth_context, &con_flags);
1857c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context,
186ab9b2e15Sgtb 			       con_flags & ~KRB5_AUTH_CONTEXT_DO_TIME);
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate 	code = krb5_fwd_tgt_creds(context, auth_context, 0,
189ab9b2e15Sgtb 				  data->cred->princ, data->ctx->there,
190ab9b2e15Sgtb 				  data->cred->ccache, 1,
191ab9b2e15Sgtb 				  &credmsg);
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* turn KRB5_AUTH_CONTEXT_DO_TIME back on */
1947c478bd9Sstevel@tonic-gate 	krb5_auth_con_setflags(context, auth_context, con_flags);
1957c478bd9Sstevel@tonic-gate 
1967c478bd9Sstevel@tonic-gate 	if (code) {
1977c478bd9Sstevel@tonic-gate 	    /* don't fail here; just don't accept/do the delegation
198ab9b2e15Sgtb                request */
1997c478bd9Sstevel@tonic-gate 	    data->ctx->gss_flags &= ~GSS_C_DELEG_FLAG;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	    data->checksum_data.length = 24;
2027c478bd9Sstevel@tonic-gate 	} else {
2037c478bd9Sstevel@tonic-gate 	    if (credmsg.length+28 > KRB5_INT16_MAX) {
2047c478bd9Sstevel@tonic-gate 		krb5_free_data_contents(context, &credmsg);
2057c478bd9Sstevel@tonic-gate 		return(KRB5KRB_ERR_FIELD_TOOLONG);
206ab9b2e15Sgtb 	    }
2077c478bd9Sstevel@tonic-gate 
208ab9b2e15Sgtb 	    data->checksum_data.length = 28+credmsg.length;
2097c478bd9Sstevel@tonic-gate 	}
2107c478bd9Sstevel@tonic-gate     } else {
2117c478bd9Sstevel@tonic-gate 	data->checksum_data.length = 24;
2127c478bd9Sstevel@tonic-gate     }
2137c478bd9Sstevel@tonic-gate #ifdef CFX_EXERCISE
214ab9b2e15Sgtb     if (data->ctx->auth_context->keyblock != NULL
215ab9b2e15Sgtb 	&& data->ctx->auth_context->keyblock->enctype == 18) {
2167c478bd9Sstevel@tonic-gate 	srand(time(0) ^ getpid());
2177c478bd9Sstevel@tonic-gate 	/* Our ftp client code stupidly assumes a base64-encoded
2187c478bd9Sstevel@tonic-gate 	   version of the token will fit in 10K, so don't make this
2197c478bd9Sstevel@tonic-gate 	   too big.  */
2207c478bd9Sstevel@tonic-gate 	junk = rand() & 0xff;
2217c478bd9Sstevel@tonic-gate     } else
222ab9b2e15Sgtb 	junk = 0;
2237c478bd9Sstevel@tonic-gate #else
2247c478bd9Sstevel@tonic-gate     junk = 0;
2257c478bd9Sstevel@tonic-gate #endif
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate     data->checksum_data.length += junk;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate     /* now allocate a buffer to hold the checksum data and
230ab9b2e15Sgtb        (maybe) KRB_CRED msg */
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate     if ((data->checksum_data.data =
2337c478bd9Sstevel@tonic-gate 	 (char *) xmalloc(data->checksum_data.length)) == NULL) {
2347c478bd9Sstevel@tonic-gate 	if (credmsg.data)
235ab9b2e15Sgtb 	    krb5_free_data_contents(context, &credmsg);
2367c478bd9Sstevel@tonic-gate 	return(ENOMEM);
2377c478bd9Sstevel@tonic-gate     }
238159d09a2SMark Phalan     /* Solaris Kerberos */
239ab9b2e15Sgtb     ptr = (uchar_t *)data->checksum_data.data; /* SUNW15resync */
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->md5.length, 0);
2427c478bd9Sstevel@tonic-gate     TWRITE_STR(ptr, (unsigned char *) data->md5.contents, data->md5.length);
2437c478bd9Sstevel@tonic-gate     TWRITE_INT(ptr, data->ctx->gss_flags, 0);
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate     /* done with this, free it */
2467c478bd9Sstevel@tonic-gate     xfree(data->md5.contents);
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate     if (credmsg.data) {
2497c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, KRB5_GSS_FOR_CREDS_OPTION, 0);
2507c478bd9Sstevel@tonic-gate 	TWRITE_INT16(ptr, credmsg.length, 0);
2517c478bd9Sstevel@tonic-gate 	TWRITE_STR(ptr, (unsigned char *) credmsg.data, credmsg.length);
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate 	/* free credmsg data */
2547c478bd9Sstevel@tonic-gate 	krb5_free_data_contents(context, &credmsg);
2557c478bd9Sstevel@tonic-gate     }
2567c478bd9Sstevel@tonic-gate     if (junk)
2577c478bd9Sstevel@tonic-gate 	memset(ptr, 'i', junk);
2587c478bd9Sstevel@tonic-gate     *out = &data->checksum_data;
2597c478bd9Sstevel@tonic-gate     return 0;
2607c478bd9Sstevel@tonic-gate }
261ab9b2e15Sgtb 
2627c478bd9Sstevel@tonic-gate static krb5_error_code
2637c478bd9Sstevel@tonic-gate make_ap_req_v1(context, ctx, cred, k_cred, chan_bindings, mech_type, token)
2647c478bd9Sstevel@tonic-gate     krb5_context context;
2657c478bd9Sstevel@tonic-gate     krb5_gss_ctx_id_rec *ctx;
2667c478bd9Sstevel@tonic-gate     krb5_gss_cred_id_t cred;
2677c478bd9Sstevel@tonic-gate     krb5_creds *k_cred;
2687c478bd9Sstevel@tonic-gate     gss_channel_bindings_t chan_bindings;
2697c478bd9Sstevel@tonic-gate     gss_OID mech_type;
2707c478bd9Sstevel@tonic-gate     gss_buffer_t token;
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate     krb5_flags mk_req_flags = 0;
2737c478bd9Sstevel@tonic-gate     krb5_error_code code;
2747c478bd9Sstevel@tonic-gate     struct gss_checksum_data cksum_struct;
2757c478bd9Sstevel@tonic-gate     krb5_checksum md5;
2767c478bd9Sstevel@tonic-gate     krb5_data ap_req;
2777c478bd9Sstevel@tonic-gate     krb5_data *checksum_data = NULL;
2787c478bd9Sstevel@tonic-gate     unsigned char *ptr;
2797c478bd9Sstevel@tonic-gate     unsigned char *t;
280ab9b2e15Sgtb     unsigned int tlen;
2817c478bd9Sstevel@tonic-gate 
282ab9b2e15Sgtb     k5_mutex_assert_locked(&cred->lock);
2837c478bd9Sstevel@tonic-gate     ap_req.data = 0;
2847c478bd9Sstevel@tonic-gate 
2857c478bd9Sstevel@tonic-gate     /* compute the hash of the channel bindings */
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate     if ((code = kg_checksum_channel_bindings(context, chan_bindings, &md5, 0)))
2887c478bd9Sstevel@tonic-gate         return(code);
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate     krb5_auth_con_set_req_cksumtype(context, ctx->auth_context,
2917c478bd9Sstevel@tonic-gate 				    CKSUMTYPE_KG_CB);
2927c478bd9Sstevel@tonic-gate     cksum_struct.md5 = md5;
2937c478bd9Sstevel@tonic-gate     cksum_struct.ctx = ctx;
2947c478bd9Sstevel@tonic-gate     cksum_struct.cred = cred;
2957c478bd9Sstevel@tonic-gate     cksum_struct.checksum_data.data = NULL;
2967c478bd9Sstevel@tonic-gate     switch (k_cred->keyblock.enctype) {
2977c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_CRC:
2987c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD4:
2997c478bd9Sstevel@tonic-gate     case ENCTYPE_DES_CBC_MD5:
3007c478bd9Sstevel@tonic-gate     case ENCTYPE_DES3_CBC_SHA1:
301ab9b2e15Sgtb       code = make_gss_checksum(context, ctx->auth_context, &cksum_struct,
302ab9b2e15Sgtb 				 &checksum_data);
303ab9b2e15Sgtb 	    if (code)
3047c478bd9Sstevel@tonic-gate 		goto cleanup;
305ab9b2e15Sgtb 	break;
3067c478bd9Sstevel@tonic-gate     default:
3077c478bd9Sstevel@tonic-gate 	krb5_auth_con_set_checksum_func(context, ctx->auth_context,
308ab9b2e15Sgtb 					make_gss_checksum, &cksum_struct);
309ab9b2e15Sgtb 	    break;
3107c478bd9Sstevel@tonic-gate     }
3117c478bd9Sstevel@tonic-gate 
312ab9b2e15Sgtb 
3137c478bd9Sstevel@tonic-gate     /* call mk_req.  subkey and ap_req need to be used or destroyed */
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate     mk_req_flags = AP_OPTS_USE_SUBKEY;
3167c478bd9Sstevel@tonic-gate 
3177c478bd9Sstevel@tonic-gate     if (ctx->gss_flags & GSS_C_MUTUAL_FLAG)
3187c478bd9Sstevel@tonic-gate 	mk_req_flags |= AP_OPTS_MUTUAL_REQUIRED;
3197c478bd9Sstevel@tonic-gate 
320ab9b2e15Sgtb     code = krb5_mk_req_extended(context, &ctx->auth_context, mk_req_flags,
321ab9b2e15Sgtb 				checksum_data, k_cred, &ap_req);
322ab9b2e15Sgtb     krb5_free_data_contents(context, &cksum_struct.checksum_data);
323ab9b2e15Sgtb     if (code)
3247c478bd9Sstevel@tonic-gate 	goto cleanup;
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate    /* store the interesting stuff from creds and authent */
3277c478bd9Sstevel@tonic-gate    ctx->endtime = k_cred->times.endtime;
3287c478bd9Sstevel@tonic-gate    ctx->krb_flags = k_cred->ticket_flags;
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate    /* build up the token */
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate    /* allocate space for the token */
3337c478bd9Sstevel@tonic-gate    tlen = g_token_size((gss_OID) mech_type, ap_req.length);
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate    if ((t = (unsigned char *) xmalloc(tlen)) == NULL) {
3367c478bd9Sstevel@tonic-gate       code = ENOMEM;
3377c478bd9Sstevel@tonic-gate       goto cleanup;
3387c478bd9Sstevel@tonic-gate    }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate    /* fill in the buffer */
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate    ptr = t;
3437c478bd9Sstevel@tonic-gate 
344ab9b2e15Sgtb    g_make_token_header(mech_type, ap_req.length,
3457c478bd9Sstevel@tonic-gate 		       &ptr, KG_TOK_CTX_AP_REQ);
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate    TWRITE_STR(ptr, (unsigned char *) ap_req.data, ap_req.length);
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate    /* pass it back */
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate    token->length = tlen;
3527c478bd9Sstevel@tonic-gate    token->value = (void *) t;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate    code = 0;
355ab9b2e15Sgtb 
356ab9b2e15Sgtb  cleanup:
357ab9b2e15Sgtb    if (checksum_data && checksum_data->data)
358ab9b2e15Sgtb        krb5_free_data_contents(context, checksum_data);
3597c478bd9Sstevel@tonic-gate    if (ap_req.data)
360ab9b2e15Sgtb        krb5_free_data_contents(context, &ap_req);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate    return (code);
3637c478bd9Sstevel@tonic-gate }
3647c478bd9Sstevel@tonic-gate 
365ab9b2e15Sgtb /*
366ab9b2e15Sgtb  * setup_enc
367ab9b2e15Sgtb  *
368ab9b2e15Sgtb  * Fill in the encryption descriptors.  Called after AP-REQ is made.
369ab9b2e15Sgtb  */
370ab9b2e15Sgtb static OM_uint32
371ab9b2e15Sgtb setup_enc(
372ab9b2e15Sgtb    OM_uint32 *minor_status,
373ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx,
374ab9b2e15Sgtb    krb5_context context)
375ab9b2e15Sgtb {
376ab9b2e15Sgtb    krb5_error_code code;
377ab9b2e15Sgtb    int i;
378ab9b2e15Sgtb    krb5int_access kaccess;
3797c478bd9Sstevel@tonic-gate 
380ab9b2e15Sgtb    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
381ab9b2e15Sgtb    if (code)
382ab9b2e15Sgtb        goto fail;
3837c478bd9Sstevel@tonic-gate 
384ab9b2e15Sgtb    ctx->have_acceptor_subkey = 0;
385ab9b2e15Sgtb    ctx->proto = 0;
386ab9b2e15Sgtb    ctx->cksumtype = 0;
387ab9b2e15Sgtb    switch(ctx->subkey->enctype) {
388ab9b2e15Sgtb    case ENCTYPE_DES_CBC_MD5:
389ab9b2e15Sgtb    case ENCTYPE_DES_CBC_MD4:
390ab9b2e15Sgtb    case ENCTYPE_DES_CBC_CRC:
391ab9b2e15Sgtb       ctx->subkey->enctype = ENCTYPE_DES_CBC_RAW;
392ab9b2e15Sgtb       ctx->signalg = SGN_ALG_DES_MAC_MD5;
393ab9b2e15Sgtb       ctx->cksum_size = 8;
394ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_DES;
3957c478bd9Sstevel@tonic-gate 
396ab9b2e15Sgtb       /* The encryption key is the session key XOR
397ab9b2e15Sgtb 	 0xf0f0f0f0f0f0f0f0.  */
398ab9b2e15Sgtb       if ((code = krb5_copy_keyblock(context, ctx->subkey, &ctx->enc)))
399ab9b2e15Sgtb 	 goto fail;
4007c478bd9Sstevel@tonic-gate 
401ab9b2e15Sgtb       for (i=0; i<ctx->enc->length; i++)
402ab9b2e15Sgtb 	 ctx->enc->contents[i] ^= 0xf0;
4037c478bd9Sstevel@tonic-gate 
404ab9b2e15Sgtb       goto copy_subkey_to_seq;
4057c478bd9Sstevel@tonic-gate 
406ab9b2e15Sgtb    case ENCTYPE_DES3_CBC_SHA1:
407ab9b2e15Sgtb        /* MIT extension */
408ab9b2e15Sgtb       ctx->subkey->enctype = ENCTYPE_DES3_CBC_RAW;
409ab9b2e15Sgtb       ctx->signalg = SGN_ALG_HMAC_SHA1_DES3_KD;
410ab9b2e15Sgtb       ctx->cksum_size = 20;
411ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_DES3KD;
412ab9b2e15Sgtb 
413ab9b2e15Sgtb    copy_subkey:
414ab9b2e15Sgtb       code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc);
415ab9b2e15Sgtb       if (code)
416ab9b2e15Sgtb 	 goto fail;
417ab9b2e15Sgtb    copy_subkey_to_seq:
418ab9b2e15Sgtb       code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq);
419ab9b2e15Sgtb       if (code) {
420ab9b2e15Sgtb 	 krb5_free_keyblock (context, ctx->enc);
421ab9b2e15Sgtb 	 goto fail;
422ab9b2e15Sgtb       }
423ab9b2e15Sgtb       goto success;
424ab9b2e15Sgtb 
425ab9b2e15Sgtb    case ENCTYPE_ARCFOUR_HMAC:
426ab9b2e15Sgtb        /* Microsoft extension */
427ab9b2e15Sgtb       ctx->signalg = SGN_ALG_HMAC_MD5 ;
428ab9b2e15Sgtb       ctx->cksum_size = 8;
429ab9b2e15Sgtb       ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ;
430ab9b2e15Sgtb 
431ab9b2e15Sgtb       goto copy_subkey;
432ab9b2e15Sgtb 
433ab9b2e15Sgtb    default:
434ab9b2e15Sgtb        /* Fill some fields we shouldn't be using on this path
435ab9b2e15Sgtb 	  with garbage.  */
436ab9b2e15Sgtb        ctx->signalg = -10;
437ab9b2e15Sgtb        ctx->sealalg = -10;
438ab9b2e15Sgtb 
439ab9b2e15Sgtb        ctx->proto = 1;
440ab9b2e15Sgtb        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context, ctx->subkey->enctype,
441ab9b2e15Sgtb 					    &ctx->cksumtype);
442ab9b2e15Sgtb        if (code)
443ab9b2e15Sgtb 	   goto fail;
444ab9b2e15Sgtb        code = krb5_c_checksum_length(context, ctx->cksumtype,
445ab9b2e15Sgtb 				     &ctx->cksum_size);
446ab9b2e15Sgtb        if (code)
447ab9b2e15Sgtb 	   goto fail;
448ab9b2e15Sgtb        goto copy_subkey;
449ab9b2e15Sgtb    }
450ab9b2e15Sgtb fail:
451ab9b2e15Sgtb    /* SUNW15resync - (as in prev snv code) add if-code and success label fix */
452ab9b2e15Sgtb   if (code) {
453ab9b2e15Sgtb       *minor_status = code;
454ab9b2e15Sgtb       return GSS_S_FAILURE;
455ab9b2e15Sgtb   }
456ab9b2e15Sgtb 
457ab9b2e15Sgtb success:
458159d09a2SMark Phalan    return (GSS_S_COMPLETE);
4597c478bd9Sstevel@tonic-gate }
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate /*
462ab9b2e15Sgtb  * new_connection
463ab9b2e15Sgtb  *
464ab9b2e15Sgtb  * Do the grunt work of setting up a new context.
4657c478bd9Sstevel@tonic-gate  */
466ab9b2e15Sgtb static OM_uint32
467ab9b2e15Sgtb new_connection(
468ab9b2e15Sgtb    OM_uint32 *minor_status,
469ab9b2e15Sgtb    krb5_gss_cred_id_t cred,
470ab9b2e15Sgtb    gss_ctx_id_t *context_handle,
471ab9b2e15Sgtb    gss_name_t target_name,
472ab9b2e15Sgtb    gss_OID mech_type,
473ab9b2e15Sgtb    OM_uint32 req_flags,
474ab9b2e15Sgtb    OM_uint32 time_req,
475ab9b2e15Sgtb    gss_channel_bindings_t input_chan_bindings,
476ab9b2e15Sgtb    gss_buffer_t input_token,
477ab9b2e15Sgtb    gss_OID *actual_mech_type,
478ab9b2e15Sgtb    gss_buffer_t output_token,
479ab9b2e15Sgtb    OM_uint32 *ret_flags,
480ab9b2e15Sgtb    OM_uint32 *time_rec,
481ab9b2e15Sgtb    krb5_context context,
482ab9b2e15Sgtb    int default_mech)
4837c478bd9Sstevel@tonic-gate {
484ab9b2e15Sgtb    OM_uint32 major_status;
485ab9b2e15Sgtb    krb5_error_code code;
486ab9b2e15Sgtb    krb5_creds *k_cred;
487ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx, *ctx_free;
488ab9b2e15Sgtb    krb5_timestamp now;
489ab9b2e15Sgtb    gss_buffer_desc token;
4907c478bd9Sstevel@tonic-gate 
491ab9b2e15Sgtb    k5_mutex_assert_locked(&cred->lock);
492ab9b2e15Sgtb    major_status = GSS_S_FAILURE;
493ab9b2e15Sgtb    token.length = 0;
494ab9b2e15Sgtb    token.value = NULL;
4957c478bd9Sstevel@tonic-gate 
496ab9b2e15Sgtb    /* make sure the cred is usable for init */
4977c478bd9Sstevel@tonic-gate 
498ab9b2e15Sgtb    if ((cred->usage != GSS_C_INITIATE) &&
499ab9b2e15Sgtb        (cred->usage != GSS_C_BOTH)) {
500ab9b2e15Sgtb       *minor_status = 0;
501ab9b2e15Sgtb       return(GSS_S_NO_CRED);
502ab9b2e15Sgtb    }
5037c478bd9Sstevel@tonic-gate 
504ab9b2e15Sgtb    /* complain if the input token is non-null */
5057c478bd9Sstevel@tonic-gate 
506ab9b2e15Sgtb    if (input_token != GSS_C_NO_BUFFER && input_token->length != 0) {
507ab9b2e15Sgtb        *minor_status = 0;
508ab9b2e15Sgtb        return(GSS_S_DEFECTIVE_TOKEN);
509ab9b2e15Sgtb    }
5107c478bd9Sstevel@tonic-gate 
511ab9b2e15Sgtb    /* create the ctx */
5127c478bd9Sstevel@tonic-gate 
513ab9b2e15Sgtb    if ((ctx = (krb5_gss_ctx_id_rec *) xmalloc(sizeof(krb5_gss_ctx_id_rec)))
514ab9b2e15Sgtb        == NULL) {
515ab9b2e15Sgtb       *minor_status = ENOMEM;
516ab9b2e15Sgtb       return(GSS_S_FAILURE);
517ab9b2e15Sgtb    }
5187c478bd9Sstevel@tonic-gate 
519ab9b2e15Sgtb    /* fill in the ctx */
520ab9b2e15Sgtb    memset(ctx, 0, sizeof(krb5_gss_ctx_id_rec));
521ab9b2e15Sgtb    ctx_free = ctx;
522ab9b2e15Sgtb    if ((code = krb5_auth_con_init(context, &ctx->auth_context)))
523ab9b2e15Sgtb       goto fail;
524ab9b2e15Sgtb    krb5_auth_con_setflags(context, ctx->auth_context,
525ab9b2e15Sgtb 			  KRB5_AUTH_CONTEXT_DO_SEQUENCE);
5267c478bd9Sstevel@tonic-gate 
527ab9b2e15Sgtb    /* limit the encryption types negotiated (if requested) */
528ab9b2e15Sgtb    if (cred->req_enctypes) {
529ab9b2e15Sgtb 	if ((code = krb5_set_default_tgs_enctypes(context,
530ab9b2e15Sgtb 						  cred->req_enctypes))) {
531ab9b2e15Sgtb 	    goto fail;
5327c478bd9Sstevel@tonic-gate 	}
533ab9b2e15Sgtb    }
5347c478bd9Sstevel@tonic-gate 
535ab9b2e15Sgtb    ctx->initiate = 1;
536ab9b2e15Sgtb    ctx->gss_flags = (GSS_C_INTEG_FLAG | GSS_C_CONF_FLAG |
537ab9b2e15Sgtb                      GSS_C_TRANS_FLAG |
538ab9b2e15Sgtb                      ((req_flags) & (GSS_C_MUTUAL_FLAG | GSS_C_REPLAY_FLAG |
539ab9b2e15Sgtb                                      GSS_C_SEQUENCE_FLAG | GSS_C_DELEG_FLAG)));
540ab9b2e15Sgtb    ctx->seed_init = 0;
541ab9b2e15Sgtb    ctx->big_endian = 0;  /* all initiators do little-endian, as per spec */
542ab9b2e15Sgtb    ctx->seqstate = 0;
5437c478bd9Sstevel@tonic-gate 
544ab9b2e15Sgtb    if ((code = krb5_timeofday(context, &now)))
545ab9b2e15Sgtb       goto fail;
5467c478bd9Sstevel@tonic-gate 
547ab9b2e15Sgtb    if (time_req == 0 || time_req == GSS_C_INDEFINITE) {
548ab9b2e15Sgtb       ctx->endtime = 0;
549ab9b2e15Sgtb    } else {
550ab9b2e15Sgtb       ctx->endtime = now + time_req;
551ab9b2e15Sgtb    }
5527c478bd9Sstevel@tonic-gate 
553ab9b2e15Sgtb    if ((code = krb5_copy_principal(context, cred->princ, &ctx->here)))
554ab9b2e15Sgtb       goto fail;
555ab9b2e15Sgtb 
556ab9b2e15Sgtb    if ((code = krb5_copy_principal(context, (krb5_principal) target_name,
557ab9b2e15Sgtb 				   &ctx->there)))
558ab9b2e15Sgtb       goto fail;
5597c478bd9Sstevel@tonic-gate 
560ab9b2e15Sgtb    code = get_credentials(context, cred, ctx->there, now,
561ab9b2e15Sgtb 			  ctx->endtime, &k_cred);
562ab9b2e15Sgtb    if (code)
563ab9b2e15Sgtb       goto fail;
5647c478bd9Sstevel@tonic-gate 
565ab9b2e15Sgtb    if (default_mech) {
566ab9b2e15Sgtb       mech_type = (gss_OID) gss_mech_krb5;
567ab9b2e15Sgtb    }
5687c478bd9Sstevel@tonic-gate 
569ab9b2e15Sgtb    if (generic_gss_copy_oid(minor_status, mech_type, &ctx->mech_used)
570ab9b2e15Sgtb        != GSS_S_COMPLETE) {
571ab9b2e15Sgtb       code = *minor_status;
572ab9b2e15Sgtb       goto fail;
573ab9b2e15Sgtb    }
574ab9b2e15Sgtb    /*
575ab9b2e15Sgtb     * Now try to make it static if at all possible....
576ab9b2e15Sgtb     */
577ab9b2e15Sgtb    ctx->mech_used = krb5_gss_convert_static_mech_oid(ctx->mech_used);
5787c478bd9Sstevel@tonic-gate 
579ab9b2e15Sgtb    {
580ab9b2e15Sgtb       /* gsskrb5 v1 */
581ab9b2e15Sgtb       krb5_ui_4 seq_temp;
582ab9b2e15Sgtb       if ((code = make_ap_req_v1(context, ctx,
583ab9b2e15Sgtb 				 cred, k_cred, input_chan_bindings,
584ab9b2e15Sgtb 				 mech_type, &token))) {
585ab9b2e15Sgtb 	 if ((code == KRB5_FCC_NOFILE) || (code == KRB5_CC_NOTFOUND) ||
586ab9b2e15Sgtb 	     (code == KG_EMPTY_CCACHE))
587ab9b2e15Sgtb 	    major_status = GSS_S_NO_CRED;
588ab9b2e15Sgtb 	 if (code == KRB5KRB_AP_ERR_TKT_EXPIRED)
589ab9b2e15Sgtb 	    major_status = GSS_S_CREDENTIALS_EXPIRED;
590ab9b2e15Sgtb 	 goto fail;
591ab9b2e15Sgtb       }
5927c478bd9Sstevel@tonic-gate 
593ab9b2e15Sgtb       krb5_auth_con_getlocalseqnumber(context, ctx->auth_context,
594ab9b2e15Sgtb 			    (krb5_int32 *)&seq_temp); /* SUNW15resync */
595ab9b2e15Sgtb       ctx->seq_send = seq_temp;
596ab9b2e15Sgtb       krb5_auth_con_getsendsubkey(context, ctx->auth_context,
597ab9b2e15Sgtb 				  &ctx->subkey);
598ab9b2e15Sgtb    }
5997c478bd9Sstevel@tonic-gate 
600ab9b2e15Sgtb    major_status = setup_enc(minor_status, ctx, context);
6017c478bd9Sstevel@tonic-gate 
602ab9b2e15Sgtb    if (k_cred) {
603ab9b2e15Sgtb       krb5_free_creds(context, k_cred);
604ab9b2e15Sgtb       k_cred = 0;
605ab9b2e15Sgtb    }
606ab9b2e15Sgtb 
607ab9b2e15Sgtb    /* at this point, the context is constructed and valid,
608ab9b2e15Sgtb       hence, releaseable */
6097c478bd9Sstevel@tonic-gate 
610ab9b2e15Sgtb    /* intern the context handle */
6117c478bd9Sstevel@tonic-gate 
612ab9b2e15Sgtb    if (! kg_save_ctx_id((gss_ctx_id_t) ctx)) {
613ab9b2e15Sgtb       code = G_VALIDATE_FAILED;
614ab9b2e15Sgtb       goto fail;
615ab9b2e15Sgtb    }
616ab9b2e15Sgtb    *context_handle = (gss_ctx_id_t) ctx;
617ab9b2e15Sgtb    ctx_free = 0;
6187c478bd9Sstevel@tonic-gate 
619ab9b2e15Sgtb    /* compute time_rec */
620ab9b2e15Sgtb    if (time_rec) {
621ab9b2e15Sgtb       if ((code = krb5_timeofday(context, &now)))
622ab9b2e15Sgtb 	 goto fail;
623ab9b2e15Sgtb       *time_rec = ctx->endtime - now;
624ab9b2e15Sgtb    }
6257c478bd9Sstevel@tonic-gate 
626ab9b2e15Sgtb    /* set the other returns */
627ab9b2e15Sgtb    *output_token = token;
6287c478bd9Sstevel@tonic-gate 
629ab9b2e15Sgtb    if (ret_flags)
630ab9b2e15Sgtb       *ret_flags = ctx->gss_flags;
6317c478bd9Sstevel@tonic-gate 
632ab9b2e15Sgtb    if (actual_mech_type)
633ab9b2e15Sgtb       *actual_mech_type = mech_type;
6347c478bd9Sstevel@tonic-gate 
635ab9b2e15Sgtb    /* return successfully */
6367c478bd9Sstevel@tonic-gate 
637ab9b2e15Sgtb    *minor_status = 0;
638ab9b2e15Sgtb    if (ctx->gss_flags & GSS_C_MUTUAL_FLAG) {
639ab9b2e15Sgtb       ctx->established = 0;
640ab9b2e15Sgtb       return(GSS_S_CONTINUE_NEEDED);
641ab9b2e15Sgtb    } else {
642ab9b2e15Sgtb       ctx->seq_recv = ctx->seq_send;
643ab9b2e15Sgtb       g_order_init(&(ctx->seqstate), ctx->seq_recv,
644ab9b2e15Sgtb 		   (ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
645ab9b2e15Sgtb 		   (ctx->gss_flags & GSS_C_SEQUENCE_FLAG) != 0, ctx->proto);
646ab9b2e15Sgtb       ctx->gss_flags |= GSS_C_PROT_READY_FLAG;
647ab9b2e15Sgtb       ctx->established = 1;
648ab9b2e15Sgtb       return(GSS_S_COMPLETE);
649ab9b2e15Sgtb    }
6507c478bd9Sstevel@tonic-gate 
651ab9b2e15Sgtb fail:
652ab9b2e15Sgtb    if (ctx_free) {
653ab9b2e15Sgtb        if (ctx_free->auth_context)
654ab9b2e15Sgtb 	   krb5_auth_con_free(context, ctx_free->auth_context);
655ab9b2e15Sgtb        if (ctx_free->here)
656ab9b2e15Sgtb 	   krb5_free_principal(context, ctx_free->here);
657ab9b2e15Sgtb        if (ctx_free->there)
658ab9b2e15Sgtb 	   krb5_free_principal(context, ctx_free->there);
659ab9b2e15Sgtb        if (ctx_free->subkey)
660ab9b2e15Sgtb 	   krb5_free_keyblock(context, ctx_free->subkey);
661ab9b2e15Sgtb        xfree(ctx_free);
662ab9b2e15Sgtb    } else
663ab9b2e15Sgtb 	(void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
664ab9b2e15Sgtb 
665ab9b2e15Sgtb    *minor_status = code;
666ab9b2e15Sgtb    return (major_status);
6677c478bd9Sstevel@tonic-gate }
6687c478bd9Sstevel@tonic-gate 
669ab9b2e15Sgtb /*
670ab9b2e15Sgtb  * mutual_auth
671ab9b2e15Sgtb  *
672ab9b2e15Sgtb  * Handle the reply from the acceptor, if we're doing mutual auth.
673ab9b2e15Sgtb  */
6747c478bd9Sstevel@tonic-gate static OM_uint32
675ab9b2e15Sgtb mutual_auth(
676ab9b2e15Sgtb    OM_uint32 *minor_status,
677ab9b2e15Sgtb    gss_ctx_id_t *context_handle,
678ab9b2e15Sgtb    gss_name_t target_name,
679ab9b2e15Sgtb    gss_OID mech_type,
680ab9b2e15Sgtb    OM_uint32 req_flags,
681ab9b2e15Sgtb    OM_uint32 time_req,
682ab9b2e15Sgtb    gss_channel_bindings_t input_chan_bindings,
683ab9b2e15Sgtb    gss_buffer_t input_token,
684ab9b2e15Sgtb    gss_OID *actual_mech_type,
685ab9b2e15Sgtb    gss_buffer_t output_token,
686ab9b2e15Sgtb    OM_uint32 *ret_flags,
687ab9b2e15Sgtb    OM_uint32 *time_rec,
688ab9b2e15Sgtb    krb5_context context)
6897c478bd9Sstevel@tonic-gate {
690ab9b2e15Sgtb    OM_uint32 major_status;
691ab9b2e15Sgtb    unsigned char *ptr;
692ab9b2e15Sgtb    char *sptr;
693ab9b2e15Sgtb    krb5_data ap_rep;
694ab9b2e15Sgtb    krb5_ap_rep_enc_part *ap_rep_data;
695ab9b2e15Sgtb    krb5_timestamp now;
696ab9b2e15Sgtb    krb5_gss_ctx_id_rec *ctx;
697ab9b2e15Sgtb    krb5_error *krb_error;
698ab9b2e15Sgtb    krb5_error_code code;
699ab9b2e15Sgtb    krb5int_access kaccess;
7007c478bd9Sstevel@tonic-gate 
701ab9b2e15Sgtb    major_status = GSS_S_FAILURE;
7027c478bd9Sstevel@tonic-gate 
703ab9b2e15Sgtb    code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION);
704ab9b2e15Sgtb    if (code)
705ab9b2e15Sgtb        goto fail;
7067c478bd9Sstevel@tonic-gate 
707ab9b2e15Sgtb    /* validate the context handle */
708ab9b2e15Sgtb    /*SUPPRESS 29*/
709ab9b2e15Sgtb    if (! kg_validate_ctx_id(*context_handle)) {
710ab9b2e15Sgtb       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
711ab9b2e15Sgtb       return(GSS_S_NO_CONTEXT);
712ab9b2e15Sgtb    }
7137c478bd9Sstevel@tonic-gate 
714159d09a2SMark Phalan    ctx = (krb5_gss_ctx_id_t) *context_handle;
7157c478bd9Sstevel@tonic-gate 
716ab9b2e15Sgtb    /* make sure the context is non-established, and that certain
717ab9b2e15Sgtb       arguments are unchanged */
7187c478bd9Sstevel@tonic-gate 
719ab9b2e15Sgtb    if ((ctx->established) ||
720ab9b2e15Sgtb        ((ctx->gss_flags & GSS_C_MUTUAL_FLAG) == 0)) {
721ab9b2e15Sgtb       code = KG_CONTEXT_ESTABLISHED;
722ab9b2e15Sgtb       goto fail;
723ab9b2e15Sgtb    }
724fe598cdcSmp 
725ab9b2e15Sgtb    if (! krb5_principal_compare(context, ctx->there,
726ab9b2e15Sgtb 				(krb5_principal) target_name)) {
727ab9b2e15Sgtb       (void)krb5_gss_delete_sec_context(minor_status,
728ab9b2e15Sgtb 					context_handle, NULL);
729ab9b2e15Sgtb       code = 0;
730ab9b2e15Sgtb       major_status = GSS_S_BAD_NAME;
731ab9b2e15Sgtb       goto fail;
732ab9b2e15Sgtb    }
733fe598cdcSmp 
734ab9b2e15Sgtb    /* verify the token and leave the AP_REP message in ap_rep */
735fe598cdcSmp 
736ab9b2e15Sgtb    if (input_token == GSS_C_NO_BUFFER) {
737ab9b2e15Sgtb       (void)krb5_gss_delete_sec_context(minor_status,
738ab9b2e15Sgtb 					context_handle, NULL);
739ab9b2e15Sgtb       code = 0;
740ab9b2e15Sgtb       major_status = GSS_S_DEFECTIVE_TOKEN;
741ab9b2e15Sgtb       goto fail;
742ab9b2e15Sgtb    }
743fe598cdcSmp 
744ab9b2e15Sgtb    ptr = (unsigned char *) input_token->value;
7457c478bd9Sstevel@tonic-gate 
746ab9b2e15Sgtb    if (g_verify_token_header(ctx->mech_used,
747ab9b2e15Sgtb 			     &(ap_rep.length),
748ab9b2e15Sgtb 			     &ptr, KG_TOK_CTX_AP_REP,
749ab9b2e15Sgtb 			     input_token->length, 1)) {
750ab9b2e15Sgtb       if (g_verify_token_header((gss_OID) ctx->mech_used,
751ab9b2e15Sgtb 				&(ap_rep.length),
752ab9b2e15Sgtb 				&ptr, KG_TOK_CTX_ERROR,
753ab9b2e15Sgtb 				input_token->length, 1) == 0) {
7547c478bd9Sstevel@tonic-gate 
755ab9b2e15Sgtb 	 /* Handle a KRB_ERROR message from the server */
7567c478bd9Sstevel@tonic-gate 
757ab9b2e15Sgtb 	 sptr = (char *) ptr;           /* PC compiler bug */
758ab9b2e15Sgtb 	 TREAD_STR(sptr, ap_rep.data, ap_rep.length);
759ab9b2e15Sgtb 
760ab9b2e15Sgtb 	 code = krb5_rd_error(context, &ap_rep, &krb_error);
761ab9b2e15Sgtb 	 if (code)
762ab9b2e15Sgtb 	    goto fail;
763ab9b2e15Sgtb 	 if (krb_error->error)
764ab9b2e15Sgtb 	    code = krb_error->error + ERROR_TABLE_BASE_krb5;
765ab9b2e15Sgtb 	 else
766ab9b2e15Sgtb 	    code = 0;
767ab9b2e15Sgtb 	 krb5_free_error(context, krb_error);
768ab9b2e15Sgtb 	 goto fail;
769ab9b2e15Sgtb       } else {
770ab9b2e15Sgtb 	 *minor_status = 0;
771ab9b2e15Sgtb 	 return(GSS_S_DEFECTIVE_TOKEN);
772ab9b2e15Sgtb       }
773ab9b2e15Sgtb    }
7747c478bd9Sstevel@tonic-gate 
775ab9b2e15Sgtb    sptr = (char *) ptr;                      /* PC compiler bug */
776ab9b2e15Sgtb    TREAD_STR(sptr, ap_rep.data, ap_rep.length);
7777c478bd9Sstevel@tonic-gate 
778ab9b2e15Sgtb    /* decode the ap_rep */
779ab9b2e15Sgtb    if ((code = krb5_rd_rep(context, ctx->auth_context, &ap_rep,
780ab9b2e15Sgtb 			   &ap_rep_data))) {
781ab9b2e15Sgtb       /*
782ab9b2e15Sgtb        * XXX A hack for backwards compatiblity.
783ab9b2e15Sgtb        * To be removed in 1999 -- proven
784ab9b2e15Sgtb        */
785ab9b2e15Sgtb       krb5_auth_con_setuseruserkey(context, ctx->auth_context,
786ab9b2e15Sgtb 				   ctx->subkey);
787ab9b2e15Sgtb       if ((krb5_rd_rep(context, ctx->auth_context, &ap_rep,
788ab9b2e15Sgtb 		       &ap_rep_data)))
789ab9b2e15Sgtb 	 goto fail;
790ab9b2e15Sgtb    }
7917c478bd9Sstevel@tonic-gate 
792ab9b2e15Sgtb    /* store away the sequence number */
793ab9b2e15Sgtb    ctx->seq_recv = ap_rep_data->seq_number;
794ab9b2e15Sgtb    g_order_init(&(ctx->seqstate), ctx->seq_recv,
795ab9b2e15Sgtb 		(ctx->gss_flags & GSS_C_REPLAY_FLAG) != 0,
796ab9b2e15Sgtb 		(ctx->gss_flags & GSS_C_SEQUENCE_FLAG) !=0, ctx->proto);
7977c478bd9Sstevel@tonic-gate 
798ab9b2e15Sgtb    if (ctx->proto == 1 && ap_rep_data->subkey) {
799ab9b2e15Sgtb        /* Keep acceptor's subkey.  */
800ab9b2e15Sgtb        ctx->have_acceptor_subkey = 1;
801ab9b2e15Sgtb        code = krb5_copy_keyblock(context, ap_rep_data->subkey,
802ab9b2e15Sgtb 				 &ctx->acceptor_subkey);
803ab9b2e15Sgtb        if (code)
804ab9b2e15Sgtb 	   goto fail;
805ab9b2e15Sgtb        code = (*kaccess.krb5int_c_mandatory_cksumtype)(context,
806ab9b2e15Sgtb 					    ctx->acceptor_subkey->enctype,
807ab9b2e15Sgtb 					    &ctx->acceptor_subkey_cksumtype);
808ab9b2e15Sgtb        if (code)
809ab9b2e15Sgtb 	   goto fail;
810ab9b2e15Sgtb    }
8117c478bd9Sstevel@tonic-gate 
812ab9b2e15Sgtb    /* free the ap_rep_data */
813ab9b2e15Sgtb    krb5_free_ap_rep_enc_part(context, ap_rep_data);
8147c478bd9Sstevel@tonic-gate 
815ab9b2e15Sgtb    /* set established */
816ab9b2e15Sgtb    ctx->established = 1;
8177c478bd9Sstevel@tonic-gate 
818ab9b2e15Sgtb    /* set returns */
8197c478bd9Sstevel@tonic-gate 
820ab9b2e15Sgtb    if (time_rec) {
821ab9b2e15Sgtb       if ((code = krb5_timeofday(context, &now)))
822ab9b2e15Sgtb 	 goto fail;
823ab9b2e15Sgtb       *time_rec = ctx->endtime - now;
824ab9b2e15Sgtb    }
8257c478bd9Sstevel@tonic-gate 
826ab9b2e15Sgtb    if (ret_flags)
827ab9b2e15Sgtb       *ret_flags = ctx->gss_flags;
8287c478bd9Sstevel@tonic-gate 
829ab9b2e15Sgtb    if (actual_mech_type)
830ab9b2e15Sgtb       *actual_mech_type = mech_type;
8317c478bd9Sstevel@tonic-gate 
832ab9b2e15Sgtb    /* success */
8337c478bd9Sstevel@tonic-gate 
834ab9b2e15Sgtb    *minor_status = 0;
835ab9b2e15Sgtb    return GSS_S_COMPLETE;
8367c478bd9Sstevel@tonic-gate 
837ab9b2e15Sgtb fail:
838ab9b2e15Sgtb    (void)krb5_gss_delete_sec_context(minor_status, context_handle, NULL);
8397c478bd9Sstevel@tonic-gate 
840ab9b2e15Sgtb    *minor_status = code;
841ab9b2e15Sgtb    return (major_status);
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate 
844ab9b2e15Sgtb OM_uint32
845ab9b2e15Sgtb krb5_gss_init_sec_context(minor_status, claimant_cred_handle,
846ab9b2e15Sgtb 			  context_handle, target_name, mech_type,
847ab9b2e15Sgtb 			  req_flags, time_req, input_chan_bindings,
848ab9b2e15Sgtb 			  input_token, actual_mech_type, output_token,
849ab9b2e15Sgtb 			  ret_flags, time_rec)
850ab9b2e15Sgtb     OM_uint32 *minor_status;
851ab9b2e15Sgtb     gss_cred_id_t claimant_cred_handle;
852ab9b2e15Sgtb     gss_ctx_id_t *context_handle;
853ab9b2e15Sgtb     gss_name_t target_name;
854ab9b2e15Sgtb     gss_OID mech_type;
855ab9b2e15Sgtb     OM_uint32 req_flags;
856ab9b2e15Sgtb     OM_uint32 time_req;
857ab9b2e15Sgtb     gss_channel_bindings_t input_chan_bindings;
858ab9b2e15Sgtb     gss_buffer_t input_token;
859ab9b2e15Sgtb     gss_OID *actual_mech_type;
860ab9b2e15Sgtb     gss_buffer_t output_token;
861ab9b2e15Sgtb     OM_uint32 *ret_flags;
862ab9b2e15Sgtb     OM_uint32 *time_rec;
8637c478bd9Sstevel@tonic-gate {
864ab9b2e15Sgtb    krb5_context context;
865ab9b2e15Sgtb    krb5_gss_cred_id_t cred;
866ab9b2e15Sgtb    int err;
867ab9b2e15Sgtb    krb5_error_code kerr;
868ab9b2e15Sgtb    int default_mech = 0;
869ab9b2e15Sgtb    OM_uint32 major_status;
870ab9b2e15Sgtb    OM_uint32 tmp_min_stat;
8717c478bd9Sstevel@tonic-gate 
872ab9b2e15Sgtb    if (*context_handle == GSS_C_NO_CONTEXT) {
873ab9b2e15Sgtb        kerr = krb5_gss_init_context(&context);
874ab9b2e15Sgtb        if (kerr) {
875ab9b2e15Sgtb 	   *minor_status = kerr;
876ab9b2e15Sgtb 	   return GSS_S_FAILURE;
877ab9b2e15Sgtb        }
878ab9b2e15Sgtb        if (GSS_ERROR(kg_sync_ccache_name(context, minor_status)))
879ab9b2e15Sgtb 	   return GSS_S_FAILURE;
880ab9b2e15Sgtb    } else {
881ab9b2e15Sgtb        context = ((krb5_gss_ctx_id_rec *)*context_handle)->k5_context;
882ab9b2e15Sgtb    }
8837c478bd9Sstevel@tonic-gate 
884ab9b2e15Sgtb    /* set up return values so they can be "freed" successfully */
8857c478bd9Sstevel@tonic-gate 
886ab9b2e15Sgtb    major_status = GSS_S_FAILURE; /* Default major code */
887ab9b2e15Sgtb    output_token->length = 0;
888ab9b2e15Sgtb    output_token->value = NULL;
889ab9b2e15Sgtb    if (actual_mech_type)
890ab9b2e15Sgtb       *actual_mech_type = NULL;
8917c478bd9Sstevel@tonic-gate 
892ab9b2e15Sgtb    /* verify that the target_name is valid and usable */
8937c478bd9Sstevel@tonic-gate 
894ab9b2e15Sgtb    if (! kg_validate_name(target_name)) {
895ab9b2e15Sgtb       *minor_status = (OM_uint32) G_VALIDATE_FAILED;
896ab9b2e15Sgtb       if (*context_handle == GSS_C_NO_CONTEXT)
897ab9b2e15Sgtb 	  krb5_free_context(context);
898ab9b2e15Sgtb       return(GSS_S_CALL_BAD_STRUCTURE|GSS_S_BAD_NAME);
899ab9b2e15Sgtb    }
9007c478bd9Sstevel@tonic-gate 
901ab9b2e15Sgtb    /* verify the credential, or use the default */
902ab9b2e15Sgtb    /*SUPPRESS 29*/
903ab9b2e15Sgtb    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) {
904ab9b2e15Sgtb       /*
905ab9b2e15Sgtb        * Solaris Kerberos: here we are using the Solaris specific
906ab9b2e15Sgtb        * function get_default_cred() to handle the special case of a
907ab9b2e15Sgtb        * root principal
908ab9b2e15Sgtb        */
909ab9b2e15Sgtb       major_status = get_default_cred(minor_status, context,
910ab9b2e15Sgtb 				    (gss_cred_id_t *)&cred);
911ab9b2e15Sgtb       if (major_status && GSS_ERROR(major_status)) {
912ab9b2e15Sgtb 	 if (*context_handle == GSS_C_NO_CONTEXT)
913ab9b2e15Sgtb 	    krb5_free_context(context);
914ab9b2e15Sgtb 	 return(major_status);
915ab9b2e15Sgtb       }
916ab9b2e15Sgtb    } else {
917ab9b2e15Sgtb       major_status = krb5_gss_validate_cred(minor_status, claimant_cred_handle);
918ab9b2e15Sgtb       if (GSS_ERROR(major_status)) {
919ab9b2e15Sgtb 	  if (*context_handle == GSS_C_NO_CONTEXT)
920ab9b2e15Sgtb 	      krb5_free_context(context);
921ab9b2e15Sgtb 	  return(major_status);
922ab9b2e15Sgtb       }
923ab9b2e15Sgtb       cred = (krb5_gss_cred_id_t) claimant_cred_handle;
924ab9b2e15Sgtb    }
925ab9b2e15Sgtb    kerr = k5_mutex_lock(&cred->lock);
926ab9b2e15Sgtb    if (kerr) {
927ab9b2e15Sgtb        krb5_free_context(context);
928ab9b2e15Sgtb        *minor_status = kerr;
929ab9b2e15Sgtb        return GSS_S_FAILURE;
930ab9b2e15Sgtb    }
9317c478bd9Sstevel@tonic-gate 
932ab9b2e15Sgtb    /* verify the mech_type */
9337c478bd9Sstevel@tonic-gate 
934ab9b2e15Sgtb    err = 0;
935ab9b2e15Sgtb    if (mech_type == GSS_C_NULL_OID) {
936ab9b2e15Sgtb        default_mech = 1;
937ab9b2e15Sgtb        if (cred->rfc_mech) {
938ab9b2e15Sgtb 	   mech_type = (gss_OID) gss_mech_krb5;
939ab9b2e15Sgtb        } else if (cred->prerfc_mech) {
940ab9b2e15Sgtb 	   mech_type = (gss_OID) gss_mech_krb5_old;
941ab9b2e15Sgtb        } else {
942ab9b2e15Sgtb 	   err = 1;
943ab9b2e15Sgtb        }
944ab9b2e15Sgtb    } else if (g_OID_equal(mech_type, gss_mech_krb5)) {
945ab9b2e15Sgtb        if (!cred->rfc_mech)
946ab9b2e15Sgtb 	   err = 1;
947ab9b2e15Sgtb    } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) {
948ab9b2e15Sgtb        if (!cred->prerfc_mech)
949ab9b2e15Sgtb 	   err = 1;
950ab9b2e15Sgtb    } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) {
951ab9b2e15Sgtb        if (!cred->rfc_mech)
952ab9b2e15Sgtb 	   err = 1;
953ab9b2e15Sgtb    } else {
954ab9b2e15Sgtb        err = 1;
955ab9b2e15Sgtb    }
956ab9b2e15Sgtb 
957ab9b2e15Sgtb    if (err) {
958ab9b2e15Sgtb       k5_mutex_unlock(&cred->lock);
959ab9b2e15Sgtb       if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
960ab9b2e15Sgtb 	 krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred);
961ab9b2e15Sgtb       *minor_status = 0;
962ab9b2e15Sgtb       if (*context_handle == GSS_C_NO_CONTEXT)
963ab9b2e15Sgtb 	 krb5_free_context(context);
964ab9b2e15Sgtb       return(GSS_S_BAD_MECH);
965ab9b2e15Sgtb    }
9667c478bd9Sstevel@tonic-gate 
967ab9b2e15Sgtb    /* is this a new connection or not? */
9687c478bd9Sstevel@tonic-gate 
969ab9b2e15Sgtb    /*SUPPRESS 29*/
970ab9b2e15Sgtb    if (*context_handle == GSS_C_NO_CONTEXT) {
971ab9b2e15Sgtb       major_status = new_connection(minor_status, cred, context_handle,
972ab9b2e15Sgtb 				    target_name, mech_type, req_flags,
973ab9b2e15Sgtb 				    time_req, input_chan_bindings,
974ab9b2e15Sgtb 				    input_token, actual_mech_type,
975ab9b2e15Sgtb 				    output_token, ret_flags, time_rec,
976ab9b2e15Sgtb 				    context, default_mech);
977ab9b2e15Sgtb       k5_mutex_unlock(&cred->lock);
978ab9b2e15Sgtb       if (*context_handle == GSS_C_NO_CONTEXT)
979ab9b2e15Sgtb 	  krb5_free_context(context);
980ab9b2e15Sgtb       else
981ab9b2e15Sgtb 	  ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context;
982ab9b2e15Sgtb    } else {
983ab9b2e15Sgtb       /* mutual_auth doesn't care about the credentials */
984ab9b2e15Sgtb       k5_mutex_unlock(&cred->lock);
985ab9b2e15Sgtb       major_status = mutual_auth(minor_status, context_handle,
986ab9b2e15Sgtb 				 target_name, mech_type, req_flags,
987ab9b2e15Sgtb 				 time_req, input_chan_bindings,
988ab9b2e15Sgtb 				 input_token, actual_mech_type,
989ab9b2e15Sgtb 				 output_token, ret_flags, time_rec,
990ab9b2e15Sgtb 				 context);
991ab9b2e15Sgtb       /* If context_handle is now NO_CONTEXT, mutual_auth called
992ab9b2e15Sgtb 	 delete_sec_context, which would've zapped the krb5 context
993ab9b2e15Sgtb 	 too.  */
994ab9b2e15Sgtb    }
9957c478bd9Sstevel@tonic-gate 
996ab9b2e15Sgtb    if (claimant_cred_handle == GSS_C_NO_CREDENTIAL)
997ab9b2e15Sgtb       krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred);
9987c478bd9Sstevel@tonic-gate 
999ab9b2e15Sgtb    return(major_status);
10007c478bd9Sstevel@tonic-gate }
10017c478bd9Sstevel@tonic-gate 
1002159d09a2SMark Phalan #ifndef _WIN32
1003ab9b2e15Sgtb k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER;
1004ab9b2e15Sgtb static int kdc_flag = 0;
1005ab9b2e15Sgtb #endif
10067c478bd9Sstevel@tonic-gate 
1007ab9b2e15Sgtb krb5_error_code
1008ab9b2e15Sgtb krb5_gss_init_context (krb5_context *ctxp)
10097c478bd9Sstevel@tonic-gate {
1010ab9b2e15Sgtb     krb5_error_code err;
1011159d09a2SMark Phalan #ifndef _WIN32
1012ab9b2e15Sgtb     int is_kdc;
1013159d09a2SMark Phalan #endif
1014ab9b2e15Sgtb 
1015ab9b2e15Sgtb     err = gssint_initialize_library();
1016ab9b2e15Sgtb     if (err)
1017ab9b2e15Sgtb 	return err;
1018159d09a2SMark Phalan #ifndef _WIN32
1019ab9b2e15Sgtb     err = k5_mutex_lock(&kg_kdc_flag_mutex);
1020ab9b2e15Sgtb     if (err)
1021ab9b2e15Sgtb 	return err;
1022ab9b2e15Sgtb     is_kdc = kdc_flag;
1023ab9b2e15Sgtb     k5_mutex_unlock(&kg_kdc_flag_mutex);
1024ab9b2e15Sgtb 
1025ab9b2e15Sgtb     if (is_kdc)
1026ab9b2e15Sgtb 	return krb5int_init_context_kdc(ctxp);
1027ab9b2e15Sgtb #endif
10287c478bd9Sstevel@tonic-gate 
1029159d09a2SMark Phalan     return krb5_init_context(ctxp);
1030ab9b2e15Sgtb }
10317c478bd9Sstevel@tonic-gate 
1032159d09a2SMark Phalan #ifndef _WIN32
1033ab9b2e15Sgtb krb5_error_code
1034ab9b2e15Sgtb krb5_gss_use_kdc_context()
1035ab9b2e15Sgtb {
1036ab9b2e15Sgtb     krb5_error_code err;
1037ab9b2e15Sgtb 
1038ab9b2e15Sgtb     err = gssint_initialize_library();
1039ab9b2e15Sgtb     if (err)
1040ab9b2e15Sgtb 	return err;
1041ab9b2e15Sgtb     err = k5_mutex_lock(&kg_kdc_flag_mutex);
1042ab9b2e15Sgtb     if (err)
1043ab9b2e15Sgtb 	return err;
1044ab9b2e15Sgtb     kdc_flag = 1;
1045ab9b2e15Sgtb     k5_mutex_unlock(&kg_kdc_flag_mutex);
1046ab9b2e15Sgtb     return 0;
1047ab9b2e15Sgtb }
1048ab9b2e15Sgtb #endif
10497c478bd9Sstevel@tonic-gate 
1050ab9b2e15Sgtb /* Solaris Kerberos specific routines start */
10517c478bd9Sstevel@tonic-gate 
1052ab9b2e15Sgtb #define ROOT_UID 0
1053ab9b2e15Sgtb #define KRB5_DEFAULT_LIFE 60*60*10
1054ab9b2e15Sgtb #define CACHE_FILENAME_LEN 35
10557c478bd9Sstevel@tonic-gate 
1056ab9b2e15Sgtb extern int
1057ab9b2e15Sgtb safechown(const char *src, uid_t uid, gid_t gid, int mode);
10587c478bd9Sstevel@tonic-gate 
1059ab9b2e15Sgtb static krb5_boolean
1060ab9b2e15Sgtb principal_ignore_inst_compare(context, princ1, princ2)
1061ab9b2e15Sgtb     krb5_context context;
1062ab9b2e15Sgtb     krb5_const_principal princ1;
1063ab9b2e15Sgtb     krb5_const_principal princ2;
1064ab9b2e15Sgtb {
1065ab9b2e15Sgtb     krb5_int32 nelem;
10667c478bd9Sstevel@tonic-gate 
1067ab9b2e15Sgtb     nelem = krb5_princ_size(context, princ1);
1068ab9b2e15Sgtb     if (nelem != krb5_princ_size(context, princ2))
1069ab9b2e15Sgtb 	return FALSE;
10707c478bd9Sstevel@tonic-gate 
1071*db02be57S     /*
1072*db02be57S      * Solaris Kerberos:
1073*db02be57S      * Don't bother to compare the realms as princ1 will always have a
1074*db02be57S      * referral realm set.
1075*db02be57S      */
10767c478bd9Sstevel@tonic-gate 
1077ab9b2e15Sgtb     /*
1078ab9b2e15Sgtb      * Solaris Kerberos
1079ab9b2e15Sgtb      * If princ1 is elem1/metachar@REALM, compare just elem1 (and REALM).
1080ab9b2e15Sgtb      */
1081ab9b2e15Sgtb     if (nelem == 2) {
1082ab9b2e15Sgtb         const krb5_data *p = krb5_princ_component(context, princ1, 1);
1083ab9b2e15Sgtb 
1084ab9b2e15Sgtb 	if (p->length == 1) {
1085ab9b2e15Sgtb 	    const char *s = p->data;
10867c478bd9Sstevel@tonic-gate 
1087ab9b2e15Sgtb 	    if (s[0] == '*') {
1088ab9b2e15Sgtb 		const krb5_data *p1 = krb5_princ_component(context, princ1, 0);
1089ab9b2e15Sgtb 		const krb5_data *p2 = krb5_princ_component(context, princ2, 0);
10907c478bd9Sstevel@tonic-gate 
1091ab9b2e15Sgtb 		if (p1->length != p2->length ||
1092ab9b2e15Sgtb 		        memcmp(p1->data, p2->data, p1->length))
1093ab9b2e15Sgtb 		    return FALSE;
1094ab9b2e15Sgtb 
1095ab9b2e15Sgtb 		return TRUE;
1096ab9b2e15Sgtb 	    }
1097ab9b2e15Sgtb 	}
1098ab9b2e15Sgtb     }
1099ab9b2e15Sgtb 
1100ab9b2e15Sgtb     return FALSE;
1101ab9b2e15Sgtb }
11027c478bd9Sstevel@tonic-gate 
1103ab9b2e15Sgtb /*
1104ab9b2e15Sgtb  * Solaris Kerberos
1105ab9b2e15Sgtb  * This is a dup of krb5_ktfile_get_entry (sigh) but is necessary to
1106ab9b2e15Sgtb  * to get a custom princ compare above (principal_ignore_inst_compare)
1107ab9b2e15Sgtb  * and thus avoid mucking w/important krb5 internal
1108ab9b2e15Sgtb  * api (krb5_principal_compare)
1109ab9b2e15Sgtb  */
1110ab9b2e15Sgtb #include "../krb5/keytab/file/ktfile.h"
11117c478bd9Sstevel@tonic-gate 
1112ab9b2e15Sgtb static krb5_error_code KRB5_CALLCONV
1113ab9b2e15Sgtb ktfile_get_entry(context, id, principal, kvno, enctype, entry)
1114ab9b2e15Sgtb    krb5_context context;
1115ab9b2e15Sgtb    krb5_keytab id;
1116ab9b2e15Sgtb    krb5_const_principal principal;
1117ab9b2e15Sgtb    krb5_kvno kvno;
1118ab9b2e15Sgtb    krb5_enctype enctype;
1119ab9b2e15Sgtb    krb5_keytab_entry * entry;
1120ab9b2e15Sgtb {
1121ab9b2e15Sgtb     krb5_keytab_entry cur_entry, new_entry;
1122ab9b2e15Sgtb     krb5_error_code kerror = 0;
1123ab9b2e15Sgtb     int found_wrong_kvno = 0;
1124ab9b2e15Sgtb     krb5_boolean similar;
1125ab9b2e15Sgtb     int kvno_offset = 0;
11267c478bd9Sstevel@tonic-gate 
1127ab9b2e15Sgtb     KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() start\n");
11287c478bd9Sstevel@tonic-gate 
1129ab9b2e15Sgtb     /* Open the keyfile for reading */
1130ab9b2e15Sgtb     if ((kerror = krb5_ktfileint_openr(context, id))){
1131ab9b2e15Sgtb 	KRB5_LOG(KRB5_ERR, "ktfile_get_entry() end, ktfileint_openr() "
1132ab9b2e15Sgtb 		"kerror= %d\n", kerror);
1133ab9b2e15Sgtb 	return(kerror);
1134ab9b2e15Sgtb     }
11357c478bd9Sstevel@tonic-gate 
1136ab9b2e15Sgtb     /*
1137ab9b2e15Sgtb      * For efficiency and simplicity, we'll use a while true that
1138ab9b2e15Sgtb      * is exited with a break statement.
1139ab9b2e15Sgtb      */
1140ab9b2e15Sgtb     cur_entry.principal = 0;
1141ab9b2e15Sgtb     cur_entry.vno = 0;
1142ab9b2e15Sgtb     cur_entry.key.contents = 0;
1143ab9b2e15Sgtb     /*CONSTCOND*/
1144ab9b2e15Sgtb     while (TRUE) {
1145ab9b2e15Sgtb 	if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry)))
1146ab9b2e15Sgtb 	    break;
11477c478bd9Sstevel@tonic-gate 
1148ab9b2e15Sgtb 	/*
1149ab9b2e15Sgtb 	 * by the time this loop exits, it must either free cur_entry,
1150ab9b2e15Sgtb 	 * and copy new_entry there, or free new_entry.  Otherwise, it
1151ab9b2e15Sgtb 	 * leaks.
1152ab9b2e15Sgtb 	 */
1153ab9b2e15Sgtb 
1154ab9b2e15Sgtb 	/*
1155ab9b2e15Sgtb 	 * if the principal isn't the one requested, free new_entry
1156ab9b2e15Sgtb 	 * and continue to the next.
1157ab9b2e15Sgtb 	 */
11587c478bd9Sstevel@tonic-gate 
1159ab9b2e15Sgtb 	if (!principal_ignore_inst_compare(context, principal,
1160ab9b2e15Sgtb 					new_entry.principal)) {
1161ab9b2e15Sgtb 		krb5_kt_free_entry(context, &new_entry);
1162ab9b2e15Sgtb 	    continue;
11637c478bd9Sstevel@tonic-gate 	}
11647c478bd9Sstevel@tonic-gate 
1165ab9b2e15Sgtb 	/*
1166ab9b2e15Sgtb 	 * if the enctype is not ignored and doesn't match, free new_entry
1167ab9b2e15Sgtb 	 * and continue to the next
1168ab9b2e15Sgtb 	 */
11697c478bd9Sstevel@tonic-gate 
1170ab9b2e15Sgtb 	if (enctype != IGNORE_ENCTYPE) {
1171ab9b2e15Sgtb 	    if ((kerror = krb5_c_enctype_compare(context, enctype,
1172ab9b2e15Sgtb 						 new_entry.key.enctype,
1173ab9b2e15Sgtb 						 &similar))) {
1174ab9b2e15Sgtb 		krb5_kt_free_entry(context, &new_entry);
1175ab9b2e15Sgtb 		break;
1176ab9b2e15Sgtb 	    }
11777c478bd9Sstevel@tonic-gate 
1178ab9b2e15Sgtb 	    if (!similar) {
1179ab9b2e15Sgtb 		krb5_kt_free_entry(context, &new_entry);
1180ab9b2e15Sgtb 		continue;
1181ab9b2e15Sgtb 	    }
1182ab9b2e15Sgtb 	    /*
1183ab9b2e15Sgtb 	     * Coerce the enctype of the output keyblock in case we
1184ab9b2e15Sgtb 	     * got an inexact match on the enctype.
1185ab9b2e15Sgtb 	     */
1186ab9b2e15Sgtb 	    new_entry.key.enctype = enctype;
1187ab9b2e15Sgtb 	}
11887c478bd9Sstevel@tonic-gate 
1189ab9b2e15Sgtb 	if (kvno == IGNORE_VNO) {
1190ab9b2e15Sgtb 	    /*
1191ab9b2e15Sgtb 	     * if this is the first match, or if the new vno is
1192ab9b2e15Sgtb 	     * bigger, free the current and keep the new.  Otherwise,
1193ab9b2e15Sgtb 	     * free the new.
1194ab9b2e15Sgtb 	     */
1195ab9b2e15Sgtb 	    /*
1196ab9b2e15Sgtb 	     * A 1.2.x keytab contains only the low 8 bits of the key
1197ab9b2e15Sgtb 	     * version number.  Since it can be much bigger, and thus
1198ab9b2e15Sgtb 	     * the 8-bit value can wrap, we need some heuristics to
1199ab9b2e15Sgtb 	     * figure out the "highest" numbered key if some numbers
1200ab9b2e15Sgtb 	     * close to 255 and some near 0 are used.
1201ab9b2e15Sgtb 	     *
1202ab9b2e15Sgtb 	     * The heuristic here:
12037c478bd9Sstevel@tonic-gate 
1204ab9b2e15Sgtb 	     * If we have any keys with versions over 240, then assume
1205ab9b2e15Sgtb 	     * that all version numbers 0-127 refer to 256+N instead.
1206ab9b2e15Sgtb 	     * Not perfect, but maybe good enough?
1207ab9b2e15Sgtb 	     */
12087c478bd9Sstevel@tonic-gate 
1209ab9b2e15Sgtb #define M(VNO) (((VNO) - kvno_offset + 256) % 256)
12107c478bd9Sstevel@tonic-gate 
1211ab9b2e15Sgtb 	    if (new_entry.vno > 240)
1212ab9b2e15Sgtb 		kvno_offset = 128;
1213ab9b2e15Sgtb 	    if (! cur_entry.principal ||
1214ab9b2e15Sgtb 		M(new_entry.vno) > M(cur_entry.vno)) {
1215ab9b2e15Sgtb 		krb5_kt_free_entry(context, &cur_entry);
1216ab9b2e15Sgtb 		cur_entry = new_entry;
1217ab9b2e15Sgtb 	    } else {
1218ab9b2e15Sgtb 		krb5_kt_free_entry(context, &new_entry);
1219ab9b2e15Sgtb 	    }
1220ab9b2e15Sgtb 	} else {
1221ab9b2e15Sgtb 	    /*
1222ab9b2e15Sgtb 	     * if this kvno matches, free the current (will there ever
1223ab9b2e15Sgtb 	     * be one?), keep the new, and break out.  Otherwise, remember
1224ab9b2e15Sgtb 	     * that we were here so we can return the right error, and
1225ab9b2e15Sgtb 	     * free the new
1226ab9b2e15Sgtb 	     */
1227ab9b2e15Sgtb 	    /*
1228ab9b2e15Sgtb 	     * Yuck.  The krb5-1.2.x keytab format only stores one byte
1229ab9b2e15Sgtb 	     * for the kvno, so we're toast if the kvno requested is
1230ab9b2e15Sgtb 	     * higher than that.  Short-term workaround: only compare
1231ab9b2e15Sgtb 	     * the low 8 bits.
1232ab9b2e15Sgtb 	     */
12337c478bd9Sstevel@tonic-gate 
1234ab9b2e15Sgtb 	    if (new_entry.vno == (kvno & 0xff)) {
1235ab9b2e15Sgtb 		krb5_kt_free_entry(context, &cur_entry);
1236ab9b2e15Sgtb 		cur_entry = new_entry;
1237ab9b2e15Sgtb 		break;
1238ab9b2e15Sgtb 	    } else {
1239ab9b2e15Sgtb 		found_wrong_kvno++;
1240ab9b2e15Sgtb 		krb5_kt_free_entry(context, &new_entry);
1241ab9b2e15Sgtb 	    }
12427c478bd9Sstevel@tonic-gate 	}
1243ab9b2e15Sgtb     }
12447c478bd9Sstevel@tonic-gate 
1245ab9b2e15Sgtb     if (kerror == KRB5_KT_END) {
1246ab9b2e15Sgtb 	 if (cur_entry.principal)
1247ab9b2e15Sgtb 	      kerror = 0;
1248ab9b2e15Sgtb 	 else if (found_wrong_kvno)
1249ab9b2e15Sgtb 	      kerror = KRB5_KT_KVNONOTFOUND;
1250ab9b2e15Sgtb 	 else
1251ab9b2e15Sgtb 	      kerror = KRB5_KT_NOTFOUND;
1252ab9b2e15Sgtb     }
1253ab9b2e15Sgtb     if (kerror) {
1254ab9b2e15Sgtb 	(void) krb5_ktfileint_close(context, id);
1255ab9b2e15Sgtb 	krb5_kt_free_entry(context, &cur_entry);
1256ab9b2e15Sgtb 	KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, kerror="
1257ab9b2e15Sgtb 		    "%d\n", kerror);
1258ab9b2e15Sgtb 	return kerror;
1259ab9b2e15Sgtb     }
1260ab9b2e15Sgtb     if ((kerror = krb5_ktfileint_close(context, id)) != 0) {
1261ab9b2e15Sgtb 	krb5_kt_free_entry(context, &cur_entry);
1262ab9b2e15Sgtb 	KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, ktfileint_close() "
1263ab9b2e15Sgtb 	       "kerror= %d\n", kerror);
1264ab9b2e15Sgtb 	return kerror;
1265ab9b2e15Sgtb     }
1266ab9b2e15Sgtb     *entry = cur_entry;
12677c478bd9Sstevel@tonic-gate 
1268ab9b2e15Sgtb     /* Let us close the file before we leave */
1269ab9b2e15Sgtb     (void) krb5_ktfileint_close(context, id);
12707c478bd9Sstevel@tonic-gate 
1271ab9b2e15Sgtb     KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() end");
1272ab9b2e15Sgtb 
1273ab9b2e15Sgtb     return 0;
12747c478bd9Sstevel@tonic-gate }
12757c478bd9Sstevel@tonic-gate 
1276ab9b2e15Sgtb 
12777c478bd9Sstevel@tonic-gate /*
1278ab9b2e15Sgtb  * Solaris Kerberos
1279ab9b2e15Sgtb  * Given a princ of name/instance@LOCALREALM, search the keytab
1280ab9b2e15Sgtb  * for a match of name and LOCALREALM and if found, return instance
1281ab9b2e15Sgtb  * as a string.
12827c478bd9Sstevel@tonic-gate  *
1283ab9b2e15Sgtb  * Caller must free returned string.
12847c478bd9Sstevel@tonic-gate  */
1285ab9b2e15Sgtb static krb5_error_code
1286ab9b2e15Sgtb get_instance_keytab(
1287ab9b2e15Sgtb 	krb5_context context,
1288ab9b2e15Sgtb 	const char *sname,
1289ab9b2e15Sgtb 	krb5_keytab keytab,
1290ab9b2e15Sgtb 	char  **instance)  /* out */
12917c478bd9Sstevel@tonic-gate {
1292ab9b2e15Sgtb 	krb5_error_code ret=0;
1293ab9b2e15Sgtb 	krb5_keytab_entry kt_ent;
1294ab9b2e15Sgtb 	krb5_int32 nelem, free_kt_ent=0;
1295ab9b2e15Sgtb 	register const krb5_data *p;
1296ab9b2e15Sgtb 	char *realm=NULL, *s=NULL;
1297ab9b2e15Sgtb 	krb5_principal client=NULL, princ=NULL;
1298*db02be57S 	size_t realm_size = strlen(KRB5_REFERRAL_REALM) + 1;
12997c478bd9Sstevel@tonic-gate 
1300ab9b2e15Sgtb 	if (!keytab)
1301ab9b2e15Sgtb 		return EINVAL;
13027c478bd9Sstevel@tonic-gate 
1303*db02be57S 	realm = malloc(realm_size);
1304*db02be57S 	if (realm == NULL)
1305*db02be57S 		return (ENOMEM);
1306*db02be57S 	strlcpy(realm, KRB5_REFERRAL_REALM, realm_size);
13077c478bd9Sstevel@tonic-gate 
1308ab9b2e15Sgtb 	ret = krb5_build_principal(context, &client, strlen(realm),
1309ab9b2e15Sgtb 				      realm, sname, "*",
1310ab9b2e15Sgtb 				      (char *)0);
1311ab9b2e15Sgtb 	if (ret)
1312ab9b2e15Sgtb 		goto out;
13137c478bd9Sstevel@tonic-gate 
1314ab9b2e15Sgtb 	ret = ktfile_get_entry(context, keytab, client,
1315ab9b2e15Sgtb 				0, /* don't have vno available */
1316ab9b2e15Sgtb 				0, &kt_ent);
1317ab9b2e15Sgtb 	if (ret)
1318ab9b2e15Sgtb 		goto out;
13197c478bd9Sstevel@tonic-gate 
1320ab9b2e15Sgtb 	free_kt_ent++;  /* kt_ent is not a ptr */
13217c478bd9Sstevel@tonic-gate 
1322ab9b2e15Sgtb 	princ = kt_ent.principal;
1323ab9b2e15Sgtb 	nelem = krb5_princ_size(context, princ);
1324ab9b2e15Sgtb 	if (nelem != 2) {
1325ab9b2e15Sgtb 		ret = KRB5_PRINC_NOMATCH;
1326ab9b2e15Sgtb 		goto out;
1327ab9b2e15Sgtb 	}
13287c478bd9Sstevel@tonic-gate 
1329ab9b2e15Sgtb 	p = krb5_princ_component(context, princ, 1);
1330ab9b2e15Sgtb 	s = calloc(p->length + sizeof(char), sizeof(char));
1331ab9b2e15Sgtb 	if (!s) {
1332ab9b2e15Sgtb 		ret = ENOMEM;
1333ab9b2e15Sgtb 		goto out;
1334ab9b2e15Sgtb 	}
13357c478bd9Sstevel@tonic-gate 
1336ab9b2e15Sgtb 	(void) memcpy(s, p->data, p->length);
13377c478bd9Sstevel@tonic-gate 
13387c478bd9Sstevel@tonic-gate 
1339ab9b2e15Sgtb out:
1340ab9b2e15Sgtb 	free(realm);
1341ab9b2e15Sgtb 	if (client)
1342ab9b2e15Sgtb 		krb5_free_principal(context, client);
1343ab9b2e15Sgtb 	if (free_kt_ent)
1344ab9b2e15Sgtb 		(void) krb5_kt_free_entry(context, &kt_ent);
1345ab9b2e15Sgtb 
1346ab9b2e15Sgtb 	if (ret == 0)
1347ab9b2e15Sgtb 		*instance = s;
1348ab9b2e15Sgtb 	return ret;
1349ab9b2e15Sgtb }
13507c478bd9Sstevel@tonic-gate 
1351ab9b2e15Sgtb static OM_uint32
1352ab9b2e15Sgtb load_root_cred_using_keytab(
1353ab9b2e15Sgtb 	OM_uint32 *minor_status,
1354ab9b2e15Sgtb 	krb5_context context,
1355ab9b2e15Sgtb 	const char *sname,
1356ab9b2e15Sgtb 	int use_nodename)
1357ab9b2e15Sgtb {
1358ab9b2e15Sgtb 	krb5_creds my_creds;
1359ab9b2e15Sgtb 	krb5_principal me;
1360ab9b2e15Sgtb 	krb5_principal server;
1361ab9b2e15Sgtb 	krb5_error_code code;
1362ab9b2e15Sgtb 	krb5_ccache ccache = NULL;
1363ab9b2e15Sgtb 	krb5_keytab keytab = NULL;
1364ab9b2e15Sgtb 	krb5_timestamp now;
1365ab9b2e15Sgtb 	krb5_deltat lifetime = KRB5_DEFAULT_LIFE;   /* -l option */
1366ab9b2e15Sgtb 	krb5_get_init_creds_opt opt;
1367ab9b2e15Sgtb 	krb5_data tgtname = {
1368ab9b2e15Sgtb 		0,
1369ab9b2e15Sgtb 		KRB5_TGS_NAME_SIZE,
1370ab9b2e15Sgtb 		KRB5_TGS_NAME
1371ab9b2e15Sgtb 	};
1372ab9b2e15Sgtb 	char *svcname = NULL;
13737c478bd9Sstevel@tonic-gate 
1374ab9b2e15Sgtb 	KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() start \n");
13757c478bd9Sstevel@tonic-gate 
1376ab9b2e15Sgtb 	if (!sname)
1377ab9b2e15Sgtb 		return (GSS_S_FAILURE);
13787c478bd9Sstevel@tonic-gate 
1379ab9b2e15Sgtb 	memset((char *)&my_creds, 0, sizeof(my_creds));
13807c478bd9Sstevel@tonic-gate 
1381ab9b2e15Sgtb 	if (code = krb5_kt_default(context, &keytab)) {
1382ab9b2e15Sgtb 		*minor_status = code;
1383ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1384ab9b2e15Sgtb 	}
13857c478bd9Sstevel@tonic-gate 
1386ab9b2e15Sgtb 	if (!use_nodename) {
1387ab9b2e15Sgtb 		char *instance = NULL;
13887c478bd9Sstevel@tonic-gate 
1389ab9b2e15Sgtb 		code = get_instance_keytab(context, sname, keytab, &instance);
1390ab9b2e15Sgtb 		if (code == 0) {
1391ab9b2e15Sgtb 			code = krb5_sname_to_principal(context,
1392ab9b2e15Sgtb 						    instance, sname,
1393ab9b2e15Sgtb 						    KRB5_NT_UNKNOWN, &me);
1394ab9b2e15Sgtb 			free(instance);
1395ab9b2e15Sgtb 		}
1396ab9b2e15Sgtb 	} else {
1397ab9b2e15Sgtb 		code = krb5_sname_to_principal(context, NULL, sname,
1398ab9b2e15Sgtb 					    KRB5_NT_SRV_HST, &me);
1399ab9b2e15Sgtb 	}
1400*db02be57S 
1401*db02be57S 	/* Solaris Kerberos */
1402*db02be57S 	if (krb5_is_referral_realm(&me->realm)) {
1403*db02be57S 		krb5_data realm;
1404*db02be57S 		code = krb5_kt_find_realm(context, keytab, me, &realm);
1405*db02be57S 		if (code == 0) {
1406*db02be57S 			krb5_free_data_contents(context, &me->realm);
1407*db02be57S 			me->realm.length = realm.length;
1408*db02be57S 			me->realm.data = realm.data;
1409*db02be57S 		} else {
1410*db02be57S 			/* Try to set a useful error message */
1411*db02be57S 			char *princ = NULL;
1412*db02be57S 			krb5_unparse_name(context, me, &princ);
1413*db02be57S 
1414*db02be57S 			krb5_set_error_message(context, code,
1415*db02be57S 			    gettext("Failed to find realm for %s in keytab"),
1416*db02be57S 			    princ ? princ : "<unknown>");
1417*db02be57S 			if (princ)
1418*db02be57S 				krb5_free_unparsed_name(context, princ);
1419*db02be57S 		}
1420*db02be57S 	}
1421*db02be57S 
1422ab9b2e15Sgtb 	if (code) {
1423ab9b2e15Sgtb 		(void) krb5_kt_close(context, keytab);
1424ab9b2e15Sgtb 		*minor_status = code;
1425ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1426ab9b2e15Sgtb 	}
14277c478bd9Sstevel@tonic-gate 
1428ab9b2e15Sgtb 	my_creds.client = me;
14297c478bd9Sstevel@tonic-gate 
1430ab9b2e15Sgtb 	if((code = krb5_build_principal_ext(context, &server,
1431ab9b2e15Sgtb 					krb5_princ_realm(context, me)->length,
1432ab9b2e15Sgtb 					krb5_princ_realm(context, me)->data,
1433ab9b2e15Sgtb 					tgtname.length, tgtname.data,
1434ab9b2e15Sgtb 					krb5_princ_realm(context, me)->length,
1435ab9b2e15Sgtb 					krb5_princ_realm(context, me)->data,
1436ab9b2e15Sgtb 					0))) {
1437ab9b2e15Sgtb 		*minor_status = code;
1438ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
1439ab9b2e15Sgtb 		(void) krb5_kt_close(context, keytab);
14407c478bd9Sstevel@tonic-gate 
1441ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1442ab9b2e15Sgtb 	}
14437c478bd9Sstevel@tonic-gate 
1444ab9b2e15Sgtb 	my_creds.server = server;
1445ab9b2e15Sgtb 	my_creds.times.starttime = 0;     /* start timer
1446ab9b2e15Sgtb 					   * when request
1447ab9b2e15Sgtb 					   * gets to KDC
1448ab9b2e15Sgtb 					   */
1449ab9b2e15Sgtb 	if ((code = krb5_timeofday(context, &now))) {
1450ab9b2e15Sgtb 		*minor_status = code;
1451ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
1452ab9b2e15Sgtb 		(void) krb5_kt_close(context, keytab);
14537c478bd9Sstevel@tonic-gate 
1454ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1455ab9b2e15Sgtb 	}
1456ab9b2e15Sgtb 	my_creds.times.endtime = now + lifetime;
1457ab9b2e15Sgtb 	my_creds.times.renew_till = 0;
14587c478bd9Sstevel@tonic-gate 
1459ab9b2e15Sgtb 	memset(&opt, 0, sizeof (opt));
1460ab9b2e15Sgtb 	krb5_get_init_creds_opt_init(&opt);
1461ab9b2e15Sgtb 	krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime);
14627c478bd9Sstevel@tonic-gate 
1463ab9b2e15Sgtb 	code = krb5_unparse_name(context, server, &svcname);
1464ab9b2e15Sgtb 	if (code != 0) {
1465ab9b2e15Sgtb 		*minor_status = code;
1466ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
1467ab9b2e15Sgtb 		(void) krb5_kt_close(context, keytab);
14687c478bd9Sstevel@tonic-gate 
1469ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1470ab9b2e15Sgtb 	}
1471ab9b2e15Sgtb 	/*
1472ab9b2e15Sgtb 	 * Evidently (sigh), on success, krb5_get_init_creds_keytab
1473ab9b2e15Sgtb 	 * changes the my_creds princ ptrs so we need to free those
1474ab9b2e15Sgtb 	 * princs (me&server) as well as freeing all of my_creds contents.
1475ab9b2e15Sgtb 	 */
1476ab9b2e15Sgtb 	code = krb5_get_init_creds_keytab(context,
1477ab9b2e15Sgtb                                 &my_creds, me, keytab,
1478ab9b2e15Sgtb                                 0, svcname, &opt);
14797c478bd9Sstevel@tonic-gate 
1480ab9b2e15Sgtb 	(void) krb5_kt_close(context, keytab);
14817c478bd9Sstevel@tonic-gate 
1482ab9b2e15Sgtb 	if (svcname != NULL)
1483ab9b2e15Sgtb 		free(svcname);
1484ab9b2e15Sgtb 	if (code) {
1485ab9b2e15Sgtb 		*minor_status = code;
1486ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
14877c478bd9Sstevel@tonic-gate 
1488ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1489ab9b2e15Sgtb 	}
14907c478bd9Sstevel@tonic-gate 
1491ab9b2e15Sgtb 	krb5_free_principal(context, server);
1492ab9b2e15Sgtb 	server = NULL;
14937c478bd9Sstevel@tonic-gate 
1494ab9b2e15Sgtb 	code = krb5_cc_resolve (context,
1495ab9b2e15Sgtb 				krb5_cc_default_name(context),
1496ab9b2e15Sgtb 				&ccache);
1497ab9b2e15Sgtb 	if (code != 0) {
1498ab9b2e15Sgtb 		*minor_status = code;
1499ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
1500ab9b2e15Sgtb 		krb5_free_principal(context, me);
15017c478bd9Sstevel@tonic-gate 
1502ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1503ab9b2e15Sgtb 	}
1504ab9b2e15Sgtb 	code = krb5_cc_initialize (context, ccache, me);
1505ab9b2e15Sgtb 	krb5_free_principal(context, me);
1506ab9b2e15Sgtb 	me = NULL;
1507ab9b2e15Sgtb 	if (code != 0) {
1508ab9b2e15Sgtb 		*minor_status = code;
1509ab9b2e15Sgtb 		krb5_free_cred_contents(context, &my_creds);
1510ab9b2e15Sgtb 		(void) krb5_cc_close(context, ccache);
15117c478bd9Sstevel@tonic-gate 
1512ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1513ab9b2e15Sgtb 	}
15147c478bd9Sstevel@tonic-gate 
1515ab9b2e15Sgtb 	code = krb5_cc_store_cred(context, ccache,
1516ab9b2e15Sgtb 				  &my_creds);
1517ab9b2e15Sgtb 	krb5_free_cred_contents(context, &my_creds);
1518ab9b2e15Sgtb 	(void) krb5_cc_close(context, ccache);
15197c478bd9Sstevel@tonic-gate 
1520ab9b2e15Sgtb 	if (code) {
1521ab9b2e15Sgtb 		*minor_status = code;
15227c478bd9Sstevel@tonic-gate 
1523ab9b2e15Sgtb 		KRB5_LOG(KRB5_ERR, "load_root_cred_using_keytab() end, error "
1524ab9b2e15Sgtb 			"code = %d\n", code);
15257c478bd9Sstevel@tonic-gate 
1526ab9b2e15Sgtb 		return (GSS_S_FAILURE);
15277c478bd9Sstevel@tonic-gate 	}
1528ab9b2e15Sgtb 
1529ab9b2e15Sgtb 	KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() end \n");
15307c478bd9Sstevel@tonic-gate 
1531ab9b2e15Sgtb 	return (GSS_S_COMPLETE);
1532ab9b2e15Sgtb }
15337c478bd9Sstevel@tonic-gate 
1534ab9b2e15Sgtb static OM_uint32
1535ab9b2e15Sgtb renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid)
1536ab9b2e15Sgtb {
1537ab9b2e15Sgtb 	krb5_principal me;
1538ab9b2e15Sgtb 	krb5_principal server;
1539ab9b2e15Sgtb 	krb5_creds	creds;
1540ab9b2e15Sgtb 	krb5_creds	tmpcreds;
1541ab9b2e15Sgtb 	krb5_creds	*out_creds;
1542ab9b2e15Sgtb 	krb5_error_code code;
1543ab9b2e15Sgtb 	krb5_ccache ccache = NULL;
1544ab9b2e15Sgtb 	static char ccache_name_buf[CACHE_FILENAME_LEN];
1545ab9b2e15Sgtb 	int options = 0;
1546ab9b2e15Sgtb 	krb5_data tgtname = {
1547ab9b2e15Sgtb 		0,
1548ab9b2e15Sgtb 		KRB5_TGS_NAME_SIZE,
1549ab9b2e15Sgtb 		KRB5_TGS_NAME
1550ab9b2e15Sgtb 	};
1551ab9b2e15Sgtb 	gid_t gid = getgid();
15527c478bd9Sstevel@tonic-gate 
1553ab9b2e15Sgtb 	memset((char *)&creds, 0, sizeof(creds));
1554ab9b2e15Sgtb 	memset((char *)&tmpcreds, 0, sizeof(creds));
15557c478bd9Sstevel@tonic-gate 
1556ab9b2e15Sgtb 	if ((code = krb5_cc_default(context, &ccache))) {
1557ab9b2e15Sgtb 		*minor_status = code;
1558ab9b2e15Sgtb 		(void) krb5_cc_close(context, ccache);
1559ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1560ab9b2e15Sgtb 	}
15617c478bd9Sstevel@tonic-gate 
1562ab9b2e15Sgtb 	if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) {
1563ab9b2e15Sgtb 		*minor_status = code;
1564ab9b2e15Sgtb 		(void) krb5_cc_close(context, ccache);
1565ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1566ab9b2e15Sgtb 	}
15677c478bd9Sstevel@tonic-gate 
1568ab9b2e15Sgtb 	creds.client = me;
15697c478bd9Sstevel@tonic-gate 
1570ab9b2e15Sgtb 	if((code = krb5_build_principal_ext(context, &server,
1571ab9b2e15Sgtb 					krb5_princ_realm(context, me)->length,
1572ab9b2e15Sgtb 					krb5_princ_realm(context, me)->data,
1573ab9b2e15Sgtb 					tgtname.length, tgtname.data,
1574ab9b2e15Sgtb 					krb5_princ_realm(context, me)->length,
1575ab9b2e15Sgtb 					krb5_princ_realm(context, me)->data,
1576ab9b2e15Sgtb 					0))) {
1577ab9b2e15Sgtb 		krb5_free_principal(context, me);
1578ab9b2e15Sgtb 		(void) krb5_cc_close(context, ccache);
1579ab9b2e15Sgtb 		*minor_status = code;
1580ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1581ab9b2e15Sgtb 	}
15827c478bd9Sstevel@tonic-gate 
1583ab9b2e15Sgtb 	creds.server = server;
1584ab9b2e15Sgtb 	creds.ticket_flags = TKT_FLG_RENEWABLE;
1585ab9b2e15Sgtb 
1586ab9b2e15Sgtb 	if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS,
1587ab9b2e15Sgtb 			&creds, &tmpcreds))) {
1588ab9b2e15Sgtb 		(void) krb5_cc_close(context, ccache);
1589ab9b2e15Sgtb 		return (KDC_ERR_BADOPTION);
1590ab9b2e15Sgtb 	}
1591ab9b2e15Sgtb 
1592ab9b2e15Sgtb 	creds.ticket_flags = 0;
1593ab9b2e15Sgtb         code = krb5_get_credentials_renew(context, options, ccache,
1594ab9b2e15Sgtb 						&creds, &out_creds);
1595ab9b2e15Sgtb 	krb5_free_cred_contents(context, &creds);
1596ab9b2e15Sgtb 	krb5_free_cred_contents(context, &tmpcreds);
15977c478bd9Sstevel@tonic-gate 
1598ab9b2e15Sgtb 	if (code) {
1599ab9b2e15Sgtb 		*minor_status = code;
1600ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1601ab9b2e15Sgtb 	}
16027c478bd9Sstevel@tonic-gate 
1603ab9b2e15Sgtb 	krb5_free_creds(context, out_creds);
1604ab9b2e15Sgtb 	snprintf(ccache_name_buf, CACHE_FILENAME_LEN, "/tmp/krb5cc_%d",
1605ab9b2e15Sgtb 		uid, -1);
1606ab9b2e15Sgtb 	code = safechown(ccache_name_buf, uid, gid, -1);
16077c478bd9Sstevel@tonic-gate 
1608ab9b2e15Sgtb 	if (code == -1) {
1609ab9b2e15Sgtb 		(void) krb5_cc_destroy(context, ccache);
1610ab9b2e15Sgtb 		*minor_status = code;
1611ab9b2e15Sgtb 		return (GSS_S_FAILURE);
1612ab9b2e15Sgtb 	}
16137c478bd9Sstevel@tonic-gate 
1614ab9b2e15Sgtb 	(void) krb5_cc_close(context, ccache);
1615ab9b2e15Sgtb 
1616ab9b2e15Sgtb 	return (GSS_S_COMPLETE);
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate }
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate /*
1621ab9b2e15Sgtb  * Solaris Kerberos:
1622ab9b2e15Sgtb  * We enforce a minimum refresh time on the root cred. This avoids problems for
1623ab9b2e15Sgtb  * the higher level communication protocol for having valid creds and
1624ab9b2e15Sgtb  * setting up a valid context, only to have it expire before or while
1625ab9b2e15Sgtb  * it is being used. For non root users we don't care since we do not refresh
1626ab9b2e15Sgtb  * there creds, they get what they can get.
16277c478bd9Sstevel@tonic-gate  */
1628ab9b2e15Sgtb #define MIN_REFRESH_TIME 300
1629ab9b2e15Sgtb #define MIN_RENEW_TIME 1500
1630ab9b2e15Sgtb 
1631ab9b2e15Sgtb /* get_default_cred() must be called with the krb5_mutex lock held */
1632ab9b2e15Sgtb static OM_uint32
1633ab9b2e15Sgtb get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle)
16347c478bd9Sstevel@tonic-gate {
1635ab9b2e15Sgtb 	krb5_timestamp now;
1636ab9b2e15Sgtb 	krb5_gss_cred_id_t cred;
1637ab9b2e15Sgtb 	OM_uint32 major;
1638ab9b2e15Sgtb 	OM_uint32 mntmp;
1639ab9b2e15Sgtb 	/*
1640ab9b2e15Sgtb 	 * Solaris Kerberos
1641ab9b2e15Sgtb 	 * Use krb5_getuid() to select the mechanism to obtain the uid.
1642ab9b2e15Sgtb 	 */
1643ab9b2e15Sgtb 	uid_t uid = krb5_getuid();
1644ab9b2e15Sgtb 	krb5_context context = (krb5_context)ct;
16457c478bd9Sstevel@tonic-gate 
1646ab9b2e15Sgtb 	KRB5_LOG0(KRB5_INFO, "get_default_cred() start\n");
16477c478bd9Sstevel@tonic-gate 
1648ab9b2e15Sgtb 	/* Get the default cred for user */
1649ab9b2e15Sgtb 	if (((major = kg_get_defcred(minor_status, cred_handle)) != NULL) &&
1650ab9b2e15Sgtb 	    GSS_ERROR(major)) {
16517c478bd9Sstevel@tonic-gate 
1652ab9b2e15Sgtb 		/* If we're not root we're done */
1653ab9b2e15Sgtb    		if (uid != ROOT_UID)
1654ab9b2e15Sgtb 	 		return (major);
16557c478bd9Sstevel@tonic-gate 
1656ab9b2e15Sgtb 		/*
1657ab9b2e15Sgtb 		 * Try and get root's cred in the cache using keytab.
1658ab9b2e15Sgtb 		 *
1659ab9b2e15Sgtb 		 * First try "root" and then try "host" - this allows
1660ab9b2e15Sgtb 		 * Secure NFS to use the host principal for mounting if
1661ab9b2e15Sgtb 		 * there is no root principal.
1662ab9b2e15Sgtb 		 *
1663ab9b2e15Sgtb 		 * Then try "host/<anything>" to match any instance (needed
1664ab9b2e15Sgtb 		 * for DHCP clients).
1665ab9b2e15Sgtb 		 */
1666ab9b2e15Sgtb 		major = load_root_cred_using_keytab(minor_status,
1667ab9b2e15Sgtb 						    context, "root", 1);
16687c478bd9Sstevel@tonic-gate 
1669ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1670ab9b2e15Sgtb 			major = load_root_cred_using_keytab(minor_status,
1671ab9b2e15Sgtb 							    context, "host", 1);
1672ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1673ab9b2e15Sgtb 			major = load_root_cred_using_keytab(minor_status,
1674ab9b2e15Sgtb 							    context, "host", 0);
16757c478bd9Sstevel@tonic-gate 
1676ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1677ab9b2e15Sgtb 			return (major);
16787c478bd9Sstevel@tonic-gate 
1679ab9b2e15Sgtb 		/* We should have valid tgt now in the cache, so get it. */
1680ab9b2e15Sgtb 		major = kg_get_defcred(minor_status, cred_handle);
16817c478bd9Sstevel@tonic-gate 
1682ab9b2e15Sgtb 		return (major);
1683ab9b2e15Sgtb       	}
16847c478bd9Sstevel@tonic-gate 
1685ab9b2e15Sgtb 	/* We've got a gss cred handle that is a kerberos cred handle. */
1686ab9b2e15Sgtb 	cred = (krb5_gss_cred_id_t)*cred_handle;
1687ab9b2e15Sgtb 
1688ab9b2e15Sgtb 	/* If we can't get the time, assume the worst. */
1689ab9b2e15Sgtb 	if (krb5_timeofday(context, &now)) {
1690ab9b2e15Sgtb 		(void) krb5_gss_release_cred(&mntmp, cred_handle);
1691ab9b2e15Sgtb 		return (GSS_S_CREDENTIALS_EXPIRED);
1692ab9b2e15Sgtb 	}
16937c478bd9Sstevel@tonic-gate 
1694ab9b2e15Sgtb 	/* If root's cred has expired re-get it */
1695ab9b2e15Sgtb 	if (cred->tgt_expire < now + MIN_REFRESH_TIME && uid == ROOT_UID) {
1696ab9b2e15Sgtb 		(void) krb5_gss_release_cred(&mntmp, cred_handle);
16977c478bd9Sstevel@tonic-gate 
1698ab9b2e15Sgtb 		major = load_root_cred_using_keytab(minor_status,
1699ab9b2e15Sgtb 						    context, "root", 1);
17007c478bd9Sstevel@tonic-gate 
1701ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1702ab9b2e15Sgtb 			major = load_root_cred_using_keytab(minor_status,
1703ab9b2e15Sgtb 							    context, "host", 1);
17047c478bd9Sstevel@tonic-gate 
1705ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1706ab9b2e15Sgtb 			major = load_root_cred_using_keytab(minor_status,
1707ab9b2e15Sgtb 							    context, "host", 0);
1708ab9b2e15Sgtb 
1709ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1710ab9b2e15Sgtb 			return (major);
1711ab9b2e15Sgtb 
1712ab9b2e15Sgtb 		major = kg_get_defcred(minor_status, cred_handle);
1713ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1714ab9b2e15Sgtb 			return (major);
1715ab9b2e15Sgtb 
1716ab9b2e15Sgtb 	/* Any body else is SOL unless we can renew their credential cache */
1717ab9b2e15Sgtb 	} else if ((cred->tgt_expire < now + MIN_RENEW_TIME) &&
1718ab9b2e15Sgtb 			(cred->tgt_expire > now)) {
1719ab9b2e15Sgtb 		(void) krb5_gss_release_cred(&mntmp, cred_handle);
1720ab9b2e15Sgtb 
1721ab9b2e15Sgtb 		major = renew_ccache(minor_status, context, uid);
1722ab9b2e15Sgtb 		if ((major != GSS_S_COMPLETE) &&
1723ab9b2e15Sgtb 			(major != KDC_ERR_BADOPTION))
1724ab9b2e15Sgtb 			return (major);
1725ab9b2e15Sgtb 
1726ab9b2e15Sgtb 		major = kg_get_defcred(minor_status, cred_handle);
1727ab9b2e15Sgtb 		if (major != GSS_S_COMPLETE)
1728ab9b2e15Sgtb 			return (major);
17297c478bd9Sstevel@tonic-gate 
1730ab9b2e15Sgtb 	}
17317c478bd9Sstevel@tonic-gate 
1732ab9b2e15Sgtb 	/* Otherwise we got non expired creds */
17337c478bd9Sstevel@tonic-gate 
1734ab9b2e15Sgtb 	KRB5_LOG0(KRB5_INFO, "get_default_cred() end\n");
17357c478bd9Sstevel@tonic-gate 
1736ab9b2e15Sgtb 	return (GSS_S_COMPLETE);
17377c478bd9Sstevel@tonic-gate }
1738ab9b2e15Sgtb 
1739ab9b2e15Sgtb /* Solaris Kerberos specific routines end */
1740