xref: /illumos-gate/usr/src/lib/krb5/kdb/kdb_default.c (revision 1da57d551424de5a9d469760be7c4b4d4f10a755)
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