diff options
Diffstat (limited to 'crypto/heimdal/lib/kadm5/ipropd_master.c')
-rw-r--r-- | crypto/heimdal/lib/kadm5/ipropd_master.c | 209 |
1 files changed, 170 insertions, 39 deletions
diff --git a/crypto/heimdal/lib/kadm5/ipropd_master.c b/crypto/heimdal/lib/kadm5/ipropd_master.c index 9c87d6e..626e853 100644 --- a/crypto/heimdal/lib/kadm5/ipropd_master.c +++ b/crypto/heimdal/lib/kadm5/ipropd_master.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -32,8 +32,9 @@ */ #include "iprop.h" +#include <rtbl.h> -RCSID("$Id: ipropd_master.c,v 1.24 2001/09/03 05:54:18 assar Exp $"); +RCSID("$Id: ipropd_master.c,v 1.28 2002/08/16 18:27:53 joda Exp $"); static krb5_log_facility *log_facility; @@ -83,6 +84,9 @@ struct slave { char *name; krb5_auth_context ac; u_int32_t version; + time_t seen; + unsigned long flags; +#define SLAVE_F_DEAD 0x1 struct slave *next; }; @@ -111,6 +115,39 @@ check_acl (krb5_context context, const char *name) } static void +slave_seen(slave *s) +{ + s->seen = time(NULL); +} + +static void +slave_dead(slave *s) +{ + s->flags |= SLAVE_F_DEAD; + slave_seen(s); +} + +static void +remove_slave (krb5_context context, slave *s, slave **root) +{ + slave **p; + + if (s->fd >= 0) + close (s->fd); + if (s->name) + free (s->name); + if (s->ac) + krb5_auth_con_free (context, s->ac); + + for (p = root; *p; p = &(*p)->next) + if (*p == s) { + *p = s->next; + break; + } + free (s); +} + +static void add_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd) { krb5_principal server; @@ -159,38 +196,36 @@ add_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd) goto error; } krb5_free_ticket (context, ticket); + ticket = NULL; + + { + slave *l = *root; + + while (l) { + if (strcmp(l->name, s->name) == 0) + break; + l = l->next; + } + if (l) { + if (l->flags & SLAVE_F_DEAD) { + remove_slave(context, l, root); + } else { + krb5_warnx (context, "second connection from %s", s->name); + goto error; + } + } + } + krb5_warnx (context, "connection from %s", s->name); s->version = 0; + s->flags = 0; + slave_seen(s); s->next = *root; *root = s; return; error: - if (s->name) - free (s->name); - if (s->ac) - krb5_auth_con_free(context, s->ac); - if (ticket) - krb5_free_ticket (context, ticket); - close (s->fd); - free(s); -} - -static void -remove_slave (krb5_context context, slave *s, slave **root) -{ - slave **p; - - close (s->fd); - free (s->name); - krb5_auth_con_free (context, s->ac); - - for (p = root; *p; p = &(*p)->next) - if (*p == s) { - *p = s->next; - break; - } - free (s); + remove_slave(context, s, root); } struct prop_context { @@ -244,21 +279,33 @@ send_complete (krb5_context context, slave *s, ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); - if (ret) - krb5_err (context, 1, ret, "krb5_write_priv_message"); + if (ret) { + krb5_warn (context, ret, "krb5_write_priv_message"); + slave_dead(s); + return ret; + } ret = hdb_foreach (context, db, 0, prop_one, s); - if (ret) - krb5_err (context, 1, ret, "hdb_foreach"); + if (ret) { + krb5_warn (context, ret, "hdb_foreach"); + slave_dead(s); + return ret; + } _krb5_put_int (buf, NOW_YOU_HAVE, 4); _krb5_put_int (buf + 4, current_version, 4); data.length = 8; + s->version = current_version; + ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); + if (ret) { + slave_dead(s); + krb5_warn (context, ret, "krb5_write_priv_message"); + return ret; + } - if (ret) - krb5_err (context, 1, ret, "krb5_write_priv_message"); + slave_seen(s); return 0; } @@ -279,12 +326,15 @@ send_diffs (krb5_context context, slave *s, int log_fd, if (s->version == current_version) return 0; + if (s->flags & SLAVE_F_DEAD) + return 0; + sp = kadm5_log_goto_end (log_fd); - right = sp->seek(sp, 0, SEEK_CUR); + right = krb5_storage_seek(sp, 0, SEEK_CUR); for (;;) { if (kadm5_log_previous (sp, &ver, ×tamp, &op, &len)) abort (); - left = sp->seek(sp, -16, SEEK_CUR); + left = krb5_storage_seek(sp, -16, SEEK_CUR); if (ver == s->version) return 0; if (ver == s->version + 1) @@ -293,17 +343,21 @@ send_diffs (krb5_context context, slave *s, int log_fd, return send_complete (context, s, database, current_version); } krb5_data_alloc (&data, right - left + 4); - sp->fetch (sp, (char *)data.data + 4, data.length - 4); + krb5_storage_read (sp, (char *)data.data + 4, data.length - 4); krb5_storage_free(sp); _krb5_put_int(data.data, FOR_YOU, 4); ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); + krb5_data_free(&data); if (ret) { krb5_warn (context, ret, "krb5_write_priv_message"); + slave_dead(s); return 1; } + slave_seen(s); + return 0; } @@ -337,9 +391,86 @@ process_msg (krb5_context context, slave *s, int log_fd, } krb5_data_free (&out); + + slave_seen(s); + return ret; } +#define SLAVE_NAME "Name" +#define SLAVE_ADDRESS "Address" +#define SLAVE_VERSION "Version" +#define SLAVE_STATUS "Status" +#define SLAVE_SEEN "Last Seen" + +static void +write_stats(krb5_context context, slave *slaves, u_int32_t current_version) +{ + char str[30]; + rtbl_t tbl; + time_t t = time(NULL); + FILE *fp; + + fp = fopen(KADM5_SLAVE_STATS, "w"); + if (fp == NULL) + return; + + strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", + localtime(&t)); + fprintf(fp, "Status for slaves, last updated: %s\n\n", str); + + fprintf(fp, "Master version: %lu\n\n", (unsigned long)current_version); + + tbl = rtbl_create(); + if (tbl == NULL) { + fclose(fp); + return; + } + + rtbl_add_column(tbl, SLAVE_NAME, 0); + rtbl_add_column(tbl, SLAVE_ADDRESS, 0); + rtbl_add_column(tbl, SLAVE_VERSION, RTBL_ALIGN_RIGHT); + rtbl_add_column(tbl, SLAVE_STATUS, 0); + rtbl_add_column(tbl, SLAVE_SEEN, 0); + + rtbl_set_prefix(tbl, " "); + rtbl_set_column_prefix(tbl, SLAVE_NAME, ""); + + while (slaves) { + krb5_address addr; + krb5_error_code ret; + rtbl_add_column_entry(tbl, SLAVE_NAME, slaves->name); + ret = krb5_sockaddr2address (context, + (struct sockaddr*)&slaves->addr, &addr); + if(ret == 0) { + krb5_print_address(&addr, str, sizeof(str), NULL); + krb5_free_address(context, &addr); + rtbl_add_column_entry(tbl, SLAVE_ADDRESS, str); + } else + rtbl_add_column_entry(tbl, SLAVE_ADDRESS, "<unknown>"); + + snprintf(str, sizeof(str), "%u", (unsigned)slaves->version); + rtbl_add_column_entry(tbl, SLAVE_VERSION, str); + + if (slaves->flags & SLAVE_F_DEAD) + rtbl_add_column_entry(tbl, SLAVE_STATUS, "Down"); + else + rtbl_add_column_entry(tbl, SLAVE_STATUS, "Up"); + + strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S", + localtime(&slaves->seen)); + rtbl_add_column_entry(tbl, SLAVE_SEEN, str); + + slaves = slaves->next; + } + + rtbl_format(tbl, fp); + rtbl_destroy(tbl); + + fclose(fp); +} + + static char *realm; static int version_flag; static int help_flag; @@ -473,18 +604,18 @@ main(int argc, char **argv) send_diffs (context, p, log_fd, database, current_version); } - for(p = slaves; p != NULL; p = p->next) + for(p = slaves; ret && p != NULL; p = p->next) if (FD_ISSET(p->fd, &readset)) { --ret; if(process_msg (context, p, log_fd, database, current_version)) - remove_slave (context, p, &slaves); + slave_dead(p); } if (ret && FD_ISSET(listen_fd, &readset)) { add_slave (context, keytab, &slaves, listen_fd); --ret; } - + write_stats(context, slaves, current_version); } return 0; |