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