hprop.c revision 178826
1193323Sed/* 2193323Sed * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan 3193323Sed * (Royal Institute of Technology, Stockholm, Sweden). 4193323Sed * All rights reserved. 5193323Sed * 6193323Sed * Redistribution and use in source and binary forms, with or without 7193323Sed * modification, are permitted provided that the following conditions 8193323Sed * are met: 9193323Sed * 10193323Sed * 1. Redistributions of source code must retain the above copyright 11193323Sed * notice, this list of conditions and the following disclaimer. 12193323Sed * 13193323Sed * 2. Redistributions in binary form must reproduce the above copyright 14193323Sed * notice, this list of conditions and the following disclaimer in the 15193323Sed * documentation and/or other materials provided with the distribution. 16193323Sed * 17193323Sed * 3. Neither the name of the Institute nor the names of its contributors 18224145Sdim * may be used to endorse or promote products derived from this software 19224145Sdim * without specific prior written permission. 20226633Sdim * 21208599Srdivacky * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22224145Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23249423Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24234353Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25249423Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26223017Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27223017Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28249423Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29193323Sed * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30193323Sed * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31193323Sed * SUCH DAMAGE. 32193323Sed */ 33223017Sdim 34193323Sed#include "hprop.h" 35234353Sdim 36234353SdimRCSID("$Id: hprop.c 21745 2007-07-31 16:11:25Z lha $"); 37234353Sdim 38239462Sdimstatic int version_flag; 39239462Sdimstatic int help_flag; 40239462Sdimstatic const char *ktname = HPROP_KEYTAB; 41239462Sdimstatic const char *database; 42263508Sdimstatic char *mkeyfile; 43263508Sdimstatic int to_stdout; 44234353Sdimstatic int verbose_flag; 45243830Sdimstatic int encrypt_flag; 46234353Sdimstatic int decrypt_flag; 47263508Sdimstatic hdb_master_key mkey5; 48263508Sdim 49263508Sdimstatic char *source_type; 50263508Sdim 51234353Sdimstatic char *afs_cell; 52239462Sdimstatic char *v4_realm; 53234353Sdim 54239462Sdimstatic int kaspecials_flag; 55239462Sdimstatic int ka_use_null_salt; 56234353Sdim 57234353Sdimstatic char *local_realm=NULL; 58234353Sdim 59234353Sdimstatic int 60234353Sdimopen_socket(krb5_context context, const char *hostname, const char *port) 61234353Sdim{ 62234353Sdim struct addrinfo *ai, *a; 63234353Sdim struct addrinfo hints; 64234353Sdim int error; 65234353Sdim 66234353Sdim memset (&hints, 0, sizeof(hints)); 67234353Sdim hints.ai_socktype = SOCK_STREAM; 68234353Sdim hints.ai_protocol = IPPROTO_TCP; 69234353Sdim 70234353Sdim error = getaddrinfo (hostname, port, &hints, &ai); 71234353Sdim if (error) { 72234353Sdim warnx ("%s: %s", hostname, gai_strerror(error)); 73234353Sdim return -1; 74234353Sdim } 75234353Sdim 76234353Sdim for (a = ai; a != NULL; a = a->ai_next) { 77234353Sdim int s; 78234353Sdim 79234353Sdim s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 80234353Sdim if (s < 0) 81239462Sdim continue; 82234353Sdim if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 83234353Sdim warn ("connect(%s)", hostname); 84263508Sdim close (s); 85263508Sdim continue; 86263508Sdim } 87263508Sdim freeaddrinfo (ai); 88263508Sdim return s; 89263508Sdim } 90263508Sdim warnx ("failed to contact %s", hostname); 91263508Sdim freeaddrinfo (ai); 92263508Sdim return -1; 93234353Sdim} 94234353Sdim 95234353Sdimkrb5_error_code 96234353Sdimv5_prop(krb5_context context, HDB *db, hdb_entry_ex *entry, void *appdata) 97234353Sdim{ 98234353Sdim krb5_error_code ret; 99234353Sdim struct prop_data *pd = appdata; 100234353Sdim krb5_data data; 101234353Sdim 102243830Sdim if(encrypt_flag) { 103243830Sdim ret = hdb_seal_keys_mkey(context, &entry->entry, mkey5); 104243830Sdim if (ret) { 105234353Sdim krb5_warn(context, ret, "hdb_seal_keys_mkey"); 106234353Sdim return ret; 107234353Sdim } 108234353Sdim } 109193323Sed if(decrypt_flag) { 110193323Sed ret = hdb_unseal_keys_mkey(context, &entry->entry, mkey5); 111193323Sed if (ret) { 112221345Sdim krb5_warn(context, ret, "hdb_unseal_keys_mkey"); 113221345Sdim return ret; 114234353Sdim } 115223017Sdim } 116223017Sdim 117234353Sdim ret = hdb_entry2value(context, &entry->entry, &data); 118234353Sdim if(ret) { 119223017Sdim krb5_warn(context, ret, "hdb_entry2value"); 120223017Sdim return ret; 121223017Sdim } 122223017Sdim 123223017Sdim if(to_stdout) 124239462Sdim ret = krb5_write_message(context, &pd->sock, &data); 125239462Sdim else 126239462Sdim ret = krb5_write_priv_message(context, pd->auth_context, 127239462Sdim &pd->sock, &data); 128239462Sdim krb5_data_free(&data); 129223017Sdim return ret; 130239462Sdim} 131223017Sdim 132239462Sdimint 133239462Sdimv4_prop(void *arg, struct v4_principal *p) 134239462Sdim{ 135239462Sdim struct prop_data *pd = arg; 136239462Sdim hdb_entry_ex ent; 137239462Sdim krb5_error_code ret; 138239462Sdim 139223017Sdim memset(&ent, 0, sizeof(ent)); 140223017Sdim 141223017Sdim ret = krb5_425_conv_principal(pd->context, p->name, p->instance, v4_realm, 142223017Sdim &ent.entry.principal); 143223017Sdim if(ret) { 144224145Sdim krb5_warn(pd->context, ret, 145234353Sdim "krb5_425_conv_principal %s.%s@%s", 146234353Sdim p->name, p->instance, v4_realm); 147224145Sdim return 0; 148239462Sdim } 149239462Sdim 150239462Sdim if(verbose_flag) { 151239462Sdim char *s; 152239462Sdim krb5_unparse_name_short(pd->context, ent.entry.principal, &s); 153239462Sdim krb5_warnx(pd->context, "%s.%s -> %s", p->name, p->instance, s); 154234353Sdim free(s); 155224145Sdim } 156239462Sdim 157239462Sdim ent.entry.kvno = p->kvno; 158239462Sdim ent.entry.keys.len = 3; 159224145Sdim ent.entry.keys.val = malloc(ent.entry.keys.len * sizeof(*ent.entry.keys.val)); 160224145Sdim if (ent.entry.keys.val == NULL) 161224145Sdim krb5_errx(pd->context, ENOMEM, "malloc"); 162224145Sdim if(p->mkvno != -1) { 163224145Sdim ent.entry.keys.val[0].mkvno = malloc (sizeof(*ent.entry.keys.val[0].mkvno)); 164239462Sdim if (ent.entry.keys.val[0].mkvno == NULL) 165239462Sdim krb5_errx(pd->context, ENOMEM, "malloc"); 166239462Sdim *(ent.entry.keys.val[0].mkvno) = p->mkvno; 167239462Sdim } else 168239462Sdim ent.entry.keys.val[0].mkvno = NULL; 169239462Sdim ent.entry.keys.val[0].salt = calloc(1, sizeof(*ent.entry.keys.val[0].salt)); 170239462Sdim if (ent.entry.keys.val[0].salt == NULL) 171239462Sdim krb5_errx(pd->context, ENOMEM, "calloc"); 172239462Sdim ent.entry.keys.val[0].salt->type = KRB5_PADATA_PW_SALT; 173239462Sdim ent.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 174239462Sdim krb5_data_alloc(&ent.entry.keys.val[0].key.keyvalue, DES_KEY_SZ); 175239462Sdim memcpy(ent.entry.keys.val[0].key.keyvalue.data, p->key, 8); 176239462Sdim 177239462Sdim copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[1]); 178239462Sdim ent.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 179239462Sdim copy_Key(&ent.entry.keys.val[0], &ent.entry.keys.val[2]); 180239462Sdim ent.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 181234353Sdim 182234353Sdim { 183234353Sdim int life = _krb5_krb_life_to_time(0, p->max_life); 184239462Sdim if(life == NEVERDATE){ 185239462Sdim ent.entry.max_life = NULL; 186239462Sdim } else { 187234353Sdim /* clean up lifetime a bit */ 188239462Sdim if(life > 86400) 189234353Sdim life = (life + 86399) / 86400 * 86400; 190234353Sdim else if(life > 3600) 191239462Sdim life = (life + 3599) / 3600 * 3600; 192239462Sdim ALLOC(ent.entry.max_life); 193239462Sdim *ent.entry.max_life = life; 194239462Sdim } 195239462Sdim } 196234353Sdim 197234353Sdim ALLOC(ent.entry.valid_end); 198234353Sdim *ent.entry.valid_end = p->exp_date; 199234353Sdim 200234353Sdim ret = krb5_make_principal(pd->context, &ent.entry.created_by.principal, 201234353Sdim v4_realm, 202234353Sdim "kadmin", 203234353Sdim "hprop", 204234353Sdim NULL); 205234353Sdim if(ret){ 206234353Sdim krb5_warn(pd->context, ret, "krb5_make_principal"); 207224145Sdim ret = 0; 208224145Sdim goto out; 209224145Sdim } 210224145Sdim ent.entry.created_by.time = time(NULL); 211226633Sdim ALLOC(ent.entry.modified_by); 212224145Sdim ret = krb5_425_conv_principal(pd->context, p->mod_name, p->mod_instance, 213224145Sdim v4_realm, &ent.entry.modified_by->principal); 214224145Sdim if(ret){ 215224145Sdim krb5_warn(pd->context, ret, "%s.%s@%s", p->name, p->instance, v4_realm); 216224145Sdim ent.entry.modified_by->principal = NULL; 217224145Sdim ret = 0; 218224145Sdim goto out; 219223017Sdim } 220223017Sdim ent.entry.modified_by->time = p->mod_date; 221239462Sdim 222239462Sdim ent.entry.flags.forwardable = 1; 223239462Sdim ent.entry.flags.renewable = 1; 224239462Sdim ent.entry.flags.proxiable = 1; 225239462Sdim ent.entry.flags.postdate = 1; 226239462Sdim ent.entry.flags.client = 1; 227239462Sdim ent.entry.flags.server = 1; 228239462Sdim 229239462Sdim /* special case password changing service */ 230239462Sdim if(strcmp(p->name, "changepw") == 0 && 231239462Sdim strcmp(p->instance, "kerberos") == 0) { 232239462Sdim ent.entry.flags.forwardable = 0; 233239462Sdim ent.entry.flags.renewable = 0; 234223017Sdim ent.entry.flags.proxiable = 0; 235224145Sdim ent.entry.flags.postdate = 0; 236239462Sdim ent.entry.flags.initial = 1; 237234353Sdim ent.entry.flags.change_pw = 1; 238193323Sed } 239193323Sed 240193323Sed ret = v5_prop(pd->context, NULL, &ent, pd); 241224145Sdim 242224145Sdim if (strcmp (p->name, "krbtgt") == 0 243226633Sdim && strcmp (v4_realm, p->instance) != 0) { 244226633Sdim krb5_free_principal (pd->context, ent.entry.principal); 245226633Sdim ret = krb5_425_conv_principal (pd->context, p->name, 246226633Sdim v4_realm, p->instance, 247226633Sdim &ent.entry.principal); 248226633Sdim if (ret == 0) 249226633Sdim ret = v5_prop (pd->context, NULL, &ent, pd); 250226633Sdim } 251226633Sdim 252226633Sdim out: 253226633Sdim hdb_free_entry(pd->context, &ent); 254226633Sdim return ret; 255226633Sdim} 256226633Sdim 257234353Sdim#include "kadb.h" 258234353Sdim 259234353Sdim/* read a `ka_entry' from `fd' at offset `pos' */ 260226633Sdimstatic void 261234353Sdimread_block(krb5_context context, int fd, int32_t pos, void *buf, size_t len) 262234353Sdim{ 263234353Sdim krb5_error_code ret; 264234353Sdim#ifdef HAVE_PREAD 265234353Sdim if((ret = pread(fd, buf, len, 64 + pos)) < 0) 266234353Sdim krb5_err(context, 1, errno, "pread(%u)", 64 + pos); 267234353Sdim#else 268234353Sdim if(lseek(fd, 64 + pos, SEEK_SET) == (off_t)-1) 269239462Sdim krb5_err(context, 1, errno, "lseek(%u)", 64 + pos); 270239462Sdim ret = read(fd, buf, len); 271239462Sdim if(ret < 0) 272239462Sdim krb5_err(context, 1, errno, "read(%lu)", (unsigned long)len); 273224145Sdim#endif 274226633Sdim if(ret != len) 275193323Sed krb5_errx(context, 1, "read(%lu) = %u", (unsigned long)len, ret); 276249423Sdim} 277193323Sed 278193323Sedstatic int 279193323Sedka_convert(struct prop_data *pd, int fd, struct ka_entry *ent) 280223017Sdim{ 281224145Sdim int32_t flags = ntohl(ent->flags); 282193323Sed krb5_error_code ret; 283226633Sdim hdb_entry_ex hdb; 284226633Sdim 285226633Sdim if(!kaspecials_flag 286226633Sdim && (flags & KAFNORMAL) == 0) /* remove special entries */ 287226633Sdim return 0; 288226633Sdim memset(&hdb, 0, sizeof(hdb)); 289249423Sdim ret = krb5_425_conv_principal(pd->context, ent->name, ent->instance, 290193323Sed v4_realm, &hdb.entry.principal); 291221345Sdim if(ret) { 292193323Sed krb5_warn(pd->context, ret, 293193323Sed "krb5_425_conv_principal (%s.%s@%s)", 294193323Sed ent->name, ent->instance, v4_realm); 295234353Sdim return 0; 296193323Sed } 297221345Sdim hdb.entry.kvno = ntohl(ent->kvno); 298224145Sdim hdb.entry.keys.len = 3; 299224145Sdim hdb.entry.keys.val = 300221345Sdim malloc(hdb.entry.keys.len * sizeof(*hdb.entry.keys.val)); 301224145Sdim if (hdb.entry.keys.val == NULL) 302212904Sdim krb5_errx(pd->context, ENOMEM, "malloc"); 303221345Sdim hdb.entry.keys.val[0].mkvno = NULL; 304212904Sdim hdb.entry.keys.val[0].salt = calloc(1, sizeof(*hdb.entry.keys.val[0].salt)); 305212904Sdim if (hdb.entry.keys.val[0].salt == NULL) 306212904Sdim krb5_errx(pd->context, ENOMEM, "calloc"); 307212904Sdim if (ka_use_null_salt) { 308212904Sdim hdb.entry.keys.val[0].salt->type = hdb_pw_salt; 309212904Sdim hdb.entry.keys.val[0].salt->salt.data = NULL; 310226633Sdim hdb.entry.keys.val[0].salt->salt.length = 0; 311226633Sdim } else { 312226633Sdim hdb.entry.keys.val[0].salt->type = hdb_afs3_salt; 313193323Sed hdb.entry.keys.val[0].salt->salt.data = strdup(afs_cell); 314226633Sdim if (hdb.entry.keys.val[0].salt->salt.data == NULL) 315226633Sdim krb5_errx(pd->context, ENOMEM, "strdup"); 316234353Sdim hdb.entry.keys.val[0].salt->salt.length = strlen(afs_cell); 317234353Sdim } 318226633Sdim 319226633Sdim hdb.entry.keys.val[0].key.keytype = ETYPE_DES_CBC_MD5; 320226633Sdim krb5_data_copy(&hdb.entry.keys.val[0].key.keyvalue, 321234353Sdim ent->key, 322234353Sdim sizeof(ent->key)); 323226633Sdim copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[1]); 324226633Sdim hdb.entry.keys.val[1].key.keytype = ETYPE_DES_CBC_MD4; 325226633Sdim copy_Key(&hdb.entry.keys.val[0], &hdb.entry.keys.val[2]); 326234353Sdim hdb.entry.keys.val[2].key.keytype = ETYPE_DES_CBC_CRC; 327234353Sdim 328234353Sdim ALLOC(hdb.entry.max_life); 329234353Sdim *hdb.entry.max_life = ntohl(ent->max_life); 330234353Sdim 331234353Sdim if(ntohl(ent->valid_end) != NEVERDATE && ntohl(ent->valid_end) != 0xffffffff) { 332234353Sdim ALLOC(hdb.entry.valid_end); 333234353Sdim *hdb.entry.valid_end = ntohl(ent->valid_end); 334234353Sdim } 335234353Sdim 336226633Sdim if (ntohl(ent->pw_change) != NEVERDATE && 337226633Sdim ent->pw_expire != 255 && 338226633Sdim ent->pw_expire != 0) { 339226633Sdim ALLOC(hdb.entry.pw_end); 340226633Sdim *hdb.entry.pw_end = ntohl(ent->pw_change) 341226633Sdim + 24 * 60 * 60 * ent->pw_expire; 342226633Sdim } 343226633Sdim 344226633Sdim ret = krb5_make_principal(pd->context, &hdb.entry.created_by.principal, 345226633Sdim v4_realm, 346226633Sdim "kadmin", 347224145Sdim "hprop", 348224145Sdim NULL); 349224145Sdim hdb.entry.created_by.time = time(NULL); 350224145Sdim 351226633Sdim if(ent->mod_ptr){ 352224145Sdim struct ka_entry mod; 353212904Sdim ALLOC(hdb.entry.modified_by); 354224145Sdim read_block(pd->context, fd, ntohl(ent->mod_ptr), &mod, sizeof(mod)); 355226633Sdim 356212904Sdim krb5_425_conv_principal(pd->context, mod.name, mod.instance, v4_realm, 357226633Sdim &hdb.entry.modified_by->principal); 358226633Sdim hdb.entry.modified_by->time = ntohl(ent->mod_time); 359226633Sdim memset(&mod, 0, sizeof(mod)); 360226633Sdim } 361239462Sdim 362239462Sdim hdb.entry.flags.forwardable = 1; 363239462Sdim hdb.entry.flags.renewable = 1; 364234353Sdim hdb.entry.flags.proxiable = 1; 365234353Sdim hdb.entry.flags.postdate = 1; 366234353Sdim /* XXX - AFS 3.4a creates krbtgt.REALMOFCELL as NOTGS+NOSEAL */ 367224145Sdim if (strcmp(ent->name, "krbtgt") == 0 && 368226633Sdim (flags & (KAFNOTGS|KAFNOSEAL)) == (KAFNOTGS|KAFNOSEAL)) 369226633Sdim flags &= ~(KAFNOTGS|KAFNOSEAL); 370226633Sdim 371226633Sdim hdb.entry.flags.client = (flags & KAFNOTGS) == 0; 372226633Sdim hdb.entry.flags.server = (flags & KAFNOSEAL) == 0; 373226633Sdim 374226633Sdim ret = v5_prop(pd->context, NULL, &hdb, pd); 375226633Sdim hdb_free_entry(pd->context, &hdb); 376226633Sdim return ret; 377226633Sdim} 378226633Sdim 379226633Sdimstatic int 380226633Sdimka_dump(struct prop_data *pd, const char *file) 381226633Sdim{ 382226633Sdim struct ka_header header; 383226633Sdim int i; 384226633Sdim int fd = open(file, O_RDONLY); 385226633Sdim 386226633Sdim if(fd < 0) 387226633Sdim krb5_err(pd->context, 1, errno, "open(%s)", file); 388226633Sdim read_block(pd->context, fd, 0, &header, sizeof(header)); 389226633Sdim if(header.version1 != header.version2) 390226633Sdim krb5_errx(pd->context, 1, "Version mismatch in header: %ld/%ld", 391226633Sdim (long)ntohl(header.version1), (long)ntohl(header.version2)); 392226633Sdim if(ntohl(header.version1) != 5) 393226633Sdim krb5_errx(pd->context, 1, "Unknown database version %ld (expected 5)", 394226633Sdim (long)ntohl(header.version1)); 395239462Sdim for(i = 0; i < ntohl(header.hashsize); i++){ 396226633Sdim int32_t pos = ntohl(header.hash[i]); 397226633Sdim while(pos){ 398226633Sdim struct ka_entry ent; 399193323Sed read_block(pd->context, fd, pos, &ent, sizeof(ent)); 400223017Sdim ka_convert(pd, fd, &ent); 401239462Sdim pos = ntohl(ent.next); 402239462Sdim } 403239462Sdim } 404239462Sdim return 0; 405239462Sdim} 406239462Sdim 407239462Sdim 408239462Sdim 409239462Sdimstruct getargs args[] = { 410239462Sdim { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" }, 411239462Sdim { "database", 'd', arg_string, &database, "database", "file" }, 412239462Sdim { "source", 0, arg_string, &source_type, "type of database to read", 413239462Sdim "heimdal" 414239462Sdim "|mit-dump" 415239462Sdim "|krb4-dump" 416239462Sdim "|kaserver" 417239462Sdim }, 418249423Sdim 419249423Sdim { "v4-realm", 'r', arg_string, &v4_realm, "v4 realm to use" }, 420249423Sdim { "cell", 'c', arg_string, &afs_cell, "name of AFS cell" }, 421239462Sdim { "kaspecials", 'S', arg_flag, &kaspecials_flag, "dump KASPECIAL keys"}, 422249423Sdim { "keytab", 'k', arg_string, &ktname, "keytab to use for authentication", "keytab" }, 423249423Sdim { "v5-realm", 'R', arg_string, &local_realm, "v5 realm to use" }, 424239462Sdim { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys" }, 425239462Sdim { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys" }, 426239462Sdim { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout" }, 427239462Sdim { "verbose", 'v', arg_flag, &verbose_flag }, 428239462Sdim { "version", 0, arg_flag, &version_flag }, 429239462Sdim { "help", 'h', arg_flag, &help_flag } 430234353Sdim}; 431234353Sdim 432234353Sdimstatic int num_args = sizeof(args) / sizeof(args[0]); 433234353Sdim 434234353Sdimstatic void 435234353Sdimusage(int ret) 436263508Sdim{ 437263508Sdim arg_printusage (args, num_args, NULL, "[host[:port]] ..."); 438263508Sdim exit (ret); 439263508Sdim} 440234353Sdim 441234353Sdimstatic void 442239462Sdimget_creds(krb5_context context, krb5_ccache *cache) 443239462Sdim{ 444239462Sdim krb5_keytab keytab; 445239462Sdim krb5_principal client; 446223017Sdim krb5_error_code ret; 447223017Sdim krb5_get_init_creds_opt *init_opts; 448223017Sdim krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; 449224145Sdim krb5_creds creds; 450224145Sdim 451234353Sdim ret = krb5_kt_register(context, &hdb_kt_ops); 452234353Sdim if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); 453234353Sdim 454234353Sdim ret = krb5_kt_resolve(context, ktname, &keytab); 455239462Sdim if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); 456239462Sdim 457239462Sdim ret = krb5_make_principal(context, &client, NULL, 458239462Sdim "kadmin", HPROP_NAME, NULL); 459239462Sdim if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); 460239462Sdim 461234353Sdim ret = krb5_get_init_creds_opt_alloc(context, &init_opts); 462224145Sdim if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 463243830Sdim krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1); 464223017Sdim 465234353Sdim ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts); 466223017Sdim if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 467239462Sdim 468234353Sdim krb5_get_init_creds_opt_free(context, init_opts); 469239462Sdim 470239462Sdim ret = krb5_kt_close(context, keytab); 471239462Sdim if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 472226633Sdim 473226633Sdim ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); 474224145Sdim if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); 475226633Sdim 476226633Sdim ret = krb5_cc_initialize(context, *cache, client); 477224145Sdim if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 478234353Sdim 479234353Sdim krb5_free_principal(context, client); 480234353Sdim 481234353Sdim ret = krb5_cc_store_cred(context, *cache, &creds); 482234353Sdim if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 483234353Sdim 484234353Sdim krb5_free_cred_contents(context, &creds); 485249423Sdim} 486249423Sdim 487249423Sdimenum hprop_source { 488249423Sdim HPROP_HEIMDAL = 1, 489234353Sdim HPROP_KRB4_DUMP, 490234353Sdim HPROP_KASERVER, 491263508Sdim HPROP_MIT_DUMP 492263508Sdim}; 493263508Sdim 494226633Sdim#define IS_TYPE_V4(X) ((X) == HPROP_KRB4_DUMP || (X) == HPROP_KASERVER) 495226633Sdim 496226633Sdimstruct { 497234353Sdim int type; 498234353Sdim const char *name; 499234353Sdim} types[] = { 500234353Sdim { HPROP_HEIMDAL, "heimdal" }, 501234353Sdim { HPROP_KRB4_DUMP, "krb4-dump" }, 502226633Sdim { HPROP_KASERVER, "kaserver" }, 503226633Sdim { HPROP_MIT_DUMP, "mit-dump" } 504234353Sdim}; 505234353Sdim 506234353Sdimstatic int 507234353Sdimparse_source_type(const char *s) 508226633Sdim{ 509234353Sdim int i; 510234353Sdim for(i = 0; i < sizeof(types) / sizeof(types[0]); i++) { 511223017Sdim if(strstr(types[i].name, s) == types[i].name) 512234353Sdim return types[i].type; 513234353Sdim } 514234353Sdim return 0; 515234353Sdim} 516234353Sdim 517234353Sdimstatic int 518223017Sdimiterate (krb5_context context, 519223017Sdim const char *database_name, 520223017Sdim HDB *db, 521243830Sdim int type, 522243830Sdim struct prop_data *pd) 523243830Sdim{ 524223017Sdim int ret; 525223017Sdim 526223017Sdim switch(type) { 527224145Sdim case HPROP_KRB4_DUMP: 528224145Sdim ret = v4_prop_dump(pd, database_name); 529223017Sdim if(ret) 530223017Sdim krb5_warnx(context, "v4_prop_dump: %s", 531223017Sdim krb5_get_err_text(context, ret)); 532234353Sdim break; 533223017Sdim case HPROP_KASERVER: 534234353Sdim ret = ka_dump(pd, database_name); 535234353Sdim if(ret) 536223017Sdim krb5_warn(context, ret, "ka_dump"); 537223017Sdim break; 538234353Sdim case HPROP_MIT_DUMP: 539234353Sdim ret = mit_prop_dump(pd, database_name); 540223017Sdim if (ret) 541239462Sdim krb5_warnx(context, "mit_prop_dump: %s", 542239462Sdim krb5_get_err_text(context, ret)); 543239462Sdim break; 544263508Sdim case HPROP_HEIMDAL: 545239462Sdim ret = hdb_foreach(context, db, HDB_F_DECRYPT, v5_prop, pd); 546239462Sdim if(ret) 547263508Sdim krb5_warn(context, ret, "hdb_foreach"); 548239462Sdim break; 549239462Sdim default: 550239462Sdim krb5_errx(context, 1, "unknown prop type: %d", type); 551239462Sdim } 552224145Sdim return ret; 553243830Sdim} 554243830Sdim 555243830Sdimstatic int 556223017Sdimdump_database (krb5_context context, int type, 557223017Sdim const char *database_name, HDB *db) 558223017Sdim{ 559223017Sdim krb5_error_code ret; 560234353Sdim struct prop_data pd; 561234353Sdim krb5_data data; 562234353Sdim 563234353Sdim pd.context = context; 564234353Sdim pd.auth_context = NULL; 565239462Sdim pd.sock = STDOUT_FILENO; 566239462Sdim 567239462Sdim ret = iterate (context, database_name, db, type, &pd); 568239462Sdim if (ret) 569239462Sdim krb5_errx(context, 1, "iterate failure"); 570239462Sdim krb5_data_zero (&data); 571239462Sdim ret = krb5_write_message (context, &pd.sock, &data); 572239462Sdim if (ret) 573239462Sdim krb5_err(context, 1, ret, "krb5_write_message"); 574239462Sdim 575239462Sdim return 0; 576239462Sdim} 577239462Sdim 578239462Sdimstatic int 579239462Sdimpropagate_database (krb5_context context, int type, 580239462Sdim const char *database_name, 581239462Sdim HDB *db, krb5_ccache ccache, 582239462Sdim int optidx, int argc, char **argv) 583239462Sdim{ 584239462Sdim krb5_principal server; 585239462Sdim krb5_error_code ret; 586239462Sdim int i, failed = 0; 587234353Sdim 588234353Sdim for(i = optidx; i < argc; i++){ 589234353Sdim krb5_auth_context auth_context; 590239462Sdim int fd; 591239462Sdim struct prop_data pd; 592239462Sdim krb5_data data; 593234353Sdim 594234353Sdim char *port, portstr[NI_MAXSERV]; 595234353Sdim char *host = argv[i]; 596234353Sdim 597234353Sdim port = strchr(host, ':'); 598234353Sdim if(port == NULL) { 599234353Sdim snprintf(portstr, sizeof(portstr), "%u", 600234353Sdim ntohs(krb5_getportbyname (context, "hprop", "tcp", 601234353Sdim HPROP_PORT))); 602239462Sdim port = portstr; 603239462Sdim } else 604239462Sdim *port++ = '\0'; 605239462Sdim 606239462Sdim fd = open_socket(context, host, port); 607239462Sdim if(fd < 0) { 608239462Sdim failed++; 609226633Sdim krb5_warn (context, errno, "connect %s", host); 610224145Sdim continue; 611224145Sdim } 612224145Sdim 613224145Sdim ret = krb5_sname_to_principal(context, argv[i], 614224145Sdim HPROP_NAME, KRB5_NT_SRV_HST, &server); 615224145Sdim if(ret) { 616224145Sdim failed++; 617224145Sdim krb5_warn(context, ret, "krb5_sname_to_principal(%s)", host); 618224145Sdim close(fd); 619224145Sdim continue; 620224145Sdim } 621224145Sdim 622224145Sdim if (local_realm) { 623234353Sdim krb5_realm my_realm; 624234353Sdim krb5_get_default_realm(context,&my_realm); 625234353Sdim 626234353Sdim free (*krb5_princ_realm(context, server)); 627234353Sdim krb5_princ_set_realm(context,server,&my_realm); 628239462Sdim } 629234353Sdim 630234353Sdim auth_context = NULL; 631234353Sdim ret = krb5_sendauth(context, 632263508Sdim &auth_context, 633263508Sdim &fd, 634263508Sdim HPROP_VERSION, 635263508Sdim NULL, 636263508Sdim server, 637263508Sdim AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 638263508Sdim NULL, /* in_data */ 639234353Sdim NULL, /* in_creds */ 640234353Sdim ccache, 641239462Sdim NULL, 642234353Sdim NULL, 643234353Sdim NULL); 644234353Sdim 645234353Sdim krb5_free_principal(context, server); 646234353Sdim 647234353Sdim if(ret) { 648263508Sdim failed++; 649234353Sdim krb5_warn(context, ret, "krb5_sendauth (%s)", host); 650234353Sdim close(fd); 651234353Sdim goto next_host; 652249423Sdim } 653249423Sdim 654249423Sdim pd.context = context; 655249423Sdim pd.auth_context = auth_context; 656249423Sdim pd.sock = fd; 657249423Sdim 658249423Sdim ret = iterate (context, database_name, db, type, &pd); 659234353Sdim if (ret) { 660234353Sdim krb5_warnx(context, "iterate to host %s failed", host); 661234353Sdim failed++; 662234353Sdim goto next_host; 663234353Sdim } 664234353Sdim 665234353Sdim krb5_data_zero (&data); 666234353Sdim ret = krb5_write_priv_message(context, auth_context, &fd, &data); 667223017Sdim if(ret) { 668223017Sdim krb5_warn(context, ret, "krb5_write_priv_message"); 669224145Sdim failed++; 670234353Sdim goto next_host; 671234353Sdim } 672234353Sdim 673234353Sdim ret = krb5_read_priv_message(context, auth_context, &fd, &data); 674234353Sdim if(ret) { 675234353Sdim krb5_warn(context, ret, "krb5_read_priv_message: %s", host); 676234353Sdim failed++; 677234353Sdim goto next_host; 678263508Sdim } else 679263508Sdim krb5_data_free (&data); 680263508Sdim 681263508Sdim next_host: 682263508Sdim krb5_auth_con_free(context, auth_context); 683223017Sdim close(fd); 684193323Sed } 685193323Sed if (failed) 686193323Sed return 1; 687 return 0; 688} 689 690int 691main(int argc, char **argv) 692{ 693 krb5_error_code ret; 694 krb5_context context; 695 krb5_ccache ccache = NULL; 696 HDB *db = NULL; 697 int optidx = 0; 698 699 int type, exit_code; 700 701 setprogname(argv[0]); 702 703 if(getarg(args, num_args, argc, argv, &optidx)) 704 usage(1); 705 706 if(help_flag) 707 usage(0); 708 709 if(version_flag){ 710 print_version(NULL); 711 exit(0); 712 } 713 714 ret = krb5_init_context(&context); 715 if(ret) 716 exit(1); 717 718 if(local_realm) 719 krb5_set_default_realm(context, local_realm); 720 721 if(v4_realm == NULL) { 722 ret = krb5_get_default_realm(context, &v4_realm); 723 if(ret) 724 krb5_err(context, 1, ret, "krb5_get_default_realm"); 725 } 726 727 if(afs_cell == NULL) { 728 afs_cell = strdup(v4_realm); 729 if(afs_cell == NULL) 730 krb5_errx(context, 1, "out of memory"); 731 strlwr(afs_cell); 732 } 733 734 735 if(encrypt_flag && decrypt_flag) 736 krb5_errx(context, 1, 737 "only one of `--encrypt' and `--decrypt' is meaningful"); 738 739 if(source_type != NULL) { 740 type = parse_source_type(source_type); 741 if(type == 0) 742 krb5_errx(context, 1, "unknown source type `%s'", source_type); 743 } else 744 type = HPROP_HEIMDAL; 745 746 if(!to_stdout) 747 get_creds(context, &ccache); 748 749 if(decrypt_flag || encrypt_flag) { 750 ret = hdb_read_master_key(context, mkeyfile, &mkey5); 751 if(ret && ret != ENOENT) 752 krb5_err(context, 1, ret, "hdb_read_master_key"); 753 if(ret) 754 krb5_errx(context, 1, "No master key file found"); 755 } 756 757 if (IS_TYPE_V4(type) && v4_realm == NULL) 758 krb5_errx(context, 1, "Its a Kerberos 4 database " 759 "but no realm configured"); 760 761 switch(type) { 762 case HPROP_KASERVER: 763 if (database == NULL) 764 database = DEFAULT_DATABASE; 765 ka_use_null_salt = krb5_config_get_bool_default(context, NULL, FALSE, 766 "hprop", 767 "afs_uses_null_salt", 768 NULL); 769 770 break; 771 case HPROP_KRB4_DUMP: 772 if (database == NULL) 773 krb5_errx(context, 1, "no dump file specified"); 774 775 break; 776 case HPROP_MIT_DUMP: 777 if (database == NULL) 778 krb5_errx(context, 1, "no dump file specified"); 779 break; 780 case HPROP_HEIMDAL: 781 ret = hdb_create (context, &db, database); 782 if(ret) 783 krb5_err(context, 1, ret, "hdb_create: %s", database); 784 ret = db->hdb_open(context, db, O_RDONLY, 0); 785 if(ret) 786 krb5_err(context, 1, ret, "db->hdb_open"); 787 break; 788 default: 789 krb5_errx(context, 1, "unknown dump type `%d'", type); 790 break; 791 } 792 793 if (to_stdout) 794 exit_code = dump_database (context, type, database, db); 795 else 796 exit_code = propagate_database (context, type, database, 797 db, ccache, optidx, argc, argv); 798 799 if(ccache != NULL) 800 krb5_cc_destroy(context, ccache); 801 802 if(db != NULL) 803 (*db->hdb_destroy)(context, db); 804 805 krb5_free_context(context); 806 return exit_code; 807} 808