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