|
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 |
}
|