Blame src/lib/kdb/kdb_default.c

Packit Service 99d1c0
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
Packit Service 99d1c0
/* lib/kdb/kdb_default.c */
Packit Service 99d1c0
/*
Packit Service 99d1c0
 * Copyright 1995, 2009 by the Massachusetts Institute of Technology.
Packit Service 99d1c0
 * All Rights Reserved.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * Export of this software from the United States of America may
Packit Service 99d1c0
 *   require a specific license from the United States Government.
Packit Service 99d1c0
 *   It is the responsibility of any person or organization contemplating
Packit Service 99d1c0
 *   export to obtain such a license before exporting.
Packit Service 99d1c0
 *
Packit Service 99d1c0
 * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
Packit Service 99d1c0
 * distribute this software and its documentation for any purpose and
Packit Service 99d1c0
 * without fee is hereby granted, provided that the above copyright
Packit Service 99d1c0
 * notice appear in all copies and that both that copyright notice and
Packit Service 99d1c0
 * this permission notice appear in supporting documentation, and that
Packit Service 99d1c0
 * the name of M.I.T. not be used in advertising or publicity pertaining
Packit Service 99d1c0
 * to distribution of the software without specific, written prior
Packit Service 99d1c0
 * permission.  Furthermore if you modify this software you must label
Packit Service 99d1c0
 * your software as modified software and not distribute it in such a
Packit Service 99d1c0
 * fashion that it might be confused with the original M.I.T. software.
Packit Service 99d1c0
 * M.I.T. makes no representations about the suitability of
Packit Service 99d1c0
 * this software for any purpose.  It is provided "as is" without express
Packit Service 99d1c0
 * or implied warranty.
Packit Service 99d1c0
 */
Packit Service 99d1c0
/*
Packit Service 99d1c0
 * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
Packit Service 99d1c0
 * Use is subject to license terms.
Packit Service 99d1c0
 */
Packit Service 99d1c0
Packit Service 99d1c0
#include "k5-int.h"
Packit Service 99d1c0
#include "kdb.h"
Packit Service 99d1c0
#include <string.h>
Packit Service 99d1c0
#include <stdio.h>
Packit Service 99d1c0
#include <errno.h>
Packit Service 99d1c0
#include <arpa/inet.h>
Packit Service 99d1c0
Packit Service 99d1c0
Packit Service 99d1c0
/*
Packit Service 99d1c0
 * Set *kd_out to the key data entry matching kvno, enctype, and salttype.  If
Packit Service 99d1c0
 * any of those three parameters are -1, ignore them.  If kvno is 0, match only
Packit Service 99d1c0
 * the highest kvno.  Begin searching at the index *start and set *start to the
Packit Service 99d1c0
 * index after the match.  Do not return keys of non-permitted enctypes; return
Packit Service 99d1c0
 * KRB5_KDB_NO_PERMITTED_KEY if the whole list was searched and only
Packit Service 99d1c0
 * non-permitted matches were found.
Packit Service 99d1c0
 */
Packit Service 99d1c0
krb5_error_code
Packit Service 99d1c0
krb5_dbe_def_search_enctype(krb5_context context, krb5_db_entry *ent,
Packit Service 99d1c0
                            krb5_int32 *start, krb5_int32 enctype,
Packit Service 99d1c0
                            krb5_int32 salttype, krb5_int32 kvno,
Packit Service 99d1c0
                            krb5_key_data **kd_out)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_key_data *kd;
Packit Service 99d1c0
    krb5_int32 db_salttype;
Packit Service 99d1c0
    krb5_boolean saw_non_permitted = FALSE;
Packit Service 99d1c0
    int i;
Packit Service 99d1c0
Packit Service 99d1c0
    *kd_out = NULL;
Packit Service 99d1c0
Packit Service 99d1c0
    if (enctype != -1 && !krb5_is_permitted_enctype(context, enctype))
Packit Service 99d1c0
        return KRB5_KDB_NO_PERMITTED_KEY;
Packit Service 99d1c0
    if (ent->n_key_data == 0)
Packit Service 99d1c0
        return KRB5_KDB_NO_MATCHING_KEY;
Packit Service 99d1c0
Packit Service 99d1c0
    /* Match the highest kvno if kvno is 0.  Key data is sorted in descending
Packit Service 99d1c0
     * order of kvno. */
Packit Service 99d1c0
    if (kvno == 0)
Packit Service 99d1c0
        kvno = ent->key_data[0].key_data_kvno;
Packit Service 99d1c0
Packit Service 99d1c0
    for (i = *start; i < ent->n_key_data; i++) {
Packit Service 99d1c0
        kd = &ent->key_data[i];
Packit Service 99d1c0
        db_salttype = (kd->key_data_ver > 1) ? kd->key_data_type[1] :
Packit Service 99d1c0
            KRB5_KDB_SALTTYPE_NORMAL;
Packit Service 99d1c0
Packit Service 99d1c0
        /* Match this entry against the arguments.  Stop searching if we have
Packit Service 99d1c0
         * passed the entries for the requested kvno. */
Packit Service 99d1c0
        if (enctype != -1 && kd->key_data_type[0] != enctype)
Packit Service 99d1c0
            continue;
Packit Service 99d1c0
        if (salttype >= 0 && db_salttype != salttype)
Packit Service 99d1c0
            continue;
Packit Service 99d1c0
        if (kvno >= 0 && kd->key_data_kvno < kvno)
Packit Service 99d1c0
            break;
Packit Service 99d1c0
        if (kvno >= 0 && kd->key_data_kvno != kvno)
Packit Service 99d1c0
            continue;
Packit Service 99d1c0
Packit Service 99d1c0
        /* Filter out non-permitted enctypes. */
Packit Service 99d1c0
        if (!krb5_is_permitted_enctype(context, kd->key_data_type[0])) {
Packit Service 99d1c0
            saw_non_permitted = TRUE;
Packit Service 99d1c0
            continue;
Packit Service 99d1c0
        }
Packit Service 99d1c0
Packit Service 99d1c0
        *start = i + 1;
Packit Service 99d1c0
        *kd_out = kd;
Packit Service 99d1c0
        return 0;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /* If we scanned the whole set of keys and matched only non-permitted
Packit Service 99d1c0
     * enctypes, indicate that. */
Packit Service 99d1c0
    return (*start == 0 && saw_non_permitted) ? KRB5_KDB_NO_PERMITTED_KEY :
Packit Service 99d1c0
        KRB5_KDB_NO_MATCHING_KEY;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
/*
Packit Service 99d1c0
 *  kdb default functions. Ideally, some other file should have this functions. For now, TBD.
Packit Service 99d1c0
 */
Packit Service 99d1c0
#ifndef min
Packit Service 99d1c0
#define min(a,b) (((a) < (b)) ? (a) : (b))
Packit Service 99d1c0
#endif
Packit Service 99d1c0
Packit Service 99d1c0
krb5_error_code
Packit Service 99d1c0
krb5_def_store_mkey_list(krb5_context       context,
Packit Service 99d1c0
                         char               *keyfile,
Packit Service 99d1c0
                         krb5_principal     mname,
Packit Service 99d1c0
                         krb5_keylist_node  *keylist,
Packit Service 99d1c0
                         char               *master_pwd)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_error_code retval = 0;
Packit Service 99d1c0
    char defkeyfile[MAXPATHLEN+1];
Packit Service 99d1c0
    char *tmp_ktname = NULL, *tmp_ktpath;
Packit Service 99d1c0
    krb5_data *realm = krb5_princ_realm(context, mname);
Packit Service 99d1c0
    krb5_keytab kt = NULL;
Packit Service 99d1c0
    krb5_keytab_entry new_entry;
Packit Service 99d1c0
    struct stat stb;
Packit Service 99d1c0
    int statrc;
Packit Service 99d1c0
Packit Service 99d1c0
    if (!keyfile) {
Packit Service 99d1c0
        (void) snprintf(defkeyfile, sizeof(defkeyfile), "%s%s",
Packit Service 99d1c0
                        DEFAULT_KEYFILE_STUB, realm->data);
Packit Service 99d1c0
        keyfile = defkeyfile;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if ((statrc = stat(keyfile, &stb)) >= 0) {
Packit Service 99d1c0
        /* if keyfile exists it better be a regular file */
Packit Service 99d1c0
        if (!S_ISREG(stb.st_mode)) {
Packit Service 99d1c0
            retval = EINVAL;
Packit Service 99d1c0
            k5_setmsg(context, retval,
Packit Service 99d1c0
                      _("keyfile (%s) is not a regular file: %s"),
Packit Service 99d1c0
                      keyfile, error_message(retval));
Packit Service 99d1c0
            goto out;
Packit Service 99d1c0
        }
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * We assume the stash file is in a directory writable only by root.
Packit Service 99d1c0
     * As such, don't worry about collisions, just do an atomic rename.
Packit Service 99d1c0
     */
Packit Service 99d1c0
    retval = asprintf(&tmp_ktname, "FILE:%s_tmp", keyfile);
Packit Service 99d1c0
    if (retval < 0) {
Packit Service 99d1c0
        k5_setmsg(context, retval,
Packit Service 99d1c0
                  _("Could not create temp keytab file name."));
Packit Service 99d1c0
        goto out;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * Set tmp_ktpath to point to the keyfile path (skip FILE:).  Subtracting
Packit Service 99d1c0
     * 1 to account for NULL terminator in sizeof calculation of a string
Packit Service 99d1c0
     * constant.  Used further down.
Packit Service 99d1c0
     */
Packit Service 99d1c0
    tmp_ktpath = tmp_ktname + (sizeof("FILE:") - 1);
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * This time-of-check-to-time-of-access race is fine; we care only
Packit Service 99d1c0
     * about an administrator running the command twice, not an attacker
Packit Service 99d1c0
     * trying to beat us to creating the file.  Per the above comment, we
Packit Service 99d1c0
     * assume the stash file is in a directory writable only by root.
Packit Service 99d1c0
     */
Packit Service 99d1c0
    statrc = stat(tmp_ktpath, &stb;;
Packit Service 99d1c0
    if (statrc == -1 && errno != ENOENT) {
Packit Service 99d1c0
        /* ENOENT is the expected case */
Packit Service 99d1c0
        retval = errno;
Packit Service 99d1c0
        goto out;
Packit Service 99d1c0
    } else if (statrc == 0) {
Packit Service 99d1c0
        retval = EEXIST;
Packit Service 99d1c0
        k5_setmsg(context, retval,
Packit Service 99d1c0
                  _("Temporary stash file already exists: %s."), tmp_ktpath);
Packit Service 99d1c0
        goto out;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /* create new stash keytab using temp file name */
Packit Service 99d1c0
    retval = krb5_kt_resolve(context, tmp_ktname, &kt;;
Packit Service 99d1c0
    if (retval != 0)
Packit Service 99d1c0
        goto out;
Packit Service 99d1c0
Packit Service 99d1c0
    while (keylist && !retval) {
Packit Service 99d1c0
        memset(&new_entry, 0, sizeof(new_entry));
Packit Service 99d1c0
        new_entry.principal = mname;
Packit Service 99d1c0
        new_entry.key = keylist->keyblock;
Packit Service 99d1c0
        new_entry.vno = keylist->kvno;
Packit Service 99d1c0
Packit Service 99d1c0
        retval = krb5_kt_add_entry(context, kt, &new_entry);
Packit Service 99d1c0
        keylist = keylist->next;
Packit Service 99d1c0
    }
Packit Service 99d1c0
    krb5_kt_close(context, kt);
Packit Service 99d1c0
Packit Service 99d1c0
    if (retval != 0) {
Packit Service 99d1c0
        /* Clean up by deleting the tmp keyfile if it exists. */
Packit Service 99d1c0
        (void)unlink(tmp_ktpath);
Packit Service 99d1c0
    } else {
Packit Service 99d1c0
        /* Atomically rename temp keyfile to original filename. */
Packit Service 99d1c0
        if (rename(tmp_ktpath, keyfile) < 0) {
Packit Service 99d1c0
            retval = errno;
Packit Service 99d1c0
            k5_setmsg(context, retval,
Packit Service 99d1c0
                      _("rename of temporary keyfile (%s) to (%s) failed: %s"),
Packit Service 99d1c0
                      tmp_ktpath, keyfile, error_message(errno));
Packit Service 99d1c0
        }
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
out:
Packit Service 99d1c0
    if (tmp_ktname != NULL)
Packit Service 99d1c0
        free(tmp_ktname);
Packit Service 99d1c0
Packit Service 99d1c0
    return retval;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
static krb5_error_code
Packit Service 99d1c0
krb5_db_def_fetch_mkey_stash(krb5_context   context,
Packit Service 99d1c0
                             const char *keyfile,
Packit Service 99d1c0
                             krb5_keyblock *key,
Packit Service 99d1c0
                             krb5_kvno     *kvno)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_error_code retval = 0;
Packit Service 99d1c0
    krb5_ui_2 enctype;
Packit Service 99d1c0
    krb5_ui_4 keylength;
Packit Service 99d1c0
    FILE *kf = NULL;
Packit Service 99d1c0
Packit Service 99d1c0
    if (!(kf = fopen(keyfile, "rb")))
Packit Service 99d1c0
        return KRB5_KDB_CANTREAD_STORED;
Packit Service 99d1c0
    set_cloexec_file(kf);
Packit Service 99d1c0
Packit Service 99d1c0
    if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
Packit Service 99d1c0
        retval = KRB5_KDB_CANTREAD_STORED;
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
#if BIG_ENDIAN_MASTER_KEY
Packit Service 99d1c0
    enctype = ntohs((uint16_t) enctype);
Packit Service 99d1c0
#endif
Packit Service 99d1c0
Packit Service 99d1c0
    if (key->enctype == ENCTYPE_UNKNOWN)
Packit Service 99d1c0
        key->enctype = enctype;
Packit Service 99d1c0
    else if (enctype != key->enctype) {
Packit Service 99d1c0
        retval = KRB5_KDB_BADSTORED_MKEY;
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (fread((krb5_pointer) &keylength,
Packit Service 99d1c0
              sizeof(keylength), 1, kf) != 1) {
Packit Service 99d1c0
        retval = KRB5_KDB_CANTREAD_STORED;
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
#if BIG_ENDIAN_MASTER_KEY
Packit Service 99d1c0
    key->length = ntohl((uint32_t) keylength);
Packit Service 99d1c0
#else
Packit Service 99d1c0
    key->length = keylength;
Packit Service 99d1c0
#endif
Packit Service 99d1c0
Packit Service 99d1c0
    if (!key->length || key->length > 1024) {
Packit Service 99d1c0
        retval = KRB5_KDB_BADSTORED_MKEY;
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (!(key->contents = (krb5_octet *)malloc(key->length))) {
Packit Service 99d1c0
        retval = ENOMEM;
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]),
Packit Service 99d1c0
              key->length, kf) != key->length) {
Packit Service 99d1c0
        retval = KRB5_KDB_CANTREAD_STORED;
Packit Service 99d1c0
        zap(key->contents, key->length);
Packit Service 99d1c0
        free(key->contents);
Packit Service 99d1c0
        key->contents = 0;
Packit Service 99d1c0
    } else
Packit Service 99d1c0
        retval = 0;
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * Note, the old stash format did not store the kvno and at this point it
Packit Service 99d1c0
     * can be assumed to be 1 as is the case for the mkey princ.  If the kvno is
Packit Service 99d1c0
     * passed in and isn't ignore_vno just leave it alone as this could cause
Packit Service 99d1c0
     * verifcation trouble if the mkey princ is using a kvno other than 1.
Packit Service 99d1c0
     */
Packit Service 99d1c0
    if (kvno && *kvno == IGNORE_VNO)
Packit Service 99d1c0
        *kvno = 1;
Packit Service 99d1c0
Packit Service 99d1c0
errout:
Packit Service 99d1c0
    (void) fclose(kf);
Packit Service 99d1c0
    return retval;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
static krb5_error_code
Packit Service 99d1c0
krb5_db_def_fetch_mkey_keytab(krb5_context   context,
Packit Service 99d1c0
                              const char     *keyfile,
Packit Service 99d1c0
                              krb5_principal mname,
Packit Service 99d1c0
                              krb5_keyblock  *key,
Packit Service 99d1c0
                              krb5_kvno      *kvno)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_error_code retval = 0;
Packit Service 99d1c0
    krb5_keytab kt = NULL;
Packit Service 99d1c0
    krb5_keytab_entry kt_ent;
Packit Service 99d1c0
    krb5_enctype enctype = IGNORE_ENCTYPE;
Packit Service 99d1c0
Packit Service 99d1c0
    if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0)
Packit Service 99d1c0
        goto errout;
Packit Service 99d1c0
Packit Service 99d1c0
    /* override default */
Packit Service 99d1c0
    if (key->enctype != ENCTYPE_UNKNOWN)
Packit Service 99d1c0
        enctype = key->enctype;
Packit Service 99d1c0
Packit Service 99d1c0
    if ((retval = krb5_kt_get_entry(context, kt, mname,
Packit Service 99d1c0
                                    kvno ? *kvno : IGNORE_VNO,
Packit Service 99d1c0
                                    enctype,
Packit Service 99d1c0
                                    &kt_ent)) == 0) {
Packit Service 99d1c0
Packit Service 99d1c0
        if (key->enctype == ENCTYPE_UNKNOWN)
Packit Service 99d1c0
            key->enctype = kt_ent.key.enctype;
Packit Service 99d1c0
Packit Service 99d1c0
        if (((int) kt_ent.key.length) < 0) {
Packit Service 99d1c0
            retval = KRB5_KDB_BADSTORED_MKEY;
Packit Service 99d1c0
            krb5_kt_free_entry(context, &kt_ent);
Packit Service 99d1c0
            goto errout;
Packit Service 99d1c0
        }
Packit Service 99d1c0
Packit Service 99d1c0
        key->length = kt_ent.key.length;
Packit Service 99d1c0
Packit Service 99d1c0
        /*
Packit Service 99d1c0
         * If a kvno pointer was passed in and it dereferences the
Packit Service 99d1c0
         * IGNORE_VNO value then it should be assigned the value of the kvno
Packit Service 99d1c0
         * found in the keytab otherwise the KNVO specified should be the
Packit Service 99d1c0
         * same as the one returned from the keytab.
Packit Service 99d1c0
         */
Packit Service 99d1c0
        if (kvno != NULL && *kvno == IGNORE_VNO)
Packit Service 99d1c0
            *kvno = kt_ent.vno;
Packit Service 99d1c0
Packit Service 99d1c0
        /*
Packit Service 99d1c0
         * kt_ent will be free'd so need to allocate and copy key contents for
Packit Service 99d1c0
         * output to caller.
Packit Service 99d1c0
         */
Packit Service 99d1c0
        key->contents = k5memdup(kt_ent.key.contents, kt_ent.key.length,
Packit Service 99d1c0
                                 &retval);
Packit Service 99d1c0
        if (key->contents == NULL) {
Packit Service 99d1c0
            krb5_kt_free_entry(context, &kt_ent);
Packit Service 99d1c0
            goto errout;
Packit Service 99d1c0
        }
Packit Service 99d1c0
        krb5_kt_free_entry(context, &kt_ent);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
errout:
Packit Service 99d1c0
    if (kt)
Packit Service 99d1c0
        krb5_kt_close(context, kt);
Packit Service 99d1c0
Packit Service 99d1c0
    return retval;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
krb5_error_code
Packit Service 99d1c0
krb5_db_def_fetch_mkey(krb5_context   context,
Packit Service 99d1c0
                       krb5_principal mname,
Packit Service 99d1c0
                       krb5_keyblock *key,
Packit Service 99d1c0
                       krb5_kvno     *kvno,
Packit Service 99d1c0
                       char          *db_args)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_error_code retval;
Packit Service 99d1c0
    char keyfile[MAXPATHLEN+1];
Packit Service 99d1c0
    krb5_data *realm = krb5_princ_realm(context, mname);
Packit Service 99d1c0
Packit Service 99d1c0
    key->magic = KV5M_KEYBLOCK;
Packit Service 99d1c0
Packit Service 99d1c0
    if (db_args != NULL) {
Packit Service 99d1c0
        (void) strncpy(keyfile, db_args, sizeof(keyfile));
Packit Service 99d1c0
    } else {
Packit Service 99d1c0
        (void) snprintf(keyfile, sizeof(keyfile), "%s%s",
Packit Service 99d1c0
                        DEFAULT_KEYFILE_STUB, realm->data);
Packit Service 99d1c0
    }
Packit Service 99d1c0
    /* null terminate no matter what */
Packit Service 99d1c0
    keyfile[sizeof(keyfile) - 1] = '\0';
Packit Service 99d1c0
Packit Service 99d1c0
    /* Try the keytab and old stash file formats. */
Packit Service 99d1c0
    retval = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno);
Packit Service 99d1c0
    if (retval == KRB5_KEYTAB_BADVNO)
Packit Service 99d1c0
        retval = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno);
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * Use a generic error code for failure to retrieve the master
Packit Service 99d1c0
     * key, but set a message indicating the actual error.
Packit Service 99d1c0
     */
Packit Service 99d1c0
    if (retval != 0) {
Packit Service 99d1c0
        k5_setmsg(context, KRB5_KDB_CANTREAD_STORED,
Packit Service 99d1c0
                  _("Can not fetch master key (error: %s)."),
Packit Service 99d1c0
                  error_message(retval));
Packit Service 99d1c0
        return KRB5_KDB_CANTREAD_STORED;
Packit Service 99d1c0
    } else
Packit Service 99d1c0
        return 0;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
krb5_error_code
Packit Service 99d1c0
krb5_def_fetch_mkey_list(krb5_context        context,
Packit Service 99d1c0
                         krb5_principal        mprinc,
Packit Service 99d1c0
                         const krb5_keyblock  *mkey,
Packit Service 99d1c0
                         krb5_keylist_node  **mkeys_list)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_error_code retval;
Packit Service 99d1c0
    krb5_db_entry *master_entry;
Packit Service 99d1c0
    krb5_boolean found_key = FALSE;
Packit Service 99d1c0
    krb5_keyblock cur_mkey;
Packit Service 99d1c0
    krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node;
Packit Service 99d1c0
    krb5_key_data *key_data;
Packit Service 99d1c0
    krb5_mkey_aux_node  *mkey_aux_data_list = NULL, *aux_data_entry;
Packit Service 99d1c0
    int i;
Packit Service 99d1c0
Packit Service 99d1c0
    if (mkeys_list == NULL)
Packit Service 99d1c0
        return (EINVAL);
Packit Service 99d1c0
Packit Service 99d1c0
    memset(&cur_mkey, 0, sizeof(cur_mkey));
Packit Service 99d1c0
Packit Service 99d1c0
    retval = krb5_db_get_principal(context, mprinc, 0, &master_entry);
Packit Service 99d1c0
    if (retval == KRB5_KDB_NOENTRY)
Packit Service 99d1c0
        return (KRB5_KDB_NOMASTERKEY);
Packit Service 99d1c0
    if (retval)
Packit Service 99d1c0
        return (retval);
Packit Service 99d1c0
Packit Service 99d1c0
    if (master_entry->n_key_data == 0) {
Packit Service 99d1c0
        retval = KRB5_KDB_NOMASTERKEY;
Packit Service 99d1c0
        goto clean_n_exit;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * Check if the input mkey is the latest key and if it isn't then find the
Packit Service 99d1c0
     * latest mkey.
Packit Service 99d1c0
     */
Packit Service 99d1c0
Packit Service 99d1c0
    if (mkey->enctype == master_entry->key_data[0].key_data_type[0]) {
Packit Service 99d1c0
        if (krb5_dbe_decrypt_key_data(context, mkey,
Packit Service 99d1c0
                                      &master_entry->key_data[0],
Packit Service 99d1c0
                                      &cur_mkey, NULL) == 0) {
Packit Service 99d1c0
            found_key = TRUE;
Packit Service 99d1c0
        }
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    if (!found_key) {
Packit Service 99d1c0
        if ((retval = krb5_dbe_lookup_mkey_aux(context, master_entry,
Packit Service 99d1c0
                                               &mkey_aux_data_list)))
Packit Service 99d1c0
            goto clean_n_exit;
Packit Service 99d1c0
Packit Service 99d1c0
        for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
Packit Service 99d1c0
             aux_data_entry = aux_data_entry->next) {
Packit Service 99d1c0
Packit Service 99d1c0
            if (krb5_dbe_decrypt_key_data(context, mkey,
Packit Service 99d1c0
                                          &aux_data_entry->latest_mkey,
Packit Service 99d1c0
                                          &cur_mkey, NULL) == 0) {
Packit Service 99d1c0
                found_key = TRUE;
Packit Service 99d1c0
                break;
Packit Service 99d1c0
            }
Packit Service 99d1c0
        }
Packit Service 99d1c0
        if (found_key != TRUE) {
Packit Service 99d1c0
            k5_setmsg(context, KRB5_KDB_BADMASTERKEY,
Packit Service 99d1c0
                      _("Unable to decrypt latest master key with the "
Packit Service 99d1c0
                        "provided master key\n"));
Packit Service 99d1c0
            retval = KRB5_KDB_BADMASTERKEY;
Packit Service 99d1c0
            goto clean_n_exit;
Packit Service 99d1c0
        }
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    /*
Packit Service 99d1c0
     * Extract all the mkeys from master_entry using the most current mkey and
Packit Service 99d1c0
     * create a mkey list for the mkeys field in kdc_realm_t.
Packit Service 99d1c0
     */
Packit Service 99d1c0
Packit Service 99d1c0
    mkey_list_head = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
Packit Service 99d1c0
    if (mkey_list_head == NULL) {
Packit Service 99d1c0
        retval = ENOMEM;
Packit Service 99d1c0
        goto clean_n_exit;
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    memset(mkey_list_head, 0, sizeof(krb5_keylist_node));
Packit Service 99d1c0
Packit Service 99d1c0
    /* Set mkey_list_head to the current mkey as an optimization. */
Packit Service 99d1c0
    /* mkvno may not be latest so ... */
Packit Service 99d1c0
    mkey_list_head->kvno = master_entry->key_data[0].key_data_kvno;
Packit Service 99d1c0
    /* this is the latest clear mkey (avoids a redundant decrypt) */
Packit Service 99d1c0
    mkey_list_head->keyblock = cur_mkey;
Packit Service 99d1c0
Packit Service 99d1c0
    /* loop through any other master keys creating a list of krb5_keylist_nodes */
Packit Service 99d1c0
    mkey_list_node = &mkey_list_head->next;
Packit Service 99d1c0
    for (i = 1; i < master_entry->n_key_data; i++) {
Packit Service 99d1c0
        if (*mkey_list_node == NULL) {
Packit Service 99d1c0
            /* *mkey_list_node points to next field of previous node */
Packit Service 99d1c0
            *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
Packit Service 99d1c0
            if (*mkey_list_node == NULL) {
Packit Service 99d1c0
                retval = ENOMEM;
Packit Service 99d1c0
                goto clean_n_exit;
Packit Service 99d1c0
            }
Packit Service 99d1c0
            memset(*mkey_list_node, 0, sizeof(krb5_keylist_node));
Packit Service 99d1c0
        }
Packit Service 99d1c0
        key_data = &master_entry->key_data[i];
Packit Service 99d1c0
        retval = krb5_dbe_decrypt_key_data(context, &cur_mkey, key_data,
Packit Service 99d1c0
                                           &((*mkey_list_node)->keyblock),
Packit Service 99d1c0
                                           NULL);
Packit Service 99d1c0
        if (retval)
Packit Service 99d1c0
            goto clean_n_exit;
Packit Service 99d1c0
Packit Service 99d1c0
        (*mkey_list_node)->kvno = key_data->key_data_kvno;
Packit Service 99d1c0
        mkey_list_node = &((*mkey_list_node)->next);
Packit Service 99d1c0
    }
Packit Service 99d1c0
Packit Service 99d1c0
    *mkeys_list = mkey_list_head;
Packit Service 99d1c0
Packit Service 99d1c0
clean_n_exit:
Packit Service 99d1c0
    krb5_db_free_principal(context, master_entry);
Packit Service 99d1c0
    krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_list);
Packit Service 99d1c0
    if (retval != 0)
Packit Service 99d1c0
        krb5_dbe_free_key_list(context, mkey_list_head);
Packit Service 99d1c0
    return retval;
Packit Service 99d1c0
}
Packit Service 99d1c0
Packit Service 99d1c0
krb5_error_code
Packit Service 99d1c0
krb5_db_def_rename_principal(krb5_context kcontext,
Packit Service 99d1c0
                             krb5_const_principal source,
Packit Service 99d1c0
                             krb5_const_principal target)
Packit Service 99d1c0
{
Packit Service 99d1c0
    krb5_db_entry *kdb = NULL;
Packit Service 99d1c0
    krb5_principal oldprinc;
Packit Service 99d1c0
    krb5_error_code ret;
Packit Service 99d1c0
Packit Service 99d1c0
    if (source == NULL || target == NULL)
Packit Service 99d1c0
        return EINVAL;
Packit Service 99d1c0
Packit Service 99d1c0
    ret = krb5_db_get_principal(kcontext, source, 0, &kdb);
Packit Service 99d1c0
    if (ret)
Packit Service 99d1c0
        goto cleanup;
Packit Service 99d1c0
Packit Service 99d1c0
    /* Store salt values explicitly so that they don't depend on the principal
Packit Service 99d1c0
     * name. */
Packit Service 99d1c0
    ret = krb5_dbe_specialize_salt(kcontext, kdb);
Packit Service 99d1c0
    if (ret)
Packit Service 99d1c0
        goto cleanup;
Packit Service 99d1c0
Packit Service 99d1c0
    /* Temporarily alias kdb->princ to target and put the principal entry. */
Packit Service 99d1c0
    oldprinc = kdb->princ;
Packit Service 99d1c0
    kdb->princ = (krb5_principal)target;
Packit Service 99d1c0
    ret = krb5_db_put_principal(kcontext, kdb);
Packit Service 99d1c0
    kdb->princ = oldprinc;
Packit Service 99d1c0
    if (ret)
Packit Service 99d1c0
        goto cleanup;
Packit Service 99d1c0
Packit Service 99d1c0
    ret = krb5_db_delete_principal(kcontext, (krb5_principal)source);
Packit Service 99d1c0
Packit Service 99d1c0
Packit Service 99d1c0
cleanup:
Packit Service 99d1c0
    krb5_db_free_principal(kcontext, kdb);
Packit Service 99d1c0
    return ret;
Packit Service 99d1c0
}