ipropd_master.c revision 120945
155682Smarkm/*
2102644Snectar * Copyright (c) 1997 - 2002 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"
35102644Snectar#include <rtbl.h>
3655682Smarkm
37120945SnectarRCSID("$Id: ipropd_master.c,v 1.29 2003/03/19 11:56:38 lha Exp $");
3855682Smarkm
3972445Sassarstatic krb5_log_facility *log_facility;
4072445Sassar
41120945Snectarconst char *slave_stats_file = KADM5_SLAVE_STATS;
42120945Snectar
4355682Smarkmstatic int
4455682Smarkmmake_signal_socket (krb5_context context)
4555682Smarkm{
4655682Smarkm    struct sockaddr_un addr;
4755682Smarkm    int fd;
4855682Smarkm
4955682Smarkm    fd = socket (AF_UNIX, SOCK_DGRAM, 0);
5055682Smarkm    if (fd < 0)
5155682Smarkm	krb5_err (context, 1, errno, "socket AF_UNIX");
5255682Smarkm    memset (&addr, 0, sizeof(addr));
5355682Smarkm    addr.sun_family = AF_UNIX;
5472445Sassar    strlcpy (addr.sun_path, KADM5_LOG_SIGNAL, sizeof(addr.sun_path));
5555682Smarkm    unlink (addr.sun_path);
5655682Smarkm    if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
5755682Smarkm	krb5_err (context, 1, errno, "bind %s", addr.sun_path);
5855682Smarkm    return fd;
5955682Smarkm}
6055682Smarkm
6155682Smarkmstatic int
6255682Smarkmmake_listen_socket (krb5_context context)
6355682Smarkm{
6455682Smarkm    int fd;
6555682Smarkm    int one = 1;
6655682Smarkm    struct sockaddr_in addr;
6755682Smarkm
6855682Smarkm    fd = socket (AF_INET, SOCK_STREAM, 0);
6955682Smarkm    if (fd < 0)
7055682Smarkm	krb5_err (context, 1, errno, "socket AF_INET");
7190926Snectar    setsockopt (fd, SOL_SOCKET, SO_REUSEADDR, (void *)&one, sizeof(one));
7255682Smarkm    memset (&addr, 0, sizeof(addr));
7355682Smarkm    addr.sin_family = AF_INET;
7472445Sassar    addr.sin_port   = krb5_getportbyname (context,
7572445Sassar					  IPROP_SERVICE, "tcp", IPROP_PORT);
7655682Smarkm    if(bind(fd, (struct sockaddr *)&addr, sizeof(addr)) < 0)
7755682Smarkm	krb5_err (context, 1, errno, "bind");
7855682Smarkm    if (listen(fd, SOMAXCONN) < 0)
7955682Smarkm	krb5_err (context, 1, errno, "listen");
8055682Smarkm    return fd;
8155682Smarkm}
8255682Smarkm
8355682Smarkmstruct slave {
8455682Smarkm    int fd;
8555682Smarkm    struct sockaddr_in addr;
8655682Smarkm    char *name;
8755682Smarkm    krb5_auth_context ac;
8855682Smarkm    u_int32_t version;
89102644Snectar    time_t seen;
90102644Snectar    unsigned long flags;
91102644Snectar#define SLAVE_F_DEAD	0x1
9255682Smarkm    struct slave *next;
9355682Smarkm};
9455682Smarkm
9555682Smarkmtypedef struct slave slave;
9655682Smarkm
9755682Smarkmstatic int
9855682Smarkmcheck_acl (krb5_context context, const char *name)
9955682Smarkm{
10055682Smarkm    FILE *fp;
10155682Smarkm    char buf[256];
10255682Smarkm    int ret = 1;
10355682Smarkm
10455682Smarkm    fp = fopen (KADM5_SLAVE_ACL, "r");
10555682Smarkm    if (fp == NULL)
10655682Smarkm	return 1;
10755682Smarkm    while (fgets(buf, sizeof(buf), fp) != NULL) {
10855682Smarkm	if (buf[strlen(buf) - 1 ] == '\n')
10955682Smarkm	    buf[strlen(buf) - 1 ] = '\0';
11055682Smarkm	if (strcmp (buf, name) == 0) {
11155682Smarkm	    ret = 0;
11255682Smarkm	    break;
11355682Smarkm	}
11455682Smarkm    }
11555682Smarkm    fclose (fp);
11655682Smarkm    return ret;
11755682Smarkm}
11855682Smarkm
11955682Smarkmstatic void
120102644Snectarslave_seen(slave *s)
121102644Snectar{
122102644Snectar    s->seen = time(NULL);
123102644Snectar}
124102644Snectar
125102644Snectarstatic void
126102644Snectarslave_dead(slave *s)
127102644Snectar{
128120945Snectar    if (s->fd >= 0) {
129120945Snectar	close (s->fd);
130120945Snectar	s->fd = -1;
131120945Snectar    }
132102644Snectar    s->flags |= SLAVE_F_DEAD;
133102644Snectar    slave_seen(s);
134102644Snectar}
135102644Snectar
136102644Snectarstatic void
137102644Snectarremove_slave (krb5_context context, slave *s, slave **root)
138102644Snectar{
139102644Snectar    slave **p;
140102644Snectar
141102644Snectar    if (s->fd >= 0)
142102644Snectar	close (s->fd);
143102644Snectar    if (s->name)
144102644Snectar	free (s->name);
145102644Snectar    if (s->ac)
146102644Snectar	krb5_auth_con_free (context, s->ac);
147102644Snectar
148102644Snectar    for (p = root; *p; p = &(*p)->next)
149102644Snectar	if (*p == s) {
150102644Snectar	    *p = s->next;
151102644Snectar	    break;
152102644Snectar	}
153102644Snectar    free (s);
154102644Snectar}
155102644Snectar
156102644Snectarstatic void
15772445Sassaradd_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd)
15855682Smarkm{
15955682Smarkm    krb5_principal server;
16055682Smarkm    krb5_error_code ret;
16155682Smarkm    slave *s;
16272445Sassar    socklen_t addr_len;
16355682Smarkm    krb5_ticket *ticket = NULL;
16455682Smarkm    char hostname[128];
16555682Smarkm
16655682Smarkm    s = malloc(sizeof(*s));
16755682Smarkm    if (s == NULL) {
16855682Smarkm	krb5_warnx (context, "add_slave: no memory");
16955682Smarkm	return;
17055682Smarkm    }
17155682Smarkm    s->name = NULL;
17255682Smarkm    s->ac = NULL;
17355682Smarkm
17455682Smarkm    addr_len = sizeof(s->addr);
17555682Smarkm    s->fd = accept (fd, (struct sockaddr *)&s->addr, &addr_len);
17655682Smarkm    if (s->fd < 0) {
17755682Smarkm	krb5_warn (context, errno, "accept");
17855682Smarkm	goto error;
17955682Smarkm    }
18055682Smarkm    gethostname(hostname, sizeof(hostname));
18155682Smarkm    ret = krb5_sname_to_principal (context, hostname, IPROP_NAME,
18255682Smarkm				   KRB5_NT_SRV_HST, &server);
18355682Smarkm    if (ret) {
18455682Smarkm	krb5_warn (context, ret, "krb5_sname_to_principal");
18555682Smarkm	goto error;
18655682Smarkm    }
18755682Smarkm
18855682Smarkm    ret = krb5_recvauth (context, &s->ac, &s->fd,
18972445Sassar			 IPROP_VERSION, server, 0, keytab, &ticket);
19055682Smarkm    krb5_free_principal (context, server);
19155682Smarkm    if (ret) {
19255682Smarkm	krb5_warn (context, ret, "krb5_recvauth");
19355682Smarkm	goto error;
19455682Smarkm    }
19555682Smarkm    ret = krb5_unparse_name (context, ticket->client, &s->name);
19655682Smarkm    if (ret) {
19755682Smarkm	krb5_warn (context, ret, "krb5_unparse_name");
19855682Smarkm	goto error;
19955682Smarkm    }
20055682Smarkm    if (check_acl (context, s->name)) {
20155682Smarkm	krb5_warnx (context, "%s not in acl", s->name);
20255682Smarkm	goto error;
20355682Smarkm    }
20455682Smarkm    krb5_free_ticket (context, ticket);
205102644Snectar    ticket = NULL;
206102644Snectar
207102644Snectar    {
208102644Snectar	slave *l = *root;
209102644Snectar
210102644Snectar	while (l) {
211102644Snectar	    if (strcmp(l->name, s->name) == 0)
212102644Snectar		break;
213102644Snectar	    l = l->next;
214102644Snectar	}
215102644Snectar	if (l) {
216102644Snectar	    if (l->flags & SLAVE_F_DEAD) {
217102644Snectar		remove_slave(context, l, root);
218102644Snectar	    } else {
219102644Snectar		krb5_warnx (context, "second connection from %s", s->name);
220102644Snectar		goto error;
221102644Snectar	    }
222102644Snectar	}
223102644Snectar    }
224102644Snectar
22572445Sassar    krb5_warnx (context, "connection from %s", s->name);
22655682Smarkm
22755682Smarkm    s->version = 0;
228102644Snectar    s->flags = 0;
229102644Snectar    slave_seen(s);
23055682Smarkm    s->next = *root;
23155682Smarkm    *root = s;
23255682Smarkm    return;
23355682Smarkmerror:
234102644Snectar    remove_slave(context, s, root);
23555682Smarkm}
23655682Smarkm
23772445Sassarstruct prop_context {
23872445Sassar    krb5_auth_context auth_context;
23972445Sassar    int fd;
24072445Sassar};
24172445Sassar
24255682Smarkmstatic int
24372445Sassarprop_one (krb5_context context, HDB *db, hdb_entry *entry, void *v)
24455682Smarkm{
24572445Sassar    krb5_error_code ret;
24672445Sassar    krb5_data data;
24772445Sassar    struct slave *slave = (struct slave *)v;
24872445Sassar
24972445Sassar    ret = hdb_entry2value (context, entry, &data);
25072445Sassar    if (ret)
25172445Sassar	return ret;
25272445Sassar    ret = krb5_data_realloc (&data, data.length + 4);
25372445Sassar    if (ret) {
25472445Sassar	krb5_data_free (&data);
25572445Sassar	return ret;
25672445Sassar    }
25772445Sassar    memmove ((char *)data.data + 4, data.data, data.length - 4);
25872445Sassar    _krb5_put_int (data.data, ONE_PRINC, 4);
25972445Sassar
26072445Sassar    ret = krb5_write_priv_message (context, slave->ac, &slave->fd, &data);
26172445Sassar    krb5_data_free (&data);
26272445Sassar    return ret;
26355682Smarkm}
26455682Smarkm
26555682Smarkmstatic int
26672445Sassarsend_complete (krb5_context context, slave *s,
26772445Sassar	       const char *database, u_int32_t current_version)
26872445Sassar{
26972445Sassar    krb5_error_code ret;
27072445Sassar    HDB *db;
27172445Sassar    krb5_data data;
27272445Sassar    char buf[8];
27372445Sassar
27472445Sassar    ret = hdb_create (context, &db, database);
27572445Sassar    if (ret)
27672445Sassar	krb5_err (context, 1, ret, "hdb_create: %s", database);
27772445Sassar    ret = db->open (context, db, O_RDONLY, 0);
27872445Sassar    if (ret)
27972445Sassar	krb5_err (context, 1, ret, "db->open");
28072445Sassar
28172445Sassar    _krb5_put_int(buf, TELL_YOU_EVERYTHING, 4);
28272445Sassar
28372445Sassar    data.data   = buf;
28472445Sassar    data.length = 4;
28572445Sassar
28672445Sassar    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
28772445Sassar
288102644Snectar    if (ret) {
289102644Snectar	krb5_warn (context, ret, "krb5_write_priv_message");
290102644Snectar	slave_dead(s);
291102644Snectar	return ret;
292102644Snectar    }
29372445Sassar
29472445Sassar    ret = hdb_foreach (context, db, 0, prop_one, s);
295102644Snectar    if (ret) {
296102644Snectar	krb5_warn (context, ret, "hdb_foreach");
297102644Snectar	slave_dead(s);
298102644Snectar	return ret;
299102644Snectar    }
30072445Sassar
30172445Sassar    _krb5_put_int (buf, NOW_YOU_HAVE, 4);
30272445Sassar    _krb5_put_int (buf + 4, current_version, 4);
30372445Sassar    data.length = 8;
30472445Sassar
305102644Snectar    s->version = current_version;
306102644Snectar
30772445Sassar    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
308102644Snectar    if (ret) {
309102644Snectar	slave_dead(s);
310102644Snectar	krb5_warn (context, ret, "krb5_write_priv_message");
311102644Snectar	return ret;
312102644Snectar    }
31372445Sassar
314102644Snectar    slave_seen(s);
31572445Sassar
31672445Sassar    return 0;
31772445Sassar}
31872445Sassar
31972445Sassarstatic int
32055682Smarkmsend_diffs (krb5_context context, slave *s, int log_fd,
32172445Sassar	    const char *database, u_int32_t current_version)
32255682Smarkm{
32372445Sassar    krb5_storage *sp;
32455682Smarkm    u_int32_t ver;
32555682Smarkm    time_t timestamp;
32655682Smarkm    enum kadm_ops op;
32755682Smarkm    u_int32_t len;
32855682Smarkm    off_t right, left;
32955682Smarkm    krb5_data data;
33055682Smarkm    int ret = 0;
33155682Smarkm
33255682Smarkm    if (s->version == current_version)
33355682Smarkm	return 0;
33455682Smarkm
335102644Snectar    if (s->flags & SLAVE_F_DEAD)
336102644Snectar	return 0;
337102644Snectar
33855682Smarkm    sp = kadm5_log_goto_end (log_fd);
339102644Snectar    right = krb5_storage_seek(sp, 0, SEEK_CUR);
34055682Smarkm    for (;;) {
34155682Smarkm	if (kadm5_log_previous (sp, &ver, &timestamp, &op, &len))
34255682Smarkm	    abort ();
343102644Snectar	left = krb5_storage_seek(sp, -16, SEEK_CUR);
34455682Smarkm	if (ver == s->version)
34555682Smarkm	    return 0;
34655682Smarkm	if (ver == s->version + 1)
34755682Smarkm	    break;
34855682Smarkm	if (left == 0)
34972445Sassar	    return send_complete (context, s, database, current_version);
35055682Smarkm    }
35155682Smarkm    krb5_data_alloc (&data, right - left + 4);
352102644Snectar    krb5_storage_read (sp, (char *)data.data + 4, data.length - 4);
35355682Smarkm    krb5_storage_free(sp);
35455682Smarkm
35555682Smarkm    _krb5_put_int(data.data, FOR_YOU, 4);
35655682Smarkm
35772445Sassar    ret = krb5_write_priv_message(context, s->ac, &s->fd, &data);
358102644Snectar    krb5_data_free(&data);
35955682Smarkm
36055682Smarkm    if (ret) {
36172445Sassar	krb5_warn (context, ret, "krb5_write_priv_message");
362102644Snectar	slave_dead(s);
36355682Smarkm	return 1;
36455682Smarkm    }
365102644Snectar    slave_seen(s);
366102644Snectar
36755682Smarkm    return 0;
36855682Smarkm}
36955682Smarkm
37055682Smarkmstatic int
37155682Smarkmprocess_msg (krb5_context context, slave *s, int log_fd,
37272445Sassar	     const char *database, u_int32_t current_version)
37355682Smarkm{
37455682Smarkm    int ret = 0;
37572445Sassar    krb5_data out;
37655682Smarkm    krb5_storage *sp;
37755682Smarkm    int32_t tmp;
37855682Smarkm
37972445Sassar    ret = krb5_read_priv_message(context, s->ac, &s->fd, &out);
38072445Sassar    if(ret) {
38172445Sassar	krb5_warn (context, ret, "error reading message from %s", s->name);
38255682Smarkm	return 1;
38355682Smarkm    }
38455682Smarkm
38555682Smarkm    sp = krb5_storage_from_mem (out.data, out.length);
38655682Smarkm    krb5_ret_int32 (sp, &tmp);
38755682Smarkm    switch (tmp) {
38855682Smarkm    case I_HAVE :
38955682Smarkm	krb5_ret_int32 (sp, &tmp);
39055682Smarkm	s->version = tmp;
39172445Sassar	ret = send_diffs (context, s, log_fd, database, current_version);
39255682Smarkm	break;
39355682Smarkm    case FOR_YOU :
39455682Smarkm    default :
39555682Smarkm	krb5_warnx (context, "Ignoring command %d", tmp);
39655682Smarkm	break;
39755682Smarkm    }
39855682Smarkm
39955682Smarkm    krb5_data_free (&out);
400102644Snectar
401102644Snectar    slave_seen(s);
402102644Snectar
40355682Smarkm    return ret;
40455682Smarkm}
40555682Smarkm
406102644Snectar#define SLAVE_NAME	"Name"
407102644Snectar#define SLAVE_ADDRESS	"Address"
408102644Snectar#define SLAVE_VERSION	"Version"
409102644Snectar#define SLAVE_STATUS	"Status"
410102644Snectar#define SLAVE_SEEN	"Last Seen"
411102644Snectar
412102644Snectarstatic void
413102644Snectarwrite_stats(krb5_context context, slave *slaves, u_int32_t current_version)
414102644Snectar{
415120945Snectar    char str[100];
416102644Snectar    rtbl_t tbl;
417102644Snectar    time_t t = time(NULL);
418102644Snectar    FILE *fp;
419102644Snectar
420120945Snectar    fp = fopen(slave_stats_file, "w");
421102644Snectar    if (fp == NULL)
422102644Snectar	return;
423102644Snectar
424102644Snectar    strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S",
425102644Snectar	     localtime(&t));
426102644Snectar    fprintf(fp, "Status for slaves, last updated: %s\n\n", str);
427102644Snectar
428102644Snectar    fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version);
429102644Snectar
430102644Snectar    tbl = rtbl_create();
431102644Snectar    if (tbl == NULL) {
432102644Snectar	fclose(fp);
433102644Snectar	return;
434102644Snectar    }
435102644Snectar
436102644Snectar    rtbl_add_column(tbl, SLAVE_NAME, 0);
437102644Snectar    rtbl_add_column(tbl, SLAVE_ADDRESS, 0);
438102644Snectar    rtbl_add_column(tbl, SLAVE_VERSION, RTBL_ALIGN_RIGHT);
439102644Snectar    rtbl_add_column(tbl, SLAVE_STATUS, 0);
440102644Snectar    rtbl_add_column(tbl, SLAVE_SEEN, 0);
441102644Snectar
442102644Snectar    rtbl_set_prefix(tbl, "  ");
443102644Snectar    rtbl_set_column_prefix(tbl, SLAVE_NAME, "");
444102644Snectar
445102644Snectar    while (slaves) {
446102644Snectar	krb5_address addr;
447102644Snectar	krb5_error_code ret;
448102644Snectar	rtbl_add_column_entry(tbl, SLAVE_NAME, slaves->name);
449102644Snectar	ret = krb5_sockaddr2address (context,
450102644Snectar				     (struct sockaddr*)&slaves->addr, &addr);
451102644Snectar	if(ret == 0) {
452102644Snectar	    krb5_print_address(&addr, str, sizeof(str), NULL);
453102644Snectar	    krb5_free_address(context, &addr);
454102644Snectar	    rtbl_add_column_entry(tbl, SLAVE_ADDRESS, str);
455102644Snectar	} else
456102644Snectar	    rtbl_add_column_entry(tbl, SLAVE_ADDRESS, "<unknown>");
457102644Snectar
458102644Snectar	snprintf(str, sizeof(str), "%u", (unsigned)slaves->version);
459102644Snectar	rtbl_add_column_entry(tbl, SLAVE_VERSION, str);
460102644Snectar
461102644Snectar	if (slaves->flags & SLAVE_F_DEAD)
462102644Snectar	    rtbl_add_column_entry(tbl, SLAVE_STATUS, "Down");
463102644Snectar	else
464102644Snectar	    rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up");
465102644Snectar
466120945Snectar	if (strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z",
467120945Snectar		     localtime(&slaves->seen)) == 0)
468120945Snectar	    strlcpy(str, "Unknown time", sizeof(str));
469102644Snectar	rtbl_add_column_entry(tbl, SLAVE_SEEN, str);
470102644Snectar
471102644Snectar	slaves = slaves->next;
472102644Snectar    }
473102644Snectar
474102644Snectar    rtbl_format(tbl, fp);
475102644Snectar    rtbl_destroy(tbl);
476102644Snectar
477102644Snectar    fclose(fp);
478102644Snectar}
479102644Snectar
480102644Snectar
48172445Sassarstatic char *realm;
48272445Sassarstatic int version_flag;
48372445Sassarstatic int help_flag;
48472445Sassarstatic char *keytab_str = "HDB:";
48572445Sassarstatic char *database;
48672445Sassar
48772445Sassarstatic struct getargs args[] = {
48855682Smarkm    { "realm", 'r', arg_string, &realm },
48972445Sassar    { "keytab", 'k', arg_string, &keytab_str,
49072445Sassar      "keytab to get authentication from", "kspec" },
49172445Sassar    { "database", 'd', arg_string, &database, "database", "file"},
492120945Snectar    { "slave-stats-file", 0, arg_string, &slave_stats_file, "file"},
49355682Smarkm    { "version", 0, arg_flag, &version_flag },
49455682Smarkm    { "help", 0, arg_flag, &help_flag }
49555682Smarkm};
49672445Sassarstatic int num_args = sizeof(args) / sizeof(args[0]);
49755682Smarkm
49855682Smarkmint
49955682Smarkmmain(int argc, char **argv)
50055682Smarkm{
50155682Smarkm    krb5_error_code ret;
50255682Smarkm    krb5_context context;
50355682Smarkm    void *kadm_handle;
50455682Smarkm    kadm5_server_context *server_context;
50555682Smarkm    kadm5_config_params conf;
50655682Smarkm    int signal_fd, listen_fd;
50755682Smarkm    int log_fd;
50855682Smarkm    slave *slaves = NULL;
50955682Smarkm    u_int32_t current_version, old_version = 0;
51072445Sassar    krb5_keytab keytab;
51155682Smarkm    int optind;
51255682Smarkm
51355682Smarkm    optind = krb5_program_setup(&context, argc, argv, args, num_args, NULL);
51455682Smarkm
51555682Smarkm    if(help_flag)
51655682Smarkm	krb5_std_usage(0, args, num_args);
51755682Smarkm    if(version_flag) {
51855682Smarkm	print_version(NULL);
51955682Smarkm	exit(0);
52055682Smarkm    }
52155682Smarkm
52290926Snectar    pidfile (NULL);
52372445Sassar    krb5_openlog (context, "ipropd-master", &log_facility);
52472445Sassar    krb5_set_warn_dest(context, log_facility);
52572445Sassar
52672445Sassar    ret = krb5_kt_register(context, &hdb_kt_ops);
52772445Sassar    if(ret)
52872445Sassar	krb5_err(context, 1, ret, "krb5_kt_register");
52972445Sassar
53072445Sassar    ret = krb5_kt_resolve(context, keytab_str, &keytab);
53172445Sassar    if(ret)
53272445Sassar	krb5_err(context, 1, ret, "krb5_kt_resolve: %s", keytab_str);
53372445Sassar
53455682Smarkm    memset(&conf, 0, sizeof(conf));
53555682Smarkm    if(realm) {
53655682Smarkm	conf.mask |= KADM5_CONFIG_REALM;
53755682Smarkm	conf.realm = realm;
53855682Smarkm    }
53972445Sassar    ret = kadm5_init_with_skey_ctx (context,
54072445Sassar				    KADM5_ADMIN_SERVICE,
54172445Sassar				    NULL,
54272445Sassar				    KADM5_ADMIN_SERVICE,
54372445Sassar				    &conf, 0, 0,
54472445Sassar				    &kadm_handle);
54555682Smarkm    if (ret)
54655682Smarkm	krb5_err (context, 1, ret, "kadm5_init_with_password_ctx");
54755682Smarkm
54855682Smarkm    server_context = (kadm5_server_context *)kadm_handle;
54955682Smarkm
55055682Smarkm    log_fd = open (server_context->log_context.log_file, O_RDONLY, 0);
55155682Smarkm    if (log_fd < 0)
55255682Smarkm	krb5_err (context, 1, errno, "open %s",
55355682Smarkm		  server_context->log_context.log_file);
55455682Smarkm
55555682Smarkm    signal_fd = make_signal_socket (context);
55655682Smarkm    listen_fd = make_listen_socket (context);
55755682Smarkm
55872445Sassar    signal (SIGPIPE, SIG_IGN);
55972445Sassar
56055682Smarkm    for (;;) {
56155682Smarkm	slave *p;
56255682Smarkm	fd_set readset;
56355682Smarkm	int max_fd = 0;
56455682Smarkm	struct timeval to = {30, 0};
56555682Smarkm	u_int32_t vers;
56655682Smarkm
56772445Sassar	if (signal_fd >= FD_SETSIZE || listen_fd >= FD_SETSIZE)
56872445Sassar	    krb5_errx (context, 1, "fd too large");
56972445Sassar
57055682Smarkm	FD_ZERO(&readset);
57155682Smarkm	FD_SET(signal_fd, &readset);
57255682Smarkm	max_fd = max(max_fd, signal_fd);
57355682Smarkm	FD_SET(listen_fd, &readset);
57455682Smarkm	max_fd = max(max_fd, listen_fd);
57555682Smarkm
57655682Smarkm	for (p = slaves; p != NULL; p = p->next) {
577120945Snectar	    if (p->flags & SLAVE_F_DEAD)
578120945Snectar		continue;
57955682Smarkm	    FD_SET(p->fd, &readset);
58055682Smarkm	    max_fd = max(max_fd, p->fd);
58155682Smarkm	}
58255682Smarkm
58355682Smarkm	ret = select (max_fd + 1,
58455682Smarkm		      &readset, NULL, NULL, &to);
58555682Smarkm	if (ret < 0) {
58655682Smarkm	    if (errno == EINTR)
58755682Smarkm		continue;
58855682Smarkm	    else
58955682Smarkm		krb5_err (context, 1, errno, "select");
59055682Smarkm	}
59155682Smarkm
59255682Smarkm	if (ret == 0) {
59355682Smarkm	    old_version = current_version;
59472445Sassar	    kadm5_log_get_version_fd (log_fd, &current_version);
59555682Smarkm
59655682Smarkm	    if (current_version > old_version)
597120945Snectar		for (p = slaves; p != NULL; p = p->next) {
598120945Snectar		    if (p->flags & SLAVE_F_DEAD)
599120945Snectar			continue;
60072445Sassar		    send_diffs (context, p, log_fd, database, current_version);
601120945Snectar		}
60255682Smarkm	}
60355682Smarkm
60455682Smarkm	if (ret && FD_ISSET(signal_fd, &readset)) {
60555682Smarkm	    struct sockaddr_un peer_addr;
60672445Sassar	    socklen_t peer_len = sizeof(peer_addr);
60755682Smarkm
60890926Snectar	    if(recvfrom(signal_fd, (void *)&vers, sizeof(vers), 0,
60955682Smarkm			(struct sockaddr *)&peer_addr, &peer_len) < 0) {
61055682Smarkm		krb5_warn (context, errno, "recvfrom");
61155682Smarkm		continue;
61255682Smarkm	    }
61355682Smarkm	    --ret;
61455682Smarkm	    old_version = current_version;
61572445Sassar	    kadm5_log_get_version_fd (log_fd, &current_version);
61655682Smarkm	    for (p = slaves; p != NULL; p = p->next)
61772445Sassar		send_diffs (context, p, log_fd, database, current_version);
61855682Smarkm	}
61955682Smarkm
620120945Snectar	for(p = slaves; ret && p != NULL; p = p->next) {
621120945Snectar	    if (p->flags & SLAVE_F_DEAD)
622120945Snectar		continue;
62355682Smarkm	    if (FD_ISSET(p->fd, &readset)) {
62478527Sassar		--ret;
62572445Sassar		if(process_msg (context, p, log_fd, database, current_version))
626102644Snectar		    slave_dead(p);
62755682Smarkm	    }
628120945Snectar	}
62955682Smarkm
63055682Smarkm	if (ret && FD_ISSET(listen_fd, &readset)) {
63172445Sassar	    add_slave (context, keytab, &slaves, listen_fd);
63255682Smarkm	    --ret;
63355682Smarkm	}
634102644Snectar	write_stats(context, slaves, current_version);
63555682Smarkm    }
63655682Smarkm
63755682Smarkm    return 0;
63855682Smarkm}
639