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