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, &timestamp);
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, &timestamp);
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