From: Paul Park Date: Mon, 21 Aug 1995 21:14:32 +0000 (+0000) Subject: Make new dump format text-based. Also add logic to read/write old format X-Git-Tag: krb5-1.0-beta6~1283 X-Git-Url: http://git.tremily.us/?a=commitdiff_plain;h=4c4732e8424fee786e98f9e0151db8a88f9beb51;p=krb5.git Make new dump format text-based. Also add logic to read/write old format git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@6557 dc483132-0cff-0310-8789-dd5450dbe970 --- diff --git a/src/admin/edit/ChangeLog b/src/admin/edit/ChangeLog index 81b8ffc49..8df2d15ab 100644 --- a/src/admin/edit/ChangeLog +++ b/src/admin/edit/ChangeLog @@ -1,4 +1,13 @@ +Mon Aug 21 16:45:39 EDT 1995 Paul Park (pjpark@mit.edu) + * dump.c - Completely rework this logic to support old (e.g. Beta 5 + and previous) dump format and new dump format using the same + commands. This is differentiated by using the "-old" command + qualifier. + * kdb5_edit.M - Add description of -R and -s. Remove "ascii represen- + tation of a decimal number". Remove "Bugs". + + Fri Aug 18 17:06:06 EDT 1995 Paul Park (pjpark@mit.edu) * ss_wrapper.c - Change sense of fgets() check so scripts work. diff --git a/src/admin/edit/dump.c b/src/admin/edit/dump.c index cbeb5985d..53f2606d9 100644 --- a/src/admin/edit/dump.c +++ b/src/admin/edit/dump.c @@ -26,94 +26,115 @@ #include "k5-int.h" #include "com_err.h" -#include "kdb5_edit.h" #include +#include "kdb5_edit.h" +#if HAVE_REGEX_H +#include +#endif /* HAVE_REGEX_H */ + +/* + * 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 +#endif /* !HAVE_REGCOMP && HAVE_REGEXP_H */ -struct dump_record { - char *comerr_name; - FILE *f; +struct dump_args { + char *programname; + FILE *ofile; + krb5_context kcontext; + char **names; + int nnames; + int verbose; }; -static char ld_vers[] = "kdb5_edit load_dump version 3.0\n"; +/* External data */ +extern char *current_dbname; +extern krb5_boolean dbactive; +extern int exit_status; +extern krb5_context edit_context; -krb5_encrypt_block master_encblock; -extern char *current_dbname; -extern krb5_boolean dbactive; -extern int exit_status; -extern krb5_context edit_context; +/* Strings */ -void update_ok_file(); +static const char k5beta_dump_header[] = "kdb5_edit load_dump version 2.0\n"; +static const char k5_dump_header[] = "kdb5_edit load_dump version 3.0\n"; -krb5_error_code -dump_iterator(ptr, entry) - krb5_pointer ptr; - krb5_db_entry * entry; -{ - struct dump_record * arg = (struct dump_record *) ptr; - krb5_error_code retval; - datum content; - - if (retval = krb5_encode_princ_contents(edit_context, &content, entry)) { - com_err(arg->comerr_name, retval, "while encoding an entry"); - exit_status++; - return retval; - } - fprintf(arg->f, "%d\t", content.dsize); - fwrite(content.dptr, content.dsize, 1, arg->f); - fprintf(arg->f, ";\n"); - return 0; -} -/*ARGSUSED*/ - -void dump_db(argc, argv) - int argc; - char **argv; -{ - FILE *f; - struct dump_record arg; - - if (argc > 2) { - com_err(argv[0], 0, "Usage: %s filename", argv[0]); - exit_status++; - return; - } - if (!dbactive) { - com_err(argv[0], 0, Err_no_database); - exit_status++; - return; - } - if (argc == 2) { - /* - * 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 dependancies than I - * want to get into. - */ - unlink(argv[1]); - if (!(f = fopen(argv[1], "w"))) { - com_err(argv[0], errno, - "While opening file %s for writing", argv[1]); - exit_status++; - return; - } - } else { - f = stdout; - } - fputs(ld_vers, f); - arg.comerr_name = argv[0]; - arg.f = f; - (void)krb5_db_iterate(edit_context, dump_iterator, (krb5_pointer) &arg); - if (argc == 2) - fclose(f); - if (argv[1]) - update_ok_file(argv[1]); -} +static const char null_mprinc_name[] = "kdb5_dump@MISSING"; +/* Message strings */ +static const char regex_err[] = "%s: regular expression error - %s\n"; +static const char regex_merr[] = "%s: regular expression match error - %s\n"; +static const char pname_unp_err[] = "%s: cannot unparse principal name (%s)\n"; +static const char mname_unp_err[] = "%s: cannot unparse modifier name (%s)\n"; +static const char nokeys_err[] = "%s: cannot find any standard key for %s\n"; +static const char sdump_tl_inc_err[] = "%s: tagged data list inconsistency for %s (counted %d, stored %d)\n"; +static const char stand_fmt_name[] = "Kerberos version 5"; +static const char old_fmt_name[] = "Kerberos version 5 old format"; +static const char ofopen_error[] = "%s: cannot open %s for writing (%s)\n"; +static const char oflock_error[] = "%s: cannot lock %s (%s)\n"; +static const char dumprec_err[] = "%s: error performing %s dump (%s)\n"; +static const char dumphdr_err[] = "%s: error dumping %s header (%s)\n"; +static const char trash_end_fmt[] = "%s(%d): ignoring trash at end of line: "; +static const char read_name_string[] = "name string"; +static const char read_key_type[] = "key type"; +static const char read_key_data[] = "key data"; +static const char read_pr_data1[] = "first set of principal attributes"; +static const char read_mod_name[] = "modifier name"; +static const char read_pr_data2[] = "second set of principal attributes"; +static const char read_salt_data[] = "salt data"; +static const char read_akey_type[] = "alternate key type"; +static const char read_akey_data[] = "alternate key data"; +static const char read_asalt_type[] = "alternate salt type"; +static const char read_asalt_data[] = "alternate salt data"; +static const char read_exp_data[] = "expansion data"; +static const char store_err_fmt[] = "%s(%d): cannot store %s(%s)\n"; +static const char add_princ_fmt[] = "%s\n"; +static const char parse_err_fmt[] = "%s(%d): cannot parse %s (%s)\n"; +static const char read_err_fmt[] = "%s(%d): cannot read %s\n"; +static const char no_mem_fmt[] = "%s(%d): no memory for buffers\n"; +static const char rhead_err_fmt[] = "%s(%d): cannot match size tokens\n"; +static const char err_line_fmt[] = "%s: error processing line %d of %s\n"; +static const char head_bad_fmt[] = "%s: dump header bad in %s\n"; +static const char read_bytecnt[] = "record byte count"; +static const char read_encdata[] = "encoded data"; +static const char n_name_unp_fmt[] = "%s(%s): cannot unparse name\n"; +static const char n_dec_cont_fmt[] = "%s(%s): cannot decode contents\n"; +static const char read_nint_data[] = "principal static attributes"; +static const char read_tcontents[] = "tagged data contents"; +static const char read_ttypelen[] = "tagged data type and length"; +static const char read_kcontents[] = "key data contents"; +static const char read_ktypelen[] = "key data type and length"; +static const char read_econtents[] = "extra data contents"; +static const char k5beta_fmt_name[] = "Kerberos version 5 old format"; +static const char standard_fmt_name[] = "Kerberos version 5 format"; +static const char lusage_err_fmt[] = "%s: usage is %s [%s] [%s] [%s] filename dbname\n"; +static const char no_name_mem_fmt[] = "%s: cannot get memory for temporary name\n"; +static const char ctx_err_fmt[] = "%s: cannot initialize Kerberos context\n"; +static const char stdin_name[] = "standard input"; +static const char restfail_fmt[] = "%s: %s restore failed\n"; +static const char close_err_fmt[] = "%s: cannot close database (%s)\n"; +static const char dbinit_err_fmt[] = "%s: cannot initialize database (%s)\n"; +static const char dbname_err_fmt[] = "%s: cannot set database name to %s (%s)\n"; +static const char dbdelerr_fmt[] = "%s: cannot delete bad database %s (%s)\n"; +static const char dbrenerr_fmt[] = "%s: cannot rename database %s to %s (%s)\n"; +static const char dbcreaterr_fmt[] = "%s: cannot create database %s (%s)\n"; +static const char dfile_err_fmt[] = "%s: cannot open %s (%s)\n"; +static const char oldoption[] = "-old"; +static const char verboseoption[] = "-verbose"; +static const char updateoption[] = "-update"; +static const char dump_tmptrail[] = "~"; + +/* + * Update the "ok" file. + */ void update_ok_file (file_name) char *file_name; { @@ -150,212 +171,1525 @@ void update_ok_file (file_name) close(fd); return; } + +/* + * 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; innames; 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, 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, 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, + ®exp_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, 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)) + match = 1; +#endif /* HAVE_REGCOMP */ + if (match) + break; + } + return(match); +} + +static krb5_error_code +find_keytype(dbentp, keytype, salttype, kentp) + krb5_db_entry *dbentp; + krb5_keytype keytype; + 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; in_key_data; i++) { + if ((dbentp->key_data[i].key_data_type[0] == keytype) && + ((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); +} + /* - * Reads a name (actually, any string) of the specified length, - * containing any characters, and the character following the string. - * Returns a negative number if the specified number of characters - * can't be read or if the character following them isn't a tab. - * - * If successful, adds a null to the end of the string and returns the - * number of newlines read into it (usually 0). - * - * There must be enough space in the passed-in buffer for len - * characters followed by a null. + * 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. */ -int read_name(f, buf, len) - FILE *f; - char *buf; - int len; +static krb5_error_code +dump_k5beta_iterator(ptr, entry) + krb5_pointer ptr; + krb5_db_entry *entry; { - char *ptr; - int c; - int newlines = 0; + krb5_error_code retval; + struct dump_args *arg; + char *name, *mod_name; + krb5_tl_mod_princ *mprinc; + krb5_tl_data *pwchg; + krb5_key_data *pkey, *akey, nullkey; + krb5_timestamp mod_date, last_pwd_change; + int i; - for (ptr = buf; - (ptr - buf < len) && ((c = fgetc(f)) >= 0); - ptr++) { - *ptr = c; - if (c == '\n') - newlines++; + /* 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, 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)) { + /* + * Deserialize the modifier record. + */ + mprinc = (krb5_tl_mod_princ *) NULL; + mod_name = (char *) NULL; + last_pwd_change = mod_date = 0; + pkey = akey = (krb5_key_data *) NULL; + if (!(retval = krb5_dbe_decode_mod_princ_data(arg->kcontext, + entry, + &mprinc))) { + if (mprinc) { + if (mprinc->mod_princ) { + /* + * Flatten the modifier name. + */ + if ((retval = krb5_unparse_name(arg->kcontext, + mprinc->mod_princ, + &mod_name))) + fprintf(stderr, mname_unp_err, arg->programname, + error_message(retval)); + krb5_free_principal(arg->kcontext, mprinc->mod_princ); + } + mod_date = mprinc->mod_date; + krb5_xfree(mprinc); + } } + if (!mod_name) + mod_name = strdup(null_mprinc_name); - if (ptr - buf < len) - return -1; + /* + * Find the last password change record and set it straight. + */ + for (pwchg = entry->tl_data; + (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE); + pwchg = pwchg->tl_data_next); + if (pwchg) { + krb5_kdb_decode_int32(pwchg->tl_data_contents, last_pwd_change); + } - if ((c = fgetc(f)) < 0) - return -1; + /* + * Find the 'primary' key and the 'alternate' key. + */ + if ((retval = find_keytype(entry, + KEYTYPE_DES, + KRB5_KDB_SALTTYPE_NORMAL, + &pkey)) && + (retval = find_keytype(entry, + KEYTYPE_DES, + KRB5_KDB_SALTTYPE_V4, + &akey))) { + fprintf(stderr, nokeys_err, arg->programname, name); + krb5_xfree(mod_name); + krb5_xfree(name); + return(retval); + } - if (c != '\t') - return -1; + /* 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; + } - *ptr = '\0'; + /* + * 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; ikey_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, + entry->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]); - return newlines; + /* Pound out the salt data, if present. */ + for (i=0; ikey_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; ikey_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; ikey_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); } - - -void load_db(argc, argv) - int argc; - char **argv; + +/* + * dump_standard_header() - Output the standard dump header. + */ +static krb5_error_code +dump_standard_header(arglist) + struct dump_args *arglist; +{ + /* The standard header consists of the leading string */ + fprintf(arglist->ofile, k5_dump_header); + return(0); +} + +/* + * dump_standard_iterator() - Output a dump record in standard format. + */ +static krb5_error_code +dump_standard_iterator(ptr, entry) + krb5_pointer ptr; + krb5_db_entry *entry; { - krb5_error_code retval; - krb5_db_entry entry; - datum contents; - FILE * f; - char * new_dbname; - char buf[64]; /* Must be longer than ld_vers */ - int lineno; - int one; - - int i; - int name_ret; - int ch; - int load_error = 0; - int stype; - int tmp1, tmp2, tmp3; + 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, 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)) { + /* + * 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 + * mkvno attributes max_life max_renewable_life expiration + * pw_expiration last_success last_failed fail_auth_count + * n_tl_data*[type length ] + * n_key_data*[ver kvno ver*(type length )] + * + * 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%d\t", + entry->mkvno, + 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; itl_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; countern_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; ikey_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; jkey_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; ie_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, sdump_tl_inc_err, + arg->programname, name, counter, (int) entry->n_tl_data); + retval = EINVAL; + } + } + krb5_xfree(name); + return(retval); +} + +/* + * usage is: + * dump_db [-old] [-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; + krb5_error_code (*dump_iterator) PROTOTYPE((krb5_pointer, + krb5_db_entry *)); + krb5_error_code (*dump_header) PROTOTYPE((struct dump_args *)); + const char * dump_name; + int aindex; + krb5_boolean locked; - if (argc != 3) { - com_err(argv[0], 0, "Usage: %s filename dbname", argv[0]); - exit_status++; - return; + /* + * Parse the arguments. + */ + programname = argv[0]; + if (strrchr(programname, (int) '/')) + programname = strrchr(argv[0], (int) '/') + 1; + ofile = (char *) NULL; + error = 0; + dump_iterator = dump_standard_iterator; + dump_header = dump_standard_header; + dump_name = stand_fmt_name; + arglist.verbose = 0; + + /* + * Parse the qualifiers. + */ + for (aindex = 1; aindex < argc; aindex++) { + if (!strcmp(argv[aindex], oldoption)) { + dump_iterator = dump_k5beta_iterator; + dump_header = dump_k5beta_header; + dump_name = old_fmt_name; } - if (!(new_dbname = malloc(strlen(argv[2])+2))) { - com_err(argv[0], 0, "No room to allocate new database name!"); - exit_status++; - return; + else if (!strcmp(argv[aindex], verboseoption)) { + arglist.verbose++; } - strcpy(new_dbname, argv[2]); - strcat(new_dbname, "~"); - if (retval = krb5_db_create(edit_context, new_dbname)) { - com_err(argv[0], retval, "while creating database '%s'", - new_dbname); - exit_status++; - return; + 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; } - if (dbactive) { - if ((retval = krb5_db_fini(edit_context)) && - retval != KRB5_KDB_DBNOTINITED) { - com_err(argv[0], retval, - "while closing previous database"); - exit_status++; - return; - } + } + + /* + * Attempt to open the database. + */ + if (!dbactive) { + com_err(argv[0], 0, Err_no_database); + exit_status++; + return; + } + + kret = 0; + locked = 0; + if (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, ofopen_error, + programname, ofile, error_message(errno)); + exit_status++; } - if (retval = krb5_db_set_name(edit_context, new_dbname)) { - com_err(argv[0], retval, - "while setting active database to '%s'", new_dbname - ); - exit(1); - } - if (retval = krb5_db_init(edit_context)) { - com_err(argv[0], retval, - "while initializing database %s", - new_dbname - ); - exit(1); - } - if (!(f = fopen(argv[1], "r"))) { - com_err(argv[0], errno, - "While opening file %s for reading", argv[1]); + if ((kret = krb5_lock_file(edit_context, + fileno(f), + KRB5_LOCKMODE_EXCLUSIVE))) { + fprintf(stderr, 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 = edit_context; + if (!(kret = (*dump_header)(&arglist))) { + if ((kret = krb5_db_iterate(edit_context, + dump_iterator, + (krb5_pointer) &arglist))) { + fprintf(stderr, dumprec_err, + programname, dump_name, error_message(kret)); exit_status++; - return; + } + } + else { + fprintf(stderr, dumphdr_err, + programname, dump_name, error_message(kret)); + exit_status++; + } + if (ofile && !exit_status) { + fclose(f); + update_ok_file(ofile); } - fgets(buf, sizeof(buf), f); - if (strcmp(buf, ld_vers)) { - com_err(argv[0], 0, "Bad dump file version"); - load_error++; - } - for (lineno = 1; load_error == 0; lineno++) { - datum contents; - int nitems; - - memset((char *)&entry, 0, sizeof(entry)); - if ((nitems = fscanf(f, "%d\t", &contents.dsize)) != 1) { - if (nitems != EOF) { - fprintf(stderr, "Couldn't parse line #%d\n", lineno); - load_error++; - continue; + } + if (locked) + (void) krb5_lock_file(edit_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; itl_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; } - break; + 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); +} + +/* + * 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) + char *fname; + krb5_context kcontext; + FILE *filep; + int verbose; + int *linenop; +{ + 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; + + 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 key */ + if (!error && read_octet_string(filep, + pkey->key_data_contents[0], + pkey->key_data_length[0])) { + try2read = read_key_data; + 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.mkvno = tmpint2; + 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++; } - if (!(contents.dptr = malloc(contents.dsize))) { - com_err(argv[0], errno, "While allocating space"); - load_error++; - continue; + /* Read alternate key type */ + if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) { + try2read = read_akey_type; + error++; } - if (fread(contents.dptr, contents.dsize, 1, f) == EOF) { - fprintf(stderr, "Couldn't read line #%d\n", lineno); - free(contents.dptr); - load_error++; - continue; + 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++; } - if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) { - fprintf(stderr, "Ignoring trash at end of entry: "); - while ((ch != '\n') && (ch != EOF)) { - putc(ch, stderr); - ch = fgetc(f); - } - putc(ch, stderr); - load_error++; - continue; + /* Read alternate salt type */ + if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) { + try2read = read_asalt_type; + error++; } - if (retval = krb5_decode_princ_contents(edit_context, &contents, &entry)) { - com_err(argv[0], retval,"while trying to parse line %d",lineno); - free (contents.dptr); - load_error++; - continue; + 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++; } - one=1; - if (retval = krb5_db_put_principal(edit_context, &entry, &one)) { - com_err(argv[0], retval, "while trying to write db entry"); - krb5_dbe_free_contents(edit_context, &entry); - free (contents.dptr); - continue; + /* 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) { + if (!(kret = krb5_parse_name(kcontext, + name, + &dbent.princ))) { + if (!(kret = krb5_parse_name(kcontext, + mod_name, + &mod_princ))) { + if (!(kret = update_tl_data(kcontext, + &dbent, + mod_princ, + mod_date, + last_pwd_change))) { + int one = 1; + + dbent.len = KRB5_KDB_V1_BASE_LENGTH; + pkey->key_data_ver = (pkey->key_data_length[1]) ? + 2 : 1; + akey->key_data_ver = (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--; + if ((kret = krb5_db_put_principal(kcontext, + &dbent, + &one)) || + (one != 1)) { + fprintf(stderr, store_err_fmt, + fname, *linenop, name, + error_message(kret)); + error++; + } + else { + if (verbose) + fprintf(stderr, add_princ_fmt, name); + retval = 0; + } + dbent.n_key_data = 2; + } + krb5_free_principal(kcontext, mod_princ); + } + else { + fprintf(stderr, parse_err_fmt, + fname, *linenop, mod_name, + error_message(kret)); + error++; + } + } + else { + fprintf(stderr, parse_err_fmt, + fname, *linenop, name, error_message(kret)); + error++; + } + } + else { + fprintf(stderr, read_err_fmt, fname, *linenop, try2read); } } - if (retval = krb5_db_fini(edit_context)) { - com_err(argv[0], retval, - "while closing database '%s'", new_dbname); - exit(1); - } - if (load_error) { - printf("Error while loading database, aborting load.\n"); - exit_status += load_error; - if (retval = kdb5_db_destroy(edit_context, new_dbname)) { - com_err(argv[0], retval, - "while destroying temporary database '%s'", - new_dbname); - exit(1); + else { + fprintf(stderr, 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, rhead_err_fmt, fname, *linenop); + else + retval = -1; + } + return(retval); +} + +/* + * process_k5_record() - Handle a dump record in new format. + * + * Returns -1 for end of file, 0 for success and 1 for failure. + */ +static int +process_k5_record(fname, kcontext, filep, verbose, linenop) + char *fname; + krb5_context kcontext; + FILE *filep; + int verbose; + int *linenop; +{ + 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))) + error++; + + /* Get memory for and form tagged data linked list */ + tlp = &dbentry.tl_data; + for (i=0; itl_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%d\t", + &t1, &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9); + if (nread == 9) { + dbentry.mkvno = (krb5_kvno) t1; + 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 */ + if (!error && dbentry.n_tl_data) { + 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; + } + } + } + + /* Get the key data */ + if (!error && dbentry.n_key_data) { + for (i=0; !error && (ikey_data_ver = (krb5_int16) t1; + kdatap->key_data_kvno = (krb5_int16) t2; + + for (j=0; jkey_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; + } + } + } + } } + + /* 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); + /* - * XXX Kludge alert, but we want to exit with a - * non-zero status, and it's hard to do that in the ss - * framework, since the the do_xxx procedures return - * void. Grump. + * We have either read in all the data or choked. */ - exit(1); - } else { - if (retval = krb5_db_rename(edit_context, new_dbname, argv[2])) { - com_err(argv[0], retval, - "while renaming database from %s to %s", - new_dbname, argv[2]); - exit(1); + if (!error) { + one = 1; + if ((kret = krb5_db_put_principal(kcontext, + &dbentry, + &one))) { + fprintf(stderr, store_err_fmt, + fname, *linenop, + name, error_message(kret)); + } + else { + if (verbose) + fprintf(stderr, add_princ_fmt, name); + retval = 0; + } } + else { + fprintf(stderr, read_err_fmt, fname, *linenop, try2read); + } + } + else { + if (kret) + fprintf(stderr, parse_err_fmt, + fname, *linenop, name, error_message(kret)); + else + fprintf(stderr, no_mem_fmt, fname, *linenop); + } + } + else { + fprintf(stderr, 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); +} + +/* + * restore_k5beta_compat() - Restore the database from a K5 Beta + * format dump file. + */ +static int +restore_k5beta_compat(programname, kcontext, dumpfile, f, verbose) + const char *programname; + krb5_context kcontext; + const char *dumpfile; + FILE *f; + int verbose; +{ + int error; + int lineno; + char buf[2*sizeof(k5beta_dump_header)]; + + /* + * Get/check the header. + */ + error = 0; + fgets(buf, sizeof(buf), f); + if (!strcmp(buf, k5beta_dump_header)) { + lineno = 1; + /* + * Process the records. + */ + while (!(error = process_k5beta_record(dumpfile, + kcontext, + f, + verbose, + &lineno))) + ; + if (error != -1) + fprintf(stderr, err_line_fmt, programname, lineno, dumpfile); + else + error = 0; + + /* + * Close the input file. + */ + if (f != stdin) + fclose(f); + } + else { + fprintf(stderr, head_bad_fmt, programname, dumpfile); + error++; + } + return(error); +} + +/* + * restore_dump() - Restore the database from a standard dump file. + */ +static int +restore_dump(programname, kcontext, dumpfile, f, verbose) + const char *programname; + krb5_context kcontext; + const char *dumpfile; + FILE *f; + int verbose; +{ + int error; + int lineno; + char buf[2*sizeof(k5_dump_header)]; + + /* + * Get/check the header. + */ + error = 0; + fgets(buf, sizeof(buf), f); + if (!strcmp(buf, k5_dump_header)) { + lineno = 1; + /* + * Process the records. + */ + while (!(error = process_k5_record(dumpfile, + kcontext, + f, + verbose, + &lineno))) + ; + if (error != -1) + fprintf(stderr, err_line_fmt, programname, lineno, dumpfile); + else + error = 0; + + /* + * Close the input file. + */ + if (f != stdin) + fclose(f); + } + else { + fprintf(stderr, head_bad_fmt, programname, dumpfile); + error++; + } + return(error); +} + +/* + * Usage is + * load_db [-old] [-verbose] [-update] filename dbname + */ +void +load_db(argc, argv) + int argc; + char **argv; +{ + krb5_error_code kret; + krb5_context kcontext; + FILE *f; + extern char *optarg; + extern int optind; + const char *programname; + const char *dumpfile; + char *dbname; + char *dbname_tmp; + int (*restore_function) PROTOTYPE((const char *, + krb5_context, + const char *, + FILE *, + int)); + const char * restore_name; + int update, verbose; + int aindex; + + /* + * Parse the arguments. + */ + programname = argv[0]; + if (strrchr(programname, (int) '/')) + programname = strrchr(argv[0], (int) '/') + 1; + dumpfile = (char *) NULL; + dbname = (char *) NULL; + restore_function = restore_dump; + restore_name = standard_fmt_name; + update = 0; + verbose = 0; + exit_status = 0; + dbname_tmp = (char *) NULL; + for (aindex = 1; aindex < argc; aindex++) { + if (!strcmp(argv[aindex], oldoption)) { + restore_function = restore_k5beta_compat; + restore_name = k5beta_fmt_name; + } + else if (!strcmp(argv[aindex], verboseoption)) { + verbose = 1; } - if (dbactive) { - if (retval = krb5_db_set_name(edit_context, current_dbname)) { - com_err(argv[0], retval, - "while resetting active database to '%s'", - current_dbname); - exit(1); + else if (!strcmp(argv[aindex], updateoption)) { + update = 1; + } + else + break; + } + if ((argc - aindex) != 2) { + fprintf(stderr, lusage_err_fmt, argv[0], argv[0], + oldoption, verboseoption, updateoption); + exit_status++; + return; + } + + dumpfile = argv[aindex]; + dbname = argv[aindex+1]; + if (!(dbname_tmp = (char *) malloc(strlen(dbname)+ + strlen(dump_tmptrail)+1))) { + fprintf(stderr, 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, ctx_err_fmt, programname); + free(dbname_tmp); + exit_status++; + return; + } + krb5_init_ets(kcontext); + + /* + * Open the dumpfile + */ + if (dumpfile) { + if ((f = fopen(dumpfile, "r"))) { + kret = krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_SHARED); + } + } + else { + f = stdin; + } + if (f && !kret) { + /* + * Create the new database if not an update restoration. + */ + if (update || !(kret = krb5_db_create(kcontext, dbname_tmp))) { + /* + * Point ourselves at it. + */ + if (!(kret = krb5_db_set_name(kcontext, + (update) ? dbname : dbname_tmp))) { + /* + * Initialize the database. + */ + if (!(kret = krb5_db_init(kcontext))) { + if ((*restore_function)(programname, + kcontext, + (dumpfile) ? dumpfile : stdin_name, + f, + verbose)) { + fprintf(stderr, restfail_fmt, + programname, restore_name); + exit_status++; + } + if ((kret = krb5_db_fini(kcontext))) { + fprintf(stderr, close_err_fmt, + programname, error_message(kret)); + exit_status++; + } + } + else { + fprintf(stderr, dbinit_err_fmt, + programname, error_message(kret)); + exit_status++; } - if (retval = krb5_db_init(edit_context)) { - com_err(argv[0], retval, - "while initializing active database %s", - current_dbname); - exit(1); + } + else { + fprintf(stderr, dbname_err_fmt, + programname, + (update) ? dbname : dbname_tmp, error_message(kret)); + exit_status++; + } + /* + * If there was an error and this is not an update, then + * destroy the database. + */ + if (!update) { + if (exit_status) { + if ((kret = kdb5_db_destroy(kcontext, dbname))) { + fprintf(stderr, dbdelerr_fmt, + programname, dbname_tmp, error_message(kret)); + exit_status++; + } } + else { + if ((kret = krb5_db_rename(kcontext, + dbname_tmp, + dbname))) { + fprintf(stderr, dbrenerr_fmt, + programname, dbname, dbname_tmp, + error_message(kret)); + exit_status++; + } + } + } + } + else { + fprintf(stderr, dbcreaterr_fmt, + programname, dbname, error_message(kret)); + exit_status++; } + if (dumpfile) { + (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK); + fclose(f); + } + } + else { + fprintf(stderr, dfile_err_fmt, dumpfile, error_message(errno)); + exit_status++; + } + free(dbname_tmp); + krb5_free_context(kcontext); }