ipropd_slave.c revision 72445
155682Smarkm/* 272445Sassar * Copyright (c) 1997 - 2000 Kungliga Tekniska H�gskolan 355682Smarkm * (Royal Institute of Technology, Stockholm, Sweden). 455682Smarkm * All rights reserved. 555682Smarkm * 655682Smarkm * Redistribution and use in source and binary forms, with or without 755682Smarkm * modification, are permitted provided that the following conditions 855682Smarkm * are met: 955682Smarkm * 1055682Smarkm * 1. Redistributions of source code must retain the above copyright 1155682Smarkm * notice, this list of conditions and the following disclaimer. 1255682Smarkm * 1355682Smarkm * 2. Redistributions in binary form must reproduce the above copyright 1455682Smarkm * notice, this list of conditions and the following disclaimer in the 1555682Smarkm * documentation and/or other materials provided with the distribution. 1655682Smarkm * 1755682Smarkm * 3. Neither the name of the Institute nor the names of its contributors 1855682Smarkm * may be used to endorse or promote products derived from this software 1955682Smarkm * without specific prior written permission. 2055682Smarkm * 2155682Smarkm * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND 2255682Smarkm * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2355682Smarkm * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2455682Smarkm * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE 2555682Smarkm * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2655682Smarkm * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2755682Smarkm * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2855682Smarkm * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2955682Smarkm * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3055682Smarkm * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3155682Smarkm * SUCH DAMAGE. 3255682Smarkm */ 3355682Smarkm 3455682Smarkm#include "iprop.h" 3555682Smarkm 3672445SassarRCSID("$Id: ipropd_slave.c,v 1.21 2000/08/06 02:06:19 assar Exp $"); 3755682Smarkm 3872445Sassarstatic krb5_log_facility *log_facility; 3972445Sassar 4055682Smarkmstatic int 4155682Smarkmconnect_to_master (krb5_context context, const char *master) 4255682Smarkm{ 4355682Smarkm int fd; 4455682Smarkm struct sockaddr_in addr; 4555682Smarkm struct hostent *he; 4655682Smarkm 4755682Smarkm fd = socket (AF_INET, SOCK_STREAM, 0); 4855682Smarkm if (fd < 0) 4955682Smarkm krb5_err (context, 1, errno, "socket AF_INET"); 5055682Smarkm memset (&addr, 0, sizeof(addr)); 5155682Smarkm addr.sin_family = AF_INET; 5272445Sassar addr.sin_port = krb5_getportbyname (context, 5372445Sassar IPROP_SERVICE, "tcp", IPROP_PORT); 5455682Smarkm he = roken_gethostbyname (master); 5555682Smarkm if (he == NULL) 5655682Smarkm krb5_errx (context, 1, "gethostbyname: %s", hstrerror(h_errno)); 5755682Smarkm memcpy (&addr.sin_addr, he->h_addr, sizeof(addr.sin_addr)); 5855682Smarkm if(connect(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) 5955682Smarkm krb5_err (context, 1, errno, "connect"); 6055682Smarkm return fd; 6155682Smarkm} 6255682Smarkm 6355682Smarkmstatic void 6472445Sassarget_creds(krb5_context context, const char *keytab_str, 6572445Sassar krb5_ccache *cache, const char *host) 6655682Smarkm{ 6755682Smarkm krb5_keytab keytab; 6855682Smarkm krb5_principal client; 6955682Smarkm krb5_error_code ret; 7055682Smarkm krb5_get_init_creds_opt init_opts; 7155682Smarkm krb5_creds creds; 7255682Smarkm char *server; 7372445Sassar char keytab_buf[256]; 7455682Smarkm 7572445Sassar ret = krb5_kt_register(context, &hdb_kt_ops); 7672445Sassar if(ret) 7772445Sassar krb5_err(context, 1, ret, "krb5_kt_register"); 7855682Smarkm 7972445Sassar if (keytab_str == NULL) { 8072445Sassar ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); 8172445Sassar if (ret) 8272445Sassar krb5_err (context, 1, ret, "krb5_kt_default_name"); 8372445Sassar keytab_str = keytab_buf; 8472445Sassar } 8572445Sassar 8672445Sassar ret = krb5_kt_resolve(context, keytab_str, &keytab); 8772445Sassar if(ret) 8872445Sassar krb5_err(context, 1, ret, "%s", keytab_str); 8972445Sassar 9072445Sassar ret = krb5_sname_to_principal (context, NULL, IPROP_NAME, 9155682Smarkm KRB5_NT_SRV_HST, &client); 9255682Smarkm if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); 9355682Smarkm 9455682Smarkm krb5_get_init_creds_opt_init(&init_opts); 9555682Smarkm 9655682Smarkm asprintf (&server, "%s/%s", IPROP_NAME, host); 9755682Smarkm if (server == NULL) 9855682Smarkm krb5_errx (context, 1, "malloc: no memory"); 9955682Smarkm 10055682Smarkm ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 10155682Smarkm 0, server, &init_opts); 10255682Smarkm free (server); 10355682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 10455682Smarkm 10555682Smarkm ret = krb5_kt_close(context, keytab); 10655682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 10755682Smarkm 10855682Smarkm ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); 10955682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); 11055682Smarkm 11155682Smarkm ret = krb5_cc_initialize(context, *cache, client); 11255682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 11355682Smarkm 11455682Smarkm ret = krb5_cc_store_cred(context, *cache, &creds); 11555682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 11655682Smarkm} 11755682Smarkm 11855682Smarkmstatic void 11955682Smarkmihave (krb5_context context, krb5_auth_context auth_context, 12055682Smarkm int fd, u_int32_t version) 12155682Smarkm{ 12255682Smarkm int ret; 12355682Smarkm u_char buf[8]; 12455682Smarkm krb5_storage *sp; 12555682Smarkm krb5_data data, priv_data; 12655682Smarkm 12755682Smarkm sp = krb5_storage_from_mem (buf, 8); 12855682Smarkm krb5_store_int32 (sp, I_HAVE); 12955682Smarkm krb5_store_int32 (sp, version); 13055682Smarkm krb5_storage_free (sp); 13155682Smarkm data.length = 8; 13255682Smarkm data.data = buf; 13355682Smarkm 13455682Smarkm ret = krb5_mk_priv (context, auth_context, &data, &priv_data, NULL); 13555682Smarkm if (ret) 13655682Smarkm krb5_err (context, 1, ret, "krb_mk_priv"); 13755682Smarkm 13855682Smarkm ret = krb5_write_message (context, &fd, &priv_data); 13955682Smarkm if (ret) 14055682Smarkm krb5_err (context, 1, ret, "krb5_write_message"); 14155682Smarkm 14255682Smarkm krb5_data_free (&priv_data); 14355682Smarkm} 14455682Smarkm 14555682Smarkmstatic void 14672445Sassarreceive_loop (krb5_context context, 14772445Sassar krb5_storage *sp, 14872445Sassar kadm5_server_context *server_context) 14955682Smarkm{ 15055682Smarkm int ret; 15155682Smarkm off_t left, right; 15255682Smarkm void *buf; 15355682Smarkm int32_t vers; 15455682Smarkm 15555682Smarkm do { 15655682Smarkm int32_t len, timestamp, tmp; 15755682Smarkm enum kadm_ops op; 15855682Smarkm 15955682Smarkm if(krb5_ret_int32 (sp, &vers) != 0) 16055682Smarkm return; 16155682Smarkm krb5_ret_int32 (sp, ×tamp); 16255682Smarkm krb5_ret_int32 (sp, &tmp); 16355682Smarkm op = tmp; 16455682Smarkm krb5_ret_int32 (sp, &len); 16555682Smarkm if (vers <= server_context->log_context.version) 16655682Smarkm sp->seek(sp, len, SEEK_CUR); 16755682Smarkm } while(vers <= server_context->log_context.version); 16855682Smarkm 16955682Smarkm left = sp->seek (sp, -16, SEEK_CUR); 17055682Smarkm right = sp->seek (sp, 0, SEEK_END); 17155682Smarkm buf = malloc (right - left); 17272445Sassar if (buf == NULL && (right - left) != 0) { 17355682Smarkm krb5_warnx (context, "malloc: no memory"); 17455682Smarkm return; 17555682Smarkm } 17655682Smarkm sp->seek (sp, left, SEEK_SET); 17755682Smarkm sp->fetch (sp, buf, right - left); 17855682Smarkm write (server_context->log_context.log_fd, buf, right-left); 17955682Smarkm fsync (server_context->log_context.log_fd); 18055682Smarkm free (buf); 18155682Smarkm 18255682Smarkm sp->seek (sp, left, SEEK_SET); 18355682Smarkm 18455682Smarkm for(;;) { 18555682Smarkm int32_t len, timestamp, tmp; 18655682Smarkm enum kadm_ops op; 18755682Smarkm 18855682Smarkm if(krb5_ret_int32 (sp, &vers) != 0) 18955682Smarkm break; 19055682Smarkm krb5_ret_int32 (sp, ×tamp); 19155682Smarkm krb5_ret_int32 (sp, &tmp); 19255682Smarkm op = tmp; 19355682Smarkm krb5_ret_int32 (sp, &len); 19455682Smarkm 19555682Smarkm ret = kadm5_log_replay (server_context, 19655682Smarkm op, vers, len, sp); 19755682Smarkm if (ret) 19855682Smarkm krb5_warn (context, ret, "kadm5_log_replay"); 19955682Smarkm else 20055682Smarkm server_context->log_context.version = vers; 20155682Smarkm sp->seek (sp, 8, SEEK_CUR); 20255682Smarkm } 20372445Sassar} 20455682Smarkm 20572445Sassarstatic void 20672445Sassarreceive (krb5_context context, 20772445Sassar krb5_storage *sp, 20872445Sassar kadm5_server_context *server_context) 20972445Sassar{ 21072445Sassar int ret; 21172445Sassar 21272445Sassar ret = server_context->db->open(context, 21372445Sassar server_context->db, 21472445Sassar O_RDWR | O_CREAT, 0600); 21572445Sassar if (ret) 21672445Sassar krb5_err (context, 1, ret, "db->open"); 21772445Sassar 21872445Sassar receive_loop (context, sp, server_context); 21972445Sassar 22055682Smarkm ret = server_context->db->close (context, server_context->db); 22155682Smarkm if (ret) 22255682Smarkm krb5_err (context, 1, ret, "db->close"); 22355682Smarkm} 22455682Smarkm 22572445Sassarstatic void 22672445Sassarreceive_everything (krb5_context context, int fd, 22772445Sassar kadm5_server_context *server_context, 22872445Sassar krb5_auth_context auth_context) 22972445Sassar{ 23072445Sassar int ret; 23172445Sassar krb5_data data; 23272445Sassar int32_t vno; 23372445Sassar int32_t opcode; 23472445Sassar 23572445Sassar ret = server_context->db->open(context, 23672445Sassar server_context->db, 23772445Sassar O_RDWR | O_CREAT | O_TRUNC, 0600); 23872445Sassar if (ret) 23972445Sassar krb5_err (context, 1, ret, "db->open"); 24072445Sassar 24172445Sassar do { 24272445Sassar krb5_storage *sp; 24372445Sassar 24472445Sassar ret = krb5_read_priv_message(context, auth_context, &fd, &data); 24572445Sassar 24672445Sassar if (ret) 24772445Sassar krb5_err (context, 1, ret, "krb5_read_priv_message"); 24872445Sassar 24972445Sassar sp = krb5_storage_from_data (&data); 25072445Sassar krb5_ret_int32 (sp, &opcode); 25172445Sassar if (opcode == ONE_PRINC) { 25272445Sassar krb5_data fake_data; 25372445Sassar hdb_entry entry; 25472445Sassar 25572445Sassar fake_data.data = (char *)data.data + 4; 25672445Sassar fake_data.length = data.length - 4; 25772445Sassar 25872445Sassar ret = hdb_value2entry (context, &fake_data, &entry); 25972445Sassar if (ret) 26072445Sassar krb5_err (context, 1, ret, "hdb_value2entry"); 26172445Sassar ret = server_context->db->store(server_context->context, 26272445Sassar server_context->db, 26372445Sassar 0, &entry); 26472445Sassar if (ret) 26572445Sassar krb5_err (context, 1, ret, "hdb_store"); 26672445Sassar 26772445Sassar hdb_free_entry (context, &entry); 26872445Sassar krb5_data_free (&data); 26972445Sassar } 27072445Sassar } while (opcode == ONE_PRINC); 27172445Sassar 27272445Sassar if (opcode != NOW_YOU_HAVE) 27372445Sassar krb5_errx (context, 1, "receive_everything: strange %d", opcode); 27472445Sassar 27572445Sassar _krb5_get_int ((char *)data.data + 4, &vno, 4); 27672445Sassar 27772445Sassar ret = kadm5_log_reinit (server_context); 27872445Sassar if (ret) 27972445Sassar krb5_err(context, 1, ret, "kadm5_log_reinit"); 28072445Sassar 28172445Sassar ret = kadm5_log_set_version (server_context, vno - 1); 28272445Sassar if (ret) 28372445Sassar krb5_err (context, 1, ret, "kadm5_log_set_version"); 28472445Sassar 28572445Sassar ret = kadm5_log_nop (server_context); 28672445Sassar if (ret) 28772445Sassar krb5_err (context, 1, ret, "kadm5_log_nop"); 28872445Sassar 28972445Sassar krb5_data_free (&data); 29072445Sassar 29172445Sassar ret = server_context->db->close (context, server_context->db); 29272445Sassar if (ret) 29372445Sassar krb5_err (context, 1, ret, "db->close"); 29472445Sassar} 29572445Sassar 29672445Sassarstatic char *realm; 29772445Sassarstatic int version_flag; 29872445Sassarstatic int help_flag; 29972445Sassarstatic char *keytab_str; 30072445Sassar 30172445Sassarstatic struct getargs args[] = { 30255682Smarkm { "realm", 'r', arg_string, &realm }, 30372445Sassar { "keytab", 'k', arg_string, &keytab_str, 30472445Sassar "keytab to get authentication from", "kspec" }, 30555682Smarkm { "version", 0, arg_flag, &version_flag }, 30655682Smarkm { "help", 0, arg_flag, &help_flag } 30755682Smarkm}; 30855682Smarkm 30972445Sassarstatic int num_args = sizeof(args) / sizeof(args[0]); 31072445Sassar 31172445Sassarstatic void 31272445Sassarusage (int code, struct getargs *args, int num_args) 31372445Sassar{ 31472445Sassar arg_printusage (args, num_args, NULL, "master"); 31572445Sassar exit (code); 31672445Sassar} 31772445Sassar 31855682Smarkmint 31955682Smarkmmain(int argc, char **argv) 32055682Smarkm{ 32155682Smarkm krb5_error_code ret; 32255682Smarkm krb5_context context; 32355682Smarkm krb5_auth_context auth_context; 32455682Smarkm void *kadm_handle; 32555682Smarkm kadm5_server_context *server_context; 32655682Smarkm kadm5_config_params conf; 32755682Smarkm int master_fd; 32855682Smarkm krb5_ccache ccache; 32955682Smarkm krb5_principal server; 33055682Smarkm 33155682Smarkm int optind; 33272445Sassar const char *master; 33355682Smarkm 33472445Sassar optind = krb5_program_setup(&context, argc, argv, args, num_args, usage); 33555682Smarkm 33655682Smarkm if(help_flag) 33772445Sassar usage (0, args, num_args); 33855682Smarkm if(version_flag) { 33955682Smarkm print_version(NULL); 34055682Smarkm exit(0); 34155682Smarkm } 34255682Smarkm 34372445Sassar argc -= optind; 34472445Sassar argv += optind; 34572445Sassar 34672445Sassar if (argc != 1) 34772445Sassar usage (1, args, num_args); 34872445Sassar 34972445Sassar master = argv[0]; 35072445Sassar 35172445Sassar krb5_openlog (context, "ipropd-master", &log_facility); 35272445Sassar krb5_set_warn_dest(context, log_facility); 35372445Sassar 35472445Sassar ret = krb5_kt_register(context, &hdb_kt_ops); 35572445Sassar if(ret) 35672445Sassar krb5_err(context, 1, ret, "krb5_kt_register"); 35772445Sassar 35855682Smarkm memset(&conf, 0, sizeof(conf)); 35955682Smarkm if(realm) { 36055682Smarkm conf.mask |= KADM5_CONFIG_REALM; 36155682Smarkm conf.realm = realm; 36255682Smarkm } 36355682Smarkm ret = kadm5_init_with_password_ctx (context, 36455682Smarkm KADM5_ADMIN_SERVICE, 36555682Smarkm NULL, 36655682Smarkm KADM5_ADMIN_SERVICE, 36755682Smarkm &conf, 0, 0, 36855682Smarkm &kadm_handle); 36955682Smarkm if (ret) 37055682Smarkm krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 37155682Smarkm 37255682Smarkm server_context = (kadm5_server_context *)kadm_handle; 37355682Smarkm 37455682Smarkm ret = kadm5_log_init (server_context); 37555682Smarkm if (ret) 37655682Smarkm krb5_err (context, 1, ret, "kadm5_log_init"); 37755682Smarkm 37872445Sassar get_creds(context, keytab_str, &ccache, master); 37955682Smarkm 38072445Sassar master_fd = connect_to_master (context, master); 38155682Smarkm 38272445Sassar ret = krb5_sname_to_principal (context, master, IPROP_NAME, 38355682Smarkm KRB5_NT_SRV_HST, &server); 38455682Smarkm if (ret) 38555682Smarkm krb5_err (context, 1, ret, "krb5_sname_to_principal"); 38655682Smarkm 38755682Smarkm auth_context = NULL; 38855682Smarkm ret = krb5_sendauth (context, &auth_context, &master_fd, 38955682Smarkm IPROP_VERSION, NULL, server, 39055682Smarkm AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, 39155682Smarkm ccache, NULL, NULL, NULL); 39255682Smarkm if (ret) 39355682Smarkm krb5_err (context, 1, ret, "krb5_sendauth"); 39455682Smarkm 39555682Smarkm ihave (context, auth_context, master_fd, 39655682Smarkm server_context->log_context.version); 39755682Smarkm 39855682Smarkm for (;;) { 39955682Smarkm int ret; 40072445Sassar krb5_data out; 40155682Smarkm krb5_storage *sp; 40255682Smarkm int32_t tmp; 40355682Smarkm 40472445Sassar ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); 40555682Smarkm 40655682Smarkm if (ret) 40772445Sassar krb5_err (context, 1, ret, "krb5_read_priv_message"); 40855682Smarkm 40955682Smarkm sp = krb5_storage_from_mem (out.data, out.length); 41055682Smarkm krb5_ret_int32 (sp, &tmp); 41155682Smarkm switch (tmp) { 41255682Smarkm case FOR_YOU : 41355682Smarkm receive (context, sp, server_context); 41455682Smarkm ihave (context, auth_context, master_fd, 41555682Smarkm server_context->log_context.version); 41655682Smarkm break; 41772445Sassar case TELL_YOU_EVERYTHING : 41872445Sassar receive_everything (context, master_fd, server_context, 41972445Sassar auth_context); 42072445Sassar break; 42172445Sassar case NOW_YOU_HAVE : 42255682Smarkm case I_HAVE : 42372445Sassar case ONE_PRINC : 42455682Smarkm default : 42555682Smarkm krb5_warnx (context, "Ignoring command %d", tmp); 42655682Smarkm break; 42755682Smarkm } 42855682Smarkm krb5_storage_free (sp); 42955682Smarkm krb5_data_free (&out); 43055682Smarkm } 43172445Sassar 43255682Smarkm return 0; 43372445Sassar } 434