xref: /freebsd/crypto/krb5/src/lib/kdb/kdb_default.c (revision 7f2fe78b9dd5f51c821d771b63d2e096f6fd49e9)
1*7f2fe78bSCy Schubert /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2*7f2fe78bSCy Schubert /* lib/kdb/kdb_default.c */
3*7f2fe78bSCy Schubert /*
4*7f2fe78bSCy Schubert  * Copyright 1995, 2009 by the Massachusetts Institute of Technology.
5*7f2fe78bSCy Schubert  * All Rights Reserved.
6*7f2fe78bSCy Schubert  *
7*7f2fe78bSCy Schubert  * Export of this software from the United States of America may
8*7f2fe78bSCy Schubert  *   require a specific license from the United States Government.
9*7f2fe78bSCy Schubert  *   It is the responsibility of any person or organization contemplating
10*7f2fe78bSCy Schubert  *   export to obtain such a license before exporting.
11*7f2fe78bSCy Schubert  *
12*7f2fe78bSCy Schubert  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13*7f2fe78bSCy Schubert  * distribute this software and its documentation for any purpose and
14*7f2fe78bSCy Schubert  * without fee is hereby granted, provided that the above copyright
15*7f2fe78bSCy Schubert  * notice appear in all copies and that both that copyright notice and
16*7f2fe78bSCy Schubert  * this permission notice appear in supporting documentation, and that
17*7f2fe78bSCy Schubert  * the name of M.I.T. not be used in advertising or publicity pertaining
18*7f2fe78bSCy Schubert  * to distribution of the software without specific, written prior
19*7f2fe78bSCy Schubert  * permission.  Furthermore if you modify this software you must label
20*7f2fe78bSCy Schubert  * your software as modified software and not distribute it in such a
21*7f2fe78bSCy Schubert  * fashion that it might be confused with the original M.I.T. software.
22*7f2fe78bSCy Schubert  * M.I.T. makes no representations about the suitability of
23*7f2fe78bSCy Schubert  * this software for any purpose.  It is provided "as is" without express
24*7f2fe78bSCy Schubert  * or implied warranty.
25*7f2fe78bSCy Schubert  */
26*7f2fe78bSCy Schubert /*
27*7f2fe78bSCy Schubert  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
28*7f2fe78bSCy Schubert  * Use is subject to license terms.
29*7f2fe78bSCy Schubert  */
30*7f2fe78bSCy Schubert 
31*7f2fe78bSCy Schubert #include "k5-int.h"
32*7f2fe78bSCy Schubert #include "kdb.h"
33*7f2fe78bSCy Schubert #include <string.h>
34*7f2fe78bSCy Schubert #include <stdio.h>
35*7f2fe78bSCy Schubert #include <errno.h>
36*7f2fe78bSCy Schubert #include <arpa/inet.h>
37*7f2fe78bSCy Schubert 
38*7f2fe78bSCy Schubert 
39*7f2fe78bSCy Schubert /*
40*7f2fe78bSCy Schubert  * Set *kd_out to the key data entry matching kvno, enctype, and salttype.  If
41*7f2fe78bSCy Schubert  * any of those three parameters are -1, ignore them.  If kvno is 0, match only
42*7f2fe78bSCy Schubert  * the highest kvno.  Begin searching at the index *start and set *start to the
43*7f2fe78bSCy Schubert  * index after the match.  Do not return keys of non-permitted enctypes; return
44*7f2fe78bSCy Schubert  * KRB5_KDB_NO_PERMITTED_KEY if the whole list was searched and only
45*7f2fe78bSCy Schubert  * non-permitted matches were found.
46*7f2fe78bSCy Schubert  */
47*7f2fe78bSCy Schubert krb5_error_code
krb5_dbe_def_search_enctype(krb5_context context,krb5_db_entry * ent,krb5_int32 * start,krb5_int32 enctype,krb5_int32 salttype,krb5_int32 kvno,krb5_key_data ** kd_out)48*7f2fe78bSCy Schubert krb5_dbe_def_search_enctype(krb5_context context, krb5_db_entry *ent,
49*7f2fe78bSCy Schubert                             krb5_int32 *start, krb5_int32 enctype,
50*7f2fe78bSCy Schubert                             krb5_int32 salttype, krb5_int32 kvno,
51*7f2fe78bSCy Schubert                             krb5_key_data **kd_out)
52*7f2fe78bSCy Schubert {
53*7f2fe78bSCy Schubert     krb5_key_data *kd;
54*7f2fe78bSCy Schubert     krb5_int32 db_salttype;
55*7f2fe78bSCy Schubert     krb5_boolean saw_non_permitted = FALSE;
56*7f2fe78bSCy Schubert     int i;
57*7f2fe78bSCy Schubert 
58*7f2fe78bSCy Schubert     *kd_out = NULL;
59*7f2fe78bSCy Schubert 
60*7f2fe78bSCy Schubert     if (enctype != -1 && !krb5_is_permitted_enctype(context, enctype))
61*7f2fe78bSCy Schubert         return KRB5_KDB_NO_PERMITTED_KEY;
62*7f2fe78bSCy Schubert     if (ent->n_key_data == 0)
63*7f2fe78bSCy Schubert         return KRB5_KDB_NO_MATCHING_KEY;
64*7f2fe78bSCy Schubert 
65*7f2fe78bSCy Schubert     /* Match the highest kvno if kvno is 0.  Key data is sorted in descending
66*7f2fe78bSCy Schubert      * order of kvno. */
67*7f2fe78bSCy Schubert     if (kvno == 0)
68*7f2fe78bSCy Schubert         kvno = ent->key_data[0].key_data_kvno;
69*7f2fe78bSCy Schubert 
70*7f2fe78bSCy Schubert     for (i = *start; i < ent->n_key_data; i++) {
71*7f2fe78bSCy Schubert         kd = &ent->key_data[i];
72*7f2fe78bSCy Schubert         db_salttype = (kd->key_data_ver > 1) ? kd->key_data_type[1] :
73*7f2fe78bSCy Schubert             KRB5_KDB_SALTTYPE_NORMAL;
74*7f2fe78bSCy Schubert 
75*7f2fe78bSCy Schubert         /* Match this entry against the arguments.  Stop searching if we have
76*7f2fe78bSCy Schubert          * passed the entries for the requested kvno. */
77*7f2fe78bSCy Schubert         if (enctype != -1 && kd->key_data_type[0] != enctype)
78*7f2fe78bSCy Schubert             continue;
79*7f2fe78bSCy Schubert         if (salttype >= 0 && db_salttype != salttype)
80*7f2fe78bSCy Schubert             continue;
81*7f2fe78bSCy Schubert         if (kvno >= 0 && kd->key_data_kvno < kvno)
82*7f2fe78bSCy Schubert             break;
83*7f2fe78bSCy Schubert         if (kvno >= 0 && kd->key_data_kvno != kvno)
84*7f2fe78bSCy Schubert             continue;
85*7f2fe78bSCy Schubert 
86*7f2fe78bSCy Schubert         /* Filter out non-permitted enctypes. */
87*7f2fe78bSCy Schubert         if (!krb5_is_permitted_enctype(context, kd->key_data_type[0])) {
88*7f2fe78bSCy Schubert             saw_non_permitted = TRUE;
89*7f2fe78bSCy Schubert             continue;
90*7f2fe78bSCy Schubert         }
91*7f2fe78bSCy Schubert 
92*7f2fe78bSCy Schubert         *start = i + 1;
93*7f2fe78bSCy Schubert         *kd_out = kd;
94*7f2fe78bSCy Schubert         return 0;
95*7f2fe78bSCy Schubert     }
96*7f2fe78bSCy Schubert 
97*7f2fe78bSCy Schubert     /* If we scanned the whole set of keys and matched only non-permitted
98*7f2fe78bSCy Schubert      * enctypes, indicate that. */
99*7f2fe78bSCy Schubert     return (*start == 0 && saw_non_permitted) ? KRB5_KDB_NO_PERMITTED_KEY :
100*7f2fe78bSCy Schubert         KRB5_KDB_NO_MATCHING_KEY;
101*7f2fe78bSCy Schubert }
102*7f2fe78bSCy Schubert 
103*7f2fe78bSCy Schubert /*
104*7f2fe78bSCy Schubert  *  kdb default functions. Ideally, some other file should have this functions. For now, TBD.
105*7f2fe78bSCy Schubert  */
106*7f2fe78bSCy Schubert #ifndef min
107*7f2fe78bSCy Schubert #define min(a,b) (((a) < (b)) ? (a) : (b))
108*7f2fe78bSCy Schubert #endif
109*7f2fe78bSCy Schubert 
110*7f2fe78bSCy Schubert krb5_error_code
krb5_def_store_mkey_list(krb5_context context,char * keyfile,krb5_principal mname,krb5_keylist_node * keylist,char * master_pwd)111*7f2fe78bSCy Schubert krb5_def_store_mkey_list(krb5_context       context,
112*7f2fe78bSCy Schubert                          char               *keyfile,
113*7f2fe78bSCy Schubert                          krb5_principal     mname,
114*7f2fe78bSCy Schubert                          krb5_keylist_node  *keylist,
115*7f2fe78bSCy Schubert                          char               *master_pwd)
116*7f2fe78bSCy Schubert {
117*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
118*7f2fe78bSCy Schubert     char defkeyfile[MAXPATHLEN+1];
119*7f2fe78bSCy Schubert     char *tmp_ktname = NULL, *tmp_ktpath;
120*7f2fe78bSCy Schubert     krb5_data *realm = krb5_princ_realm(context, mname);
121*7f2fe78bSCy Schubert     krb5_keytab kt = NULL;
122*7f2fe78bSCy Schubert     krb5_keytab_entry new_entry;
123*7f2fe78bSCy Schubert     struct stat stb;
124*7f2fe78bSCy Schubert     int statrc;
125*7f2fe78bSCy Schubert 
126*7f2fe78bSCy Schubert     if (!keyfile) {
127*7f2fe78bSCy Schubert         (void) snprintf(defkeyfile, sizeof(defkeyfile), "%s%s",
128*7f2fe78bSCy Schubert                         DEFAULT_KEYFILE_STUB, realm->data);
129*7f2fe78bSCy Schubert         keyfile = defkeyfile;
130*7f2fe78bSCy Schubert     }
131*7f2fe78bSCy Schubert 
132*7f2fe78bSCy Schubert     if ((statrc = stat(keyfile, &stb)) >= 0) {
133*7f2fe78bSCy Schubert         /* if keyfile exists it better be a regular file */
134*7f2fe78bSCy Schubert         if (!S_ISREG(stb.st_mode)) {
135*7f2fe78bSCy Schubert             retval = EINVAL;
136*7f2fe78bSCy Schubert             k5_setmsg(context, retval,
137*7f2fe78bSCy Schubert                       _("keyfile (%s) is not a regular file: %s"),
138*7f2fe78bSCy Schubert                       keyfile, error_message(retval));
139*7f2fe78bSCy Schubert             goto out;
140*7f2fe78bSCy Schubert         }
141*7f2fe78bSCy Schubert     }
142*7f2fe78bSCy Schubert 
143*7f2fe78bSCy Schubert     /*
144*7f2fe78bSCy Schubert      * We assume the stash file is in a directory writable only by root.
145*7f2fe78bSCy Schubert      * As such, don't worry about collisions, just do an atomic rename.
146*7f2fe78bSCy Schubert      */
147*7f2fe78bSCy Schubert     retval = asprintf(&tmp_ktname, "FILE:%s_tmp", keyfile);
148*7f2fe78bSCy Schubert     if (retval < 0) {
149*7f2fe78bSCy Schubert         k5_setmsg(context, retval,
150*7f2fe78bSCy Schubert                   _("Could not create temp keytab file name."));
151*7f2fe78bSCy Schubert         goto out;
152*7f2fe78bSCy Schubert     }
153*7f2fe78bSCy Schubert 
154*7f2fe78bSCy Schubert     /*
155*7f2fe78bSCy Schubert      * Set tmp_ktpath to point to the keyfile path (skip FILE:).  Subtracting
156*7f2fe78bSCy Schubert      * 1 to account for NULL terminator in sizeof calculation of a string
157*7f2fe78bSCy Schubert      * constant.  Used further down.
158*7f2fe78bSCy Schubert      */
159*7f2fe78bSCy Schubert     tmp_ktpath = tmp_ktname + (sizeof("FILE:") - 1);
160*7f2fe78bSCy Schubert 
161*7f2fe78bSCy Schubert     /*
162*7f2fe78bSCy Schubert      * This time-of-check-to-time-of-access race is fine; we care only
163*7f2fe78bSCy Schubert      * about an administrator running the command twice, not an attacker
164*7f2fe78bSCy Schubert      * trying to beat us to creating the file.  Per the above comment, we
165*7f2fe78bSCy Schubert      * assume the stash file is in a directory writable only by root.
166*7f2fe78bSCy Schubert      */
167*7f2fe78bSCy Schubert     statrc = stat(tmp_ktpath, &stb);
168*7f2fe78bSCy Schubert     if (statrc == -1 && errno != ENOENT) {
169*7f2fe78bSCy Schubert         /* ENOENT is the expected case */
170*7f2fe78bSCy Schubert         retval = errno;
171*7f2fe78bSCy Schubert         goto out;
172*7f2fe78bSCy Schubert     } else if (statrc == 0) {
173*7f2fe78bSCy Schubert         retval = EEXIST;
174*7f2fe78bSCy Schubert         k5_setmsg(context, retval,
175*7f2fe78bSCy Schubert                   _("Temporary stash file already exists: %s."), tmp_ktpath);
176*7f2fe78bSCy Schubert         goto out;
177*7f2fe78bSCy Schubert     }
178*7f2fe78bSCy Schubert 
179*7f2fe78bSCy Schubert     /* create new stash keytab using temp file name */
180*7f2fe78bSCy Schubert     retval = krb5_kt_resolve(context, tmp_ktname, &kt);
181*7f2fe78bSCy Schubert     if (retval != 0)
182*7f2fe78bSCy Schubert         goto out;
183*7f2fe78bSCy Schubert 
184*7f2fe78bSCy Schubert     while (keylist && !retval) {
185*7f2fe78bSCy Schubert         memset(&new_entry, 0, sizeof(new_entry));
186*7f2fe78bSCy Schubert         new_entry.principal = mname;
187*7f2fe78bSCy Schubert         new_entry.key = keylist->keyblock;
188*7f2fe78bSCy Schubert         new_entry.vno = keylist->kvno;
189*7f2fe78bSCy Schubert 
190*7f2fe78bSCy Schubert         retval = krb5_kt_add_entry(context, kt, &new_entry);
191*7f2fe78bSCy Schubert         keylist = keylist->next;
192*7f2fe78bSCy Schubert     }
193*7f2fe78bSCy Schubert     krb5_kt_close(context, kt);
194*7f2fe78bSCy Schubert 
195*7f2fe78bSCy Schubert     if (retval != 0) {
196*7f2fe78bSCy Schubert         /* Clean up by deleting the tmp keyfile if it exists. */
197*7f2fe78bSCy Schubert         (void)unlink(tmp_ktpath);
198*7f2fe78bSCy Schubert     } else {
199*7f2fe78bSCy Schubert         /* Atomically rename temp keyfile to original filename. */
200*7f2fe78bSCy Schubert         if (rename(tmp_ktpath, keyfile) < 0) {
201*7f2fe78bSCy Schubert             retval = errno;
202*7f2fe78bSCy Schubert             k5_setmsg(context, retval,
203*7f2fe78bSCy Schubert                       _("rename of temporary keyfile (%s) to (%s) failed: %s"),
204*7f2fe78bSCy Schubert                       tmp_ktpath, keyfile, error_message(errno));
205*7f2fe78bSCy Schubert         }
206*7f2fe78bSCy Schubert     }
207*7f2fe78bSCy Schubert 
208*7f2fe78bSCy Schubert out:
209*7f2fe78bSCy Schubert     if (tmp_ktname != NULL)
210*7f2fe78bSCy Schubert         free(tmp_ktname);
211*7f2fe78bSCy Schubert 
212*7f2fe78bSCy Schubert     return retval;
213*7f2fe78bSCy Schubert }
214*7f2fe78bSCy Schubert 
215*7f2fe78bSCy Schubert static krb5_error_code
krb5_db_def_fetch_mkey_stash(krb5_context context,const char * keyfile,krb5_keyblock * key,krb5_kvno * kvno)216*7f2fe78bSCy Schubert krb5_db_def_fetch_mkey_stash(krb5_context   context,
217*7f2fe78bSCy Schubert                              const char *keyfile,
218*7f2fe78bSCy Schubert                              krb5_keyblock *key,
219*7f2fe78bSCy Schubert                              krb5_kvno     *kvno)
220*7f2fe78bSCy Schubert {
221*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
222*7f2fe78bSCy Schubert     krb5_ui_2 enctype;
223*7f2fe78bSCy Schubert     krb5_ui_4 keylength;
224*7f2fe78bSCy Schubert     FILE *kf = NULL;
225*7f2fe78bSCy Schubert 
226*7f2fe78bSCy Schubert     if (!(kf = fopen(keyfile, "rb")))
227*7f2fe78bSCy Schubert         return KRB5_KDB_CANTREAD_STORED;
228*7f2fe78bSCy Schubert     set_cloexec_file(kf);
229*7f2fe78bSCy Schubert 
230*7f2fe78bSCy Schubert     if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
231*7f2fe78bSCy Schubert         retval = KRB5_KDB_CANTREAD_STORED;
232*7f2fe78bSCy Schubert         goto errout;
233*7f2fe78bSCy Schubert     }
234*7f2fe78bSCy Schubert 
235*7f2fe78bSCy Schubert #if BIG_ENDIAN_MASTER_KEY
236*7f2fe78bSCy Schubert     enctype = ntohs((uint16_t) enctype);
237*7f2fe78bSCy Schubert #endif
238*7f2fe78bSCy Schubert 
239*7f2fe78bSCy Schubert     if (key->enctype == ENCTYPE_UNKNOWN)
240*7f2fe78bSCy Schubert         key->enctype = enctype;
241*7f2fe78bSCy Schubert     else if (enctype != key->enctype) {
242*7f2fe78bSCy Schubert         retval = KRB5_KDB_BADSTORED_MKEY;
243*7f2fe78bSCy Schubert         goto errout;
244*7f2fe78bSCy Schubert     }
245*7f2fe78bSCy Schubert 
246*7f2fe78bSCy Schubert     if (fread((krb5_pointer) &keylength,
247*7f2fe78bSCy Schubert               sizeof(keylength), 1, kf) != 1) {
248*7f2fe78bSCy Schubert         retval = KRB5_KDB_CANTREAD_STORED;
249*7f2fe78bSCy Schubert         goto errout;
250*7f2fe78bSCy Schubert     }
251*7f2fe78bSCy Schubert 
252*7f2fe78bSCy Schubert #if BIG_ENDIAN_MASTER_KEY
253*7f2fe78bSCy Schubert     key->length = ntohl((uint32_t) keylength);
254*7f2fe78bSCy Schubert #else
255*7f2fe78bSCy Schubert     key->length = keylength;
256*7f2fe78bSCy Schubert #endif
257*7f2fe78bSCy Schubert 
258*7f2fe78bSCy Schubert     if (!key->length || key->length > 1024) {
259*7f2fe78bSCy Schubert         retval = KRB5_KDB_BADSTORED_MKEY;
260*7f2fe78bSCy Schubert         goto errout;
261*7f2fe78bSCy Schubert     }
262*7f2fe78bSCy Schubert 
263*7f2fe78bSCy Schubert     if (!(key->contents = (krb5_octet *)malloc(key->length))) {
264*7f2fe78bSCy Schubert         retval = ENOMEM;
265*7f2fe78bSCy Schubert         goto errout;
266*7f2fe78bSCy Schubert     }
267*7f2fe78bSCy Schubert 
268*7f2fe78bSCy Schubert     if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]),
269*7f2fe78bSCy Schubert               key->length, kf) != key->length) {
270*7f2fe78bSCy Schubert         retval = KRB5_KDB_CANTREAD_STORED;
271*7f2fe78bSCy Schubert         zap(key->contents, key->length);
272*7f2fe78bSCy Schubert         free(key->contents);
273*7f2fe78bSCy Schubert         key->contents = 0;
274*7f2fe78bSCy Schubert     } else
275*7f2fe78bSCy Schubert         retval = 0;
276*7f2fe78bSCy Schubert 
277*7f2fe78bSCy Schubert     /*
278*7f2fe78bSCy Schubert      * Note, the old stash format did not store the kvno and at this point it
279*7f2fe78bSCy Schubert      * can be assumed to be 1 as is the case for the mkey princ.  If the kvno is
280*7f2fe78bSCy Schubert      * passed in and isn't ignore_vno just leave it alone as this could cause
281*7f2fe78bSCy Schubert      * verifcation trouble if the mkey princ is using a kvno other than 1.
282*7f2fe78bSCy Schubert      */
283*7f2fe78bSCy Schubert     if (kvno && *kvno == IGNORE_VNO)
284*7f2fe78bSCy Schubert         *kvno = 1;
285*7f2fe78bSCy Schubert 
286*7f2fe78bSCy Schubert errout:
287*7f2fe78bSCy Schubert     (void) fclose(kf);
288*7f2fe78bSCy Schubert     return retval;
289*7f2fe78bSCy Schubert }
290*7f2fe78bSCy Schubert 
291*7f2fe78bSCy Schubert static krb5_error_code
krb5_db_def_fetch_mkey_keytab(krb5_context context,const char * keyfile,krb5_principal mname,krb5_keyblock * key,krb5_kvno * kvno)292*7f2fe78bSCy Schubert krb5_db_def_fetch_mkey_keytab(krb5_context   context,
293*7f2fe78bSCy Schubert                               const char     *keyfile,
294*7f2fe78bSCy Schubert                               krb5_principal mname,
295*7f2fe78bSCy Schubert                               krb5_keyblock  *key,
296*7f2fe78bSCy Schubert                               krb5_kvno      *kvno)
297*7f2fe78bSCy Schubert {
298*7f2fe78bSCy Schubert     krb5_error_code retval = 0;
299*7f2fe78bSCy Schubert     krb5_keytab kt = NULL;
300*7f2fe78bSCy Schubert     krb5_keytab_entry kt_ent;
301*7f2fe78bSCy Schubert     krb5_enctype enctype = IGNORE_ENCTYPE;
302*7f2fe78bSCy Schubert 
303*7f2fe78bSCy Schubert     if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0)
304*7f2fe78bSCy Schubert         goto errout;
305*7f2fe78bSCy Schubert 
306*7f2fe78bSCy Schubert     /* override default */
307*7f2fe78bSCy Schubert     if (key->enctype != ENCTYPE_UNKNOWN)
308*7f2fe78bSCy Schubert         enctype = key->enctype;
309*7f2fe78bSCy Schubert 
310*7f2fe78bSCy Schubert     if ((retval = krb5_kt_get_entry(context, kt, mname,
311*7f2fe78bSCy Schubert                                     kvno ? *kvno : IGNORE_VNO,
312*7f2fe78bSCy Schubert                                     enctype,
313*7f2fe78bSCy Schubert                                     &kt_ent)) == 0) {
314*7f2fe78bSCy Schubert 
315*7f2fe78bSCy Schubert         if (key->enctype == ENCTYPE_UNKNOWN)
316*7f2fe78bSCy Schubert             key->enctype = kt_ent.key.enctype;
317*7f2fe78bSCy Schubert 
318*7f2fe78bSCy Schubert         if (((int) kt_ent.key.length) < 0) {
319*7f2fe78bSCy Schubert             retval = KRB5_KDB_BADSTORED_MKEY;
320*7f2fe78bSCy Schubert             krb5_kt_free_entry(context, &kt_ent);
321*7f2fe78bSCy Schubert             goto errout;
322*7f2fe78bSCy Schubert         }
323*7f2fe78bSCy Schubert 
324*7f2fe78bSCy Schubert         key->length = kt_ent.key.length;
325*7f2fe78bSCy Schubert 
326*7f2fe78bSCy Schubert         /*
327*7f2fe78bSCy Schubert          * If a kvno pointer was passed in and it dereferences the
328*7f2fe78bSCy Schubert          * IGNORE_VNO value then it should be assigned the value of the kvno
329*7f2fe78bSCy Schubert          * found in the keytab otherwise the KNVO specified should be the
330*7f2fe78bSCy Schubert          * same as the one returned from the keytab.
331*7f2fe78bSCy Schubert          */
332*7f2fe78bSCy Schubert         if (kvno != NULL && *kvno == IGNORE_VNO)
333*7f2fe78bSCy Schubert             *kvno = kt_ent.vno;
334*7f2fe78bSCy Schubert 
335*7f2fe78bSCy Schubert         /*
336*7f2fe78bSCy Schubert          * kt_ent will be free'd so need to allocate and copy key contents for
337*7f2fe78bSCy Schubert          * output to caller.
338*7f2fe78bSCy Schubert          */
339*7f2fe78bSCy Schubert         key->contents = k5memdup(kt_ent.key.contents, kt_ent.key.length,
340*7f2fe78bSCy Schubert                                  &retval);
341*7f2fe78bSCy Schubert         if (key->contents == NULL) {
342*7f2fe78bSCy Schubert             krb5_kt_free_entry(context, &kt_ent);
343*7f2fe78bSCy Schubert             goto errout;
344*7f2fe78bSCy Schubert         }
345*7f2fe78bSCy Schubert         krb5_kt_free_entry(context, &kt_ent);
346*7f2fe78bSCy Schubert     }
347*7f2fe78bSCy Schubert 
348*7f2fe78bSCy Schubert errout:
349*7f2fe78bSCy Schubert     if (kt)
350*7f2fe78bSCy Schubert         krb5_kt_close(context, kt);
351*7f2fe78bSCy Schubert 
352*7f2fe78bSCy Schubert     return retval;
353*7f2fe78bSCy Schubert }
354*7f2fe78bSCy Schubert 
355*7f2fe78bSCy Schubert krb5_error_code
krb5_db_def_fetch_mkey(krb5_context context,krb5_principal mname,krb5_keyblock * key,krb5_kvno * kvno,char * db_args)356*7f2fe78bSCy Schubert krb5_db_def_fetch_mkey(krb5_context   context,
357*7f2fe78bSCy Schubert                        krb5_principal mname,
358*7f2fe78bSCy Schubert                        krb5_keyblock *key,
359*7f2fe78bSCy Schubert                        krb5_kvno     *kvno,
360*7f2fe78bSCy Schubert                        char          *db_args)
361*7f2fe78bSCy Schubert {
362*7f2fe78bSCy Schubert     krb5_error_code retval;
363*7f2fe78bSCy Schubert     char keyfile[MAXPATHLEN+1];
364*7f2fe78bSCy Schubert     krb5_data *realm = krb5_princ_realm(context, mname);
365*7f2fe78bSCy Schubert 
366*7f2fe78bSCy Schubert     key->magic = KV5M_KEYBLOCK;
367*7f2fe78bSCy Schubert 
368*7f2fe78bSCy Schubert     if (db_args != NULL) {
369*7f2fe78bSCy Schubert         (void) strncpy(keyfile, db_args, sizeof(keyfile));
370*7f2fe78bSCy Schubert     } else {
371*7f2fe78bSCy Schubert         (void) snprintf(keyfile, sizeof(keyfile), "%s%s",
372*7f2fe78bSCy Schubert                         DEFAULT_KEYFILE_STUB, realm->data);
373*7f2fe78bSCy Schubert     }
374*7f2fe78bSCy Schubert     /* null terminate no matter what */
375*7f2fe78bSCy Schubert     keyfile[sizeof(keyfile) - 1] = '\0';
376*7f2fe78bSCy Schubert 
377*7f2fe78bSCy Schubert     /* Try the keytab and old stash file formats. */
378*7f2fe78bSCy Schubert     retval = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno);
379*7f2fe78bSCy Schubert     if (retval == KRB5_KEYTAB_BADVNO)
380*7f2fe78bSCy Schubert         retval = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno);
381*7f2fe78bSCy Schubert 
382*7f2fe78bSCy Schubert     /*
383*7f2fe78bSCy Schubert      * Use a generic error code for failure to retrieve the master
384*7f2fe78bSCy Schubert      * key, but set a message indicating the actual error.
385*7f2fe78bSCy Schubert      */
386*7f2fe78bSCy Schubert     if (retval != 0) {
387*7f2fe78bSCy Schubert         k5_setmsg(context, KRB5_KDB_CANTREAD_STORED,
388*7f2fe78bSCy Schubert                   _("Can not fetch master key (error: %s)."),
389*7f2fe78bSCy Schubert                   error_message(retval));
390*7f2fe78bSCy Schubert         return KRB5_KDB_CANTREAD_STORED;
391*7f2fe78bSCy Schubert     } else
392*7f2fe78bSCy Schubert         return 0;
393*7f2fe78bSCy Schubert }
394*7f2fe78bSCy Schubert 
395*7f2fe78bSCy Schubert krb5_error_code
krb5_def_fetch_mkey_list(krb5_context context,krb5_principal mprinc,const krb5_keyblock * mkey,krb5_keylist_node ** mkeys_list)396*7f2fe78bSCy Schubert krb5_def_fetch_mkey_list(krb5_context        context,
397*7f2fe78bSCy Schubert                          krb5_principal        mprinc,
398*7f2fe78bSCy Schubert                          const krb5_keyblock  *mkey,
399*7f2fe78bSCy Schubert                          krb5_keylist_node  **mkeys_list)
400*7f2fe78bSCy Schubert {
401*7f2fe78bSCy Schubert     krb5_error_code retval;
402*7f2fe78bSCy Schubert     krb5_db_entry *master_entry;
403*7f2fe78bSCy Schubert     krb5_boolean found_key = FALSE;
404*7f2fe78bSCy Schubert     krb5_keyblock cur_mkey;
405*7f2fe78bSCy Schubert     krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node;
406*7f2fe78bSCy Schubert     krb5_key_data *key_data;
407*7f2fe78bSCy Schubert     krb5_mkey_aux_node  *mkey_aux_data_list = NULL, *aux_data_entry;
408*7f2fe78bSCy Schubert     int i;
409*7f2fe78bSCy Schubert 
410*7f2fe78bSCy Schubert     if (mkeys_list == NULL)
411*7f2fe78bSCy Schubert         return (EINVAL);
412*7f2fe78bSCy Schubert 
413*7f2fe78bSCy Schubert     memset(&cur_mkey, 0, sizeof(cur_mkey));
414*7f2fe78bSCy Schubert 
415*7f2fe78bSCy Schubert     retval = krb5_db_get_principal(context, mprinc, 0, &master_entry);
416*7f2fe78bSCy Schubert     if (retval == KRB5_KDB_NOENTRY)
417*7f2fe78bSCy Schubert         return (KRB5_KDB_NOMASTERKEY);
418*7f2fe78bSCy Schubert     if (retval)
419*7f2fe78bSCy Schubert         return (retval);
420*7f2fe78bSCy Schubert 
421*7f2fe78bSCy Schubert     if (master_entry->n_key_data == 0) {
422*7f2fe78bSCy Schubert         retval = KRB5_KDB_NOMASTERKEY;
423*7f2fe78bSCy Schubert         goto clean_n_exit;
424*7f2fe78bSCy Schubert     }
425*7f2fe78bSCy Schubert 
426*7f2fe78bSCy Schubert     /*
427*7f2fe78bSCy Schubert      * Check if the input mkey is the latest key and if it isn't then find the
428*7f2fe78bSCy Schubert      * latest mkey.
429*7f2fe78bSCy Schubert      */
430*7f2fe78bSCy Schubert 
431*7f2fe78bSCy Schubert     if (mkey->enctype == master_entry->key_data[0].key_data_type[0]) {
432*7f2fe78bSCy Schubert         if (krb5_dbe_decrypt_key_data(context, mkey,
433*7f2fe78bSCy Schubert                                       &master_entry->key_data[0],
434*7f2fe78bSCy Schubert                                       &cur_mkey, NULL) == 0) {
435*7f2fe78bSCy Schubert             found_key = TRUE;
436*7f2fe78bSCy Schubert         }
437*7f2fe78bSCy Schubert     }
438*7f2fe78bSCy Schubert 
439*7f2fe78bSCy Schubert     if (!found_key) {
440*7f2fe78bSCy Schubert         if ((retval = krb5_dbe_lookup_mkey_aux(context, master_entry,
441*7f2fe78bSCy Schubert                                                &mkey_aux_data_list)))
442*7f2fe78bSCy Schubert             goto clean_n_exit;
443*7f2fe78bSCy Schubert 
444*7f2fe78bSCy Schubert         for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
445*7f2fe78bSCy Schubert              aux_data_entry = aux_data_entry->next) {
446*7f2fe78bSCy Schubert 
447*7f2fe78bSCy Schubert             if (krb5_dbe_decrypt_key_data(context, mkey,
448*7f2fe78bSCy Schubert                                           &aux_data_entry->latest_mkey,
449*7f2fe78bSCy Schubert                                           &cur_mkey, NULL) == 0) {
450*7f2fe78bSCy Schubert                 found_key = TRUE;
451*7f2fe78bSCy Schubert                 break;
452*7f2fe78bSCy Schubert             }
453*7f2fe78bSCy Schubert         }
454*7f2fe78bSCy Schubert         if (found_key != TRUE) {
455*7f2fe78bSCy Schubert             k5_setmsg(context, KRB5_KDB_BADMASTERKEY,
456*7f2fe78bSCy Schubert                       _("Unable to decrypt latest master key with the "
457*7f2fe78bSCy Schubert                         "provided master key\n"));
458*7f2fe78bSCy Schubert             retval = KRB5_KDB_BADMASTERKEY;
459*7f2fe78bSCy Schubert             goto clean_n_exit;
460*7f2fe78bSCy Schubert         }
461*7f2fe78bSCy Schubert     }
462*7f2fe78bSCy Schubert 
463*7f2fe78bSCy Schubert     /*
464*7f2fe78bSCy Schubert      * Extract all the mkeys from master_entry using the most current mkey and
465*7f2fe78bSCy Schubert      * create a mkey list for the mkeys field in kdc_realm_t.
466*7f2fe78bSCy Schubert      */
467*7f2fe78bSCy Schubert 
468*7f2fe78bSCy Schubert     mkey_list_head = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
469*7f2fe78bSCy Schubert     if (mkey_list_head == NULL) {
470*7f2fe78bSCy Schubert         retval = ENOMEM;
471*7f2fe78bSCy Schubert         goto clean_n_exit;
472*7f2fe78bSCy Schubert     }
473*7f2fe78bSCy Schubert 
474*7f2fe78bSCy Schubert     memset(mkey_list_head, 0, sizeof(krb5_keylist_node));
475*7f2fe78bSCy Schubert 
476*7f2fe78bSCy Schubert     /* Set mkey_list_head to the current mkey as an optimization. */
477*7f2fe78bSCy Schubert     /* mkvno may not be latest so ... */
478*7f2fe78bSCy Schubert     mkey_list_head->kvno = master_entry->key_data[0].key_data_kvno;
479*7f2fe78bSCy Schubert     /* this is the latest clear mkey (avoids a redundant decrypt) */
480*7f2fe78bSCy Schubert     mkey_list_head->keyblock = cur_mkey;
481*7f2fe78bSCy Schubert 
482*7f2fe78bSCy Schubert     /* loop through any other master keys creating a list of krb5_keylist_nodes */
483*7f2fe78bSCy Schubert     mkey_list_node = &mkey_list_head->next;
484*7f2fe78bSCy Schubert     for (i = 1; i < master_entry->n_key_data; i++) {
485*7f2fe78bSCy Schubert         if (*mkey_list_node == NULL) {
486*7f2fe78bSCy Schubert             /* *mkey_list_node points to next field of previous node */
487*7f2fe78bSCy Schubert             *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
488*7f2fe78bSCy Schubert             if (*mkey_list_node == NULL) {
489*7f2fe78bSCy Schubert                 retval = ENOMEM;
490*7f2fe78bSCy Schubert                 goto clean_n_exit;
491*7f2fe78bSCy Schubert             }
492*7f2fe78bSCy Schubert             memset(*mkey_list_node, 0, sizeof(krb5_keylist_node));
493*7f2fe78bSCy Schubert         }
494*7f2fe78bSCy Schubert         key_data = &master_entry->key_data[i];
495*7f2fe78bSCy Schubert         retval = krb5_dbe_decrypt_key_data(context, &cur_mkey, key_data,
496*7f2fe78bSCy Schubert                                            &((*mkey_list_node)->keyblock),
497*7f2fe78bSCy Schubert                                            NULL);
498*7f2fe78bSCy Schubert         if (retval)
499*7f2fe78bSCy Schubert             goto clean_n_exit;
500*7f2fe78bSCy Schubert 
501*7f2fe78bSCy Schubert         (*mkey_list_node)->kvno = key_data->key_data_kvno;
502*7f2fe78bSCy Schubert         mkey_list_node = &((*mkey_list_node)->next);
503*7f2fe78bSCy Schubert     }
504*7f2fe78bSCy Schubert 
505*7f2fe78bSCy Schubert     *mkeys_list = mkey_list_head;
506*7f2fe78bSCy Schubert 
507*7f2fe78bSCy Schubert clean_n_exit:
508*7f2fe78bSCy Schubert     krb5_db_free_principal(context, master_entry);
509*7f2fe78bSCy Schubert     krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_list);
510*7f2fe78bSCy Schubert     if (retval != 0)
511*7f2fe78bSCy Schubert         krb5_dbe_free_key_list(context, mkey_list_head);
512*7f2fe78bSCy Schubert     return retval;
513*7f2fe78bSCy Schubert }
514*7f2fe78bSCy Schubert 
515*7f2fe78bSCy Schubert krb5_error_code
krb5_db_def_rename_principal(krb5_context kcontext,krb5_const_principal source,krb5_const_principal target)516*7f2fe78bSCy Schubert krb5_db_def_rename_principal(krb5_context kcontext,
517*7f2fe78bSCy Schubert                              krb5_const_principal source,
518*7f2fe78bSCy Schubert                              krb5_const_principal target)
519*7f2fe78bSCy Schubert {
520*7f2fe78bSCy Schubert     krb5_db_entry *kdb = NULL;
521*7f2fe78bSCy Schubert     krb5_principal oldprinc;
522*7f2fe78bSCy Schubert     krb5_error_code ret;
523*7f2fe78bSCy Schubert 
524*7f2fe78bSCy Schubert     if (source == NULL || target == NULL)
525*7f2fe78bSCy Schubert         return EINVAL;
526*7f2fe78bSCy Schubert 
527*7f2fe78bSCy Schubert     ret = krb5_db_get_principal(kcontext, source, 0, &kdb);
528*7f2fe78bSCy Schubert     if (ret)
529*7f2fe78bSCy Schubert         goto cleanup;
530*7f2fe78bSCy Schubert 
531*7f2fe78bSCy Schubert     /* Store salt values explicitly so that they don't depend on the principal
532*7f2fe78bSCy Schubert      * name. */
533*7f2fe78bSCy Schubert     ret = krb5_dbe_specialize_salt(kcontext, kdb);
534*7f2fe78bSCy Schubert     if (ret)
535*7f2fe78bSCy Schubert         goto cleanup;
536*7f2fe78bSCy Schubert 
537*7f2fe78bSCy Schubert     /* Temporarily alias kdb->princ to target and put the principal entry. */
538*7f2fe78bSCy Schubert     oldprinc = kdb->princ;
539*7f2fe78bSCy Schubert     kdb->princ = (krb5_principal)target;
540*7f2fe78bSCy Schubert     ret = krb5_db_put_principal(kcontext, kdb);
541*7f2fe78bSCy Schubert     kdb->princ = oldprinc;
542*7f2fe78bSCy Schubert     if (ret)
543*7f2fe78bSCy Schubert         goto cleanup;
544*7f2fe78bSCy Schubert 
545*7f2fe78bSCy Schubert     ret = krb5_db_delete_principal(kcontext, (krb5_principal)source);
546*7f2fe78bSCy Schubert 
547*7f2fe78bSCy Schubert 
548*7f2fe78bSCy Schubert cleanup:
549*7f2fe78bSCy Schubert     krb5_db_free_principal(kcontext, kdb);
550*7f2fe78bSCy Schubert     return ret;
551*7f2fe78bSCy Schubert }
552