1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */ 2 /* lib/kdb/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 (strlcpy(name, "KDB:", namelen) >= namelen) 45 return KRB5_KT_NAME_TOOLONG; 46 return 0; 47 } 48 49 krb5_kt_ops krb5_kt_kdb_ops = { 50 0, 51 "KDB", /* Prefix -- this string should not appear anywhere else! */ 52 krb5_ktkdb_resolve, /* resolve */ 53 krb5_ktkdb_get_name, /* get_name */ 54 krb5_ktkdb_close, /* close */ 55 krb5_ktkdb_get_entry, /* get */ 56 NULL, /* start_seq_get */ 57 NULL, /* get_next */ 58 NULL, /* end_get */ 59 NULL, /* add (extended) */ 60 NULL, /* remove (extended) */ 61 }; 62 63 typedef struct krb5_ktkdb_data { 64 char * name; 65 } krb5_ktkdb_data; 66 67 krb5_error_code 68 krb5_db_register_keytab(krb5_context context) 69 { 70 return krb5_kt_register(context, &krb5_kt_kdb_ops); 71 } 72 73 krb5_error_code 74 krb5_ktkdb_resolve(context, name, id) 75 krb5_context context; 76 const char * name; 77 krb5_keytab * id; 78 { 79 if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL) 80 return(ENOMEM); 81 (*id)->ops = &krb5_kt_kdb_ops; 82 (*id)->magic = KV5M_KEYTAB; 83 return(0); 84 } 85 86 krb5_error_code 87 krb5_ktkdb_close(context, kt) 88 krb5_context context; 89 krb5_keytab kt; 90 { 91 /* 92 * This routine is responsible for freeing all memory allocated 93 * for this keytab. There are no system resources that need 94 * to be freed nor are there any open files. 95 * 96 * This routine should undo anything done by krb5_ktkdb_resolve(). 97 */ 98 99 kt->ops = NULL; 100 free(kt); 101 102 return 0; 103 } 104 105 static krb5_context ktkdb_ctx = NULL; 106 107 /* 108 * Set a different context for use with ktkdb_get_entry(). This is 109 * primarily useful for kadmind, where the gssapi library context, 110 * which will be used for the keytab, will necessarily have a 111 * different context than that used by the kadm5 library to access the 112 * database for its own purposes. 113 */ 114 krb5_error_code 115 krb5_ktkdb_set_context(krb5_context ctx) 116 { 117 ktkdb_ctx = ctx; 118 return 0; 119 } 120 121 krb5_error_code 122 krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry) 123 krb5_context in_context; 124 krb5_keytab id; 125 krb5_const_principal principal; 126 krb5_kvno kvno; 127 krb5_enctype enctype; 128 krb5_keytab_entry * entry; 129 { 130 krb5_context context; 131 krb5_error_code kerror = 0; 132 krb5_key_data * key_data; 133 krb5_db_entry * db_entry; 134 int xrealm_tgt; 135 krb5_boolean similar; 136 137 if (ktkdb_ctx) 138 context = ktkdb_ctx; 139 else 140 context = in_context; 141 142 xrealm_tgt = is_xrealm_tgt(context, principal); 143 144 /* Check whether database is inited. Open is commented */ 145 if ((kerror = krb5_db_inited(context))) 146 return(kerror); 147 148 /* get_principal */ 149 kerror = krb5_db_get_principal(context, principal, 0, &db_entry); 150 if (kerror == KRB5_KDB_NOENTRY) 151 return(KRB5_KT_NOTFOUND); 152 if (kerror) 153 return(kerror); 154 155 if (db_entry->attributes & KRB5_KDB_DISALLOW_SVR 156 || db_entry->attributes & KRB5_KDB_DISALLOW_ALL_TIX) { 157 kerror = KRB5_KT_NOTFOUND; 158 goto error; 159 } 160 161 /* match key */ 162 /* For cross realm tgts, we match whatever enctype is provided; 163 * for other principals, we only match the first enctype that is 164 * found. Since the TGS and AS code do the same thing, then we 165 * will only successfully decrypt tickets we have issued.*/ 166 kerror = krb5_dbe_find_enctype(context, db_entry, 167 xrealm_tgt?enctype:-1, 168 -1, kvno, &key_data); 169 if (kerror == KRB5_KDB_NO_MATCHING_KEY) 170 kerror = KRB5_KT_KVNONOTFOUND; 171 if (kerror) 172 goto error; 173 174 175 kerror = krb5_dbe_decrypt_key_data(context, NULL, key_data, 176 &entry->key, NULL); 177 if (kerror) 178 goto error; 179 180 if (enctype > 0) { 181 kerror = krb5_c_enctype_compare(context, enctype, 182 entry->key.enctype, &similar); 183 if (kerror) 184 goto error; 185 186 if (!similar) { 187 kerror = KRB5_KDB_NO_PERMITTED_KEY; 188 goto error; 189 } 190 } 191 /* 192 * Coerce the enctype of the output keyblock in case we got an 193 * inexact match on the enctype. 194 */ 195 entry->key.enctype = enctype; 196 197 kerror = krb5_copy_principal(context, principal, &entry->principal); 198 if (kerror) 199 goto error; 200 201 /* Close database */ 202 error: 203 krb5_db_free_principal(context, db_entry); 204 /* krb5_db_close_database(context); */ 205 return(kerror); 206 } 207 208 /* 209 * is_xrealm_tgt: Returns true if the principal is a cross-realm TGT 210 * principal-- a principal with first component krbtgt and second 211 * component not equal to realm. 212 */ 213 static int 214 is_xrealm_tgt(krb5_context context, krb5_const_principal princ) 215 { 216 krb5_data *dat; 217 if (krb5_princ_size(context, princ) != 2) 218 return 0; 219 dat = krb5_princ_component(context, princ, 0); 220 if (strncmp("krbtgt", dat->data, dat->length) != 0) 221 return 0; 222 dat = krb5_princ_component(context, princ, 1); 223 if (dat->length != princ->realm.length) 224 return 1; 225 if (strncmp(dat->data, princ->realm.data, dat->length) == 0) 226 return 0; 227 return 1; 228 229 } 230