Home | History | Annotate | Download | only in dbutil
      1 /*
      2  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
      3  * Use is subject to license terms.
      4  */
      5 
      6 /*
      7  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
      8  *
      9  *	Openvision retains the copyright to derivative works of
     10  *	this source code.  Do *NOT* create a derivative of this
     11  *	source code before consulting with your legal department.
     12  *	Do *NOT* integrate *ANY* of this source code into another
     13  *	product before consulting with your legal department.
     14  *
     15  *	For further information, read the top-level Openvision
     16  *	copyright which is contained in the top-level MIT Kerberos
     17  *	copyright.
     18  *
     19  * WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING
     20  *
     21  */
     22 
     23 
     24 /*
     25  * admin/edit/dump.c
     26  *
     27  * Copyright 1990,1991 by the Massachusetts Institute of Technology.
     28  * All Rights Reserved.
     29  *
     30  * Export of this software from the United States of America may
     31  *   require a specific license from the United States Government.
     32  *   It is the responsibility of any person or organization contemplating
     33  *   export to obtain such a license before exporting.
     34  *
     35  * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and
     36  * distribute this software and its documentation for any purpose and
     37  * without fee is hereby granted, provided that the above copyright
     38  * notice appear in all copies and that both that copyright notice and
     39  * this permission notice appear in supporting documentation, and that
     40  * the name of M.I.T. not be used in advertising or publicity pertaining
     41  * to distribution of the software without specific, written prior
     42  * permission.  Furthermore if you modify this software you must label
     43  * your software as modified software and not distribute it in such a
     44  * fashion that it might be confused with the original M.I.T. software.
     45  * M.I.T. makes no representations about the suitability of
     46  * this software for any purpose.  It is provided "as is" without express
     47  * or implied warranty.
     48  *
     49  *
     50  * Dump a KDC database
     51  */
     52 
     53 #include <stdio.h>
     54 #include <k5-int.h>
     55 #include <kadm5/admin.h>
     56 #include <kadm5/server_internal.h>
     57 #include <kdb.h>
     58 #include <com_err.h>
     59 #include <libintl.h>
     60 #include "kdb5_util.h"
     61 #if defined(HAVE_REGEX_H) && defined(HAVE_REGCOMP)
     62 #include <regex.h>
     63 #endif	/* HAVE_REGEX_H */
     64 
     65 /*
     66  * Needed for master key conversion.
     67  */
     68 extern krb5_keyblock master_key;
     69 extern krb5_principal master_princ;
     70 static int			mkey_convert;
     71 static krb5_keyblock		new_master_key;
     72 
     73 static int	backwards;
     74 static int	recursive;
     75 
     76 /*
     77  * Use compile(3) if no regcomp present.
     78  */
     79 #if	!defined(HAVE_REGCOMP) && defined(HAVE_REGEXP_H)
     80 #define	INIT		char *sp = instring;
     81 #define	GETC()		(*sp++)
     82 #define	PEEKC()		(*sp)
     83 #define	UNGETC(c)	(--sp)
     84 #define	RETURN(c)	return(c)
     85 #define	ERROR(c)
     86 #define	RE_BUF_SIZE	1024
     87 #include <regexp.h>
     88 #endif	/* !HAVE_REGCOMP && HAVE_REGEXP_H */
     89 
     90 struct dump_args {
     91     char		*programname;
     92     FILE		*ofile;
     93     krb5_context	kcontext;
     94     char		**names;
     95     int			nnames;
     96     int			verbose;
     97 };
     98 
     99 static krb5_error_code dump_k5beta_iterator (krb5_pointer,
    100 					     krb5_db_entry *);
    101 static krb5_error_code dump_k5beta6_iterator (krb5_pointer,
    102 					      krb5_db_entry *);
    103 static krb5_error_code dump_k5beta6_iterator_ext (krb5_pointer,
    104 						  krb5_db_entry *,
    105 						  int);
    106 static krb5_error_code dump_iprop_iterator (krb5_pointer,
    107 						  krb5_db_entry *);
    108 static krb5_error_code dump_k5beta7_princ (krb5_pointer,
    109 					   krb5_db_entry *);
    110 static krb5_error_code dump_k5beta7_princ_ext (krb5_pointer,
    111 					       krb5_db_entry *,
    112 					       int);
    113 static krb5_error_code dump_k5beta7_princ_withpolicy
    114 			(krb5_pointer, krb5_db_entry *);
    115 static krb5_error_code dump_iprop_princ (krb5_pointer,
    116 					       krb5_db_entry *);
    117 static krb5_error_code dump_ov_princ (krb5_pointer,
    118 				      krb5_db_entry *);
    119 static void dump_k5beta7_policy (void *, osa_policy_ent_t);
    120 
    121 typedef krb5_error_code (*dump_func)(krb5_pointer,
    122 				     krb5_db_entry *);
    123 
    124 static int process_k5beta_record (char *, krb5_context,
    125 				  FILE *, int, int *);
    126 static int process_k5beta6_record (char *, krb5_context,
    127 				   FILE *, int, int *);
    128 static int process_k5beta7_record (char *, krb5_context,
    129 				   FILE *, int, int *);
    130 static int process_ov_record (char *, krb5_context,
    131 			      FILE *, int, int *);
    132 typedef krb5_error_code (*load_func)(char *, krb5_context,
    133 				     FILE *, int, int *);
    134 
    135 typedef struct _dump_version {
    136      char *name;
    137      char *header;
    138      int updateonly;
    139      int create_kadm5;
    140      dump_func dump_princ;
    141      osa_adb_iter_policy_func dump_policy;
    142      load_func load_record;
    143 } dump_version;
    144 
    145 dump_version old_version = {
    146      "Kerberos version 5 old format",
    147      "kdb5_edit load_dump version 2.0\n",
    148      0,
    149      1,
    150      dump_k5beta_iterator,
    151      NULL,
    152      process_k5beta_record
    153 };
    154 dump_version beta6_version = {
    155      "Kerberos version 5 beta 6 format",
    156      "kdb5_edit load_dump version 3.0\n",
    157      0,
    158      1,
    159      dump_k5beta6_iterator,
    160      NULL,
    161      process_k5beta6_record
    162 };
    163 dump_version beta7_version = {
    164      "Kerberos version 5",
    165      "kdb5_util load_dump version 4\n",
    166      0,
    167      0,
    168      dump_k5beta7_princ,
    169      dump_k5beta7_policy,
    170      process_k5beta7_record
    171 };
    172 dump_version iprop_version = {
    173      "Kerberos iprop version",
    174      "iprop",
    175      0,
    176      0,
    177      dump_iprop_princ,
    178      dump_k5beta7_policy,
    179      process_k5beta7_record
    180 };
    181 dump_version ov_version = {
    182      "OpenV*Secure V1.0",
    183      "OpenV*Secure V1.0\t",
    184      1,
    185      1,
    186      dump_ov_princ,
    187      dump_k5beta7_policy,
    188      process_ov_record
    189 };
    190 
    191 dump_version r1_3_version = {
    192      "Kerberos version 5 release 1.3",
    193      "kdb5_util load_dump version 5\n",
    194      0,
    195      0,
    196      dump_k5beta7_princ_withpolicy,
    197      dump_k5beta7_policy,
    198      process_k5beta7_record,
    199 };
    200 
    201 /* External data */
    202 extern char		*current_dbname;
    203 extern krb5_boolean	dbactive;
    204 extern int		exit_status;
    205 extern krb5_context	util_context;
    206 extern kadm5_config_params global_params;
    207 
    208 /* Strings */
    209 
    210 #define k5beta_dump_header	"kdb5_edit load_dump version 2.0\n"
    211 
    212 static const char null_mprinc_name[] = "kdb5_dump@MISSING";
    213 
    214 /*
    215  * We define gettext(s) to be s here, so that xgettext will extract the
    216  * strings to the .po file. At the end of the message section we will
    217  * undef gettext so that we can use it as a funtion.
    218  */
    219 
    220 #define	gettext(s) s
    221 
    222 /* Message strings */
    223 static const char regex_err[] =
    224 	gettext("%s: regular expression error - %s\n");
    225 static const char regex_merr[] =
    226 	gettext("%s: regular expression match error - %s\n");
    227 static const char pname_unp_err[] =
    228 	gettext("%s: cannot unparse principal name (%s)\n");
    229 static const char mname_unp_err[] =
    230 	gettext("%s: cannot unparse modifier name (%s)\n");
    231 static const char nokeys_err[] =
    232 	gettext("%s: cannot find any standard key for %s\n");
    233 static const char sdump_tl_inc_err[] =
    234 	gettext("%s: tagged data list inconsistency for %s "
    235 		"(counted %d, stored %d)\n");
    236 static const char stand_fmt_name[] =
    237 	gettext("Kerberos version 5");
    238 static const char old_fmt_name[] =
    239 	gettext("Kerberos version 5 old format");
    240 static const char b6_fmt_name[] =
    241 	gettext("Kerberos version 5 beta 6 format");
    242 static const char ofopen_error[] =
    243 	gettext("%s: cannot open %s for writing (%s)\n");
    244 static const char oflock_error[] =
    245 	gettext("%s: cannot lock %s (%s)\n");
    246 static const char dumprec_err[] =
    247 	gettext("%s: error performing %s dump (%s)\n");
    248 static const char dumphdr_err[] =
    249 	gettext("%s: error dumping %s header (%s)\n");
    250 static const char trash_end_fmt[] =
    251 	gettext("%s(%d): ignoring trash at end of line: ");
    252 static const char read_name_string[] =
    253 	gettext("name string");
    254 static const char read_key_type[] =
    255 	gettext("key type");
    256 static const char read_key_data[] =
    257 	gettext("key data");
    258 static const char read_pr_data1[] =
    259 	gettext("first set of principal attributes");
    260 static const char read_mod_name[] =
    261 	gettext("modifier name");
    262 static const char read_pr_data2[] =
    263 	gettext("second set of principal attributes");
    264 static const char read_salt_data[] =
    265 	gettext("salt data");
    266 static const char read_akey_type[] =
    267 	gettext("alternate key type");
    268 static const char read_akey_data[] =
    269 	gettext("alternate key data");
    270 static const char read_asalt_type[] =
    271 	gettext("alternate salt type");
    272 static const char read_asalt_data[] =
    273 	gettext("alternate salt data");
    274 static const char read_exp_data[] =
    275 	gettext("expansion data");
    276 static const char store_err_fmt[] =
    277 	gettext("%s(%d): cannot store %s(%s)\n");
    278 static const char add_princ_fmt[] =
    279 	gettext("%s\n");
    280 static const char parse_err_fmt[] =
    281 	gettext("%s(%d): cannot parse %s (%s)\n");
    282 static const char read_err_fmt[] =
    283 	gettext("%s(%d): cannot read %s\n");
    284 static const char no_mem_fmt[] =
    285 	gettext("%s(%d): no memory for buffers\n");
    286 static const char rhead_err_fmt[] =
    287 	gettext("%s(%d): cannot match size tokens\n");
    288 static const char err_line_fmt[] =
    289 	gettext("%s: error processing line %d of %s\n");
    290 static const char head_bad_fmt[] =
    291 	gettext("%s: dump header bad in %s\n");
    292 static const char read_bytecnt[] =
    293 	gettext("record byte count");
    294 static const char read_encdata[] =
    295 	gettext("encoded data");
    296 static const char n_name_unp_fmt[] =
    297 	gettext("%s(%s): cannot unparse name\n");
    298 static const char n_dec_cont_fmt[] =
    299 	gettext("%s(%s): cannot decode contents\n");
    300 static const char read_nint_data[] =
    301 	gettext("principal static attributes");
    302 static const char read_tcontents[] =
    303 	gettext("tagged data contents");
    304 static const char read_ttypelen[] =
    305 	gettext("tagged data type and length");
    306 static const char read_kcontents[] =
    307 	gettext("key data contents");
    308 static const char read_ktypelen[] =
    309 	gettext("key data type and length");
    310 static const char read_econtents[] =
    311 	gettext("extra data contents");
    312 static const char k5beta_fmt_name[] =
    313 	gettext("Kerberos version 5 old format");
    314 static const char standard_fmt_name[] =
    315 	gettext("Kerberos version 5 format");
    316 static const char no_name_mem_fmt[] =
    317 	gettext("%s: cannot get memory for temporary name\n");
    318 static const char ctx_err_fmt[] =
    319 	gettext("%s: cannot initialize Kerberos context\n");
    320 static const char stdin_name[] =
    321 	gettext("standard input");
    322 static const char remaster_err_fmt[] =
    323 	gettext("while re-encoding keys for principal %s with new master key");
    324 static const char restfail_fmt[] =
    325 	gettext("%s: %s restore failed\n");
    326 static const char close_err_fmt[] =
    327 	gettext("%s: cannot close database (%s)\n");
    328 static const char dbinit_err_fmt[] =
    329 	gettext("%s: cannot initialize database (%s)\n");
    330 static const char dblock_err_fmt[] =
    331 	gettext("%s: cannot initialize database lock (%s)\n");
    332 static const char dbname_err_fmt[] =
    333 	gettext("%s: cannot set database name to %s (%s)\n");
    334 static const char dbdelerr_fmt[] =
    335 	gettext("%s: cannot delete bad database %s (%s)\n");
    336 static const char dbunlockerr_fmt[] =
    337 	gettext("%s: cannot unlock database %s (%s)\n");
    338 static const char dbrenerr_fmt[] =
    339 	gettext("%s: cannot rename database %s to %s (%s)\n");
    340 static const char dbcreaterr_fmt[] =
    341 	gettext("%s: cannot create database %s (%s)\n");
    342 static const char dfile_err_fmt[] =
    343 	gettext("%s: cannot open %s (%s)\n");
    344 
    345 /*
    346  * We now return you to your regularly scheduled program.
    347  */
    348 #undef gettext
    349 
    350 static const char oldoption[] = "-old";
    351 static const char b6option[] = "-b6";
    352 static const char b7option[] = "-b7";
    353 static const char ipropoption[] = "-i";
    354 static const char verboseoption[] = "-verbose";
    355 static const char updateoption[] = "-update";
    356 static const char hashoption[] = "-hash";
    357 static const char ovoption[] = "-ov";
    358 static const char dump_tmptrail[] = "~";
    359 
    360 /*
    361  * Re-encrypt the key_data with the new master key...
    362  */
    363 static krb5_error_code master_key_convert(context, db_entry)
    364     krb5_context	  context;
    365     krb5_db_entry	* db_entry;
    366 {
    367     krb5_error_code	retval;
    368     krb5_keyblock 	v5plainkey, *key_ptr;
    369     krb5_keysalt 	keysalt;
    370     int	      i, j;
    371     krb5_key_data	new_key_data, *key_data;
    372     krb5_boolean	is_mkey;
    373 
    374     is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ);
    375 
    376     if (is_mkey && db_entry->n_key_data != 1)
    377 	    fprintf(stderr,
    378 		    gettext(
    379 		      "Master key db entry has %d keys, expecting only 1!\n"),
    380 		    db_entry->n_key_data);
    381     for (i=0; i < db_entry->n_key_data; i++) {
    382 	key_data = &db_entry->key_data[i];
    383 	if (key_data->key_data_length == 0)
    384 	    continue;
    385 	retval = krb5_dbekd_decrypt_key_data(context, &master_key,
    386 					     key_data, &v5plainkey,
    387 					     &keysalt);
    388 	if (retval)
    389 		return retval;
    390 
    391 	memset(&new_key_data, 0, sizeof(new_key_data));
    392 	key_ptr = is_mkey ? &new_master_key : &v5plainkey;
    393 	retval = krb5_dbekd_encrypt_key_data(context, &new_master_key,
    394 					     key_ptr, &keysalt,
    395 					     key_data->key_data_kvno,
    396 					     &new_key_data);
    397 	if (retval)
    398 		return retval;
    399 	krb5_free_keyblock_contents(context, &v5plainkey);
    400 	for (j = 0; j < key_data->key_data_ver; j++) {
    401 	    if (key_data->key_data_length[j]) {
    402 		free(key_data->key_data_contents[j]);
    403 	    }
    404 	}
    405 	*key_data = new_key_data;
    406     }
    407     return 0;
    408 }
    409 
    410 /*
    411  * Update the "ok" file.
    412  */
    413 void update_ok_file (file_name)
    414      char *file_name;
    415 {
    416 	/* handle slave locking/failure stuff */
    417 	char *file_ok;
    418 	int fd;
    419 	static char ok[]=".dump_ok";
    420 
    421 	if ((file_ok = (char *)malloc(strlen(file_name) + strlen(ok) + 1))
    422 	    == NULL) {
    423 		com_err(progname, ENOMEM,
    424 		    gettext("while allocating filename "
    425 			"for update_ok_file"));
    426 		exit_status++;
    427 		return;
    428 	}
    429 	strcpy(file_ok, file_name);
    430 	strcat(file_ok, ok);
    431 	if ((fd = open(file_ok, O_WRONLY|O_CREAT|O_TRUNC, 0600)) < 0) {
    432 		com_err(progname, errno,
    433 		    gettext("while creating 'ok' file, '%s'"),
    434 			file_ok);
    435 		exit_status++;
    436 		free(file_ok);
    437 		return;
    438 	}
    439 	if (write(fd, "", 1) != 1) {
    440 		com_err(progname, errno,
    441 		    gettext("while writing to 'ok' file, '%s'"),
    442 		    file_ok);
    443 	     exit_status++;
    444 	     free(file_ok);
    445 	     return;
    446 	}
    447 
    448 	free(file_ok);
    449 	close(fd);
    450 	return;
    451 }
    452 
    453 /*
    454  * name_matches()	- See if a principal name matches a regular expression
    455  *			  or string.
    456  */
    457 static int
    458 name_matches(name, arglist)
    459     char		*name;
    460     struct dump_args	*arglist;
    461 {
    462 #if	HAVE_REGCOMP
    463     regex_t	match_exp;
    464     regmatch_t	match_match;
    465     int		match_error;
    466     char	match_errmsg[BUFSIZ];
    467     size_t	errmsg_size;
    468 #elif	HAVE_REGEXP_H
    469     char	regexp_buffer[RE_BUF_SIZE];
    470 #elif	HAVE_RE_COMP
    471     extern char	*re_comp();
    472     char	*re_result;
    473 #endif	/* HAVE_RE_COMP */
    474     int		i, match;
    475 
    476     /*
    477      * Plow, brute force, through the list of names/regular expressions.
    478      */
    479     match = (arglist->nnames) ? 0 : 1;
    480     for (i=0; i<arglist->nnames; i++) {
    481 #if	HAVE_REGCOMP
    482 	/*
    483 	 * Compile the regular expression.
    484 	 */
    485 	match_error = regcomp(&match_exp, arglist->names[i], REG_EXTENDED);
    486 	if (match_error) {
    487 	    errmsg_size = regerror(match_error,
    488 				   &match_exp,
    489 				   match_errmsg,
    490 				   sizeof(match_errmsg));
    491 			fprintf(stderr, gettext(regex_err),
    492 			    arglist->programname, match_errmsg);
    493 	    break;
    494 	}
    495 	/*
    496 	 * See if we have a match.
    497 	 */
    498 	match_error = regexec(&match_exp, name, 1, &match_match, 0);
    499 	if (match_error) {
    500 	    if (match_error != REG_NOMATCH) {
    501 		errmsg_size = regerror(match_error,
    502 				       &match_exp,
    503 				       match_errmsg,
    504 				       sizeof(match_errmsg));
    505 				fprintf(stderr, gettext(regex_merr),
    506 			arglist->programname, match_errmsg);
    507 		break;
    508 	    }
    509 	}
    510 	else {
    511 	    /*
    512 	     * We have a match.  See if it matches the whole
    513 	     * name.
    514 	     */
    515 	    if ((match_match.rm_so == 0) &&
    516 		(match_match.rm_eo == strlen(name)))
    517 		match = 1;
    518 	}
    519 	regfree(&match_exp);
    520 #elif	HAVE_REGEXP_H
    521 	/*
    522 	 * Compile the regular expression.
    523 	 */
    524 	compile(arglist->names[i],
    525 		regexp_buffer,
    526 		&regexp_buffer[RE_BUF_SIZE],
    527 		'\0');
    528 	if (step(name, regexp_buffer)) {
    529 	    if ((loc1 == name) &&
    530 		(loc2 == &name[strlen(name)]))
    531 		match = 1;
    532 	}
    533 #elif	HAVE_RE_COMP
    534 	/*
    535 	 * Compile the regular expression.
    536 	 */
    537 	if (re_result = re_comp(arglist->names[i])) {
    538 	    fprintf(stderr, gettext(regex_err), arglist->programname, re_result);
    539 	    break;
    540 	}
    541 	if (re_exec(name))
    542 	    match = 1;
    543 #else	/* HAVE_RE_COMP */
    544 	/*
    545 	 * If no regular expression support, then just compare the strings.
    546 	 */
    547 	if (!strcmp(arglist->names[i], name))
    548 	    match = 1;
    549 #endif	/* HAVE_REGCOMP */
    550 	if (match)
    551 	    break;
    552     }
    553     return(match);
    554 }
    555 
    556 static krb5_error_code
    557 find_enctype(dbentp, enctype, salttype, kentp)
    558     krb5_db_entry	*dbentp;
    559     krb5_enctype	enctype;
    560     krb5_int32		salttype;
    561     krb5_key_data	**kentp;
    562 {
    563     int			i;
    564     int			maxkvno;
    565     krb5_key_data	*datap;
    566 
    567     maxkvno = -1;
    568     datap = (krb5_key_data *) NULL;
    569     for (i=0; i<dbentp->n_key_data; i++) {
    570 	if (( (krb5_enctype)dbentp->key_data[i].key_data_type[0] == enctype) &&
    571 	    ((dbentp->key_data[i].key_data_type[1] == salttype) ||
    572 	     (salttype < 0))) {
    573 	    maxkvno = dbentp->key_data[i].key_data_kvno;
    574 	    datap = &dbentp->key_data[i];
    575 	}
    576     }
    577     if (maxkvno >= 0) {
    578 	*kentp = datap;
    579 	return(0);
    580     }
    581     return(ENOENT);
    582 }
    583 
    584 #if 0
    585 /*
    586  * dump_k5beta_header()	- Make a dump header that is recognizable by Kerberos
    587  *			  Version 5 Beta 5 and previous releases.
    588  */
    589 static krb5_error_code
    590 dump_k5beta_header(arglist)
    591     struct dump_args *arglist;
    592 {
    593     /* The old header consists of the leading string */
    594     fprintf(arglist->ofile, k5beta_dump_header);
    595     return(0);
    596 }
    597 #endif
    598 
    599 /*
    600  * dump_k5beta_iterator()	- Dump an entry in a format that is usable
    601  *				  by Kerberos Version 5 Beta 5 and previous
    602  *				  releases.
    603  */
    604 static krb5_error_code
    605 dump_k5beta_iterator(ptr, entry)
    606     krb5_pointer	ptr;
    607     krb5_db_entry	*entry;
    608 {
    609     krb5_error_code	retval;
    610     struct dump_args	*arg;
    611     char		*name, *mod_name;
    612     krb5_principal	mod_princ;
    613     krb5_key_data	*pkey, *akey, nullkey;
    614     krb5_timestamp	mod_date, last_pwd_change;
    615     int			i;
    616 
    617     /* Initialize */
    618     arg = (struct dump_args *) ptr;
    619     name = (char *) NULL;
    620     mod_name = (char *) NULL;
    621     memset(&nullkey, 0, sizeof(nullkey));
    622 
    623     /*
    624      * Flatten the principal name.
    625      */
    626     if ((retval = krb5_unparse_name(arg->kcontext,
    627 				    entry->princ,
    628 				    &name))) {
    629 		fprintf(stderr, gettext(pname_unp_err),
    630 		arg->programname, error_message(retval));
    631 	return(retval);
    632     }
    633 
    634     /*
    635      * Re-encode the keys in the new master key, if necessary.
    636      */
    637     if (mkey_convert) {
    638 	retval = master_key_convert(arg->kcontext, entry);
    639 	if (retval) {
    640 	    com_err(arg->programname, retval, remaster_err_fmt, name);
    641 	    return retval;
    642 	}
    643     }
    644 
    645     /*
    646      * If we don't have any match strings, or if our name matches, then
    647      * proceed with the dump, otherwise, just forget about it.
    648      */
    649     if (!arg->nnames || name_matches(name, arg)) {
    650 	/*
    651 	 * Deserialize the modifier record.
    652 	 */
    653 	mod_name = (char *) NULL;
    654 	mod_princ = NULL;
    655 	last_pwd_change = mod_date = 0;
    656 	pkey = akey = (krb5_key_data *) NULL;
    657 	if (!(retval = krb5_dbe_lookup_mod_princ_data(arg->kcontext,
    658 						      entry,
    659 						      &mod_date,
    660 						      &mod_princ))) {
    661 	    if (mod_princ) {
    662 		/*
    663 		 * Flatten the modifier name.
    664 		 */
    665 		if ((retval = krb5_unparse_name(arg->kcontext,
    666 						mod_princ,
    667 						&mod_name)))
    668 					fprintf(stderr, gettext(mname_unp_err),
    669 					    arg->programname,
    670 			    error_message(retval));
    671 		krb5_free_principal(arg->kcontext, mod_princ);
    672 	    }
    673 	}
    674 	if (!mod_name)
    675 	    mod_name = strdup(null_mprinc_name);
    676 
    677 	/*
    678 	 * Find the last password change record and set it straight.
    679 	 */
    680 	if ((retval =
    681 	     krb5_dbe_lookup_last_pwd_change(arg->kcontext, entry,
    682 					     &last_pwd_change))) {
    683 			fprintf(stderr, gettext(nokeys_err),
    684 			    arg->programname, name);
    685 	    krb5_xfree(mod_name);
    686 	    krb5_xfree(name);
    687 	    return(retval);
    688 	}
    689 
    690 	/*
    691 	 * Find the 'primary' key and the 'alternate' key.
    692 	 */
    693 	if ((retval = find_enctype(entry,
    694 				   ENCTYPE_DES_CBC_CRC,
    695 				   KRB5_KDB_SALTTYPE_NORMAL,
    696 				   &pkey)) &&
    697 	    (retval = find_enctype(entry,
    698 				   ENCTYPE_DES_CBC_CRC,
    699 				   KRB5_KDB_SALTTYPE_V4,
    700 				   &akey))) {
    701 			fprintf(stderr, gettext(nokeys_err),
    702 			    arg->programname, name);
    703 	    krb5_xfree(mod_name);
    704 	    krb5_xfree(name);
    705 	    return(retval);
    706 	}
    707 
    708 	/* If we only have one type, then ship it out as the primary. */
    709 	if (!pkey && akey) {
    710 	    pkey = akey;
    711 	    akey = &nullkey;
    712 	}
    713 	else {
    714 	    if (!akey)
    715 		akey = &nullkey;
    716 	}
    717 
    718 	/*
    719 	 * First put out strings representing the length of the variable
    720 	 * length data in this record, then the name and the primary key type.
    721 	 */
    722 	fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%s\t%d\t", strlen(name),
    723 		strlen(mod_name),
    724 		(krb5_int32) pkey->key_data_length[0],
    725 		(krb5_int32) akey->key_data_length[0],
    726 		(krb5_int32) pkey->key_data_length[1],
    727 		(krb5_int32) akey->key_data_length[1],
    728 		name,
    729 		(krb5_int32) pkey->key_data_type[0]);
    730 	for (i=0; i<pkey->key_data_length[0]; i++) {
    731 	    fprintf(arg->ofile, "%02x", pkey->key_data_contents[0][i]);
    732 	}
    733 	/*
    734 	 * Second, print out strings representing the standard integer
    735 	 * data in this record.
    736 	 */
    737 	fprintf(arg->ofile,
    738 		"\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",
    739 		(krb5_int32) pkey->key_data_kvno,
    740 		entry->max_life, entry->max_renewable_life,
    741 		1 /* Fake mkvno */, entry->expiration, entry->pw_expiration,
    742 		last_pwd_change, entry->last_success, entry->last_failed,
    743 		entry->fail_auth_count, mod_name, mod_date,
    744 		entry->attributes, pkey->key_data_type[1]);
    745 
    746 	/* Pound out the salt data, if present. */
    747 	for (i=0; i<pkey->key_data_length[1]; i++) {
    748 	    fprintf(arg->ofile, "%02x", pkey->key_data_contents[1][i]);
    749 	}
    750 	/* Pound out the alternate key type and contents */
    751 	fprintf(arg->ofile, "\t%u\t", akey->key_data_type[0]);
    752 	for (i=0; i<akey->key_data_length[0]; i++) {
    753 	    fprintf(arg->ofile, "%02x", akey->key_data_contents[0][i]);
    754 	}
    755 	/* Pound out the alternate salt type and contents */
    756 	fprintf(arg->ofile, "\t%u\t", akey->key_data_type[1]);
    757 	for (i=0; i<akey->key_data_length[1]; i++) {
    758 	    fprintf(arg->ofile, "%02x", akey->key_data_contents[1][i]);
    759 	}
    760 	/* Pound out the expansion data. (is null) */
    761 	for (i=0; i < 8; i++) {
    762 	    fprintf(arg->ofile, "\t%u", 0);
    763 	}
    764 	fprintf(arg->ofile, ";\n");
    765 	/* If we're blabbing, do it */
    766 	if (arg->verbose)
    767 	    fprintf(stderr, "%s\n", name);
    768 	krb5_xfree(mod_name);
    769     }
    770     krb5_xfree(name);
    771     return(0);
    772 }
    773 
    774 /*
    775  * dump_k5beta6_iterator()	- Output a dump record in krb5b6 format.
    776  */
    777 static krb5_error_code
    778 dump_k5beta6_iterator(ptr, entry)
    779     krb5_pointer	ptr;
    780     krb5_db_entry	*entry;
    781 {
    782     return dump_k5beta6_iterator_ext(ptr, entry, 0);
    783 }
    784 
    785 static krb5_error_code
    786 dump_k5beta6_iterator_ext(ptr, entry, kadm)
    787     krb5_pointer	ptr;
    788     krb5_db_entry	*entry;
    789     int			kadm;
    790 {
    791     krb5_error_code	retval;
    792     struct dump_args	*arg;
    793     char		*name;
    794     krb5_tl_data	*tlp;
    795     krb5_key_data	*kdata;
    796     int			counter, skip, i, j;
    797 
    798     /* Initialize */
    799     arg = (struct dump_args *) ptr;
    800     name = (char *) NULL;
    801 
    802     /*
    803      * Flatten the principal name.
    804      */
    805     if ((retval = krb5_unparse_name(arg->kcontext,
    806 				    entry->princ,
    807 				    &name))) {
    808 		fprintf(stderr, gettext(pname_unp_err),
    809 		arg->programname, error_message(retval));
    810 	return(retval);
    811     }
    812 
    813     /*
    814      * Re-encode the keys in the new master key, if necessary.
    815      */
    816     if (mkey_convert) {
    817 	retval = master_key_convert(arg->kcontext, entry);
    818 	if (retval) {
    819 	    com_err(arg->programname, retval, remaster_err_fmt, name);
    820 	    return retval;
    821 	}
    822     }
    823 
    824     /*
    825      * If we don't have any match strings, or if our name matches, then
    826      * proceed with the dump, otherwise, just forget about it.
    827      */
    828     if (!arg->nnames || name_matches(name, arg)) {
    829 	/*
    830 	 * We'd like to just blast out the contents as they would appear in
    831 	 * the database so that we can just suck it back in, but it doesn't
    832 	 * lend itself to easy editing.
    833 	 */
    834 
    835 	/*
    836 	 * The dump format is as follows:
    837 	 *	len strlen(name) n_tl_data n_key_data e_length
    838 	 *	name
    839 	 *	attributes max_life max_renewable_life expiration
    840 	 *	pw_expiration last_success last_failed fail_auth_count
    841 	 *	n_tl_data*[type length <contents>]
    842 	 *	n_key_data*[ver kvno ver*(type length <contents>)]
    843 	 *	<e_data>
    844 	 * Fields which are not encapsulated by angle-brackets are to appear
    845 	 * verbatim.  A bracketed field's absence is indicated by a -1 in its
    846 	 * place
    847 	 */
    848 
    849 	/*
    850 	 * Make sure that the tagged list is reasonably correct.
    851 	 */
    852 	counter = skip = 0;
    853 	for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
    854 	     /*
    855 	      * don't dump tl data types we know aren't understood by
    856 	      * earlier revisions [krb5-admin/89]
    857 	      */
    858 	     switch (tlp->tl_data_type) {
    859 	     case KRB5_TL_KADM_DATA:
    860 		  if (kadm)
    861 		      counter++;
    862 		  else
    863 		      skip++;
    864 		  break;
    865 	     default:
    866 		  counter++;
    867 		  break;
    868 	     }
    869 	}
    870 
    871 	if (counter + skip == entry->n_tl_data) {
    872 	    /* Pound out header */
    873 	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
    874 		    (int) entry->len,
    875 		    strlen(name),
    876 		    counter,
    877 		    (int) entry->n_key_data,
    878 		    (int) entry->e_length,
    879 		    name);
    880 	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
    881 		    entry->attributes,
    882 		    entry->max_life,
    883 		    entry->max_renewable_life,
    884 		    entry->expiration,
    885 		    entry->pw_expiration,
    886 		    entry->last_success,
    887 		    entry->last_failed,
    888 		    entry->fail_auth_count);
    889 	    /* Pound out tagged data. */
    890 	    for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
    891 		if (tlp->tl_data_type == KRB5_TL_KADM_DATA && !kadm)
    892 		     continue; /* see above, [krb5-admin/89] */
    893 
    894 		fprintf(arg->ofile, "%d\t%d\t",
    895 			(int) tlp->tl_data_type,
    896 			(int) tlp->tl_data_length);
    897 		if (tlp->tl_data_length)
    898 		    for (i=0; i<tlp->tl_data_length; i++)
    899 			fprintf(arg->ofile, "%02x", tlp->tl_data_contents[i]);
    900 		else
    901 		    fprintf(arg->ofile, "%d", -1);
    902 		fprintf(arg->ofile, "\t");
    903 	    }
    904 
    905 	    /* Pound out key data */
    906 	    for (counter=0; counter<entry->n_key_data; counter++) {
    907 		kdata = &entry->key_data[counter];
    908 		fprintf(arg->ofile, "%d\t%d\t",
    909 			(int) kdata->key_data_ver,
    910 			(int) kdata->key_data_kvno);
    911 		for (i=0; i<kdata->key_data_ver; i++) {
    912 		    fprintf(arg->ofile, "%d\t%d\t",
    913 			    kdata->key_data_type[i],
    914 			    kdata->key_data_length[i]);
    915 		    if (kdata->key_data_length[i])
    916 			for (j=0; j<kdata->key_data_length[i]; j++)
    917 			    fprintf(arg->ofile, "%02x",
    918 				    kdata->key_data_contents[i][j]);
    919 		    else
    920 			fprintf(arg->ofile, "%d", -1);
    921 		    fprintf(arg->ofile, "\t");
    922 		}
    923 	    }
    924 
    925 	    /* Pound out extra data */
    926 	    if (entry->e_length)
    927 		for (i=0; i<entry->e_length; i++)
    928 		    fprintf(arg->ofile, "%02x", entry->e_data[i]);
    929 	    else
    930 		fprintf(arg->ofile, "%d", -1);
    931 
    932 	    /* Print trailer */
    933 	    fprintf(arg->ofile, ";\n");
    934 
    935 	    if (arg->verbose)
    936 		fprintf(stderr, "%s\n", name);
    937 	}
    938 	else {
    939 			fprintf(stderr, gettext(sdump_tl_inc_err),
    940 		    arg->programname, name, counter+skip,
    941 		    (int) entry->n_tl_data);
    942 	    retval = EINVAL;
    943 	}
    944     }
    945     krb5_xfree(name);
    946     return(retval);
    947 }
    948 
    949 /*
    950  * dump_iprop_iterator()	- Output a dump record in iprop format.
    951  */
    952 static krb5_error_code
    953 dump_iprop_iterator(ptr, entry)
    954     krb5_pointer	ptr;
    955     krb5_db_entry	*entry;
    956 {
    957     krb5_error_code	retval;
    958     struct dump_args	*arg;
    959     char		*name;
    960     krb5_tl_data	*tlp;
    961     krb5_key_data	*kdata;
    962     int			counter, i, j;
    963 
    964     /* Initialize */
    965     arg = (struct dump_args *) ptr;
    966     name = (char *) NULL;
    967 
    968     /*
    969      * Flatten the principal name.
    970      */
    971     if ((retval = krb5_unparse_name(arg->kcontext,
    972 				    entry->princ,
    973 				    &name))) {
    974 		fprintf(stderr, gettext(pname_unp_err),
    975 		arg->programname, error_message(retval));
    976 	return(retval);
    977     }
    978 
    979     /*
    980      * Re-encode the keys in the new master key, if necessary.
    981      */
    982     if (mkey_convert) {
    983 	retval = master_key_convert(arg->kcontext, entry);
    984 	if (retval) {
    985 	    com_err(arg->programname, retval, remaster_err_fmt, name);
    986 	    return retval;
    987 	}
    988     }
    989 
    990     /*
    991      * If we don't have any match strings, or if our name matches, then
    992      * proceed with the dump, otherwise, just forget about it.
    993      */
    994     if (!arg->nnames || name_matches(name, arg)) {
    995 	/*
    996 	 * We'd like to just blast out the contents as they would
    997 	 * appear in the database so that we can just suck it back
    998 	 * in, but it doesn't lend itself to easy editing.
    999 	 */
   1000 
   1001 	/*
   1002 	 * The dump format is as follows: len strlen(name)
   1003 	 * n_tl_data n_key_data e_length name attributes max_life
   1004 	 * max_renewable_life expiration pw_expiration last_success
   1005 	 * last_failed fail_auth_count n_tl_data*[type length
   1006 	 * <contents>] n_key_data*[ver kvno ver*(type length
   1007 	 * <contents>)] <e_data> Fields which are not encapsulated
   1008 	 * by angle-brackets are to appear verbatim.  Bracketed
   1009 	 * fields absence is indicated by a -1 in its place
   1010 	 */
   1011 
   1012 	/*
   1013 	 * Make sure that the tagged list is reasonably correct.
   1014 	 */
   1015 	counter = 0;
   1016 	for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next)
   1017 		  counter++;
   1018 
   1019 	if (counter == entry->n_tl_data) {
   1020 	    /* Pound out header */
   1021 	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%s\t",
   1022 		    (int) entry->len,
   1023 		    strlen(name),
   1024 		    (int) entry->n_tl_data,
   1025 		    (int) entry->n_key_data,
   1026 		    (int) entry->e_length,
   1027 		    name);
   1028 	    fprintf(arg->ofile, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
   1029 		    entry->attributes,
   1030 		    entry->max_life,
   1031 		    entry->max_renewable_life,
   1032 		    entry->expiration,
   1033 		    entry->pw_expiration,
   1034 		    entry->last_success,
   1035 		    entry->last_failed,
   1036 		    entry->fail_auth_count);
   1037 	    /* Pound out tagged data. */
   1038 			for (tlp = entry->tl_data; tlp;
   1039 			    tlp = tlp->tl_data_next) {
   1040 		fprintf(arg->ofile, "%d\t%d\t",
   1041 			(int) tlp->tl_data_type,
   1042 			(int) tlp->tl_data_length);
   1043 		if (tlp->tl_data_length)
   1044 					for (i = 0;
   1045 					    i < tlp->tl_data_length;
   1046 					    i++)
   1047 						fprintf(arg->ofile, "%02x",
   1048 							tlp->
   1049 							tl_data_contents[i]);
   1050 		else
   1051 		    fprintf(arg->ofile, "%d", -1);
   1052 		fprintf(arg->ofile, "\t");
   1053 	    }
   1054 
   1055 	    /* Pound out key data */
   1056 			for (counter = 0;
   1057 			    counter < entry->n_key_data; counter++) {
   1058 		kdata = &entry->key_data[counter];
   1059 		fprintf(arg->ofile, "%d\t%d\t",
   1060 			(int) kdata->key_data_ver,
   1061 			(int) kdata->key_data_kvno);
   1062 		for (i=0; i<kdata->key_data_ver; i++) {
   1063 		    fprintf(arg->ofile, "%d\t%d\t",
   1064 			    kdata->key_data_type[i],
   1065 			    kdata->key_data_length[i]);
   1066 		    if (kdata->key_data_length[i])
   1067 						for (j = 0;
   1068 						    j < kdata->
   1069 							key_data_length[i];
   1070 						    j++)
   1071 							fprintf(arg->ofile,
   1072 							    "%02x",
   1073 							    kdata->
   1074 							    key_data_contents
   1075 								[i][j]);
   1076 		    else
   1077 			fprintf(arg->ofile, "%d", -1);
   1078 		    fprintf(arg->ofile, "\t");
   1079 		}
   1080 	    }
   1081 
   1082 	    /* Pound out extra data */
   1083 	    if (entry->e_length)
   1084 		for (i=0; i<entry->e_length; i++)
   1085 					fprintf(arg->ofile, "%02x",
   1086 						entry->e_data[i]);
   1087 	    else
   1088 		fprintf(arg->ofile, "%d", -1);
   1089 
   1090 	    /* Print trailer */
   1091 	    fprintf(arg->ofile, ";\n");
   1092 
   1093 	    if (arg->verbose)
   1094 		fprintf(stderr, "%s\n", name);
   1095 		} else {
   1096 			fprintf(stderr, gettext(sdump_tl_inc_err),
   1097 		    arg->programname, name, counter,
   1098 		    (int) entry->n_tl_data);
   1099 	    retval = EINVAL;
   1100 	}
   1101     }
   1102     krb5_xfree(name);
   1103     return(retval);
   1104 }
   1105 
   1106 /*
   1107  * dump_k5beta7_iterator()	- Output a dump record in krb5b7 format.
   1108  */
   1109 static krb5_error_code
   1110 dump_k5beta7_princ(ptr, entry)
   1111     krb5_pointer	ptr;
   1112     krb5_db_entry	*entry;
   1113 {
   1114     return dump_k5beta7_princ_ext(ptr, entry, 0);
   1115 }
   1116 
   1117 static krb5_error_code
   1118 dump_k5beta7_princ_ext(ptr, entry, kadm)
   1119     krb5_pointer	ptr;
   1120     krb5_db_entry	*entry;
   1121     int			kadm;
   1122 {
   1123      krb5_error_code retval;
   1124      struct dump_args *arg;
   1125      char *name;
   1126      int tmp_nnames;
   1127 
   1128      /* Initialize */
   1129      arg = (struct dump_args *) ptr;
   1130      name = (char *) NULL;
   1131 
   1132      /*
   1133       * Flatten the principal name.
   1134       */
   1135      if ((retval = krb5_unparse_name(arg->kcontext,
   1136 				     entry->princ,
   1137 				     &name))) {
   1138 		fprintf(stderr, gettext(pname_unp_err),
   1139 		  arg->programname, error_message(retval));
   1140 	  return(retval);
   1141      }
   1142      /*
   1143       * If we don't have any match strings, or if our name matches, then
   1144       * proceed with the dump, otherwise, just forget about it.
   1145       */
   1146      if (!arg->nnames || name_matches(name, arg)) {
   1147 	  fprintf(arg->ofile, "princ\t");
   1148 
   1149 	  /* save the callee from matching the name again */
   1150 	  tmp_nnames = arg->nnames;
   1151 	  arg->nnames = 0;
   1152 	  retval = dump_k5beta6_iterator_ext(ptr, entry, kadm);
   1153 	  arg->nnames = tmp_nnames;
   1154      }
   1155 
   1156      free(name);
   1157      return retval;
   1158 }
   1159 
   1160 /*
   1161  * dump_iprop_princ()	- Output a dump record in iprop format.
   1162  * This was created in order to dump more data, such as kadm5 tl
   1163  */
   1164 static krb5_error_code
   1165 dump_iprop_princ(ptr, entry)
   1166     krb5_pointer	ptr;
   1167     krb5_db_entry	*entry;
   1168 {
   1169      krb5_error_code retval;
   1170      struct dump_args *arg;
   1171      char *name;
   1172      int tmp_nnames;
   1173 
   1174      /* Initialize */
   1175      arg = (struct dump_args *) ptr;
   1176      name = (char *) NULL;
   1177 
   1178      /*
   1179       * Flatten the principal name.
   1180       */
   1181      if ((retval = krb5_unparse_name(arg->kcontext,
   1182 				     entry->princ,
   1183 				     &name))) {
   1184 		fprintf(stderr, gettext(pname_unp_err),
   1185 		  arg->programname, error_message(retval));
   1186 	  return(retval);
   1187      }
   1188      /*
   1189       * If we don't have any match strings, or if our name matches, then
   1190       * proceed with the dump, otherwise, just forget about it.
   1191       */
   1192      if (!arg->nnames || name_matches(name, arg)) {
   1193 	  fprintf(arg->ofile, "princ\t");
   1194 
   1195 	  /* save the callee from matching the name again */
   1196 	  tmp_nnames = arg->nnames;
   1197 	  arg->nnames = 0;
   1198 	  retval = dump_iprop_iterator(ptr, entry);
   1199 	  arg->nnames = tmp_nnames;
   1200      }
   1201      free(name);
   1202 	return (retval);
   1203 }
   1204 
   1205 static krb5_error_code
   1206 dump_k5beta7_princ_withpolicy(ptr, entry)
   1207     krb5_pointer	ptr;
   1208     krb5_db_entry	*entry;
   1209 {
   1210     return dump_k5beta7_princ_ext(ptr, entry, 1);
   1211 }
   1212 
   1213 void dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
   1214 {
   1215      struct dump_args *arg;
   1216 
   1217      arg = (struct dump_args *) data;
   1218      fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
   1219 	     entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
   1220 	     entry->pw_min_classes, entry->pw_history_num,
   1221 	     entry->policy_refcnt);
   1222 }
   1223 
   1224 static void print_key_data(FILE *f, krb5_key_data *key_data)
   1225 {
   1226      int c;
   1227 
   1228      fprintf(f, "%d\t%d\t", key_data->key_data_type[0],
   1229 	     key_data->key_data_length[0]);
   1230      for(c = 0; c < key_data->key_data_length[0]; c++)
   1231 	  fprintf(f, "%02x ",
   1232 		  key_data->key_data_contents[0][c]);
   1233 }
   1234 
   1235 /*
   1236  * Function: print_princ
   1237  *
   1238  * Purpose: output osa_adb_princ_ent data in a human
   1239  *	    readable format (which is a format suitable for
   1240  *	    ovsec_adm_import consumption)
   1241  *
   1242  * Arguments:
   1243  *	data		(input) pointer to a structure containing a FILE *
   1244  *			        and a record counter.
   1245  *	entry		(input) entry to get dumped.
   1246  * 	<return value>	void
   1247  *
   1248  * Requires:
   1249  *	nuttin
   1250  *
   1251  * Effects:
   1252  *	writes data to the specified file pointerp.
   1253  *
   1254  * Modifies:
   1255  *	nuttin
   1256  *
   1257  */
   1258 static krb5_error_code dump_ov_princ(krb5_pointer ptr, krb5_db_entry *kdb)
   1259 {
   1260     char *princstr;
   1261     int	x, y, foundcrc;
   1262     struct dump_args *arg;
   1263     krb5_tl_data tl_data;
   1264     osa_princ_ent_rec adb;
   1265     XDR xdrs;
   1266 
   1267     arg = (struct dump_args *) ptr;
   1268     /*
   1269      * XXX Currently, lookup_tl_data always returns zero; it sets
   1270      * tl_data->tl_data_length to zero if the type isn't found.
   1271      * This should be fixed...
   1272      */
   1273     /*
   1274      * XXX Should this function do nothing for a principal with no
   1275      * admin data, or print a record of "default" values?   See
   1276      * comment in server_kdb.c to help decide.
   1277      */
   1278     tl_data.tl_data_type = KRB5_TL_KADM_DATA;
   1279     if (krb5_dbe_lookup_tl_data(arg->kcontext, kdb, &tl_data)
   1280 	|| (tl_data.tl_data_length == 0))
   1281 	 return 0;
   1282 
   1283     memset(&adb, 0, sizeof(adb));
   1284     xdrmem_create(&xdrs, (const caddr_t) tl_data.tl_data_contents,
   1285 		  tl_data.tl_data_length, XDR_DECODE);
   1286     if (! xdr_osa_princ_ent_rec(&xdrs, &adb)) {
   1287 	 xdr_destroy(&xdrs);
   1288 	 return(KADM5_XDR_FAILURE);
   1289     }
   1290     xdr_destroy(&xdrs);
   1291 
   1292     krb5_unparse_name(arg->kcontext, kdb->princ, &princstr);
   1293     fprintf(arg->ofile, "princ\t%s\t", princstr);
   1294     if(adb.policy == NULL)
   1295 	fputc('\t', arg->ofile);
   1296     else
   1297 	fprintf(arg->ofile, "%s\t", adb.policy);
   1298     fprintf(arg->ofile, "%lx\t%d\t%d\t%d", adb.aux_attributes,
   1299 	    adb.old_key_len,adb.old_key_next, adb.admin_history_kvno);
   1300 
   1301     for (x = 0; x < adb.old_key_len; x++) {
   1302 	 foundcrc = 0;
   1303 	 for (y = 0; y < adb.old_keys[x].n_key_data; y++) {
   1304 	      krb5_key_data *key_data = &adb.old_keys[x].key_data[y];
   1305 
   1306 	      if (key_data->key_data_type[0] != ENCTYPE_DES_CBC_CRC)
   1307 		   continue;
   1308 	      if (foundcrc) {
   1309 				fprintf(stderr,
   1310 				    gettext("Warning!  Multiple DES-CBC-CRC "
   1311 					"keys for principal %s; skipping "
   1312 					"duplicates.\n"),
   1313 			   princstr);
   1314 		   continue;
   1315 	      }
   1316 	      foundcrc++;
   1317 
   1318 	      fputc('\t', arg->ofile);
   1319 	      print_key_data(arg->ofile, key_data);
   1320 	 }
   1321 	 if (!foundcrc)
   1322 			fprintf(stderr,
   1323 			    gettext("Warning!  No DES-CBC-CRC key "
   1324 				"for principal %s, cannot generate "
   1325 				"OV-compatible record; skipping\n"),
   1326 		      princstr);
   1327     }
   1328 
   1329     fputc('\n', arg->ofile);
   1330     free(princstr);
   1331     return 0;
   1332 }
   1333 
   1334 /*
   1335  * usage is:
   1336  *	dump_db [-i] [-old] [-b6] [-b7] [-ov] [-verbose] [-mkey_convert]
   1337  *		[-new_mkey_file mkey_file] [-rev] [-recurse]
   1338  *		[filename [principals...]]
   1339  */
   1340 void
   1341 dump_db(argc, argv)
   1342     int		argc;
   1343     char	**argv;
   1344 {
   1345     FILE		*f;
   1346     struct dump_args	arglist;
   1347 /* Solaris Kerberos */
   1348 #if 0
   1349     char		*programname;
   1350 #endif
   1351     char		*ofile;
   1352     krb5_error_code	kret, retval;
   1353     dump_version	*dump;
   1354     int			aindex;
   1355     krb5_boolean	locked;
   1356     char		*new_mkey_file = 0;
   1357     bool_t		dump_sno = FALSE;
   1358     kdb_log_context	*log_ctx;
   1359     /* Solaris Kerberos: adding support for -rev/recurse flags */
   1360     int			db_arg_index = 0;
   1361     char		*db_args[3] = {NULL, NULL, NULL};
   1362 
   1363     /*
   1364      * Parse the arguments.
   1365      */
   1366 /* Solaris Kerberos */
   1367 #if 0
   1368     programname = argv[0];
   1369     if (strrchr(programname, (int) '/'))
   1370 	programname = strrchr(argv[0], (int) '/') + 1;
   1371 #endif
   1372     ofile = (char *) NULL;
   1373     dump = &r1_3_version;
   1374     arglist.verbose = 0;
   1375     new_mkey_file = 0;
   1376     mkey_convert = 0;
   1377     backwards = 0;
   1378     recursive = 0;
   1379     log_ctx = util_context->kdblog_context;
   1380 
   1381     /*
   1382      * Parse the qualifiers.
   1383      */
   1384     for (aindex = 1; aindex < argc; aindex++) {
   1385 	if (!strcmp(argv[aindex], oldoption))
   1386 	     dump = &old_version;
   1387 	else if (!strcmp(argv[aindex], b6option))
   1388 	     dump = &beta6_version;
   1389 	else if (!strcmp(argv[aindex], b7option))
   1390 	     dump = &beta7_version;
   1391 	else if (!strcmp(argv[aindex], ovoption))
   1392 	     dump = &ov_version;
   1393 	else if (!strcmp(argv[aindex], ipropoption)) {
   1394 			if (log_ctx && log_ctx->iproprole) {
   1395 				dump = &iprop_version;
   1396 				/*
   1397 				 * dump_sno is used to indicate if the serial
   1398 				 * # should be populated in the output
   1399 				 * file to be used later by iprop for updating
   1400 				 * the slave's update log when loading
   1401 				 */
   1402 				dump_sno = TRUE;
   1403 			} else {
   1404 				fprintf(stderr, gettext("Iprop not enabled\n"));
   1405 				exit_status++;
   1406 				return;
   1407 			}
   1408 		}
   1409 	else if (!strcmp(argv[aindex], verboseoption))
   1410 	    arglist.verbose++;
   1411 	else if (!strcmp(argv[aindex], "-mkey_convert"))
   1412 	    mkey_convert = 1;
   1413 	else if (!strcmp(argv[aindex], "-new_mkey_file")) {
   1414 	    new_mkey_file = argv[++aindex];
   1415 	    mkey_convert = 1;
   1416         } else if (!strcmp(argv[aindex], "-rev")) {
   1417 	    /* Solaris Kerberos: adding support for -rev/recurse flags */
   1418 	    /* hack to pass args to db specific plugin */
   1419 	    db_args[db_arg_index++] = "rev";
   1420 	} else if (!strcmp(argv[aindex], "-recurse")) {
   1421 	    /* hack to pass args to db specific plugin */
   1422 	    db_args[db_arg_index++] = "recurse";
   1423 	} else
   1424 	    break;
   1425     }
   1426 
   1427     arglist.names = (char **) NULL;
   1428     arglist.nnames = 0;
   1429     if (aindex < argc) {
   1430 	ofile = argv[aindex];
   1431 	aindex++;
   1432 	if (aindex < argc) {
   1433 	    arglist.names = &argv[aindex];
   1434 	    arglist.nnames = argc - aindex;
   1435 	}
   1436     }
   1437 
   1438     /*
   1439      * Make sure the database is open.  The policy database only has
   1440      * to be opened if we try a dump that uses it.
   1441      */
   1442     if (!dbactive) {
   1443 	/* Solaris Kerberos */
   1444 	com_err(progname, 0, Err_no_database); /* Solaris Kerberos */
   1445 	exit_status++;
   1446 	return;
   1447     }
   1448 
   1449     /*
   1450      * If we're doing a master key conversion, set up for it.
   1451      */
   1452     if (mkey_convert) {
   1453 	    if (!valid_master_key) {
   1454 		    /* TRUE here means read the keyboard, but only once */
   1455 		    retval = krb5_db_fetch_mkey(util_context,
   1456 						master_princ,
   1457 						global_params.enctype,
   1458 						TRUE, FALSE,
   1459 						(char *) NULL, 0,
   1460 						&master_key);
   1461 		    if (retval) {
   1462 			    /* Solaris Kerberos */
   1463 			    com_err(progname, retval,
   1464 				    gettext("while reading master key"));
   1465 			    exit(1);
   1466 		    }
   1467 		    retval = krb5_db_verify_master_key(util_context,
   1468 						       master_princ,
   1469 						       &master_key);
   1470 		    if (retval) {
   1471 			    /* Solaris Kerberos */
   1472 			    com_err(progname, retval,
   1473 				    gettext("while verifying master key"));
   1474 			    exit(1);
   1475 		    }
   1476 	    }
   1477 	    if (!new_mkey_file)
   1478 		    printf(gettext("Please enter new master key....\n"));
   1479 	    if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
   1480 					     global_params.enctype,
   1481 					     (new_mkey_file == 0) ?
   1482 					        (krb5_boolean) 1 : 0,
   1483 					     TRUE,
   1484 					     new_mkey_file, 0,
   1485 					     &new_master_key))) {
   1486 		    /* Solaris Kerberos */
   1487 		    com_err(progname, retval,
   1488 			    gettext("while reading new master key"));
   1489 		    exit(1);
   1490 	    }
   1491     }
   1492 
   1493     kret = 0;
   1494     locked = 0;
   1495     if (ofile && strcmp(ofile, "-")) {
   1496 	/*
   1497 	 * Discourage accidental dumping to filenames beginning with '-'.
   1498 	 */
   1499 	if (ofile[0] == '-')
   1500 	    usage();
   1501 	/*
   1502 	 * Make sure that we don't open and truncate on the fopen,
   1503 	 * since that may hose an on-going kprop process.
   1504 	 *
   1505 	 * We could also control this by opening for read and
   1506 	 * write, doing an flock with LOCK_EX, and then
   1507 	 * truncating the file once we have gotten the lock,
   1508 	 * but that would involve more OS dependencies than I
   1509 	 * want to get into.
   1510 	 */
   1511 	unlink(ofile);
   1512 	if (!(f = fopen(ofile, "w"))) {
   1513 			/* Solaris Kerberos */
   1514 			fprintf(stderr, gettext(ofopen_error),
   1515 		    progname, ofile, error_message(errno));
   1516 	    exit_status++;
   1517 	    return;
   1518        }
   1519 	if ((kret = krb5_lock_file(util_context,
   1520 				   fileno(f),
   1521 				   KRB5_LOCKMODE_EXCLUSIVE))) {
   1522 			/* Solaris Kerberos */
   1523 			fprintf(stderr, gettext(oflock_error),
   1524 		    progname, ofile, error_message(kret));
   1525 	    exit_status++;
   1526 	}
   1527 	else
   1528 	    locked = 1;
   1529     } else {
   1530 	f = stdout;
   1531     }
   1532     if (f && !(kret)) {
   1533 	/* Solaris Kerberos */
   1534 	arglist.programname = progname;
   1535 	arglist.ofile = f;
   1536 	arglist.kcontext = util_context;
   1537 	fprintf(arglist.ofile, "%s", dump->header);
   1538 
   1539 	if (dump_sno) {
   1540 		if (ulog_map(util_context, &global_params, FKCOMMAND)) {
   1541 			/* Solaris Kerberos */
   1542 			fprintf(stderr,
   1543 			    gettext("%s: Could not map log\n"), progname);
   1544 			exit_status++;
   1545 			goto error;
   1546 		}
   1547 
   1548 		/*
   1549 		 * We grab the lock twice (once again in the iterator call),
   1550 		 * but that's ok since the lock func handles incr locks held.
   1551 		 */
   1552 		if (krb5_db_lock(util_context, KRB5_LOCKMODE_SHARED)) {
   1553 			/* Solaris Kerberos */
   1554 			fprintf(stderr,
   1555 			    gettext("%s: Couldn't grab lock\n"), progname);
   1556 			exit_status++;
   1557 			goto error;
   1558 		}
   1559 
   1560 		fprintf(f, " %u", log_ctx->ulog->kdb_last_sno);
   1561 		fprintf(f, " %u", log_ctx->ulog->kdb_last_time.seconds);
   1562 		fprintf(f, " %u", log_ctx->ulog->kdb_last_time.useconds);
   1563 	}
   1564 
   1565 	if (dump->header[strlen(dump->header)-1] != '\n')
   1566 	     fputc('\n', arglist.ofile);
   1567 
   1568 	/* Solaris Kerberos: adding support for -rev/recurse flags */
   1569 	/* don't pass in db_args if there aren't any */
   1570 	if ((kret = krb5_db_iterate(util_context,
   1571 				    NULL,
   1572 				    dump->dump_princ,
   1573 				    (krb5_pointer) &arglist,
   1574 				    db_arg_index > 0 ? (char **)&db_args : NULL))) {
   1575 	     /* Solaris Kerberos */
   1576 	     fprintf(stderr, dumprec_err,
   1577 		     progname, dump->name, error_message(kret));
   1578 	     exit_status++;
   1579 		if (dump_sno)
   1580 			(void) krb5_db_unlock(util_context);
   1581 	}
   1582 	if (dump->dump_policy &&
   1583 	    (kret = krb5_db_iter_policy( util_context, "*", dump->dump_policy,
   1584 					 &arglist))) {
   1585 	     /* Solaris Kerberos */
   1586 	     fprintf(stderr, gettext(dumprec_err),
   1587 		progname, dump->name,
   1588 		     error_message(kret));
   1589 	     exit_status++;
   1590 	}
   1591 
   1592 error:
   1593 	if (ofile && f != stdout && !exit_status) {
   1594 	    if (locked) {
   1595 		(void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
   1596 		locked = 0;
   1597 	    }
   1598 	    fclose(f);
   1599 	    update_ok_file(ofile);
   1600 	}
   1601     }
   1602     if (locked)
   1603 	(void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
   1604 }
   1605 
   1606 /*
   1607  * Read a string of bytes while counting the number of lines passed.
   1608  */
   1609 static int
   1610 read_string(f, buf, len, lp)
   1611     FILE	*f;
   1612     char	*buf;
   1613     int		len;
   1614     int		*lp;
   1615 {
   1616     int c;
   1617     int i, retval;
   1618 
   1619     retval = 0;
   1620     for (i=0; i<len; i++) {
   1621 	c = fgetc(f);
   1622 	if (c < 0) {
   1623 	    retval = 1;
   1624 	    break;
   1625 	}
   1626 	if (c == '\n')
   1627 	    (*lp)++;
   1628 	buf[i] = (char) c;
   1629     }
   1630     buf[len] = '\0';
   1631     return(retval);
   1632 }
   1633 
   1634 /*
   1635  * Read a string of two character representations of bytes.
   1636  */
   1637 static int
   1638 read_octet_string(f, buf, len)
   1639     FILE	*f;
   1640     krb5_octet	*buf;
   1641     int		len;
   1642 {
   1643     int c;
   1644     int i, retval;
   1645 
   1646     retval = 0;
   1647     for (i=0; i<len; i++) {
   1648 	if (fscanf(f, "%02x", &c) != 1) {
   1649 	    retval = 1;
   1650 	    break;
   1651 	}
   1652 	buf[i] = (krb5_octet) c;
   1653     }
   1654     return(retval);
   1655 }
   1656 
   1657 /*
   1658  * Find the end of an old format record.
   1659  */
   1660 static void
   1661 find_record_end(f, fn, lineno)
   1662     FILE	*f;
   1663     char	*fn;
   1664     int		lineno;
   1665 {
   1666     int	ch;
   1667 
   1668     if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
   1669 		fprintf(stderr, gettext(trash_end_fmt), fn, lineno);
   1670 	while (ch != '\n') {
   1671 	    putc(ch, stderr);
   1672 	    ch = fgetc(f);
   1673 	}
   1674 	putc(ch, stderr);
   1675     }
   1676 }
   1677 
   1678 #if 0
   1679 /*
   1680  * update_tl_data()	- Generate the tl_data entries.
   1681  */
   1682 static krb5_error_code
   1683 update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
   1684     krb5_context	kcontext;
   1685     krb5_db_entry	*dbentp;
   1686     krb5_principal	mod_name;
   1687     krb5_timestamp	mod_date;
   1688     krb5_timestamp	last_pwd_change;
   1689 {
   1690     krb5_error_code	kret;
   1691 
   1692     kret = 0 ;
   1693 
   1694     /*
   1695      * Handle modification principal.
   1696      */
   1697     if (mod_name) {
   1698 	krb5_tl_mod_princ	mprinc;
   1699 
   1700 	memset(&mprinc, 0, sizeof(mprinc));
   1701 	if (!(kret = krb5_copy_principal(kcontext,
   1702 					 mod_name,
   1703 					 &mprinc.mod_princ))) {
   1704 	    mprinc.mod_date = mod_date;
   1705 	    kret = krb5_dbe_encode_mod_princ_data(kcontext,
   1706 						  &mprinc,
   1707 						  dbentp);
   1708 	}
   1709 	if (mprinc.mod_princ)
   1710 	    krb5_free_principal(kcontext, mprinc.mod_princ);
   1711     }
   1712 
   1713     /*
   1714      * Handle last password change.
   1715      */
   1716     if (!kret) {
   1717 	krb5_tl_data	*pwchg;
   1718 	krb5_boolean	linked;
   1719 
   1720 	/* Find a previously existing entry */
   1721 	for (pwchg = dbentp->tl_data;
   1722 	     (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
   1723 	     pwchg = pwchg->tl_data_next);
   1724 
   1725 	/* Check to see if we found one. */
   1726 	linked = 0;
   1727 	if (!pwchg) {
   1728 	    /* No, allocate a new one */
   1729 	    if ((pwchg = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
   1730 		memset(pwchg, 0, sizeof(krb5_tl_data));
   1731 		if (!(pwchg->tl_data_contents =
   1732 		      (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
   1733 		    free(pwchg);
   1734 		    pwchg = (krb5_tl_data *) NULL;
   1735 		}
   1736 		else {
   1737 		    pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
   1738 		    pwchg->tl_data_length =
   1739 			(krb5_int16) sizeof(krb5_timestamp);
   1740 		}
   1741 	    }
   1742 	}
   1743 	else
   1744 	    linked = 1;
   1745 
   1746 	/* Do we have an entry? */
   1747 	if (pwchg && pwchg->tl_data_contents) {
   1748 	    /* Encode it */
   1749 	    krb5_kdb_encode_int32(last_pwd_change, pwchg->tl_data_contents);
   1750 	    /* Link it in if necessary */
   1751 	    if (!linked) {
   1752 		pwchg->tl_data_next = dbentp->tl_data;
   1753 		dbentp->tl_data = pwchg;
   1754 		dbentp->n_tl_data++;
   1755 	    }
   1756 	}
   1757 	else
   1758 	    kret = ENOMEM;
   1759     }
   1760 
   1761     return(kret);
   1762 }
   1763 #endif
   1764 
   1765 /*
   1766  * process_k5beta_record()	- Handle a dump record in old format.
   1767  *
   1768  * Returns -1 for end of file, 0 for success and 1 for failure.
   1769  */
   1770 static int
   1771 process_k5beta_record(fname, kcontext, filep, verbose, linenop)
   1772     char		*fname;
   1773     krb5_context	kcontext;
   1774     FILE		*filep;
   1775     int			verbose;
   1776     int			*linenop;
   1777 {
   1778     int			nmatched;
   1779     int			retval;
   1780     krb5_db_entry	dbent;
   1781     int			name_len, mod_name_len, key_len;
   1782     int			alt_key_len, salt_len, alt_salt_len;
   1783     char		*name;
   1784     char		*mod_name;
   1785     int			tmpint1, tmpint2, tmpint3;
   1786     int			error;
   1787     const char		*try2read;
   1788     int			i;
   1789     krb5_key_data	*pkey, *akey;
   1790     krb5_timestamp	last_pwd_change, mod_date;
   1791     krb5_principal	mod_princ;
   1792     krb5_error_code	kret;
   1793     krb5_octet 		*shortcopy1 = NULL; /* SUNWresync121 memleak fix */
   1794     krb5_octet 		*shortcopy2 = NULL;
   1795 
   1796     try2read = (char *) NULL;
   1797     (*linenop)++;
   1798     retval = 1;
   1799     memset((char *)&dbent, 0, sizeof(dbent));
   1800 
   1801     /* Make sure we've got key_data entries */
   1802     if (krb5_dbe_create_key_data(kcontext, &dbent) ||
   1803 	krb5_dbe_create_key_data(kcontext, &dbent)) {
   1804 	krb5_db_free_principal(kcontext, &dbent, 1);
   1805 	return(1);
   1806     }
   1807     pkey = &dbent.key_data[0];
   1808     akey = &dbent.key_data[1];
   1809 
   1810     /*
   1811      * Match the sizes.  6 tokens to match.
   1812      */
   1813     nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
   1814 		      &name_len, &mod_name_len, &key_len,
   1815 		      &alt_key_len, &salt_len, &alt_salt_len);
   1816     if (nmatched == 6) {
   1817         pkey->key_data_length[0] = key_len;
   1818 	akey->key_data_length[0] = alt_key_len;
   1819 	pkey->key_data_length[1] = salt_len;
   1820 	akey->key_data_length[1] = alt_salt_len;
   1821 	name = (char *) NULL;
   1822 	mod_name = (char *) NULL;
   1823 	/*
   1824 	 * Get the memory for the variable length fields.
   1825 	 */
   1826 	if ((name = (char *) malloc((size_t) (name_len + 1))) &&
   1827 	    (mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
   1828 	    (!key_len ||
   1829 	     (pkey->key_data_contents[0] =
   1830 	      (krb5_octet *) malloc((size_t) (key_len + 1)))) &&
   1831 	    (!alt_key_len ||
   1832 	     (akey->key_data_contents[0] =
   1833 	      (krb5_octet *) malloc((size_t) (alt_key_len + 1)))) &&
   1834 	    (!salt_len ||
   1835 	     (pkey->key_data_contents[1] =
   1836 	      (krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
   1837 	    (!alt_salt_len ||
   1838 	     (akey->key_data_contents[1] =
   1839 	      (krb5_octet *) malloc((size_t) (alt_salt_len + 1))))
   1840 	    ) {
   1841 	    error = 0;
   1842 
   1843 	    /* Read the principal name */
   1844 	    if (read_string(filep, name, name_len, linenop)) {
   1845 		try2read = read_name_string;
   1846 		error++;
   1847 	    }
   1848 	    /* Read the key type */
   1849 	    if (!error && (fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
   1850 		try2read = read_key_type;
   1851 		error++;
   1852 	    }
   1853 	    pkey->key_data_type[0] = tmpint1;
   1854 	    /* Read the old format key */
   1855 	    if (!error && read_octet_string(filep,
   1856 					    pkey->key_data_contents[0],
   1857 					    pkey->key_data_length[0])) {
   1858 		try2read = read_key_data;
   1859 		error++;
   1860 	    }
   1861 	    /* convert to a new format key */
   1862 	    /* the encrypted version is stored as the unencrypted key length
   1863 	       (4 bytes, MSB first) followed by the encrypted key. */
   1864 	    if ((pkey->key_data_length[0] > 4)
   1865 		&& (pkey->key_data_contents[0][0] == 0)
   1866 		&& (pkey->key_data_contents[0][1] == 0)) {
   1867 	      /* this really does look like an old key, so drop and swap */
   1868 	      /* the *new* length is 2 bytes, LSB first, sigh. */
   1869 	      size_t shortlen = pkey->key_data_length[0]-4+2;
   1870 	      krb5_octet *origdata = pkey->key_data_contents[0];
   1871 
   1872 		    shortcopy1 = (krb5_octet *) malloc(shortlen);
   1873 		    if (shortcopy1) {
   1874 			shortcopy1[0] = origdata[3];
   1875 			shortcopy1[1] = origdata[2];
   1876 			memcpy(shortcopy1 + 2, origdata + 4, shortlen - 2);
   1877 			free(origdata);
   1878 			pkey->key_data_length[0] = shortlen;
   1879 			pkey->key_data_contents[0] = shortcopy1;
   1880 		    } else {
   1881 			fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
   1882 			error++;
   1883 		    }
   1884 	    }
   1885 
   1886 	    /* Read principal attributes */
   1887 	    if (!error && (fscanf(filep,
   1888 				  "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t",
   1889 				  &tmpint1, &dbent.max_life,
   1890 				  &dbent.max_renewable_life,
   1891 				  &tmpint2, &dbent.expiration,
   1892 				  &dbent.pw_expiration, &last_pwd_change,
   1893 				  &dbent.last_success, &dbent.last_failed,
   1894 				  &tmpint3) != 10)) {
   1895 		try2read = read_pr_data1;
   1896 		error++;
   1897 	    }
   1898 	    pkey->key_data_kvno = tmpint1;
   1899 	    dbent.fail_auth_count = tmpint3;
   1900 	    /* Read modifier name */
   1901 	    if (!error && read_string(filep,
   1902 				      mod_name,
   1903 				      mod_name_len,
   1904 				      linenop)) {
   1905 		try2read = read_mod_name;
   1906 		error++;
   1907 	    }
   1908 	    /* Read second set of attributes */
   1909 	    if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
   1910 				  &mod_date, &dbent.attributes,
   1911 				  &tmpint1) != 3)) {
   1912 		try2read = read_pr_data2;
   1913 		error++;
   1914 	    }
   1915 	    pkey->key_data_type[1] = tmpint1;
   1916 	    /* Read salt data */
   1917 	    if (!error && read_octet_string(filep,
   1918 					    pkey->key_data_contents[1],
   1919 					    pkey->key_data_length[1])) {
   1920 		try2read = read_salt_data;
   1921 		error++;
   1922 	    }
   1923 	    /* Read alternate key type */
   1924 	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
   1925 		try2read = read_akey_type;
   1926 		error++;
   1927 	    }
   1928 	    akey->key_data_type[0] = tmpint1;
   1929 	    /* Read alternate key */
   1930 	    if (!error && read_octet_string(filep,
   1931 					    akey->key_data_contents[0],
   1932 					    akey->key_data_length[0])) {
   1933 		try2read = read_akey_data;
   1934 		error++;
   1935 	    }
   1936 
   1937 	    /* convert to a new format key */
   1938 	    /* the encrypted version is stored as the unencrypted key length
   1939 	       (4 bytes, MSB first) followed by the encrypted key. */
   1940 	    if ((akey->key_data_length[0] > 4)
   1941 		&& (akey->key_data_contents[0][0] == 0)
   1942 		&& (akey->key_data_contents[0][1] == 0)) {
   1943 	      /* this really does look like an old key, so drop and swap */
   1944 	      /* the *new* length is 2 bytes, LSB first, sigh. */
   1945 	      size_t shortlen = akey->key_data_length[0]-4+2;
   1946 
   1947 		    krb5_octet *origdata = akey->key_data_contents[0];
   1948 
   1949 		    shortcopy2 = (krb5_octet *) malloc(shortlen);
   1950 		    if (shortcopy2) {
   1951 			shortcopy2[0] = origdata[3];
   1952 			shortcopy2[1] = origdata[2];
   1953 			memcpy(shortcopy2 + 2,
   1954 			    origdata + 4, shortlen - 2);
   1955 			free(origdata);
   1956 			akey->key_data_length[0] = shortlen;
   1957 			akey->key_data_contents[0] = shortcopy2;
   1958 		    } else {
   1959 			fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
   1960 			error++;
   1961 		    }
   1962 	    }
   1963 
   1964 	    /* Read alternate salt type */
   1965 	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
   1966 		try2read = read_asalt_type;
   1967 		error++;
   1968 	    }
   1969 	    akey->key_data_type[1] = tmpint1;
   1970 	    /* Read alternate salt data */
   1971 	    if (!error && read_octet_string(filep,
   1972 					    akey->key_data_contents[1],
   1973 					    akey->key_data_length[1])) {
   1974 		try2read = read_asalt_data;
   1975 		error++;
   1976 	    }
   1977 	    /* Read expansion data - discard it */
   1978 	    if (!error) {
   1979 		for (i=0; i<8; i++) {
   1980 		    if (fscanf(filep, "\t%u", &tmpint1) != 1) {
   1981 			try2read = read_exp_data;
   1982 			error++;
   1983 			break;
   1984 		    }
   1985 		}
   1986 		if (!error)
   1987 		    find_record_end(filep, fname, *linenop);
   1988 	    }
   1989 
   1990 	    /*
   1991 	     * If no error, then we're done reading.  Now parse the names
   1992 	     * and store the database dbent.
   1993 	     */
   1994 	    if (!error) {
   1995 		if (!(kret = krb5_parse_name(kcontext,
   1996 					     name,
   1997 					     &dbent.princ))) {
   1998 		    if (!(kret = krb5_parse_name(kcontext,
   1999 						 mod_name,
   2000 						 &mod_princ))) {
   2001 			if (!(kret =
   2002 			      krb5_dbe_update_mod_princ_data(kcontext,
   2003 							     &dbent,
   2004 							     mod_date,
   2005 							     mod_princ)) &&
   2006 			    !(kret =
   2007 			      krb5_dbe_update_last_pwd_change(kcontext,
   2008 							      &dbent,
   2009 							      last_pwd_change))) {
   2010 			    int one = 1;
   2011 
   2012 			    dbent.len = KRB5_KDB_V1_BASE_LENGTH;
   2013 			    pkey->key_data_ver = (pkey->key_data_type[1] || pkey->key_data_length[1]) ?
   2014 				2 : 1;
   2015 			    akey->key_data_ver = (akey->key_data_type[1] || akey->key_data_length[1]) ?
   2016 				2 : 1;
   2017 			    if ((pkey->key_data_type[0] ==
   2018 				 akey->key_data_type[0]) &&
   2019 				(pkey->key_data_type[1] ==
   2020 				 akey->key_data_type[1]))
   2021 				dbent.n_key_data--;
   2022 			    else if ((akey->key_data_type[0] == 0)
   2023 				     && (akey->key_data_length[0] == 0)
   2024 				     && (akey->key_data_type[1] == 0)
   2025 				     && (akey->key_data_length[1] == 0))
   2026 			        dbent.n_key_data--;
   2027 
   2028 			    dbent.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
   2029 				KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_KEY_DATA |
   2030 				KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
   2031 				KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT;
   2032 
   2033 			    if ((kret = krb5_db_put_principal(kcontext,
   2034 							      &dbent,
   2035 							      &one)) ||
   2036 				(one != 1)) {
   2037 				fprintf(stderr, gettext(store_err_fmt),
   2038 					fname, *linenop, name,
   2039 					error_message(kret));
   2040 				error++;
   2041 			    }
   2042 			    else {
   2043 				if (verbose)
   2044 				    fprintf(stderr,
   2045 							gettext(add_princ_fmt),
   2046 							name);
   2047 				retval = 0;
   2048 			    }
   2049 			    dbent.n_key_data = 2;
   2050 			}
   2051 			krb5_free_principal(kcontext, mod_princ);
   2052 		    }
   2053 		    else {
   2054 			fprintf(stderr,
   2055 				gettext(parse_err_fmt),
   2056 				fname, *linenop, mod_name,
   2057 				error_message(kret));
   2058 			error++;
   2059 		    }
   2060 		}
   2061 		else {
   2062 		    fprintf(stderr, gettext(parse_err_fmt),
   2063 			    fname, *linenop, name, error_message(kret));
   2064 		    error++;
   2065 		}
   2066 	    }
   2067 	    else {
   2068 	    fprintf(stderr, gettext(no_mem_fmt), fname, *linenop, try2read);
   2069 	    }
   2070 	}
   2071 	else {
   2072 		fprintf(stderr, gettext(read_err_fmt), fname, *linenop);
   2073 	}
   2074 
   2075 	krb5_db_free_principal(kcontext, &dbent, 1);
   2076 	if (mod_name)
   2077 	    free(mod_name);
   2078 	if (name)
   2079 	    free(name);
   2080     }
   2081     else {
   2082 	if (nmatched != EOF)
   2083 	   fprintf(stderr, gettext(rhead_err_fmt),
   2084 		fname, *linenop);
   2085 	else
   2086 	    retval = -1;
   2087     }
   2088 
   2089     if (shortcopy1)
   2090 	free(shortcopy1);
   2091     if (shortcopy2)
   2092 	free(shortcopy2);
   2093 
   2094     return(retval);
   2095 }
   2096 
   2097 /*
   2098  * process_k5beta6_record()	- Handle a dump record in krb5b6 format.
   2099  *
   2100  * Returns -1 for end of file, 0 for success and 1 for failure.
   2101  */
   2102 static int
   2103 process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
   2104     char		*fname;
   2105     krb5_context	kcontext;
   2106     FILE		*filep;
   2107     int			verbose;
   2108     int			*linenop;
   2109 {
   2110     int			retval;
   2111     krb5_db_entry	dbentry;
   2112     krb5_int32		t1, t2, t3, t4, t5, t6, t7, t8, t9;
   2113     int			nread;
   2114     int			error;
   2115     int			i, j, one;
   2116     char		*name;
   2117     krb5_key_data	*kp, *kdatap;
   2118     krb5_tl_data	**tlp, *tl;
   2119     krb5_octet 		*op;
   2120     krb5_error_code	kret;
   2121     const char		*try2read;
   2122 
   2123     try2read = (char *) NULL;
   2124     memset((char *) &dbentry, 0, sizeof(dbentry));
   2125     (*linenop)++;
   2126     retval = 1;
   2127     name = (char *) NULL;
   2128     kp = (krb5_key_data *) NULL;
   2129     op = (krb5_octet *) NULL;
   2130     error = 0;
   2131     kret = 0;
   2132     nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
   2133     if (nread == 5) {
   2134 	/* Get memory for flattened principal name */
   2135 	if (!(name = (char *) malloc((size_t) t2 + 1)))
   2136 	    error++;
   2137 
   2138 	/* Get memory for and form tagged data linked list */
   2139 	tlp = &dbentry.tl_data;
   2140 	for (i=0; i<t3; i++) {
   2141 	    if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
   2142 		memset(*tlp, 0, sizeof(krb5_tl_data));
   2143 		tlp = &((*tlp)->tl_data_next);
   2144 		dbentry.n_tl_data++;
   2145 	    }
   2146 	    else {
   2147 		error++;
   2148 		break;
   2149 	    }
   2150 	}
   2151 
   2152 	/* Get memory for key list */
   2153 	if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
   2154 						  (t4*sizeof(krb5_key_data)))))
   2155 	    error++;
   2156 
   2157 	/* Get memory for extra data */
   2158 	if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
   2159 	    error++;
   2160 
   2161 	if (!error) {
   2162 	    dbentry.len = t1;
   2163 	    dbentry.n_key_data = t4;
   2164 	    dbentry.e_length = t5;
   2165 	    if (kp) {
   2166 		memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
   2167 		dbentry.key_data = kp;
   2168 		kp = (krb5_key_data *) NULL;
   2169 	    }
   2170 	    if (op) {
   2171 		memset(op, 0, (size_t) t5);
   2172 		dbentry.e_data = op;
   2173 		op = (krb5_octet *) NULL;
   2174 	    }
   2175 
   2176 	    /* Read in and parse the principal name */
   2177 	    if (!read_string(filep, name, t2, linenop) &&
   2178 		!(kret = krb5_parse_name(kcontext, name, &dbentry.princ))) {
   2179 
   2180 		/* Get the fixed principal attributes */
   2181 		nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
   2182 			       &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
   2183 		if (nread == 8) {
   2184 		    dbentry.attributes = (krb5_flags) t2;
   2185 		    dbentry.max_life = (krb5_deltat) t3;
   2186 		    dbentry.max_renewable_life = (krb5_deltat) t4;
   2187 		    dbentry.expiration = (krb5_timestamp) t5;
   2188 		    dbentry.pw_expiration = (krb5_timestamp) t6;
   2189 		    dbentry.last_success = (krb5_timestamp) t7;
   2190 		    dbentry.last_failed = (krb5_timestamp) t8;
   2191 		    dbentry.fail_auth_count = (krb5_kvno) t9;
   2192 		    dbentry.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
   2193 			KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
   2194 			KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
   2195 			KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT;
   2196 		} else {
   2197 		    try2read = read_nint_data;
   2198 		    error++;
   2199 		}
   2200 
   2201 		/*
   2202 		 * Get the tagged data.
   2203 		 *
   2204 		 * Really, this code ought to discard tl data types
   2205 		 * that it knows are special to the current version
   2206 		 * and were not supported in the previous version.
   2207 		 * But it's a pain to implement that here, and doing
   2208 		 * it at dump time has almost as good an effect, so
   2209 		 * that's what I did.  [krb5-admin/89]
   2210 		 */
   2211 		if (!error && dbentry.n_tl_data) {
   2212 		    for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
   2213 			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
   2214 			if (nread == 2) {
   2215 			    tl->tl_data_type = (krb5_int16) t1;
   2216 			    tl->tl_data_length = (krb5_int16) t2;
   2217 			    if (tl->tl_data_length) {
   2218 				if (!(tl->tl_data_contents =
   2219 				      (krb5_octet *) malloc((size_t) t2+1)) ||
   2220 				    read_octet_string(filep,
   2221 						      tl->tl_data_contents,
   2222 						      t2)) {
   2223 				    try2read = read_tcontents;
   2224 				    error++;
   2225 				    break;
   2226 				}
   2227 				/* test to set mask fields */
   2228 				if (t1 == KRB5_TL_KADM_DATA) {
   2229 				    XDR xdrs;
   2230 				    osa_princ_ent_rec osa_princ_ent;
   2231 
   2232 				    /*
   2233 				     * Assuming aux_attributes will always be
   2234 				     * there
   2235 				     */
   2236 				    dbentry.mask |= KADM5_AUX_ATTRIBUTES;
   2237 
   2238 				    /* test for an actual policy reference */
   2239 				    memset(&osa_princ_ent, 0, sizeof(osa_princ_ent));
   2240 				    xdrmem_create(&xdrs, (char *)tl->tl_data_contents,
   2241 					    tl->tl_data_length, XDR_DECODE);
   2242 				    if (xdr_osa_princ_ent_rec(&xdrs, &osa_princ_ent) &&
   2243 					    (osa_princ_ent.aux_attributes & KADM5_POLICY) &&
   2244 					    osa_princ_ent.policy != NULL) {
   2245 
   2246 					dbentry.mask |= KADM5_POLICY;
   2247 					kdb_free_entry(NULL, NULL, &osa_princ_ent);
   2248 				    }
   2249 				    xdr_destroy(&xdrs);
   2250 				}
   2251 			    }
   2252 			    else {
   2253 				/* Should be a null field */
   2254 				nread = fscanf(filep, "%d", &t9);
   2255 				if ((nread != 1) || (t9 != -1)) {
   2256 				    error++;
   2257 				    try2read = read_tcontents;
   2258 				    break;
   2259 				}
   2260 			    }
   2261 			}
   2262 			else {
   2263 			    try2read = read_ttypelen;
   2264 			    error++;
   2265 			    break;
   2266 			}
   2267 		    }
   2268 		    if (!error)
   2269 			dbentry.mask |= KADM5_TL_DATA;
   2270 		}
   2271 
   2272 		/* Get the key data */
   2273 		if (!error && dbentry.n_key_data) {
   2274 		    for (i=0; !error && (i<dbentry.n_key_data); i++) {
   2275 			kdatap = &dbentry.key_data[i];
   2276 			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
   2277 			if (nread == 2) {
   2278 			    kdatap->key_data_ver = (krb5_int16) t1;
   2279 			    kdatap->key_data_kvno = (krb5_int16) t2;
   2280 
   2281 			    for (j=0; j<t1; j++) {
   2282 				nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
   2283 				if (nread == 2) {
   2284 				    kdatap->key_data_type[j] = t3;
   2285 				    kdatap->key_data_length[j] = t4;
   2286 				    if (t4) {
   2287 					if (!(kdatap->key_data_contents[j] =
   2288 					      (krb5_octet *)
   2289 					      malloc((size_t) t4+1)) ||
   2290 					    read_octet_string(filep,
   2291 							      kdatap->key_data_contents[j],
   2292 							      t4)) {
   2293 					    try2read = read_kcontents;
   2294 					    error++;
   2295 					    break;
   2296 					}
   2297 				    }
   2298 				    else {
   2299 					/* Should be a null field */
   2300 					nread = fscanf(filep, "%d", &t9);
   2301 					if ((nread != 1) || (t9 != -1)) {
   2302 					    error++;
   2303 					    try2read = read_kcontents;
   2304 					    break;
   2305 					}
   2306 				    }
   2307 				}
   2308 				else {
   2309 				    try2read = read_ktypelen;
   2310 				    error++;
   2311 				    break;
   2312 				}
   2313 			    }
   2314 			}
   2315 		    }
   2316 		    if (!error)
   2317 			dbentry.mask |= KADM5_KEY_DATA;
   2318 		}
   2319 
   2320 		/* Get the extra data */
   2321 		if (!error && dbentry.e_length) {
   2322 		    if (read_octet_string(filep,
   2323 					  dbentry.e_data,
   2324 					  (int) dbentry.e_length)) {
   2325 			try2read = read_econtents;
   2326 			error++;
   2327 		    }
   2328 		}
   2329 		else {
   2330 		    nread = fscanf(filep, "%d", &t9);
   2331 		    if ((nread != 1) || (t9 != -1)) {
   2332 			error++;
   2333 			try2read = read_econtents;
   2334 		    }
   2335 		}
   2336 
   2337 		/* Finally, find the end of the record. */
   2338 		if (!error)
   2339 		    find_record_end(filep, fname, *linenop);
   2340 
   2341 		/*
   2342 		 * We have either read in all the data or choked.
   2343 		 */
   2344 		if (!error) {
   2345 		    one = 1;
   2346 		    if ((kret = krb5_db_put_principal(kcontext,
   2347 						      &dbentry,
   2348 						      &one))) {
   2349 						fprintf(stderr,
   2350 						    gettext(store_err_fmt),
   2351 				fname, *linenop,
   2352 				name, error_message(kret));
   2353 		    }
   2354 		    else {
   2355 			if (verbose)
   2356 							fprintf(stderr,
   2357 							    gettext(
   2358 								add_princ_fmt),
   2359 							    name);
   2360 			retval = 0;
   2361 		    }
   2362 		}
   2363 		else {
   2364 					fprintf(stderr, gettext(read_err_fmt),
   2365 					    fname, *linenop, try2read);
   2366 		}
   2367 	    }
   2368 	    else {
   2369 		if (kret)
   2370 					fprintf(stderr, gettext(parse_err_fmt),
   2371 			    fname, *linenop, name, error_message(kret));
   2372 		else
   2373 		    fprintf(stderr, gettext(no_mem_fmt),
   2374 						fname, *linenop);
   2375 	    }
   2376 	}
   2377 	else {
   2378 	    fprintf(stderr,
   2379 				gettext(rhead_err_fmt), fname, *linenop);
   2380 	}
   2381 
   2382 	if (op)
   2383 	    free(op);
   2384 	if (kp)
   2385 	    free(kp);
   2386 	if (name)
   2387 	    free(name);
   2388 	krb5_db_free_principal(kcontext, &dbentry, 1);
   2389     }
   2390     else {
   2391 	if (nread == EOF)
   2392 	    retval = -1;
   2393     }
   2394     return(retval);
   2395 }
   2396 
   2397 static int
   2398 process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
   2399     char		*fname;
   2400     krb5_context	kcontext;
   2401     FILE		*filep;
   2402     int			verbose;
   2403     int			*linenop;
   2404     void *pol_db;
   2405 {
   2406     osa_policy_ent_rec rec;
   2407     char namebuf[1024];
   2408     int nread, ret;
   2409 
   2410     (*linenop)++;
   2411     rec.name = namebuf;
   2412 
   2413     nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
   2414 		   &rec.pw_min_life, &rec.pw_max_life,
   2415 		   &rec.pw_min_length, &rec.pw_min_classes,
   2416 		   &rec.pw_history_num, &rec.policy_refcnt);
   2417     if (nread == EOF)
   2418 	 return -1;
   2419     else if (nread != 7) {
   2420 		fprintf(stderr,
   2421 		    gettext("cannot parse policy on line %d (%d read)\n"),
   2422 		 *linenop, nread);
   2423 	 return 1;
   2424     }
   2425 
   2426     if ((ret = krb5_db_create_policy(kcontext, &rec))) {
   2427 	 if (ret &&
   2428 	     ((ret = krb5_db_put_policy(kcontext, &rec)))) {
   2429 	      fprintf(stderr, gettext("cannot create policy on line %d: %s\n"),
   2430 		      *linenop, error_message(ret));
   2431 	      return 1;
   2432 	 }
   2433     }
   2434     if (verbose)
   2435 		fprintf(stderr, gettext("created policy %s\n"), rec.name);
   2436 
   2437     return 0;
   2438 }
   2439 
   2440 /*
   2441  * process_k5beta7_record()	- Handle a dump record in krb5b7 format.
   2442  *
   2443  * Returns -1 for end of file, 0 for success and 1 for failure.
   2444  */
   2445 static int
   2446 process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
   2447     char		*fname;
   2448     krb5_context	kcontext;
   2449     FILE		*filep;
   2450     int			verbose;
   2451     int			*linenop;
   2452 {
   2453      int nread;
   2454      char rectype[100];
   2455 
   2456      nread = fscanf(filep, "%100s\t", rectype);
   2457      if (nread == EOF)
   2458 	  return -1;
   2459      else if (nread != 1)
   2460 	  return 1;
   2461      if (strcmp(rectype, "princ") == 0)
   2462 	  process_k5beta6_record(fname, kcontext, filep, verbose,
   2463 				 linenop);
   2464      else if (strcmp(rectype, "policy") == 0)
   2465 	  process_k5beta7_policy(fname, kcontext, filep, verbose,
   2466 				 linenop);
   2467      else {
   2468 		fprintf(stderr,
   2469 		    gettext("unknown record type \"%s\" on line %d\n"),
   2470 		  rectype, *linenop);
   2471 	  return 1;
   2472      }
   2473 
   2474      return 0;
   2475 }
   2476 
   2477 /*
   2478  * process_ov_record()	- Handle a dump record in OpenV*Secure 1.0 format.
   2479  *
   2480  * Returns -1 for end of file, 0 for success and 1 for failure.
   2481  */
   2482 static int
   2483 process_ov_record(fname, kcontext, filep, verbose, linenop)
   2484     char		*fname;
   2485     krb5_context	kcontext;
   2486     FILE		*filep;
   2487     int			verbose;
   2488     int			*linenop;
   2489 {
   2490      int nread;
   2491      char rectype[100];
   2492 
   2493      nread = fscanf(filep, "%100s\t", rectype);
   2494      if (nread == EOF)
   2495 	  return -1;
   2496      else if (nread != 1)
   2497 	  return 1;
   2498      if (strcmp(rectype, "princ") == 0)
   2499 	  process_ov_principal(fname, kcontext, filep, verbose,
   2500 			       linenop);
   2501      else if (strcmp(rectype, "policy") == 0)
   2502 	  process_k5beta7_policy(fname, kcontext, filep, verbose,
   2503 				 linenop);
   2504      else if (strcmp(rectype, "End") == 0)
   2505 	  return -1;
   2506      else {
   2507 		fprintf(stderr,
   2508 		    gettext("unknown record type \"%s\" on line %d\n"),
   2509 		  rectype, *linenop);
   2510 	  return 1;
   2511      }
   2512 
   2513      return 0;
   2514 }
   2515 
   2516 /*
   2517  * restore_dump()	- Restore the database from any version dump file.
   2518  */
   2519 static int
   2520 restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
   2521     char		*programname;
   2522     krb5_context	kcontext;
   2523     char		*dumpfile;
   2524     FILE		*f;
   2525     int			verbose;
   2526     dump_version	*dump;
   2527 {
   2528     int		error;
   2529     int		lineno;
   2530 
   2531     error = 0;
   2532     lineno = 1;
   2533 
   2534     /*
   2535      * Process the records.
   2536      */
   2537     while (!(error = (*dump->load_record)(dumpfile,
   2538 					  kcontext,
   2539 					  f,
   2540 					  verbose,
   2541 					  &lineno)))
   2542 	 ;
   2543     if (error != -1)
   2544 		fprintf(stderr, gettext(err_line_fmt),
   2545 		    programname, lineno, dumpfile);
   2546     else
   2547 	 error = 0;
   2548 
   2549     return(error);
   2550 }
   2551 
   2552 /*
   2553  * Usage: load_db [-i] [-old] [-ov] [-b6] [-b7] [-verbose] [-update] [-hash]
   2554  *		filename
   2555  */
   2556 void
   2557 load_db(argc, argv)
   2558     int		argc;
   2559     char	**argv;
   2560 {
   2561     kadm5_config_params newparams;
   2562     krb5_error_code	kret;
   2563     krb5_context	kcontext;
   2564     FILE		*f;
   2565     extern char		*optarg;
   2566     extern int		optind;
   2567 /* Solaris Kerberos */
   2568 #if 0
   2569     char		*programname;
   2570 #endif
   2571     char		*dumpfile;
   2572     char		*dbname;
   2573     char		*dbname_tmp;
   2574     char		buf[BUFSIZ];
   2575     dump_version	*load;
   2576     int			update, verbose;
   2577     krb5_int32		crflags;
   2578     int			aindex;
   2579     bool_t		add_update = TRUE;
   2580     char		iheader[MAX_HEADER];
   2581     uint32_t		caller, last_sno, last_seconds, last_useconds;
   2582     kdb_log_context	*log_ctx;
   2583     int			db_locked = 0;
   2584 
   2585     /*
   2586      * Parse the arguments.
   2587      */
   2588 /* Solaris Kerberos */
   2589 #if 0
   2590     programname = argv[0];
   2591     if (strrchr(programname, (int) '/'))
   2592 	programname = strrchr(argv[0], (int) '/') + 1;
   2593 #endif
   2594     dumpfile = (char *) NULL;
   2595     dbname = global_params.dbname;
   2596     load = NULL;
   2597     update = 0;
   2598     verbose = 0;
   2599     crflags = KRB5_KDB_CREATE_BTREE;
   2600     exit_status = 0;
   2601     dbname_tmp = (char *) NULL;
   2602     log_ctx = util_context->kdblog_context;
   2603 
   2604     for (aindex = 1; aindex < argc; aindex++) {
   2605 	if (!strcmp(argv[aindex], oldoption))
   2606 	     load = &old_version;
   2607 	else if (!strcmp(argv[aindex], b6option))
   2608 	     load = &beta6_version;
   2609 	else if (!strcmp(argv[aindex], b7option))
   2610 	     load = &beta7_version;
   2611 	else if (!strcmp(argv[aindex], ovoption))
   2612 	     load = &ov_version;
   2613 	else if (!strcmp(argv[aindex], ipropoption)) {
   2614 			if (log_ctx && log_ctx->iproprole) {
   2615 				load = &iprop_version;
   2616 				add_update = FALSE;
   2617 			} else {
   2618 				fprintf(stderr, gettext("Iprop not enabled\n"));
   2619 				exit_status++;
   2620 				return;
   2621 			}
   2622 		}
   2623 	else if (!strcmp(argv[aindex], verboseoption))
   2624 	    verbose = 1;
   2625 	else if (!strcmp(argv[aindex], updateoption))
   2626 	    update = 1;
   2627 	else if (!strcmp(argv[aindex], hashoption)) {
   2628 	    if (!add_db_arg("hash=true")) {
   2629 		com_err(progname, ENOMEM, "while parsing command arguments\n");
   2630 		exit(1);
   2631 	    }
   2632 	} else
   2633 	    break;
   2634     }
   2635     if ((argc - aindex) != 1) {
   2636 	usage();
   2637 	return;
   2638     }
   2639     dumpfile = argv[aindex];
   2640 
   2641     if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
   2642 				       strlen(dump_tmptrail)+1))) {
   2643 		/* Solaris Kerberos */
   2644 		fprintf(stderr, gettext(no_name_mem_fmt), progname);
   2645 	exit_status++;
   2646 	return;
   2647     }
   2648     strcpy(dbname_tmp, dbname);
   2649     strcat(dbname_tmp, dump_tmptrail);
   2650 
   2651     /*
   2652      * Initialize the Kerberos context and error tables.
   2653      */
   2654     if ((kret = kadm5_init_krb5_context(&kcontext))) {
   2655 	/* Solaris Kerberos */
   2656 	fprintf(stderr, gettext(ctx_err_fmt), progname);
   2657 	free(dbname_tmp);
   2658 	exit_status++;
   2659 	return;
   2660     }
   2661 
   2662     if( (kret = krb5_set_default_realm(kcontext, util_context->default_realm)) )
   2663     {
   2664 	/* Solaris Kerberos */
   2665 	fprintf(stderr, gettext("%s: Unable to set the default realm\n"), progname);
   2666 	free(dbname_tmp);
   2667 	exit_status++;
   2668 	return;
   2669     }
   2670     if (log_ctx && log_ctx->iproprole)
   2671 	kcontext->kdblog_context = (void *)log_ctx;
   2672     /*
   2673      * Open the dumpfile
   2674      */
   2675     if (dumpfile) {
   2676 	if ((f = fopen(dumpfile, "r")) == NULL) {
   2677 			/* Solaris Kerberos */
   2678 			fprintf(stderr, gettext(dfile_err_fmt),
   2679 			    progname, dumpfile,
   2680 		     error_message(errno));
   2681 	     exit_status++;
   2682 	     return;
   2683 	}
   2684 	if ((kret = krb5_lock_file(kcontext, fileno(f),
   2685 				   KRB5_LOCKMODE_SHARED))) {
   2686 	     /* Solaris Kerberos */
   2687 	     fprintf(stderr, gettext("%s: Cannot lock %s: %s\n"), progname,
   2688 		     dumpfile, error_message(errno));
   2689 	     exit_status++;
   2690 	     return;
   2691 	}
   2692     } else
   2693 	f = stdin;
   2694 
   2695     /*
   2696      * Auto-detect dump version if we weren't told, verify if we
   2697      * were told.
   2698      */
   2699     fgets(buf, sizeof(buf), f);
   2700     if (load) {
   2701 	 /* only check what we know; some headers only contain a prefix */
   2702 	 if (strncmp(buf, load->header, strlen(load->header)) != 0) {
   2703 			/* Solaris Kerberos */
   2704 			fprintf(stderr, gettext(head_bad_fmt), progname, dumpfile);
   2705 	      exit_status++;
   2706 	      if (dumpfile) fclose(f);
   2707 	      return;
   2708 	 }
   2709     } else {
   2710 	 /* perhaps this should be in an array, but so what? */
   2711 	 if (strcmp(buf, old_version.header) == 0)
   2712 	      load = &old_version;
   2713 	 else if (strcmp(buf, beta6_version.header) == 0)
   2714 	      load = &beta6_version;
   2715 	 else if (strcmp(buf, beta7_version.header) == 0)
   2716 	      load = &beta7_version;
   2717 	 else if (strcmp(buf, r1_3_version.header) == 0)
   2718 	      load = &r1_3_version;
   2719 	 else if (strncmp(buf, ov_version.header,
   2720 			  strlen(ov_version.header)) == 0)
   2721 	      load = &ov_version;
   2722 	 else {
   2723 			/* Solaris Kerberos */
   2724 			fprintf(stderr, gettext(head_bad_fmt),
   2725 				progname, dumpfile);
   2726 	      exit_status++;
   2727 	      if (dumpfile) fclose(f);
   2728 	      return;
   2729 	 }
   2730     }
   2731     if (load->updateonly && !update) {
   2732 		/* Solaris Kerberos */
   2733 		fprintf(stderr,
   2734 		    gettext("%s: dump version %s can only "
   2735 			"be loaded with the -update flag\n"),
   2736 		    progname, load->name);
   2737 	 exit_status++;
   2738 	 return;
   2739     }
   2740 
   2741     /*
   2742      * Cons up params for the new databases.  If we are not in update
   2743      * mode, we create an alternate database and then promote it to
   2744      * be the live db.
   2745      */
   2746     newparams = global_params;
   2747     if (! update) {
   2748 	 newparams.mask |= KADM5_CONFIG_DBNAME;
   2749 	 newparams.dbname = dbname_tmp;
   2750 
   2751 	 if ((kret = kadm5_get_config_params(kcontext, 1,
   2752 					     &newparams, &newparams))) {
   2753 	      /* Solaris Kerberos */
   2754 	      com_err(progname, kret,
   2755 			    gettext("while retreiving new "
   2756 				"configuration parameters"));
   2757 	      exit_status++;
   2758 	      return;
   2759 	 }
   2760 
   2761 	 if (!add_db_arg("temporary")) {
   2762 	     com_err(progname, ENOMEM, "computing parameters for database");
   2763 	     exit(1);
   2764 	 }
   2765     }
   2766 
   2767     /*
   2768      * If not an update restoration, create the database. otherwise open
   2769      */
   2770     if (!update) {
   2771 	if((kret = krb5_db_create(kcontext, db5util_db_args))) {
   2772 	    const char *emsg = krb5_get_error_message(kcontext, kret);
   2773 	    /*
   2774 	     * See if something (like DAL KDB plugin) has set a specific error
   2775 	     * message and use that otherwise use default.
   2776 	     */
   2777 
   2778 	    if (emsg != NULL) {
   2779 		/* Solaris Kerberos */
   2780 		fprintf(stderr, "%s: %s\n", progname, emsg);
   2781 		krb5_free_error_message (kcontext, emsg);
   2782 	    } else {
   2783 		/* Solaris Kerberos */
   2784 		fprintf(stderr, dbcreaterr_fmt,
   2785 			progname, dbname, error_message(kret));
   2786 	    }
   2787 	    exit_status++;
   2788 	    kadm5_free_config_params(kcontext, &newparams);
   2789 	    if (dumpfile) fclose(f);
   2790 	    return;
   2791 	}
   2792     }
   2793     else {
   2794 	    /*
   2795 	     * Initialize the database.
   2796 	     */
   2797 	    if ((kret = krb5_db_open(kcontext, db5util_db_args,
   2798 				     KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
   2799 		const char *emsg = krb5_get_error_message(kcontext, kret);
   2800 		/*
   2801 		 * See if something (like DAL KDB plugin) has set a specific
   2802 		 * error message and use that otherwise use default.
   2803 		 */
   2804 
   2805 		if (emsg != NULL) {
   2806 		    /* Solaris Kerberos */
   2807 		    fprintf(stderr, "%s: %s\n", progname, emsg);
   2808 		    krb5_free_error_message (kcontext, emsg);
   2809 		} else {
   2810 		    /* Solaris Kerberos */
   2811 		    fprintf(stderr, dbinit_err_fmt,
   2812 			    progname, error_message(kret));
   2813 		}
   2814 		exit_status++;
   2815 		goto error;
   2816 	    }
   2817     }
   2818 
   2819 
   2820     /*
   2821      * If an update restoration, make sure the db is left unusable if
   2822      * the update fails.
   2823      */
   2824     if ((kret = krb5_db_lock(kcontext, update?KRB5_DB_LOCKMODE_PERMANENT: KRB5_DB_LOCKMODE_EXCLUSIVE))) {
   2825 	/*
   2826 	 * Ignore a not supported error since there is nothing to do about it
   2827 	 * anyway.
   2828 	 */
   2829 	if (kret != KRB5_PLUGIN_OP_NOTSUPP) {
   2830 	    /* Solaris Kerberos */
   2831 	    fprintf(stderr, gettext("%s: %s while permanently locking database\n"),
   2832 		    progname, error_message(kret));
   2833 	    exit_status++;
   2834 	    goto error;
   2835 	}
   2836     }
   2837     else
   2838 	db_locked = 1;
   2839 
   2840 	if (log_ctx && log_ctx->iproprole) {
   2841 		if (add_update)
   2842 			caller = FKCOMMAND;
   2843 		else
   2844 			caller = FKPROPD;
   2845 
   2846 		if (ulog_map(kcontext, &global_params, caller)) {
   2847 			/* Solaris Kerberos */
   2848 			fprintf(stderr,
   2849 				gettext("%s: Could not map log\n"),
   2850 				progname);
   2851 			exit_status++;
   2852 			goto error;
   2853 		}
   2854 
   2855 		/*
   2856 		 * We don't want to take out the ulog out from underneath
   2857 		 * kadmind so we reinit the header log.
   2858 		 *
   2859 		 * We also don't want to add to the update log since we
   2860 		 * are doing a whole sale replace of the db, because:
   2861 		 * 	we could easily exceed # of update entries
   2862 		 * 	we could implicity delete db entries during a replace
   2863 		 *	no advantage in incr updates when entire db is replaced
   2864 		 */
   2865 		if (!update) {
   2866                         memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
   2867 
   2868                         log_ctx->ulog->kdb_hmagic = KDB_HMAGIC;
   2869                         log_ctx->ulog->db_version_num = KDB_VERSION;
   2870                         log_ctx->ulog->kdb_state = KDB_STABLE;
   2871                         log_ctx->ulog->kdb_block = ULOG_BLOCK;
   2872 
   2873 			log_ctx->iproprole = IPROP_NULL;
   2874 
   2875 			if (!add_update) {
   2876 				sscanf(buf, "%s %u %u %u", iheader, &last_sno,
   2877 					&last_seconds, &last_useconds);
   2878 
   2879 				log_ctx->ulog->kdb_last_sno = last_sno;
   2880 				log_ctx->ulog->kdb_last_time.seconds =
   2881 				    last_seconds;
   2882 				log_ctx->ulog->kdb_last_time.useconds =
   2883 				    last_useconds;
   2884 			}
   2885 		}
   2886 	}
   2887 
   2888     /* Solaris Kerberos */
   2889     if (restore_dump(progname, kcontext, (dumpfile) ? dumpfile : stdin_name,
   2890 		     f, verbose, load)) {
   2891 	 /* Solaris Kerberos */
   2892 	 fprintf(stderr, gettext(restfail_fmt),
   2893 		 progname, load->name);
   2894 	 exit_status++;
   2895     }
   2896 
   2897     if (!update && load->create_kadm5 &&
   2898 	((kret = kadm5_create_magic_princs(&newparams, kcontext)))) {
   2899 	 /* error message printed by create_magic_princs */
   2900 	 exit_status++;
   2901     }
   2902 
   2903     if (db_locked && (kret = krb5_db_unlock(kcontext))) {
   2904 	 /* change this error? */
   2905 		/* Solaris Kerberos */
   2906 		fprintf(stderr, gettext(dbunlockerr_fmt),
   2907 		 progname, dbname, error_message(kret));
   2908 	 exit_status++;
   2909     }
   2910 
   2911 #if 0
   2912     if ((kret = krb5_db_fini(kcontext))) {
   2913 		/* Solaris Kerberos */
   2914 		fprintf(stderr, gettext(close_err_fmt),
   2915 		 progname, error_message(kret));
   2916 	 exit_status++;
   2917     }
   2918 #endif
   2919 
   2920     /* close policy db below */
   2921 
   2922     if (exit_status == 0 && !update) {
   2923 	kret = krb5_db_promote(kcontext, db5util_db_args);
   2924 	/*
   2925 	 * Ignore a not supported error since there is nothing to do about it
   2926 	 * anyway.
   2927 	 */
   2928 	if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) {
   2929 	    /* Solaris Kerberos */
   2930 	    fprintf(stderr, gettext("%s: cannot make newly loaded database live (%s)\n"),
   2931 		    progname, error_message(kret));
   2932 	    exit_status++;
   2933 	}
   2934     }
   2935 
   2936 error:
   2937     /*
   2938      * If not an update: if there was an error, destroy the temp database,
   2939      * otherwise rename it into place.
   2940      *
   2941      * If an update: if there was no error, unlock the database.
   2942      */
   2943     if (!update) {
   2944 	 if (exit_status) {
   2945 	      kret = krb5_db_destroy(kcontext, db5util_db_args);
   2946 	      /*
   2947 	       * Ignore a not supported error since there is nothing to do about
   2948 	       * it anyway.
   2949 	       */
   2950 	      if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) {
   2951 		   /* Solaris Kerberos */
   2952 		   fprintf(stderr, gettext(dbdelerr_fmt),
   2953 			   progname, dbname, error_message(kret));
   2954 		   exit_status++;
   2955 	      }
   2956 	 }
   2957     }
   2958 
   2959     if (dumpfile) {
   2960 	 (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK);
   2961 	 fclose(f);
   2962     }
   2963 
   2964     if (dbname_tmp)
   2965 	 free(dbname_tmp);
   2966     krb5_free_context(kcontext);
   2967 }
   2968