2N/A/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2N/A/*
2N/A * lib/kdb/kdb_helper.c
2N/A *
2N/A * Copyright 1995, 2009 by the Massachusetts Institute of Technology.
2N/A * All Rights Reserved.
2N/A *
2N/A * Export of this software from the United States of America may
2N/A * require a specific license from the United States Government.
2N/A * It is the responsibility of any person or organization contemplating
2N/A * export to obtain such a license before exporting.
2N/A *
2N/A * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
2N/A * distribute this software and its documentation for any purpose and
2N/A * without fee is hereby granted, provided that the above copyright
2N/A * notice appear in all copies and that both that copyright notice and
2N/A * this permission notice appear in supporting documentation, and that
2N/A * the name of M.I.T. not be used in advertising or publicity pertaining
2N/A * to distribution of the software without specific, written prior
2N/A * permission. Furthermore if you modify this software you must label
2N/A * your software as modified software and not distribute it in such a
2N/A * fashion that it might be confused with the original M.I.T. software.
2N/A * M.I.T. makes no representations about the suitability of
2N/A * this software for any purpose. It is provided "as is" without express
2N/A * or implied warranty.
2N/A *
2N/A */
2N/A
2N/A/*
2N/A * Copyright (c) 2007, 2012, Oracle and/or its affiliates. All rights reserved.
2N/A */
2N/A
2N/A#include "k5-int.h"
2N/A#include "kdb.h"
2N/A#include <string.h>
2N/A#include <stdio.h>
2N/A#include <errno.h>
2N/A#include <arpa/inet.h>
2N/A#include <libintl.h> /* Solaris Kerberos */
2N/A
2N/A
2N/A/*
2N/A * Given a particular enctype and optional salttype and kvno, find the
2N/A * most appropriate krb5_key_data entry of the database entry.
2N/A *
2N/A * If stype or kvno is negative, it is ignored.
2N/A * If kvno is 0 get the key which is maxkvno for the princ and matches
2N/A * the other attributes.
2N/A */
2N/Akrb5_error_code
2N/Akrb5_dbe_def_search_enctype(kcontext, dbentp, start, ktype, stype, kvno, kdatap)
2N/A krb5_context kcontext;
2N/A krb5_db_entry *dbentp;
2N/A krb5_int32 *start;
2N/A krb5_int32 ktype;
2N/A krb5_int32 stype;
2N/A krb5_int32 kvno;
2N/A krb5_key_data **kdatap;
2N/A{
2N/A int i, idx;
2N/A int maxkvno;
2N/A krb5_key_data *datap;
2N/A krb5_error_code ret;
2N/A krb5_boolean saw_non_permitted = FALSE;
2N/A
2N/A ret = 0;
2N/A if (kvno == -1 && stype == -1 && ktype == -1)
2N/A kvno = 0;
2N/A
2N/A if (kvno == 0) {
2N/A /* Get the max key version */
2N/A for (i = 0; i < dbentp->n_key_data; i++) {
2N/A if (kvno < dbentp->key_data[i].key_data_kvno) {
2N/A kvno = dbentp->key_data[i].key_data_kvno;
2N/A }
2N/A }
2N/A }
2N/A
2N/A maxkvno = -1;
2N/A datap = (krb5_key_data *) NULL;
2N/A for (i = *start; i < dbentp->n_key_data; i++) {
2N/A krb5_boolean similar;
2N/A krb5_int32 db_stype;
2N/A
2N/A ret = 0;
2N/A if (dbentp->key_data[i].key_data_ver > 1) {
2N/A db_stype = dbentp->key_data[i].key_data_type[1];
2N/A } else {
2N/A db_stype = KRB5_KDB_SALTTYPE_NORMAL;
2N/A }
2N/A
2N/A /* Match this entry against the arguments. */
2N/A if (ktype != -1) {
2N/A if ((ret = krb5_c_enctype_compare(kcontext, (krb5_enctype) ktype,
2N/A dbentp->key_data[i].key_data_type[0],
2N/A &similar)))
2N/A
2N/A return(ret);
2N/A if (!similar)
2N/A continue;
2N/A }
2N/A if (stype >= 0 && db_stype != stype)
2N/A continue;
2N/A if (kvno >= 0 && dbentp->key_data[i].key_data_kvno != kvno)
2N/A continue;
2N/A
2N/A /* Filter out non-permitted enctypes. */
2N/A if (!krb5_is_permitted_enctype(kcontext,
2N/A dbentp->key_data[i].key_data_type[0])) {
2N/A saw_non_permitted = TRUE;
2N/A continue;
2N/A }
2N/A
2N/A if (dbentp->key_data[i].key_data_kvno > maxkvno) {
2N/A maxkvno = dbentp->key_data[i].key_data_kvno;
2N/A datap = &dbentp->key_data[i];
2N/A idx = i;
2N/A }
2N/A }
2N/A /* If we scanned the whole set of keys and matched only non-permitted
2N/A * enctypes, indicate that. */
2N/A if (maxkvno < 0 && *start == 0 && saw_non_permitted)
2N/A ret = KRB5_KDB_NO_PERMITTED_KEY;
2N/A if (maxkvno < 0)
2N/A return ret ? ret : KRB5_KDB_NO_MATCHING_KEY;
2N/A *kdatap = datap;
2N/A *start = idx+1;
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * kdb default functions. Ideally, some other file should have this functions. For now, TBD.
2N/A */
2N/A#ifndef min
2N/A#define min(a,b) (((a) < (b)) ? (a) : (b))
2N/A#endif
2N/A
2N/Akrb5_error_code
2N/Akrb5_def_store_mkey_list(krb5_context context,
2N/A char *keyfile,
2N/A krb5_principal mname,
2N/A krb5_keylist_node *keylist,
2N/A char *master_pwd)
2N/A{
2N/A krb5_error_code retval = 0;
2N/A char defkeyfile[MAXPATHLEN+1];
2N/A char *tmp_ktname = NULL, *tmp_ktpath;
2N/A krb5_data *realm = krb5_princ_realm(context, mname);
2N/A krb5_keytab kt = NULL;
2N/A krb5_keytab_entry new_entry;
2N/A struct stat stb;
2N/A int statrc;
2N/A
2N/A if (!keyfile) {
2N/A (void) snprintf(defkeyfile, sizeof(defkeyfile), "%s%s",
2N/A DEFAULT_KEYFILE_STUB, realm->data);
2N/A keyfile = defkeyfile;
2N/A }
2N/A
2N/A /*
2N/A * XXX making the assumption that the keyfile is in a dir that requires root
2N/A * privilege to write to thus making timing attacks unlikely.
2N/A */
2N/A if ((statrc = stat(keyfile, &stb)) >= 0) {
2N/A /* if keyfile exists it better be a regular file */
2N/A if (!S_ISREG(stb.st_mode)) {
2N/A retval = EINVAL;
2N/A krb5_set_error_message (context, retval,
2N/A gettext("keyfile (%s) is not a regular file: %s"),
2N/A keyfile, error_message(retval));
2N/A goto out;
2N/A }
2N/A }
2N/A
2N/A /* Use temp keytab file name in case creation of keytab fails */
2N/A
2N/A /* create temp file template for use by mktemp() */
2N/A if ((retval = asprintf(&tmp_ktname, "WRFILE:%s_XXXXXX", keyfile)) < 0) {
2N/A krb5_set_error_message (context, retval,
2N/A "Could not create temp keytab file name.");
2N/A goto out;
2N/A }
2N/A
2N/A /*
2N/A * Set tmp_ktpath to point to the keyfile path (skip WRFILE:). Subtracting
2N/A * 1 to account for NULL terminator in sizeof calculation of a string
2N/A * constant. Used further down.
2N/A */
2N/A tmp_ktpath = tmp_ktname + (sizeof("WRFILE:") - 1);
2N/A
2N/A if (mktemp(tmp_ktpath) == NULL) {
2N/A retval = errno;
2N/A krb5_set_error_message (context, retval,
2N/A "Could not create temp stash file: %s",
2N/A error_message(errno));
2N/A goto out;
2N/A }
2N/A
2N/A /* create new stash keytab using temp file name */
2N/A retval = krb5_kt_resolve(context, tmp_ktname, &kt);
2N/A if (retval != 0)
2N/A goto out;
2N/A
2N/A while (keylist && !retval) {
2N/A memset(&new_entry, 0, sizeof(new_entry));
2N/A new_entry.principal = mname;
2N/A new_entry.key = keylist->keyblock;
2N/A new_entry.vno = keylist->kvno;
2N/A
2N/A retval = krb5_kt_add_entry(context, kt, &new_entry);
2N/A keylist = keylist->next;
2N/A }
2N/A krb5_kt_close(context, kt);
2N/A
2N/A if (retval != 0) {
2N/A /* delete tmp keyfile if it exists and an error occurrs */
2N/A if (stat(keyfile, &stb) >= 0)
2N/A (void) unlink(tmp_ktpath);
2N/A } else {
2N/A /* rename original keyfile to original filename */
2N/A if (rename(tmp_ktpath, keyfile) < 0) {
2N/A retval = errno;
2N/A krb5_set_error_message (context, retval,
2N/A "rename of temporary keyfile (%s) to (%s) failed: %s",
2N/A tmp_ktpath, keyfile, error_message(errno));
2N/A }
2N/A }
2N/A
2N/Aout:
2N/A if (tmp_ktname != NULL)
2N/A free(tmp_ktname);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Akrb5_def_store_mkey(krb5_context context,
2N/A char *keyfile,
2N/A krb5_principal mname,
2N/A krb5_kvno kvno,
2N/A krb5_keyblock *key,
2N/A char *master_pwd)
2N/A{
2N/A krb5_keylist_node list;
2N/A
2N/A list.kvno = kvno;
2N/A list.keyblock = *key;
2N/A list.next = NULL;
2N/A return krb5_def_store_mkey_list(context, keyfile, mname, &list,
2N/A master_pwd);
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Akrb5_db_def_fetch_mkey_stash(krb5_context context,
2N/A const char *keyfile,
2N/A krb5_keyblock *key,
2N/A krb5_kvno *kvno)
2N/A{
2N/A krb5_error_code retval = 0;
2N/A krb5_ui_2 enctype;
2N/A krb5_ui_4 keylength;
2N/A FILE *kf = NULL;
2N/A
2N/A#ifdef ANSI_STDIO
2N/A if (!(kf = fopen(keyfile, "rb")))
2N/A#else
2N/A if (!(kf = fopen(keyfile, "r")))
2N/A#endif
2N/A return KRB5_KDB_CANTREAD_STORED;
2N/A set_cloexec_file(kf);
2N/A
2N/A if (fread((krb5_pointer) &enctype, 2, 1, kf) != 1) {
2N/A retval = KRB5_KDB_CANTREAD_STORED;
2N/A goto errout;
2N/A }
2N/A
2N/A#if BIG_ENDIAN_MASTER_KEY
2N/A enctype = ntohs((uint16_t) enctype);
2N/A#endif
2N/A
2N/A if (key->enctype == ENCTYPE_UNKNOWN)
2N/A key->enctype = enctype;
2N/A else if (enctype != key->enctype) {
2N/A retval = KRB5_KDB_BADSTORED_MKEY;
2N/A goto errout;
2N/A }
2N/A
2N/A if (fread((krb5_pointer) &keylength,
2N/A sizeof(keylength), 1, kf) != 1) {
2N/A retval = KRB5_KDB_CANTREAD_STORED;
2N/A goto errout;
2N/A }
2N/A
2N/A#if BIG_ENDIAN_MASTER_KEY
2N/A key->length = ntohl((uint32_t) keylength);
2N/A#else
2N/A key->length = keylength;
2N/A#endif
2N/A
2N/A if (!key->length || ((int) key->length) < 0) {
2N/A retval = KRB5_KDB_BADSTORED_MKEY;
2N/A goto errout;
2N/A }
2N/A
2N/A if (!(key->contents = (krb5_octet *)malloc(key->length))) {
2N/A retval = ENOMEM;
2N/A goto errout;
2N/A }
2N/A
2N/A if (fread((krb5_pointer) key->contents, sizeof(key->contents[0]),
2N/A key->length, kf) != key->length) {
2N/A retval = KRB5_KDB_CANTREAD_STORED;
2N/A zap(key->contents, key->length);
2N/A free(key->contents);
2N/A key->contents = 0;
2N/A } else
2N/A retval = 0;
2N/A
2N/A /*
2N/A * Note, the old stash format did not store the kvno and at this point it
2N/A * can be assumed to be 1 as is the case for the mkey princ. If the kvno is
2N/A * passed in and isn't ignore_vno just leave it alone as this could cause
2N/A * verifcation trouble if the mkey princ is using a kvno other than 1.
2N/A */
2N/A if (kvno && *kvno == IGNORE_VNO)
2N/A *kvno = 1;
2N/A
2N/Aerrout:
2N/A (void) fclose(kf);
2N/A return retval;
2N/A}
2N/A
2N/Astatic krb5_error_code
2N/Akrb5_db_def_fetch_mkey_keytab(krb5_context context,
2N/A const char *keyfile,
2N/A krb5_principal mname,
2N/A krb5_keyblock *key,
2N/A krb5_kvno *kvno)
2N/A{
2N/A krb5_error_code retval = 0;
2N/A krb5_keytab kt = NULL;
2N/A krb5_keytab_entry kt_ent;
2N/A krb5_enctype enctype = IGNORE_ENCTYPE;
2N/A
2N/A if ((retval = krb5_kt_resolve(context, keyfile, &kt)) != 0)
2N/A goto errout;
2N/A
2N/A /* override default */
2N/A if (key->enctype != ENCTYPE_UNKNOWN)
2N/A enctype = key->enctype;
2N/A
2N/A if ((retval = krb5_kt_get_entry(context, kt, mname,
2N/A kvno ? *kvno : IGNORE_VNO,
2N/A enctype,
2N/A &kt_ent)) == 0) {
2N/A
2N/A if (key->enctype == ENCTYPE_UNKNOWN)
2N/A key->enctype = kt_ent.key.enctype;
2N/A
2N/A if (((int) kt_ent.key.length) < 0) {
2N/A retval = KRB5_KDB_BADSTORED_MKEY;
2N/A krb5_kt_free_entry(context, &kt_ent);
2N/A goto errout;
2N/A }
2N/A
2N/A key->length = kt_ent.key.length;
2N/A
2N/A /*
2N/A * If a kvno pointer was passed in and it dereferences the
2N/A * IGNORE_VNO value then it should be assigned the value of the kvno
2N/A * found in the keytab otherwise the KNVO specified should be the
2N/A * same as the one returned from the keytab.
2N/A */
2N/A if (kvno != NULL && *kvno == IGNORE_VNO)
2N/A *kvno = kt_ent.vno;
2N/A
2N/A /*
2N/A * kt_ent will be free'd so need to allocate and copy key contents for
2N/A * output to caller.
2N/A */
2N/A if (!(key->contents = (krb5_octet *)malloc(key->length))) {
2N/A retval = ENOMEM;
2N/A krb5_kt_free_entry(context, &kt_ent);
2N/A goto errout;
2N/A }
2N/A memcpy(key->contents, kt_ent.key.contents, kt_ent.key.length);
2N/A krb5_kt_free_entry(context, &kt_ent);
2N/A }
2N/A
2N/Aerrout:
2N/A if (kt)
2N/A krb5_kt_close(context, kt);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code
2N/Akrb5_db_def_fetch_mkey(krb5_context context,
2N/A krb5_principal mname,
2N/A krb5_keyblock *key,
2N/A krb5_kvno *kvno,
2N/A char *db_args)
2N/A{
2N/A krb5_error_code retval;
2N/A char keyfile[MAXPATHLEN+1];
2N/A krb5_data *realm = krb5_princ_realm(context, mname);
2N/A
2N/A key->magic = KV5M_KEYBLOCK;
2N/A
2N/A if (db_args != NULL) {
2N/A (void) strncpy(keyfile, db_args, sizeof(keyfile));
2N/A } else {
2N/A (void) snprintf(keyfile, sizeof(keyfile), "%s%s",
2N/A DEFAULT_KEYFILE_STUB, realm->data);
2N/A }
2N/A /* null terminate no matter what */
2N/A keyfile[sizeof(keyfile) - 1] = '\0';
2N/A
2N/A /* Try the keytab and old stash file formats. */
2N/A retval = krb5_db_def_fetch_mkey_keytab(context, keyfile, mname, key, kvno);
2N/A if (retval == KRB5_KEYTAB_BADVNO)
2N/A retval = krb5_db_def_fetch_mkey_stash(context, keyfile, key, kvno);
2N/A
2N/A /*
2N/A * Use a generic error code for failure to retrieve the master
2N/A * key, but set a message indicating the actual error.
2N/A */
2N/A if (retval != 0) {
2N/A krb5_set_error_message(context, KRB5_KDB_CANTREAD_STORED,
2N/A "Can not fetch master key (error: %s).",
2N/A error_message(retval));
2N/A return KRB5_KDB_CANTREAD_STORED;
2N/A } else
2N/A return 0;
2N/A}
2N/A
2N/A/*
2N/A * Note, this verifies that the input mkey is currently protecting all the mkeys
2N/A */
2N/Akrb5_error_code
2N/Akrb5_def_verify_master_key(krb5_context context,
2N/A krb5_principal mprinc,
2N/A krb5_kvno kvno,
2N/A krb5_keyblock *mkey)
2N/A{
2N/A krb5_error_code retval;
2N/A krb5_db_entry master_entry;
2N/A int nprinc;
2N/A krb5_boolean more;
2N/A krb5_keyblock tempkey;
2N/A
2N/A nprinc = 1;
2N/A if ((retval = krb5_db_get_principal(context, mprinc,
2N/A &master_entry, &nprinc, &more)))
2N/A return(retval);
2N/A
2N/A if (nprinc != 1) {
2N/A if (nprinc)
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A return(KRB5_KDB_NOMASTERKEY);
2N/A } else if (more) {
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A return(KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
2N/A }
2N/A
2N/A if ((retval = krb5_dbekd_decrypt_key_data(context, mkey,
2N/A &master_entry.key_data[0],
2N/A &tempkey, NULL))) {
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A return retval;
2N/A }
2N/A
2N/A if (mkey->length != tempkey.length ||
2N/A memcmp((char *)mkey->contents,
2N/A (char *)tempkey.contents,mkey->length)) {
2N/A retval = KRB5_KDB_BADMASTERKEY;
2N/A }
2N/A
2N/A if (kvno != IGNORE_VNO &&
2N/A kvno != (krb5_kvno) master_entry.key_data->key_data_kvno) {
2N/A retval = KRB5_KDB_BADMASTERKEY;
2N/A krb5_set_error_message (context, retval,
2N/A "User specified mkeyVNO (%u) does not match master key princ's KVNO (%u)",
2N/A kvno, master_entry.key_data->key_data_kvno);
2N/A }
2N/A
2N/A zap((char *)tempkey.contents, tempkey.length);
2N/A free(tempkey.contents);
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A
2N/A return retval;
2N/A}
2N/A
2N/A/* Solaris Kerberos: removed unused mkvno arg */
2N/Akrb5_error_code
2N/Akrb5_def_fetch_mkey_list(krb5_context context,
2N/A krb5_principal mprinc,
2N/A const krb5_keyblock *mkey,
2N/A krb5_keylist_node **mkeys_list)
2N/A{
2N/A krb5_error_code retval;
2N/A krb5_db_entry master_entry;
2N/A int nprinc;
2N/A krb5_boolean more, found_key = FALSE;
2N/A krb5_keyblock cur_mkey;
2N/A krb5_keylist_node *mkey_list_head = NULL, **mkey_list_node;
2N/A krb5_key_data *key_data;
2N/A krb5_mkey_aux_node *mkey_aux_data_list = NULL, *aux_data_entry;
2N/A int i;
2N/A
2N/A if (mkeys_list == NULL)
2N/A return (EINVAL);
2N/A
2N/A memset(&cur_mkey, 0, sizeof(cur_mkey));
2N/A memset(&master_entry, 0, sizeof(master_entry));
2N/A
2N/A nprinc = 1;
2N/A if ((retval = krb5_db_get_principal(context, mprinc,
2N/A &master_entry, &nprinc, &more)))
2N/A return (retval);
2N/A
2N/A if (nprinc != 1) {
2N/A if (nprinc)
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A return(KRB5_KDB_NOMASTERKEY);
2N/A } else if (more) {
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A return (KRB5KDC_ERR_PRINCIPAL_NOT_UNIQUE);
2N/A }
2N/A
2N/A /*
2N/A * Check if the input mkey is the latest key and if it isn't then find the
2N/A * latest mkey.
2N/A */
2N/A
2N/A if (mkey->enctype == master_entry.key_data[0].key_data_type[0]) {
2N/A if (krb5_dbekd_decrypt_key_data(context, mkey,
2N/A &master_entry.key_data[0],
2N/A &cur_mkey, NULL) == 0) {
2N/A found_key = TRUE;
2N/A }
2N/A }
2N/A
2N/A if (!found_key) {
2N/A if ((retval = krb5_dbe_lookup_mkey_aux(context, &master_entry,
2N/A &mkey_aux_data_list)))
2N/A goto clean_n_exit;
2N/A
2N/A for (aux_data_entry = mkey_aux_data_list; aux_data_entry != NULL;
2N/A aux_data_entry = aux_data_entry->next) {
2N/A
2N/A if (krb5_dbekd_decrypt_key_data(context, mkey,
2N/A &aux_data_entry->latest_mkey,
2N/A &cur_mkey, NULL) == 0) {
2N/A found_key = TRUE;
2N/A break;
2N/A }
2N/A }
2N/A if (found_key != TRUE) {
2N/A krb5_set_error_message (context, KRB5_KDB_BADMASTERKEY,
2N/A "Unable to decrypt latest master key with the provided master key\n");
2N/A retval = KRB5_KDB_BADMASTERKEY;
2N/A goto clean_n_exit;
2N/A }
2N/A }
2N/A
2N/A /*
2N/A * Extract all the mkeys from master_entry using the most current mkey and
2N/A * create a mkey list for the mkeys field in kdc_realm_t.
2N/A */
2N/A
2N/A mkey_list_head = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
2N/A if (mkey_list_head == NULL) {
2N/A retval = ENOMEM;
2N/A goto clean_n_exit;
2N/A }
2N/A
2N/A memset(mkey_list_head, 0, sizeof(krb5_keylist_node));
2N/A
2N/A /* loop through any other master keys creating a list of krb5_keylist_nodes */
2N/A mkey_list_node = &mkey_list_head->next;
2N/A for (i = 1; i < master_entry.n_key_data; i++) {
2N/A if (*mkey_list_node == NULL) {
2N/A /* *mkey_list_node points to next field of previous node */
2N/A *mkey_list_node = (krb5_keylist_node *) malloc(sizeof(krb5_keylist_node));
2N/A if (*mkey_list_node == NULL) {
2N/A retval = ENOMEM;
2N/A goto clean_n_exit;
2N/A }
2N/A memset(*mkey_list_node, 0, sizeof(krb5_keylist_node));
2N/A }
2N/A key_data = &master_entry.key_data[i];
2N/A retval = krb5_dbekd_decrypt_key_data(context, &cur_mkey,
2N/A key_data,
2N/A &((*mkey_list_node)->keyblock),
2N/A NULL);
2N/A if (retval)
2N/A goto clean_n_exit;
2N/A
2N/A (*mkey_list_node)->kvno = key_data->key_data_kvno;
2N/A mkey_list_node = &((*mkey_list_node)->next);
2N/A }
2N/A
2N/A /*
2N/A * Solaris Kerberos: moved this part down because we cache derived keys in
2N/A * the cur_mkey block during the krb5_dbekd_decrypt_key_data() above so the
2N/A * latest version of cur_mkey should be copied to mkey_list_head->keyblock
2N/A * so it has those derived keys.
2N/A */
2N/A /* Set mkey_list_head to the current mkey as an optimization. */
2N/A /* mkvno may not be latest so ... */
2N/A mkey_list_head->kvno = master_entry.key_data[0].key_data_kvno;
2N/A /* this is the latest clear mkey (avoids a redundant decrypt) */
2N/A mkey_list_head->keyblock = cur_mkey;
2N/A
2N/A *mkeys_list = mkey_list_head;
2N/A
2N/Aclean_n_exit:
2N/A krb5_db_free_principal(context, &master_entry, nprinc);
2N/A krb5_dbe_free_mkey_aux_list(context, mkey_aux_data_list);
2N/A if (retval != 0) {
2N/A /*
2N/A * Solaris Kerberos: derived key caching changes. If retval != 0 then
2N/A * mkey_list_head->keyblock hasn't been set so just free mkey_list_head
2N/A * and maybe free cur_mkey separately.
2N/A */
2N/A if (mkey_list_head != NULL) {
2N/A krb5_dbe_free_key_list(context, mkey_list_head->next);
2N/A krb5_xfree(mkey_list_head);
2N/A }
2N/A if (found_key == TRUE)
2N/A krb5_free_keyblock_contents(context, &cur_mkey);
2N/A }
2N/A return retval;
2N/A}
2N/A
2N/Akrb5_error_code kdb_def_set_mkey ( krb5_context kcontext,
2N/A char *pwd,
2N/A krb5_keyblock *key )
2N/A{
2N/A /* printf("default set master key\n"); */
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code kdb_def_get_mkey ( krb5_context kcontext,
2N/A krb5_keyblock **key )
2N/A{
2N/A /* printf("default get master key\n"); */
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code kdb_def_set_mkey_list ( krb5_context kcontext,
2N/A krb5_keylist_node *keylist )
2N/A{
2N/A /* printf("default set master key\n"); */
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code kdb_def_get_mkey_list ( krb5_context kcontext,
2N/A krb5_keylist_node **keylist )
2N/A{
2N/A /* printf("default get master key\n"); */
2N/A return 0;
2N/A}
2N/A
2N/Akrb5_error_code krb5_def_promote_db (krb5_context kcontext,
2N/A char *s, char **args)
2N/A{
2N/A /* printf("default promote_db\n"); */
2N/A return KRB5_PLUGIN_OP_NOTSUPP;
2N/A}