1 /*
2 * Copyright 2007 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
4 */
5
6 /*
7 * lib/kdb/kdb_helper.c
8 *
9 * Copyright 1995 by the Massachusetts Institute of Technology.
10 * All Rights Reserved.
11 *
12 * Export of this software from the United States of America may
13 * require a specific license from the United States Government.
14 * It is the responsibility of any person or organization contemplating
15 * export to obtain such a license before exporting.
16 *
17 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
18 * distribute this software and its documentation for any purpose and
19 * without fee is hereby granted, provided that the above copyright
20 * notice appear in all copies and that both that copyright notice and
21 * this permission notice appear in supporting documentation, and that
22 * the name of M.I.T. not be used in advertising or publicity pertaining
23 * to distribution of the software without specific, written prior
24 * permission. Furthermore if you modify this software you must label
25 * your software as modified software and not distribute it in such a
26 * fashion that it might be confused with the original M.I.T. software.
27 * M.I.T. makes no representations about the suitability of
28 * this software for any purpose. It is provided "as is" without express
29 * or implied warranty.
30 *
31 */
32
33 #include "k5-int.h"
34 #include "kdb.h"
35 #include <string.h>
36 #include <stdio.h>
37 #include <errno.h>
38 #include <libintl.h>
39
40
41 /*
42 * Given a particular enctype and optional salttype and kvno, find the
43 * most appropriate krb5_key_data entry of the database entry.
44 *
45 * If stype or kvno is negative, it is ignored.
46 * If kvno is 0 get the key which is maxkvno for the princ and matches
47 * the other attributes.
48 */
49 krb5_error_code
krb5_dbe_def_search_enctype(kcontext,dbentp,start,ktype,stype,kvno,kdatap)50 krb5_dbe_def_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap)
51 krb5_context kcontext;
52 krb5_db_entry *dbentp;
53 krb5_int32 *start;
54 krb5_int32 ktype;
55 krb5_int32 stype;
56 krb5_int32 kvno;
57 krb5_key_data **kdatap;
58 {
59 int i, idx;
60 int maxkvno;
61 krb5_key_data *datap;
62 krb5_error_code ret;
63
64 ret = 0;
65 if (kvno == -1 && stype == -1 && ktype == -1)
66 kvno = 0;
67
68 if (kvno == 0) {
69 /* Get the max key version */
70 for (i = 0; i < dbentp->n_key_data; i++) {
71 if (kvno < dbentp->key_data[i].key_data_kvno) {
72 kvno = dbentp->key_data[i].key_data_kvno;
73 }
74 }
75 }
76
77 maxkvno = -1;
78 datap = (krb5_key_data *) NULL;
79 for (i = *start; i < dbentp->n_key_data; i++) {
80 krb5_boolean similar;
81 krb5_int32 db_stype;
82
83 ret = 0;
84 if (dbentp->key_data[i].key_data_ver > 1) {
85 db_stype = dbentp->key_data[i].key_data_type[1];
86 } else {
87 db_stype = KRB5_KDB_SALTTYPE_NORMAL;
88 }
89
90 /*
91 * Filter out non-permitted enctypes.
92 */
93 if (!krb5_is_permitted_enctype(kcontext,
94 dbentp->key_data[i].key_data_type[0])) {
95 ret = KRB5_KDB_NO_PERMITTED_KEY;
96 continue;
97 }
98
99
100 if (ktype > 0) {
101 if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
102 dbentp->key_data[i].key_data_type[0],
103 &similar)))
104
105 return(ret);
106 }
107
108 if (((ktype <= 0) || similar) &&
109 ((db_stype == stype) || (stype < 0))) {
110 if (kvno >= 0) {
111 if (kvno == dbentp->key_data[i].key_data_kvno) {
112 datap = &dbentp->key_data[i];
113 idx = i;
114 maxkvno = kvno;
115 break;
116 }
117 } else {
118 if (dbentp->key_data[i].key_data_kvno > maxkvno) {
119 maxkvno = dbentp->key_data[i].key_data_kvno;
120 datap = &dbentp->key_data[i];
121 idx = i;
122 }
123 }
124 }
125 }
126 if (maxkvno < 0)
127 return ret ? ret : KRB5_KDB_NO_MATCHING_KEY;
128 *kdatap = datap;
129 *start = idx+1;
130 return 0;
131 }
132
133 /*
134 * kdb default functions. Ideally, some other file should have this functions. For now, TBD.
135 */
136 #ifndef min
137 #define min(a,b) (((a) < (b)) ? (a) : (b))
138 #endif
139
140 krb5_error_code
krb5_def_store_mkey(context,keyfile,mname,key,master_pwd)141 krb5_def_store_mkey(context, keyfile, mname, key, master_pwd)
142 krb5_context context;
143 char *keyfile;
144 krb5_principal mname;
145 krb5_keyblock *key;
146 char *master_pwd;
147 {
148 FILE *kf;
149 krb5_error_code retval = 0;
150 krb5_ui_2 enctype;
151 char defkeyfile[MAXPATHLEN+1];
152 krb5_data *realm = krb5_princ_realm(context, mname);
153 #if HAVE_UMASK
154 mode_t oumask;
155 #endif
156
157 if (!keyfile) {
158 (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
159 (void) strncat(defkeyfile, realm->data,
160 min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
161 realm->length));
162 defkeyfile[sizeof(defkeyfile) - 1] = '\0';
163 keyfile = defkeyfile;
164 }
165
166 #if HAVE_UMASK
167 oumask = umask(077);
168 #endif
169 #ifdef ANSI_STDIO
170 /* Solaris Kerberos: using F to deal with 256 open file limit */
171 if (!(kf = fopen(keyfile, "wbF")))
172 #else
173 if (!(kf = fopen(keyfile, "wF")))
174 #endif
175 {
176 int e = errno;
177 #if HAVE_UMASK
178 (void) umask(oumask);
179 #endif
180 krb5_set_error_message (context, e,
181 gettext("%s accessing file '%s'"),
182 error_message (e), keyfile);
183 return e;
184 }
185 enctype = key->enctype;
186 if ((fwrite((krb5_pointer) &enctype,
187 2, 1, kf) != 1) ||
188 (fwrite((krb5_pointer) &key->length,
189 sizeof(key->length), 1, kf) != 1) ||
190 (fwrite((krb5_pointer) key->contents,
191 sizeof(key->contents[0]), (unsigned) key->length,
192 kf) != key->length)) {
193 retval = errno;
194 (void) fclose(kf);
195 }
196 if (fclose(kf) == EOF)
197 retval = errno;
198 #if HAVE_UMASK
199 (void) umask(oumask);
200 #endif
201 return retval;
202 }
203
204
205 krb5_error_code
krb5_db_def_fetch_mkey(krb5_context context,krb5_principal mname,krb5_keyblock * key,int * kvno,char * db_args)206 krb5_db_def_fetch_mkey( krb5_context context,
207 krb5_principal mname,
208 krb5_keyblock *key,
209 int *kvno,
210 char *db_args)
211 {
212 krb5_error_code retval;
213 krb5_ui_2 enctype;
214 char defkeyfile[MAXPATHLEN+1];
215 krb5_data *realm = krb5_princ_realm(context, mname);
216 FILE *kf = NULL;
217
218 retval = 0;
219 key->magic = KV5M_KEYBLOCK;
220 (void) strcpy(defkeyfile, DEFAULT_KEYFILE_STUB);
221 (void) strncat(defkeyfile, realm->data,
222 min(sizeof(defkeyfile)-sizeof(DEFAULT_KEYFILE_STUB)-1,
223 realm->length));
224 defkeyfile[sizeof(defkeyfile) - 1] = '\0';
225
226 #ifdef ANSI_STDIO
227 /* Solaris Kerberos: using F to deal with 256 open file limit */
228 if (!(kf = fopen((db_args) ? db_args : defkeyfile, "rbF")))
229 #else
230 if (!(kf = fopen((db_args) ? db_args : defkeyfile, "rF")))
231 #endif
232 return KRB5_KDB_CANTREAD_STORED;
233
234 if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
235 retval = KRB5_KDB_CANTREAD_STORED;
236 goto errout;
237 }
238
239 if (key->enctype == ENCTYPE_UNKNOWN)
240 key->enctype = enctype;
241 else if (enctype != key->enctype) {
242 retval = KRB5_KDB_BADSTORED_MKEY;
243 goto errout;
244 }
245
246 if (fread((krb5_pointer) &key->length,
247 sizeof(key->length), 1, kf) != 1) {
248 retval = KRB5_KDB_CANTREAD_STORED;
249 goto errout;
250 }
251
252 if (!key->length || ((int) key->length) < 0) {
253 retval = KRB5_KDB_BADSTORED_MKEY;
254 goto errout;
255 }
256
257 if (!(key->contents = (krb5_octet *)malloc(key->length))) {
258 retval = ENOMEM;
259 goto errout;
260 }
261
262 if (fread((krb5_pointer) key->contents,
263 sizeof(key->contents[0]), key->length, kf)
264 != key->length) {
265 retval = KRB5_KDB_CANTREAD_STORED;
266 memset(key->contents, 0, key->length);
267 free(key->contents);
268 key->contents = 0;
269 } else
270 retval = 0;
271
272 *kvno = 0;
273
274 errout:
275 (void) fclose(kf);
276 return retval;
277
278 }
279
280
281 krb5_error_code
krb5_def_verify_master_key(context,mprinc,mkey)282 krb5_def_verify_master_key(context, mprinc, mkey)
283 krb5_context context;
284 krb5_principal mprinc;
285 krb5_keyblock *mkey;
286 {
287 krb5_error_code retval;
288 krb5_db_entry master_entry;
289 int nprinc;
290 krb5_boolean more;
291 krb5_keyblock tempkey;
292
293 nprinc = 1;
294 if ((retval = krb5_db_get_principal(context, mprinc,
295 &master_entry, &nprinc, &more)))
296 return(retval);
297
298 if (nprinc != 1) {
299 if (nprinc)
300 krb5_db_free_principal(context, &master_entry, nprinc);
301 return(KRB5_KDB_NOMASTERKEY);
302 } else if (more) {
303 krb5_db_free_principal(context, &master_entry, nprinc);
304 return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
305 }
306
307 if ((retval = krb5_dbekd_decrypt_key_data(context, mkey,
308 &master_entry.key_data[0],
309 &tempkey, NULL))) {
310 krb5_db_free_principal(context, &master_entry, nprinc);
311 return retval;
312 }
313
314 if (mkey->length != tempkey.length ||
315 memcmp((char *)mkey->contents,
316 (char *)tempkey.contents,mkey->length)) {
317 retval = KRB5_KDB_BADMASTERKEY;
318 }
319
320 memset((char *)tempkey.contents, 0, tempkey.length);
321 krb5_xfree(tempkey.contents);
322 krb5_db_free_principal(context, &master_entry, nprinc);
323
324 return retval;
325 }
326
327
kdb_def_set_mkey(krb5_context kcontext,char * pwd,krb5_keyblock * key)328 krb5_error_code kdb_def_set_mkey ( krb5_context kcontext,
329 char *pwd,
330 krb5_keyblock *key )
331 {
332 /* printf("default set master key\n"); */
333 return 0;
334 }
335
kdb_def_get_mkey(krb5_context kcontext,krb5_keyblock ** key)336 krb5_error_code kdb_def_get_mkey ( krb5_context kcontext,
337 krb5_keyblock **key )
338 {
339 /* printf("default get master key\n"); */
340 return 0;
341 }
342
krb5_def_promote_db(krb5_context kcontext,char * s,char ** args)343 krb5_error_code krb5_def_promote_db (krb5_context kcontext,
344 char *s, char **args)
345 {
346 /* printf("default promote_db\n"); */
347 return KRB5_PLUGIN_OP_NOTSUPP;
348 }
349