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