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