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