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