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