1 /* 2 * Copyright (c) 1997, 1998, 1999 Kungliga Tekniska H�gskolan 3 * (Royal Institute of Technology, Stockholm, Sweden). 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 17 * 3. Neither the name of the Institute nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #include "hprop.h" 35 36 RCSID("$Id: hprop.c,v 1.40 1999/12/04 18:02:18 assar Exp $"); 37 38 static int version_flag; 39 static int help_flag; 40 static char *ktname = HPROP_KEYTAB; 41 static char *database; 42 static char *mkeyfile; 43 static int to_stdout; 44 static int verbose_flag; 45 static int encrypt_flag; 46 static int decrypt_flag; 47 static EncryptionKey mkey5; 48 static krb5_data msched5; 49 50 static int v4_db; 51 static int ka_db; 52 static char *afs_cell; 53 54 #ifdef KRB4 55 static char *realm; 56 57 #ifdef KASERVER_DB 58 static int kaspecials_flag; 59 #endif 60 #endif 61 62 static int 63 open_socket(krb5_context context, const char *hostname) 64 { 65 struct addrinfo *ai, *a; 66 struct addrinfo hints; 67 int error; 68 char portstr[NI_MAXSERV]; 69 70 memset (&hints, 0, sizeof(hints)); 71 hints.ai_socktype = SOCK_STREAM; 72 hints.ai_protocol = IPPROTO_TCP; 73 74 snprintf (portstr, sizeof(portstr), 75 "%u", 76 ntohs(krb5_getportbyname (context, "hprop", "tcp", HPROP_PORT))); 77 78 error = getaddrinfo (hostname, portstr, &hints, &ai); 79 if (error) { 80 warnx ("%s: %s", hostname, gai_strerror(error)); 81 return -1; 82 } 83 84 for (a = ai; a != NULL; a = a->ai_next) { 85 int s; 86 87 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 88 if (s < 0) 89 continue; 90 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 91 warn ("connect(%s)", hostname); 92 close (s); 93 continue; 94 } 95 freeaddrinfo (ai); 96 return s; 97 } 98 warnx ("failed to contact %s", hostname); 99 freeaddrinfo (ai); 100 return -1; 101 } 102 103 struct prop_data{ 104 krb5_context context; 105 krb5_auth_context auth_context; 106 int sock; 107 }; 108 109 int hdb_entry2value(krb5_context, hdb_entry*, krb5_data*); 110 111 static krb5_error_code 112 v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata) 113 { 114 krb5_error_code ret; 115 struct prop_data *pd = appdata; 116 krb5_data data; 117 118 if(encrypt_flag) 119 _hdb_seal_keys_int(entry, 0, msched5); 120 if(decrypt_flag) 121 _hdb_unseal_keys_int(entry, 0, msched5); 122 123 ret = hdb_entry2value(context, entry, &data); 124 if(ret) return ret; 125 126 if(to_stdout) 127 ret = send_clear(context, STDOUT_FILENO, data); 128 else 129 ret = send_priv(context, pd->auth_context, &data, pd->sock); 130 krb5_data_free(&data); 131 return ret; 132 } 133 134 #ifdef KRB4 135 static des_cblock mkey4; 136 static des_key_schedule msched4; 137 static char realm_buf[REALM_SZ]; 138 139 static int 140 v4_prop(void *arg, Principal *p) 141 { 142 struct prop_data *pd = arg; 143 hdb_entry ent; 144 krb5_error_code ret; 145 146 memset(&ent, 0, sizeof(ent)); 147 148 ret = krb5_425_conv_principal(pd->context, p->name, p->instance, realm, 149 &ent.principal); 150 if(ret){ 151 krb5_warn(pd->context, ret, 152 "krb5_425_conv_principal %s.%s@%s", 153 p->name, p->instance, realm); 154 return 0; 155 } 156 157 if(verbose_flag) { 158 char *s; 159 krb5_unparse_name_short(pd->context, ent.principal, &s); 160 krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s); 161 free(s); 162 } 163 164 ent.kvno = p->key_version; 165 ent.keys.len = 3; 166 ent.keys.val = malloc(ent.keys.len * sizeof(*ent.keys.val)); 167 ent.keys.val[0].mkvno = NULL; 168 #if 0 169 ent.keys.val[0].mkvno = malloc (sizeof(*ent.keys.val[0].mkvno)); 170 *(ent.keys.val[0].mkvno) = p->kdc_key_ver; /* XXX */ 171 #endif 172 ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt)); 173 ent.keys.val[0].salt->type = pa_pw_salt; 174 ent.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 175 krb5_data_alloc(&ent.keys.val[0].key.keyvalue, sizeof(des_cblock)); 176 177 { 178 unsigned char *key = ent.keys.val[0].key.keyvalue.data; 179 unsigned char null_key[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; 180 memcpy(key, &p->key_low, 4); 181 memcpy(key + 4, &p->key_high, 4); 182 kdb_encrypt_key((des_cblock*)key, (des_cblock*)key, 183 &mkey4, msched4, DES_DECRYPT); 184 if(memcmp(key, null_key, sizeof(null_key)) == 0) { 185 free_Key(&ent.keys.val[0]); 186 ent.keys.val = 0; 187 ent.flags.invalid = 1; 188 } 189 } 190 copy_Key(&ent.keys.val[0], &ent.keys.val[1]); 191 ent.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 192 copy_Key(&ent.keys.val[0], &ent.keys.val[2]); 193 ent.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 194 195 ALLOC(ent.max_life); 196 *ent.max_life = krb_life_to_time(0, p->max_life); 197 if(*ent.max_life == NEVERDATE){ 198 free(ent.max_life); 199 ent.max_life = NULL; 200 } 201 202 ALLOC(ent.pw_end); 203 *ent.pw_end = p->exp_date; 204 ret = krb5_make_principal(pd->context, &ent.created_by.principal, 205 realm, 206 "kadmin", 207 "hprop", 208 NULL); 209 if(ret){ 210 krb5_warn(pd->context, ret, "krb5_make_principal"); 211 ret = 0; 212 goto out; 213 } 214 ent.created_by.time = time(NULL); 215 ALLOC(ent.modified_by); 216 ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, 217 realm, &ent.modified_by->principal); 218 if(ret){ 219 krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, realm); 220 ent.modified_by->principal = NULL; 221 ret = 0; 222 goto out; 223 } 224 ent.modified_by->time = p->mod_date; 225 226 ent.flags.forwardable = 1; 227 ent.flags.renewable = 1; 228 ent.flags.proxiable = 1; 229 ent.flags.postdate = 1; 230 ent.flags.client = 1; 231 ent.flags.server = 1; 232 233 /* special case password changing service */ 234 if(strcmp(p->name, "changepw") == 0 && 235 strcmp(p->instance, "kerberos") == 0) { 236 ent.flags.forwardable = 0; 237 ent.flags.renewable = 0; 238 ent.flags.proxiable = 0; 239 ent.flags.postdate = 0; 240 ent.flags.initial = 1; 241 ent.flags.change_pw = 1; 242 } 243 244 ret = v5_prop(pd->context, NULL, &ent, pd); 245 246 if (strcmp (p->name, "krbtgt") == 0 247 && strcmp (realm, p->instance) != 0) { 248 krb5_free_principal (pd->context, ent.principal); 249 ret = krb5_425_conv_principal (pd->context, p->name, 250 realm, p->instance, 251 &ent.principal); 252 if (ret == 0) 253 ret = v5_prop (pd->context, NULL, &ent, pd); 254 } 255 256 out: 257 hdb_free_entry(pd->context, &ent); 258 return ret; 259 } 260 261 #ifdef KASERVER_DB 262 263 #include "kadb.h" 264 265 /* read a `ka_entry' from `fd' at offset `pos' */ 266 static void 267 read_block(krb5_context context, int fd, int32_t pos, void *buf, size_t len) 268 { 269 krb5_error_code ret; 270 if(lseek(fd, 64 + pos, SEEK_SET) == (off_t)-1) 271 krb5_err(context, 1, errno, "lseek(%u)", 64 + pos); 272 ret = read(fd, buf, len); 273 if(ret < 0) 274 krb5_err(context, 1, errno, "read(%u)", len); 275 if(ret != len) 276 krb5_errx(context, 1, "read(%u) = %u", len, ret); 277 } 278 279 static int 280 ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent, 281 const char *cell) 282 { 283 int32_t flags = ntohl(ent->flags); 284 krb5_error_code ret; 285 hdb_entry hdb; 286 287 if(!kaspecials_flag 288 && (flags & KAFNORMAL) == 0) /* remove special entries */ 289 return 0; 290 memset(&hdb, 0, sizeof(hdb)); 291 ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, realm, 292 &hdb.principal); 293 if(ret) { 294 krb5_warn(pd->context, ret, 295 "krb5_425_conv_principal (%s.%s@%s)", 296 ent->name, ent->instance, realm); 297 return 0; 298 } 299 hdb.kvno = ntohl(ent->kvno); 300 hdb.keys.len = 3; 301 hdb.keys.val = malloc(hdb.keys.len * sizeof(*hdb.keys.val)); 302 hdb.keys.val[0].mkvno = NULL; 303 hdb.keys.val[0].salt = calloc(1, sizeof(*hdb.keys.val[0].salt)); 304 hdb.keys.val[0].salt->type = hdb_afs3_salt; 305 hdb.keys.val[0].salt->salt.data = strdup(cell); 306 hdb.keys.val[0].salt->salt.length = strlen(cell); 307 308 hdb.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 309 krb5_data_copy(&hdb.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key)); 310 copy_Key(&hdb.keys.val[0], &hdb.keys.val[1]); 311 hdb.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 312 copy_Key(&hdb.keys.val[0], &hdb.keys.val[2]); 313 hdb.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 314 315 ALLOC(hdb.max_life); 316 *hdb.max_life = ntohl(ent->max_life); 317 318 if(ntohl(ent->pw_end) != NEVERDATE && ntohl(ent->pw_end) != -1){ 319 ALLOC(hdb.pw_end); 320 *hdb.pw_end = ntohl(ent->pw_end); 321 } 322 323 ret = krb5_make_principal(pd->context, &hdb.created_by.principal, 324 realm, 325 "kadmin", 326 "hprop", 327 NULL); 328 hdb.created_by.time = time(NULL); 329 330 if(ent->mod_ptr){ 331 struct ka_entry mod; 332 ALLOC(hdb.modified_by); 333 read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod)); 334 335 krb5_425_conv_principal(pd->context, mod.name, mod.instance, realm, 336 &hdb.modified_by->principal); 337 hdb.modified_by->time = ntohl(ent->mod_time); 338 memset(&mod, 0, sizeof(mod)); 339 } 340 341 hdb.flags.forwardable = 1; 342 hdb.flags.renewable = 1; 343 hdb.flags.proxiable = 1; 344 hdb.flags.postdate = 1; 345 /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */ 346 if (strcmp(ent->name, "krbtgt") == 0 && 347 (flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL)) 348 flags &= ~(KAFNOTGS|KAFNOSEAL); 349 350 hdb.flags.client = (flags & KAFNOTGS) == 0; 351 hdb.flags.server = (flags & KAFNOSEAL) == 0; 352 353 ret = v5_prop(pd->context, NULL, &hdb, pd); 354 hdb_free_entry(pd->context, &hdb); 355 return ret; 356 } 357 358 static int 359 ka_dump(struct prop_data *pd, const char *file, const char *cell) 360 { 361 struct ka_header header; 362 int i; 363 int fd = open(file, O_RDONLY); 364 365 if(fd < 0) 366 krb5_err(pd->context, 1, errno, "open(%s)", file); 367 read_block(pd->context, fd, 0, &header, sizeof(header)); 368 if(header.version1 != header.version2) 369 krb5_errx(pd->context, 1, "Version mismatch in header: %d/%d", 370 ntohl(header.version1), ntohl(header.version2)); 371 if(ntohl(header.version1) != 5) 372 krb5_errx(pd->context, 1, "Unknown database version %d (expected 5)", 373 ntohl(header.version1)); 374 for(i = 0; i < ntohl(header.hashsize); i++){ 375 int32_t pos = ntohl(header.hash[i]); 376 while(pos){ 377 struct ka_entry ent; 378 read_block(pd->context, fd, pos, &ent, sizeof(ent)); 379 ka_convert(pd, fd, &ent, cell); 380 pos = ntohl(ent.next); 381 } 382 } 383 return 0; 384 } 385 386 #endif /* KASERVER_DB */ 387 388 #endif /* KRB4 */ 389 390 391 struct getargs args[] = { 392 { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" }, 393 #ifdef KRB4 394 #endif 395 { "database", 'd', arg_string, &database, "database", "file" }, 396 #ifdef KRB4 397 { "v4-db", '4', arg_flag, &v4_db, "use version 4 database" }, 398 { "v4-realm", 'r', arg_string, &realm, "v4 realm to use" }, 399 #endif 400 #ifdef KASERVER_DB 401 { "ka-db", 'K', arg_flag, &ka_db, "use kaserver database" }, 402 { "cell", 'c', arg_string, &afs_cell, "name of AFS cell" }, 403 { "kaspecials", 'S', arg_flag, &kaspecials_flag, "dump KASPECIAL keys"}, 404 #endif 405 { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" }, 406 { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" }, 407 { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" }, 408 { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" }, 409 { "verbose", 'v', arg_flag, &verbose_flag }, 410 { "version", 0, arg_flag, &version_flag }, 411 { "help", 'h', arg_flag, &help_flag } 412 }; 413 414 static int num_args = sizeof(args) / sizeof(args[0]); 415 416 static void 417 usage(int ret) 418 { 419 arg_printusage (args, num_args, NULL, "host ..."); 420 exit (ret); 421 } 422 423 static void 424 get_creds(krb5_context context, krb5_ccache *cache) 425 { 426 krb5_keytab keytab; 427 krb5_principal client; 428 krb5_error_code ret; 429 krb5_get_init_creds_opt init_opts; 430 krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; 431 krb5_creds creds; 432 433 ret = krb5_kt_resolve(context, ktname, &keytab); 434 if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); 435 436 ret = krb5_make_principal(context, &client, NULL, 437 "kadmin", HPROP_NAME, NULL); 438 if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); 439 440 krb5_get_init_creds_opt_init(&init_opts); 441 krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1); 442 443 ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, &init_opts); 444 if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 445 446 ret = krb5_kt_close(context, keytab); 447 if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 448 449 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); 450 if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); 451 452 ret = krb5_cc_initialize(context, *cache, client); 453 if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 454 455 ret = krb5_cc_store_cred(context, *cache, &creds); 456 if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 457 } 458 459 static void 460 iterate (krb5_context context, 461 const char *database, 462 const char *afs_cell, 463 HDB *db, 464 int v4_db, int ka_db, 465 struct prop_data *pd) 466 { 467 #ifdef KRB4 468 if(v4_db) { 469 int e = kerb_db_iterate ((k_iter_proc_t)v4_prop, pd); 470 if(e) 471 krb5_errx(context, 1, "kerb_db_iterate: %s", 472 krb_get_err_text(e)); 473 #ifdef KASERVER_DB 474 } else if(ka_db) { 475 int e = ka_dump(pd, database, afs_cell); 476 if(e) 477 krb5_errx(context, 1, "ka_dump: %s", krb_get_err_text(e)); 478 #endif 479 } else 480 #endif 481 { 482 krb5_error_code ret = hdb_foreach(context, db, HDB_F_DECRYPT, 483 v5_prop, pd); 484 if(ret) 485 krb5_err(context, 1, ret, "hdb_foreach"); 486 } 487 } 488 489 static int 490 dump_database (krb5_context context, int v4_db, int ka_db, 491 const char *database, const char *afs_cell, 492 HDB *db) 493 { 494 struct prop_data pd; 495 496 pd.context = context; 497 pd.auth_context = NULL; 498 pd.sock = STDOUT_FILENO; 499 500 iterate (context, database, afs_cell, db, v4_db, ka_db, &pd); 501 return 0; 502 } 503 504 static int 505 propagate_database (krb5_context context, int v4_db, int ka_db, 506 const char *database, const char *afs_cell, 507 HDB *db, krb5_ccache ccache, 508 int optind, int argc, char **argv) 509 { 510 krb5_principal server; 511 krb5_error_code ret; 512 int i; 513 514 for(i = optind; i < argc; i++){ 515 krb5_auth_context auth_context; 516 int fd; 517 struct prop_data pd; 518 krb5_data data; 519 520 fd = open_socket(context, argv[i]); 521 if(fd < 0) { 522 krb5_warn (context, errno, "connect %s", argv[i]); 523 continue; 524 } 525 526 ret = krb5_sname_to_principal(context, argv[i], 527 HPROP_NAME, KRB5_NT_SRV_HST, &server); 528 if(ret) { 529 krb5_warn(context, ret, "krb5_sname_to_principal(%s)", argv[i]); 530 close(fd); 531 continue; 532 } 533 534 auth_context = NULL; 535 ret = krb5_sendauth(context, 536 &auth_context, 537 &fd, 538 HPROP_VERSION, 539 NULL, 540 server, 541 AP_OPTS_MUTUAL_REQUIRED, 542 NULL, /* in_data */ 543 NULL, /* in_creds */ 544 ccache, 545 NULL, 546 NULL, 547 NULL); 548 549 if(ret) { 550 krb5_warn(context, ret, "krb5_sendauth"); 551 close(fd); 552 continue; 553 } 554 555 pd.context = context; 556 pd.auth_context = auth_context; 557 pd.sock = fd; 558 559 iterate (context, database, afs_cell, db, 560 v4_db, ka_db, &pd); 561 562 data.data = NULL; 563 data.length = 0; 564 ret = send_priv(context, auth_context, &data, fd); 565 if(ret) 566 krb5_warn(context, ret, "send_priv"); 567 568 ret = recv_priv(context, auth_context, fd, &data); 569 if(ret) 570 krb5_warn(context, ret, "recv_priv"); 571 else 572 krb5_data_free (&data); 573 574 krb5_auth_con_free(context, auth_context); 575 close(fd); 576 } 577 return 0; 578 } 579 580 int 581 main(int argc, char **argv) 582 { 583 krb5_error_code ret; 584 krb5_context context; 585 krb5_ccache ccache; 586 HDB *db; 587 int optind = 0; 588 589 set_progname(argv[0]); 590 591 if(getarg(args, num_args, argc, argv, &optind)) 592 usage(1); 593 594 if(help_flag) 595 usage(0); 596 597 if(version_flag){ 598 print_version(NULL); 599 exit(0); 600 } 601 602 ret = krb5_init_context(&context); 603 if(ret) 604 exit(1); 605 606 if(encrypt_flag && decrypt_flag) 607 krb5_errx(context, 1, 608 "Only one of `--encrypt' and `--decrypt' is meaningful"); 609 610 if(!to_stdout) 611 get_creds(context, &ccache); 612 613 ret = hdb_read_master_key(context, mkeyfile, &mkey5); 614 if(ret && ret != ENOENT) 615 krb5_err(context, 1, ret, "hdb_read_master_key"); 616 if(ret) { 617 if(encrypt_flag || decrypt_flag) 618 krb5_errx(context, 1, "No master key file found"); 619 } else { 620 ret = hdb_process_master_key(context, mkey5, &msched5); 621 if(ret) 622 krb5_err(context, 1, ret, "hdb_process_master_key"); 623 } 624 625 #ifdef KRB4 626 if (v4_db 627 #ifdef KASERVER_DB 628 || ka_db 629 #endif 630 ) { 631 int e; 632 633 if (realm == NULL) { 634 e = krb_get_lrealm(realm_buf, 1); 635 if(e) 636 krb5_errx(context, 1, "krb_get_lrealm: %s", 637 krb_get_err_text(e)); 638 realm = realm_buf; 639 } 640 } 641 642 if(v4_db) { 643 int e = kerb_db_set_name (database); 644 if(e) 645 krb5_errx(context, 1, "kerb_db_set_name: %s", 646 krb_get_err_text(e)); 647 e = kdb_get_master_key(0, &mkey4, msched4); 648 if(e) 649 krb5_errx(context, 1, "kdb_get_master_key: %s", 650 krb_get_err_text(e)); 651 } else 652 #ifdef KASERVER_DB 653 if (ka_db) { 654 /* no preparation required */ 655 } else 656 #endif 657 #endif /* KRB4 */ 658 { 659 ret = hdb_create (context, &db, database); 660 if(ret) 661 krb5_err(context, 1, ret, "hdb_create: %s", database); 662 ret = db->open(context, db, O_RDONLY, 0); 663 if(ret) 664 krb5_err(context, 1, ret, "db->open"); 665 } 666 667 if (to_stdout) 668 dump_database (context, v4_db, ka_db, 669 database, afs_cell, db); 670 else 671 propagate_database (context, v4_db, ka_db, 672 database, afs_cell, 673 db, ccache, 674 optind, argc, argv); 675 return 0; 676 } 677