1*7c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 2*7c478bd9Sstevel@tonic-gate /* 3*7c478bd9Sstevel@tonic-gate * kadmin/v5server/keytab.c 4*7c478bd9Sstevel@tonic-gate * 5*7c478bd9Sstevel@tonic-gate * Copyright 1995 by the Massachusetts Institute of Technology. 6*7c478bd9Sstevel@tonic-gate * All Rights Reserved. 7*7c478bd9Sstevel@tonic-gate * 8*7c478bd9Sstevel@tonic-gate * Export of this software from the United States of America may 9*7c478bd9Sstevel@tonic-gate * require a specific license from the United States Government. 10*7c478bd9Sstevel@tonic-gate * It is the responsibility of any person or organization contemplating 11*7c478bd9Sstevel@tonic-gate * export to obtain such a license before exporting. 12*7c478bd9Sstevel@tonic-gate * 13*7c478bd9Sstevel@tonic-gate * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and 14*7c478bd9Sstevel@tonic-gate * distribute this software and its documentation for any purpose and 15*7c478bd9Sstevel@tonic-gate * without fee is hereby granted, provided that the above copyright 16*7c478bd9Sstevel@tonic-gate * notice appear in all copies and that both that copyright notice and 17*7c478bd9Sstevel@tonic-gate * this permission notice appear in supporting documentation, and that 18*7c478bd9Sstevel@tonic-gate * the name of M.I.T. not be used in advertising or publicity pertaining 19*7c478bd9Sstevel@tonic-gate * to distribution of the software without specific, written prior 20*7c478bd9Sstevel@tonic-gate * permission. Furthermore if you modify this software you must label 21*7c478bd9Sstevel@tonic-gate * your software as modified software and not distribute it in such a 22*7c478bd9Sstevel@tonic-gate * fashion that it might be confused with the original M.I.T. software. 23*7c478bd9Sstevel@tonic-gate * M.I.T. makes no representations about the suitability of 24*7c478bd9Sstevel@tonic-gate * this software for any purpose. It is provided "as is" without express 25*7c478bd9Sstevel@tonic-gate * or implied warranty. 26*7c478bd9Sstevel@tonic-gate * 27*7c478bd9Sstevel@tonic-gate */ 28*7c478bd9Sstevel@tonic-gate #include <string.h> 29*7c478bd9Sstevel@tonic-gate 30*7c478bd9Sstevel@tonic-gate #include "k5-int.h" 31*7c478bd9Sstevel@tonic-gate 32*7c478bd9Sstevel@tonic-gate static int 33*7c478bd9Sstevel@tonic-gate is_xrealm_tgt(krb5_context, krb5_const_principal); 34*7c478bd9Sstevel@tonic-gate 35*7c478bd9Sstevel@tonic-gate krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab); 36*7c478bd9Sstevel@tonic-gate 37*7c478bd9Sstevel@tonic-gate krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal, 38*7c478bd9Sstevel@tonic-gate krb5_kvno, krb5_enctype, krb5_keytab_entry *); 39*7c478bd9Sstevel@tonic-gate 40*7c478bd9Sstevel@tonic-gate krb5_error_code krb5_ktkdb_resolve( 41*7c478bd9Sstevel@tonic-gate krb5_context context, 42*7c478bd9Sstevel@tonic-gate const char * name, 43*7c478bd9Sstevel@tonic-gate krb5_keytab * id); 44*7c478bd9Sstevel@tonic-gate 45*7c478bd9Sstevel@tonic-gate krb5_kt_ops krb5_kt_kdb_ops = { 46*7c478bd9Sstevel@tonic-gate 0, 47*7c478bd9Sstevel@tonic-gate "KDB", /* Prefix -- this string should not appear anywhere else! */ 48*7c478bd9Sstevel@tonic-gate krb5_ktkdb_resolve, /* resolve */ 49*7c478bd9Sstevel@tonic-gate NULL, /* get_name */ 50*7c478bd9Sstevel@tonic-gate krb5_ktkdb_close, /* close */ 51*7c478bd9Sstevel@tonic-gate krb5_ktkdb_get_entry, /* get */ 52*7c478bd9Sstevel@tonic-gate NULL, /* start_seq_get */ 53*7c478bd9Sstevel@tonic-gate NULL, /* get_next */ 54*7c478bd9Sstevel@tonic-gate NULL, /* end_get */ 55*7c478bd9Sstevel@tonic-gate NULL, /* add (extended) */ 56*7c478bd9Sstevel@tonic-gate NULL, /* remove (extended) */ 57*7c478bd9Sstevel@tonic-gate NULL, /* (void *) &krb5_ktfile_ser_entry */ 58*7c478bd9Sstevel@tonic-gate }; 59*7c478bd9Sstevel@tonic-gate 60*7c478bd9Sstevel@tonic-gate typedef struct krb5_ktkdb_data { 61*7c478bd9Sstevel@tonic-gate char * name; 62*7c478bd9Sstevel@tonic-gate } krb5_ktkdb_data; 63*7c478bd9Sstevel@tonic-gate 64*7c478bd9Sstevel@tonic-gate krb5_error_code 65*7c478bd9Sstevel@tonic-gate krb5_ktkdb_resolve(context, name, id) 66*7c478bd9Sstevel@tonic-gate krb5_context context; 67*7c478bd9Sstevel@tonic-gate const char * name; 68*7c478bd9Sstevel@tonic-gate krb5_keytab * id; 69*7c478bd9Sstevel@tonic-gate { 70*7c478bd9Sstevel@tonic-gate if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL) 71*7c478bd9Sstevel@tonic-gate return(ENOMEM); 72*7c478bd9Sstevel@tonic-gate (*id)->ops = &krb5_kt_kdb_ops; 73*7c478bd9Sstevel@tonic-gate (*id)->magic = KV5M_KEYTAB; 74*7c478bd9Sstevel@tonic-gate return(0); 75*7c478bd9Sstevel@tonic-gate } 76*7c478bd9Sstevel@tonic-gate 77*7c478bd9Sstevel@tonic-gate krb5_error_code 78*7c478bd9Sstevel@tonic-gate krb5_ktkdb_close(context, kt) 79*7c478bd9Sstevel@tonic-gate krb5_context context; 80*7c478bd9Sstevel@tonic-gate krb5_keytab kt; 81*7c478bd9Sstevel@tonic-gate { 82*7c478bd9Sstevel@tonic-gate /* 83*7c478bd9Sstevel@tonic-gate * This routine is responsible for freeing all memory allocated 84*7c478bd9Sstevel@tonic-gate * for this keytab. There are no system resources that need 85*7c478bd9Sstevel@tonic-gate * to be freed nor are there any open files. 86*7c478bd9Sstevel@tonic-gate * 87*7c478bd9Sstevel@tonic-gate * This routine should undo anything done by krb5_ktkdb_resolve(). 88*7c478bd9Sstevel@tonic-gate */ 89*7c478bd9Sstevel@tonic-gate 90*7c478bd9Sstevel@tonic-gate kt->ops = NULL; 91*7c478bd9Sstevel@tonic-gate krb5_xfree(kt); 92*7c478bd9Sstevel@tonic-gate 93*7c478bd9Sstevel@tonic-gate return 0; 94*7c478bd9Sstevel@tonic-gate } 95*7c478bd9Sstevel@tonic-gate 96*7c478bd9Sstevel@tonic-gate static krb5_context ktkdb_ctx = NULL; 97*7c478bd9Sstevel@tonic-gate 98*7c478bd9Sstevel@tonic-gate /* 99*7c478bd9Sstevel@tonic-gate * Set a different context for use with ktkdb_get_entry(). This is 100*7c478bd9Sstevel@tonic-gate * primarily useful for kadmind, where the gssapi library context, 101*7c478bd9Sstevel@tonic-gate * which will be used for the keytab, will necessarily have a 102*7c478bd9Sstevel@tonic-gate * different context than that used by the kadm5 library to access the 103*7c478bd9Sstevel@tonic-gate * database for its own purposes. 104*7c478bd9Sstevel@tonic-gate */ 105*7c478bd9Sstevel@tonic-gate krb5_error_code 106*7c478bd9Sstevel@tonic-gate krb5_ktkdb_set_context(krb5_context ctx) 107*7c478bd9Sstevel@tonic-gate { 108*7c478bd9Sstevel@tonic-gate ktkdb_ctx = ctx; 109*7c478bd9Sstevel@tonic-gate return 0; 110*7c478bd9Sstevel@tonic-gate } 111*7c478bd9Sstevel@tonic-gate 112*7c478bd9Sstevel@tonic-gate krb5_error_code 113*7c478bd9Sstevel@tonic-gate krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) 114*7c478bd9Sstevel@tonic-gate krb5_context in_context; 115*7c478bd9Sstevel@tonic-gate krb5_keytab id; 116*7c478bd9Sstevel@tonic-gate krb5_const_principal principal; 117*7c478bd9Sstevel@tonic-gate krb5_kvno kvno; 118*7c478bd9Sstevel@tonic-gate krb5_enctype enctype; 119*7c478bd9Sstevel@tonic-gate krb5_keytab_entry * entry; 120*7c478bd9Sstevel@tonic-gate { 121*7c478bd9Sstevel@tonic-gate krb5_context context; 122*7c478bd9Sstevel@tonic-gate krb5_keyblock * master_key; 123*7c478bd9Sstevel@tonic-gate krb5_error_code kerror = 0; 124*7c478bd9Sstevel@tonic-gate krb5_key_data * key_data; 125*7c478bd9Sstevel@tonic-gate krb5_db_entry db_entry; 126*7c478bd9Sstevel@tonic-gate krb5_boolean more = 0; 127*7c478bd9Sstevel@tonic-gate int n = 0; 128*7c478bd9Sstevel@tonic-gate int xrealm_tgt = is_xrealm_tgt(context, principal); 129*7c478bd9Sstevel@tonic-gate krb5_boolean similar; 130*7c478bd9Sstevel@tonic-gate 131*7c478bd9Sstevel@tonic-gate if (ktkdb_ctx) 132*7c478bd9Sstevel@tonic-gate context = ktkdb_ctx; 133*7c478bd9Sstevel@tonic-gate else 134*7c478bd9Sstevel@tonic-gate context = in_context; 135*7c478bd9Sstevel@tonic-gate 136*7c478bd9Sstevel@tonic-gate /* Open database */ 137*7c478bd9Sstevel@tonic-gate /* krb5_db_init(context); */ 138*7c478bd9Sstevel@tonic-gate if ((kerror = krb5_db_open_database(context))) 139*7c478bd9Sstevel@tonic-gate return(kerror); 140*7c478bd9Sstevel@tonic-gate 141*7c478bd9Sstevel@tonic-gate /* get_principal */ 142*7c478bd9Sstevel@tonic-gate kerror = krb5_db_get_principal(context, principal, & 143*7c478bd9Sstevel@tonic-gate db_entry, &n, &more); 144*7c478bd9Sstevel@tonic-gate if (kerror) { 145*7c478bd9Sstevel@tonic-gate krb5_db_close_database(context); 146*7c478bd9Sstevel@tonic-gate return(kerror); 147*7c478bd9Sstevel@tonic-gate } 148*7c478bd9Sstevel@tonic-gate if (n != 1) { 149*7c478bd9Sstevel@tonic-gate krb5_db_close_database(context); 150*7c478bd9Sstevel@tonic-gate return KRB5_KT_NOTFOUND; 151*7c478bd9Sstevel@tonic-gate } 152*7c478bd9Sstevel@tonic-gate 153*7c478bd9Sstevel@tonic-gate if (db_entry.attributes & KRB5_KDB_DISALLOW_SVR 154*7c478bd9Sstevel@tonic-gate || db_entry.attributes & KRB5_KDB_DISALLOW_ALL_TIX) { 155*7c478bd9Sstevel@tonic-gate kerror = KRB5_KT_NOTFOUND; 156*7c478bd9Sstevel@tonic-gate goto error; 157*7c478bd9Sstevel@tonic-gate } 158*7c478bd9Sstevel@tonic-gate 159*7c478bd9Sstevel@tonic-gate /* match key */ 160*7c478bd9Sstevel@tonic-gate kerror = krb5_db_get_mkey(context, &master_key); 161*7c478bd9Sstevel@tonic-gate if (kerror) 162*7c478bd9Sstevel@tonic-gate goto error; 163*7c478bd9Sstevel@tonic-gate 164*7c478bd9Sstevel@tonic-gate /* For cross realm tgts, we match whatever enctype is provided; 165*7c478bd9Sstevel@tonic-gate * for other principals, we only match the first enctype that is 166*7c478bd9Sstevel@tonic-gate * found. Since the TGS and AS code do the same thing, then we 167*7c478bd9Sstevel@tonic-gate * will only successfully decrypt tickets we have issued.*/ 168*7c478bd9Sstevel@tonic-gate kerror = krb5_dbe_find_enctype(context, &db_entry, 169*7c478bd9Sstevel@tonic-gate xrealm_tgt?enctype:-1, 170*7c478bd9Sstevel@tonic-gate -1, kvno, &key_data); 171*7c478bd9Sstevel@tonic-gate if (kerror) 172*7c478bd9Sstevel@tonic-gate goto error; 173*7c478bd9Sstevel@tonic-gate 174*7c478bd9Sstevel@tonic-gate 175*7c478bd9Sstevel@tonic-gate kerror = krb5_dbekd_decrypt_key_data(context, master_key, 176*7c478bd9Sstevel@tonic-gate key_data, &entry->key, NULL); 177*7c478bd9Sstevel@tonic-gate if (kerror) 178*7c478bd9Sstevel@tonic-gate goto error; 179*7c478bd9Sstevel@tonic-gate 180*7c478bd9Sstevel@tonic-gate if (enctype > 0) { 181*7c478bd9Sstevel@tonic-gate kerror = krb5_c_enctype_compare(context, enctype, 182*7c478bd9Sstevel@tonic-gate entry->key.enctype, &similar); 183*7c478bd9Sstevel@tonic-gate if (kerror) 184*7c478bd9Sstevel@tonic-gate goto error; 185*7c478bd9Sstevel@tonic-gate 186*7c478bd9Sstevel@tonic-gate if (!similar) { 187*7c478bd9Sstevel@tonic-gate kerror = KRB5_KDB_NO_PERMITTED_KEY; 188*7c478bd9Sstevel@tonic-gate goto error; 189*7c478bd9Sstevel@tonic-gate } 190*7c478bd9Sstevel@tonic-gate } 191*7c478bd9Sstevel@tonic-gate /* 192*7c478bd9Sstevel@tonic-gate * Coerce the enctype of the output keyblock in case we got an 193*7c478bd9Sstevel@tonic-gate * inexact match on the enctype. 194*7c478bd9Sstevel@tonic-gate */ 195*7c478bd9Sstevel@tonic-gate entry->key.enctype = enctype; 196*7c478bd9Sstevel@tonic-gate 197*7c478bd9Sstevel@tonic-gate kerror = krb5_copy_principal(context, principal, &entry->principal); 198*7c478bd9Sstevel@tonic-gate if (kerror) 199*7c478bd9Sstevel@tonic-gate goto error; 200*7c478bd9Sstevel@tonic-gate 201*7c478bd9Sstevel@tonic-gate /* Close database */ 202*7c478bd9Sstevel@tonic-gate error: 203*7c478bd9Sstevel@tonic-gate krb5_dbe_free_contents(context, &db_entry); 204*7c478bd9Sstevel@tonic-gate krb5_db_close_database(context); 205*7c478bd9Sstevel@tonic-gate return(kerror); 206*7c478bd9Sstevel@tonic-gate } 207*7c478bd9Sstevel@tonic-gate 208*7c478bd9Sstevel@tonic-gate /* 209*7c478bd9Sstevel@tonic-gate * is_xrealm_tgt: Returns true if the principal is a cross-realm TGT 210*7c478bd9Sstevel@tonic-gate * principal-- a principal with first component krbtgt and second 211*7c478bd9Sstevel@tonic-gate * component not equal to realm. 212*7c478bd9Sstevel@tonic-gate */ 213*7c478bd9Sstevel@tonic-gate static int 214*7c478bd9Sstevel@tonic-gate is_xrealm_tgt(krb5_context context, krb5_const_principal princ) 215*7c478bd9Sstevel@tonic-gate { 216*7c478bd9Sstevel@tonic-gate krb5_data *dat; 217*7c478bd9Sstevel@tonic-gate if (krb5_princ_size(context, princ) != 2) 218*7c478bd9Sstevel@tonic-gate return 0; 219*7c478bd9Sstevel@tonic-gate dat = krb5_princ_component(context, princ, 0); 220*7c478bd9Sstevel@tonic-gate if (strncmp("krbtgt", dat->data, dat->length) != 0) 221*7c478bd9Sstevel@tonic-gate return 0; 222*7c478bd9Sstevel@tonic-gate dat = krb5_princ_component(context, princ, 1); 223*7c478bd9Sstevel@tonic-gate if (dat->length != princ->realm.length) 224*7c478bd9Sstevel@tonic-gate return 1; 225*7c478bd9Sstevel@tonic-gate if (strncmp(dat->data, princ->realm.data, dat->length) == 0) 226*7c478bd9Sstevel@tonic-gate return 0; 227*7c478bd9Sstevel@tonic-gate return 1; 228*7c478bd9Sstevel@tonic-gate 229*7c478bd9Sstevel@tonic-gate } 230*7c478bd9Sstevel@tonic-gate 231