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