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