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