From 715020f048a53a7237f64f3b0969edc7648ec8b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Thu, 3 Jul 2003 13:36:09 +0000 Subject: [PATCH] Add probing from the server that the client is still there, also make the client check that the server is probing. git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@12419 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/kadm5/iprop.h | 6 ++- lib/kadm5/ipropd_master.c | 102 ++++++++++++++++++++++++++++++++++---- lib/kadm5/ipropd_slave.c | 59 +++++++++++++++++++++- 3 files changed, 155 insertions(+), 12 deletions(-) diff --git a/lib/kadm5/iprop.h b/lib/kadm5/iprop.h index fafccfe68..4dc01a543 100644 --- a/lib/kadm5/iprop.h +++ b/lib/kadm5/iprop.h @@ -46,6 +46,8 @@ #include #endif +#include + #define IPROP_VERSION "iprop-0.0" #define KADM5_SLAVE_ACL HDB_DB_DIR "/slaves" @@ -62,7 +64,9 @@ enum iprop_cmd { I_HAVE = 1, FOR_YOU = 2, TELL_YOU_EVERYTHING = 3, ONE_PRINC = 4, - NOW_YOU_HAVE = 5 + NOW_YOU_HAVE = 5, + ARE_YOU_THERE = 6, + I_AM_HERE = 7 }; #endif /* __IPROP_H__ */ diff --git a/lib/kadm5/ipropd_master.c b/lib/kadm5/ipropd_master.c index ad29e307f..99a3ebaea 100644 --- a/lib/kadm5/ipropd_master.c +++ b/lib/kadm5/ipropd_master.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -39,6 +39,11 @@ RCSID("$Id$"); static krb5_log_facility *log_facility; const char *slave_stats_file = KADM5_SLAVE_STATS; +const char *slave_time_missing = "2 min"; +const char *slave_time_gone = "5 min"; + +static int time_before_missing; +static int time_before_gone; static int make_signal_socket (krb5_context context) @@ -122,6 +127,22 @@ slave_seen(slave *s) s->seen = time(NULL); } +static int +slave_missing_p (slave *s) +{ + if (time(NULL) > s->seen + time_before_missing) + return 1; + return 0; +} + +static int +slave_gone_p (slave *s) +{ + if (time(NULL) > s->seen + time_before_gone) + return 1; + return 0; +} + static void slave_dead(slave *s) { @@ -316,6 +337,35 @@ send_complete (krb5_context context, slave *s, return 0; } +static int +send_are_you_there (krb5_context context, slave *s) +{ + krb5_data data; + int ret; + + if (s->flags & SLAVE_F_DEAD) + return 0; + + ret = krb5_data_alloc (&data, 4); + if (ret) { + krb5_warn (context, ret, "are_you_there: krb5_data_alloc"); + slave_dead(s); + return 1; + } + _krb5_put_int(data.data, ARE_YOU_THERE, 4); + + ret = krb5_write_priv_message(context, s->ac, &s->fd, &data); + krb5_data_free(&data); + + if (ret) { + krb5_warn (context, ret, "are_you_there: krb5_write_priv_message"); + slave_dead(s); + return 1; + } + + return 0; +} + static int send_diffs (krb5_context context, slave *s, int log_fd, const char *database, u_int32_t current_version) @@ -348,7 +398,12 @@ send_diffs (krb5_context context, slave *s, int log_fd, if (left == 0) return send_complete (context, s, database, current_version); } - krb5_data_alloc (&data, right - left + 4); + ret = krb5_data_alloc (&data, right - left + 4); + if (ret) { + krb5_warn (context, ret, "send_diffs: krb5_data_alloc"); + slave_dead(s); + return 1; + } krb5_storage_read (sp, (char *)data.data + 4, data.length - 4); krb5_storage_free(sp); @@ -358,7 +413,7 @@ send_diffs (krb5_context context, slave *s, int log_fd, krb5_data_free(&data); if (ret) { - krb5_warn (context, ret, "krb5_write_priv_message"); + krb5_warn (context, ret, "send_diffs: krb5_write_priv_message"); slave_dead(s); return 1; } @@ -383,13 +438,29 @@ process_msg (krb5_context context, slave *s, int log_fd, } sp = krb5_storage_from_mem (out.data, out.length); - krb5_ret_int32 (sp, &tmp); + if (sp == NULL) { + krb5_warnx (context, "process_msg: no memory"); + krb5_data_free (&out); + return 1; + } + if (krb5_ret_int32 (sp, &tmp) != 0) { + krb5_warnx (context, "process_msg: client send too short command"); + krb5_data_free (&out); + return 1; + } switch (tmp) { case I_HAVE : - krb5_ret_int32 (sp, &tmp); + ret = krb5_ret_int32 (sp, &tmp); + if (ret != 0) { + krb5_warnx (context, "process_msg: client send too I_HAVE data"); + break; + } s->version = tmp; ret = send_diffs (context, s, log_fd, database, current_version); break; + case I_AM_HERE : + break; + case ARE_YOU_THERE: case FOR_YOU : default : krb5_warnx (context, "Ignoring command %d", tmp); @@ -490,6 +561,8 @@ static struct getargs args[] = { "keytab to get authentication from", "kspec" }, { "database", 'd', arg_string, &database, "database", "file"}, { "slave-stats-file", 0, arg_string, &slave_stats_file, "file"}, + { "time-missing", 0, arg_string, &slave_time_missing, "time"}, + { "time-gone", 0, arg_string, &slave_time_gone, "time"}, { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -519,6 +592,13 @@ main(int argc, char **argv) exit(0); } + time_before_gone = parse_time (slave_time_gone, "s"); + if (time_before_gone < 0) + krb5_errx (context, 1, "couldn't parse time: %s", slave_time_gone); + time_before_missing = parse_time (slave_time_missing, "s"); + if (time_before_missing < 0) + krb5_errx (context, 1, "couldn't parse time: %s", slave_time_missing); + pidfile (NULL); krb5_openlog (context, "ipropd-master", &log_facility); krb5_set_warn_dest(context, log_facility); @@ -593,12 +673,13 @@ main(int argc, char **argv) old_version = current_version; kadm5_log_get_version_fd (log_fd, ¤t_version); - if (current_version > old_version) + if (current_version > old_version) { for (p = slaves; p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) continue; send_diffs (context, p, log_fd, database, current_version); } + } } if (ret && FD_ISSET(signal_fd, &readset)) { @@ -615,16 +696,19 @@ main(int argc, char **argv) kadm5_log_get_version_fd (log_fd, ¤t_version); for (p = slaves; p != NULL; p = p->next) send_diffs (context, p, log_fd, database, current_version); - } + } for(p = slaves; ret && p != NULL; p = p->next) { if (p->flags & SLAVE_F_DEAD) - continue; + continue; if (FD_ISSET(p->fd, &readset)) { --ret; if(process_msg (context, p, log_fd, database, current_version)) slave_dead(p); - } + } else if (slave_gone_p (p)) + slave_dead (p); + else if (slave_missing_p (p)) + send_are_you_there (context, p); } if (ret && FD_ISSET(listen_fd, &readset)) { diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c index a3ec74782..0bf808fd7 100644 --- a/lib/kadm5/ipropd_slave.c +++ b/lib/kadm5/ipropd_slave.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2002 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2003 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -36,6 +36,8 @@ RCSID("$Id$"); static krb5_log_facility *log_facility; +static char *server_time_lost = "5 min"; +static int time_before_lost; static int connect_to_master (krb5_context context, const char *master) @@ -191,7 +193,7 @@ receive_loop (krb5_context context, ret = kadm5_log_replay (server_context, op, vers, len, sp); if (ret) - krb5_warn (context, ret, "kadm5_log_replay"); + krb5_warn (context, ret, "kadm5_log_replay: %d", (int)vers); else server_context->log_context.version = vers; krb5_storage_seek (sp, 8, SEEK_CUR); @@ -218,6 +220,26 @@ receive (krb5_context context, krb5_err (context, 1, ret, "db->close"); } +static void +send_im_here (krb5_context context, int fd, + krb5_auth_context auth_context) +{ + krb5_data data; + int ret; + + ret = krb5_data_alloc (&data, 4); + if (ret) + krb5_err (context, 1, ret, "send_im_here"); + + _krb5_put_int(data.data, I_AM_HERE, 4); + + ret = krb5_write_priv_message(context, auth_context, &fd, &data); + krb5_data_free(&data); + + if (ret) + krb5_err (context, 1, ret, "krb5_write_priv_message"); +} + static void receive_everything (krb5_context context, int fd, kadm5_server_context *server_context, @@ -321,6 +343,8 @@ static struct getargs args[] = { { "realm", 'r', arg_string, &realm }, { "keytab", 'k', arg_string, &keytab_str, "keytab to get authentication from", "kspec" }, + { "time-lost", 0, arg_string, &server_time_lost, + "time before server is considered lost", "time" }, { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -375,6 +399,10 @@ main(int argc, char **argv) if(ret) krb5_err(context, 1, ret, "krb5_kt_register"); + time_before_lost = parse_time (server_time_lost, "s"); + if (time_before_lost < 0) + krb5_errx (context, 1, "couldn't parse time: %s", server_time_lost); + memset(&conf, 0, sizeof(conf)); if(realm) { conf.mask |= KADM5_CONFIG_REALM; @@ -420,6 +448,29 @@ main(int argc, char **argv) krb5_data out; krb5_storage *sp; int32_t tmp; + fd_set readset; + struct timeval to; + + if (master_fd >= FD_SETSIZE) + krb5_errx (context, 1, "fd too large"); + + FD_ZERO(&readset); + FD_SET(master_fd, &readset); + + to.tv_sec = time_before_lost; + to.tv_usec = 0; + + ret = select (master_fd + 1, + &readset, NULL, NULL, &to); + if (ret < 0) { + if (errno == EINTR) + continue; + else + krb5_err (context, 1, errno, "select"); + } + if (ret == 0) + krb5_errx (context, 1, "server didn't send a message " + "in %d seconds", time_before_lost); ret = krb5_read_priv_message(context, auth_context, &master_fd, &out); @@ -438,9 +489,13 @@ main(int argc, char **argv) receive_everything (context, master_fd, server_context, auth_context); break; + case ARE_YOU_THERE : + send_im_here (context, master_fd, auth_context); + break; case NOW_YOU_HAVE : case I_HAVE : case ONE_PRINC : + case I_AM_HERE : default : krb5_warnx (context, "Ignoring command %d", tmp); break;