1 /* 2 * Copyright (c) 1997 - 2001 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.60 2001/02/05 03:40:00 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 hdb_master_key mkey5; 48 49 static char *source_type; 50 51 static char *afs_cell; 52 static char *realm; 53 54 #ifdef KRB4 55 static int v4_db; 56 57 static des_cblock mkey4; 58 static des_key_schedule msched4; 59 60 #ifdef KASERVER_DB 61 static int kaspecials_flag; 62 static int ka_db; 63 static int ka_use_null_salt; 64 #endif 65 #endif 66 67 static char *local_realm=NULL; 68 69 static int 70 open_socket(krb5_context context, const char *hostname, const char *port) 71 { 72 struct addrinfo *ai, *a; 73 struct addrinfo hints; 74 int error; 75 76 memset (&hints, 0, sizeof(hints)); 77 hints.ai_socktype = SOCK_STREAM; 78 hints.ai_protocol = IPPROTO_TCP; 79 80 error = getaddrinfo (hostname, port, &hints, &ai); 81 if (error) { 82 warnx ("%s: %s", hostname, gai_strerror(error)); 83 return -1; 84 } 85 86 for (a = ai; a != NULL; a = a->ai_next) { 87 int s; 88 89 s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 90 if (s < 0) 91 continue; 92 if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 93 warn ("connect(%s)", hostname); 94 close (s); 95 continue; 96 } 97 freeaddrinfo (ai); 98 return s; 99 } 100 warnx ("failed to contact %s", hostname); 101 freeaddrinfo (ai); 102 return -1; 103 } 104 105 krb5_error_code 106 v5_prop(krb5_context context, HDB *db, hdb_entry *entry, void *appdata) 107 { 108 krb5_error_code ret; 109 struct prop_data *pd = appdata; 110 krb5_data data; 111 112 if(encrypt_flag) { 113 ret = hdb_seal_keys_mkey(context, entry, mkey5); 114 if (ret) { 115 krb5_warn(context, ret, "hdb_seal_keys_mkey"); 116 return ret; 117 } 118 } 119 if(decrypt_flag) { 120 ret = hdb_unseal_keys_mkey(context, entry, mkey5); 121 if (ret) { 122 krb5_warn(context, ret, "hdb_unseal_keys_mkey"); 123 return ret; 124 } 125 } 126 127 ret = hdb_entry2value(context, entry, &data); 128 if(ret) { 129 krb5_warn(context, ret, "hdb_entry2value"); 130 return ret; 131 } 132 133 if(to_stdout) 134 ret = krb5_write_message(context, &pd->sock, &data); 135 else 136 ret = krb5_write_priv_message(context, pd->auth_context, 137 &pd->sock, &data); 138 krb5_data_free(&data); 139 return ret; 140 } 141 142 #ifdef KRB4 143 144 static char realm_buf[REALM_SZ]; 145 146 static int 147 kdb_prop(void *arg, Principal *p) 148 { 149 int ret; 150 struct v4_principal pr; 151 152 memset(&pr, 0, sizeof(pr)); 153 154 if(p->attributes != 0) { 155 warnx("%s.%s has non-zero attributes - skipping", 156 p->name, p->instance); 157 return 0; 158 } 159 strlcpy(pr.name, p->name, sizeof(pr.name)); 160 strlcpy(pr.instance, p->instance, sizeof(pr.instance)); 161 162 copy_to_key(&p->key_low, &p->key_high, pr.key); 163 kdb_encrypt_key(&pr.key, &pr.key, &mkey4, msched4, DES_DECRYPT); 164 pr.exp_date = p->exp_date; 165 pr.mod_date = p->mod_date; 166 strlcpy(pr.mod_name, p->mod_name, sizeof(pr.mod_name)); 167 strlcpy(pr.mod_instance, p->mod_instance, sizeof(pr.mod_instance)); 168 pr.max_life = p->max_life; 169 pr.mkvno = -1; /* p->kdc_key_ver; */ 170 pr.kvno = p->key_version; 171 172 ret = v4_prop(arg, &pr); 173 memset(&pr, 0, sizeof(pr)); 174 return ret; 175 } 176 177 #endif /* KRB4 */ 178 179 #ifndef KRB4 180 static time_t 181 krb_life_to_time(time_t start, int life) 182 { 183 static int lifetimes[] = { 184 38400, 41055, 43894, 46929, 50174, 53643, 57352, 61318, 185 65558, 70091, 74937, 80119, 85658, 91581, 97914, 104684, 186 111922, 119661, 127935, 136781, 146239, 156350, 167161, 178720, 187 191077, 204289, 218415, 233517, 249664, 266926, 285383, 305116, 188 326213, 348769, 372885, 398668, 426234, 455705, 487215, 520904, 189 556921, 595430, 636601, 680618, 727680, 777995, 831789, 889303, 190 950794, 1016537, 1086825, 1161973, 1242318, 1328218, 1420057, 1518247, 191 1623226, 1735464, 1855462, 1983758, 2120925, 2267576, 2424367, 2592000 192 }; 193 194 #if 0 195 int i; 196 double q = exp((log(2592000.0) - log(38400.0)) / 63); 197 double x = 38400; 198 for(i = 0; i < 64; i++) { 199 lifetimes[i] = (int)x; 200 x *= q; 201 } 202 #endif 203 204 if(life == 0xff) 205 return NEVERDATE; 206 if(life < 0x80) 207 return start + life * 5 * 60; 208 if(life > 0xbf) 209 life = 0xbf; 210 return start + lifetimes[life - 0x80]; 211 } 212 #endif /* !KRB4 */ 213 214 int 215 v4_prop(void *arg, struct v4_principal *p) 216 { 217 struct prop_data *pd = arg; 218 hdb_entry ent; 219 krb5_error_code ret; 220 221 memset(&ent, 0, sizeof(ent)); 222 223 ret = krb5_425_conv_principal(pd->context, p->name, p->instance, realm, 224 &ent.principal); 225 if(ret){ 226 krb5_warn(pd->context, ret, 227 "krb5_425_conv_principal %s.%s@%s", 228 p->name, p->instance, realm); 229 return 0; 230 } 231 232 if(verbose_flag) { 233 char *s; 234 krb5_unparse_name_short(pd->context, ent.principal, &s); 235 krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s); 236 free(s); 237 } 238 239 ent.kvno = p->kvno; 240 ent.keys.len = 3; 241 ent.keys.val = malloc(ent.keys.len * sizeof(*ent.keys.val)); 242 if(p->mkvno != -1) { 243 ent.keys.val[0].mkvno = malloc (sizeof(*ent.keys.val[0].mkvno)); 244 #if 0 245 *(ent.keys.val[0].mkvno) = p->mkvno; /* XXX */ 246 #else 247 *(ent.keys.val[0].mkvno) = 0; 248 #endif 249 } else 250 ent.keys.val[0].mkvno = NULL; 251 ent.keys.val[0].salt = calloc(1, sizeof(*ent.keys.val[0].salt)); 252 ent.keys.val[0].salt->type = KRB5_PADATA_PW_SALT; 253 ent.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 254 krb5_data_alloc(&ent.keys.val[0].key.keyvalue, sizeof(des_cblock)); 255 memcpy(ent.keys.val[0].key.keyvalue.data, p->key, 8); 256 257 copy_Key(&ent.keys.val[0], &ent.keys.val[1]); 258 ent.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 259 copy_Key(&ent.keys.val[0], &ent.keys.val[2]); 260 ent.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 261 262 { 263 int life = krb_life_to_time(0, p->max_life); 264 if(life == NEVERDATE){ 265 ent.max_life = NULL; 266 } else { 267 /* clean up lifetime a bit */ 268 if(life > 86400) 269 life = (life + 86399) / 86400 * 86400; 270 else if(life > 3600) 271 life = (life + 3599) / 3600 * 3600; 272 ALLOC(ent.max_life); 273 *ent.max_life = life; 274 } 275 } 276 277 ALLOC(ent.valid_end); 278 *ent.valid_end = p->exp_date; 279 280 ret = krb5_make_principal(pd->context, &ent.created_by.principal, 281 realm, 282 "kadmin", 283 "hprop", 284 NULL); 285 if(ret){ 286 krb5_warn(pd->context, ret, "krb5_make_principal"); 287 ret = 0; 288 goto out; 289 } 290 ent.created_by.time = time(NULL); 291 ALLOC(ent.modified_by); 292 ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, 293 realm, &ent.modified_by->principal); 294 if(ret){ 295 krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, realm); 296 ent.modified_by->principal = NULL; 297 ret = 0; 298 goto out; 299 } 300 ent.modified_by->time = p->mod_date; 301 302 ent.flags.forwardable = 1; 303 ent.flags.renewable = 1; 304 ent.flags.proxiable = 1; 305 ent.flags.postdate = 1; 306 ent.flags.client = 1; 307 ent.flags.server = 1; 308 309 /* special case password changing service */ 310 if(strcmp(p->name, "changepw") == 0 && 311 strcmp(p->instance, "kerberos") == 0) { 312 ent.flags.forwardable = 0; 313 ent.flags.renewable = 0; 314 ent.flags.proxiable = 0; 315 ent.flags.postdate = 0; 316 ent.flags.initial = 1; 317 ent.flags.change_pw = 1; 318 } 319 320 ret = v5_prop(pd->context, NULL, &ent, pd); 321 322 if (strcmp (p->name, "krbtgt") == 0 323 && strcmp (realm, p->instance) != 0) { 324 krb5_free_principal (pd->context, ent.principal); 325 ret = krb5_425_conv_principal (pd->context, p->name, 326 realm, p->instance, 327 &ent.principal); 328 if (ret == 0) 329 ret = v5_prop (pd->context, NULL, &ent, pd); 330 } 331 332 out: 333 hdb_free_entry(pd->context, &ent); 334 return ret; 335 } 336 337 #ifdef KRB4 338 #ifdef KASERVER_DB 339 340 #include "kadb.h" 341 342 /* read a `ka_entry' from `fd' at offset `pos' */ 343 static void 344 read_block(krb5_context context, int fd, int32_t pos, void *buf, size_t len) 345 { 346 krb5_error_code ret; 347 if(lseek(fd, 64 + pos, SEEK_SET) == (off_t)-1) 348 krb5_err(context, 1, errno, "lseek(%u)", 64 + pos); 349 ret = read(fd, buf, len); 350 if(ret < 0) 351 krb5_err(context, 1, errno, "read(%u)", len); 352 if(ret != len) 353 krb5_errx(context, 1, "read(%u) = %u", len, ret); 354 } 355 356 static int 357 ka_convert(struct prop_data *pd, int fd, struct ka_entry *ent, 358 const char *cell) 359 { 360 int32_t flags = ntohl(ent->flags); 361 krb5_error_code ret; 362 hdb_entry hdb; 363 364 if(!kaspecials_flag 365 && (flags & KAFNORMAL) == 0) /* remove special entries */ 366 return 0; 367 memset(&hdb, 0, sizeof(hdb)); 368 ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, realm, 369 &hdb.principal); 370 if(ret) { 371 krb5_warn(pd->context, ret, 372 "krb5_425_conv_principal (%s.%s@%s)", 373 ent->name, ent->instance, realm); 374 return 0; 375 } 376 hdb.kvno = ntohl(ent->kvno); 377 hdb.keys.len = 3; 378 hdb.keys.val = malloc(hdb.keys.len * sizeof(*hdb.keys.val)); 379 hdb.keys.val[0].mkvno = NULL; 380 hdb.keys.val[0].salt = calloc(1, sizeof(*hdb.keys.val[0].salt)); 381 if (ka_use_null_salt) { 382 hdb.keys.val[0].salt->type = hdb_pw_salt; 383 hdb.keys.val[0].salt->salt.data = NULL; 384 hdb.keys.val[0].salt->salt.length = 0; 385 } else { 386 hdb.keys.val[0].salt->type = hdb_afs3_salt; 387 hdb.keys.val[0].salt->salt.data = strdup(cell); 388 hdb.keys.val[0].salt->salt.length = strlen(cell); 389 } 390 391 hdb.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 392 krb5_data_copy(&hdb.keys.val[0].key.keyvalue, ent->key, sizeof(ent->key)); 393 copy_Key(&hdb.keys.val[0], &hdb.keys.val[1]); 394 hdb.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 395 copy_Key(&hdb.keys.val[0], &hdb.keys.val[2]); 396 hdb.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 397 398 ALLOC(hdb.max_life); 399 *hdb.max_life = ntohl(ent->max_life); 400 401 if(ntohl(ent->valid_end) != NEVERDATE && ntohl(ent->valid_end) != -1){ 402 ALLOC(hdb.valid_end); 403 *hdb.valid_end = ntohl(ent->valid_end); 404 } 405 406 if (ntohl(ent->pw_change) != NEVERDATE && 407 ent->pw_expire != 255 && 408 ent->pw_expire != 0) { 409 ALLOC(hdb.pw_end); 410 *hdb.pw_end = ntohl(ent->pw_change) 411 + 24 * 60 * 60 * ent->pw_expire; 412 } 413 414 ret = krb5_make_principal(pd->context, &hdb.created_by.principal, 415 realm, 416 "kadmin", 417 "hprop", 418 NULL); 419 hdb.created_by.time = time(NULL); 420 421 if(ent->mod_ptr){ 422 struct ka_entry mod; 423 ALLOC(hdb.modified_by); 424 read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod)); 425 426 krb5_425_conv_principal(pd->context, mod.name, mod.instance, realm, 427 &hdb.modified_by->principal); 428 hdb.modified_by->time = ntohl(ent->mod_time); 429 memset(&mod, 0, sizeof(mod)); 430 } 431 432 hdb.flags.forwardable = 1; 433 hdb.flags.renewable = 1; 434 hdb.flags.proxiable = 1; 435 hdb.flags.postdate = 1; 436 /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */ 437 if (strcmp(ent->name, "krbtgt") == 0 && 438 (flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL)) 439 flags &= ~(KAFNOTGS|KAFNOSEAL); 440 441 hdb.flags.client = (flags & KAFNOTGS) == 0; 442 hdb.flags.server = (flags & KAFNOSEAL) == 0; 443 444 ret = v5_prop(pd->context, NULL, &hdb, pd); 445 hdb_free_entry(pd->context, &hdb); 446 return ret; 447 } 448 449 static int 450 ka_dump(struct prop_data *pd, const char *file, const char *cell) 451 { 452 struct ka_header header; 453 int i; 454 int fd = open(file, O_RDONLY); 455 456 if(fd < 0) 457 krb5_err(pd->context, 1, errno, "open(%s)", file); 458 read_block(pd->context, fd, 0, &header, sizeof(header)); 459 if(header.version1 != header.version2) 460 krb5_errx(pd->context, 1, "Version mismatch in header: %d/%d", 461 ntohl(header.version1), ntohl(header.version2)); 462 if(ntohl(header.version1) != 5) 463 krb5_errx(pd->context, 1, "Unknown database version %d (expected 5)", 464 ntohl(header.version1)); 465 for(i = 0; i < ntohl(header.hashsize); i++){ 466 int32_t pos = ntohl(header.hash[i]); 467 while(pos){ 468 struct ka_entry ent; 469 read_block(pd->context, fd, pos, &ent, sizeof(ent)); 470 ka_convert(pd, fd, &ent, cell); 471 pos = ntohl(ent.next); 472 } 473 } 474 return 0; 475 } 476 477 #endif /* KASERVER_DB */ 478 479 #endif /* KRB4 */ 480 481 482 struct getargs args[] = { 483 { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" }, 484 { "database", 'd', arg_string, &database, "database", "file" }, 485 { "source", 0, arg_string, &source_type, "type of database to read", 486 "heimdal" 487 "|mit-dump" 488 "|krb4-dump" 489 #ifdef KRB4 490 "|krb4-db" 491 #ifdef KASERVER_DB 492 "|kaserver" 493 #endif 494 #endif 495 }, 496 497 #ifdef KRB4 498 { "v4-db", '4', arg_flag, &v4_db }, 499 #endif 500 { "v4-realm", 'r', arg_string, &realm, "v4 realm to use" }, 501 #ifdef KASERVER_DB 502 { "ka-db", 'K', arg_flag, &ka_db }, 503 { "cell", 'c', arg_string, &afs_cell, "name of AFS cell" }, 504 { "kaspecials", 'S', arg_flag, &kaspecials_flag, "dump KASPECIAL keys"}, 505 #endif 506 { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" }, 507 { "v5-realm", 'R', arg_string, &local_realm, "v5 realm to use" }, 508 { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" }, 509 { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" }, 510 { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" }, 511 { "verbose", 'v', arg_flag, &verbose_flag }, 512 { "version", 0, arg_flag, &version_flag }, 513 { "help", 'h', arg_flag, &help_flag } 514 }; 515 516 static int num_args = sizeof(args) / sizeof(args[0]); 517 518 static void 519 usage(int ret) 520 { 521 arg_printusage (args, num_args, NULL, "host ..."); 522 exit (ret); 523 } 524 525 static void 526 get_creds(krb5_context context, krb5_ccache *cache) 527 { 528 krb5_keytab keytab; 529 krb5_principal client; 530 krb5_error_code ret; 531 krb5_get_init_creds_opt init_opts; 532 krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; 533 krb5_creds creds; 534 535 ret = krb5_kt_register(context, &hdb_kt_ops); 536 if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); 537 538 ret = krb5_kt_resolve(context, ktname, &keytab); 539 if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); 540 541 ret = krb5_make_principal(context, &client, NULL, 542 "kadmin", HPROP_NAME, NULL); 543 if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); 544 545 krb5_get_init_creds_opt_init(&init_opts); 546 krb5_get_init_creds_opt_set_preauth_list(&init_opts, &preauth, 1); 547 548 ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, &init_opts); 549 if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 550 551 ret = krb5_kt_close(context, keytab); 552 if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 553 554 ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); 555 if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); 556 557 ret = krb5_cc_initialize(context, *cache, client); 558 if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 559 560 ret = krb5_cc_store_cred(context, *cache, &creds); 561 if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 562 } 563 564 enum hprop_source { 565 HPROP_HEIMDAL = 1, 566 HPROP_KRB4_DB, 567 HPROP_KRB4_DUMP, 568 HPROP_KASERVER, 569 HPROP_MIT_DUMP 570 }; 571 572 #define IS_TYPE_V4(X) ((X) == HPROP_KRB4_DB || (X) == HPROP_KRB4_DUMP || (X) == HPROP_KASERVER) 573 574 struct { 575 int type; 576 const char *name; 577 } types[] = { 578 { HPROP_HEIMDAL, "heimdal" }, 579 { HPROP_KRB4_DUMP, "krb4-dump" }, 580 #ifdef KRB4 581 { HPROP_KRB4_DB, "krb4-db" }, 582 #ifdef KASERVER_DB 583 { HPROP_KASERVER, "kaserver" }, 584 #endif 585 #endif 586 { HPROP_MIT_DUMP, "mit-dump" } 587 }; 588 589 static int 590 parse_source_type(const char *s) 591 { 592 int i; 593 for(i = 0; i < sizeof(types) / sizeof(types[0]); i++) { 594 if(strstr(types[i].name, s) == types[i].name) 595 return types[i].type; 596 } 597 return 0; 598 } 599 600 static void 601 iterate (krb5_context context, 602 const char *database, 603 const char *afs_cell, 604 HDB *db, 605 int type, 606 struct prop_data *pd) 607 { 608 int ret; 609 610 switch(type) { 611 case HPROP_KRB4_DUMP: 612 ret = v4_prop_dump(pd, database); 613 break; 614 #ifdef KRB4 615 case HPROP_KRB4_DB: 616 ret = kerb_db_iterate ((k_iter_proc_t)kdb_prop, pd); 617 if(ret) 618 krb5_errx(context, 1, "kerb_db_iterate: %s", 619 krb_get_err_text(ret)); 620 break; 621 #ifdef KASERVER_DB 622 case HPROP_KASERVER: 623 ret = ka_dump(pd, database, afs_cell); 624 if(ret) 625 krb5_errx(context, 1, "ka_dump: %s", krb_get_err_text(ret)); 626 break; 627 #endif 628 #endif /* KRB4 */ 629 case HPROP_MIT_DUMP: 630 ret = mit_prop_dump(pd, database); 631 if (ret) 632 krb5_errx(context, 1, "mit_prop_dump: %s", 633 krb5_get_err_text(context, ret)); 634 break; 635 case HPROP_HEIMDAL: 636 ret = hdb_foreach(context, db, HDB_F_DECRYPT, v5_prop, pd); 637 if(ret) 638 krb5_err(context, 1, ret, "hdb_foreach"); 639 break; 640 } 641 } 642 643 static int 644 dump_database (krb5_context context, int type, 645 const char *database, const char *afs_cell, 646 HDB *db) 647 { 648 krb5_error_code ret; 649 struct prop_data pd; 650 krb5_data data; 651 652 pd.context = context; 653 pd.auth_context = NULL; 654 pd.sock = STDOUT_FILENO; 655 656 iterate (context, database, afs_cell, db, type, &pd); 657 krb5_data_zero (&data); 658 ret = krb5_write_message (context, &pd.sock, &data); 659 if (ret) 660 krb5_err(context, 1, ret, "krb5_write_message"); 661 662 return 0; 663 } 664 665 static int 666 propagate_database (krb5_context context, int type, 667 const char *database, const char *afs_cell, 668 HDB *db, krb5_ccache ccache, 669 int optind, int argc, char **argv) 670 { 671 krb5_principal server; 672 krb5_error_code ret; 673 int i; 674 675 for(i = optind; i < argc; i++){ 676 krb5_auth_context auth_context; 677 int fd; 678 struct prop_data pd; 679 krb5_data data; 680 681 char *port, portstr[NI_MAXSERV]; 682 683 port = strchr(argv[i], ':'); 684 if(port == NULL) { 685 snprintf(portstr, sizeof(portstr), "%u", 686 ntohs(krb5_getportbyname (context, "hprop", "tcp", 687 HPROP_PORT))); 688 port = portstr; 689 } else 690 *port++ = '\0'; 691 692 fd = open_socket(context, argv[i], port); 693 if(fd < 0) { 694 krb5_warn (context, errno, "connect %s", argv[i]); 695 continue; 696 } 697 698 ret = krb5_sname_to_principal(context, argv[i], 699 HPROP_NAME, KRB5_NT_SRV_HST, &server); 700 if(ret) { 701 krb5_warn(context, ret, "krb5_sname_to_principal(%s)", argv[i]); 702 close(fd); 703 continue; 704 } 705 706 if (local_realm) { 707 krb5_realm my_realm; 708 krb5_get_default_realm(context,&my_realm); 709 710 krb5_princ_set_realm(context,server,&my_realm); 711 } 712 713 auth_context = NULL; 714 ret = krb5_sendauth(context, 715 &auth_context, 716 &fd, 717 HPROP_VERSION, 718 NULL, 719 server, 720 AP_OPTS_MUTUAL_REQUIRED, 721 NULL, /* in_data */ 722 NULL, /* in_creds */ 723 ccache, 724 NULL, 725 NULL, 726 NULL); 727 728 if(ret) { 729 krb5_warn(context, ret, "krb5_sendauth"); 730 close(fd); 731 continue; 732 } 733 734 pd.context = context; 735 pd.auth_context = auth_context; 736 pd.sock = fd; 737 738 iterate (context, database, afs_cell, db, type, &pd); 739 740 krb5_data_zero (&data); 741 ret = krb5_write_priv_message(context, auth_context, &fd, &data); 742 if(ret) 743 krb5_warn(context, ret, "krb5_write_priv_message"); 744 745 ret = krb5_read_priv_message(context, auth_context, &fd, &data); 746 if(ret) 747 krb5_warn(context, ret, "krb5_read_priv_message"); 748 else 749 krb5_data_free (&data); 750 751 krb5_auth_con_free(context, auth_context); 752 close(fd); 753 } 754 return 0; 755 } 756 757 #ifdef KRB4 758 759 static void 760 v4_get_masterkey (krb5_context context, char *database) 761 { 762 int e; 763 764 e = kerb_db_set_name (database); 765 if(e) 766 krb5_errx(context, 1, "kerb_db_set_name: %s", 767 krb_get_err_text(e)); 768 e = kdb_get_master_key(0, &mkey4, msched4); 769 if(e) 770 krb5_errx(context, 1, "kdb_get_master_key: %s", 771 krb_get_err_text(e)); 772 e = kdb_verify_master_key(&mkey4, msched4, NULL); 773 if (e < 0) 774 krb5_errx(context, 1, "kdb_verify_master_key failed"); 775 } 776 777 #endif 778 779 int 780 main(int argc, char **argv) 781 { 782 krb5_error_code ret; 783 krb5_context context; 784 krb5_ccache ccache; 785 HDB *db; 786 int optind = 0; 787 788 int type = 0; 789 790 set_progname(argv[0]); 791 792 if(getarg(args, num_args, argc, argv, &optind)) 793 usage(1); 794 795 if(help_flag) 796 usage(0); 797 798 if(version_flag){ 799 print_version(NULL); 800 exit(0); 801 } 802 803 ret = krb5_init_context(&context); 804 if(ret) 805 exit(1); 806 807 if(local_realm) 808 krb5_set_default_realm(context, local_realm); 809 810 811 if(encrypt_flag && decrypt_flag) 812 krb5_errx(context, 1, 813 "only one of `--encrypt' and `--decrypt' is meaningful"); 814 815 #ifdef KRB4 816 if(v4_db) { 817 if(type != 0) 818 krb5_errx(context, 1, "more than one database type specified"); 819 type = HPROP_KRB4_DB; 820 } 821 #ifdef KASERVER_DB 822 if(ka_db) { 823 if(type != 0) 824 krb5_errx(context, 1, "more than one database type specified"); 825 type = HPROP_KASERVER; 826 } 827 #endif 828 #endif 829 830 if(source_type != NULL) { 831 if(type != 0) 832 krb5_errx(context, 1, "more than one database type specified"); 833 type = parse_source_type(source_type); 834 if(type == 0) 835 krb5_errx(context, 1, "unknown source type `%s'", source_type); 836 } else if(type == 0) 837 type = HPROP_HEIMDAL; 838 839 if(!to_stdout) 840 get_creds(context, &ccache); 841 842 if(decrypt_flag || encrypt_flag) { 843 ret = hdb_read_master_key(context, mkeyfile, &mkey5); 844 if(ret && ret != ENOENT) 845 krb5_err(context, 1, ret, "hdb_read_master_key"); 846 if(ret) 847 krb5_errx(context, 1, "No master key file found"); 848 } 849 850 #ifdef KRB4 851 if (IS_TYPE_V4(type)) { 852 int e; 853 854 if (realm == NULL) { 855 e = krb_get_lrealm(realm_buf, 1); 856 if(e) 857 krb5_errx(context, 1, "krb_get_lrealm: %s", 858 krb_get_err_text(e)); 859 realm = realm_buf; 860 } 861 } 862 #endif 863 864 switch(type) { 865 #ifdef KRB4 866 case HPROP_KRB4_DB: 867 if (database == NULL) 868 krb5_errx(context, 1, "no database specified"); 869 v4_get_masterkey (context, database); 870 break; 871 #ifdef KASERVER_DB 872 case HPROP_KASERVER: 873 if (database == NULL) 874 database = DEFAULT_DATABASE; 875 ka_use_null_salt = krb5_config_get_bool_default(context, NULL, FALSE, 876 "hprop", 877 "afs_uses_null_salt", 878 NULL); 879 880 break; 881 #endif 882 #endif /* KRB4 */ 883 case HPROP_KRB4_DUMP: 884 if (database == NULL) 885 krb5_errx(context, 1, "no dump file specified"); 886 #ifdef KRB4 887 v4_get_masterkey (context, database); 888 #endif 889 break; 890 case HPROP_MIT_DUMP: 891 if (database == NULL) 892 krb5_errx(context, 1, "no dump file specified"); 893 break; 894 case HPROP_HEIMDAL: 895 ret = hdb_create (context, &db, database); 896 if(ret) 897 krb5_err(context, 1, ret, "hdb_create: %s", database); 898 ret = db->open(context, db, O_RDONLY, 0); 899 if(ret) 900 krb5_err(context, 1, ret, "db->open"); 901 break; 902 default: 903 krb5_errx(context, 1, "unknown dump type `%d'", type); 904 break; 905 } 906 907 if (to_stdout) 908 dump_database (context, type, database, afs_cell, db); 909 else 910 propagate_database (context, type, database, afs_cell, 911 db, ccache, optind, argc, argv); 912 return 0; 913 } 914