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