xref: /illumos-gate/usr/src/cmd/krb5/kadmin/dbutil/dump.c (revision 2654012f83cec5dc15b61dfe3e4a4915f186e7a6)
1 /*
2  * Copyright 2008 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     /* Solaris Kerberos: adding support for -rev/recurse flags */
1359     int			db_arg_index = 0;
1360     char		*db_args[3] = {NULL, NULL, NULL};
1361 
1362     /*
1363      * Parse the arguments.
1364      */
1365     programname = argv[0];
1366     if (strrchr(programname, (int) '/'))
1367 	programname = strrchr(argv[0], (int) '/') + 1;
1368     ofile = (char *) NULL;
1369     dump = &r1_3_version;
1370     arglist.verbose = 0;
1371     new_mkey_file = 0;
1372     mkey_convert = 0;
1373     backwards = 0;
1374     recursive = 0;
1375     log_ctx = util_context->kdblog_context;
1376 
1377     /*
1378      * Parse the qualifiers.
1379      */
1380     for (aindex = 1; aindex < argc; aindex++) {
1381 	if (!strcmp(argv[aindex], oldoption))
1382 	     dump = &old_version;
1383 	else if (!strcmp(argv[aindex], b6option))
1384 	     dump = &beta6_version;
1385 	else if (!strcmp(argv[aindex], b7option))
1386 	     dump = &beta7_version;
1387 	else if (!strcmp(argv[aindex], ovoption))
1388 	     dump = &ov_version;
1389 	else if (!strcmp(argv[aindex], ipropoption)) {
1390 			if (log_ctx && log_ctx->iproprole) {
1391 				dump = &iprop_version;
1392 				/*
1393 				 * dump_sno is used to indicate if the serial
1394 				 * # should be populated in the output
1395 				 * file to be used later by iprop for updating
1396 				 * the slave's update log when loading
1397 				 */
1398 				dump_sno = TRUE;
1399 			} else {
1400 				fprintf(stderr, gettext("Iprop not enabled\n"));
1401 				exit_status++;
1402 				return;
1403 			}
1404 		}
1405 	else if (!strcmp(argv[aindex], verboseoption))
1406 	    arglist.verbose++;
1407 	else if (!strcmp(argv[aindex], "-mkey_convert"))
1408 	    mkey_convert = 1;
1409 	else if (!strcmp(argv[aindex], "-new_mkey_file")) {
1410 	    new_mkey_file = argv[++aindex];
1411 	    mkey_convert = 1;
1412         } else if (!strcmp(argv[aindex], "-rev")) {
1413 	    /* Solaris Kerberos: adding support for -rev/recurse flags */
1414 	    /* hack to pass args to db specific plugin */
1415 	    db_args[db_arg_index++] = "rev";
1416 	} else if (!strcmp(argv[aindex], "-recurse")) {
1417 	    /* hack to pass args to db specific plugin */
1418 	    db_args[db_arg_index++] = "recurse";
1419 	} else
1420 	    break;
1421     }
1422 
1423     arglist.names = (char **) NULL;
1424     arglist.nnames = 0;
1425     if (aindex < argc) {
1426 	ofile = argv[aindex];
1427 	aindex++;
1428 	if (aindex < argc) {
1429 	    arglist.names = &argv[aindex];
1430 	    arglist.nnames = argc - aindex;
1431 	}
1432     }
1433 
1434     /*
1435      * Make sure the database is open.  The policy database only has
1436      * to be opened if we try a dump that uses it.
1437      */
1438     if (!dbactive) {
1439 	com_err(argv[0], 0, Err_no_database);
1440 	exit_status++;
1441 	return;
1442     }
1443 
1444     /*
1445      * If we're doing a master key conversion, set up for it.
1446      */
1447     if (mkey_convert) {
1448 	    if (!valid_master_key) {
1449 		    /* TRUE here means read the keyboard, but only once */
1450 		    retval = krb5_db_fetch_mkey(util_context,
1451 						master_princ,
1452 						global_params.enctype,
1453 						TRUE, FALSE,
1454 						(char *) NULL, 0,
1455 						&master_key);
1456 		    if (retval) {
1457 			    com_err(argv[0], retval,
1458 				    gettext("while reading master key"));
1459 			    exit(1);
1460 		    }
1461 		    retval = krb5_db_verify_master_key(util_context,
1462 						       master_princ,
1463 						       &master_key);
1464 		    if (retval) {
1465 			    com_err(argv[0], retval,
1466 				    gettext("while verifying master key"));
1467 			    exit(1);
1468 		    }
1469 	    }
1470 	    if (!new_mkey_file)
1471 		    printf(gettext("Please enter new master key....\n"));
1472 	    if ((retval = krb5_db_fetch_mkey(util_context, master_princ,
1473 					     global_params.enctype,
1474 					     (new_mkey_file == 0) ?
1475 					        (krb5_boolean) 1 : 0,
1476 					     TRUE,
1477 					     new_mkey_file, 0,
1478 					     &new_master_key))) {
1479 		    com_err(argv[0], retval,
1480 			    gettext("while reading new master key"));
1481 		    exit(1);
1482 	    }
1483     }
1484 
1485     kret = 0;
1486     locked = 0;
1487     if (ofile && strcmp(ofile, "-")) {
1488 	/*
1489 	 * Discourage accidental dumping to filenames beginning with '-'.
1490 	 */
1491 	if (ofile[0] == '-')
1492 	    usage();
1493 	/*
1494 	 * Make sure that we don't open and truncate on the fopen,
1495 	 * since that may hose an on-going kprop process.
1496 	 *
1497 	 * We could also control this by opening for read and
1498 	 * write, doing an flock with LOCK_EX, and then
1499 	 * truncating the file once we have gotten the lock,
1500 	 * but that would involve more OS dependencies than I
1501 	 * want to get into.
1502 	 */
1503 	unlink(ofile);
1504 	if (!(f = fopen(ofile, "w"))) {
1505 			fprintf(stderr, gettext(ofopen_error),
1506 		    programname, ofile, error_message(errno));
1507 	    exit_status++;
1508 	    return;
1509        }
1510 	if ((kret = krb5_lock_file(util_context,
1511 				   fileno(f),
1512 				   KRB5_LOCKMODE_EXCLUSIVE))) {
1513 			fprintf(stderr, gettext(oflock_error),
1514 		    programname, ofile, error_message(kret));
1515 	    exit_status++;
1516 	}
1517 	else
1518 	    locked = 1;
1519     } else {
1520 	f = stdout;
1521     }
1522     if (f && !(kret)) {
1523 	arglist.programname = programname;
1524 	arglist.ofile = f;
1525 	arglist.kcontext = util_context;
1526 	fprintf(arglist.ofile, "%s", dump->header);
1527 
1528 	if (dump_sno) {
1529 		if (ulog_map(util_context, &global_params, FKCOMMAND)) {
1530 			fprintf(stderr,
1531 			    gettext("%s: Could not map log\n"), programname);
1532 			exit_status++;
1533 			goto error;
1534 		}
1535 
1536 		/*
1537 		 * We grab the lock twice (once again in the iterator call),
1538 		 * but that's ok since the lock func handles incr locks held.
1539 		 */
1540 		if (krb5_db_lock(util_context, KRB5_LOCKMODE_SHARED)) {
1541 			fprintf(stderr,
1542 			    gettext("%s: Couldn't grab lock\n"), programname);
1543 			exit_status++;
1544 			goto error;
1545 		}
1546 
1547 		fprintf(f, " %u", log_ctx->ulog->kdb_last_sno);
1548 		fprintf(f, " %u", log_ctx->ulog->kdb_last_time.seconds);
1549 		fprintf(f, " %u", log_ctx->ulog->kdb_last_time.useconds);
1550 	}
1551 
1552 	if (dump->header[strlen(dump->header)-1] != '\n')
1553 	     fputc('\n', arglist.ofile);
1554 
1555 	/* Solaris Kerberos: adding support for -rev/recurse flags */
1556 	/* don't pass in db_args if there aren't any */
1557 	if ((kret = krb5_db_iterate(util_context,
1558 				    NULL,
1559 				    dump->dump_princ,
1560 				    (krb5_pointer) &arglist,
1561 				    db_arg_index > 0 ? (char **)&db_args : NULL))) {
1562 	     fprintf(stderr, dumprec_err,
1563 		     programname, dump->name, error_message(kret));
1564 	     exit_status++;
1565 		if (dump_sno)
1566 			(void) krb5_db_unlock(util_context);
1567 	}
1568 	if (dump->dump_policy &&
1569 	    (kret = krb5_db_iter_policy( util_context, "*", dump->dump_policy,
1570 					 &arglist))) {
1571 	     fprintf(stderr, gettext(dumprec_err),
1572 		programname, dump->name,
1573 		     error_message(kret));
1574 	     exit_status++;
1575 	}
1576 
1577 error:
1578 	if (ofile && f != stdout && !exit_status) {
1579 	    if (locked) {
1580 		(void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
1581 		locked = 0;
1582 	    }
1583 	    fclose(f);
1584 	    update_ok_file(ofile);
1585 	}
1586     }
1587     if (locked)
1588 	(void) krb5_lock_file(util_context, fileno(f), KRB5_LOCKMODE_UNLOCK);
1589 }
1590 
1591 /*
1592  * Read a string of bytes while counting the number of lines passed.
1593  */
1594 static int
1595 read_string(f, buf, len, lp)
1596     FILE	*f;
1597     char	*buf;
1598     int		len;
1599     int		*lp;
1600 {
1601     int c;
1602     int i, retval;
1603 
1604     retval = 0;
1605     for (i=0; i<len; i++) {
1606 	c = fgetc(f);
1607 	if (c < 0) {
1608 	    retval = 1;
1609 	    break;
1610 	}
1611 	if (c == '\n')
1612 	    (*lp)++;
1613 	buf[i] = (char) c;
1614     }
1615     buf[len] = '\0';
1616     return(retval);
1617 }
1618 
1619 /*
1620  * Read a string of two character representations of bytes.
1621  */
1622 static int
1623 read_octet_string(f, buf, len)
1624     FILE	*f;
1625     krb5_octet	*buf;
1626     int		len;
1627 {
1628     int c;
1629     int i, retval;
1630 
1631     retval = 0;
1632     for (i=0; i<len; i++) {
1633 	if (fscanf(f, "%02x", &c) != 1) {
1634 	    retval = 1;
1635 	    break;
1636 	}
1637 	buf[i] = (krb5_octet) c;
1638     }
1639     return(retval);
1640 }
1641 
1642 /*
1643  * Find the end of an old format record.
1644  */
1645 static void
1646 find_record_end(f, fn, lineno)
1647     FILE	*f;
1648     char	*fn;
1649     int		lineno;
1650 {
1651     int	ch;
1652 
1653     if (((ch = fgetc(f)) != ';') || ((ch = fgetc(f)) != '\n')) {
1654 		fprintf(stderr, gettext(trash_end_fmt), fn, lineno);
1655 	while (ch != '\n') {
1656 	    putc(ch, stderr);
1657 	    ch = fgetc(f);
1658 	}
1659 	putc(ch, stderr);
1660     }
1661 }
1662 
1663 #if 0
1664 /*
1665  * update_tl_data()	- Generate the tl_data entries.
1666  */
1667 static krb5_error_code
1668 update_tl_data(kcontext, dbentp, mod_name, mod_date, last_pwd_change)
1669     krb5_context	kcontext;
1670     krb5_db_entry	*dbentp;
1671     krb5_principal	mod_name;
1672     krb5_timestamp	mod_date;
1673     krb5_timestamp	last_pwd_change;
1674 {
1675     krb5_error_code	kret;
1676 
1677     kret = 0 ;
1678 
1679     /*
1680      * Handle modification principal.
1681      */
1682     if (mod_name) {
1683 	krb5_tl_mod_princ	mprinc;
1684 
1685 	memset(&mprinc, 0, sizeof(mprinc));
1686 	if (!(kret = krb5_copy_principal(kcontext,
1687 					 mod_name,
1688 					 &mprinc.mod_princ))) {
1689 	    mprinc.mod_date = mod_date;
1690 	    kret = krb5_dbe_encode_mod_princ_data(kcontext,
1691 						  &mprinc,
1692 						  dbentp);
1693 	}
1694 	if (mprinc.mod_princ)
1695 	    krb5_free_principal(kcontext, mprinc.mod_princ);
1696     }
1697 
1698     /*
1699      * Handle last password change.
1700      */
1701     if (!kret) {
1702 	krb5_tl_data	*pwchg;
1703 	krb5_boolean	linked;
1704 
1705 	/* Find a previously existing entry */
1706 	for (pwchg = dbentp->tl_data;
1707 	     (pwchg) && (pwchg->tl_data_type != KRB5_TL_LAST_PWD_CHANGE);
1708 	     pwchg = pwchg->tl_data_next);
1709 
1710 	/* Check to see if we found one. */
1711 	linked = 0;
1712 	if (!pwchg) {
1713 	    /* No, allocate a new one */
1714 	    if ((pwchg = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
1715 		memset(pwchg, 0, sizeof(krb5_tl_data));
1716 		if (!(pwchg->tl_data_contents =
1717 		      (krb5_octet *) malloc(sizeof(krb5_timestamp)))) {
1718 		    free(pwchg);
1719 		    pwchg = (krb5_tl_data *) NULL;
1720 		}
1721 		else {
1722 		    pwchg->tl_data_type = KRB5_TL_LAST_PWD_CHANGE;
1723 		    pwchg->tl_data_length =
1724 			(krb5_int16) sizeof(krb5_timestamp);
1725 		}
1726 	    }
1727 	}
1728 	else
1729 	    linked = 1;
1730 
1731 	/* Do we have an entry? */
1732 	if (pwchg && pwchg->tl_data_contents) {
1733 	    /* Encode it */
1734 	    krb5_kdb_encode_int32(last_pwd_change, pwchg->tl_data_contents);
1735 	    /* Link it in if necessary */
1736 	    if (!linked) {
1737 		pwchg->tl_data_next = dbentp->tl_data;
1738 		dbentp->tl_data = pwchg;
1739 		dbentp->n_tl_data++;
1740 	    }
1741 	}
1742 	else
1743 	    kret = ENOMEM;
1744     }
1745 
1746     return(kret);
1747 }
1748 #endif
1749 
1750 /*
1751  * process_k5beta_record()	- Handle a dump record in old format.
1752  *
1753  * Returns -1 for end of file, 0 for success and 1 for failure.
1754  */
1755 static int
1756 process_k5beta_record(fname, kcontext, filep, verbose, linenop)
1757     char		*fname;
1758     krb5_context	kcontext;
1759     FILE		*filep;
1760     int			verbose;
1761     int			*linenop;
1762 {
1763     int			nmatched;
1764     int			retval;
1765     krb5_db_entry	dbent;
1766     int			name_len, mod_name_len, key_len;
1767     int			alt_key_len, salt_len, alt_salt_len;
1768     char		*name;
1769     char		*mod_name;
1770     int			tmpint1, tmpint2, tmpint3;
1771     int			error;
1772     const char		*try2read;
1773     int			i;
1774     krb5_key_data	*pkey, *akey;
1775     krb5_timestamp	last_pwd_change, mod_date;
1776     krb5_principal	mod_princ;
1777     krb5_error_code	kret;
1778     krb5_octet 		*shortcopy1 = NULL; /* SUNWresync121 memleak fix */
1779     krb5_octet 		*shortcopy2 = NULL;
1780 
1781     try2read = (char *) NULL;
1782     (*linenop)++;
1783     retval = 1;
1784     memset((char *)&dbent, 0, sizeof(dbent));
1785 
1786     /* Make sure we've got key_data entries */
1787     if (krb5_dbe_create_key_data(kcontext, &dbent) ||
1788 	krb5_dbe_create_key_data(kcontext, &dbent)) {
1789 	krb5_db_free_principal(kcontext, &dbent, 1);
1790 	return(1);
1791     }
1792     pkey = &dbent.key_data[0];
1793     akey = &dbent.key_data[1];
1794 
1795     /*
1796      * Match the sizes.  6 tokens to match.
1797      */
1798     nmatched = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t",
1799 		      &name_len, &mod_name_len, &key_len,
1800 		      &alt_key_len, &salt_len, &alt_salt_len);
1801     if (nmatched == 6) {
1802         pkey->key_data_length[0] = key_len;
1803 	akey->key_data_length[0] = alt_key_len;
1804 	pkey->key_data_length[1] = salt_len;
1805 	akey->key_data_length[1] = alt_salt_len;
1806 	name = (char *) NULL;
1807 	mod_name = (char *) NULL;
1808 	/*
1809 	 * Get the memory for the variable length fields.
1810 	 */
1811 	if ((name = (char *) malloc((size_t) (name_len + 1))) &&
1812 	    (mod_name = (char *) malloc((size_t) (mod_name_len + 1))) &&
1813 	    (!key_len ||
1814 	     (pkey->key_data_contents[0] =
1815 	      (krb5_octet *) malloc((size_t) (key_len + 1)))) &&
1816 	    (!alt_key_len ||
1817 	     (akey->key_data_contents[0] =
1818 	      (krb5_octet *) malloc((size_t) (alt_key_len + 1)))) &&
1819 	    (!salt_len ||
1820 	     (pkey->key_data_contents[1] =
1821 	      (krb5_octet *) malloc((size_t) (salt_len + 1)))) &&
1822 	    (!alt_salt_len ||
1823 	     (akey->key_data_contents[1] =
1824 	      (krb5_octet *) malloc((size_t) (alt_salt_len + 1))))
1825 	    ) {
1826 	    error = 0;
1827 
1828 	    /* Read the principal name */
1829 	    if (read_string(filep, name, name_len, linenop)) {
1830 		try2read = read_name_string;
1831 		error++;
1832 	    }
1833 	    /* Read the key type */
1834 	    if (!error && (fscanf(filep, "\t%d\t", &tmpint1) != 1)) {
1835 		try2read = read_key_type;
1836 		error++;
1837 	    }
1838 	    pkey->key_data_type[0] = tmpint1;
1839 	    /* Read the old format key */
1840 	    if (!error && read_octet_string(filep,
1841 					    pkey->key_data_contents[0],
1842 					    pkey->key_data_length[0])) {
1843 		try2read = read_key_data;
1844 		error++;
1845 	    }
1846 	    /* convert to a new format key */
1847 	    /* the encrypted version is stored as the unencrypted key length
1848 	       (4 bytes, MSB first) followed by the encrypted key. */
1849 	    if ((pkey->key_data_length[0] > 4)
1850 		&& (pkey->key_data_contents[0][0] == 0)
1851 		&& (pkey->key_data_contents[0][1] == 0)) {
1852 	      /* this really does look like an old key, so drop and swap */
1853 	      /* the *new* length is 2 bytes, LSB first, sigh. */
1854 	      size_t shortlen = pkey->key_data_length[0]-4+2;
1855 	      krb5_octet *origdata = pkey->key_data_contents[0];
1856 
1857 		    shortcopy1 = (krb5_octet *) malloc(shortlen);
1858 		    if (shortcopy1) {
1859 			shortcopy1[0] = origdata[3];
1860 			shortcopy1[1] = origdata[2];
1861 			memcpy(shortcopy1 + 2, origdata + 4, shortlen - 2);
1862 			free(origdata);
1863 			pkey->key_data_length[0] = shortlen;
1864 			pkey->key_data_contents[0] = shortcopy1;
1865 		    } else {
1866 			fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
1867 			error++;
1868 		    }
1869 	    }
1870 
1871 	    /* Read principal attributes */
1872 	    if (!error && (fscanf(filep,
1873 				  "\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t",
1874 				  &tmpint1, &dbent.max_life,
1875 				  &dbent.max_renewable_life,
1876 				  &tmpint2, &dbent.expiration,
1877 				  &dbent.pw_expiration, &last_pwd_change,
1878 				  &dbent.last_success, &dbent.last_failed,
1879 				  &tmpint3) != 10)) {
1880 		try2read = read_pr_data1;
1881 		error++;
1882 	    }
1883 	    pkey->key_data_kvno = tmpint1;
1884 	    dbent.fail_auth_count = tmpint3;
1885 	    /* Read modifier name */
1886 	    if (!error && read_string(filep,
1887 				      mod_name,
1888 				      mod_name_len,
1889 				      linenop)) {
1890 		try2read = read_mod_name;
1891 		error++;
1892 	    }
1893 	    /* Read second set of attributes */
1894 	    if (!error && (fscanf(filep, "\t%u\t%u\t%u\t",
1895 				  &mod_date, &dbent.attributes,
1896 				  &tmpint1) != 3)) {
1897 		try2read = read_pr_data2;
1898 		error++;
1899 	    }
1900 	    pkey->key_data_type[1] = tmpint1;
1901 	    /* Read salt data */
1902 	    if (!error && read_octet_string(filep,
1903 					    pkey->key_data_contents[1],
1904 					    pkey->key_data_length[1])) {
1905 		try2read = read_salt_data;
1906 		error++;
1907 	    }
1908 	    /* Read alternate key type */
1909 	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
1910 		try2read = read_akey_type;
1911 		error++;
1912 	    }
1913 	    akey->key_data_type[0] = tmpint1;
1914 	    /* Read alternate key */
1915 	    if (!error && read_octet_string(filep,
1916 					    akey->key_data_contents[0],
1917 					    akey->key_data_length[0])) {
1918 		try2read = read_akey_data;
1919 		error++;
1920 	    }
1921 
1922 	    /* convert to a new format key */
1923 	    /* the encrypted version is stored as the unencrypted key length
1924 	       (4 bytes, MSB first) followed by the encrypted key. */
1925 	    if ((akey->key_data_length[0] > 4)
1926 		&& (akey->key_data_contents[0][0] == 0)
1927 		&& (akey->key_data_contents[0][1] == 0)) {
1928 	      /* this really does look like an old key, so drop and swap */
1929 	      /* the *new* length is 2 bytes, LSB first, sigh. */
1930 	      size_t shortlen = akey->key_data_length[0]-4+2;
1931 
1932 		    krb5_octet *origdata = akey->key_data_contents[0];
1933 
1934 		    shortcopy2 = (krb5_octet *) malloc(shortlen);
1935 		    if (shortcopy2) {
1936 			shortcopy2[0] = origdata[3];
1937 			shortcopy2[1] = origdata[2];
1938 			memcpy(shortcopy2 + 2,
1939 			    origdata + 4, shortlen - 2);
1940 			free(origdata);
1941 			akey->key_data_length[0] = shortlen;
1942 			akey->key_data_contents[0] = shortcopy2;
1943 		    } else {
1944 			fprintf(stderr, gettext(no_mem_fmt), fname, *linenop);
1945 			error++;
1946 		    }
1947 	    }
1948 
1949 	    /* Read alternate salt type */
1950 	    if (!error && (fscanf(filep, "\t%u\t", &tmpint1) != 1)) {
1951 		try2read = read_asalt_type;
1952 		error++;
1953 	    }
1954 	    akey->key_data_type[1] = tmpint1;
1955 	    /* Read alternate salt data */
1956 	    if (!error && read_octet_string(filep,
1957 					    akey->key_data_contents[1],
1958 					    akey->key_data_length[1])) {
1959 		try2read = read_asalt_data;
1960 		error++;
1961 	    }
1962 	    /* Read expansion data - discard it */
1963 	    if (!error) {
1964 		for (i=0; i<8; i++) {
1965 		    if (fscanf(filep, "\t%u", &tmpint1) != 1) {
1966 			try2read = read_exp_data;
1967 			error++;
1968 			break;
1969 		    }
1970 		}
1971 		if (!error)
1972 		    find_record_end(filep, fname, *linenop);
1973 	    }
1974 
1975 	    /*
1976 	     * If no error, then we're done reading.  Now parse the names
1977 	     * and store the database dbent.
1978 	     */
1979 	    if (!error) {
1980 		if (!(kret = krb5_parse_name(kcontext,
1981 					     name,
1982 					     &dbent.princ))) {
1983 		    if (!(kret = krb5_parse_name(kcontext,
1984 						 mod_name,
1985 						 &mod_princ))) {
1986 			if (!(kret =
1987 			      krb5_dbe_update_mod_princ_data(kcontext,
1988 							     &dbent,
1989 							     mod_date,
1990 							     mod_princ)) &&
1991 			    !(kret =
1992 			      krb5_dbe_update_last_pwd_change(kcontext,
1993 							      &dbent,
1994 							      last_pwd_change))) {
1995 			    int one = 1;
1996 
1997 			    dbent.len = KRB5_KDB_V1_BASE_LENGTH;
1998 			    pkey->key_data_ver = (pkey->key_data_type[1] || pkey->key_data_length[1]) ?
1999 				2 : 1;
2000 			    akey->key_data_ver = (akey->key_data_type[1] || akey->key_data_length[1]) ?
2001 				2 : 1;
2002 			    if ((pkey->key_data_type[0] ==
2003 				 akey->key_data_type[0]) &&
2004 				(pkey->key_data_type[1] ==
2005 				 akey->key_data_type[1]))
2006 				dbent.n_key_data--;
2007 			    else if ((akey->key_data_type[0] == 0)
2008 				     && (akey->key_data_length[0] == 0)
2009 				     && (akey->key_data_type[1] == 0)
2010 				     && (akey->key_data_length[1] == 0))
2011 			        dbent.n_key_data--;
2012 
2013 			    dbent.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
2014 				KADM5_MAX_LIFE | KADM5_MAX_RLIFE | KADM5_KEY_DATA |
2015 				KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
2016 				KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT;
2017 
2018 			    if ((kret = krb5_db_put_principal(kcontext,
2019 							      &dbent,
2020 							      &one)) ||
2021 				(one != 1)) {
2022 				fprintf(stderr, gettext(store_err_fmt),
2023 					fname, *linenop, name,
2024 					error_message(kret));
2025 				error++;
2026 			    }
2027 			    else {
2028 				if (verbose)
2029 				    fprintf(stderr,
2030 							gettext(add_princ_fmt),
2031 							name);
2032 				retval = 0;
2033 			    }
2034 			    dbent.n_key_data = 2;
2035 			}
2036 			krb5_free_principal(kcontext, mod_princ);
2037 		    }
2038 		    else {
2039 			fprintf(stderr,
2040 				gettext(parse_err_fmt),
2041 				fname, *linenop, mod_name,
2042 				error_message(kret));
2043 			error++;
2044 		    }
2045 		}
2046 		else {
2047 		    fprintf(stderr, gettext(parse_err_fmt),
2048 			    fname, *linenop, name, error_message(kret));
2049 		    error++;
2050 		}
2051 	    }
2052 	    else {
2053 	    fprintf(stderr, gettext(no_mem_fmt), fname, *linenop, try2read);
2054 	    }
2055 	}
2056 	else {
2057 		fprintf(stderr, gettext(read_err_fmt), fname, *linenop);
2058 	}
2059 
2060 	krb5_db_free_principal(kcontext, &dbent, 1);
2061 	if (mod_name)
2062 	    free(mod_name);
2063 	if (name)
2064 	    free(name);
2065     }
2066     else {
2067 	if (nmatched != EOF)
2068 	   fprintf(stderr, gettext(rhead_err_fmt),
2069 		fname, *linenop);
2070 	else
2071 	    retval = -1;
2072     }
2073 
2074     if (shortcopy1)
2075 	free(shortcopy1);
2076     if (shortcopy2)
2077 	free(shortcopy2);
2078 
2079     return(retval);
2080 }
2081 
2082 /*
2083  * process_k5beta6_record()	- Handle a dump record in krb5b6 format.
2084  *
2085  * Returns -1 for end of file, 0 for success and 1 for failure.
2086  */
2087 static int
2088 process_k5beta6_record(fname, kcontext, filep, verbose, linenop)
2089     char		*fname;
2090     krb5_context	kcontext;
2091     FILE		*filep;
2092     int			verbose;
2093     int			*linenop;
2094 {
2095     int			retval;
2096     krb5_db_entry	dbentry;
2097     krb5_int32		t1, t2, t3, t4, t5, t6, t7, t8, t9;
2098     int			nread;
2099     int			error;
2100     int			i, j, one;
2101     char		*name;
2102     krb5_key_data	*kp, *kdatap;
2103     krb5_tl_data	**tlp, *tl;
2104     krb5_octet 		*op;
2105     krb5_error_code	kret;
2106     const char		*try2read;
2107 
2108     try2read = (char *) NULL;
2109     memset((char *) &dbentry, 0, sizeof(dbentry));
2110     (*linenop)++;
2111     retval = 1;
2112     name = (char *) NULL;
2113     kp = (krb5_key_data *) NULL;
2114     op = (krb5_octet *) NULL;
2115     error = 0;
2116     kret = 0;
2117     nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t", &t1, &t2, &t3, &t4, &t5);
2118     if (nread == 5) {
2119 	/* Get memory for flattened principal name */
2120 	if (!(name = (char *) malloc((size_t) t2 + 1)))
2121 	    error++;
2122 
2123 	/* Get memory for and form tagged data linked list */
2124 	tlp = &dbentry.tl_data;
2125 	for (i=0; i<t3; i++) {
2126 	    if ((*tlp = (krb5_tl_data *) malloc(sizeof(krb5_tl_data)))) {
2127 		memset(*tlp, 0, sizeof(krb5_tl_data));
2128 		tlp = &((*tlp)->tl_data_next);
2129 		dbentry.n_tl_data++;
2130 	    }
2131 	    else {
2132 		error++;
2133 		break;
2134 	    }
2135 	}
2136 
2137 	/* Get memory for key list */
2138 	if (t4 && !(kp = (krb5_key_data *) malloc((size_t)
2139 						  (t4*sizeof(krb5_key_data)))))
2140 	    error++;
2141 
2142 	/* Get memory for extra data */
2143 	if (t5 && !(op = (krb5_octet *) malloc((size_t) t5)))
2144 	    error++;
2145 
2146 	if (!error) {
2147 	    dbentry.len = t1;
2148 	    dbentry.n_key_data = t4;
2149 	    dbentry.e_length = t5;
2150 	    if (kp) {
2151 		memset(kp, 0, (size_t) (t4*sizeof(krb5_key_data)));
2152 		dbentry.key_data = kp;
2153 		kp = (krb5_key_data *) NULL;
2154 	    }
2155 	    if (op) {
2156 		memset(op, 0, (size_t) t5);
2157 		dbentry.e_data = op;
2158 		op = (krb5_octet *) NULL;
2159 	    }
2160 
2161 	    /* Read in and parse the principal name */
2162 	    if (!read_string(filep, name, t2, linenop) &&
2163 		!(kret = krb5_parse_name(kcontext, name, &dbentry.princ))) {
2164 
2165 		/* Get the fixed principal attributes */
2166 		nread = fscanf(filep, "%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t",
2167 			       &t2, &t3, &t4, &t5, &t6, &t7, &t8, &t9);
2168 		if (nread == 8) {
2169 		    dbentry.attributes = (krb5_flags) t2;
2170 		    dbentry.max_life = (krb5_deltat) t3;
2171 		    dbentry.max_renewable_life = (krb5_deltat) t4;
2172 		    dbentry.expiration = (krb5_timestamp) t5;
2173 		    dbentry.pw_expiration = (krb5_timestamp) t6;
2174 		    dbentry.last_success = (krb5_timestamp) t7;
2175 		    dbentry.last_failed = (krb5_timestamp) t8;
2176 		    dbentry.fail_auth_count = (krb5_kvno) t9;
2177 		    dbentry.mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
2178 			KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
2179 			KADM5_PRINC_EXPIRE_TIME | KADM5_LAST_SUCCESS |
2180 			KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT;
2181 		} else {
2182 		    try2read = read_nint_data;
2183 		    error++;
2184 		}
2185 
2186 		/*
2187 		 * Get the tagged data.
2188 		 *
2189 		 * Really, this code ought to discard tl data types
2190 		 * that it knows are special to the current version
2191 		 * and were not supported in the previous version.
2192 		 * But it's a pain to implement that here, and doing
2193 		 * it at dump time has almost as good an effect, so
2194 		 * that's what I did.  [krb5-admin/89]
2195 		 */
2196 		if (!error && dbentry.n_tl_data) {
2197 		    for (tl = dbentry.tl_data; tl; tl = tl->tl_data_next) {
2198 			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
2199 			if (nread == 2) {
2200 			    tl->tl_data_type = (krb5_int16) t1;
2201 			    tl->tl_data_length = (krb5_int16) t2;
2202 			    if (tl->tl_data_length) {
2203 				if (!(tl->tl_data_contents =
2204 				      (krb5_octet *) malloc((size_t) t2+1)) ||
2205 				    read_octet_string(filep,
2206 						      tl->tl_data_contents,
2207 						      t2)) {
2208 				    try2read = read_tcontents;
2209 				    error++;
2210 				    break;
2211 				}
2212 				/* test to set mask fields */
2213 				if (t1 == KRB5_TL_KADM_DATA) {
2214 				    XDR xdrs;
2215 				    osa_princ_ent_rec osa_princ_ent;
2216 
2217 				    /*
2218 				     * Assuming aux_attributes will always be
2219 				     * there
2220 				     */
2221 				    dbentry.mask |= KADM5_AUX_ATTRIBUTES;
2222 
2223 				    /* test for an actual policy reference */
2224 				    memset(&osa_princ_ent, 0, sizeof(osa_princ_ent));
2225 				    xdrmem_create(&xdrs, (char *)tl->tl_data_contents,
2226 					    tl->tl_data_length, XDR_DECODE);
2227 				    if (xdr_osa_princ_ent_rec(&xdrs, &osa_princ_ent) &&
2228 					    (osa_princ_ent.aux_attributes & KADM5_POLICY) &&
2229 					    osa_princ_ent.policy != NULL) {
2230 
2231 					dbentry.mask |= KADM5_POLICY;
2232 					kdb_free_entry(NULL, NULL, &osa_princ_ent);
2233 				    }
2234 				    xdr_destroy(&xdrs);
2235 				}
2236 			    }
2237 			    else {
2238 				/* Should be a null field */
2239 				nread = fscanf(filep, "%d", &t9);
2240 				if ((nread != 1) || (t9 != -1)) {
2241 				    error++;
2242 				    try2read = read_tcontents;
2243 				    break;
2244 				}
2245 			    }
2246 			}
2247 			else {
2248 			    try2read = read_ttypelen;
2249 			    error++;
2250 			    break;
2251 			}
2252 		    }
2253 		    if (!error)
2254 			dbentry.mask |= KADM5_TL_DATA;
2255 		}
2256 
2257 		/* Get the key data */
2258 		if (!error && dbentry.n_key_data) {
2259 		    for (i=0; !error && (i<dbentry.n_key_data); i++) {
2260 			kdatap = &dbentry.key_data[i];
2261 			nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
2262 			if (nread == 2) {
2263 			    kdatap->key_data_ver = (krb5_int16) t1;
2264 			    kdatap->key_data_kvno = (krb5_int16) t2;
2265 
2266 			    for (j=0; j<t1; j++) {
2267 				nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
2268 				if (nread == 2) {
2269 				    kdatap->key_data_type[j] = t3;
2270 				    kdatap->key_data_length[j] = t4;
2271 				    if (t4) {
2272 					if (!(kdatap->key_data_contents[j] =
2273 					      (krb5_octet *)
2274 					      malloc((size_t) t4+1)) ||
2275 					    read_octet_string(filep,
2276 							      kdatap->key_data_contents[j],
2277 							      t4)) {
2278 					    try2read = read_kcontents;
2279 					    error++;
2280 					    break;
2281 					}
2282 				    }
2283 				    else {
2284 					/* Should be a null field */
2285 					nread = fscanf(filep, "%d", &t9);
2286 					if ((nread != 1) || (t9 != -1)) {
2287 					    error++;
2288 					    try2read = read_kcontents;
2289 					    break;
2290 					}
2291 				    }
2292 				}
2293 				else {
2294 				    try2read = read_ktypelen;
2295 				    error++;
2296 				    break;
2297 				}
2298 			    }
2299 			}
2300 		    }
2301 		    if (!error)
2302 			dbentry.mask |= KADM5_KEY_DATA;
2303 		}
2304 
2305 		/* Get the extra data */
2306 		if (!error && dbentry.e_length) {
2307 		    if (read_octet_string(filep,
2308 					  dbentry.e_data,
2309 					  (int) dbentry.e_length)) {
2310 			try2read = read_econtents;
2311 			error++;
2312 		    }
2313 		}
2314 		else {
2315 		    nread = fscanf(filep, "%d", &t9);
2316 		    if ((nread != 1) || (t9 != -1)) {
2317 			error++;
2318 			try2read = read_econtents;
2319 		    }
2320 		}
2321 
2322 		/* Finally, find the end of the record. */
2323 		if (!error)
2324 		    find_record_end(filep, fname, *linenop);
2325 
2326 		/*
2327 		 * We have either read in all the data or choked.
2328 		 */
2329 		if (!error) {
2330 		    one = 1;
2331 		    if ((kret = krb5_db_put_principal(kcontext,
2332 						      &dbentry,
2333 						      &one))) {
2334 						fprintf(stderr,
2335 						    gettext(store_err_fmt),
2336 				fname, *linenop,
2337 				name, error_message(kret));
2338 		    }
2339 		    else {
2340 			if (verbose)
2341 							fprintf(stderr,
2342 							    gettext(
2343 								add_princ_fmt),
2344 							    name);
2345 			retval = 0;
2346 		    }
2347 		}
2348 		else {
2349 					fprintf(stderr, gettext(read_err_fmt),
2350 					    fname, *linenop, try2read);
2351 		}
2352 	    }
2353 	    else {
2354 		if (kret)
2355 					fprintf(stderr, gettext(parse_err_fmt),
2356 			    fname, *linenop, name, error_message(kret));
2357 		else
2358 		    fprintf(stderr, gettext(no_mem_fmt),
2359 						fname, *linenop);
2360 	    }
2361 	}
2362 	else {
2363 	    fprintf(stderr,
2364 				gettext(rhead_err_fmt), fname, *linenop);
2365 	}
2366 
2367 	if (op)
2368 	    free(op);
2369 	if (kp)
2370 	    free(kp);
2371 	if (name)
2372 	    free(name);
2373 	krb5_db_free_principal(kcontext, &dbentry, 1);
2374     }
2375     else {
2376 	if (nread == EOF)
2377 	    retval = -1;
2378     }
2379     return(retval);
2380 }
2381 
2382 static int
2383 process_k5beta7_policy(fname, kcontext, filep, verbose, linenop, pol_db)
2384     char		*fname;
2385     krb5_context	kcontext;
2386     FILE		*filep;
2387     int			verbose;
2388     int			*linenop;
2389     void *pol_db;
2390 {
2391     osa_policy_ent_rec rec;
2392     char namebuf[1024];
2393     int nread, ret;
2394 
2395     (*linenop)++;
2396     rec.name = namebuf;
2397 
2398     nread = fscanf(filep, "%1024s\t%d\t%d\t%d\t%d\t%d\t%d", rec.name,
2399 		   &rec.pw_min_life, &rec.pw_max_life,
2400 		   &rec.pw_min_length, &rec.pw_min_classes,
2401 		   &rec.pw_history_num, &rec.policy_refcnt);
2402     if (nread == EOF)
2403 	 return -1;
2404     else if (nread != 7) {
2405 		fprintf(stderr,
2406 		    gettext("cannot parse policy on line %d (%d read)\n"),
2407 		 *linenop, nread);
2408 	 return 1;
2409     }
2410 
2411     if ((ret = krb5_db_create_policy(kcontext, &rec))) {
2412 	 if (ret &&
2413 	     ((ret = krb5_db_put_policy(kcontext, &rec)))) {
2414 	      fprintf(stderr, gettext("cannot create policy on line %d: %s\n"),
2415 		      *linenop, error_message(ret));
2416 	      return 1;
2417 	 }
2418     }
2419     if (verbose)
2420 		fprintf(stderr, gettext("created policy %s\n"), rec.name);
2421 
2422     return 0;
2423 }
2424 
2425 /*
2426  * process_k5beta7_record()	- Handle a dump record in krb5b7 format.
2427  *
2428  * Returns -1 for end of file, 0 for success and 1 for failure.
2429  */
2430 static int
2431 process_k5beta7_record(fname, kcontext, filep, verbose, linenop)
2432     char		*fname;
2433     krb5_context	kcontext;
2434     FILE		*filep;
2435     int			verbose;
2436     int			*linenop;
2437 {
2438      int nread;
2439      char rectype[100];
2440 
2441      nread = fscanf(filep, "%100s\t", rectype);
2442      if (nread == EOF)
2443 	  return -1;
2444      else if (nread != 1)
2445 	  return 1;
2446      if (strcmp(rectype, "princ") == 0)
2447 	  process_k5beta6_record(fname, kcontext, filep, verbose,
2448 				 linenop);
2449      else if (strcmp(rectype, "policy") == 0)
2450 	  process_k5beta7_policy(fname, kcontext, filep, verbose,
2451 				 linenop);
2452      else {
2453 		fprintf(stderr,
2454 		    gettext("unknown record type \"%s\" on line %d\n"),
2455 		  rectype, *linenop);
2456 	  return 1;
2457      }
2458 
2459      return 0;
2460 }
2461 
2462 /*
2463  * process_ov_record()	- Handle a dump record in OpenV*Secure 1.0 format.
2464  *
2465  * Returns -1 for end of file, 0 for success and 1 for failure.
2466  */
2467 static int
2468 process_ov_record(fname, kcontext, filep, verbose, linenop)
2469     char		*fname;
2470     krb5_context	kcontext;
2471     FILE		*filep;
2472     int			verbose;
2473     int			*linenop;
2474 {
2475      int nread;
2476      char rectype[100];
2477 
2478      nread = fscanf(filep, "%100s\t", rectype);
2479      if (nread == EOF)
2480 	  return -1;
2481      else if (nread != 1)
2482 	  return 1;
2483      if (strcmp(rectype, "princ") == 0)
2484 	  process_ov_principal(fname, kcontext, filep, verbose,
2485 			       linenop);
2486      else if (strcmp(rectype, "policy") == 0)
2487 	  process_k5beta7_policy(fname, kcontext, filep, verbose,
2488 				 linenop);
2489      else if (strcmp(rectype, "End") == 0)
2490 	  return -1;
2491      else {
2492 		fprintf(stderr,
2493 		    gettext("unknown record type \"%s\" on line %d\n"),
2494 		  rectype, *linenop);
2495 	  return 1;
2496      }
2497 
2498      return 0;
2499 }
2500 
2501 /*
2502  * restore_dump()	- Restore the database from any version dump file.
2503  */
2504 static int
2505 restore_dump(programname, kcontext, dumpfile, f, verbose, dump)
2506     char		*programname;
2507     krb5_context	kcontext;
2508     char		*dumpfile;
2509     FILE		*f;
2510     int			verbose;
2511     dump_version	*dump;
2512 {
2513     int		error;
2514     int		lineno;
2515 
2516     error = 0;
2517     lineno = 1;
2518 
2519     /*
2520      * Process the records.
2521      */
2522     while (!(error = (*dump->load_record)(dumpfile,
2523 					  kcontext,
2524 					  f,
2525 					  verbose,
2526 					  &lineno)))
2527 	 ;
2528     if (error != -1)
2529 		fprintf(stderr, gettext(err_line_fmt),
2530 		    programname, lineno, dumpfile);
2531     else
2532 	 error = 0;
2533 
2534     return(error);
2535 }
2536 
2537 /*
2538  * Usage: load_db [-i] [-old] [-ov] [-b6] [-b7] [-verbose] [-update] [-hash]
2539  *		filename
2540  */
2541 void
2542 load_db(argc, argv)
2543     int		argc;
2544     char	**argv;
2545 {
2546     kadm5_config_params newparams;
2547     krb5_error_code	kret;
2548     krb5_context	kcontext;
2549     FILE		*f;
2550     extern char		*optarg;
2551     extern int		optind;
2552     char		*programname;
2553     char		*dumpfile;
2554     char		*dbname;
2555     char		*dbname_tmp;
2556     char		buf[BUFSIZ];
2557     dump_version	*load;
2558     int			update, verbose;
2559     krb5_int32		crflags;
2560     int			aindex;
2561     bool_t		add_update = TRUE;
2562     char		iheader[MAX_HEADER];
2563     uint32_t		caller, last_sno, last_seconds, last_useconds;
2564     kdb_log_context	*log_ctx;
2565     int			db_locked = 0;
2566 
2567     /*
2568      * Parse the arguments.
2569      */
2570     programname = argv[0];
2571     if (strrchr(programname, (int) '/'))
2572 	programname = strrchr(argv[0], (int) '/') + 1;
2573     dumpfile = (char *) NULL;
2574     dbname = global_params.dbname;
2575     load = NULL;
2576     update = 0;
2577     verbose = 0;
2578     crflags = KRB5_KDB_CREATE_BTREE;
2579     exit_status = 0;
2580     dbname_tmp = (char *) NULL;
2581     log_ctx = util_context->kdblog_context;
2582 
2583     for (aindex = 1; aindex < argc; aindex++) {
2584 	if (!strcmp(argv[aindex], oldoption))
2585 	     load = &old_version;
2586 	else if (!strcmp(argv[aindex], b6option))
2587 	     load = &beta6_version;
2588 	else if (!strcmp(argv[aindex], b7option))
2589 	     load = &beta7_version;
2590 	else if (!strcmp(argv[aindex], ovoption))
2591 	     load = &ov_version;
2592 	else if (!strcmp(argv[aindex], ipropoption)) {
2593 			if (log_ctx && log_ctx->iproprole) {
2594 				load = &iprop_version;
2595 				add_update = FALSE;
2596 			} else {
2597 				fprintf(stderr, gettext("Iprop not enabled\n"));
2598 				exit_status++;
2599 				return;
2600 			}
2601 		}
2602 	else if (!strcmp(argv[aindex], verboseoption))
2603 	    verbose = 1;
2604 	else if (!strcmp(argv[aindex], updateoption))
2605 	    update = 1;
2606 	else if (!strcmp(argv[aindex], hashoption)) {
2607 	    if (!add_db_arg("hash=true")) {
2608 		com_err(progname, ENOMEM, "while parsing command arguments\n");
2609 		exit(1);
2610 	    }
2611 	} else
2612 	    break;
2613     }
2614     if ((argc - aindex) != 1) {
2615 	usage();
2616 	return;
2617     }
2618     dumpfile = argv[aindex];
2619 
2620     if (!(dbname_tmp = (char *) malloc(strlen(dbname)+
2621 				       strlen(dump_tmptrail)+1))) {
2622 		fprintf(stderr, gettext(no_name_mem_fmt), argv[0]);
2623 	exit_status++;
2624 	return;
2625     }
2626     strcpy(dbname_tmp, dbname);
2627     strcat(dbname_tmp, dump_tmptrail);
2628 
2629     /*
2630      * Initialize the Kerberos context and error tables.
2631      */
2632     if ((kret = kadm5_init_krb5_context(&kcontext))) {
2633 	fprintf(stderr, gettext(ctx_err_fmt), programname);
2634 	free(dbname_tmp);
2635 	exit_status++;
2636 	return;
2637     }
2638 
2639     if( (kret = krb5_set_default_realm(kcontext, util_context->default_realm)) )
2640     {
2641 	fprintf(stderr, gettext("%s: Unable to set the default realm\n"), programname);
2642 	free(dbname_tmp);
2643 	exit_status++;
2644 	return;
2645     }
2646     if (log_ctx && log_ctx->iproprole)
2647 	kcontext->kdblog_context = (void *)log_ctx;
2648     /*
2649      * Open the dumpfile
2650      */
2651     if (dumpfile) {
2652 	if ((f = fopen(dumpfile, "r")) == NULL) {
2653 			fprintf(stderr, gettext(dfile_err_fmt),
2654 			    programname, dumpfile,
2655 		     error_message(errno));
2656 	     exit_status++;
2657 	     return;
2658 	}
2659 	if ((kret = krb5_lock_file(kcontext, fileno(f),
2660 				   KRB5_LOCKMODE_SHARED))) {
2661 	     fprintf(stderr, gettext("%s: Cannot lock %s: %s\n"), programname,
2662 		     dumpfile, error_message(errno));
2663 	     exit_status++;
2664 	     return;
2665 	}
2666     } else
2667 	f = stdin;
2668 
2669     /*
2670      * Auto-detect dump version if we weren't told, verify if we
2671      * were told.
2672      */
2673     fgets(buf, sizeof(buf), f);
2674     if (load) {
2675 	 /* only check what we know; some headers only contain a prefix */
2676 	 if (strncmp(buf, load->header, strlen(load->header)) != 0) {
2677 			fprintf(stderr, gettext(head_bad_fmt), programname, dumpfile);
2678 	      exit_status++;
2679 	      if (dumpfile) fclose(f);
2680 	      return;
2681 	 }
2682     } else {
2683 	 /* perhaps this should be in an array, but so what? */
2684 	 if (strcmp(buf, old_version.header) == 0)
2685 	      load = &old_version;
2686 	 else if (strcmp(buf, beta6_version.header) == 0)
2687 	      load = &beta6_version;
2688 	 else if (strcmp(buf, beta7_version.header) == 0)
2689 	      load = &beta7_version;
2690 	 else if (strcmp(buf, r1_3_version.header) == 0)
2691 	      load = &r1_3_version;
2692 	 else if (strncmp(buf, ov_version.header,
2693 			  strlen(ov_version.header)) == 0)
2694 	      load = &ov_version;
2695 	 else {
2696 			fprintf(stderr, gettext(head_bad_fmt),
2697 				programname, dumpfile);
2698 	      exit_status++;
2699 	      if (dumpfile) fclose(f);
2700 	      return;
2701 	 }
2702     }
2703     if (load->updateonly && !update) {
2704 		fprintf(stderr,
2705 		    gettext("%s: dump version %s can only "
2706 			"be loaded with the -update flag\n"),
2707 		    programname, load->name);
2708 	 exit_status++;
2709 	 return;
2710     }
2711 
2712     /*
2713      * Cons up params for the new databases.  If we are not in update
2714      * mode, we create an alternate database and then promote it to
2715      * be the live db.
2716      */
2717     newparams = global_params;
2718     if (! update) {
2719 	 newparams.mask |= KADM5_CONFIG_DBNAME;
2720 	 newparams.dbname = dbname_tmp;
2721 
2722 	 /* Solaris kerberos: using older kadm5_get_config_params interface */
2723 	 if ((kret = kadm5_get_config_params(kcontext, NULL, NULL,
2724 					     &newparams, &newparams))) {
2725 	      com_err(argv[0], kret,
2726 			    gettext("while retreiving new "
2727 				"configuration parameters"));
2728 	      exit_status++;
2729 	      return;
2730 	 }
2731 
2732 	 if (!add_db_arg("temporary")) {
2733 	     com_err(progname, ENOMEM, "computing parameters for database");
2734 	     exit(1);
2735 	 }
2736     }
2737 
2738     /*
2739      * If not an update restoration, create the database. otherwise open
2740      */
2741     if (!update) {
2742 	if((kret = krb5_db_create(kcontext, db5util_db_args))) {
2743 	    const char *emsg = krb5_get_error_message(kcontext, kret);
2744 	    /*
2745 	     * See if something (like DAL KDB plugin) has set a specific error
2746 	     * message and use that otherwise use default.
2747 	     */
2748 
2749 	    if (emsg != NULL) {
2750 		fprintf(stderr, "%s: %s\n", programname, emsg);
2751 		krb5_free_error_message (kcontext, emsg);
2752 	    } else {
2753 		fprintf(stderr, dbcreaterr_fmt,
2754 			programname, dbname, error_message(kret));
2755 	    }
2756 	    exit_status++;
2757 	    kadm5_free_config_params(kcontext, &newparams);
2758 	    if (dumpfile) fclose(f);
2759 	    return;
2760 	}
2761     }
2762     else {
2763 	    /*
2764 	     * Initialize the database.
2765 	     */
2766 	    if ((kret = krb5_db_open(kcontext, db5util_db_args,
2767 				     KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN))) {
2768 		const char *emsg = krb5_get_error_message(kcontext, kret);
2769 		/*
2770 		 * See if something (like DAL KDB plugin) has set a specific
2771 		 * error message and use that otherwise use default.
2772 		 */
2773 
2774 		if (emsg != NULL) {
2775 		    fprintf(stderr, "%s: %s\n", programname, emsg);
2776 		    krb5_free_error_message (kcontext, emsg);
2777 		} else {
2778 		    fprintf(stderr, dbinit_err_fmt,
2779 			    programname, error_message(kret));
2780 		}
2781 		exit_status++;
2782 		goto error;
2783 	    }
2784     }
2785 
2786 
2787     /*
2788      * If an update restoration, make sure the db is left unusable if
2789      * the update fails.
2790      */
2791     if ((kret = krb5_db_lock(kcontext, update?KRB5_DB_LOCKMODE_PERMANENT: KRB5_DB_LOCKMODE_EXCLUSIVE))) {
2792 	/*
2793 	 * Ignore a not supported error since there is nothing to do about it
2794 	 * anyway.
2795 	 */
2796 	if (kret != KRB5_PLUGIN_OP_NOTSUPP) {
2797 	    fprintf(stderr, gettext("%s: %s while permanently locking database\n"),
2798 		    programname, error_message(kret));
2799 	    exit_status++;
2800 	    goto error;
2801 	}
2802     }
2803     else
2804 	db_locked = 1;
2805 
2806 	if (log_ctx && log_ctx->iproprole) {
2807 		if (add_update)
2808 			caller = FKCOMMAND;
2809 		else
2810 			caller = FKPROPD;
2811 
2812 		if (ulog_map(kcontext, &global_params, caller)) {
2813 			fprintf(stderr,
2814 				gettext("%s: Could not map log\n"),
2815 				programname);
2816 			exit_status++;
2817 			goto error;
2818 		}
2819 
2820 		/*
2821 		 * We don't want to take out the ulog out from underneath
2822 		 * kadmind so we reinit the header log.
2823 		 *
2824 		 * We also don't want to add to the update log since we
2825 		 * are doing a whole sale replace of the db, because:
2826 		 * 	we could easily exceed # of update entries
2827 		 * 	we could implicity delete db entries during a replace
2828 		 *	no advantage in incr updates when entire db is replaced
2829 		 */
2830 		if (!update) {
2831                         memset(log_ctx->ulog, 0, sizeof (kdb_hlog_t));
2832 
2833                         log_ctx->ulog->kdb_hmagic = KDB_HMAGIC;
2834                         log_ctx->ulog->db_version_num = KDB_VERSION;
2835                         log_ctx->ulog->kdb_state = KDB_STABLE;
2836                         log_ctx->ulog->kdb_block = ULOG_BLOCK;
2837 
2838 			log_ctx->iproprole = IPROP_NULL;
2839 
2840 			if (!add_update) {
2841 				sscanf(buf, "%s %u %u %u", iheader, &last_sno,
2842 					&last_seconds, &last_useconds);
2843 
2844 				log_ctx->ulog->kdb_last_sno = last_sno;
2845 				log_ctx->ulog->kdb_last_time.seconds =
2846 				    last_seconds;
2847 				log_ctx->ulog->kdb_last_time.useconds =
2848 				    last_useconds;
2849 			}
2850 		}
2851 	}
2852 
2853     if (restore_dump(programname, kcontext, (dumpfile) ? dumpfile : stdin_name,
2854 		     f, verbose, load)) {
2855 	 fprintf(stderr, gettext(restfail_fmt),
2856 		 programname, load->name);
2857 	 exit_status++;
2858     }
2859 
2860     if (!update && load->create_kadm5 &&
2861 	((kret = kadm5_create_magic_princs(&newparams, kcontext)))) {
2862 	 /* error message printed by create_magic_princs */
2863 	 exit_status++;
2864     }
2865 
2866     if (db_locked && (kret = krb5_db_unlock(kcontext))) {
2867 	 /* change this error? */
2868 		fprintf(stderr, gettext(dbunlockerr_fmt),
2869 		 programname, dbname, error_message(kret));
2870 	 exit_status++;
2871     }
2872 
2873 #if 0
2874     if ((kret = krb5_db_fini(kcontext))) {
2875 		fprintf(stderr, gettext(close_err_fmt),
2876 		 programname, error_message(kret));
2877 	 exit_status++;
2878     }
2879 #endif
2880 
2881     /* close policy db below */
2882 
2883     if (exit_status == 0 && !update) {
2884 	kret = krb5_db_promote(kcontext, db5util_db_args);
2885 	/*
2886 	 * Ignore a not supported error since there is nothing to do about it
2887 	 * anyway.
2888 	 */
2889 	if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) {
2890 	    fprintf(stderr, gettext("%s: cannot make newly loaded database live (%s)\n"),
2891 		    programname, error_message(kret));
2892 	    exit_status++;
2893 	}
2894     }
2895 
2896 error:
2897     /*
2898      * If not an update: if there was an error, destroy the temp database,
2899      * otherwise rename it into place.
2900      *
2901      * If an update: if there was no error, unlock the database.
2902      */
2903     if (!update) {
2904 	 if (exit_status) {
2905 	      kret = krb5_db_destroy(kcontext, db5util_db_args);
2906 	      /*
2907 	       * Ignore a not supported error since there is nothing to do about
2908 	       * it anyway.
2909 	       */
2910 	      if (kret != 0 && kret != KRB5_PLUGIN_OP_NOTSUPP) {
2911 		   fprintf(stderr, gettext(dbdelerr_fmt),
2912 			   programname, dbname, error_message(kret));
2913 		   exit_status++;
2914 	      }
2915 	 }
2916     }
2917 
2918     if (dumpfile) {
2919 	 (void) krb5_lock_file(kcontext, fileno(f), KRB5_LOCKMODE_UNLOCK);
2920 	 fclose(f);
2921     }
2922 
2923     if (dbname_tmp)
2924 	 free(dbname_tmp);
2925     krb5_free_context(kcontext);
2926 }
2927