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
krb5_ktkdb_get_name(krb5_context context,krb5_keytab keytab,char * name,unsigned int namelen)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
krb5_ktkdb_resolve(krb5_context context,const char * name,krb5_keytab * id)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
krb5_ktkdb_close(krb5_context context,krb5_keytab kt)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
krb5_ktkdb_set_context(krb5_context ctx)136 krb5_ktkdb_set_context(krb5_context ctx)
137 {
138 ktkdb_ctx = ctx;
139 return 0;
140 }
141
142 krb5_error_code
krb5_ktkdb_get_entry(in_context,id,principal,kvno,enctype,entry)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
is_xrealm_tgt(krb5_context context,krb5_const_principal princ)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