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