1 /* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2 /* lib/kdb/kdb_default.c */
4 * Copyright 1995, 2009 by the Massachusetts Institute of Technology.
7 * Export of this software from the United States of America may
8 * require a specific license from the United States Government.
9 * It is the responsibility of any person or organization contemplating
10 * export to obtain such a license before exporting.
12 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
13 * distribute this software and its documentation for any purpose and
14 * without fee is hereby granted, provided that the above copyright
15 * notice appear in all copies and that both that copyright notice and
16 * this permission notice appear in supporting documentation, and that
17 * the name of M.I.T. not be used in advertising or publicity pertaining
18 * to distribution of the software without specific, written prior
19 * permission. Furthermore if you modify this software you must label
20 * your software as modified software and not distribute it in such a
21 * fashion that it might be confused with the original M.I.T. software.
22 * M.I.T. makes no representations about the suitability of
23 * this software for any purpose. It is provided "as is" without express
24 * or implied warranty.
27 * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
28 * Use is subject to license terms.
36 #include <arpa/inet.h>
40 * Given a particular enctype and optional salttype and kvno, find the
41 * most appropriate krb5_key_data entry of the database entry.
43 * If stype or kvno is negative, it is ignored.
44 * If kvno is 0 get the key which is maxkvno for the princ and matches
45 * the other attributes.
48 krb5_dbe_def_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap)
49 krb5_context kcontext;
50 krb5_db_entry *dbentp;
55 krb5_key_data **kdatap;
61 krb5_boolean saw_non_permitted = FALSE;
64 if (ktype != -1 && !krb5_is_permitted_enctype(kcontext, ktype))
65 return KRB5_KDB_NO_PERMITTED_KEY;
67 if (kvno == -1 && stype == -1 && ktype == -1)
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;
81 datap = (krb5_key_data *) NULL;
82 for (i = *start; i < dbentp->n_key_data; i++) {
87 if (dbentp->key_data[i].key_data_ver > 1) {
88 db_stype = dbentp->key_data[i].key_data_type[1];
90 db_stype = KRB5_KDB_SALTTYPE_NORMAL;
93 /* Match this entry against the arguments. */
95 ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
96 dbentp->key_data[i].key_data_type[0],
98 if (ret != 0 || !similar)
101 if (stype >= 0 && db_stype != stype)
103 if (kvno >= 0 && dbentp->key_data[i].key_data_kvno != kvno)
106 /* Filter out non-permitted enctypes. */
107 if (!krb5_is_permitted_enctype(kcontext,
108 dbentp->key_data[i].key_data_type[0])) {
109 saw_non_permitted = TRUE;
113 if (dbentp->key_data[i].key_data_kvno > maxkvno) {
114 maxkvno = dbentp->key_data[i].key_data_kvno;
115 datap = &dbentp->key_data[i];
119 /* If we scanned the whole set of keys and matched only non-permitted
120 * enctypes, indicate that. */
121 if (maxkvno < 0 && *start == 0 && saw_non_permitted)
122 ret = KRB5_KDB_NO_PERMITTED_KEY;
124 return ret ? ret : KRB5_KDB_NO_MATCHING_KEY;
131 * kdb default functions. Ideally, some other file should have this functions. For now, TBD.
134 #define min(a,b) (((a) < (b)) ? (a) : (b))
138 krb5_def_store_mkey_list(krb5_context context,
140 krb5_principal mname,
141 krb5_keylist_node *keylist,
144 krb5_error_code retval = 0;
145 char defkeyfile[MAXPATHLEN+1];
146 char *tmp_ktname = NULL, *tmp_ktpath;
147 krb5_data *realm = krb5_princ_realm(context, mname);
148 krb5_keytab kt = NULL;
149 krb5_keytab_entry new_entry;
154 (void) snprintf(defkeyfile, sizeof(defkeyfile), "%s%s",
155 DEFAULT_KEYFILE_STUB, realm->data);
156 keyfile = defkeyfile;
159 if ((statrc = stat(keyfile, &stb)) >= 0) {
160 /* if keyfile exists it better be a regular file */
161 if (!S_ISREG(stb.st_mode)) {
163 k5_setmsg(context, retval,
164 _("keyfile (%s) is not a regular file: %s"),
165 keyfile, error_message(retval));
171 * We assume the stash file is in a directory writable only by root.
172 * As such, don't worry about collisions, just do an atomic rename.
174 retval = asprintf(&tmp_ktname, "FILE:%s_tmp", keyfile);
176 k5_setmsg(context, retval,
177 _("Could not create temp keytab file name."));
182 * Set tmp_ktpath to point to the keyfile path (skip FILE:). Subtracting
183 * 1 to account for NULL terminator in sizeof calculation of a string
184 * constant. Used further down.
186 tmp_ktpath = tmp_ktname + (sizeof("FILE:") - 1);
189 * This time-of-check-to-time-of-access race is fine; we care only
190 * about an administrator running the command twice, not an attacker
191 * trying to beat us to creating the file. Per the above comment, we
192 * assume the stash file is in a directory writable only by root.
194 statrc = stat(tmp_ktpath, &stb);
195 if (statrc == -1 && errno != ENOENT) {
196 /* ENOENT is the expected case */
199 } else if (statrc == 0) {
201 k5_setmsg(context, retval,
202 _("Temporary stash file already exists: %s."), tmp_ktpath);
206 /* create new stash keytab using temp file name */
207 retval = krb5_kt_resolve(context, tmp_ktname, &kt);
211 while (keylist && !retval) {
212 memset(&new_entry, 0, sizeof(new_entry));
213 new_entry.principal = mname;
214 new_entry.key = keylist->keyblock;
215 new_entry.vno = keylist->kvno;
217 retval = krb5_kt_add_entry(context, kt, &new_entry);
218 keylist = keylist->next;
220 krb5_kt_close(context, kt);
223 /* Clean up by deleting the tmp keyfile if it exists. */
224 (void)unlink(tmp_ktpath);
226 /* Atomically rename temp keyfile to original filename. */
227 if (rename(tmp_ktpath, keyfile) < 0) {
229 k5_setmsg(context, retval,
230 _("rename of temporary keyfile (%s) to (%s) failed: %s"),
231 tmp_ktpath, keyfile, error_message(errno));
236 if (tmp_ktname != NULL)
242 static krb5_error_code
243 krb5_db_def_fetch_mkey_stash(krb5_context context,
248 krb5_error_code retval = 0;
253 if (!(kf = fopen(keyfile, "rb")))
254 return KRB5_KDB_CANTREAD_STORED;
255 set_cloexec_file(kf);
257 if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
258 retval = KRB5_KDB_CANTREAD_STORED;
262 #if BIG_ENDIAN_MASTER_KEY
263 enctype = ntohs((uint16_t) enctype);
266 if (key->enctype == ENCTYPE_UNKNOWN)
267 key->enctype = enctype;
268 else if (enctype != key->enctype) {
269 retval = KRB5_KDB_BADSTORED_MKEY;
273 if (fread((krb5_pointer) &keylength,
274 sizeof(keylength), 1, kf) != 1) {
275 retval = KRB5_KDB_CANTREAD_STORED;
279 #if BIG_ENDIAN_MASTER_KEY
280 key->length = ntohl((uint32_t) keylength);
282 key->length = keylength;
285 if (!key->length || ((int) key->length) < 0) {
286 retval = KRB5_KDB_BADSTORED_MKEY;
290 if (!(key->contents = (krb5_octet *)malloc(key->length))) {
295 if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]),
296 key->length, kf) != key->length) {
297 retval = KRB5_KDB_CANTREAD_STORED;
298 zap(key->contents, key->length);
305 * Note, the old stash format did not store the kvno and at this point it
306 * can be assumed to be 1 as is the case for the mkey princ. If the kvno is
307 * passed in and isn't ignore_vno just leave it alone as this could cause
308 * verifcation trouble if the mkey princ is using a kvno other than 1.
310 if (kvno && *kvno == IGNORE_VNO)
318 static krb5_error_code
319 krb5_db_def_fetch_mkey_keytab(krb5_context context,
321 krb5_principal mname,
325 krb5_error_code retval = 0;
326 krb5_keytab kt = NULL;
327 krb5_keytab_entry kt_ent;
328 krb5_enctype enctype = IGNORE_ENCTYPE;
330 if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0)
333 /* override default */
334 if (key->enctype != ENCTYPE_UNKNOWN)
335 enctype = key->enctype;
337 if ((retval = krb5_kt_get_entry(context, kt, mname,
338 kvno ? *kvno : IGNORE_VNO,
342 if (key->enctype == ENCTYPE_UNKNOWN)
343 key->enctype = kt_ent.key.enctype;
345 if (((int) kt_ent.key.length) < 0) {
346 retval = KRB5_KDB_BADSTORED_MKEY;
347 krb5_kt_free_entry(context, &kt_ent);
351 key->length = kt_ent.key.length;
354 * If a kvno pointer was passed in and it dereferences the
355 * IGNORE_VNO value then it should be assigned the value of the kvno
356 * found in the keytab otherwise the KNVO specified should be the
357 * same as the one returned from the keytab.
359 if (kvno != NULL && *kvno == IGNORE_VNO)
363 * kt_ent will be free'd so need to allocate and copy key contents for
366 key->contents = k5memdup(kt_ent.key.contents, kt_ent.key.length,
368 if (key->contents == NULL) {
369 krb5_kt_free_entry(context, &kt_ent);
372 krb5_kt_free_entry(context, &kt_ent);
377 krb5_kt_close(context, kt);
383 krb5_db_def_fetch_mkey(krb5_context context,
384 krb5_principal mname,
389 krb5_error_code retval;
390 char keyfile[MAXPATHLEN+1];
391 krb5_data *realm = krb5_princ_realm(context, mname);
393 key->magic = KV5M_KEYBLOCK;
395 if (db_args != NULL) {
396 (void) strncpy(keyfile, db_args, sizeof(keyfile));
398 (void) snprintf(keyfile, sizeof(keyfile), "%s%s",
399 DEFAULT_KEYFILE_STUB, realm->data);
401 /* null terminate no matter what */
402 keyfile[sizeof(keyfile) - 1] = '\0';
404 /* Try the keytab and old stash file formats. */
405 retval = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno);
406 if (retval == KRB5_KEYTAB_BADVNO)
407 retval = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno);
410 * Use a generic error code for failure to retrieve the master
411 * key, but set a message indicating the actual error.
414 k5_setmsg(context, KRB5_KDB_CANTREAD_STORED,
415 _("Can not fetch master key (error: %s)."),
416 error_message(retval));
417 return KRB5_KDB_CANTREAD_STORED;
423 krb5_def_fetch_mkey_list(krb5_context context,
424 krb5_principal mprinc,
425 const krb5_keyblock *mkey,
426 krb5_keylist_node **mkeys_list)
428 krb5_error_code retval;
429 krb5_db_entry *master_entry;
430 krb5_boolean found_key = FALSE;
431 krb5_keyblock cur_mkey;
432 krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node;
433 krb5_key_data *key_data;
434 krb5_mkey_aux_node *mkey_aux_data_list = NULL, *aux_data_entry;
437 if (mkeys_list == NULL)
440 memset(&cur_mkey, 0, sizeof(cur_mkey));
442 retval = krb5_db_get_principal(context, mprinc, 0, &master_entry);
443 if (retval == KRB5_KDB_NOENTRY)
444 return (KRB5_KDB_NOMASTERKEY);
448 if (master_entry->n_key_data == 0) {
449 retval = KRB5_KDB_NOMASTERKEY;
454 * Check if the input mkey is the latest key and if it isn't then find the
458 if (mkey->enctype == master_entry->key_data[0].key_data_type[0]) {
459 if (krb5_dbe_decrypt_key_data(context, mkey,
460 &master_entry->key_data[0],
461 &cur_mkey, NULL) == 0) {
467 if ((retval = krb5_dbe_lookup_mkey_aux(context, master_entry,
468 &mkey_aux_data_list)))
471 for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
472 aux_data_entry = aux_data_entry->next) {
474 if (krb5_dbe_decrypt_key_data(context, mkey,
475 &aux_data_entry->latest_mkey,
476 &cur_mkey, NULL) == 0) {
481 if (found_key != TRUE) {
482 k5_setmsg(context, KRB5_KDB_BADMASTERKEY,
483 _("Unable to decrypt latest master key with the "
484 "provided master key\n"));
485 retval = KRB5_KDB_BADMASTERKEY;
491 * Extract all the mkeys from master_entry using the most current mkey and
492 * create a mkey list for the mkeys field in kdc_realm_t.
495 mkey_list_head = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
496 if (mkey_list_head == NULL) {
501 memset(mkey_list_head, 0, sizeof(krb5_keylist_node));
503 /* Set mkey_list_head to the current mkey as an optimization. */
504 /* mkvno may not be latest so ... */
505 mkey_list_head->kvno = master_entry->key_data[0].key_data_kvno;
506 /* this is the latest clear mkey (avoids a redundant decrypt) */
507 mkey_list_head->keyblock = cur_mkey;
509 /* loop through any other master keys creating a list of krb5_keylist_nodes */
510 mkey_list_node = &mkey_list_head->next;
511 for (i = 1; i < master_entry->n_key_data; i++) {
512 if (*mkey_list_node == NULL) {
513 /* *mkey_list_node points to next field of previous node */
514 *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
515 if (*mkey_list_node == NULL) {
519 memset(*mkey_list_node, 0, sizeof(krb5_keylist_node));
521 key_data = &master_entry->key_data[i];
522 retval = krb5_dbe_decrypt_key_data(context, &cur_mkey, key_data,
523 &((*mkey_list_node)->keyblock),
528 (*mkey_list_node)->kvno = key_data->key_data_kvno;
529 mkey_list_node = &((*mkey_list_node)->next);
532 *mkeys_list = mkey_list_head;
535 krb5_db_free_principal(context, master_entry);
536 krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_list);
538 krb5_dbe_free_key_list(context, mkey_list_head);
543 krb5_db_def_rename_principal(krb5_context kcontext,
544 krb5_const_principal source,
545 krb5_const_principal target)
547 krb5_db_entry *kdb = NULL;
548 krb5_principal oldprinc;
551 if (source == NULL || target == NULL)
554 ret = krb5_db_get_principal(kcontext, source, KRB5_KDB_FLAG_ALIAS_OK,
559 /* Store salt values explicitly so that they don't depend on the principal
561 ret = krb5_dbe_specialize_salt(kcontext, kdb);
565 /* Temporarily alias kdb->princ to target and put the principal entry. */
566 oldprinc = kdb->princ;
567 kdb->princ = (krb5_principal)target;
568 ret = krb5_db_put_principal(kcontext, kdb);
569 kdb->princ = oldprinc;
573 ret = krb5_db_delete_principal(kcontext, (krb5_principal)source);
577 krb5_db_free_principal(kcontext, kdb);