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 /* 28 * Copyright 2015 OmniTI Computer Consulting, Inc. All rights reserved. 29 * Copyright 2024 Toomas Soome <tsoome@me.com> 30 */ 31 #include <string.h> 32 33 #include "k5-int.h" 34 #include "kdb_kt.h" 35 36 static int 37 is_xrealm_tgt(krb5_context, krb5_const_principal); 38 39 krb5_error_code krb5_ktkdb_close (krb5_context, krb5_keytab); 40 41 krb5_error_code krb5_ktkdb_get_entry (krb5_context, krb5_keytab, krb5_const_principal, 42 krb5_kvno, krb5_enctype, krb5_keytab_entry *); 43 44 static krb5_error_code 45 krb5_ktkdb_get_name(krb5_context context, krb5_keytab keytab, 46 char *name, unsigned int namelen) 47 { 48 if (namelen < sizeof("KDB:")) 49 return KRB5_KT_NAME_TOOLONG; 50 strcpy(name, "KDB:"); 51 return 0; 52 } 53 54 krb5_kt_ops krb5_kt_kdb_ops = { 55 0, 56 "KDB", /* Prefix -- this string should not appear anywhere else! */ 57 krb5_ktkdb_resolve, /* resolve */ 58 krb5_ktkdb_get_name, /* get_name */ 59 krb5_ktkdb_close, /* close */ 60 krb5_ktkdb_get_entry, /* get */ 61 NULL, /* start_seq_get */ 62 NULL, /* get_next */ 63 NULL, /* end_get */ 64 NULL, /* add (extended) */ 65 NULL, /* remove (extended) */ 66 NULL, /* (void *) &krb5_ktfile_ser_entry */ 67 }; 68 69 typedef struct krb5_ktkdb_data { 70 char *name; 71 } krb5_ktkdb_data; 72 73 krb5_error_code 74 krb5_ktkdb_resolve(krb5_context context, const char *name, krb5_keytab *id) 75 { 76 krb5_ktkdb_data *data; 77 krb5_keytab kt; 78 79 kt = malloc(sizeof (*kt)); 80 if (kt == NULL) 81 return (ENOMEM); 82 83 kt->ops = &krb5_kt_kdb_ops; 84 kt->magic = KV5M_KEYTAB; 85 86 data = calloc(1, sizeof (*data)); 87 if (data == NULL) 88 goto fail; 89 90 if (name != NULL) { 91 data->name = strdup(name); 92 if (data->name == NULL) 93 goto fail; 94 } 95 kt->data = data; 96 *id = kt; 97 return (0); 98 fail: 99 krb5_xfree(data); 100 krb5_xfree(kt); 101 return (ENOMEM); 102 } 103 104 krb5_error_code 105 krb5_ktkdb_close(krb5_context context, krb5_keytab kt) 106 { 107 krb5_ktkdb_data *data; 108 109 /* 110 * This routine is responsible for freeing all memory allocated 111 * for this keytab. There are no system resources that need 112 * to be freed nor are there any open files. 113 * 114 * This routine should undo anything done by krb5_ktkdb_resolve(). 115 */ 116 117 kt->ops = NULL; 118 data = kt->data; 119 krb5_xfree(data->name); 120 krb5_xfree(data); 121 krb5_xfree(kt); 122 123 return (0); 124 } 125 126 static krb5_context ktkdb_ctx = NULL; 127 128 /* 129 * Set a different context for use with ktkdb_get_entry(). This is 130 * primarily useful for kadmind, where the gssapi library context, 131 * which will be used for the keytab, will necessarily have a 132 * different context than that used by the kadm5 library to access the 133 * database for its own purposes. 134 */ 135 krb5_error_code 136 krb5_ktkdb_set_context(krb5_context ctx) 137 { 138 ktkdb_ctx = ctx; 139 return 0; 140 } 141 142 krb5_error_code 143 krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) 144 krb5_context in_context; 145 krb5_keytab id; 146 krb5_const_principal principal; 147 krb5_kvno kvno; 148 krb5_enctype enctype; 149 krb5_keytab_entry *entry; 150 { 151 krb5_context context; 152 krb5_keyblock *master_key; 153 krb5_error_code kerror = 0; 154 krb5_key_data *key_data; 155 krb5_db_entry db_entry; 156 krb5_boolean more = 0; 157 int n = 0; 158 int xrealm_tgt; 159 krb5_boolean similar; 160 161 if (ktkdb_ctx) 162 context = ktkdb_ctx; 163 else 164 context = in_context; 165 166 xrealm_tgt = is_xrealm_tgt(context, principal); 167 168 /* Open database */ 169 /* krb5_db_init(context); */ 170 if ((kerror = krb5_db_inited(context))) 171 return(kerror); 172 173 /* get_principal */ 174 kerror = krb5_db_get_principal(context, principal, & 175 db_entry, &n, &more); 176 if (kerror) { 177 /* krb5_db_close_database(context); */ 178 return(kerror); 179 } 180 if (n != 1) { 181 /* krb5_db_close_database(context); */ 182 return KRB5_KT_NOTFOUND; 183 } 184 185 if (db_entry.attributes & KRB5_KDB_DISALLOW_SVR 186 || db_entry.attributes & KRB5_KDB_DISALLOW_ALL_TIX) { 187 kerror = KRB5_KT_NOTFOUND; 188 goto error; 189 } 190 191 /* match key */ 192 kerror = krb5_db_get_mkey(context, &master_key); 193 if (kerror) 194 goto error; 195 196 /* For cross realm tgts, we match whatever enctype is provided; 197 * for other principals, we only match the first enctype that is 198 * found. Since the TGS and AS code do the same thing, then we 199 * will only successfully decrypt tickets we have issued.*/ 200 kerror = krb5_dbe_find_enctype(context, &db_entry, 201 xrealm_tgt?enctype:-1, 202 -1, kvno, &key_data); 203 if (kerror) 204 goto error; 205 206 207 kerror = krb5_dbekd_decrypt_key_data(context, master_key, 208 key_data, &entry->key, NULL); 209 if (kerror) 210 goto error; 211 212 if (enctype > 0) { 213 kerror = krb5_c_enctype_compare(context, enctype, 214 entry->key.enctype, &similar); 215 if (kerror) 216 goto error; 217 218 if (!similar) { 219 kerror = KRB5_KDB_NO_PERMITTED_KEY; 220 goto error; 221 } 222 } 223 /* 224 * Coerce the enctype of the output keyblock in case we got an 225 * inexact match on the enctype. 226 */ 227 entry->key.enctype = enctype; 228 229 kerror = krb5_copy_principal(context, principal, &entry->principal); 230 if (kerror) 231 goto error; 232 233 /* Close database */ 234 error: 235 krb5_db_free_principal(context, &db_entry, 1); 236 /* krb5_db_close_database(context); */ 237 return(kerror); 238 } 239 240 /* 241 * is_xrealm_tgt: Returns true if the principal is a cross-realm TGT 242 * principal-- a principal with first component krbtgt and second 243 * component not equal to realm. 244 */ 245 static int 246 is_xrealm_tgt(krb5_context context, krb5_const_principal princ) 247 { 248 krb5_data *dat; 249 if (krb5_princ_size(context, princ) != 2) 250 return 0; 251 dat = krb5_princ_component(context, princ, 0); 252 if (strncmp("krbtgt", dat->data, dat->length) != 0) 253 return 0; 254 dat = krb5_princ_component(context, princ, 1); 255 if (dat->length != princ->realm.length) 256 return 1; 257 if (strncmp(dat->data, princ->realm.data, dat->length) == 0) 258 return 0; 259 return 1; 260 261 } 262 263