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