155682Smarkm/* 2233294Sstas * Copyright (c) 1997 - 2005 Kungliga Tekniska H��gskolan 3233294Sstas * (Royal Institute of Technology, Stockholm, Sweden). 4233294Sstas * All rights reserved. 555682Smarkm * 6233294Sstas * Redistribution and use in source and binary forms, with or without 7233294Sstas * modification, are permitted provided that the following conditions 8233294Sstas * are met: 955682Smarkm * 10233294Sstas * 1. Redistributions of source code must retain the above copyright 11233294Sstas * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 13233294Sstas * 2. Redistributions in binary form must reproduce the above copyright 14233294Sstas * notice, this list of conditions and the following disclaimer in the 15233294Sstas * documentation and/or other materials provided with the distribution. 1655682Smarkm * 17233294Sstas * 3. Neither the name of the Institute nor the names of its contributors 18233294Sstas * may be used to endorse or promote products derived from this software 19233294Sstas * without specific prior written permission. 2055682Smarkm * 21233294Sstas * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 22233294Sstas * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23233294Sstas * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24233294Sstas * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 25233294Sstas * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26233294Sstas * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27233294Sstas * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28233294Sstas * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29233294Sstas * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30233294Sstas * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31233294Sstas * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 34233294Sstas#define KRB5_DEPRECATED /* uses v4 functions that will die */ 35233294Sstas 3655682Smarkm#include "hprop.h" 3755682Smarkm 3855682Smarkmstatic int version_flag; 3955682Smarkmstatic int help_flag; 40102644Snectarstatic const char *ktname = HPROP_KEYTAB; 41102644Snectarstatic const char *database; 4255682Smarkmstatic char *mkeyfile; 4355682Smarkmstatic int to_stdout; 4455682Smarkmstatic int verbose_flag; 4555682Smarkmstatic int encrypt_flag; 4655682Smarkmstatic int decrypt_flag; 4772445Sassarstatic hdb_master_key mkey5; 4855682Smarkm 4972445Sassarstatic char *source_type; 5072445Sassar 5172445Sassarstatic char *local_realm=NULL; 5272445Sassar 5355682Smarkmstatic int 5472445Sassaropen_socket(krb5_context context, const char *hostname, const char *port) 5555682Smarkm{ 5655682Smarkm struct addrinfo *ai, *a; 5755682Smarkm struct addrinfo hints; 5855682Smarkm int error; 5955682Smarkm 6055682Smarkm memset (&hints, 0, sizeof(hints)); 6155682Smarkm hints.ai_socktype = SOCK_STREAM; 6255682Smarkm hints.ai_protocol = IPPROTO_TCP; 6355682Smarkm 6472445Sassar error = getaddrinfo (hostname, port, &hints, &ai); 6555682Smarkm if (error) { 6655682Smarkm warnx ("%s: %s", hostname, gai_strerror(error)); 6755682Smarkm return -1; 6855682Smarkm } 69233294Sstas 7055682Smarkm for (a = ai; a != NULL; a = a->ai_next) { 7155682Smarkm int s; 7255682Smarkm 7355682Smarkm s = socket (a->ai_family, a->ai_socktype, a->ai_protocol); 7455682Smarkm if (s < 0) 7555682Smarkm continue; 7655682Smarkm if (connect (s, a->ai_addr, a->ai_addrlen) < 0) { 7755682Smarkm warn ("connect(%s)", hostname); 7855682Smarkm close (s); 7955682Smarkm continue; 8055682Smarkm } 8155682Smarkm freeaddrinfo (ai); 8255682Smarkm return s; 8355682Smarkm } 8455682Smarkm warnx ("failed to contact %s", hostname); 8555682Smarkm freeaddrinfo (ai); 8655682Smarkm return -1; 8755682Smarkm} 8855682Smarkm 8972445Sassarkrb5_error_code 90178825Sdfrv5_prop(krb5_context context, HDB *db, hdb_entry_ex *entry, void *appdata) 9155682Smarkm{ 9255682Smarkm krb5_error_code ret; 9355682Smarkm struct prop_data *pd = appdata; 9455682Smarkm krb5_data data; 9555682Smarkm 9672445Sassar if(encrypt_flag) { 97178825Sdfr ret = hdb_seal_keys_mkey(context, &entry->entry, mkey5); 9872445Sassar if (ret) { 9972445Sassar krb5_warn(context, ret, "hdb_seal_keys_mkey"); 10072445Sassar return ret; 10172445Sassar } 10272445Sassar } 10372445Sassar if(decrypt_flag) { 104178825Sdfr ret = hdb_unseal_keys_mkey(context, &entry->entry, mkey5); 10572445Sassar if (ret) { 10672445Sassar krb5_warn(context, ret, "hdb_unseal_keys_mkey"); 10772445Sassar return ret; 10872445Sassar } 109233294Sstas } 11055682Smarkm 111178825Sdfr ret = hdb_entry2value(context, &entry->entry, &data); 11272445Sassar if(ret) { 11372445Sassar krb5_warn(context, ret, "hdb_entry2value"); 11472445Sassar return ret; 11572445Sassar } 11655682Smarkm 11755682Smarkm if(to_stdout) 11872445Sassar ret = krb5_write_message(context, &pd->sock, &data); 11955682Smarkm else 120233294Sstas ret = krb5_write_priv_message(context, pd->auth_context, 12172445Sassar &pd->sock, &data); 12255682Smarkm krb5_data_free(&data); 12355682Smarkm return ret; 12455682Smarkm} 12555682Smarkm 12655682Smarkmstruct getargs args[] = { 12755682Smarkm { "master-key", 'm', arg_string, &mkeyfile, "v5 master key file", "file" }, 128233294Sstas { "database", 'd', arg_string, rk_UNCONST(&database), "database", "file" }, 129233294Sstas { "source", 0, arg_string, &source_type, "type of database to read", 13072445Sassar "heimdal" 13172445Sassar "|mit-dump" 13272445Sassar }, 133233294Sstas 134233294Sstas { "keytab", 'k', arg_string, rk_UNCONST(&ktname), 135233294Sstas "keytab to use for authentication", "keytab" }, 136233294Sstas { "v5-realm", 'R', arg_string, &local_realm, "v5 realm to use", NULL }, 137233294Sstas { "decrypt", 'D', arg_flag, &decrypt_flag, "decrypt keys", NULL }, 138233294Sstas { "encrypt", 'E', arg_flag, &encrypt_flag, "encrypt keys", NULL }, 139233294Sstas { "stdout", 'n', arg_flag, &to_stdout, "dump to stdout", NULL }, 140233294Sstas { "verbose", 'v', arg_flag, &verbose_flag, NULL, NULL }, 141233294Sstas { "version", 0, arg_flag, &version_flag, NULL, NULL }, 142233294Sstas { "help", 'h', arg_flag, &help_flag, NULL, NULL } 14355682Smarkm}; 14455682Smarkm 14555682Smarkmstatic int num_args = sizeof(args) / sizeof(args[0]); 14655682Smarkm 14755682Smarkmstatic void 14855682Smarkmusage(int ret) 14955682Smarkm{ 15090926Snectar arg_printusage (args, num_args, NULL, "[host[:port]] ..."); 15155682Smarkm exit (ret); 15255682Smarkm} 15355682Smarkm 15455682Smarkmstatic void 15555682Smarkmget_creds(krb5_context context, krb5_ccache *cache) 15655682Smarkm{ 15755682Smarkm krb5_keytab keytab; 15855682Smarkm krb5_principal client; 15955682Smarkm krb5_error_code ret; 160178825Sdfr krb5_get_init_creds_opt *init_opts; 16155682Smarkm krb5_preauthtype preauth = KRB5_PADATA_ENC_TIMESTAMP; 16255682Smarkm krb5_creds creds; 163233294Sstas 16472445Sassar ret = krb5_kt_register(context, &hdb_kt_ops); 16572445Sassar if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); 16672445Sassar 16755682Smarkm ret = krb5_kt_resolve(context, ktname, &keytab); 16855682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_kt_resolve"); 169233294Sstas 170233294Sstas ret = krb5_make_principal(context, &client, NULL, 17155682Smarkm "kadmin", HPROP_NAME, NULL); 17255682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_make_principal"); 17355682Smarkm 174178825Sdfr ret = krb5_get_init_creds_opt_alloc(context, &init_opts); 175178825Sdfr if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); 176178825Sdfr krb5_get_init_creds_opt_set_preauth_list(init_opts, &preauth, 1); 17755682Smarkm 178178825Sdfr ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 0, NULL, init_opts); 17955682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 180178825Sdfr 181178825Sdfr krb5_get_init_creds_opt_free(context, init_opts); 182233294Sstas 18355682Smarkm ret = krb5_kt_close(context, keytab); 18455682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 18555682Smarkm 186233294Sstas ret = krb5_cc_new_unique(context, krb5_cc_type_memory, NULL, cache); 187233294Sstas if(ret) krb5_err(context, 1, ret, "krb5_cc_new_unique"); 188233294Sstas 18955682Smarkm ret = krb5_cc_initialize(context, *cache, client); 19055682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 19155682Smarkm 19290926Snectar krb5_free_principal(context, client); 19390926Snectar 19455682Smarkm ret = krb5_cc_store_cred(context, *cache, &creds); 19555682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 19690926Snectar 197178825Sdfr krb5_free_cred_contents(context, &creds); 19855682Smarkm} 19955682Smarkm 20072445Sassarenum hprop_source { 20172445Sassar HPROP_HEIMDAL = 1, 20272445Sassar HPROP_MIT_DUMP 20372445Sassar}; 20472445Sassar 20572445Sassarstruct { 20672445Sassar int type; 20772445Sassar const char *name; 20872445Sassar} types[] = { 20972445Sassar { HPROP_HEIMDAL, "heimdal" }, 21072445Sassar { HPROP_MIT_DUMP, "mit-dump" } 21172445Sassar}; 21272445Sassar 21372445Sassarstatic int 21472445Sassarparse_source_type(const char *s) 21572445Sassar{ 216233294Sstas size_t i; 21772445Sassar for(i = 0; i < sizeof(types) / sizeof(types[0]); i++) { 21872445Sassar if(strstr(types[i].name, s) == types[i].name) 21972445Sassar return types[i].type; 22072445Sassar } 22172445Sassar return 0; 22272445Sassar} 22372445Sassar 224178825Sdfrstatic int 22555682Smarkmiterate (krb5_context context, 226178825Sdfr const char *database_name, 22755682Smarkm HDB *db, 22872445Sassar int type, 22955682Smarkm struct prop_data *pd) 23055682Smarkm{ 23172445Sassar int ret; 23272445Sassar 23372445Sassar switch(type) { 23472445Sassar case HPROP_MIT_DUMP: 235178825Sdfr ret = mit_prop_dump(pd, database_name); 23672445Sassar if (ret) 237233294Sstas krb5_warn(context, ret, "mit_prop_dump"); 23872445Sassar break; 23972445Sassar case HPROP_HEIMDAL: 24072445Sassar ret = hdb_foreach(context, db, HDB_F_DECRYPT, v5_prop, pd); 24155682Smarkm if(ret) 242178825Sdfr krb5_warn(context, ret, "hdb_foreach"); 24372445Sassar break; 244178825Sdfr default: 245178825Sdfr krb5_errx(context, 1, "unknown prop type: %d", type); 24655682Smarkm } 247178825Sdfr return ret; 24855682Smarkm} 24955682Smarkm 25055682Smarkmstatic int 25172445Sassardump_database (krb5_context context, int type, 252178825Sdfr const char *database_name, HDB *db) 25355682Smarkm{ 25472445Sassar krb5_error_code ret; 25555682Smarkm struct prop_data pd; 25672445Sassar krb5_data data; 25755682Smarkm 25855682Smarkm pd.context = context; 25955682Smarkm pd.auth_context = NULL; 26055682Smarkm pd.sock = STDOUT_FILENO; 261233294Sstas 262178825Sdfr ret = iterate (context, database_name, db, type, &pd); 263178825Sdfr if (ret) 264178825Sdfr krb5_errx(context, 1, "iterate failure"); 26572445Sassar krb5_data_zero (&data); 26672445Sassar ret = krb5_write_message (context, &pd.sock, &data); 26772445Sassar if (ret) 26872445Sassar krb5_err(context, 1, ret, "krb5_write_message"); 26972445Sassar 27055682Smarkm return 0; 27155682Smarkm} 27255682Smarkm 27355682Smarkmstatic int 27472445Sassarpropagate_database (krb5_context context, int type, 275233294Sstas const char *database_name, 27655682Smarkm HDB *db, krb5_ccache ccache, 277178825Sdfr int optidx, int argc, char **argv) 27855682Smarkm{ 27955682Smarkm krb5_principal server; 28055682Smarkm krb5_error_code ret; 281178825Sdfr int i, failed = 0; 28255682Smarkm 283178825Sdfr for(i = optidx; i < argc; i++){ 28455682Smarkm krb5_auth_context auth_context; 28555682Smarkm int fd; 28655682Smarkm struct prop_data pd; 28755682Smarkm krb5_data data; 28855682Smarkm 28972445Sassar char *port, portstr[NI_MAXSERV]; 290178825Sdfr char *host = argv[i]; 291178825Sdfr 292178825Sdfr port = strchr(host, ':'); 29372445Sassar if(port == NULL) { 294233294Sstas snprintf(portstr, sizeof(portstr), "%u", 295233294Sstas ntohs(krb5_getportbyname (context, "hprop", "tcp", 29672445Sassar HPROP_PORT))); 29772445Sassar port = portstr; 29872445Sassar } else 29972445Sassar *port++ = '\0'; 30072445Sassar 301178825Sdfr fd = open_socket(context, host, port); 30255682Smarkm if(fd < 0) { 303178825Sdfr failed++; 304178825Sdfr krb5_warn (context, errno, "connect %s", host); 30555682Smarkm continue; 30655682Smarkm } 30755682Smarkm 30855682Smarkm ret = krb5_sname_to_principal(context, argv[i], 30955682Smarkm HPROP_NAME, KRB5_NT_SRV_HST, &server); 31055682Smarkm if(ret) { 311178825Sdfr failed++; 312178825Sdfr krb5_warn(context, ret, "krb5_sname_to_principal(%s)", host); 31355682Smarkm close(fd); 31455682Smarkm continue; 31555682Smarkm } 31672445Sassar 31772445Sassar if (local_realm) { 31872445Sassar krb5_realm my_realm; 31972445Sassar krb5_get_default_realm(context,&my_realm); 320233294Sstas krb5_principal_set_realm(context,server,my_realm); 321233294Sstas krb5_xfree(my_realm); 322233294Sstas } 32372445Sassar 32455682Smarkm auth_context = NULL; 32555682Smarkm ret = krb5_sendauth(context, 32655682Smarkm &auth_context, 32755682Smarkm &fd, 32855682Smarkm HPROP_VERSION, 32955682Smarkm NULL, 33055682Smarkm server, 331103423Snectar AP_OPTS_MUTUAL_REQUIRED | AP_OPTS_USE_SUBKEY, 33255682Smarkm NULL, /* in_data */ 33355682Smarkm NULL, /* in_creds */ 33455682Smarkm ccache, 33555682Smarkm NULL, 33655682Smarkm NULL, 33755682Smarkm NULL); 33855682Smarkm 33990926Snectar krb5_free_principal(context, server); 34090926Snectar 34155682Smarkm if(ret) { 342178825Sdfr failed++; 343178825Sdfr krb5_warn(context, ret, "krb5_sendauth (%s)", host); 34455682Smarkm close(fd); 345178825Sdfr goto next_host; 34655682Smarkm } 347233294Sstas 34855682Smarkm pd.context = context; 34955682Smarkm pd.auth_context = auth_context; 35055682Smarkm pd.sock = fd; 35155682Smarkm 352178825Sdfr ret = iterate (context, database_name, db, type, &pd); 353178825Sdfr if (ret) { 354178825Sdfr krb5_warnx(context, "iterate to host %s failed", host); 355178825Sdfr failed++; 356178825Sdfr goto next_host; 357178825Sdfr } 35855682Smarkm 35972445Sassar krb5_data_zero (&data); 36072445Sassar ret = krb5_write_priv_message(context, auth_context, &fd, &data); 361178825Sdfr if(ret) { 36272445Sassar krb5_warn(context, ret, "krb5_write_priv_message"); 363178825Sdfr failed++; 364178825Sdfr goto next_host; 365178825Sdfr } 36655682Smarkm 36772445Sassar ret = krb5_read_priv_message(context, auth_context, &fd, &data); 368178825Sdfr if(ret) { 369178825Sdfr krb5_warn(context, ret, "krb5_read_priv_message: %s", host); 370178825Sdfr failed++; 371178825Sdfr goto next_host; 372178825Sdfr } else 37355682Smarkm krb5_data_free (&data); 374233294Sstas 375178825Sdfr next_host: 37655682Smarkm krb5_auth_con_free(context, auth_context); 37755682Smarkm close(fd); 37855682Smarkm } 379178825Sdfr if (failed) 380178825Sdfr return 1; 38155682Smarkm return 0; 38255682Smarkm} 38355682Smarkm 38455682Smarkmint 38555682Smarkmmain(int argc, char **argv) 38655682Smarkm{ 38755682Smarkm krb5_error_code ret; 38855682Smarkm krb5_context context; 38990926Snectar krb5_ccache ccache = NULL; 39090926Snectar HDB *db = NULL; 391178825Sdfr int optidx = 0; 39255682Smarkm 393178825Sdfr int type, exit_code; 39472445Sassar 39578527Sassar setprogname(argv[0]); 39655682Smarkm 397178825Sdfr if(getarg(args, num_args, argc, argv, &optidx)) 39855682Smarkm usage(1); 39955682Smarkm 40055682Smarkm if(help_flag) 40155682Smarkm usage(0); 402233294Sstas 40355682Smarkm if(version_flag){ 40455682Smarkm print_version(NULL); 40555682Smarkm exit(0); 40655682Smarkm } 40755682Smarkm 40855682Smarkm ret = krb5_init_context(&context); 40955682Smarkm if(ret) 41055682Smarkm exit(1); 41155682Smarkm 412233294Sstas /* We may be reading an old database encrypted with a DES master key. */ 413233294Sstas ret = krb5_allow_weak_crypto(context, 1); 414233294Sstas if(ret) 415233294Sstas krb5_err(context, 1, ret, "krb5_allow_weak_crypto"); 416233294Sstas 41772445Sassar if(local_realm) 41872445Sassar krb5_set_default_realm(context, local_realm); 41972445Sassar 42055682Smarkm if(encrypt_flag && decrypt_flag) 421233294Sstas krb5_errx(context, 1, 42272445Sassar "only one of `--encrypt' and `--decrypt' is meaningful"); 42355682Smarkm 42472445Sassar if(source_type != NULL) { 42572445Sassar type = parse_source_type(source_type); 42672445Sassar if(type == 0) 42772445Sassar krb5_errx(context, 1, "unknown source type `%s'", source_type); 428178825Sdfr } else 42972445Sassar type = HPROP_HEIMDAL; 43072445Sassar 43155682Smarkm if(!to_stdout) 43255682Smarkm get_creds(context, &ccache); 433233294Sstas 43472445Sassar if(decrypt_flag || encrypt_flag) { 43572445Sassar ret = hdb_read_master_key(context, mkeyfile, &mkey5); 43672445Sassar if(ret && ret != ENOENT) 43772445Sassar krb5_err(context, 1, ret, "hdb_read_master_key"); 43872445Sassar if(ret) 43955682Smarkm krb5_errx(context, 1, "No master key file found"); 44055682Smarkm } 44155682Smarkm 44272445Sassar switch(type) { 44372445Sassar case HPROP_MIT_DUMP: 44472445Sassar if (database == NULL) 44572445Sassar krb5_errx(context, 1, "no dump file specified"); 44672445Sassar break; 44772445Sassar case HPROP_HEIMDAL: 44872445Sassar ret = hdb_create (context, &db, database); 44972445Sassar if(ret) 45072445Sassar krb5_err(context, 1, ret, "hdb_create: %s", database); 451178825Sdfr ret = db->hdb_open(context, db, O_RDONLY, 0); 45272445Sassar if(ret) 453178825Sdfr krb5_err(context, 1, ret, "db->hdb_open"); 45472445Sassar break; 45572445Sassar default: 45672445Sassar krb5_errx(context, 1, "unknown dump type `%d'", type); 45772445Sassar break; 45872445Sassar } 45955682Smarkm 46055682Smarkm if (to_stdout) 461178825Sdfr exit_code = dump_database (context, type, database, db); 46255682Smarkm else 463233294Sstas exit_code = propagate_database (context, type, database, 464178825Sdfr db, ccache, optidx, argc, argv); 46590926Snectar 46690926Snectar if(ccache != NULL) 46790926Snectar krb5_cc_destroy(context, ccache); 468233294Sstas 46990926Snectar if(db != NULL) 470178825Sdfr (*db->hdb_destroy)(context, db); 47190926Snectar 47290926Snectar krb5_free_context(context); 473178825Sdfr return exit_code; 47455682Smarkm} 475