dump.c revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
/*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
* Openvision retains the copyright to derivative works of
* this source code. Do *NOT* create a derivative of this
* source code before consulting with your legal department.
* Do *NOT* integrate *ANY* of this source code into another
* product before consulting with your legal department.
*
* For further information, read the top-level Openvision
* copyright which is contained in the top-level MIT Kerberos
* copyright.
*
* WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
*
*/
/*
* admin/edit/dump.c
*
* Copyright 1990,1991 by the Massachusetts Institute of Technology.
* All Rights Reserved.
*
* Export of this software from the United States of America may
* require a specific license from the United States Government.
* It is the responsibility of any person or organization contemplating
* export to obtain such a license before exporting.
*
* WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
* distribute this software and its documentation for any purpose and
* without fee is hereby granted, provided that the above copyright
* notice appear in all copies and that both that copyright notice and
* this permission notice appear in supporting documentation, and that
* the name of M.I.T. not be used in advertising or publicity pertaining
* to distribution of the software without specific, written prior
* permission. Furthermore if you modify this software you must label
* your software as modified software and not distribute it in such a
* fashion that it might be confused with the original M.I.T. software.
* M.I.T. makes no representations about the suitability of
* this software for any purpose. It is provided "as is" without express
* or implied warranty.
*
*
* Dump a KDC database
*/
#define KDB5_DISPATCH
#define KRB5_KDB5_DBM__
#include <k5-int.h>
/* #define these to avoid an indirection function; for future implementations,
these may be redirected from a dispatch table/routine */
/* SUNWresync121 - this appears to be an orig SEAM thang */
#define krb5_dbm_db_set_name krb5_db_set_name
#define krb5_dbm_db_set_nonblocking krb5_db_set_nonblocking
#define krb5_dbm_db_init krb5_db_init
#define krb5_dbm_db_get_age krb5_db_get_age
#define krb5_dbm_db_create krb5_db_create
#define krb5_dbm_db_rename krb5_db_rename
#define krb5_dbm_db_get_principal krb5_db_get_principal
#define krb5_dbm_db_free_principal krb5_db_free_principal
#define krb5_dbm_db_put_principal krb5_db_put_principal
#define krb5_dbm_db_delete_principal krb5_db_delete_principal
#define krb5_dbm_db_lock krb5_db_lock
#define krb5_dbm_db_unlock krb5_db_unlock
#define krb5_dbm_db_set_lockmode krb5_db_set_lockmode
#define krb5_dbm_db_close_database krb5_db_close_database
#define krb5_dbm_db_open_database krb5_db_open_database
#define krb5_dbm_db_iterate krb5_db_iterate
#include <stdio.h>
#include <com_err.h>
#include <kadm5/admin.h>
#include <kadm5/adb.h>
#include <libintl.h>
#include "kdb5_util.h"
#if HAVE_REGEX_H
#include <regex.h>
#endif /* HAVE_REGEX_H */
/*
* Needed for master key conversion.
*/
extern krb5_keyblock master_key;
extern krb5_principal master_princ;
extern int valid_master_key;
extern void usage();
static int mkey_convert;
static krb5_keyblock new_master_key;
/*
* Use compile(3) if no regcomp present.
*/
#if !defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
#define INIT char *sp = instring;
#define GETC() (*sp++)
#define PEEKC() (*sp)
#define UNGETC(c) (--sp)
#define RETURN(c) return(c)
#define ERROR(c)
#define RE_BUF_SIZE 1024
#include <regexp.h>
#endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */
struct dump_args {
char *programname;
FILE *ofile;
krb5_context kcontext;
char **names;
int nnames;
int verbose;
};
static krb5_error_code dump_k5beta_iterator
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static krb5_error_code dump_k5beta6_iterator
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static krb5_error_code dump_iprop_iterator
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static krb5_error_code dump_k5beta7_princ
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static krb5_error_code dump_iprop_princ
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static krb5_error_code dump_ov_princ
PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static void dump_k5beta7_policy PROTOTYPE((void *, osa_policy_ent_t));
typedef
krb5_error_code(*dump_func) PROTOTYPE((krb5_pointer,
krb5_db_entry *));
static int process_k5beta_record
PROTOTYPE((char *, krb5_context,
FILE *, int, int *, void *));
static int process_k5beta6_record
PROTOTYPE((char *, krb5_context,
FILE *, int, int *, void *));
static int process_k5beta7_record
PROTOTYPE((char *, krb5_context,
FILE *, int, int *, void *));
static int process_ov_record
PROTOTYPE((char *, krb5_context,
FILE *, int, int *, void *));
typedef
krb5_error_code(*load_func) PROTOTYPE((char *, krb5_context,
FILE *, int, int *, void *));
typedef struct _dump_version {
char *name;
char *header;
int updateonly;
int create_kadm5;
dump_func dump_princ;
osa_adb_iter_policy_func dump_policy;
load_func load_record;
} dump_version;
dump_version old_version = {
"Kerberos version 5 old format",
"kdb5_edit load_dump version 2.0\n",
0,
1,
dump_k5beta_iterator,
NULL,
process_k5beta_record,
};
dump_version beta6_version = {
"Kerberos version 5 beta 6 format",
"kdb5_edit load_dump version 3.0\n",
0,
1,
dump_k5beta6_iterator,
NULL,
process_k5beta6_record,
};
dump_version beta7_version = {
"Kerberos version 5",
"kdb5_util load_dump version 4\n",
0,
0,
dump_k5beta7_princ,
dump_k5beta7_policy,
process_k5beta7_record,
};
dump_version iprop_version = {
"Kerberos iprop version",
"iprop",
0,
0,
dump_iprop_princ,
dump_k5beta7_policy,
process_k5beta7_record,
};
dump_version ov_version = {
"OpenV*Secure V1.0",
"OpenV*Secure V1.0\t",
1,
1,
dump_ov_princ,
dump_k5beta7_policy,
process_ov_record,
};
/* External data */
extern char *current_dbname;
extern krb5_boolean dbactive;
extern int exit_status;
extern krb5_context util_context;
extern kadm5_config_params global_params;
/* Strings */
static const char k5beta_dump_header[] = "kdb5_edit load_dump version 2.0\n";
static const char k5beta6_dump_header[] = "kdb5_edit load_dump version 3.0\n";
static const char k5beta7_dump_header[] = "kdb5_edit load_dump version 4\n";
static const char null_mprinc_name[] = "kdb5_dump@MISSING";
/*
* We define gettext(s) to be s here, so that xgettext will extract the
* strings to the .po file. At the end of the message section we will
* undef gettext so that we can use it as a funtion.
*/
#define gettext(s) s
/* Message strings */
static const char regex_err[] =
gettext("%s: regular expression error - %s\n");
static const char regex_merr[] =
gettext("%s: regular expression match error - %s\n");
static const char pname_unp_err[] =
gettext("%s: cannot unparse principal name (%s)\n");
static const char mname_unp_err[] =
gettext("%s: cannot unparse modifier name (%s)\n");
static const char nokeys_err[] =
gettext("%s: cannot find any standard key for %s\n");
static const char sdump_tl_inc_err[] =
gettext("%s: tagged data list inconsistency for %s "
"(counted %d, stored %d)\n");
static const char stand_fmt_name[] =
gettext("Kerberos version 5");
static const char old_fmt_name[] =
gettext("Kerberos version 5 old format");
static const char b6_fmt_name[] =
gettext("Kerberos version 5 beta 6 format");
static const char ofopen_error[] =
gettext("%s: cannot open %s for writing (%s)\n");
static const char oflock_error[] =
gettext("%s: cannot lock %s (%s)\n");
static const char dumprec_err[] =
gettext("%s: error performing %s dump (%s)\n");
static const char dumphdr_err[] =
gettext("%s: error dumping %s header (%s)\n");
static const char trash_end_fmt[] =
gettext("%s(%d): ignoring trash at end of line: ");
static const char read_name_string[] =
gettext("name string");
static const char read_key_type[] =
gettext("key type");
static const char read_key_data[] =
gettext("key data");
static const char read_pr_data1[] =
gettext("first set of principal attributes");
static const char read_mod_name[] =
gettext("modifier name");
static const char read_pr_data2[] =
gettext("second set of principal attributes");
static const char read_salt_data[] =
gettext("salt data");
static const char read_akey_type[] =
gettext("alternate key type");
static const char read_akey_data[] =
gettext("alternate key data");
static const char read_asalt_type[] =
gettext("alternate salt type");
static const char read_asalt_data[] =
gettext("alternate salt data");
static const char read_exp_data[] =
gettext("expansion data");
static const char store_err_fmt[] =
gettext("%s(%d): cannot store %s(%s)\n");
static const char add_princ_fmt[] =
gettext("%s\n");
static const char parse_err_fmt[] =
gettext("%s(%d): cannot parse %s (%s)\n");
static const char read_err_fmt[] =
gettext("%s(%d): cannot read %s\n");
static const char no_mem_fmt[] =
gettext("%s(%d): no memory for buffers\n");
static const char rhead_err_fmt[] =
gettext("%s(%d): cannot match size tokens\n");
static const char err_line_fmt[] =
gettext("%s: error processing line %d of %s\n");
static const char head_bad_fmt[] =
gettext("%s: dump header bad in %s\n");
static const char read_bytecnt[] =
gettext("record byte count");
static const char read_encdata[] =
gettext("encoded data");
static const char n_name_unp_fmt[] =
gettext("%s(%s): cannot unparse name\n");
static const char n_dec_cont_fmt[] =
gettext("%s(%s): cannot decode contents\n");
static const char read_nint_data[] =
gettext("principal static attributes");
static const char read_tcontents[] =
gettext("tagged data contents");
static const char read_ttypelen[] =
gettext("tagged data type and length");
static const char read_kcontents[] =
gettext("key data contents");
static const char read_ktypelen[] =
gettext("key data type and length");
static const char read_econtents[] =
gettext("extra data contents");
static const char k5beta_fmt_name[] =
gettext("Kerberos version 5 old format");
static const char standard_fmt_name[] =
gettext("Kerberos version 5 format");
static const char no_name_mem_fmt[] =
gettext("%s: cannot get memory for temporary name\n");
static const char ctx_err_fmt[] =
gettext("%s: cannot initialize Kerberos context\n");
static const char stdin_name[] =
gettext("standard input");
static const char remaster_err_fmt[] =
gettext("while re-encoding keys for principal %s with new master key");
static const char restfail_fmt[] =
gettext("%s: %s restore failed\n");
static const char close_err_fmt[] =
gettext("%s: cannot close database (%s)\n");
static const char dbinit_err_fmt[] =
gettext("%s: cannot initialize database (%s)\n");
static const char dblock_err_fmt[] =
gettext("%s: cannot initialize database lock (%s)\n");
static const char dbname_err_fmt[] =
gettext("%s: cannot set database name to %s (%s)\n");
static const char dbdelerr_fmt[] =
gettext("%s: cannot delete bad database %s (%s)\n");
static const char dbunlockerr_fmt[] =
gettext("%s: cannot unlock database %s (%s)\n");
static const char dbrenerr_fmt[] =
gettext("%s: cannot rename database %s to %s (%s)\n");
static const char dbcreaterr_fmt[] =
gettext("%s: cannot create database %s (%s)\n");
static const char dfile_err_fmt[] =
gettext("%s: cannot open %s (%s)\n");
/*
* We now return you to your regularly scheduled program.
*/
#undef gettext
static const char oldoption[] = "-old";
static const char b6option[] = "-b6";
static const char ipropoption[] = "-i";
static const char verboseoption[] = "-verbose";
static const char updateoption[] = "-update";
static const char hashoption[] = "-hash";
static const char ovoption[] = "-ov";
static const char dump_tmptrail[] = "~";
/*
* Re-encrypt the key_data with the new master key...
*/
krb5_error_code master_key_convert(context, db_entry)
krb5_context context;
krb5_db_entry * db_entry;
{
krb5_error_code retval;
krb5_keyblock v5plainkey, *key_ptr;
krb5_keysalt keysalt;
int i;
krb5_key_data new_key_data, *key_data;
krb5_boolean is_mkey;
is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ);
if (is_mkey && db_entry->n_key_data != 1)
fprintf(stderr,
gettext(
"Master key db entry has %d keys, expecting only 1!\n"),
db_entry->n_key_data);
for (i=0; i < db_entry->n_key_data; i++) {
key_data = &db_entry->key_data[i];
if (key_data->key_data_length == 0)
continue;
retval = krb5_dbekd_decrypt_key_data(context, &master_key,
key_data, &v5plainkey,
&keysalt);
if (retval)
return retval;
memset(&new_key_data, 0, sizeof(new_key_data));
key_ptr = is_mkey ? &new_master_key : &v5plainkey;
retval = krb5_dbekd_encrypt_key_data(context, &new_master_key,
key_ptr, &keysalt,
key_data->key_data_kvno,
&new_key_data);
if (retval)
return retval;
krb5_free_keyblock_contents(context, &v5plainkey);
free(key_data->key_data_contents);
*key_data = new_key_data;
}
return 0;
}
/*
* Update the "ok" file.
*/
void
update_ok_file(file_name)
char *file_name;
{
/* handle slave locking/failure stuff */
char *file_ok;
int fd;
static char ok[]=".dump_ok";
if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1))
== NULL) {
com_err(progname, ENOMEM,
gettext("while allocating filename "
"for update_ok_file"));
exit_status++;
return;
}
strcpy(file_ok, file_name);
strcat(file_ok, ok);
if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
com_err(progname, errno,
gettext("while creating 'ok' file, '%s'"),
file_ok);
exit_status++;
free(file_ok);
return;
}
if (write(fd, "", 1) != 1) {
com_err(progname, errno,
gettext("while writing to 'ok' file, '%s'"),
file_ok);
exit_status++;
free(file_ok);
return;
}
free(file_ok);
close(fd);
}
/*
* name_matches() - See if a principal name matches a regular expression
* or string.
*/
static int
name_matches(name, arglist)
char *name;
struct dump_args *arglist;
{
#if HAVE_REGCOMP
regex_t match_exp;
regmatch_t match_match;
int match_error;
char match_errmsg[BUFSIZ];
size_t errmsg_size;
#elif HAVE_REGEXP_H
char regexp_buffer[RE_BUF_SIZE];
#elif HAVE_RE_COMP
extern char *re_comp();
char *re_result;
#endif /* HAVE_RE_COMP */
int i, match;
/*
* Plow, brute force, through the list of names/regular
* expressions.
*/
match = (arglist->nnames) ? 0 : 1;
for (i=0; i<arglist->nnames; i++) {
#if HAVE_REGCOMP
/*
* Compile the regular expression.
*/
if (match_error = regcomp(&match_exp,
arglist->names[i],
REG_EXTENDED)) {
errmsg_size = regerror(match_error,
&match_exp,
match_errmsg,
sizeof(match_errmsg));
fprintf(stderr, gettext(regex_err),
arglist->programname, match_errmsg);
break;
}
/*
* See if we have a match.
*/
if (match_error = regexec(&match_exp,
name, 1, &match_match, 0)) {
if (match_error != REG_NOMATCH) {
errmsg_size = regerror(match_error,
&match_exp,
match_errmsg,
sizeof(match_errmsg));
fprintf(stderr, gettext(regex_merr),
arglist->programname, match_errmsg);
break;
}
} else {
/*
* We have a match. See if it matches the whole
* name.
*/
if ((match_match.rm_so == 0) &&
(match_match.rm_eo == strlen(name)))
match = 1;
}
regfree(&match_exp);
#elif HAVE_REGEXP_H
/*
* Compile the regular expression.
*/
compile(arglist->names[i],
regexp_buffer,
&regexp_buffer[RE_BUF_SIZE],
'\0');
if (step(name, regexp_buffer)) {
if ((loc1 == name) &&
(loc2 == &name[strlen(name)]))
match = 1;
}
#elif HAVE_RE_COMP
/*
* Compile the regular expression.
*/
if (re_result = re_comp(arglist->names[i])) {
fprintf(stderr, gettext(regex_err),
arglist->programname, re_result);
break;
}
if (re_exec(name))
match = 1;
#else /* HAVE_RE_COMP */
/*
* If no regular expression support, then just compare the
* strings.
*/
if (strcmp(arglist->names[i], name) == 0)
match = 1;
#endif /* HAVE_REGCOMP */
if (match)
break;
}
return(match);
}
static krb5_error_code
find_enctype(dbentp, enctype, salttype, kentp)
krb5_db_entry *dbentp;
krb5_enctype enctype;
krb5_int32 salttype;
krb5_key_data **kentp;
{
int i;
int maxkvno;
krb5_key_data *datap;
maxkvno = -1;
datap = (krb5_key_data *) NULL;
for (i=0; i<dbentp->n_key_data; i++) {
if (( (krb5_enctype)dbentp->key_data[i].key_data_type[0] == enctype) &&
((dbentp->key_data[i].key_data_type[1] == salttype) ||
(salttype < 0))) {
maxkvno = dbentp->key_data[i].key_data_kvno;
datap = &dbentp->key_data[i];
}
}
if (maxkvno >= 0) {
*kentp = datap;
return(0);
}
return(ENOENT);
}
/*
* dump_k5beta_header() - Make a dump header that is recognizable by Kerberos
* Version 5 Beta 5 and previous releases.
*/
static krb5_error_code
dump_k5beta_header(arglist)
struct dump_args *arglist;
{
/* The old header consists of the leading string */
fprintf(arglist->ofile, k5beta_dump_header);
return(0);
}
/*
* dump_k5beta_iterator() - Dump an entry in a format that is usable
* by Kerberos Version 5 Beta 5 and previous
* releases.
*/
static krb5_error_code
dump_k5beta_iterator(ptr, entry)
krb5_pointer ptr;
krb5_db_entry *entry;
{
krb5_error_code retval;
struct dump_args *arg;
char *name, *mod_name;
krb5_principal mod_princ;
krb5_key_data *pkey, *akey, nullkey;
krb5_timestamp mod_date, last_pwd_change;
int i;
/* Initialize */
arg = (struct dump_args *) ptr;
name = (char *) NULL;
mod_name = (char *) NULL;
memset(&nullkey, 0, sizeof(nullkey));
/*
* Flatten the principal name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
entry->princ,
&name))) {
fprintf(stderr, gettext(pname_unp_err),
arg->programname, error_message(retval));
return(retval);
}
/*
* Re-encode the keys in the new master key, if necessary.
*/
if (mkey_convert) {
retval = master_key_convert(arg->kcontext, entry);
if (retval) {
com_err(arg->programname, retval, remaster_err_fmt, name);
return retval;
}
}
/*
* If we don't have any match strings, or if our name matches, then
* proceed with the dump, otherwise, just forget about it.
*/
if (!arg->nnames || name_matches(name, arg)) {
/*
* Deserialize the modifier record.
*/
mod_name = (char *) NULL;
mod_princ = NULL;
last_pwd_change = mod_date = 0;
pkey = akey = (krb5_key_data *) NULL;
if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext,
entry,
&mod_date,
&mod_princ))) {
if (mod_princ) {
/*
* Flatten the modifier name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
mod_princ,
&mod_name)))
fprintf(stderr, gettext(mname_unp_err),
arg->programname,
error_message(retval));
krb5_free_principal(arg->kcontext, mod_princ);
}
}
if (!mod_name)
mod_name = strdup(null_mprinc_name);
/*
* Find the last password change record and set it
* straight.
*/
if ((retval =
krb5_dbe_lookup_last_pwd_change(arg->kcontext, entry,
&last_pwd_change))) {
fprintf(stderr, gettext(nokeys_err),
arg->programname, name);
krb5_xfree(mod_name);
krb5_xfree(name);
return(retval);
}
/*
* Find the 'primary' key and the 'alternate' key.
*/
if ((retval = find_enctype(entry,
ENCTYPE_DES_CBC_CRC,
KRB5_KDB_SALTTYPE_NORMAL,
&pkey)) &&
(retval = find_enctype(entry,
ENCTYPE_DES_CBC_CRC,
KRB5_KDB_SALTTYPE_V4,
&akey))) {
fprintf(stderr, gettext(nokeys_err),
arg->programname, name);
krb5_xfree(mod_name);
krb5_xfree(name);
return(retval);
}
/*
* If we only have one type, then ship it out as the
* primary.
*/
if (!pkey && akey) {
pkey = akey;
akey = &nullkey;
} else {
if (!akey)
akey = &nullkey;
}
/*
* First put out strings representing the length of the
* variable length data in this record, then the name and
* the primary key type.
*/
fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t",
strlen(name),
strlen(mod_name),
(krb5_int32) pkey->key_data_length[0],
(krb5_int32) akey->key_data_length[0],
(krb5_int32) pkey->key_data_length[1],
(krb5_int32) akey->key_data_length[1],
name,
(krb5_int32) pkey->key_data_type[0]);
for (i=0; i<pkey->key_data_length[0]; i++) {
fprintf(arg->ofile, "%02x",
pkey->key_data_contents[0][i]);
}
/*
* Second, print out strings representing the standard
* integer data in this record.
*/
fprintf(arg->ofile,
"\t%u\t%u\t%u\t%u\t%u\t%u\t%u"
"\t%u\t%u\t%u\t%s\t%u\t%u\t%u\t",
(krb5_int32) pkey->key_data_kvno,
entry->max_life, entry->max_renewable_life,
1 /* Fake mkvno */, entry->expiration,
entry->pw_expiration, last_pwd_change,
entry->last_success, entry->last_failed,
entry->fail_auth_count, mod_name, mod_date,
entry->attributes, pkey->key_data_type[1]);
/* Pound out the salt data, if present. */
for (i=0; i<pkey->key_data_length[1]; i++) {
fprintf(arg->ofile, "%02x",
pkey->key_data_contents[1][i]);
}
/* Pound out the alternate key type and contents */
fprintf(arg->ofile, "\t%u\t", akey->key_data_type[0]);
for (i=0; i<akey->key_data_length[0]; i++) {
fprintf(arg->ofile, "%02x",
akey->key_data_contents[0][i]);
}
/* Pound out the alternate salt type and contents */
fprintf(arg->ofile, "\t%u\t", akey->key_data_type[1]);
for (i=0; i<akey->key_data_length[1]; i++) {
fprintf(arg->ofile, "%02x",
akey->key_data_contents[1][i]);
}
/* Pound out the expansion data. (is null) */
for (i=0; i < 8; i++) {
fprintf(arg->ofile, "\t%u", 0);
}
fprintf(arg->ofile, ";\n");
/* If we're blabbing, do it */
if (arg->verbose)
fprintf(stderr, "%s\n", name);
krb5_xfree(mod_name);
}
krb5_xfree(name);
return(0);
}
/*
* dump_k5beta6_iterator() - Output a dump record in krb5b6 format.
*/
static krb5_error_code
dump_k5beta6_iterator(ptr, entry)
krb5_pointer ptr;
krb5_db_entry *entry;
{
krb5_error_code retval;
struct dump_args *arg;
char *name;
krb5_tl_data *tlp;
krb5_key_data *kdata;
int counter, skip, i, j;
/* Initialize */
arg = (struct dump_args *) ptr;
name = (char *) NULL;
/*
* Flatten the principal name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
entry->princ,
&name))) {
fprintf(stderr, gettext(pname_unp_err),
arg->programname, error_message(retval));
return(retval);
}
/*
* Re-encode the keys in the new master key, if necessary.
*/
if (mkey_convert) {
retval = master_key_convert(arg->kcontext, entry);
if (retval) {
com_err(arg->programname, retval, remaster_err_fmt, name);
return retval;
}
}
/*
* If we don't have any match strings, or if our name matches, then
* proceed with the dump, otherwise, just forget about it.
*/
if (!arg->nnames || name_matches(name, arg)) {
/*
* We'd like to just blast out the contents as they would
* appear in the database so that we can just suck it back
* in, but it doesn't lend itself to easy editing.
*/
/*
* The dump format is as follows: len strlen(name)
* n_tl_data n_key_data e_length name attributes max_life
* max_renewable_life expiration pw_expiration last_success
* last_failed fail_auth_count n_tl_data*[type length
* <contents>] n_key_data*[ver kvno ver*(type length
* <contents>)] <e_data> Fields which are not encapsulated
* by angle-brackets are to appear verbatim. Bracketed
* fields absence is indicated by a -1 in its place
*/
/*
* Make sure that the tagged list is reasonably correct.
*/
counter = skip = 0;
for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
/*
* don't dump tl data types we know aren't
* understood by earlier revisions [krb5-admin/89]
*/
switch (tlp->tl_data_type) {
case KRB5_TL_KADM_DATA:
skip++;
break;
default:
counter++;
break;
}
}
if (counter + skip == entry->n_tl_data) {
/* Pound out header */
fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
(int) entry->len,
strlen(name),
counter,
(int) entry->n_key_data,
(int) entry->e_length,
name);
fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
entry->attributes,
entry->max_life,
entry->max_renewable_life,
entry->expiration,
entry->pw_expiration,
entry->last_success,
entry->last_failed,
entry->fail_auth_count);
/* Pound out tagged data. */
for (tlp = entry->tl_data; tlp;
tlp = tlp->tl_data_next) {
if (tlp->tl_data_type == KRB5_TL_KADM_DATA)
/* see above, [krb5-admin/89] */
continue;
fprintf(arg->ofile, "%d\t%d\t",
(int) tlp->tl_data_type,
(int) tlp->tl_data_length);
if (tlp->tl_data_length)
for (i = 0;
i < tlp->tl_data_length;
i++)
fprintf(arg->ofile, "%02x",
tlp->
tl_data_contents[i]);
else
fprintf(arg->ofile, "%d", -1);
fprintf(arg->ofile, "\t");
}
/* Pound out key data */
for (counter = 0;
counter < entry->n_key_data; counter++) {
kdata = &entry->key_data[counter];
fprintf(arg->ofile, "%d\t%d\t",
(int) kdata->key_data_ver,
(int) kdata->key_data_kvno);
for (i=0; i<kdata->key_data_ver; i++) {
fprintf(arg->ofile, "%d\t%d\t",
kdata->key_data_type[i],
kdata->key_data_length[i]);
if (kdata->key_data_length[i])
for (j = 0;
j < kdata->
key_data_length[i];
j++)
fprintf(arg->ofile,
"%02x",
kdata->
key_data_contents
[i][j]);
else
fprintf(arg->ofile, "%d", -1);
fprintf(arg->ofile, "\t");
}
}
/* Pound out extra data */
if (entry->e_length)
for (i=0; i<entry->e_length; i++)
fprintf(arg->ofile, "%02x",
entry->e_data[i]);
else
fprintf(arg->ofile, "%d", -1);
/* Print trailer */
fprintf(arg->ofile, ";\n");
if (arg->verbose)
fprintf(stderr, "%s\n", name);
} else {
fprintf(stderr, gettext(sdump_tl_inc_err),
arg->programname, name, counter + skip,
(int) entry->n_tl_data);
retval = EINVAL;
}
}
krb5_xfree(name);
return(retval);
}
/*
* dump_iprop_iterator() - Output a dump record in iprop format.
*/
static krb5_error_code
dump_iprop_iterator(ptr, entry)
krb5_pointer ptr;
krb5_db_entry *entry;
{
krb5_error_code retval;
struct dump_args *arg;
char *name;
krb5_tl_data *tlp;
krb5_key_data *kdata;
int counter, i, j;
/* Initialize */
arg = (struct dump_args *) ptr;
name = (char *) NULL;
/*
* Flatten the principal name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
entry->princ,
&name))) {
fprintf(stderr, gettext(pname_unp_err),
arg->programname, error_message(retval));
return(retval);
}
/*
* Re-encode the keys in the new master key, if necessary.
*/
if (mkey_convert) {
retval = master_key_convert(arg->kcontext, entry);
if (retval) {
com_err(arg->programname, retval, remaster_err_fmt, name);
return retval;
}
}
/*
* If we don't have any match strings, or if our name matches, then
* proceed with the dump, otherwise, just forget about it.
*/
if (!arg->nnames || name_matches(name, arg)) {
/*
* We'd like to just blast out the contents as they would
* appear in the database so that we can just suck it back
* in, but it doesn't lend itself to easy editing.
*/
/*
* The dump format is as follows: len strlen(name)
* n_tl_data n_key_data e_length name attributes max_life
* max_renewable_life expiration pw_expiration last_success
* last_failed fail_auth_count n_tl_data*[type length
* <contents>] n_key_data*[ver kvno ver*(type length
* <contents>)] <e_data> Fields which are not encapsulated
* by angle-brackets are to appear verbatim. Bracketed
* fields absence is indicated by a -1 in its place
*/
/*
* Make sure that the tagged list is reasonably correct.
*/
counter = 0;
for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next)
counter++;
if (counter == entry->n_tl_data) {
/* Pound out header */
fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
(int) entry->len,
strlen(name),
(int) entry->n_tl_data,
(int) entry->n_key_data,
(int) entry->e_length,
name);
fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
entry->attributes,
entry->max_life,
entry->max_renewable_life,
entry->expiration,
entry->pw_expiration,
entry->last_success,
entry->last_failed,
entry->fail_auth_count);
/* Pound out tagged data. */
for (tlp = entry->tl_data; tlp;
tlp = tlp->tl_data_next) {
fprintf(arg->ofile, "%d\t%d\t",
(int) tlp->tl_data_type,
(int) tlp->tl_data_length);
if (tlp->tl_data_length)
for (i = 0;
i < tlp->tl_data_length;
i++)
fprintf(arg->ofile, "%02x",
tlp->
tl_data_contents[i]);
else
fprintf(arg->ofile, "%d", -1);
fprintf(arg->ofile, "\t");
}
/* Pound out key data */
for (counter = 0;
counter < entry->n_key_data; counter++) {
kdata = &entry->key_data[counter];
fprintf(arg->ofile, "%d\t%d\t",
(int) kdata->key_data_ver,
(int) kdata->key_data_kvno);
for (i=0; i<kdata->key_data_ver; i++) {
fprintf(arg->ofile, "%d\t%d\t",
kdata->key_data_type[i],
kdata->key_data_length[i]);
if (kdata->key_data_length[i])
for (j = 0;
j < kdata->
key_data_length[i];
j++)
fprintf(arg->ofile,
"%02x",
kdata->
key_data_contents
[i][j]);
else
fprintf(arg->ofile, "%d", -1);
fprintf(arg->ofile, "\t");
}
}
/* Pound out extra data */
if (entry->e_length)
for (i=0; i<entry->e_length; i++)
fprintf(arg->ofile, "%02x",
entry->e_data[i]);
else
fprintf(arg->ofile, "%d", -1);
/* Print trailer */
fprintf(arg->ofile, ";\n");
if (arg->verbose)
fprintf(stderr, "%s\n", name);
} else {
fprintf(stderr, gettext(sdump_tl_inc_err),
arg->programname, name, counter,
(int) entry->n_tl_data);
retval = EINVAL;
}
}
krb5_xfree(name);
return(retval);
}
/*
* dump_k5beta7_iterator() - Output a dump record in krb5b7 format.
*/
static krb5_error_code
dump_k5beta7_princ(ptr, entry)
krb5_pointer ptr;
krb5_db_entry *entry;
{
krb5_error_code retval;
struct dump_args *arg;
char *name;
int tmp_nnames;
/* Initialize */
arg = (struct dump_args *) ptr;
name = (char *) NULL;
/*
* Flatten the principal name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
entry->princ,
&name))) {
fprintf(stderr, gettext(pname_unp_err),
arg->programname, error_message(retval));
return(retval);
}
/*
* If we don't have any match strings, or if our name matches, then
* proceed with the dump, otherwise, just forget about it.
*/
if (!arg->nnames || name_matches(name, arg)) {
fprintf(arg->ofile, "princ\t");
/* save the callee from matching the name again */
tmp_nnames = arg->nnames;
arg->nnames = 0;
retval = dump_k5beta6_iterator(ptr, entry);
arg->nnames = tmp_nnames;
}
free(name);
return (retval);
}
/*
* dump_iprop_princ() - Output a dump record in iprop format.
* This was created in order to dump more data, such as kadm5 tl
*/
static krb5_error_code
dump_iprop_princ(ptr, entry)
krb5_pointer ptr;
krb5_db_entry *entry;
{
krb5_error_code retval;
struct dump_args *arg;
char *name;
int tmp_nnames;
/* Initialize */
arg = (struct dump_args *) ptr;
name = (char *) NULL;
/*
* Flatten the principal name.
*/
if ((retval = krb5_unparse_name(arg->kcontext,
entry->princ,
&name))) {
fprintf(stderr, gettext(pname_unp_err),
arg->programname, error_message(retval));
return(retval);
}
/*
* If we don't have any match strings, or if our name matches, then
* proceed with the dump, otherwise, just forget about it.
*/
if (!arg->nnames || name_matches(name, arg)) {
fprintf(arg->ofile, "princ\t");
/* save the callee from matching the name again */
tmp_nnames = arg->nnames;
arg->nnames = 0;
retval = dump_iprop_iterator(ptr, entry);
arg->nnames = tmp_nnames;
}
free(name);
return (retval);
}
void
dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
{
struct dump_args *arg;
arg = (struct dump_args *) data;
fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
entry->pw_min_classes, entry->pw_history_num,
entry->policy_refcnt);
}
void
print_key_data(FILE * f, krb5_key_data * key_data)
{
int c;
fprintf(f, "%d\t%d\t", key_data->key_data_type[0],
key_data->key_data_length[0]);
for(c = 0; c < key_data->key_data_length[0]; c++)
fprintf(f, "%02x ",
key_data->key_data_contents[0][c]);
}
/*
* Function: print_princ
*
* Purpose: output osa_adb_princ_ent data in a human
* readable format (which is a format suitable for
* ovsec_adm_import consumption)
*
* Arguments:
* data (input) pointer to a structure containing a FILE *
* and a record counter.
* entry (input) entry to get dumped.
* <return value> void
*
* Requires:
* nuttin
*
* Effects:
* writes data to the specified file pointerp.
*
* Modifies:
* nuttin
*
*/
static krb5_error_code
dump_ov_princ(krb5_pointer ptr, krb5_db_entry * kdb)
{
char *princstr;
int x, y, foundcrc, ret;
struct dump_args *arg;
krb5_tl_data tl_data;
osa_princ_ent_rec adb;
XDR xdrs;
arg = (struct dump_args *) ptr;
/*
* XXX Currently, lookup_tl_data always returns zero; it sets
* tl_data->tl_data_length to zero if the type isn't found. This
* should be fixed...
*/
/*
* XXX Should this function do nothing for a principal with no
* admin data, or print a record of "default" values? See comment
* in server_kdb.c to help decide.
*/
tl_data.tl_data_type = KRB5_TL_KADM_DATA;
if ((ret = krb5_dbe_lookup_tl_data(arg->kcontext, kdb, &tl_data)) ||
(tl_data.tl_data_length == 0))
return (0);
memset(&adb, 0, sizeof(adb));
xdrmem_create(&xdrs, (const caddr_t) tl_data.tl_data_contents,
tl_data.tl_data_length, XDR_DECODE);
if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) {
xdr_destroy(&xdrs);
return(OSA_ADB_XDR_FAILURE);
}
xdr_destroy(&xdrs);
krb5_unparse_name(arg->kcontext, kdb->princ, &princstr);
fprintf(arg->ofile, "princ\t%s\t", princstr);
if(adb.policy == NULL)
fputc('\t', arg->ofile);
else
fprintf(arg->ofile, "%s\t", adb.policy);
fprintf(arg->ofile, "%x\t%d\t%d\t%d", adb.aux_attributes,
adb.old_key_len,adb.old_key_next, adb.admin_history_kvno);
for (x = 0; x < adb.old_key_len; x++) {
foundcrc = 0;
for (y = 0; y < adb.old_keys[x].n_key_data; y++) {
krb5_key_data *key_data = &adb.old_keys[x].key_data[y];
if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC)
continue;
if (foundcrc) {
fprintf(stderr,
gettext("Warning! Multiple DES-CBC-CRC "
"keys for principal %s; skipping "
"duplicates.\n"),
princstr);
continue;
}
foundcrc++;
fputc('\t', arg->ofile);
print_key_data(arg->ofile, key_data);
}
if (!foundcrc)
fprintf(stderr,
gettext("Warning! No DES-CBC-CRC key "
"for principal %s, cannot generate "
"OV-compatible record; skipping\n"),
princstr);
}
fputc('\n', arg->ofile);
free(princstr);
return (0);
}
/*
* usage is:
* dump_db [-i] [-old] [-b6] [-ov] [-verbose] [filename [principals...]]
*/
void
dump_db(argc, argv)
int argc;
char **argv;
{
FILE *f;
struct dump_args arglist;
int error;
char *programname;
char *ofile;
krb5_error_code kret, retval;
dump_version *dump;
int aindex;
krb5_boolean locked;
extern osa_adb_policy_t policy_db;
char *new_mkey_file = 0;
bool_t dump_sno = FALSE;
kdb_log_context *log_ctx;
/*
* Parse the arguments.
*/
programname = argv[0];
if (strrchr(programname, (int) '/'))
programname = strrchr(argv[0], (int) '/') + 1;
ofile = (char *) NULL;
error = 0;
dump = &beta7_version;
arglist.verbose = 0;
new_mkey_file = 0;
mkey_convert = 0;
log_ctx = util_context->kdblog_context;
/*
* Parse the qualifiers.
*/
for (aindex = 1; aindex < argc; aindex++) {
if (strcmp(argv[aindex], oldoption) == 0)
dump = &old_version;
else if (strcmp(argv[aindex], b6option) == 0)
dump = &beta6_version;
else if (strcmp(argv[aindex], ovoption) == 0)
dump = &ov_version;
else if (!strcmp(argv[aindex], ipropoption)) {
if (log_ctx && log_ctx->iproprole) {
dump = &iprop_version;
/*
* dump_sno is used to indicate if the serial
* # should be populated in the output
* file to be used later by iprop for updating
* the slave's update log when loading
*/
dump_sno = TRUE;
} else {
fprintf(stderr, gettext("Iprop not enabled\n"));
exit_status++;
return;
}
}
else if (strcmp(argv[aindex], verboseoption) == 0)
arglist.verbose++;
else if (!strcmp(argv[aindex], "-mkey_convert"))
mkey_convert = 1;
else if (!strcmp(argv[aindex], "-new_mkey_file")) {
new_mkey_file = argv[++aindex];
mkey_convert = 1;
} else
break;
}
arglist.names = (char **) NULL;
arglist.nnames = 0;
if (aindex < argc) {
ofile = argv[aindex];
aindex++;
if (aindex < argc) {
arglist.names = &argv[aindex];
arglist.nnames = argc - aindex;
}
}
/*
* Make sure the database is open. The policy database only has
* to be opened if we try a dump that uses it.
*/
if (!dbactive || (dump->dump_policy != NULL && policy_db == NULL)) {
com_err(argv[0], 0, Err_no_database);
exit_status++;
return;
}
/*
* If we're doing a master key conversion, set up for it.
*/
if (mkey_convert) {
if (!valid_master_key) {
/* TRUE here means read the keyboard, but only once */
retval = krb5_db_fetch_mkey(util_context,
master_princ,
global_params.enctype,
TRUE, FALSE,
(char *) NULL, 0,
&master_key);
if (retval) {
com_err(argv[0], retval,
gettext("while reading master key"));
exit(1);
}
retval = krb5_db_verify_master_key(util_context,
master_princ,
&master_key);
if (retval) {
com_err(argv[0], retval,
gettext("while verifying master key"));
exit(1);
}
}
if (!new_mkey_file)
printf(gettext("Please enter new master key....\n"));
if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
global_params.enctype,
!new_mkey_file, TRUE,
new_mkey_file, 0,
&new_master_key))) {
com_err(argv[0], retval,
gettext("while reading new master key"));
exit(1);
}
}
kret = 0;
locked = 0;
if (ofile && strcmp(ofile, "-")) {
/*
* Make sure that we don't open and truncate on the fopen,
* since that may hose an on-going kprop process.
*
* We could also control this by opening for read and write,
* doing an flock with LOCK_EX, and then truncating the
* file once we have gotten the lock, but that would
* involve more OS dependencies than I want to get into.
*/
unlink(ofile);
if (!(f = fopen(ofile, "w"))) {
fprintf(stderr, gettext(ofopen_error),
programname, ofile, error_message(errno));
exit_status++;
return;
}
if ((kret = krb5_lock_file(util_context,
fileno(f),
KRB5_LOCKMODE_EXCLUSIVE))) {
fprintf(stderr, gettext(oflock_error),
programname, ofile, error_message(kret));
exit_status++;
} else
locked = 1;
} else {
f = stdout;
}
if (f && !(kret)) {
arglist.programname = programname;
arglist.ofile = f;
arglist.kcontext = util_context;
fprintf(arglist.ofile, "%s", dump->header);
if (dump_sno) {
if (ulog_map(util_context, &global_params, FKCOMMAND)) {
fprintf(stderr,
gettext("%s: Could not map log\n"), programname);
exit_status++;
goto error;
}
/*
* We grab the lock twice (once again in the iterator call),
* but that's ok since the lock func handles incr locks held.
*/
if (krb5_db_lock(util_context, KRB5_LOCKMODE_SHARED)) {
fprintf(stderr,
gettext("%s: Couldn't grab lock\n"), programname);
exit_status++;
goto error;
}
fprintf(f, " %u", log_ctx->ulog->kdb_last_sno);
fprintf(f, " %u", log_ctx->ulog->kdb_last_time.seconds);
fprintf(f, " %u", log_ctx->ulog->kdb_last_time.useconds);
}
if (dump->header[strlen(dump->header)-1] != '\n')
fputc('\n', arglist.ofile);
if ((kret = krb5_dbm_db_iterate(util_context,
dump->dump_princ,
(krb5_pointer) &arglist))) {
fprintf(stderr, gettext(dumprec_err),
programname, dump->name, error_message(kret));
exit_status++;
if (dump_sno)
(void) krb5_db_unlock(util_context);
}
if (dump->dump_policy &&
(kret = osa_adb_iter_policy(policy_db, dump->dump_policy,
&arglist))) {
fprintf(stderr, gettext(dumprec_err),
programname, dump->name,
error_message(kret));
exit_status++;
}
error:
if (ofile && f != stdout && !exit_status) {
fclose(f);
update_ok_file(ofile);
}
}
if (locked)
(void) krb5_lock_file(util_context,
fileno(f), KRB5_LOCKMODE_UNLOCK);
}
/*
* Read a string of bytes while counting the number of lines passed.
*/
static int
read_string(f, buf, len, lp)
FILE *f;
char *buf;
int len;
int *lp;
{
int c;
int i, retval;
retval = 0;
for (i=0; i<len; i++) {
c = fgetc(f);
if (c < 0) {
retval = 1;
break;
}
if (c == '\n')
(*lp)++;
buf[i] = (char) c;
}
buf[len] = '\0';
return(retval);
}
/*
* Read a string of two character representations of bytes.
*/
static int
read_octet_string(f, buf, len)
FILE *f;
krb5_octet *buf;
int len;
{
int c;
int i, retval;
retval = 0;
for (i=0; i<len; i++) {
if (fscanf(f, "%02x", &c) != 1) {
retval = 1;
break;
}
buf[i] = (krb5_octet) c;
}
return(retval);
}
/*
* Find the end of an old format record.
*/
static void
find_record_end(f, fn, lineno)
FILE *f;
char *fn;
int lineno;
{
int ch;
if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
fprintf(stderr, gettext(trash_end_fmt), fn, lineno);
while (ch != '\n') {
putc(ch, stderr);
ch = fgetc(f);
}
putc(ch, stderr);
}
}
#if 0
/*
* update_tl_data() - Generate the tl_data entries.
*/
static krb5_error_code
update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
krb5_context kcontext;
krb5_db_entry *dbentp;
krb5_principal mod_name;
krb5_timestamp mod_date;
krb5_timestamp last_pwd_change;
{
krb5_error_code kret;
kret = 0 ;
/*
* Handle modification principal.
*/
if (mod_name) {
krb5_tl_mod_princ mprinc;
memset(&mprinc, 0, sizeof(mprinc));
if (!(kret = krb5_copy_principal(kcontext,
mod_name,
&mprinc.mod_princ))) {
mprinc.mod_date = mod_date;
kret = krb5_dbe_encode_mod_princ_data(kcontext,
&mprinc,
dbentp);
}
if (mprinc.mod_princ)
krb5_free_principal(kcontext, mprinc.mod_princ);
}
/*
* Handle last password change.
*/
if (!kret) {
krb5_tl_data *pwchg;
krb5_boolean linked;
/* Find a previously existing entry */
for (pwchg = dbentp->tl_data;
(pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
pwchg = pwchg->tl_data_next);
/* Check to see if we found one. */
linked = 0;
if (!pwchg) {
/* No, allocate a new one */
if ((pwchg = (krb5_tl_data *)
malloc(sizeof (krb5_tl_data)))) {
memset(pwchg, 0, sizeof(krb5_tl_data));
if (!(pwchg->tl_data_contents =
(krb5_octet *) malloc(sizeof (krb5_timestamp)))) {
free(pwchg);
pwchg = (krb5_tl_data *) NULL;
} else {
pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
pwchg->tl_data_length =
(krb5_int16) sizeof (krb5_timestamp);
}
}
} else
linked = 1;
/* Do we have an entry? */
if (pwchg && pwchg->tl_data_contents) {
/* Encode it */
krb5_kdb_encode_int32(last_pwd_change,
pwchg->tl_data_contents);
/* Link it in if necessary */
if (!linked) {
pwchg->tl_data_next = dbentp->tl_data;
dbentp->tl_data = pwchg;
dbentp->n_tl_data++;
}
} else
kret = ENOMEM;
}
return(kret);
}
#endif
static int
k5beta_parse_and_store(char *fname, krb5_context kcontext, int verbose,
int *linenop, krb5_db_entry *dbent,
char *name, char *mod_name,
krb5_timestamp last_pwd_change,
krb5_timestamp mod_date
)
{
int error;
int retval = 1;
krb5_error_code kret;
krb5_principal mod_princ;
krb5_key_data *pkey, *akey;
pkey = &dbent->key_data[0];
akey = &dbent->key_data[1];
if (!(kret = krb5_parse_name(kcontext, name, &dbent->princ))) {
if (!(kret =
krb5_parse_name(kcontext, mod_name, &mod_princ))) {
if (!(kret = krb5_dbe_update_mod_princ_data(
kcontext, dbent,
mod_date, mod_princ)) &&
!(kret = krb5_dbe_update_last_pwd_change(
kcontext, dbent, last_pwd_change))) {
int one = 1;
dbent->len = KRB5_KDB_V1_BASE_LENGTH;
pkey->key_data_ver =
(pkey->key_data_type[1] ||
pkey->key_data_length[1]) ? 2 : 1;
akey->key_data_ver =
(akey->key_data_type[1] ||
akey->key_data_length[1]) ? 2 : 1;
if ((pkey->key_data_type[0] ==
akey->key_data_type[0]) &&
(pkey->key_data_type[1] ==
akey->key_data_type[1]))
dbent->n_key_data--;
else if ((akey->key_data_type[0] == 0) &&
(akey->key_data_length[0] == 0) &&
(akey->key_data_type[1] == 0) &&
(akey->key_data_length[1] == 0))
dbent->n_key_data--;
if ((kret = krb5_db_put_principal(
kcontext, dbent, &one)) ||
(one != 1)) {
fprintf(stderr, gettext(store_err_fmt),
fname, *linenop, name,
error_message(kret));
error++;
} else {
if (verbose)
fprintf(stderr,
gettext(add_princ_fmt),
name);
retval = 0;
}
dbent->n_key_data = 2;
}
krb5_free_principal(kcontext, mod_princ);
} else {
fprintf(stderr,
gettext(parse_err_fmt),
fname, *linenop, mod_name,
error_message(kret));
error++;
}
} else {
fprintf(stderr, gettext(parse_err_fmt),
fname, *linenop, name,
error_message(kret));
error++;
}
return (retval);
}
/*
* process_k5beta_record() - Handle a dump record in old format.
*
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
process_k5beta_record(fname, kcontext, filep, verbose, linenop, pol_db)
char *fname;
krb5_context kcontext;
FILE *filep;
int verbose;
int *linenop;
void *pol_db;
{
int nmatched;
int retval;
krb5_db_entry dbent;
int name_len, mod_name_len, key_len;
int alt_key_len, salt_len, alt_salt_len;
char *name;
char *mod_name;
int tmpint1, tmpint2, tmpint3;
int error;
const char *try2read;
int i;
krb5_key_data *pkey, *akey;
krb5_timestamp last_pwd_change, mod_date;
krb5_principal mod_princ;
krb5_error_code kret;
krb5_octet *shortcopy1 = NULL; /* SUNWresync121 memleak fix */
krb5_octet *shortcopy2 = NULL;
try2read = (char *) NULL;
(*linenop)++;
retval = 1;
memset((char *)&dbent, 0, sizeof(dbent));
/* Make sure we've got key_data entries */
if (krb5_dbe_create_key_data(kcontext, &dbent) ||
krb5_dbe_create_key_data(kcontext, &dbent)) {
krb5_db_free_principal(kcontext, &dbent, 1);
return(1);
}
pkey = &dbent.key_data[0];
akey = &dbent.key_data[1];
/*
* Match the sizes. 6 tokens to match.
*/
nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
&name_len, &mod_name_len, &key_len,
&alt_key_len, &salt_len, &alt_salt_len);
if (nmatched == 6) {
pkey->key_data_length[0] = key_len;
akey->key_data_length[0] = alt_key_len;
pkey->key_data_length[1] = salt_len;
akey->key_data_length[1] = alt_salt_len;
name = (char *) NULL;
mod_name = (char *) NULL;
/*
* Get the memory for the variable length fields.
*/
if ((name = (char *) malloc((size_t) (name_len + 1))) &&
(mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
(!key_len ||
(pkey->key_data_contents[0] =
(krb5_octet *) malloc((size_t) (key_len + 1)))) &&
(!alt_key_len ||
(akey->key_data_contents[0] =
(krb5_octet *)
malloc((size_t) (alt_key_len + 1)))) &&
(!salt_len ||
(pkey->key_data_contents[1] =
(krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
(!alt_salt_len ||
(akey->key_data_contents[1] =
(krb5_octet *)
malloc((size_t) (alt_salt_len + 1))))) {
error = 0;
/* Read the principal name */
if (read_string(filep, name, name_len, linenop)) {
try2read = read_name_string;
error++;
}
/* Read the key type */
if (!error &&
(fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
try2read = read_key_type;
error++;
}
pkey->key_data_type[0] = tmpint1;
/* Read the old format key */
if (!error && read_octet_string(filep,
pkey->key_data_contents[0],
pkey->key_data_length[0])) {
try2read = read_key_data;
error++;
}
/* convert to a new format key */
/*
* the encrypted version is stored as the
* unencrypted key length (4 bytes, MSB first)
* followed by the encrypted key.
*/
if ((pkey->key_data_length[0] > 4) &&
(pkey->key_data_contents[0][0] == 0) &&
(pkey->key_data_contents[0][1] == 0)) {
/*
* this really does look like an old key,
* so drop and swap
*/
/*
* the *new* length is 2 bytes, LSB first,
* sigh.
*/
size_t shortlen = pkey->key_data_length[0] - 4 + 2;
krb5_octet *origdata = pkey->key_data_contents[0];
shortcopy1 = (krb5_octet *) malloc(shortlen);
if (shortcopy1) {
shortcopy1[0] = origdata[3];
shortcopy1[1] = origdata[2];
memcpy(shortcopy1 + 2, origdata + 4, shortlen - 2);
free(origdata);
pkey->key_data_length[0] = shortlen;
pkey->key_data_contents[0] = shortcopy1;
} else {
fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
error++;
}
}
/* Read principal attributes */
if (!error &&
(fscanf(filep, "\t%u\t%u\t%u\t%u\t%u\t%u"
"\t%u\t%u\t%u\t%u\t",
&tmpint1, &dbent.max_life,
&dbent.max_renewable_life,
&tmpint2, &dbent.expiration,
&dbent.pw_expiration, &last_pwd_change,
&dbent.last_success, &dbent.last_failed,
&tmpint3) != 10)) {
try2read = read_pr_data1;
error++;
}
pkey->key_data_kvno = tmpint1;
dbent.fail_auth_count = tmpint3;
/* Read modifier name */
if (!error && read_string(filep,
mod_name,
mod_name_len,
linenop)) {
try2read = read_mod_name;
error++;
}
/* Read second set of attributes */
if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
&mod_date, &dbent.attributes,
&tmpint1) != 3)) {
try2read = read_pr_data2;
error++;
}
pkey->key_data_type[1] = tmpint1;
/* Read salt data */
if (!error && read_octet_string(filep,
pkey->key_data_contents[1],
pkey->key_data_length[1])) {
try2read = read_salt_data;
error++;
}
/* Read alternate key type */
if (!error &&
(fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
try2read = read_akey_type;
error++;
}
akey->key_data_type[0] = tmpint1;
/* Read alternate key */
if (!error && read_octet_string(filep,
akey->key_data_contents[0],
akey->key_data_length[0])) {
try2read = read_akey_data;
error++;
}
/* convert to a new format key */
/*
* the encrypted version is stored as the
* unencrypted key length (4 bytes, MSB first)
* followed by the encrypted key.
*/
if ((akey->key_data_length[0] > 4) &&
(akey->key_data_contents[0][0] == 0) &&
(akey->key_data_contents[0][1] == 0)) {
/*
* this really does look like an old key,
* so drop and swap
*/
/*
* the *new* length is 2 bytes, LSB first,
* sigh.
*/
size_t shortlen = akey->key_data_length[0] - 4 + 2;
krb5_octet *origdata = akey->key_data_contents[0];
shortcopy2 = (krb5_octet *) malloc(shortlen);
if (shortcopy2) {
shortcopy2[0] = origdata[3];
shortcopy2[1] = origdata[2];
memcpy(shortcopy2 + 2,
origdata + 4, shortlen - 2);
free(origdata);
akey->key_data_length[0] = shortlen;
akey->key_data_contents[0] = shortcopy2;
} else {
fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
error++;
}
}
/* Read alternate salt type */
if (!error &&
(fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
try2read = read_asalt_type;
error++;
}
akey->key_data_type[1] = tmpint1;
/* Read alternate salt data */
if (!error && read_octet_string(filep,
akey->key_data_contents[1],
akey->key_data_length[1])) {
try2read = read_asalt_data;
error++;
}
/* Read expansion data - discard it */
if (!error) {
for (i=0; i<8; i++) {
if (fscanf(filep,
"\t%u", &tmpint1) != 1) {
try2read = read_exp_data;
error++;
break;
}
}
if (!error)
find_record_end(filep, fname, *linenop);
}
/*
* If no error, then we're done reading. Now parse
* the names and store the database dbent.
*/
if (!error) {
retval = k5beta_parse_and_store(
fname, kcontext, verbose,
linenop, &dbent, name, mod_name,
last_pwd_change, mod_date);
} else {
fprintf(stderr, gettext(read_err_fmt),
fname, *linenop, try2read);
}
} else {
fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
}
krb5_db_free_principal(kcontext, &dbent, 1);
if (mod_name)
free(mod_name);
if (name)
free(name);
} else {
if (nmatched != EOF)
fprintf(stderr, gettext(rhead_err_fmt),
fname, *linenop);
else
retval = -1;
}
if (shortcopy1)
free(shortcopy1);
if (shortcopy2)
free(shortcopy2);
return (retval);
}
static int
get_k5beta6_tag_data(FILE *filep, krb5_db_entry dbentry, const char **try2read)
{
int error = 0;
int i;
krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
int nread;
krb5_tl_data *tl;
for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
if (nread == 2) {
tl->tl_data_type = (krb5_int16) t1;
tl->tl_data_length = (krb5_int16) t2;
if (tl->tl_data_length) {
if (!(tl->tl_data_contents =
(krb5_octet *)
malloc((size_t) t2 + 1)) ||
read_octet_string(filep,
tl->tl_data_contents, t2)) {
*try2read = read_tcontents;
error++;
break;
}
} else {
/* Should be a null field */
nread = fscanf(filep, "%d", &t9);
if ((nread != 1) || (t9 != -1)) {
error++;
*try2read = read_tcontents;
break;
}
}
} else {
*try2read = read_ttypelen;
error++;
break;
}
}
return (error);
}
static int
get_k5beta6_key_data(FILE *filep, krb5_db_entry dbentry, const char **try2read)
{
int error = 0;
int i, j;
krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
int nread;
krb5_key_data *kdatap;
for (i = 0; !error && (i < dbentry.n_key_data); i++) {
kdatap = &dbentry.key_data[i];
nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
if (nread == 2) {
kdatap->key_data_ver = (krb5_int16) t1;
kdatap->key_data_kvno = (krb5_int16) t2;
for (j = 0; j < t1; j++) {
nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
if (nread == 2) {
kdatap->key_data_type[j] = t3;
kdatap->key_data_length[j] = t4;
if (t4) {
if (!(kdatap->
key_data_contents[j] =
(krb5_octet *)
malloc((size_t) t4
+ 1)) ||
read_octet_string(filep,
kdatap->
key_data_contents[j],
t4)) {
*try2read =
read_kcontents;
error++;
break;
}
} else {
/* Should be a null field */
nread = fscanf(filep,
"%d", &t9);
if ((nread != 1) ||
(t9 != -1)) {
error++;
*try2read =
read_kcontents;
break;
}
}
} else {
*try2read = read_ktypelen;
error++;
break;
}
}
}
}
return (error);
}
/*
* process_k5beta6_record() - Handle a dump record in krb5b6 format.
*
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
process_k5beta6_record(fname, kcontext, filep, verbose, linenop, pol_db)
char *fname;
krb5_context kcontext;
FILE *filep;
int verbose;
int *linenop;
void *pol_db;
{
int retval;
krb5_db_entry dbentry;
krb5_int32 t1, t2, t3, t4, t5, t6, t7, t8, t9;
int nread;
int error;
int i, j, one;
char *name;
krb5_key_data *kp, *kdatap;
krb5_tl_data **tlp, *tl;
krb5_octet *op;
krb5_error_code kret;
const char *try2read;
try2read = (char *) NULL;
memset((char *) &dbentry, 0, sizeof(dbentry));
(*linenop)++;
retval = 1;
name = (char *) NULL;
kp = (krb5_key_data *) NULL;
op = (krb5_octet *) NULL;
error = 0;
kret = 0;
nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
if (nread == 5) {
/* Get memory for flattened principal name */
if (!(name = (char *) malloc((size_t) t2 + 1)))
error++;
/* Get memory for and form tagged data linked list */
tlp = &dbentry.tl_data;
for (i=0; i<t3; i++) {
if ((*tlp = (krb5_tl_data *)
malloc(sizeof (krb5_tl_data)))) {
memset(*tlp, 0, sizeof(krb5_tl_data));
tlp = &((*tlp)->tl_data_next);
dbentry.n_tl_data++;
} else {
error++;
break;
}
}
/* Get memory for key list */
if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
(t4*sizeof(krb5_key_data)))))
error++;
/* Get memory for extra data */
if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
error++;
if (!error) {
dbentry.len = t1;
dbentry.n_key_data = t4;
dbentry.e_length = t5;
if (kp) {
memset(kp, 0,
(size_t) (t4 * sizeof (krb5_key_data)));
dbentry.key_data = kp;
kp = (krb5_key_data *) NULL;
}
if (op) {
memset(op, 0, (size_t) t5);
dbentry.e_data = op;
op = (krb5_octet *) NULL;
}
/* Read in and parse the principal name */
if (!read_string(filep, name, t2, linenop) &&
!(kret = krb5_parse_name(kcontext,
name, &dbentry.princ))) {
/* Get the fixed principal attributes */
nread = fscanf(filep, "%d\t%d\t%d\t%d"
"\t%d\t%d\t%d\t%d\t",
&t2, &t3, &t4, &t5,
&t6, &t7, &t8, &t9);
if (nread == 8) {
dbentry.attributes = (krb5_flags) t2;
dbentry.max_life = (krb5_deltat) t3;
dbentry.max_renewable_life =
(krb5_deltat) t4;
dbentry.expiration =
(krb5_timestamp) t5;
dbentry.pw_expiration =
(krb5_timestamp) t6;
dbentry.last_success =
(krb5_timestamp) t7;
dbentry.last_failed =
(krb5_timestamp) t8;
dbentry.fail_auth_count =
(krb5_kvno) t9;
} else {
try2read = read_nint_data;
error++;
}
/*
* Get the tagged data.
*
* Really, this code ought to discard tl data
* types that it knows are special to the
* current version and were not supported
* in the previous version. But it's a pain
* to implement that here, and doing it at
* dump time has almost as good an effect,
* so that's what I did. [krb5-admin/89/
*/
if (!error && dbentry.n_tl_data) {
error = get_k5beta6_tag_data(
filep,
dbentry,
&try2read);
}
/* Get the key data */
if (!error && dbentry.n_key_data) {
error = get_k5beta6_key_data(
filep,
dbentry,
&try2read);
}
/* Get the extra data */
if (!error && dbentry.e_length) {
if (read_octet_string(filep,
dbentry.e_data,
(int) dbentry.e_length)) {
try2read = read_econtents;
error++;
}
} else {
nread = fscanf(filep, "%d", &t9);
if ((nread != 1) || (t9 != -1)) {
error++;
try2read = read_econtents;
}
}
/* Finally, find the end of the record. */
if (!error)
find_record_end(filep, fname, *linenop);
/*
* We have either read in all the data or
* choked.
*/
if (!error) {
one = 1;
if ((kret = krb5_db_put_principal(
kcontext,
&dbentry,
&one))) {
fprintf(stderr,
gettext(store_err_fmt),
fname, *linenop,
name, error_message(kret));
} else {
if (verbose)
fprintf(stderr,
gettext(
add_princ_fmt),
name);
retval = 0;
}
} else {
fprintf(stderr, gettext(read_err_fmt),
fname, *linenop, try2read);
}
} else {
if (kret)
fprintf(stderr, gettext(parse_err_fmt),
fname, *linenop, name,
error_message(kret));
else
fprintf(stderr, gettext(no_mem_fmt),
fname, *linenop);
}
} else {
fprintf(stderr,
gettext(rhead_err_fmt), fname, *linenop);
}
if (op)
free(op);
if (kp)
free(kp);
if (name)
free(name);
krb5_db_free_principal(kcontext, &dbentry, 1);
} else {
if (nread == EOF)
retval = -1;
}
return(retval);
}
int
process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
char *fname;
krb5_context kcontext;
FILE *filep;
int verbose;
int *linenop;
void *pol_db;
{
osa_policy_ent_rec rec;
char namebuf[1024];
int nread, ret;
(*linenop)++;
rec.name = namebuf;
nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
&rec.pw_min_life, &rec.pw_max_life,
&rec.pw_min_length, &rec.pw_min_classes,
&rec.pw_history_num, &rec.policy_refcnt);
if (nread == EOF)
return (-1);
else if (nread != 7) {
fprintf(stderr,
gettext("cannot parse policy on line %d (%d read)\n"),
*linenop, nread);
return (1);
}
if ((ret = osa_adb_create_policy(pol_db, &rec))) {
if (ret == OSA_ADB_DUP &&
((ret = osa_adb_put_policy(pol_db, &rec)))) {
fprintf(stderr, gettext("cannot create policy on line %d: %s\n"),
*linenop, error_message(ret));
return (1);
}
}
if (verbose)
fprintf(stderr, gettext("created policy %s\n"), rec.name);
return (0);
}
/*
* process_k5beta7_record() - Handle a dump record in krb5b6 format.
*
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
process_k5beta7_record(fname, kcontext, filep, verbose, linenop, pol_db)
char *fname;
krb5_context kcontext;
FILE *filep;
int verbose;
int *linenop;
void *pol_db;
{
int nread;
char rectype[100];
nread = fscanf(filep, "%100s\t", rectype);
if (nread == EOF)
return (-1);
else if (nread != 1)
return (1);
if (strcmp(rectype, "princ") == 0)
process_k5beta6_record(fname, kcontext, filep, verbose,
linenop, pol_db);
else if (strcmp(rectype, "policy") == 0)
process_k5beta7_policy(fname, kcontext, filep, verbose,
linenop, pol_db);
else {
fprintf(stderr,
gettext("unknown record type \"%s\" on line %d\n"),
rectype, *linenop);
return (1);
}
return (0);
}
/*
* process_ov_record() - Handle a dump record in OpenV*Secure 1.0 format.
*
* Returns -1 for end of file, 0 for success and 1 for failure.
*/
static int
process_ov_record(fname, kcontext, filep, verbose, linenop, pol_db)
char *fname;
krb5_context kcontext;
FILE *filep;
int verbose;
int *linenop;
void *pol_db;
{
int nread;
char rectype[100];
nread = fscanf(filep, "%100s\t", rectype);
if (nread == EOF)
return (-1);
else if (nread != 1)
return (1);
if (strcmp(rectype, "princ") == 0)
process_ov_principal(fname, kcontext, filep, verbose,
linenop, pol_db);
else if (strcmp(rectype, "policy") == 0)
process_k5beta7_policy(fname, kcontext, filep, verbose,
linenop, pol_db);
else if (strcmp(rectype, "End") == 0)
return (-1);
else {
fprintf(stderr,
gettext("unknown record type \"%s\" on line %d\n"),
rectype, *linenop);
return (1);
}
return (0);
}
/*
* restore_dump() - Restore the database from any version dump file.
*/
static int
restore_dump(programname, kcontext, dumpfile, f, verbose, dump, pol_db)
char *programname;
krb5_context kcontext;
char *dumpfile;
FILE *f;
int verbose;
dump_version *dump;
osa_adb_policy_t pol_db;
{
int error;
int lineno;
error = 0;
lineno = 1;
/*
* Process the records.
*/
while (!(error = (*dump->load_record)(dumpfile,
kcontext,
f,
verbose,
&lineno,
pol_db)));
if (error != -1)
fprintf(stderr, gettext(err_line_fmt),
programname, lineno, dumpfile);
else
error = 0;
return(error);
}
/*
* Usage: load_db [-i] [-old] [-ov] [-b6] [-verbose] [-update] [-hash] filename
*/
void
load_db(argc, argv)
int argc;
char **argv;
{
kadm5_config_params newparams;
osa_adb_policy_t tmppol_db;
krb5_error_code kret;
krb5_context kcontext;
FILE *f;
extern char *optarg;
extern int optind;
char *programname;
char *dumpfile;
char *dbname;
char *dbname_tmp;
char buf[BUFSIZ];
dump_version *load;
int update, verbose;
krb5_int32 crflags;
int aindex;
bool_t add_update = TRUE;
char iheader[MAX_HEADER];
uint32_t caller, last_sno, last_seconds, last_useconds;
kdb_log_context *log_ctx;
/*
* Parse the arguments.
*/
programname = argv[0];
if (strrchr(programname, (int) '/'))
programname = strrchr(argv[0], (int) '/') + 1;
dumpfile = (char *) NULL;
dbname = global_params.dbname;
load = NULL;
update = 0;
verbose = 0;
crflags = KRB5_KDB_CREATE_BTREE;
exit_status = 0;
dbname_tmp = (char *) NULL;
tmppol_db = NULL;
log_ctx = util_context->kdblog_context;
for (aindex = 1; aindex < argc; aindex++) {
if (strcmp(argv[aindex], oldoption) == 0)
load = &old_version;
else if (strcmp(argv[aindex], b6option) == 0)
load = &beta6_version;
else if (strcmp(argv[aindex], ovoption) == 0)
load = &ov_version;
else if (!strcmp(argv[aindex], ipropoption)) {
if (log_ctx && log_ctx->iproprole) {
load = &iprop_version;
add_update = FALSE;
} else {
fprintf(stderr, gettext("Iprop not enabled\n"));
exit_status++;
return;
}
} else if (strcmp(argv[aindex], verboseoption) == 0)
verbose = 1;
else if (strcmp(argv[aindex], updateoption) == 0)
update = 1;
else if (!strcmp(argv[aindex], hashoption))
crflags = KRB5_KDB_CREATE_HASH;
else
break;
}
if ((argc - aindex) != 1) {
usage();
return;
}
dumpfile = argv[aindex];
if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
strlen(dump_tmptrail)+1))) {
fprintf(stderr, gettext(no_name_mem_fmt), argv[0]);
exit_status++;
return;
}
strcpy(dbname_tmp, dbname);
strcat(dbname_tmp, dump_tmptrail);
/*
* Initialize the Kerberos context and error tables.
*/
if ((kret = krb5_init_context(&kcontext))) {
fprintf(stderr, gettext(ctx_err_fmt), programname);
free(dbname_tmp);
exit_status++;
return;
}
if (log_ctx && log_ctx->iproprole)
kcontext->kdblog_context = (void *)log_ctx;
/*
* Open the dumpfile
*/
if (dumpfile) {
if ((f = fopen(dumpfile, "r+")) == NULL) {
fprintf(stderr, gettext(dfile_err_fmt),
programname, dumpfile,
error_message(errno));
exit_status++;
return;
}
if ((kret = krb5_lock_file(kcontext, fileno(f),
KRB5_LOCKMODE_SHARED))) {
fprintf(stderr, gettext("%s: Cannot lock %s: %s\n"), programname,
dumpfile, error_message(errno));
exit_status++;
return;
}
} else
f = stdin;
/*
* Auto-detect dump version if we weren't told, verify if we were
* told.
*/
fgets(buf, sizeof(buf), f);
if (load) {
/*
* only check what we know; some headers only contain a
* prefix
*/
if (strncmp(buf, load->header, strlen(load->header)) != 0) {
fprintf(stderr, gettext(head_bad_fmt),
programname, dumpfile);
exit_status++;
if (dumpfile)
fclose(f);
return;
}
} else {
/* perhaps this should be in an array, but so what? */
if (strcmp(buf, old_version.header) == 0)
load = &old_version;
else if (strcmp(buf, beta6_version.header) == 0)
load = &beta6_version;
else if (strcmp(buf, beta7_version.header) == 0)
load = &beta7_version;
else if (strncmp(buf, ov_version.header,
strlen(ov_version.header)) == 0)
load = &ov_version;
else {
fprintf(stderr, gettext(head_bad_fmt),
programname, dumpfile);
exit_status++;
if (dumpfile)
fclose(f);
return;
}
}
if (load->updateonly && !update) {
fprintf(stderr,
gettext("%s: dump version %s can only "
"be loaded with the -update flag\n"),
programname, load->name);
exit_status++;
return;
}
/*
* Cons up params for the new databases. If we are not in update
* mode use a temp name that we'll rename later.
*/
newparams = global_params;
if (! update) {
newparams.mask |= KADM5_CONFIG_DBNAME;
newparams.dbname = dbname_tmp;
if ((kret = kadm5_get_config_params(kcontext, NULL, NULL,
&newparams, &newparams))) {
com_err(argv[0], kret,
gettext("while retreiving new "
"configuration parameters"));
exit_status++;
return;
}
}
/*
* If not an update restoration, create the temp database. Always
* create a temp policy db, even if we are not loading a dump file
* with policy info, because they may be loading an old dump
* intending to use it with the new kadm5 system.
*/
if (!update && ((kret = krb5_db_create(kcontext, dbname_tmp, crflags)))) {
fprintf(stderr, gettext(dbcreaterr_fmt),
programname, dbname_tmp, error_message(kret));
exit_status++;
kadm5_free_config_params(kcontext, &newparams);
if (dumpfile) fclose(f);
return;
}
if (!update && (kret = osa_adb_create_policy_db(&newparams))) {
fprintf(stderr,
gettext("%s: %s while creating policy database\n"),
programname, error_message(kret));
exit_status++;
kadm5_free_config_params(kcontext, &newparams);
if (dumpfile)
fclose(f);
return;
}
/*
* Point ourselves at the new databases.
*/
if ((kret = krb5_db_set_name(kcontext,
(update) ? dbname : dbname_tmp))) {
fprintf(stderr, gettext(dbname_err_fmt),
programname,
(update) ? dbname : dbname_tmp, error_message(kret));
exit_status++;
goto error;
}
if ((kret = osa_adb_open_policy(&tmppol_db, &newparams))) {
fprintf(stderr,
gettext("%s: %s while opening policy database\n"),
programname, error_message(kret));
exit_status++;
goto error;
}
/*
* If an update restoration, make sure the db is left unusable if
* the update fails.
*/
if (update) {
if ((kret = osa_adb_get_lock(tmppol_db, OSA_ADB_PERMANENT))) {
fprintf(stderr,
gettext("%s: %s while "
"permanently locking database\n"),
programname, error_message(kret));
exit_status++;
goto error;
}
}
/*
* Initialize the database.
*/
if ((kret = krb5_db_init(kcontext))) {
fprintf(stderr, gettext(dbinit_err_fmt),
programname, error_message(kret));
exit_status++;
goto error;
}
/*
* grab an extra lock, since there are no other users
*/
if (!update) {
kret = krb5_db_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
if (kret) {
fprintf(stderr, gettext(dblock_err_fmt),
programname, error_message(kret));
exit_status++;
goto error;
}
}
if (log_ctx && log_ctx->iproprole) {
if (add_update)
caller = FKCOMMAND;
else
caller = FKPROPD;
if (ulog_map(kcontext, &global_params, caller)) {
fprintf(stderr,
gettext("%s: Could not map log\n"),
programname);
exit_status++;
goto error;
}
/*
* We don't want to take out the ulog out from underneath
* kadmind so we reinit the header log.
*
* We also don't want to add to the update log since we
* are doing a whole sale replace of the db, because:
* we could easily exceed # of update entries
* we could implicity delete db entries during a replace
* no advantage in incr updates when entire db is replaced
*/
if (!update) {
memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
log_ctx->ulog->kdb_hmagic = KDB_HMAGIC;
log_ctx->ulog->db_version_num = KDB_VERSION;
log_ctx->ulog->kdb_state = KDB_STABLE;
log_ctx->ulog->kdb_block = ULOG_BLOCK;
log_ctx->iproprole = IPROP_NULL;
if (!add_update) {
sscanf(buf, "%s %u %u %u", iheader, &last_sno,
&last_seconds, &last_useconds);
log_ctx->ulog->kdb_last_sno = last_sno;
log_ctx->ulog->kdb_last_time.seconds =
last_seconds;
log_ctx->ulog->kdb_last_time.useconds =
last_useconds;
}
}
}
if (restore_dump(programname, kcontext,
(dumpfile) ? dumpfile : stdin_name,
f, verbose, load, tmppol_db)) {
fprintf(stderr, gettext(restfail_fmt),
programname, load->name);
exit_status++;
}
if (!update && (kret = krb5_db_unlock(kcontext))) {
/* change this error? */
fprintf(stderr, gettext(dbunlockerr_fmt),
programname, dbname_tmp, error_message(kret));
exit_status++;
}
if ((kret = krb5_db_fini(kcontext))) {
fprintf(stderr, gettext(close_err_fmt),
programname, error_message(kret));
exit_status++;
}
if (!update && load->create_kadm5 &&
((kret = kadm5_create_magic_princs(&newparams, kcontext)))) {
/* error message printed by create_magic_princs */
exit_status++;
}
/* close policy db below */
error:
/*
* If not an update: if there was an error, destroy the temp
* database, otherwise rename it into place.
*
* If an update: if there was no error, unlock the database.
*/
if (!update) {
if (exit_status) {
if ((kret =
krb5_db_destroy(kcontext, dbname_tmp))) {
fprintf(stderr, gettext(dbdelerr_fmt),
programname, dbname_tmp,
error_message(kret));
exit_status++;
}
if ((kret = osa_adb_destroy_policy_db(&newparams))) {
fprintf(stderr,
gettext("%s: %s while destroying "
"policy database\n"),
programname, error_message(kret));
exit_status++;
}
} else {
if ((kret = krb5_db_rename(kcontext,
dbname_tmp,
dbname))) {
fprintf(stderr, gettext(dbrenerr_fmt),
programname, dbname_tmp, dbname,
error_message(kret));
exit_status++;
}
if ((kret = osa_adb_close_policy(tmppol_db))) {
fprintf(stderr, gettext(close_err_fmt),
programname, error_message(kret));
exit_status++;
}
if ((kret = osa_adb_rename_policy_db(&newparams,
&global_params))) {
fprintf(stderr,
gettext("%s: %s while renaming "
"policy db %s to %s\n"),
programname, error_message(kret),
newparams.admin_dbname,
global_params.admin_dbname);
exit_status++;
}
}
} else { /* update */
if (!exit_status && ((kret = osa_adb_release_lock(tmppol_db)))) {
fprintf(stderr,
gettext("%s: %s while releasing permanent lock\n"),
programname, error_message(kret));
exit_status++;
}
if (tmppol_db && ((kret = osa_adb_close_policy(tmppol_db)))) {
fprintf(stderr, gettext(close_err_fmt),
programname, error_message(kret));
exit_status++;
}
}
if (dumpfile) {
(void) krb5_lock_file(kcontext,
fileno(f), KRB5_LOCKMODE_UNLOCK);
fclose(f);
}
if (dbname_tmp)
free(dbname_tmp);
krb5_free_context(kcontext);
}