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