Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
freebsd
GitHub Repository: freebsd/freebsd-src
Path: blob/main/crypto/krb5/src/kadmin/dbutil/dump.c
34907 views
1
/* -*- mode: c; c-basic-offset: 4; indent-tabs-mode: nil -*- */
2
/* kadmin/dbutil/dump.c - Dump a KDC database */
3
/*
4
* Copyright 1990,1991,2001,2006,2008,2009,2013 by the Massachusetts Institute
5
* of Technology. 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
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
28
* Use is subject to license terms.
29
*/
30
31
#include <k5-int.h>
32
#include <kadm5/admin.h>
33
#include <kadm5/server_internal.h>
34
#include <kdb.h>
35
#include <com_err.h>
36
#include "kdb5_util.h"
37
#include "k5-regex.h"
38
39
/* Needed for master key conversion. */
40
static krb5_boolean mkey_convert;
41
krb5_keyblock new_master_keyblock;
42
krb5_kvno new_mkvno;
43
44
#define K5Q1(x) #x
45
#define K5Q(x) K5Q1(x)
46
#define K5CONST_WIDTH_SCANF_STR(x) "%" K5Q(x) "s"
47
48
typedef krb5_error_code (*dump_func)(krb5_context context,
49
krb5_db_entry *entry, const char *name,
50
FILE *fp, krb5_boolean verbose,
51
krb5_boolean omit_nra);
52
typedef int (*load_func)(krb5_context context, const char *dumpfile, FILE *fp,
53
krb5_boolean verbose, int *linenop);
54
55
typedef struct _dump_version {
56
char *name;
57
char *header;
58
int updateonly;
59
int iprop;
60
int ipropx;
61
dump_func dump_princ;
62
osa_adb_iter_policy_func dump_policy;
63
load_func load_record;
64
} dump_version;
65
66
struct dump_args {
67
FILE *ofile;
68
krb5_context context;
69
char **names;
70
int nnames;
71
krb5_boolean verbose;
72
krb5_boolean omit_nra; /* omit non-replicated attributes */
73
dump_version *dump;
74
};
75
76
/* External data */
77
extern krb5_db_entry *master_entry;
78
79
/*
80
* Re-encrypt the key_data with the new master key...
81
*/
82
krb5_error_code
83
master_key_convert(krb5_context context, krb5_db_entry *db_entry)
84
{
85
krb5_error_code retval;
86
krb5_keyblock v5plainkey, *key_ptr, *tmp_mkey;
87
krb5_keysalt keysalt;
88
krb5_key_data new_key_data, *key_data;
89
krb5_boolean is_mkey;
90
krb5_kvno kvno;
91
int i, j;
92
93
is_mkey = krb5_principal_compare(context, master_princ, db_entry->princ);
94
95
if (is_mkey) {
96
return add_new_mkey(context, db_entry, &new_master_keyblock,
97
new_mkvno);
98
}
99
100
for (i = 0; i < db_entry->n_key_data; i++) {
101
key_data = &db_entry->key_data[i];
102
retval = krb5_dbe_find_mkey(context, db_entry, &tmp_mkey);
103
if (retval)
104
return retval;
105
retval = krb5_dbe_decrypt_key_data(context, tmp_mkey, key_data,
106
&v5plainkey, &keysalt);
107
if (retval)
108
return retval;
109
110
memset(&new_key_data, 0, sizeof(new_key_data));
111
112
key_ptr = &v5plainkey;
113
kvno = key_data->key_data_kvno;
114
115
retval = krb5_dbe_encrypt_key_data(context, &new_master_keyblock,
116
key_ptr, &keysalt, kvno,
117
&new_key_data);
118
if (retval)
119
return retval;
120
krb5_free_keyblock_contents(context, &v5plainkey);
121
for (j = 0; j < key_data->key_data_ver; j++) {
122
if (key_data->key_data_length[j])
123
free(key_data->key_data_contents[j]);
124
}
125
*key_data = new_key_data;
126
}
127
assert(new_mkvno > 0);
128
return krb5_dbe_update_mkvno(context, db_entry, new_mkvno);
129
}
130
131
/* Create temp file for new dump to be named ofile. */
132
static FILE *
133
create_ofile(char *ofile, char **tmpname)
134
{
135
int fd = -1;
136
FILE *f;
137
138
*tmpname = NULL;
139
if (asprintf(tmpname, "%s-XXXXXX", ofile) < 0)
140
goto error;
141
142
fd = mkstemp(*tmpname);
143
if (fd == -1)
144
goto error;
145
146
f = fdopen(fd, "w+");
147
if (f != NULL)
148
return f;
149
150
error:
151
com_err(progname, errno, _("while allocating temporary filename dump"));
152
if (fd >= 0)
153
unlink(*tmpname);
154
exit(1);
155
}
156
157
/* Rename new dump file into place. */
158
static void
159
finish_ofile(char *ofile, char **tmpname)
160
{
161
if (rename(*tmpname, ofile) == -1) {
162
com_err(progname, errno, _("while renaming dump file into place"));
163
exit(1);
164
}
165
free(*tmpname);
166
*tmpname = NULL;
167
}
168
169
/* Create the .dump_ok file. */
170
static krb5_boolean
171
prep_ok_file(krb5_context context, char *file_name, int *fd_out)
172
{
173
static char ok[] = ".dump_ok";
174
krb5_error_code retval;
175
char *file_ok = NULL;
176
int fd = -1;
177
krb5_boolean success = FALSE;
178
179
*fd_out = -1;
180
181
if (asprintf(&file_ok, "%s%s", file_name, ok) < 0) {
182
com_err(progname, ENOMEM, _("while allocating dump_ok filename"));
183
goto cleanup;
184
}
185
186
fd = open(file_ok, O_WRONLY | O_CREAT | O_TRUNC, 0600);
187
if (fd == -1) {
188
com_err(progname, errno, _("while creating 'ok' file, '%s'"), file_ok);
189
goto cleanup;
190
}
191
retval = krb5_lock_file(context, fd, KRB5_LOCKMODE_EXCLUSIVE);
192
if (retval) {
193
com_err(progname, retval, _("while locking 'ok' file, '%s'"), file_ok);
194
goto cleanup;
195
}
196
197
*fd_out = fd;
198
fd = -1;
199
success = TRUE;
200
201
cleanup:
202
free(file_ok);
203
if (fd != -1)
204
close(fd);
205
if (!success)
206
exit_status++;
207
return success;
208
}
209
210
/*
211
* Update the "ok" file.
212
*/
213
static void
214
update_ok_file(krb5_context context, int fd)
215
{
216
write(fd, "", 1);
217
krb5_lock_file(context, fd, KRB5_LOCKMODE_UNLOCK);
218
close(fd);
219
}
220
221
/* Return true if a principal name matches a regular expression or string. */
222
static int
223
name_matches(char *name, struct dump_args *args)
224
{
225
regex_t reg;
226
regmatch_t rmatch;
227
int st;
228
char errmsg[BUFSIZ];
229
int i, match;
230
231
/* Check each regular expression in args. */
232
match = args->nnames ? 0 : 1;
233
for (i = 0; i < args->nnames && !match; i++) {
234
/* Compile the regular expression. */
235
st = regcomp(&reg, args->names[i], REG_EXTENDED);
236
if (st) {
237
regerror(st, &reg, errmsg, sizeof(errmsg));
238
fprintf(stderr, _("%s: regular expression error: %s\n"), progname,
239
errmsg);
240
break;
241
}
242
/* See if we have a match. */
243
st = regexec(&reg, name, 1, &rmatch, 0);
244
if (st == 0) {
245
/* See if it matches the whole name. */
246
if (rmatch.rm_so == 0 && (size_t)rmatch.rm_eo == strlen(name))
247
match = 1;
248
} else if (st != REG_NOMATCH) {
249
regerror(st, &reg, errmsg, sizeof(errmsg));
250
fprintf(stderr, _("%s: regular expression match error: %s\n"),
251
progname, errmsg);
252
break;
253
}
254
regfree(&reg);
255
}
256
return match;
257
}
258
259
/* Output "-1" if len is 0; otherwise output len bytes of data in hex. */
260
static void
261
dump_octets_or_minus1(FILE *fp, unsigned char *data, size_t len)
262
{
263
if (len > 0) {
264
for (; len > 0; len--)
265
fprintf(fp, "%02x", *data++);
266
} else {
267
fprintf(fp, "-1");
268
}
269
}
270
271
/*
272
* Dump TL data; common to principals and policies.
273
*
274
* If filter_kadm then the KRB5_TL_KADM_DATA (where a principal's policy
275
* name is stored) is filtered out. This is for dump formats that don't
276
* support policies.
277
*/
278
static void
279
dump_tl_data(FILE *ofile, krb5_tl_data *tlp, krb5_boolean filter_kadm)
280
{
281
for (; tlp != NULL; tlp = tlp->tl_data_next) {
282
if (tlp->tl_data_type == KRB5_TL_KADM_DATA && filter_kadm)
283
continue;
284
fprintf(ofile, "\t%d\t%d\t", (int)tlp->tl_data_type,
285
(int)tlp->tl_data_length);
286
dump_octets_or_minus1(ofile, tlp->tl_data_contents,
287
tlp->tl_data_length);
288
}
289
}
290
291
/* Dump a principal entry in krb5 beta 7 format. Omit kadmin tl-data if kadm
292
* is false. */
293
static krb5_error_code
294
k5beta7_common(krb5_context context, krb5_db_entry *entry,
295
const char *name, FILE *fp, krb5_boolean verbose,
296
krb5_boolean omit_nra, krb5_boolean kadm)
297
{
298
krb5_tl_data *tlp;
299
krb5_key_data *kdata;
300
int counter, skip, i;
301
302
/*
303
* The dump format is as follows:
304
* len strlen(name) n_tl_data n_key_data e_length
305
* name
306
* attributes max_life max_renewable_life expiration
307
* pw_expiration last_success last_failed fail_auth_count
308
* n_tl_data*[type length <contents>]
309
* n_key_data*[ver kvno ver*(type length <contents>)]
310
* <e_data>
311
* Fields which are not encapsulated by angle-brackets are to appear
312
* verbatim. A bracketed field's absence is indicated by a -1 in its
313
* place.
314
*/
315
316
/* Make sure that the tagged list is reasonably correct. */
317
counter = skip = 0;
318
for (tlp = entry->tl_data; tlp; tlp = tlp->tl_data_next) {
319
/* Don't dump tl data types we know aren't understood by earlier
320
* versions. */
321
if (tlp->tl_data_type == KRB5_TL_KADM_DATA && !kadm)
322
skip++;
323
else
324
counter++;
325
}
326
327
if (counter + skip != entry->n_tl_data) {
328
fprintf(stderr, _("%s: tagged data list inconsistency for %s "
329
"(counted %d, stored %d)\n"), progname, name,
330
counter + skip, (int)entry->n_tl_data);
331
return EINVAL;
332
}
333
334
/* Write out header. */
335
fprintf(fp, "princ\t%d\t%lu\t%d\t%d\t%d\t%s\t", (int)entry->len,
336
(unsigned long)strlen(name), counter, (int)entry->n_key_data,
337
(int)entry->e_length, name);
338
fprintf(fp, "%d\t%d\t%d\t%u\t%u\t%u\t%u\t%d", entry->attributes,
339
entry->max_life, entry->max_renewable_life,
340
(unsigned int)entry->expiration,
341
(unsigned int)entry->pw_expiration,
342
(unsigned int)(omit_nra ? 0 : entry->last_success),
343
(unsigned int)(omit_nra ? 0 : entry->last_failed),
344
omit_nra ? 0 : entry->fail_auth_count);
345
346
/* Write out tagged data. */
347
dump_tl_data(fp, entry->tl_data, !kadm);
348
fprintf(fp, "\t");
349
350
/* Write out key data. */
351
for (counter = 0; counter < entry->n_key_data; counter++) {
352
kdata = &entry->key_data[counter];
353
fprintf(fp, "%d\t%d\t", (int)kdata->key_data_ver,
354
(int)kdata->key_data_kvno);
355
for (i = 0; i < kdata->key_data_ver; i++) {
356
fprintf(fp, "%d\t%d\t", kdata->key_data_type[i],
357
kdata->key_data_length[i]);
358
dump_octets_or_minus1(fp, kdata->key_data_contents[i],
359
kdata->key_data_length[i]);
360
fprintf(fp, "\t");
361
}
362
}
363
364
/* Write out extra data. */
365
dump_octets_or_minus1(fp, entry->e_data, entry->e_length);
366
367
/* Write trailer. */
368
fprintf(fp, ";\n");
369
370
if (verbose)
371
fprintf(stderr, "%s\n", name);
372
373
return 0;
374
}
375
376
/* Output a dump record in krb5b7 format. */
377
static krb5_error_code
378
dump_k5beta7_princ(krb5_context context, krb5_db_entry *entry,
379
const char *name, FILE *fp, krb5_boolean verbose,
380
krb5_boolean omit_nra)
381
{
382
return k5beta7_common(context, entry, name, fp, verbose, omit_nra, FALSE);
383
}
384
385
static krb5_error_code
386
dump_k5beta7_princ_withpolicy(krb5_context context, krb5_db_entry *entry,
387
const char *name, FILE *fp, krb5_boolean verbose,
388
krb5_boolean omit_nra)
389
{
390
return k5beta7_common(context, entry, name, fp, verbose, omit_nra, TRUE);
391
}
392
393
static void
394
dump_k5beta7_policy(void *data, osa_policy_ent_t entry)
395
{
396
struct dump_args *arg = data;
397
398
fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\n", entry->name,
399
entry->pw_min_life, entry->pw_max_life, entry->pw_min_length,
400
entry->pw_min_classes, entry->pw_history_num, 0);
401
}
402
403
static void
404
dump_r1_8_policy(void *data, osa_policy_ent_t entry)
405
{
406
struct dump_args *arg = data;
407
408
fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\n",
409
entry->name, entry->pw_min_life, entry->pw_max_life,
410
entry->pw_min_length, entry->pw_min_classes, entry->pw_history_num,
411
0, entry->pw_max_fail, entry->pw_failcnt_interval,
412
entry->pw_lockout_duration);
413
}
414
415
static void
416
dump_r1_11_policy(void *data, osa_policy_ent_t entry)
417
{
418
struct dump_args *arg = data;
419
420
fprintf(arg->ofile, "policy\t%s\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t%d\t"
421
"%d\t%d\t%d\t%s\t%d", entry->name, entry->pw_min_life,
422
entry->pw_max_life, entry->pw_min_length, entry->pw_min_classes,
423
entry->pw_history_num, 0, entry->pw_max_fail,
424
entry->pw_failcnt_interval, entry->pw_lockout_duration,
425
entry->attributes, entry->max_life, entry->max_renewable_life,
426
entry->allowed_keysalts ? entry->allowed_keysalts : "-",
427
entry->n_tl_data);
428
429
dump_tl_data(arg->ofile, entry->tl_data, FALSE);
430
fprintf(arg->ofile, "\n");
431
}
432
433
static krb5_error_code
434
dump_iterator(void *ptr, krb5_db_entry *entry)
435
{
436
krb5_error_code ret;
437
struct dump_args *args = ptr;
438
char *name;
439
440
ret = krb5_unparse_name(args->context, entry->princ, &name);
441
if (ret) {
442
com_err(progname, ret, _("while unparsing principal name"));
443
return ret;
444
}
445
446
/* Re-encode the keys in the new master key, if necessary. */
447
if (mkey_convert) {
448
ret = master_key_convert(args->context, entry);
449
if (ret) {
450
com_err(progname, ret, _("while converting %s to new master key"),
451
name);
452
goto cleanup;
453
}
454
}
455
456
/* Don't dump this entry if we have match strings and it doesn't match. */
457
if (args->nnames > 0 && !name_matches(name, args))
458
goto cleanup;
459
460
ret = args->dump->dump_princ(args->context, entry, name, args->ofile,
461
args->verbose, args->omit_nra);
462
463
cleanup:
464
free(name);
465
return ret;
466
}
467
468
static inline void
469
load_err(const char *fname, int lineno, const char *msg)
470
{
471
fprintf(stderr, _("%s(%d): %s\n"), fname, lineno, msg);
472
}
473
474
/* Read a string of bytes. Increment *lp for each newline. Return 0 on
475
* success, 1 on failure. */
476
static int
477
read_string(FILE *f, char *buf, int len, int *lp)
478
{
479
int c, i;
480
481
for (i = 0; i < len; i++) {
482
c = fgetc(f);
483
if (c < 0)
484
return 1;
485
if (c == '\n')
486
(*lp)++;
487
buf[i] = c;
488
}
489
buf[len] = '\0';
490
return 0;
491
}
492
493
/* Read a string of two-character representations of bytes. */
494
static int
495
read_octet_string(FILE *f, unsigned char *buf, int len)
496
{
497
int c, i;
498
499
for (i = 0; i < len; i++) {
500
if (fscanf(f, "%02x", &c) != 1)
501
return 1;
502
buf[i] = c;
503
}
504
return 0;
505
}
506
507
/* Read the end of a dumpfile record. */
508
static void
509
read_record_end(FILE *f, const char *fn, int lineno)
510
{
511
int ch;
512
513
if ((ch = fgetc(f)) != ';' || (ch = fgetc(f)) != '\n') {
514
fprintf(stderr, _("%s(%d): ignoring trash at end of line: "), fn,
515
lineno);
516
while (ch != '\n') {
517
putc(ch, stderr);
518
ch = fgetc(f);
519
}
520
putc(ch, stderr);
521
}
522
}
523
524
/* Allocate and form a TL data list of a desired size. */
525
static int
526
alloc_tl_data(krb5_int16 n_tl_data, krb5_tl_data **tldp)
527
{
528
krb5_tl_data **tlp = tldp;
529
int i;
530
531
for (i = 0; i < n_tl_data; i++) {
532
*tlp = calloc(1, sizeof(krb5_tl_data));
533
if (*tlp == NULL)
534
return ENOMEM; /* caller cleans up */
535
tlp = &((*tlp)->tl_data_next);
536
}
537
538
return 0;
539
}
540
541
/* If len is zero, read the string "-1" from fp. Otherwise allocate space and
542
* read len octets. Return 0 on success, 1 on failure. */
543
static int
544
read_octets_or_minus1(FILE *fp, size_t len, unsigned char **out)
545
{
546
int ival;
547
unsigned char *buf;
548
549
*out = NULL;
550
if (len == 0)
551
return fscanf(fp, "%d", &ival) != 1 || ival != -1;
552
buf = malloc(len);
553
if (buf == NULL)
554
return 1;
555
if (read_octet_string(fp, buf, len)) {
556
free(buf);
557
return 1;
558
}
559
*out = buf;
560
return 0;
561
}
562
563
/* Read TL data for a principal or policy. Print an error and return -1 on
564
* failure. */
565
static int
566
process_tl_data(const char *fname, FILE *filep, int lineno,
567
krb5_tl_data *tl_data)
568
{
569
krb5_tl_data *tl;
570
int nread, i1;
571
unsigned int u1;
572
573
for (tl = tl_data; tl; tl = tl->tl_data_next) {
574
nread = fscanf(filep, "%d\t%u\t", &i1, &u1);
575
if (nread != 2) {
576
load_err(fname, lineno,
577
_("cannot read tagged data type and length"));
578
return EINVAL;
579
}
580
if (i1 < INT16_MIN || i1 > INT16_MAX || u1 > UINT16_MAX) {
581
load_err(fname, lineno, _("data type or length overflowed"));
582
return EINVAL;
583
}
584
tl->tl_data_type = i1;
585
tl->tl_data_length = u1;
586
if (read_octets_or_minus1(filep, tl->tl_data_length,
587
&tl->tl_data_contents)) {
588
load_err(fname, lineno, _("cannot read tagged data contents"));
589
return EINVAL;
590
}
591
}
592
593
return 0;
594
}
595
596
/* Read a beta 7 entry and add it to the database. Return -1 for end of file,
597
* 0 for success and 1 for failure. */
598
static int
599
process_k5beta7_princ(krb5_context context, const char *fname, FILE *filep,
600
krb5_boolean verbose, int *linenop)
601
{
602
int retval, nread, i, j;
603
krb5_db_entry *dbentry;
604
int t1, t2, t3, t4;
605
unsigned int u1, u2, u3, u4, u5;
606
char *name = NULL;
607
krb5_key_data *kp = NULL, *kd;
608
krb5_tl_data *tl;
609
krb5_error_code ret;
610
611
dbentry = calloc(1, sizeof(*dbentry));
612
if (dbentry == NULL)
613
return 1;
614
(*linenop)++;
615
nread = fscanf(filep, "%u\t%u\t%u\t%u\t%u\t", &u1, &u2, &u3, &u4, &u5);
616
if (nread == EOF) {
617
retval = -1;
618
goto cleanup;
619
}
620
if (nread != 5) {
621
load_err(fname, *linenop, _("cannot match size tokens"));
622
goto fail;
623
}
624
625
/* Get memory for flattened principal name */
626
if (u2 > UINT_MAX / 2) {
627
load_err(fname, *linenop, _("cannot allocate principal (too large)"));
628
goto fail;
629
}
630
name = malloc(u2 + 1);
631
if (name == NULL)
632
goto fail;
633
634
/* Get memory for and form tagged data linked list */
635
if (u3 > UINT16_MAX) {
636
load_err(fname, *linenop, _("cannot allocate tl_data (too large)"));
637
goto fail;
638
}
639
if (alloc_tl_data(u3, &dbentry->tl_data))
640
goto fail;
641
dbentry->n_tl_data = u3;
642
643
/* Get memory for key list */
644
if (u4 > INT16_MAX) {
645
load_err(fname, *linenop, _("invalid key_data size"));
646
goto fail;
647
}
648
if (u4 && (kp = calloc(u4, sizeof(krb5_key_data))) == NULL)
649
goto fail;
650
651
dbentry->len = u1;
652
dbentry->n_key_data = u4;
653
654
if (u5 > UINT16_MAX) {
655
load_err(fname, *linenop, _("invalid principal extra data size"));
656
goto fail;
657
}
658
dbentry->e_length = u5;
659
660
if (kp != NULL) {
661
dbentry->key_data = kp;
662
kp = NULL;
663
}
664
665
/* Read in and parse the principal name */
666
if (read_string(filep, name, u2, linenop)) {
667
load_err(fname, *linenop, _("cannot read name string"));
668
goto fail;
669
}
670
ret = krb5_parse_name(context, name, &dbentry->princ);
671
if (ret) {
672
com_err(progname, ret, _("while parsing name %s"), name);
673
goto fail;
674
}
675
676
/* Get the fixed principal attributes */
677
nread = fscanf(filep, "%d\t%d\t%d\t%u\t%u\t%d\t%d\t%d\t",
678
&t1, &t2, &t3, &u1, &u2, &u3, &u4, &u5);
679
if (nread != 8) {
680
load_err(fname, *linenop, _("cannot read principal attributes"));
681
goto fail;
682
}
683
dbentry->attributes = t1;
684
dbentry->max_life = t2;
685
dbentry->max_renewable_life = t3;
686
dbentry->expiration = u1;
687
dbentry->pw_expiration = u2;
688
dbentry->last_success = u3;
689
dbentry->last_failed = u4;
690
dbentry->fail_auth_count = u5;
691
dbentry->mask = KADM5_LOAD | KADM5_PRINCIPAL | KADM5_ATTRIBUTES |
692
KADM5_MAX_LIFE | KADM5_MAX_RLIFE |
693
KADM5_PRINC_EXPIRE_TIME | KADM5_PW_EXPIRATION | KADM5_LAST_SUCCESS |
694
KADM5_LAST_FAILED | KADM5_FAIL_AUTH_COUNT;
695
696
/* Read tagged data. */
697
if (dbentry->n_tl_data) {
698
if (process_tl_data(fname, filep, *linenop, dbentry->tl_data))
699
goto fail;
700
for (tl = dbentry->tl_data; tl; tl = tl->tl_data_next) {
701
/* test to set mask fields */
702
if (tl->tl_data_type == KRB5_TL_KADM_DATA) {
703
XDR xdrs;
704
osa_princ_ent_rec osa_princ_ent;
705
706
/*
707
* Assuming aux_attributes will always be
708
* there
709
*/
710
dbentry->mask |= KADM5_AUX_ATTRIBUTES;
711
712
/* test for an actual policy reference */
713
memset(&osa_princ_ent, 0, sizeof(osa_princ_ent));
714
xdrmem_create(&xdrs, (char *)tl->tl_data_contents,
715
tl->tl_data_length, XDR_DECODE);
716
if (xdr_osa_princ_ent_rec(&xdrs, &osa_princ_ent)) {
717
if ((osa_princ_ent.aux_attributes & KADM5_POLICY) &&
718
osa_princ_ent.policy != NULL)
719
dbentry->mask |= KADM5_POLICY;
720
kdb_free_entry(NULL, NULL, &osa_princ_ent);
721
}
722
xdr_destroy(&xdrs);
723
}
724
}
725
dbentry->mask |= KADM5_TL_DATA;
726
}
727
728
/* Get the key data. */
729
for (i = 0; i < dbentry->n_key_data; i++) {
730
kd = &dbentry->key_data[i];
731
nread = fscanf(filep, "%d\t%d\t", &t1, &t2);
732
if (nread != 2) {
733
load_err(fname, *linenop, _("cannot read key size and version"));
734
goto fail;
735
}
736
if (t1 > KRB5_KDB_V1_KEY_DATA_ARRAY) {
737
load_err(fname, *linenop, _("unsupported key_data_ver version"));
738
goto fail;
739
}
740
if (t2 < 0 || t2 > UINT16_MAX) {
741
load_err(fname, *linenop, _("invalid kvno"));
742
goto fail;
743
}
744
745
kd->key_data_ver = t1;
746
kd->key_data_kvno = t2;
747
748
for (j = 0; j < t1; j++) {
749
nread = fscanf(filep, "%d\t%d\t", &t3, &t4);
750
if (nread != 2 || t4 < 0 || t4 > UINT16_MAX) {
751
load_err(fname, *linenop,
752
_("cannot read key type and length"));
753
goto fail;
754
}
755
kd->key_data_type[j] = t3;
756
kd->key_data_length[j] = t4;
757
if (read_octets_or_minus1(filep, t4, &kd->key_data_contents[j])) {
758
load_err(fname, *linenop, _("cannot read key data"));
759
goto fail;
760
}
761
}
762
}
763
if (dbentry->n_key_data)
764
dbentry->mask |= KADM5_KEY_DATA;
765
766
/* Get the extra data */
767
if (read_octets_or_minus1(filep, dbentry->e_length, &dbentry->e_data)) {
768
load_err(fname, *linenop, _("cannot read extra data"));
769
goto fail;
770
}
771
772
/* Finally, find the end of the record. */
773
read_record_end(filep, fname, *linenop);
774
775
ret = krb5_db_put_principal(context, dbentry);
776
if (ret) {
777
com_err(progname, ret, _("while storing %s"), name);
778
goto fail;
779
}
780
781
if (verbose)
782
fprintf(stderr, "%s\n", name);
783
retval = 0;
784
785
cleanup:
786
free(kp);
787
free(name);
788
krb5_db_free_principal(context, dbentry);
789
return retval;
790
791
fail:
792
retval = 1;
793
goto cleanup;
794
}
795
796
static int
797
process_k5beta7_policy(krb5_context context, const char *fname, FILE *filep,
798
krb5_boolean verbose, int *linenop)
799
{
800
osa_policy_ent_rec rec;
801
char namebuf[1024];
802
unsigned int refcnt;
803
int nread, ret;
804
805
memset(&rec, 0, sizeof(rec));
806
807
(*linenop)++;
808
rec.name = namebuf;
809
810
nread = fscanf(filep, "%1023s\t%u\t%u\t%u\t%u\t%u\t%u", rec.name,
811
&rec.pw_min_life, &rec.pw_max_life, &rec.pw_min_length,
812
&rec.pw_min_classes, &rec.pw_history_num, &refcnt);
813
if (nread == EOF)
814
return -1;
815
if (nread != 7) {
816
fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
817
return 1;
818
}
819
820
ret = krb5_db_create_policy(context, &rec);
821
if (ret)
822
ret = krb5_db_put_policy(context, &rec);
823
if (ret) {
824
com_err(progname, ret, _("while creating policy"));
825
return 1;
826
}
827
if (verbose)
828
fprintf(stderr, _("created policy %s\n"), rec.name);
829
830
return 0;
831
}
832
833
static int
834
process_r1_8_policy(krb5_context context, const char *fname, FILE *filep,
835
krb5_boolean verbose, int *linenop)
836
{
837
osa_policy_ent_rec rec;
838
char namebuf[1024];
839
unsigned int refcnt;
840
int nread, ret;
841
842
memset(&rec, 0, sizeof(rec));
843
844
(*linenop)++;
845
rec.name = namebuf;
846
847
nread = fscanf(filep, "%1023s\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u",
848
rec.name, &rec.pw_min_life, &rec.pw_max_life,
849
&rec.pw_min_length, &rec.pw_min_classes,
850
&rec.pw_history_num, &refcnt, &rec.pw_max_fail,
851
&rec.pw_failcnt_interval, &rec.pw_lockout_duration);
852
if (nread == EOF)
853
return -1;
854
if (nread != 10) {
855
fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
856
return 1;
857
}
858
859
ret = krb5_db_create_policy(context, &rec);
860
if (ret)
861
ret = krb5_db_put_policy(context, &rec);
862
if (ret) {
863
com_err(progname, ret, _("while creating policy"));
864
return 1;
865
}
866
if (verbose)
867
fprintf(stderr, "created policy %s\n", rec.name);
868
869
return 0;
870
}
871
872
static int
873
process_r1_11_policy(krb5_context context, const char *fname, FILE *filep,
874
krb5_boolean verbose, int *linenop)
875
{
876
osa_policy_ent_rec rec;
877
krb5_tl_data *tl, *tl_next;
878
char namebuf[1024];
879
char keysaltbuf[KRB5_KDB_MAX_ALLOWED_KS_LEN + 1];
880
unsigned int refcnt;
881
int nread, c, ret = 0;
882
883
memset(&rec, 0, sizeof(rec));
884
885
(*linenop)++;
886
rec.name = namebuf;
887
888
/*
889
* Due to a historical error, iprop dumps use the same version before and
890
* after the 1.11 policy extensions. So we need to accept both 1.8-format
891
* and 1.11-format policy entries. Begin by reading the 1.8 fields.
892
*/
893
nread = fscanf(filep, "%1023s\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u",
894
rec.name, &rec.pw_min_life, &rec.pw_max_life,
895
&rec.pw_min_length, &rec.pw_min_classes,
896
&rec.pw_history_num, &refcnt, &rec.pw_max_fail,
897
&rec.pw_failcnt_interval, &rec.pw_lockout_duration);
898
if (nread == EOF)
899
return -1;
900
if (nread != 10) {
901
fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
902
return 1;
903
}
904
905
/* The next character should be a newline (1.8) or a tab (1.11). */
906
c = getc(filep);
907
if (c == EOF)
908
return -1;
909
if (c != '\n') {
910
/* Read the additional 1.11-format fields. */
911
rec.allowed_keysalts = keysaltbuf;
912
nread = fscanf(filep, "%u\t%u\t%u\t"
913
K5CONST_WIDTH_SCANF_STR(KRB5_KDB_MAX_ALLOWED_KS_LEN)
914
"\t%hd", &rec.attributes, &rec.max_life,
915
&rec.max_renewable_life, rec.allowed_keysalts,
916
&rec.n_tl_data);
917
if (nread == EOF)
918
return -1;
919
if (nread != 5) {
920
fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
921
return 1;
922
}
923
924
if (rec.allowed_keysalts && !strcmp(rec.allowed_keysalts, "-"))
925
rec.allowed_keysalts = NULL;
926
927
/* Get TL data */
928
ret = alloc_tl_data(rec.n_tl_data, &rec.tl_data);
929
if (ret)
930
goto cleanup;
931
932
ret = process_tl_data(fname, filep, *linenop, rec.tl_data);
933
if (ret)
934
goto cleanup;
935
}
936
937
ret = krb5_db_create_policy(context, &rec);
938
if (ret)
939
ret = krb5_db_put_policy(context, &rec);
940
if (ret) {
941
com_err(progname, ret, _("while creating policy"));
942
goto cleanup;
943
}
944
if (verbose)
945
fprintf(stderr, "created policy %s\n", rec.name);
946
947
cleanup:
948
for (tl = rec.tl_data; tl; tl = tl_next) {
949
tl_next = tl->tl_data_next;
950
free(tl->tl_data_contents);
951
free(tl);
952
}
953
return ret ? 1 : 0;
954
}
955
956
/* Read a record which is tagged with "princ" or "policy", calling princfn
957
* or policyfn as appropriate. */
958
static int
959
process_tagged(krb5_context context, const char *fname, FILE *filep,
960
krb5_boolean verbose, int *linenop, load_func princfn,
961
load_func policyfn)
962
{
963
int nread;
964
char rectype[100];
965
966
nread = fscanf(filep, "%99s\t", rectype);
967
if (nread == EOF)
968
return -1;
969
if (nread != 1)
970
return 1;
971
if (strcmp(rectype, "princ") == 0)
972
return (*princfn)(context, fname, filep, verbose, linenop);
973
if (strcmp(rectype, "policy") == 0)
974
return (*policyfn)(context, fname, filep, verbose, linenop);
975
if (strcmp(rectype, "End") == 0) /* Only expected for OV format */
976
return -1;
977
978
fprintf(stderr, _("unknown record type \"%s\"\n"), rectype);
979
return 1;
980
}
981
982
static int
983
process_k5beta7_record(krb5_context context, const char *fname, FILE *filep,
984
krb5_boolean verbose, int *linenop)
985
{
986
return process_tagged(context, fname, filep, verbose, linenop,
987
process_k5beta7_princ, process_k5beta7_policy);
988
}
989
990
static int
991
process_r1_8_record(krb5_context context, const char *fname, FILE *filep,
992
krb5_boolean verbose, int *linenop)
993
{
994
return process_tagged(context, fname, filep, verbose, linenop,
995
process_k5beta7_princ, process_r1_8_policy);
996
}
997
998
static int
999
process_r1_11_record(krb5_context context, const char *fname, FILE *filep,
1000
krb5_boolean verbose, int *linenop)
1001
{
1002
return process_tagged(context, fname, filep, verbose, linenop,
1003
process_k5beta7_princ, process_r1_11_policy);
1004
}
1005
1006
dump_version beta7_version = {
1007
"Kerberos version 5",
1008
"kdb5_util load_dump version 4\n",
1009
0,
1010
0,
1011
0,
1012
dump_k5beta7_princ,
1013
dump_k5beta7_policy,
1014
process_k5beta7_record,
1015
};
1016
dump_version r1_3_version = {
1017
"Kerberos version 5 release 1.3",
1018
"kdb5_util load_dump version 5\n",
1019
0,
1020
0,
1021
0,
1022
dump_k5beta7_princ_withpolicy,
1023
dump_k5beta7_policy,
1024
process_k5beta7_record,
1025
};
1026
dump_version r1_8_version = {
1027
"Kerberos version 5 release 1.8",
1028
"kdb5_util load_dump version 6\n",
1029
0,
1030
0,
1031
0,
1032
dump_k5beta7_princ_withpolicy,
1033
dump_r1_8_policy,
1034
process_r1_8_record,
1035
};
1036
dump_version r1_11_version = {
1037
"Kerberos version 5 release 1.11",
1038
"kdb5_util load_dump version 7\n",
1039
0,
1040
0,
1041
0,
1042
dump_k5beta7_princ_withpolicy,
1043
dump_r1_11_policy,
1044
process_r1_11_record,
1045
};
1046
dump_version iprop_version = {
1047
"Kerberos iprop version",
1048
"iprop",
1049
0,
1050
1,
1051
0,
1052
dump_k5beta7_princ_withpolicy,
1053
dump_k5beta7_policy,
1054
process_k5beta7_record,
1055
};
1056
dump_version ipropx_1_version = {
1057
"Kerberos iprop extensible version",
1058
"ipropx",
1059
0,
1060
1,
1061
1,
1062
dump_k5beta7_princ_withpolicy,
1063
dump_r1_11_policy,
1064
process_r1_11_record,
1065
};
1066
1067
/* Read the dump header. Return 1 on success, 0 if the file is not a
1068
* recognized iprop dump format. */
1069
static int
1070
parse_iprop_header(char *buf, dump_version **dv, kdb_last_t *last)
1071
{
1072
char head[128];
1073
int nread;
1074
uint32_t u[4];
1075
uint32_t *up = &u[0];
1076
1077
nread = sscanf(buf, "%127s %u %u %u %u", head, &u[0], &u[1], &u[2], &u[3]);
1078
if (nread < 1)
1079
return 0;
1080
1081
if (!strcmp(head, ipropx_1_version.header)) {
1082
if (nread != 5)
1083
return 0;
1084
if (u[0] == IPROPX_VERSION_0) {
1085
*dv = &iprop_version;
1086
} else if (u[0] == IPROPX_VERSION_1) {
1087
*dv = &ipropx_1_version;
1088
} else {
1089
fprintf(stderr, _("%s: Unknown iprop dump version %d\n"), progname,
1090
u[0]);
1091
return 0;
1092
}
1093
up = &u[1];
1094
} else if (!strcmp(head, iprop_version.header)) {
1095
if (nread != 4)
1096
return 0;
1097
*dv = &iprop_version;
1098
} else {
1099
fprintf(stderr, "Invalid iprop header\n");
1100
return 0;
1101
}
1102
1103
last->last_sno = *up++;
1104
last->last_time.seconds = *up++;
1105
last->last_time.useconds = *up++;
1106
return 1;
1107
}
1108
1109
/* Return true if the serial number and timestamp in an existing dump file is
1110
* in the ulog. */
1111
static krb5_boolean
1112
current_dump_sno_in_ulog(krb5_context context, const char *ifile)
1113
{
1114
update_status_t status;
1115
dump_version *junk;
1116
kdb_last_t last;
1117
char buf[BUFSIZ], *r;
1118
FILE *f;
1119
1120
f = fopen(ifile, "r");
1121
if (f == NULL)
1122
return 0; /* aliasing other errors to ENOENT here is OK */
1123
1124
r = fgets(buf, sizeof(buf), f);
1125
fclose(f);
1126
if (r == NULL)
1127
return errno ? -1 : 0;
1128
1129
if (!parse_iprop_header(buf, &junk, &last))
1130
return 0;
1131
1132
status = ulog_get_sno_status(context, &last);
1133
return status == UPDATE_OK || status == UPDATE_NIL;
1134
}
1135
1136
void
1137
dump_db(int argc, char **argv)
1138
{
1139
FILE *f;
1140
struct dump_args args;
1141
char *ofile = NULL, *tmpofile = NULL, *new_mkey_file = NULL;
1142
krb5_error_code ret, retval;
1143
dump_version *dump;
1144
int aindex, ok_fd = -1;
1145
bool_t dump_sno = FALSE;
1146
kdb_log_context *log_ctx;
1147
unsigned int ipropx_version = IPROPX_VERSION_0;
1148
krb5_kvno kt_kvno;
1149
krb5_boolean conditional = FALSE;
1150
kdb_last_t last;
1151
krb5_flags iterflags = 0;
1152
1153
/* Parse the arguments. */
1154
dump = &r1_11_version;
1155
args.verbose = FALSE;
1156
args.omit_nra = FALSE;
1157
mkey_convert = FALSE;
1158
log_ctx = util_context->kdblog_context;
1159
1160
/*
1161
* Parse the qualifiers.
1162
*/
1163
for (aindex = 1; aindex < argc; aindex++) {
1164
if (!strcmp(argv[aindex], "-b7")) {
1165
dump = &beta7_version;
1166
} else if (!strcmp(argv[aindex], "-ov")) {
1167
fprintf(stderr, _("OV dump format not supported\n"));
1168
goto error;
1169
} else if (!strcmp(argv[aindex], "-r13")) {
1170
dump = &r1_3_version;
1171
} else if (!strcmp(argv[aindex], "-r18")) {
1172
dump = &r1_8_version;
1173
} else if (!strncmp(argv[aindex], "-i", 2)) {
1174
/* Intentionally undocumented - only used by kadmin. */
1175
if (log_ctx && log_ctx->iproprole) {
1176
/* ipropx_version is the maximum version acceptable. */
1177
ipropx_version = atoi(argv[aindex] + 2);
1178
dump = ipropx_version ? &ipropx_1_version : &iprop_version;
1179
/*
1180
* dump_sno is used to indicate if the serial number should be
1181
* populated in the output file to be used later by iprop for
1182
* updating the replica's update log when loading.
1183
*/
1184
dump_sno = TRUE;
1185
/* FLAG_OMIT_NRA is set to indicate that non-replicated
1186
* attributes should be omitted. */
1187
args.omit_nra = TRUE;
1188
} else {
1189
fprintf(stderr, _("Iprop not enabled\n"));
1190
goto error;
1191
}
1192
} else if (!strcmp(argv[aindex], "-c")) {
1193
conditional = 1;
1194
} else if (!strcmp(argv[aindex], "-verbose")) {
1195
args.verbose = TRUE;
1196
} else if (!strcmp(argv[aindex], "-mkey_convert")) {
1197
mkey_convert = 1;
1198
} else if (!strcmp(argv[aindex], "-new_mkey_file")) {
1199
new_mkey_file = argv[++aindex];
1200
mkey_convert = 1;
1201
} else if (!strcmp(argv[aindex], "-rev")) {
1202
iterflags |= KRB5_DB_ITER_REV;
1203
} else if (!strcmp(argv[aindex], "-recurse")) {
1204
iterflags |= KRB5_DB_ITER_RECURSE;
1205
} else {
1206
break;
1207
}
1208
}
1209
1210
args.names = NULL;
1211
args.nnames = 0;
1212
if (aindex < argc) {
1213
ofile = argv[aindex];
1214
aindex++;
1215
if (aindex < argc) {
1216
args.names = &argv[aindex];
1217
args.nnames = argc - aindex;
1218
}
1219
}
1220
1221
/* If a conditional ipropx dump we check if the existing dump is
1222
* good enough. */
1223
if (ofile != NULL && conditional) {
1224
if (!dump->iprop) {
1225
com_err(progname, 0,
1226
_("Conditional dump is an undocumented option for "
1227
"use only for iprop dumps"));
1228
goto error;
1229
}
1230
if (current_dump_sno_in_ulog(util_context, ofile))
1231
return;
1232
}
1233
1234
/*
1235
* Make sure the database is open. The policy database only has
1236
* to be opened if we try a dump that uses it.
1237
*/
1238
if (!dbactive) {
1239
com_err(progname, 0, _("Database not currently opened!"));
1240
goto error;
1241
}
1242
1243
/*
1244
* If we're doing a master key conversion, set up for it.
1245
*/
1246
if (mkey_convert) {
1247
if (!valid_master_key) {
1248
/* TRUE here means read the keyboard, but only once */
1249
retval = krb5_db_fetch_mkey(util_context, master_princ,
1250
master_keyblock.enctype, TRUE, FALSE,
1251
NULL, NULL, NULL, &master_keyblock);
1252
if (retval) {
1253
com_err(progname, retval, _("while reading master key"));
1254
exit(1);
1255
}
1256
retval = krb5_db_fetch_mkey_list(util_context, master_princ,
1257
&master_keyblock);
1258
if (retval) {
1259
com_err(progname, retval, _("while verifying master key"));
1260
exit(1);
1261
}
1262
}
1263
new_master_keyblock.enctype = global_params.enctype;
1264
if (new_master_keyblock.enctype == ENCTYPE_UNKNOWN)
1265
new_master_keyblock.enctype = DEFAULT_KDC_ENCTYPE;
1266
1267
if (new_mkey_file) {
1268
if (global_params.mask & KADM5_CONFIG_KVNO)
1269
kt_kvno = global_params.kvno;
1270
else
1271
kt_kvno = IGNORE_VNO;
1272
1273
retval = krb5_db_fetch_mkey(util_context, master_princ,
1274
new_master_keyblock.enctype, FALSE,
1275
FALSE, new_mkey_file, &kt_kvno, NULL,
1276
&new_master_keyblock);
1277
if (retval) {
1278
com_err(progname, retval, _("while reading new master key"));
1279
exit(1);
1280
}
1281
} else {
1282
printf(_("Please enter new master key....\n"));
1283
retval = krb5_db_fetch_mkey(util_context, master_princ,
1284
new_master_keyblock.enctype, TRUE,
1285
TRUE, NULL, NULL, NULL,
1286
&new_master_keyblock);
1287
if (retval) {
1288
com_err(progname, retval, _("while reading new master key"));
1289
exit(1);
1290
}
1291
}
1292
/* Get new master key vno that will be used to protect princs. */
1293
new_mkvno = get_next_kvno(util_context, master_entry);
1294
}
1295
1296
ret = 0;
1297
1298
if (ofile != NULL && strcmp(ofile, "-")) {
1299
/* Discourage accidental dumping to filenames beginning with '-'. */
1300
if (ofile[0] == '-')
1301
usage();
1302
if (!prep_ok_file(util_context, ofile, &ok_fd))
1303
return; /* prep_ok_file() bumps exit_status */
1304
f = create_ofile(ofile, &tmpofile);
1305
if (f == NULL) {
1306
com_err(progname, errno, _("while opening %s for writing"), ofile);
1307
goto error;
1308
}
1309
} else {
1310
f = stdout;
1311
}
1312
1313
args.ofile = f;
1314
args.context = util_context;
1315
args.dump = dump;
1316
fprintf(args.ofile, "%s", dump->header);
1317
1318
if (dump_sno) {
1319
ret = ulog_get_last(util_context, &last);
1320
if (ret) {
1321
com_err(progname, ret, _("while reading update log header"));
1322
goto error;
1323
}
1324
if (ipropx_version)
1325
fprintf(f, " %u", IPROPX_VERSION);
1326
fprintf(f, " %u", last.last_sno);
1327
fprintf(f, " %u", last.last_time.seconds);
1328
fprintf(f, " %u", last.last_time.useconds);
1329
}
1330
1331
if (dump->header[strlen(dump->header)-1] != '\n')
1332
fputc('\n', args.ofile);
1333
1334
ret = krb5_db_iterate(util_context, NULL, dump_iterator, &args, iterflags);
1335
if (ret) {
1336
com_err(progname, ret, _("performing %s dump"), dump->name);
1337
goto error;
1338
}
1339
1340
/* Don't dump policies if specific principal entries were requested. */
1341
if (dump->dump_policy != NULL && args.nnames == 0) {
1342
ret = krb5_db_iter_policy(util_context, "*", dump->dump_policy, &args);
1343
if (ret) {
1344
com_err(progname, ret, _("performing %s dump"), dump->name);
1345
goto error;
1346
}
1347
}
1348
1349
if (f != stdout) {
1350
fclose(f);
1351
finish_ofile(ofile, &tmpofile);
1352
update_ok_file(util_context, ok_fd);
1353
}
1354
return;
1355
1356
error:
1357
if (tmpofile != NULL)
1358
unlink(tmpofile);
1359
free(tmpofile);
1360
exit_status++;
1361
}
1362
1363
/* Restore the database from any version dump file. */
1364
static int
1365
restore_dump(krb5_context context, char *dumpfile, FILE *f,
1366
krb5_boolean verbose, dump_version *dump)
1367
{
1368
int err = 0;
1369
int lineno = 1;
1370
1371
/* Process the records. */
1372
while (!(err = dump->load_record(context, dumpfile, f, verbose, &lineno)));
1373
if (err != -1) {
1374
fprintf(stderr, _("%s: error processing line %d of %s\n"), progname,
1375
lineno, dumpfile);
1376
return err;
1377
}
1378
return 0;
1379
}
1380
1381
void
1382
load_db(int argc, char **argv)
1383
{
1384
krb5_error_code ret;
1385
FILE *f = NULL;
1386
char *dumpfile = NULL, *dbname, buf[BUFSIZ];
1387
dump_version *load = NULL;
1388
int aindex;
1389
kdb_log_context *log_ctx;
1390
kdb_last_t last;
1391
krb5_boolean db_locked = FALSE, temp_db_created = FALSE;
1392
krb5_boolean verbose = FALSE, update = FALSE, iprop_load = FALSE;
1393
1394
/* Parse the arguments. */
1395
dbname = global_params.dbname;
1396
exit_status = 0;
1397
log_ctx = util_context->kdblog_context;
1398
1399
for (aindex = 1; aindex < argc; aindex++) {
1400
if (!strcmp(argv[aindex], "-b7")){
1401
load = &beta7_version;
1402
} else if (!strcmp(argv[aindex], "-ov")) {
1403
fprintf(stderr, _("OV dump format not supported\n"));
1404
goto error;
1405
} else if (!strcmp(argv[aindex], "-r13")) {
1406
load = &r1_3_version;
1407
} else if (!strcmp(argv[aindex], "-r18")){
1408
load = &r1_8_version;
1409
} else if (!strcmp(argv[aindex], "-i")) {
1410
/* Intentionally undocumented - only used by kadmin. */
1411
if (log_ctx && log_ctx->iproprole) {
1412
load = &iprop_version;
1413
iprop_load = TRUE;
1414
} else {
1415
fprintf(stderr, _("Iprop not enabled\n"));
1416
goto error;
1417
}
1418
} else if (!strcmp(argv[aindex], "-verbose")) {
1419
verbose = TRUE;
1420
} else if (!strcmp(argv[aindex], "-update")){
1421
update = TRUE;
1422
} else if (!strcmp(argv[aindex], "-hash")) {
1423
if (!add_db_arg("hash=true")) {
1424
com_err(progname, ENOMEM, _("while parsing options"));
1425
goto error;
1426
}
1427
} else {
1428
break;
1429
}
1430
}
1431
if (argc - aindex != 1)
1432
usage();
1433
dumpfile = argv[aindex];
1434
1435
/* Open the dumpfile. */
1436
if (dumpfile != NULL) {
1437
f = fopen(dumpfile, "r");
1438
if (f == NULL) {
1439
com_err(progname, errno, _("while opening %s"), dumpfile);
1440
goto error;
1441
}
1442
} else {
1443
f = stdin;
1444
dumpfile = _("standard input");
1445
}
1446
1447
/* Auto-detect dump version if we weren't told, or verify if we were. */
1448
if (fgets(buf, sizeof(buf), f) == NULL) {
1449
fprintf(stderr, _("%s: can't read dump header in %s\n"), progname,
1450
dumpfile);
1451
goto error;
1452
}
1453
if (load) {
1454
/* Only check what we know; some headers only contain a prefix.
1455
* NB: this should work for ipropx even though load is iprop */
1456
if (strncmp(buf, load->header, strlen(load->header)) != 0) {
1457
fprintf(stderr, _("%s: dump header bad in %s\n"), progname,
1458
dumpfile);
1459
goto error;
1460
}
1461
} else {
1462
if (strcmp(buf, beta7_version.header) == 0) {
1463
load = &beta7_version;
1464
} else if (strcmp(buf, r1_3_version.header) == 0) {
1465
load = &r1_3_version;
1466
} else if (strcmp(buf, r1_8_version.header) == 0) {
1467
load = &r1_8_version;
1468
} else if (strcmp(buf, r1_11_version.header) == 0) {
1469
load = &r1_11_version;
1470
} else {
1471
fprintf(stderr, _("%s: dump header bad in %s\n"), progname,
1472
dumpfile);
1473
goto error;
1474
}
1475
}
1476
1477
if (global_params.iprop_enabled &&
1478
ulog_map(util_context, global_params.iprop_logfile,
1479
global_params.iprop_ulogsize)) {
1480
fprintf(stderr, _("Could not open iprop ulog\n"));
1481
goto error;
1482
}
1483
1484
if (load->updateonly && !update) {
1485
fprintf(stderr, _("%s: dump version %s can only be loaded with the "
1486
"-update flag\n"), progname, load->name);
1487
goto error;
1488
}
1489
1490
/* If we are not in update mode, we create an alternate database and then
1491
* promote it to be the live db. */
1492
if (!update) {
1493
if (!add_db_arg("temporary")) {
1494
com_err(progname, ENOMEM, _("computing parameters for database"));
1495
goto error;
1496
}
1497
1498
if (iprop_load && !add_db_arg("merge_nra")) {
1499
com_err(progname, ENOMEM, _("computing parameters for database"));
1500
goto error;
1501
}
1502
1503
ret = krb5_db_create(util_context, db5util_db_args);
1504
if (ret) {
1505
com_err(progname, ret, _("while creating database"));
1506
goto error;
1507
}
1508
temp_db_created = TRUE;
1509
} else {
1510
/* Initialize the database. */
1511
ret = krb5_db_open(util_context, db5util_db_args,
1512
KRB5_KDB_OPEN_RW | KRB5_KDB_SRV_TYPE_ADMIN);
1513
if (ret) {
1514
com_err(progname, ret, _("while opening database"));
1515
goto error;
1516
}
1517
1518
/* Make sure the db is left unusable if the update fails, if the db
1519
* supports locking. */
1520
ret = krb5_db_lock(util_context, KRB5_DB_LOCKMODE_PERMANENT);
1521
if (ret == 0) {
1522
db_locked = TRUE;
1523
} else if (ret != KRB5_PLUGIN_OP_NOTSUPP) {
1524
com_err(progname, ret, _("while permanently locking database"));
1525
goto error;
1526
}
1527
}
1528
1529
if (log_ctx != NULL && log_ctx->iproprole && !update) {
1530
/* Don't record updates we are making to the temporary DB. We will
1531
* reinitialize or update the ulog header after promoting it. */
1532
log_ctx->iproprole = IPROP_REPLICA;
1533
if (iprop_load) {
1534
/* Parse the iprop header information. */
1535
if (!parse_iprop_header(buf, &load, &last))
1536
goto error;
1537
}
1538
}
1539
1540
if (restore_dump(util_context, dumpfile ? dumpfile : _("standard input"),
1541
f, verbose, load)) {
1542
fprintf(stderr, _("%s: %s restore failed\n"), progname, load->name);
1543
goto error;
1544
}
1545
1546
if (db_locked && (ret = krb5_db_unlock(util_context))) {
1547
com_err(progname, ret, _("while unlocking database"));
1548
goto error;
1549
}
1550
1551
if (!update) {
1552
/* Initialize the ulog header before promoting so we can't leave behind
1553
* the pre-load ulog state if we are killed just after promoting. */
1554
if (log_ctx != NULL && log_ctx->iproprole) {
1555
ret = ulog_init_header(util_context);
1556
if (ret) {
1557
com_err(progname, ret, _("while reinitializing update log"));
1558
goto error;
1559
}
1560
}
1561
1562
ret = krb5_db_promote(util_context, db5util_db_args);
1563
/* Ignore a not supported error since there is nothing to do about it
1564
* anyway. */
1565
if (ret != 0 && ret != KRB5_PLUGIN_OP_NOTSUPP) {
1566
com_err(progname, ret,
1567
_("while making newly loaded database live"));
1568
goto error;
1569
}
1570
1571
if (log_ctx != NULL && log_ctx->iproprole) {
1572
/* Reinitialize the ulog header since we replaced the DB, and
1573
* record the iprop state if we received it. */
1574
ret = ulog_init_header(util_context);
1575
if (ret) {
1576
com_err(progname, ret, _("while reinitializing update log"));
1577
goto error;
1578
}
1579
if (iprop_load) {
1580
ret = ulog_set_last(util_context, &last);
1581
if (ret) {
1582
com_err(progname, ret,
1583
_("while writing update log header"));
1584
goto error;
1585
}
1586
}
1587
}
1588
}
1589
1590
cleanup:
1591
/* If we created a temporary DB but didn't succeed, destroy it. */
1592
if (exit_status && temp_db_created) {
1593
ret = krb5_db_destroy(util_context, db5util_db_args);
1594
/* Ignore a not supported error since there is nothing to do about
1595
* it anyway. */
1596
if (ret != 0 && ret != KRB5_PLUGIN_OP_NOTSUPP) {
1597
com_err(progname, ret, _("while deleting bad database %s"),
1598
dbname);
1599
}
1600
}
1601
1602
if (f != NULL && f != stdin)
1603
fclose(f);
1604
1605
return;
1606
1607
error:
1608
exit_status++;
1609
goto cleanup;
1610
}
1611
1612