xref: /illumos-gate/usr/src/lib/krb5/kdb/keytab.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1 #pragma ident	"%Z%%M%	%I%	%E% SMI"
2 /*
3  * kadmin/v5server/keytab.c
4  *
5  * Copyright 1995 by the Massachusetts Institute of Technology.
6  * All Rights Reserved.
7  *
8  * Export of this software from the United States of America may
9  *   require a specific license from the United States Government.
10  *   It is the responsibility of any person or organization contemplating
11  *   export to obtain such a license before exporting.
12  *
13  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
14  * distribute this software and its documentation for any purpose and
15  * without fee is hereby granted, provided that the above copyright
16  * notice appear in all copies and that both that copyright notice and
17  * this permission notice appear in supporting documentation, and that
18  * the name of M.I.T. not be used in advertising or publicity pertaining
19  * to distribution of the software without specific, written prior
20  * permission.  Furthermore if you modify this software you must label
21  * your software as modified software and not distribute it in such a
22  * fashion that it might be confused with the original M.I.T. software.
23  * M.I.T. makes no representations about the suitability of
24  * this software for any purpose.  It is provided "as is" without express
25  * or implied warranty.
26  *
27  */
28 #include <string.h>
29 
30 #include "k5-int.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 krb5_error_code krb5_ktkdb_resolve(
41     krb5_context  	  context,
42     const char		* name,
43     krb5_keytab		* id);
44 
45 krb5_kt_ops krb5_kt_kdb_ops = {
46     0,
47     "KDB", 	/* Prefix -- this string should not appear anywhere else! */
48     krb5_ktkdb_resolve,		/* resolve */
49     NULL,			/* get_name */
50     krb5_ktkdb_close,		/* close */
51     krb5_ktkdb_get_entry,	/* get */
52     NULL,			/* start_seq_get */
53     NULL,			/* get_next */
54     NULL,			/* end_get */
55     NULL,			/* add (extended) */
56     NULL,			/* remove (extended) */
57     NULL, 		/* (void *) &krb5_ktfile_ser_entry */
58 };
59 
60 typedef struct krb5_ktkdb_data {
61     char * name;
62 } krb5_ktkdb_data;
63 
64 krb5_error_code
65 krb5_ktkdb_resolve(context, name, id)
66     krb5_context  	  context;
67     const char		* name;
68     krb5_keytab		* id;
69 {
70     if ((*id = (krb5_keytab) malloc(sizeof(**id))) == NULL)
71         return(ENOMEM);
72     (*id)->ops = &krb5_kt_kdb_ops;
73     (*id)->magic = KV5M_KEYTAB;
74     return(0);
75 }
76 
77 krb5_error_code
78 krb5_ktkdb_close(context, kt)
79      krb5_context context;
80      krb5_keytab kt;
81 {
82   /*
83    * This routine is responsible for freeing all memory allocated
84    * for this keytab.  There are no system resources that need
85    * to be freed nor are there any open files.
86    *
87    * This routine should undo anything done by krb5_ktkdb_resolve().
88    */
89 
90   kt->ops = NULL;
91   krb5_xfree(kt);
92 
93   return 0;
94 }
95 
96 static krb5_context ktkdb_ctx = NULL;
97 
98 /*
99  * Set a different context for use with ktkdb_get_entry().  This is
100  * primarily useful for kadmind, where the gssapi library context,
101  * which will be used for the keytab, will necessarily have a
102  * different context than that used by the kadm5 library to access the
103  * database for its own purposes.
104  */
105 krb5_error_code
106 krb5_ktkdb_set_context(krb5_context ctx)
107 {
108     ktkdb_ctx = ctx;
109     return 0;
110 }
111 
112 krb5_error_code
113 krb5_ktkdb_get_entry(in_context, id, principal, kvno, enctype, entry)
114     krb5_context 	  in_context;
115     krb5_keytab 	  id;
116     krb5_const_principal  principal;
117     krb5_kvno 	 	  kvno;
118     krb5_enctype 	  enctype;
119     krb5_keytab_entry 	* entry;
120 {
121     krb5_context	  context;
122     krb5_keyblock       * master_key;
123     krb5_error_code 	  kerror = 0;
124     krb5_key_data 	* key_data;
125     krb5_db_entry 	  db_entry;
126     krb5_boolean 	  more = 0;
127     int 	 	  n = 0;
128     int xrealm_tgt = is_xrealm_tgt(context, principal);
129     krb5_boolean	 similar;
130 
131     if (ktkdb_ctx)
132 	context = ktkdb_ctx;
133     else
134 	context = in_context;
135 
136     /* Open database */
137     /* krb5_db_init(context); */
138     if ((kerror = krb5_db_open_database(context)))
139         return(kerror);
140 
141     /* get_principal */
142     kerror = krb5_db_get_principal(context, principal, &
143 				       db_entry, &n, &more);
144     if (kerror) {
145         krb5_db_close_database(context);
146         return(kerror);
147     }
148     if (n != 1) {
149 	krb5_db_close_database(context);
150 	return KRB5_KT_NOTFOUND;
151     }
152 
153     if (db_entry.attributes & KRB5_KDB_DISALLOW_SVR
154 	|| db_entry.attributes & KRB5_KDB_DISALLOW_ALL_TIX) {
155 	kerror = KRB5_KT_NOTFOUND;
156 	goto error;
157     }
158 
159     /* match key */
160     kerror = krb5_db_get_mkey(context, &master_key);
161     if (kerror)
162 	goto error;
163 
164     /* For cross realm tgts, we match whatever enctype is provided;
165      * for other principals, we only match the first enctype that is
166      * found.  Since the TGS and AS code do the same thing, then we
167      * will only successfully decrypt  tickets we have issued.*/
168     kerror = krb5_dbe_find_enctype(context, &db_entry,
169 				   xrealm_tgt?enctype:-1,
170 				   -1, kvno, &key_data);
171     if (kerror)
172 	goto error;
173 
174 
175     kerror = krb5_dbekd_decrypt_key_data(context, master_key,
176 					 key_data, &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_dbe_free_contents(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 
231