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 */ 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 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 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 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 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 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 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 } 976ab9b2e15Sgtb } else if (g_OID_equal(mech_type, gss_mech_krb5)) { 977ab9b2e15Sgtb if (!cred->rfc_mech) 978ab9b2e15Sgtb err = 1; 979ab9b2e15Sgtb } else if (g_OID_equal(mech_type, gss_mech_krb5_old)) { 980ab9b2e15Sgtb if (!cred->prerfc_mech) 981ab9b2e15Sgtb err = 1; 982ab9b2e15Sgtb } else if (g_OID_equal(mech_type, gss_mech_krb5_wrong)) { 983ab9b2e15Sgtb if (!cred->rfc_mech) 984ab9b2e15Sgtb err = 1; 985ab9b2e15Sgtb } else { 986ab9b2e15Sgtb err = 1; 987ab9b2e15Sgtb } 988ab9b2e15Sgtb 989ab9b2e15Sgtb if (err) { 990ab9b2e15Sgtb k5_mutex_unlock(&cred->lock); 991ab9b2e15Sgtb if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) 992ab9b2e15Sgtb krb5_gss_release_cred(minor_status, (gss_cred_id_t *)&cred); 993ab9b2e15Sgtb *minor_status = 0; 994ab9b2e15Sgtb if (*context_handle == GSS_C_NO_CONTEXT) 995ab9b2e15Sgtb krb5_free_context(context); 996ab9b2e15Sgtb return(GSS_S_BAD_MECH); 997ab9b2e15Sgtb } 9987c478bd9Sstevel@tonic-gate 999ab9b2e15Sgtb /* is this a new connection or not? */ 10007c478bd9Sstevel@tonic-gate 1001ab9b2e15Sgtb /*SUPPRESS 29*/ 1002ab9b2e15Sgtb if (*context_handle == GSS_C_NO_CONTEXT) { 1003ab9b2e15Sgtb major_status = new_connection(minor_status, cred, context_handle, 1004ab9b2e15Sgtb target_name, mech_type, req_flags, 1005ab9b2e15Sgtb time_req, input_chan_bindings, 1006ab9b2e15Sgtb input_token, actual_mech_type, 1007ab9b2e15Sgtb output_token, ret_flags, time_rec, 1008ab9b2e15Sgtb context, default_mech); 1009ab9b2e15Sgtb k5_mutex_unlock(&cred->lock); 10105e01956fSGlenn Barry if (*context_handle == GSS_C_NO_CONTEXT) { 10115e01956fSGlenn Barry save_error_info (*minor_status, context); 1012ab9b2e15Sgtb krb5_free_context(context); 10135e01956fSGlenn Barry } else 1014ab9b2e15Sgtb ((krb5_gss_ctx_id_rec *) *context_handle)->k5_context = context; 1015ab9b2e15Sgtb } else { 1016ab9b2e15Sgtb /* mutual_auth doesn't care about the credentials */ 1017ab9b2e15Sgtb k5_mutex_unlock(&cred->lock); 1018ab9b2e15Sgtb major_status = mutual_auth(minor_status, context_handle, 1019ab9b2e15Sgtb target_name, mech_type, req_flags, 1020ab9b2e15Sgtb time_req, input_chan_bindings, 1021ab9b2e15Sgtb input_token, actual_mech_type, 1022ab9b2e15Sgtb output_token, ret_flags, time_rec, 1023ab9b2e15Sgtb context); 1024ab9b2e15Sgtb /* If context_handle is now NO_CONTEXT, mutual_auth called 1025ab9b2e15Sgtb delete_sec_context, which would've zapped the krb5 context 1026ab9b2e15Sgtb too. */ 1027ab9b2e15Sgtb } 10287c478bd9Sstevel@tonic-gate 1029ab9b2e15Sgtb if (claimant_cred_handle == GSS_C_NO_CREDENTIAL) 1030ab9b2e15Sgtb krb5_gss_release_cred(&tmp_min_stat, (gss_cred_id_t *)&cred); 10317c478bd9Sstevel@tonic-gate 1032ab9b2e15Sgtb return(major_status); 10337c478bd9Sstevel@tonic-gate } 10347c478bd9Sstevel@tonic-gate 1035159d09a2SMark Phalan #ifndef _WIN32 1036ab9b2e15Sgtb k5_mutex_t kg_kdc_flag_mutex = K5_MUTEX_PARTIAL_INITIALIZER; 1037ab9b2e15Sgtb static int kdc_flag = 0; 1038ab9b2e15Sgtb #endif 10397c478bd9Sstevel@tonic-gate 1040ab9b2e15Sgtb krb5_error_code 1041ab9b2e15Sgtb krb5_gss_init_context (krb5_context *ctxp) 10427c478bd9Sstevel@tonic-gate { 1043ab9b2e15Sgtb krb5_error_code err; 1044159d09a2SMark Phalan #ifndef _WIN32 1045ab9b2e15Sgtb int is_kdc; 1046159d09a2SMark Phalan #endif 1047ab9b2e15Sgtb 1048ab9b2e15Sgtb err = gssint_initialize_library(); 1049ab9b2e15Sgtb if (err) 1050ab9b2e15Sgtb return err; 1051159d09a2SMark Phalan #ifndef _WIN32 1052ab9b2e15Sgtb err = k5_mutex_lock(&kg_kdc_flag_mutex); 1053ab9b2e15Sgtb if (err) 1054ab9b2e15Sgtb return err; 1055ab9b2e15Sgtb is_kdc = kdc_flag; 1056ab9b2e15Sgtb k5_mutex_unlock(&kg_kdc_flag_mutex); 1057ab9b2e15Sgtb 1058ab9b2e15Sgtb if (is_kdc) 1059ab9b2e15Sgtb return krb5int_init_context_kdc(ctxp); 1060ab9b2e15Sgtb #endif 10617c478bd9Sstevel@tonic-gate 1062159d09a2SMark Phalan return krb5_init_context(ctxp); 1063ab9b2e15Sgtb } 10647c478bd9Sstevel@tonic-gate 1065159d09a2SMark Phalan #ifndef _WIN32 1066ab9b2e15Sgtb krb5_error_code 1067ab9b2e15Sgtb krb5_gss_use_kdc_context() 1068ab9b2e15Sgtb { 1069ab9b2e15Sgtb krb5_error_code err; 1070ab9b2e15Sgtb 1071ab9b2e15Sgtb err = gssint_initialize_library(); 1072ab9b2e15Sgtb if (err) 1073ab9b2e15Sgtb return err; 1074ab9b2e15Sgtb err = k5_mutex_lock(&kg_kdc_flag_mutex); 1075ab9b2e15Sgtb if (err) 1076ab9b2e15Sgtb return err; 1077ab9b2e15Sgtb kdc_flag = 1; 1078ab9b2e15Sgtb k5_mutex_unlock(&kg_kdc_flag_mutex); 1079ab9b2e15Sgtb return 0; 1080ab9b2e15Sgtb } 1081ab9b2e15Sgtb #endif 10827c478bd9Sstevel@tonic-gate 1083ab9b2e15Sgtb /* Solaris Kerberos specific routines start */ 10847c478bd9Sstevel@tonic-gate 1085ab9b2e15Sgtb #define ROOT_UID 0 1086ab9b2e15Sgtb #define KRB5_DEFAULT_LIFE 60*60*10 1087ab9b2e15Sgtb #define CACHE_FILENAME_LEN 35 10887c478bd9Sstevel@tonic-gate 1089ab9b2e15Sgtb extern int 1090ab9b2e15Sgtb safechown(const char *src, uid_t uid, gid_t gid, int mode); 10917c478bd9Sstevel@tonic-gate 1092ab9b2e15Sgtb static krb5_boolean 1093ab9b2e15Sgtb principal_ignore_inst_compare(context, princ1, princ2) 1094ab9b2e15Sgtb krb5_context context; 1095ab9b2e15Sgtb krb5_const_principal princ1; 1096ab9b2e15Sgtb krb5_const_principal princ2; 1097ab9b2e15Sgtb { 1098ab9b2e15Sgtb krb5_int32 nelem; 10997c478bd9Sstevel@tonic-gate 1100ab9b2e15Sgtb nelem = krb5_princ_size(context, princ1); 1101ab9b2e15Sgtb if (nelem != krb5_princ_size(context, princ2)) 1102ab9b2e15Sgtb return FALSE; 11037c478bd9Sstevel@tonic-gate 1104db02be57S /* 1105db02be57S * Solaris Kerberos: 1106db02be57S * Don't bother to compare the realms as princ1 will always have a 1107db02be57S * referral realm set. 1108db02be57S */ 11097c478bd9Sstevel@tonic-gate 1110ab9b2e15Sgtb /* 1111ab9b2e15Sgtb * Solaris Kerberos 1112ab9b2e15Sgtb * If princ1 is elem1/metachar@REALM, compare just elem1 (and REALM). 1113ab9b2e15Sgtb */ 1114ab9b2e15Sgtb if (nelem == 2) { 1115ab9b2e15Sgtb const krb5_data *p = krb5_princ_component(context, princ1, 1); 1116ab9b2e15Sgtb 1117ab9b2e15Sgtb if (p->length == 1) { 1118ab9b2e15Sgtb const char *s = p->data; 11197c478bd9Sstevel@tonic-gate 1120ab9b2e15Sgtb if (s[0] == '*') { 1121ab9b2e15Sgtb const krb5_data *p1 = krb5_princ_component(context, princ1, 0); 1122ab9b2e15Sgtb const krb5_data *p2 = krb5_princ_component(context, princ2, 0); 11237c478bd9Sstevel@tonic-gate 1124ab9b2e15Sgtb if (p1->length != p2->length || 1125ab9b2e15Sgtb memcmp(p1->data, p2->data, p1->length)) 1126ab9b2e15Sgtb return FALSE; 1127ab9b2e15Sgtb 1128ab9b2e15Sgtb return TRUE; 1129ab9b2e15Sgtb } 1130ab9b2e15Sgtb } 1131ab9b2e15Sgtb } 1132ab9b2e15Sgtb 1133ab9b2e15Sgtb return FALSE; 1134ab9b2e15Sgtb } 11357c478bd9Sstevel@tonic-gate 1136ab9b2e15Sgtb /* 1137ab9b2e15Sgtb * Solaris Kerberos 1138ab9b2e15Sgtb * This is a dup of krb5_ktfile_get_entry (sigh) but is necessary to 1139ab9b2e15Sgtb * to get a custom princ compare above (principal_ignore_inst_compare) 1140ab9b2e15Sgtb * and thus avoid mucking w/important krb5 internal 1141ab9b2e15Sgtb * api (krb5_principal_compare) 1142ab9b2e15Sgtb */ 1143ab9b2e15Sgtb #include "../krb5/keytab/file/ktfile.h" 11447c478bd9Sstevel@tonic-gate 1145ab9b2e15Sgtb static krb5_error_code KRB5_CALLCONV 1146ab9b2e15Sgtb ktfile_get_entry(context, id, principal, kvno, enctype, entry) 1147ab9b2e15Sgtb krb5_context context; 1148ab9b2e15Sgtb krb5_keytab id; 1149ab9b2e15Sgtb krb5_const_principal principal; 1150ab9b2e15Sgtb krb5_kvno kvno; 1151ab9b2e15Sgtb krb5_enctype enctype; 1152ab9b2e15Sgtb krb5_keytab_entry * entry; 1153ab9b2e15Sgtb { 1154ab9b2e15Sgtb krb5_keytab_entry cur_entry, new_entry; 1155ab9b2e15Sgtb krb5_error_code kerror = 0; 1156ab9b2e15Sgtb int found_wrong_kvno = 0; 1157ab9b2e15Sgtb krb5_boolean similar; 1158ab9b2e15Sgtb int kvno_offset = 0; 11597c478bd9Sstevel@tonic-gate 1160ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() start\n"); 11617c478bd9Sstevel@tonic-gate 1162ab9b2e15Sgtb /* Open the keyfile for reading */ 1163ab9b2e15Sgtb if ((kerror = krb5_ktfileint_openr(context, id))){ 1164ab9b2e15Sgtb KRB5_LOG(KRB5_ERR, "ktfile_get_entry() end, ktfileint_openr() " 1165ab9b2e15Sgtb "kerror= %d\n", kerror); 1166ab9b2e15Sgtb return(kerror); 1167ab9b2e15Sgtb } 11687c478bd9Sstevel@tonic-gate 1169ab9b2e15Sgtb /* 1170ab9b2e15Sgtb * For efficiency and simplicity, we'll use a while true that 1171ab9b2e15Sgtb * is exited with a break statement. 1172ab9b2e15Sgtb */ 1173ab9b2e15Sgtb cur_entry.principal = 0; 1174ab9b2e15Sgtb cur_entry.vno = 0; 1175ab9b2e15Sgtb cur_entry.key.contents = 0; 1176ab9b2e15Sgtb /*CONSTCOND*/ 1177ab9b2e15Sgtb while (TRUE) { 1178ab9b2e15Sgtb if ((kerror = krb5_ktfileint_read_entry(context, id, &new_entry))) 1179ab9b2e15Sgtb break; 11807c478bd9Sstevel@tonic-gate 1181ab9b2e15Sgtb /* 1182ab9b2e15Sgtb * by the time this loop exits, it must either free cur_entry, 1183ab9b2e15Sgtb * and copy new_entry there, or free new_entry. Otherwise, it 1184ab9b2e15Sgtb * leaks. 1185ab9b2e15Sgtb */ 1186ab9b2e15Sgtb 1187ab9b2e15Sgtb /* 1188ab9b2e15Sgtb * if the principal isn't the one requested, free new_entry 1189ab9b2e15Sgtb * and continue to the next. 1190ab9b2e15Sgtb */ 11917c478bd9Sstevel@tonic-gate 1192ab9b2e15Sgtb if (!principal_ignore_inst_compare(context, principal, 1193ab9b2e15Sgtb new_entry.principal)) { 1194ab9b2e15Sgtb krb5_kt_free_entry(context, &new_entry); 1195ab9b2e15Sgtb continue; 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 1198ab9b2e15Sgtb /* 1199ab9b2e15Sgtb * if the enctype is not ignored and doesn't match, free new_entry 1200ab9b2e15Sgtb * and continue to the next 1201ab9b2e15Sgtb */ 12027c478bd9Sstevel@tonic-gate 1203ab9b2e15Sgtb if (enctype != IGNORE_ENCTYPE) { 1204ab9b2e15Sgtb if ((kerror = krb5_c_enctype_compare(context, enctype, 1205ab9b2e15Sgtb new_entry.key.enctype, 1206ab9b2e15Sgtb &similar))) { 1207ab9b2e15Sgtb krb5_kt_free_entry(context, &new_entry); 1208ab9b2e15Sgtb break; 1209ab9b2e15Sgtb } 12107c478bd9Sstevel@tonic-gate 1211ab9b2e15Sgtb if (!similar) { 1212ab9b2e15Sgtb krb5_kt_free_entry(context, &new_entry); 1213ab9b2e15Sgtb continue; 1214ab9b2e15Sgtb } 1215ab9b2e15Sgtb /* 1216ab9b2e15Sgtb * Coerce the enctype of the output keyblock in case we 1217ab9b2e15Sgtb * got an inexact match on the enctype. 1218ab9b2e15Sgtb */ 1219ab9b2e15Sgtb new_entry.key.enctype = enctype; 1220ab9b2e15Sgtb } 12217c478bd9Sstevel@tonic-gate 1222ab9b2e15Sgtb if (kvno == IGNORE_VNO) { 1223ab9b2e15Sgtb /* 1224ab9b2e15Sgtb * if this is the first match, or if the new vno is 1225ab9b2e15Sgtb * bigger, free the current and keep the new. Otherwise, 1226ab9b2e15Sgtb * free the new. 1227ab9b2e15Sgtb */ 1228ab9b2e15Sgtb /* 1229ab9b2e15Sgtb * A 1.2.x keytab contains only the low 8 bits of the key 1230ab9b2e15Sgtb * version number. Since it can be much bigger, and thus 1231ab9b2e15Sgtb * the 8-bit value can wrap, we need some heuristics to 1232ab9b2e15Sgtb * figure out the "highest" numbered key if some numbers 1233ab9b2e15Sgtb * close to 255 and some near 0 are used. 1234ab9b2e15Sgtb * 1235ab9b2e15Sgtb * The heuristic here: 12367c478bd9Sstevel@tonic-gate 1237ab9b2e15Sgtb * If we have any keys with versions over 240, then assume 1238ab9b2e15Sgtb * that all version numbers 0-127 refer to 256+N instead. 1239ab9b2e15Sgtb * Not perfect, but maybe good enough? 1240ab9b2e15Sgtb */ 12417c478bd9Sstevel@tonic-gate 1242ab9b2e15Sgtb #define M(VNO) (((VNO) - kvno_offset + 256) % 256) 12437c478bd9Sstevel@tonic-gate 1244ab9b2e15Sgtb if (new_entry.vno > 240) 1245ab9b2e15Sgtb kvno_offset = 128; 1246ab9b2e15Sgtb if (! cur_entry.principal || 1247ab9b2e15Sgtb M(new_entry.vno) > M(cur_entry.vno)) { 1248ab9b2e15Sgtb krb5_kt_free_entry(context, &cur_entry); 1249ab9b2e15Sgtb cur_entry = new_entry; 1250ab9b2e15Sgtb } else { 1251ab9b2e15Sgtb krb5_kt_free_entry(context, &new_entry); 1252ab9b2e15Sgtb } 1253ab9b2e15Sgtb } else { 1254ab9b2e15Sgtb /* 1255ab9b2e15Sgtb * if this kvno matches, free the current (will there ever 1256ab9b2e15Sgtb * be one?), keep the new, and break out. Otherwise, remember 1257ab9b2e15Sgtb * that we were here so we can return the right error, and 1258ab9b2e15Sgtb * free the new 1259ab9b2e15Sgtb */ 1260ab9b2e15Sgtb /* 1261ab9b2e15Sgtb * Yuck. The krb5-1.2.x keytab format only stores one byte 1262ab9b2e15Sgtb * for the kvno, so we're toast if the kvno requested is 1263ab9b2e15Sgtb * higher than that. Short-term workaround: only compare 1264ab9b2e15Sgtb * the low 8 bits. 1265ab9b2e15Sgtb */ 12667c478bd9Sstevel@tonic-gate 1267ab9b2e15Sgtb if (new_entry.vno == (kvno & 0xff)) { 1268ab9b2e15Sgtb krb5_kt_free_entry(context, &cur_entry); 1269ab9b2e15Sgtb cur_entry = new_entry; 1270ab9b2e15Sgtb break; 1271ab9b2e15Sgtb } else { 1272ab9b2e15Sgtb found_wrong_kvno++; 1273ab9b2e15Sgtb krb5_kt_free_entry(context, &new_entry); 1274ab9b2e15Sgtb } 12757c478bd9Sstevel@tonic-gate } 1276ab9b2e15Sgtb } 12777c478bd9Sstevel@tonic-gate 1278ab9b2e15Sgtb if (kerror == KRB5_KT_END) { 1279ab9b2e15Sgtb if (cur_entry.principal) 1280ab9b2e15Sgtb kerror = 0; 1281ab9b2e15Sgtb else if (found_wrong_kvno) 1282ab9b2e15Sgtb kerror = KRB5_KT_KVNONOTFOUND; 1283ab9b2e15Sgtb else 1284ab9b2e15Sgtb kerror = KRB5_KT_NOTFOUND; 1285ab9b2e15Sgtb } 1286ab9b2e15Sgtb if (kerror) { 1287ab9b2e15Sgtb (void) krb5_ktfileint_close(context, id); 1288ab9b2e15Sgtb krb5_kt_free_entry(context, &cur_entry); 1289ab9b2e15Sgtb KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, kerror=" 1290ab9b2e15Sgtb "%d\n", kerror); 1291ab9b2e15Sgtb return kerror; 1292ab9b2e15Sgtb } 1293ab9b2e15Sgtb if ((kerror = krb5_ktfileint_close(context, id)) != 0) { 1294ab9b2e15Sgtb krb5_kt_free_entry(context, &cur_entry); 1295ab9b2e15Sgtb KRB5_LOG(KRB5_ERR,"ktfile_get_entry() end, ktfileint_close() " 1296ab9b2e15Sgtb "kerror= %d\n", kerror); 1297ab9b2e15Sgtb return kerror; 1298ab9b2e15Sgtb } 1299ab9b2e15Sgtb *entry = cur_entry; 13007c478bd9Sstevel@tonic-gate 1301ab9b2e15Sgtb /* Let us close the file before we leave */ 1302ab9b2e15Sgtb (void) krb5_ktfileint_close(context, id); 13037c478bd9Sstevel@tonic-gate 1304ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "ktfile_get_entry() end"); 1305ab9b2e15Sgtb 1306ab9b2e15Sgtb return 0; 13077c478bd9Sstevel@tonic-gate } 13087c478bd9Sstevel@tonic-gate 1309ab9b2e15Sgtb 13107c478bd9Sstevel@tonic-gate /* 1311ab9b2e15Sgtb * Solaris Kerberos 1312ab9b2e15Sgtb * Given a princ of name/instance@LOCALREALM, search the keytab 1313ab9b2e15Sgtb * for a match of name and LOCALREALM and if found, return instance 1314ab9b2e15Sgtb * as a string. 13157c478bd9Sstevel@tonic-gate * 1316ab9b2e15Sgtb * Caller must free returned string. 13177c478bd9Sstevel@tonic-gate */ 1318ab9b2e15Sgtb static krb5_error_code 1319ab9b2e15Sgtb get_instance_keytab( 1320ab9b2e15Sgtb krb5_context context, 1321ab9b2e15Sgtb const char *sname, 1322ab9b2e15Sgtb krb5_keytab keytab, 1323ab9b2e15Sgtb char **instance) /* out */ 13247c478bd9Sstevel@tonic-gate { 1325ab9b2e15Sgtb krb5_error_code ret=0; 1326ab9b2e15Sgtb krb5_keytab_entry kt_ent; 1327ab9b2e15Sgtb krb5_int32 nelem, free_kt_ent=0; 1328ab9b2e15Sgtb register const krb5_data *p; 1329ab9b2e15Sgtb char *realm=NULL, *s=NULL; 1330ab9b2e15Sgtb krb5_principal client=NULL, princ=NULL; 1331db02be57S size_t realm_size = strlen(KRB5_REFERRAL_REALM) + 1; 13327c478bd9Sstevel@tonic-gate 1333ab9b2e15Sgtb if (!keytab) 1334ab9b2e15Sgtb return EINVAL; 13357c478bd9Sstevel@tonic-gate 1336db02be57S realm = malloc(realm_size); 1337db02be57S if (realm == NULL) 1338db02be57S return (ENOMEM); 1339db02be57S strlcpy(realm, KRB5_REFERRAL_REALM, realm_size); 13407c478bd9Sstevel@tonic-gate 1341ab9b2e15Sgtb ret = krb5_build_principal(context, &client, strlen(realm), 1342ab9b2e15Sgtb realm, sname, "*", 1343ab9b2e15Sgtb (char *)0); 1344ab9b2e15Sgtb if (ret) 1345ab9b2e15Sgtb goto out; 13467c478bd9Sstevel@tonic-gate 1347ab9b2e15Sgtb ret = ktfile_get_entry(context, keytab, client, 1348ab9b2e15Sgtb 0, /* don't have vno available */ 1349ab9b2e15Sgtb 0, &kt_ent); 1350ab9b2e15Sgtb if (ret) 1351ab9b2e15Sgtb goto out; 13527c478bd9Sstevel@tonic-gate 1353ab9b2e15Sgtb free_kt_ent++; /* kt_ent is not a ptr */ 13547c478bd9Sstevel@tonic-gate 1355ab9b2e15Sgtb princ = kt_ent.principal; 1356ab9b2e15Sgtb nelem = krb5_princ_size(context, princ); 1357ab9b2e15Sgtb if (nelem != 2) { 1358ab9b2e15Sgtb ret = KRB5_PRINC_NOMATCH; 1359ab9b2e15Sgtb goto out; 1360ab9b2e15Sgtb } 13617c478bd9Sstevel@tonic-gate 1362ab9b2e15Sgtb p = krb5_princ_component(context, princ, 1); 1363ab9b2e15Sgtb s = calloc(p->length + sizeof(char), sizeof(char)); 1364ab9b2e15Sgtb if (!s) { 1365ab9b2e15Sgtb ret = ENOMEM; 1366ab9b2e15Sgtb goto out; 1367ab9b2e15Sgtb } 13687c478bd9Sstevel@tonic-gate 1369ab9b2e15Sgtb (void) memcpy(s, p->data, p->length); 13707c478bd9Sstevel@tonic-gate 13717c478bd9Sstevel@tonic-gate 1372ab9b2e15Sgtb out: 1373ab9b2e15Sgtb free(realm); 1374ab9b2e15Sgtb if (client) 1375ab9b2e15Sgtb krb5_free_principal(context, client); 1376ab9b2e15Sgtb if (free_kt_ent) 1377ab9b2e15Sgtb (void) krb5_kt_free_entry(context, &kt_ent); 1378ab9b2e15Sgtb 1379ab9b2e15Sgtb if (ret == 0) 1380ab9b2e15Sgtb *instance = s; 1381ab9b2e15Sgtb return ret; 1382ab9b2e15Sgtb } 13837c478bd9Sstevel@tonic-gate 1384ab9b2e15Sgtb static OM_uint32 1385ab9b2e15Sgtb load_root_cred_using_keytab( 1386ab9b2e15Sgtb OM_uint32 *minor_status, 1387ab9b2e15Sgtb krb5_context context, 1388ab9b2e15Sgtb const char *sname, 1389ab9b2e15Sgtb int use_nodename) 1390ab9b2e15Sgtb { 1391ab9b2e15Sgtb krb5_creds my_creds; 1392ab9b2e15Sgtb krb5_principal me; 1393ab9b2e15Sgtb krb5_principal server; 1394ab9b2e15Sgtb krb5_error_code code; 1395ab9b2e15Sgtb krb5_ccache ccache = NULL; 1396ab9b2e15Sgtb krb5_keytab keytab = NULL; 1397ab9b2e15Sgtb krb5_timestamp now; 1398ab9b2e15Sgtb krb5_deltat lifetime = KRB5_DEFAULT_LIFE; /* -l option */ 1399ab9b2e15Sgtb krb5_get_init_creds_opt opt; 1400ab9b2e15Sgtb krb5_data tgtname = { 1401ab9b2e15Sgtb 0, 1402ab9b2e15Sgtb KRB5_TGS_NAME_SIZE, 1403ab9b2e15Sgtb KRB5_TGS_NAME 1404ab9b2e15Sgtb }; 1405ab9b2e15Sgtb char *svcname = NULL; 14067c478bd9Sstevel@tonic-gate 1407ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() start \n"); 14087c478bd9Sstevel@tonic-gate 1409ab9b2e15Sgtb if (!sname) 1410ab9b2e15Sgtb return (GSS_S_FAILURE); 14117c478bd9Sstevel@tonic-gate 1412ab9b2e15Sgtb memset((char *)&my_creds, 0, sizeof(my_creds)); 14137c478bd9Sstevel@tonic-gate 1414ab9b2e15Sgtb if (code = krb5_kt_default(context, &keytab)) { 1415ab9b2e15Sgtb *minor_status = code; 1416ab9b2e15Sgtb return (GSS_S_FAILURE); 1417ab9b2e15Sgtb } 14187c478bd9Sstevel@tonic-gate 1419ab9b2e15Sgtb if (!use_nodename) { 1420ab9b2e15Sgtb char *instance = NULL; 14217c478bd9Sstevel@tonic-gate 1422ab9b2e15Sgtb code = get_instance_keytab(context, sname, keytab, &instance); 1423ab9b2e15Sgtb if (code == 0) { 1424ab9b2e15Sgtb code = krb5_sname_to_principal(context, 1425ab9b2e15Sgtb instance, sname, 1426ab9b2e15Sgtb KRB5_NT_UNKNOWN, &me); 1427ab9b2e15Sgtb free(instance); 1428ab9b2e15Sgtb } 1429ab9b2e15Sgtb } else { 1430ab9b2e15Sgtb code = krb5_sname_to_principal(context, NULL, sname, 1431ab9b2e15Sgtb KRB5_NT_SRV_HST, &me); 1432ab9b2e15Sgtb } 1433db02be57S 1434db02be57S /* Solaris Kerberos */ 143582449e72SMark Phalan if (code == 0 && krb5_is_referral_realm(&me->realm)) { 1436db02be57S krb5_data realm; 1437db02be57S code = krb5_kt_find_realm(context, keytab, me, &realm); 1438db02be57S if (code == 0) { 1439db02be57S krb5_free_data_contents(context, &me->realm); 1440db02be57S me->realm.length = realm.length; 1441db02be57S me->realm.data = realm.data; 1442db02be57S } else { 1443db02be57S /* Try to set a useful error message */ 1444db02be57S char *princ = NULL; 14455e01956fSGlenn Barry krb5_error_code ret; 14465e01956fSGlenn Barry ret = krb5_unparse_name(context, me, &princ); 1447db02be57S 1448db02be57S krb5_set_error_message(context, code, 14495e01956fSGlenn Barry dgettext(TEXT_DOMAIN, 14505e01956fSGlenn Barry "Failed to find realm for %s in keytab"), 14515e01956fSGlenn Barry ret == 0 ? princ : "unknown"); 1452db02be57S if (princ) 1453db02be57S krb5_free_unparsed_name(context, princ); 1454db02be57S } 1455db02be57S } 1456db02be57S 1457ab9b2e15Sgtb if (code) { 1458ab9b2e15Sgtb (void) krb5_kt_close(context, keytab); 1459ab9b2e15Sgtb *minor_status = code; 1460ab9b2e15Sgtb return (GSS_S_FAILURE); 1461ab9b2e15Sgtb } 14627c478bd9Sstevel@tonic-gate 1463ab9b2e15Sgtb my_creds.client = me; 14647c478bd9Sstevel@tonic-gate 1465ab9b2e15Sgtb if((code = krb5_build_principal_ext(context, &server, 1466ab9b2e15Sgtb krb5_princ_realm(context, me)->length, 1467ab9b2e15Sgtb krb5_princ_realm(context, me)->data, 1468ab9b2e15Sgtb tgtname.length, tgtname.data, 1469ab9b2e15Sgtb krb5_princ_realm(context, me)->length, 1470ab9b2e15Sgtb krb5_princ_realm(context, me)->data, 1471ab9b2e15Sgtb 0))) { 1472ab9b2e15Sgtb *minor_status = code; 1473ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1474ab9b2e15Sgtb (void) krb5_kt_close(context, keytab); 14757c478bd9Sstevel@tonic-gate 1476ab9b2e15Sgtb return (GSS_S_FAILURE); 1477ab9b2e15Sgtb } 14787c478bd9Sstevel@tonic-gate 1479ab9b2e15Sgtb my_creds.server = server; 1480ab9b2e15Sgtb my_creds.times.starttime = 0; /* start timer 1481ab9b2e15Sgtb * when request 1482ab9b2e15Sgtb * gets to KDC 1483ab9b2e15Sgtb */ 1484ab9b2e15Sgtb if ((code = krb5_timeofday(context, &now))) { 1485ab9b2e15Sgtb *minor_status = code; 1486ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1487ab9b2e15Sgtb (void) krb5_kt_close(context, keytab); 14887c478bd9Sstevel@tonic-gate 1489ab9b2e15Sgtb return (GSS_S_FAILURE); 1490ab9b2e15Sgtb } 1491ab9b2e15Sgtb my_creds.times.endtime = now + lifetime; 1492ab9b2e15Sgtb my_creds.times.renew_till = 0; 14937c478bd9Sstevel@tonic-gate 1494ab9b2e15Sgtb memset(&opt, 0, sizeof (opt)); 1495ab9b2e15Sgtb krb5_get_init_creds_opt_init(&opt); 1496ab9b2e15Sgtb krb5_get_init_creds_opt_set_tkt_life(&opt, lifetime); 14977c478bd9Sstevel@tonic-gate 1498ab9b2e15Sgtb code = krb5_unparse_name(context, server, &svcname); 1499ab9b2e15Sgtb if (code != 0) { 1500ab9b2e15Sgtb *minor_status = code; 1501ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1502ab9b2e15Sgtb (void) krb5_kt_close(context, keytab); 15037c478bd9Sstevel@tonic-gate 1504ab9b2e15Sgtb return (GSS_S_FAILURE); 1505ab9b2e15Sgtb } 1506ab9b2e15Sgtb /* 1507ab9b2e15Sgtb * Evidently (sigh), on success, krb5_get_init_creds_keytab 1508ab9b2e15Sgtb * changes the my_creds princ ptrs so we need to free those 1509ab9b2e15Sgtb * princs (me&server) as well as freeing all of my_creds contents. 1510ab9b2e15Sgtb */ 1511ab9b2e15Sgtb code = krb5_get_init_creds_keytab(context, 1512ab9b2e15Sgtb &my_creds, me, keytab, 1513ab9b2e15Sgtb 0, svcname, &opt); 15147c478bd9Sstevel@tonic-gate 1515ab9b2e15Sgtb (void) krb5_kt_close(context, keytab); 15167c478bd9Sstevel@tonic-gate 1517ab9b2e15Sgtb if (svcname != NULL) 1518ab9b2e15Sgtb free(svcname); 1519ab9b2e15Sgtb if (code) { 1520ab9b2e15Sgtb *minor_status = code; 1521ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 15227c478bd9Sstevel@tonic-gate 1523ab9b2e15Sgtb return (GSS_S_FAILURE); 1524ab9b2e15Sgtb } 15257c478bd9Sstevel@tonic-gate 1526ab9b2e15Sgtb krb5_free_principal(context, server); 1527ab9b2e15Sgtb server = NULL; 15287c478bd9Sstevel@tonic-gate 1529ab9b2e15Sgtb code = krb5_cc_resolve (context, 1530ab9b2e15Sgtb krb5_cc_default_name(context), 1531ab9b2e15Sgtb &ccache); 1532ab9b2e15Sgtb if (code != 0) { 1533ab9b2e15Sgtb *minor_status = code; 1534ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1535ab9b2e15Sgtb krb5_free_principal(context, me); 15367c478bd9Sstevel@tonic-gate 1537ab9b2e15Sgtb return (GSS_S_FAILURE); 1538ab9b2e15Sgtb } 1539ab9b2e15Sgtb code = krb5_cc_initialize (context, ccache, me); 1540ab9b2e15Sgtb krb5_free_principal(context, me); 1541ab9b2e15Sgtb me = NULL; 1542ab9b2e15Sgtb if (code != 0) { 1543ab9b2e15Sgtb *minor_status = code; 1544ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1545ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 15467c478bd9Sstevel@tonic-gate 1547ab9b2e15Sgtb return (GSS_S_FAILURE); 1548ab9b2e15Sgtb } 15497c478bd9Sstevel@tonic-gate 1550ab9b2e15Sgtb code = krb5_cc_store_cred(context, ccache, 1551ab9b2e15Sgtb &my_creds); 1552ab9b2e15Sgtb krb5_free_cred_contents(context, &my_creds); 1553ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 15547c478bd9Sstevel@tonic-gate 1555ab9b2e15Sgtb if (code) { 1556ab9b2e15Sgtb *minor_status = code; 15577c478bd9Sstevel@tonic-gate 1558ab9b2e15Sgtb KRB5_LOG(KRB5_ERR, "load_root_cred_using_keytab() end, error " 1559ab9b2e15Sgtb "code = %d\n", code); 15607c478bd9Sstevel@tonic-gate 1561ab9b2e15Sgtb return (GSS_S_FAILURE); 15627c478bd9Sstevel@tonic-gate } 1563ab9b2e15Sgtb 1564ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "load_root_cred_using_keytab() end \n"); 15657c478bd9Sstevel@tonic-gate 1566ab9b2e15Sgtb return (GSS_S_COMPLETE); 1567ab9b2e15Sgtb } 15687c478bd9Sstevel@tonic-gate 1569ab9b2e15Sgtb static OM_uint32 1570ab9b2e15Sgtb renew_ccache(OM_uint32 *minor_status, krb5_context context, uid_t uid) 1571ab9b2e15Sgtb { 1572ab9b2e15Sgtb krb5_principal me; 1573ab9b2e15Sgtb krb5_principal server; 1574ab9b2e15Sgtb krb5_creds creds; 1575ab9b2e15Sgtb krb5_creds tmpcreds; 1576ab9b2e15Sgtb krb5_creds *out_creds; 1577ab9b2e15Sgtb krb5_error_code code; 1578ab9b2e15Sgtb krb5_ccache ccache = NULL; 1579ab9b2e15Sgtb static char ccache_name_buf[CACHE_FILENAME_LEN]; 1580ab9b2e15Sgtb int options = 0; 1581ab9b2e15Sgtb krb5_data tgtname = { 1582ab9b2e15Sgtb 0, 1583ab9b2e15Sgtb KRB5_TGS_NAME_SIZE, 1584ab9b2e15Sgtb KRB5_TGS_NAME 1585ab9b2e15Sgtb }; 1586ab9b2e15Sgtb gid_t gid = getgid(); 15877c478bd9Sstevel@tonic-gate 1588ab9b2e15Sgtb memset((char *)&creds, 0, sizeof(creds)); 1589ab9b2e15Sgtb memset((char *)&tmpcreds, 0, sizeof(creds)); 15907c478bd9Sstevel@tonic-gate 1591ab9b2e15Sgtb if ((code = krb5_cc_default(context, &ccache))) { 1592ab9b2e15Sgtb *minor_status = code; 1593ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 1594ab9b2e15Sgtb return (GSS_S_FAILURE); 1595ab9b2e15Sgtb } 15967c478bd9Sstevel@tonic-gate 1597ab9b2e15Sgtb if ((code = krb5_cc_get_principal(context, ccache, &me)) != 0) { 1598ab9b2e15Sgtb *minor_status = code; 1599ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 1600ab9b2e15Sgtb return (GSS_S_FAILURE); 1601ab9b2e15Sgtb } 16027c478bd9Sstevel@tonic-gate 1603ab9b2e15Sgtb creds.client = me; 16047c478bd9Sstevel@tonic-gate 1605ab9b2e15Sgtb if((code = krb5_build_principal_ext(context, &server, 1606ab9b2e15Sgtb krb5_princ_realm(context, me)->length, 1607ab9b2e15Sgtb krb5_princ_realm(context, me)->data, 1608ab9b2e15Sgtb tgtname.length, tgtname.data, 1609ab9b2e15Sgtb krb5_princ_realm(context, me)->length, 1610ab9b2e15Sgtb krb5_princ_realm(context, me)->data, 1611ab9b2e15Sgtb 0))) { 1612ab9b2e15Sgtb krb5_free_principal(context, me); 1613ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 1614ab9b2e15Sgtb *minor_status = code; 1615ab9b2e15Sgtb return (GSS_S_FAILURE); 1616ab9b2e15Sgtb } 16177c478bd9Sstevel@tonic-gate 1618ab9b2e15Sgtb creds.server = server; 1619ab9b2e15Sgtb creds.ticket_flags = TKT_FLG_RENEWABLE; 1620ab9b2e15Sgtb 1621ab9b2e15Sgtb if ((krb5_cc_retrieve_cred(context, ccache, KRB5_TC_MATCH_FLAGS, 1622ab9b2e15Sgtb &creds, &tmpcreds))) { 1623ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 1624ab9b2e15Sgtb return (KDC_ERR_BADOPTION); 1625ab9b2e15Sgtb } 1626ab9b2e15Sgtb 1627ab9b2e15Sgtb creds.ticket_flags = 0; 1628ab9b2e15Sgtb code = krb5_get_credentials_renew(context, options, ccache, 1629ab9b2e15Sgtb &creds, &out_creds); 1630ab9b2e15Sgtb krb5_free_cred_contents(context, &creds); 1631ab9b2e15Sgtb krb5_free_cred_contents(context, &tmpcreds); 16327c478bd9Sstevel@tonic-gate 1633ab9b2e15Sgtb if (code) { 1634ab9b2e15Sgtb *minor_status = code; 1635ab9b2e15Sgtb return (GSS_S_FAILURE); 1636ab9b2e15Sgtb } 16377c478bd9Sstevel@tonic-gate 1638ab9b2e15Sgtb krb5_free_creds(context, out_creds); 1639ab9b2e15Sgtb snprintf(ccache_name_buf, CACHE_FILENAME_LEN, "/tmp/krb5cc_%d", 1640ab9b2e15Sgtb uid, -1); 1641ab9b2e15Sgtb code = safechown(ccache_name_buf, uid, gid, -1); 16427c478bd9Sstevel@tonic-gate 1643ab9b2e15Sgtb if (code == -1) { 1644ab9b2e15Sgtb (void) krb5_cc_destroy(context, ccache); 1645ab9b2e15Sgtb *minor_status = code; 1646ab9b2e15Sgtb return (GSS_S_FAILURE); 1647ab9b2e15Sgtb } 16487c478bd9Sstevel@tonic-gate 1649ab9b2e15Sgtb (void) krb5_cc_close(context, ccache); 1650ab9b2e15Sgtb 1651ab9b2e15Sgtb return (GSS_S_COMPLETE); 16527c478bd9Sstevel@tonic-gate 16537c478bd9Sstevel@tonic-gate } 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate /* 1656ab9b2e15Sgtb * Solaris Kerberos: 1657ab9b2e15Sgtb * We enforce a minimum refresh time on the root cred. This avoids problems for 1658ab9b2e15Sgtb * the higher level communication protocol for having valid creds and 1659ab9b2e15Sgtb * setting up a valid context, only to have it expire before or while 1660ab9b2e15Sgtb * it is being used. For non root users we don't care since we do not refresh 1661ab9b2e15Sgtb * there creds, they get what they can get. 16627c478bd9Sstevel@tonic-gate */ 1663ab9b2e15Sgtb #define MIN_REFRESH_TIME 300 1664ab9b2e15Sgtb #define MIN_RENEW_TIME 1500 1665ab9b2e15Sgtb 1666ab9b2e15Sgtb /* get_default_cred() must be called with the krb5_mutex lock held */ 1667ab9b2e15Sgtb static OM_uint32 1668ab9b2e15Sgtb get_default_cred(OM_uint32 *minor_status, void *ct, gss_cred_id_t *cred_handle) 16697c478bd9Sstevel@tonic-gate { 1670ab9b2e15Sgtb krb5_timestamp now; 1671ab9b2e15Sgtb krb5_gss_cred_id_t cred; 1672ab9b2e15Sgtb OM_uint32 major; 1673ab9b2e15Sgtb OM_uint32 mntmp; 1674ab9b2e15Sgtb /* 1675ab9b2e15Sgtb * Solaris Kerberos 1676ab9b2e15Sgtb * Use krb5_getuid() to select the mechanism to obtain the uid. 1677ab9b2e15Sgtb */ 1678ab9b2e15Sgtb uid_t uid = krb5_getuid(); 1679ab9b2e15Sgtb krb5_context context = (krb5_context)ct; 16807c478bd9Sstevel@tonic-gate 1681ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "get_default_cred() start\n"); 16827c478bd9Sstevel@tonic-gate 1683ab9b2e15Sgtb /* Get the default cred for user */ 1684*940daf74SToomas Soome if (((major = kg_get_defcred(minor_status, cred_handle)) != 0) && 1685ab9b2e15Sgtb GSS_ERROR(major)) { 16867c478bd9Sstevel@tonic-gate 1687ab9b2e15Sgtb /* If we're not root we're done */ 1688ab9b2e15Sgtb if (uid != ROOT_UID) 1689ab9b2e15Sgtb return (major); 16907c478bd9Sstevel@tonic-gate 1691ab9b2e15Sgtb /* 1692ab9b2e15Sgtb * Try and get root's cred in the cache using keytab. 1693ab9b2e15Sgtb * 1694ab9b2e15Sgtb * First try "root" and then try "host" - this allows 1695ab9b2e15Sgtb * Secure NFS to use the host principal for mounting if 1696ab9b2e15Sgtb * there is no root principal. 1697ab9b2e15Sgtb * 1698ab9b2e15Sgtb * Then try "host/<anything>" to match any instance (needed 1699ab9b2e15Sgtb * for DHCP clients). 1700ab9b2e15Sgtb */ 1701ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1702ab9b2e15Sgtb context, "root", 1); 17037c478bd9Sstevel@tonic-gate 1704ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1705ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1706ab9b2e15Sgtb context, "host", 1); 1707ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1708ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1709ab9b2e15Sgtb context, "host", 0); 17107c478bd9Sstevel@tonic-gate 1711ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1712ab9b2e15Sgtb return (major); 17137c478bd9Sstevel@tonic-gate 1714ab9b2e15Sgtb /* We should have valid tgt now in the cache, so get it. */ 1715ab9b2e15Sgtb major = kg_get_defcred(minor_status, cred_handle); 17167c478bd9Sstevel@tonic-gate 1717ab9b2e15Sgtb return (major); 1718ab9b2e15Sgtb } 17197c478bd9Sstevel@tonic-gate 1720ab9b2e15Sgtb /* We've got a gss cred handle that is a kerberos cred handle. */ 1721ab9b2e15Sgtb cred = (krb5_gss_cred_id_t)*cred_handle; 1722ab9b2e15Sgtb 1723ab9b2e15Sgtb /* If we can't get the time, assume the worst. */ 1724ab9b2e15Sgtb if (krb5_timeofday(context, &now)) { 1725ab9b2e15Sgtb (void) krb5_gss_release_cred(&mntmp, cred_handle); 1726ab9b2e15Sgtb return (GSS_S_CREDENTIALS_EXPIRED); 1727ab9b2e15Sgtb } 17287c478bd9Sstevel@tonic-gate 1729ab9b2e15Sgtb /* If root's cred has expired re-get it */ 1730ab9b2e15Sgtb if (cred->tgt_expire < now + MIN_REFRESH_TIME && uid == ROOT_UID) { 1731ab9b2e15Sgtb (void) krb5_gss_release_cred(&mntmp, cred_handle); 17327c478bd9Sstevel@tonic-gate 1733ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1734ab9b2e15Sgtb context, "root", 1); 17357c478bd9Sstevel@tonic-gate 1736ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1737ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1738ab9b2e15Sgtb context, "host", 1); 17397c478bd9Sstevel@tonic-gate 1740ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1741ab9b2e15Sgtb major = load_root_cred_using_keytab(minor_status, 1742ab9b2e15Sgtb context, "host", 0); 1743ab9b2e15Sgtb 1744ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1745ab9b2e15Sgtb return (major); 1746ab9b2e15Sgtb 1747ab9b2e15Sgtb major = kg_get_defcred(minor_status, cred_handle); 1748ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1749ab9b2e15Sgtb return (major); 1750ab9b2e15Sgtb 1751ab9b2e15Sgtb /* Any body else is SOL unless we can renew their credential cache */ 1752ab9b2e15Sgtb } else if ((cred->tgt_expire < now + MIN_RENEW_TIME) && 1753ab9b2e15Sgtb (cred->tgt_expire > now)) { 1754ab9b2e15Sgtb (void) krb5_gss_release_cred(&mntmp, cred_handle); 1755ab9b2e15Sgtb 1756ab9b2e15Sgtb major = renew_ccache(minor_status, context, uid); 1757ab9b2e15Sgtb if ((major != GSS_S_COMPLETE) && 1758ab9b2e15Sgtb (major != KDC_ERR_BADOPTION)) 1759ab9b2e15Sgtb return (major); 1760ab9b2e15Sgtb 1761ab9b2e15Sgtb major = kg_get_defcred(minor_status, cred_handle); 1762ab9b2e15Sgtb if (major != GSS_S_COMPLETE) 1763ab9b2e15Sgtb return (major); 17647c478bd9Sstevel@tonic-gate 1765ab9b2e15Sgtb } 17667c478bd9Sstevel@tonic-gate 1767ab9b2e15Sgtb /* Otherwise we got non expired creds */ 17687c478bd9Sstevel@tonic-gate 1769ab9b2e15Sgtb KRB5_LOG0(KRB5_INFO, "get_default_cred() end\n"); 17707c478bd9Sstevel@tonic-gate 1771ab9b2e15Sgtb return (GSS_S_COMPLETE); 17727c478bd9Sstevel@tonic-gate } 1773ab9b2e15Sgtb 1774ab9b2e15Sgtb /* Solaris Kerberos specific routines end */ 1775