xref: /illumos-gate/usr/src/lib/krb5/kdb/keytab.c (revision b7e3455d7b36184e7b725a11032528422ac91a5c)
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