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