ipropd_slave.c revision 90926
155682Smarkm/* 290926Snectar * Copyright (c) 1997 - 2001 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 3690926SnectarRCSID("$Id: ipropd_slave.c,v 1.24 2001/08/31 03:12:17 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 if (keytab_str == NULL) { 7672445Sassar ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf)); 7772445Sassar if (ret) 7872445Sassar krb5_err (context, 1, ret, "krb5_kt_default_name"); 7972445Sassar keytab_str = keytab_buf; 8072445Sassar } 8172445Sassar 8272445Sassar ret = krb5_kt_resolve(context, keytab_str, &keytab); 8372445Sassar if(ret) 8472445Sassar krb5_err(context, 1, ret, "%s", keytab_str); 8572445Sassar 8672445Sassar ret = krb5_sname_to_principal (context, NULL, IPROP_NAME, 8755682Smarkm KRB5_NT_SRV_HST, &client); 8855682Smarkm if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); 8955682Smarkm 9055682Smarkm krb5_get_init_creds_opt_init(&init_opts); 9155682Smarkm 9255682Smarkm asprintf (&server, "%s/%s", IPROP_NAME, host); 9355682Smarkm if (server == NULL) 9455682Smarkm krb5_errx (context, 1, "malloc: no memory"); 9555682Smarkm 9655682Smarkm ret = krb5_get_init_creds_keytab(context, &creds, client, keytab, 9755682Smarkm 0, server, &init_opts); 9855682Smarkm free (server); 9955682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_get_init_creds"); 10055682Smarkm 10155682Smarkm ret = krb5_kt_close(context, keytab); 10255682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_kt_close"); 10355682Smarkm 10455682Smarkm ret = krb5_cc_gen_new(context, &krb5_mcc_ops, cache); 10555682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_gen_new"); 10655682Smarkm 10755682Smarkm ret = krb5_cc_initialize(context, *cache, client); 10855682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_initialize"); 10955682Smarkm 11055682Smarkm ret = krb5_cc_store_cred(context, *cache, &creds); 11155682Smarkm if(ret) krb5_err(context, 1, ret, "krb5_cc_store_cred"); 11255682Smarkm} 11355682Smarkm 11455682Smarkmstatic void 11555682Smarkmihave (krb5_context context, krb5_auth_context auth_context, 11655682Smarkm int fd, u_int32_t version) 11755682Smarkm{ 11855682Smarkm int ret; 11955682Smarkm u_char buf[8]; 12055682Smarkm krb5_storage *sp; 12155682Smarkm krb5_data data, priv_data; 12255682Smarkm 12355682Smarkm sp = krb5_storage_from_mem (buf, 8); 12455682Smarkm krb5_store_int32 (sp, I_HAVE); 12555682Smarkm krb5_store_int32 (sp, version); 12655682Smarkm krb5_storage_free (sp); 12755682Smarkm data.length = 8; 12855682Smarkm data.data = buf; 12955682Smarkm 13055682Smarkm ret = krb5_mk_priv (context, auth_context, &data, &priv_data, NULL); 13155682Smarkm if (ret) 13255682Smarkm krb5_err (context, 1, ret, "krb_mk_priv"); 13355682Smarkm 13455682Smarkm ret = krb5_write_message (context, &fd, &priv_data); 13555682Smarkm if (ret) 13655682Smarkm krb5_err (context, 1, ret, "krb5_write_message"); 13755682Smarkm 13855682Smarkm krb5_data_free (&priv_data); 13955682Smarkm} 14055682Smarkm 14155682Smarkmstatic void 14272445Sassarreceive_loop (krb5_context context, 14372445Sassar krb5_storage *sp, 14472445Sassar kadm5_server_context *server_context) 14555682Smarkm{ 14655682Smarkm int ret; 14755682Smarkm off_t left, right; 14855682Smarkm void *buf; 14955682Smarkm int32_t vers; 15055682Smarkm 15155682Smarkm do { 15255682Smarkm int32_t len, timestamp, tmp; 15355682Smarkm enum kadm_ops op; 15455682Smarkm 15555682Smarkm if(krb5_ret_int32 (sp, &vers) != 0) 15655682Smarkm return; 15755682Smarkm krb5_ret_int32 (sp, ×tamp); 15855682Smarkm krb5_ret_int32 (sp, &tmp); 15955682Smarkm op = tmp; 16055682Smarkm krb5_ret_int32 (sp, &len); 16155682Smarkm if (vers <= server_context->log_context.version) 16255682Smarkm sp->seek(sp, len, SEEK_CUR); 16355682Smarkm } while(vers <= server_context->log_context.version); 16455682Smarkm 16555682Smarkm left = sp->seek (sp, -16, SEEK_CUR); 16655682Smarkm right = sp->seek (sp, 0, SEEK_END); 16755682Smarkm buf = malloc (right - left); 16872445Sassar if (buf == NULL && (right - left) != 0) { 16955682Smarkm krb5_warnx (context, "malloc: no memory"); 17055682Smarkm return; 17155682Smarkm } 17255682Smarkm sp->seek (sp, left, SEEK_SET); 17355682Smarkm sp->fetch (sp, buf, right - left); 17455682Smarkm write (server_context->log_context.log_fd, buf, right-left); 17555682Smarkm fsync (server_context->log_context.log_fd); 17655682Smarkm free (buf); 17755682Smarkm 17855682Smarkm sp->seek (sp, left, SEEK_SET); 17955682Smarkm 18055682Smarkm for(;;) { 18155682Smarkm int32_t len, timestamp, tmp; 18255682Smarkm enum kadm_ops op; 18355682Smarkm 18455682Smarkm if(krb5_ret_int32 (sp, &vers) != 0) 18555682Smarkm break; 18655682Smarkm krb5_ret_int32 (sp, ×tamp); 18755682Smarkm krb5_ret_int32 (sp, &tmp); 18855682Smarkm op = tmp; 18955682Smarkm krb5_ret_int32 (sp, &len); 19055682Smarkm 19155682Smarkm ret = kadm5_log_replay (server_context, 19255682Smarkm op, vers, len, sp); 19355682Smarkm if (ret) 19455682Smarkm krb5_warn (context, ret, "kadm5_log_replay"); 19555682Smarkm else 19655682Smarkm server_context->log_context.version = vers; 19755682Smarkm sp->seek (sp, 8, SEEK_CUR); 19855682Smarkm } 19972445Sassar} 20055682Smarkm 20172445Sassarstatic void 20272445Sassarreceive (krb5_context context, 20372445Sassar krb5_storage *sp, 20472445Sassar kadm5_server_context *server_context) 20572445Sassar{ 20672445Sassar int ret; 20772445Sassar 20872445Sassar ret = server_context->db->open(context, 20972445Sassar server_context->db, 21072445Sassar O_RDWR | O_CREAT, 0600); 21172445Sassar if (ret) 21272445Sassar krb5_err (context, 1, ret, "db->open"); 21372445Sassar 21472445Sassar receive_loop (context, sp, server_context); 21572445Sassar 21655682Smarkm ret = server_context->db->close (context, server_context->db); 21755682Smarkm if (ret) 21855682Smarkm krb5_err (context, 1, ret, "db->close"); 21955682Smarkm} 22055682Smarkm 22172445Sassarstatic void 22272445Sassarreceive_everything (krb5_context context, int fd, 22372445Sassar kadm5_server_context *server_context, 22472445Sassar krb5_auth_context auth_context) 22572445Sassar{ 22672445Sassar int ret; 22772445Sassar krb5_data data; 22872445Sassar int32_t vno; 22972445Sassar int32_t opcode; 23072445Sassar 23172445Sassar ret = server_context->db->open(context, 23272445Sassar server_context->db, 23372445Sassar O_RDWR | O_CREAT | O_TRUNC, 0600); 23472445Sassar if (ret) 23572445Sassar krb5_err (context, 1, ret, "db->open"); 23672445Sassar 23772445Sassar do { 23872445Sassar krb5_storage *sp; 23972445Sassar 24072445Sassar ret = krb5_read_priv_message(context, auth_context, &fd, &data); 24172445Sassar 24272445Sassar if (ret) 24372445Sassar krb5_err (context, 1, ret, "krb5_read_priv_message"); 24472445Sassar 24572445Sassar sp = krb5_storage_from_data (&data); 24672445Sassar krb5_ret_int32 (sp, &opcode); 24772445Sassar if (opcode == ONE_PRINC) { 24872445Sassar krb5_data fake_data; 24972445Sassar hdb_entry entry; 25072445Sassar 25172445Sassar fake_data.data = (char *)data.data + 4; 25272445Sassar fake_data.length = data.length - 4; 25372445Sassar 25472445Sassar ret = hdb_value2entry (context, &fake_data, &entry); 25572445Sassar if (ret) 25672445Sassar krb5_err (context, 1, ret, "hdb_value2entry"); 25772445Sassar ret = server_context->db->store(server_context->context, 25872445Sassar server_context->db, 25972445Sassar 0, &entry); 26072445Sassar if (ret) 26172445Sassar krb5_err (context, 1, ret, "hdb_store"); 26272445Sassar 26372445Sassar hdb_free_entry (context, &entry); 26472445Sassar krb5_data_free (&data); 26572445Sassar } 26672445Sassar } while (opcode == ONE_PRINC); 26772445Sassar 26872445Sassar if (opcode != NOW_YOU_HAVE) 26972445Sassar krb5_errx (context, 1, "receive_everything: strange %d", opcode); 27072445Sassar 27172445Sassar _krb5_get_int ((char *)data.data + 4, &vno, 4); 27272445Sassar 27372445Sassar ret = kadm5_log_reinit (server_context); 27472445Sassar if (ret) 27572445Sassar krb5_err(context, 1, ret, "kadm5_log_reinit"); 27672445Sassar 27772445Sassar ret = kadm5_log_set_version (server_context, vno - 1); 27872445Sassar if (ret) 27972445Sassar krb5_err (context, 1, ret, "kadm5_log_set_version"); 28072445Sassar 28172445Sassar ret = kadm5_log_nop (server_context); 28272445Sassar if (ret) 28372445Sassar krb5_err (context, 1, ret, "kadm5_log_nop"); 28472445Sassar 28572445Sassar krb5_data_free (&data); 28672445Sassar 28772445Sassar ret = server_context->db->close (context, server_context->db); 28872445Sassar if (ret) 28972445Sassar krb5_err (context, 1, ret, "db->close"); 29072445Sassar} 29172445Sassar 29272445Sassarstatic char *realm; 29372445Sassarstatic int version_flag; 29472445Sassarstatic int help_flag; 29572445Sassarstatic char *keytab_str; 29672445Sassar 29772445Sassarstatic struct getargs args[] = { 29855682Smarkm { "realm", 'r', arg_string, &realm }, 29972445Sassar { "keytab", 'k', arg_string, &keytab_str, 30072445Sassar "keytab to get authentication from", "kspec" }, 30155682Smarkm { "version", 0, arg_flag, &version_flag }, 30255682Smarkm { "help", 0, arg_flag, &help_flag } 30355682Smarkm}; 30455682Smarkm 30572445Sassarstatic int num_args = sizeof(args) / sizeof(args[0]); 30672445Sassar 30772445Sassarstatic void 30872445Sassarusage (int code, struct getargs *args, int num_args) 30972445Sassar{ 31072445Sassar arg_printusage (args, num_args, NULL, "master"); 31172445Sassar exit (code); 31272445Sassar} 31372445Sassar 31455682Smarkmint 31555682Smarkmmain(int argc, char **argv) 31655682Smarkm{ 31755682Smarkm krb5_error_code ret; 31855682Smarkm krb5_context context; 31955682Smarkm krb5_auth_context auth_context; 32055682Smarkm void *kadm_handle; 32155682Smarkm kadm5_server_context *server_context; 32255682Smarkm kadm5_config_params conf; 32355682Smarkm int master_fd; 32455682Smarkm krb5_ccache ccache; 32555682Smarkm krb5_principal server; 32655682Smarkm 32755682Smarkm int optind; 32872445Sassar const char *master; 32955682Smarkm 33072445Sassar optind = krb5_program_setup(&context, argc, argv, args, num_args, usage); 33155682Smarkm 33255682Smarkm if(help_flag) 33372445Sassar usage (0, args, num_args); 33455682Smarkm if(version_flag) { 33555682Smarkm print_version(NULL); 33655682Smarkm exit(0); 33755682Smarkm } 33855682Smarkm 33972445Sassar argc -= optind; 34072445Sassar argv += optind; 34172445Sassar 34272445Sassar if (argc != 1) 34372445Sassar usage (1, args, num_args); 34472445Sassar 34572445Sassar master = argv[0]; 34672445Sassar 34790926Snectar pidfile (NULL); 34890926Snectar krb5_openlog (context, "ipropd-slave", &log_facility); 34972445Sassar krb5_set_warn_dest(context, log_facility); 35072445Sassar 35172445Sassar ret = krb5_kt_register(context, &hdb_kt_ops); 35272445Sassar if(ret) 35372445Sassar krb5_err(context, 1, ret, "krb5_kt_register"); 35472445Sassar 35555682Smarkm memset(&conf, 0, sizeof(conf)); 35655682Smarkm if(realm) { 35755682Smarkm conf.mask |= KADM5_CONFIG_REALM; 35855682Smarkm conf.realm = realm; 35955682Smarkm } 36055682Smarkm ret = kadm5_init_with_password_ctx (context, 36155682Smarkm KADM5_ADMIN_SERVICE, 36255682Smarkm NULL, 36355682Smarkm KADM5_ADMIN_SERVICE, 36455682Smarkm &conf, 0, 0, 36555682Smarkm &kadm_handle); 36655682Smarkm if (ret) 36755682Smarkm krb5_err (context, 1, ret, "kadm5_init_with_password_ctx"); 36855682Smarkm 36955682Smarkm server_context = (kadm5_server_context *)kadm_handle; 37055682Smarkm 37155682Smarkm ret = kadm5_log_init (server_context); 37255682Smarkm if (ret) 37355682Smarkm krb5_err (context, 1, ret, "kadm5_log_init"); 37455682Smarkm 37572445Sassar get_creds(context, keytab_str, &ccache, master); 37655682Smarkm 37772445Sassar master_fd = connect_to_master (context, master); 37855682Smarkm 37972445Sassar ret = krb5_sname_to_principal (context, master, IPROP_NAME, 38055682Smarkm KRB5_NT_SRV_HST, &server); 38155682Smarkm if (ret) 38255682Smarkm krb5_err (context, 1, ret, "krb5_sname_to_principal"); 38355682Smarkm 38455682Smarkm auth_context = NULL; 38555682Smarkm ret = krb5_sendauth (context, &auth_context, &master_fd, 38655682Smarkm IPROP_VERSION, NULL, server, 38755682Smarkm AP_OPTS_MUTUAL_REQUIRED, NULL, NULL, 38855682Smarkm ccache, NULL, NULL, NULL); 38955682Smarkm if (ret) 39055682Smarkm krb5_err (context, 1, ret, "krb5_sendauth"); 39155682Smarkm 39255682Smarkm ihave (context, auth_context, master_fd, 39355682Smarkm server_context->log_context.version); 39455682Smarkm 39555682Smarkm for (;;) { 39655682Smarkm int ret; 39772445Sassar krb5_data out; 39855682Smarkm krb5_storage *sp; 39955682Smarkm int32_t tmp; 40055682Smarkm 40172445Sassar ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); 40255682Smarkm 40355682Smarkm if (ret) 40472445Sassar krb5_err (context, 1, ret, "krb5_read_priv_message"); 40555682Smarkm 40655682Smarkm sp = krb5_storage_from_mem (out.data, out.length); 40755682Smarkm krb5_ret_int32 (sp, &tmp); 40855682Smarkm switch (tmp) { 40955682Smarkm case FOR_YOU : 41055682Smarkm receive (context, sp, server_context); 41155682Smarkm ihave (context, auth_context, master_fd, 41255682Smarkm server_context->log_context.version); 41355682Smarkm break; 41472445Sassar case TELL_YOU_EVERYTHING : 41572445Sassar receive_everything (context, master_fd, server_context, 41672445Sassar auth_context); 41772445Sassar break; 41872445Sassar case NOW_YOU_HAVE : 41955682Smarkm case I_HAVE : 42072445Sassar case ONE_PRINC : 42155682Smarkm default : 42255682Smarkm krb5_warnx (context, "Ignoring command %d", tmp); 42355682Smarkm break; 42455682Smarkm } 42555682Smarkm krb5_storage_free (sp); 42655682Smarkm krb5_data_free (&out); 42755682Smarkm } 42872445Sassar 42955682Smarkm return 0; 43090926Snectar} 431