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