From 0382061b7b739ac4293d8641523f73a8ca79fc87 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Tue, 31 Jul 2007 22:15:08 +0000 Subject: [PATCH] add configuration for signal file and acl file, let user select hostname, catch signals and print why we are quiting, make nop cause one new version, not two git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@21756 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/kadm5/Makefile.am | 4 +- lib/kadm5/context_s.c | 16 +++----- lib/kadm5/iprop.h | 3 ++ lib/kadm5/ipropd_common.c | 69 ++++++++++++++++++++++++++++++++ lib/kadm5/ipropd_master.c | 84 +++++++++++++++++++++++++++++++++++---- lib/kadm5/ipropd_slave.c | 55 ++++++++++++++++++------- lib/kadm5/log.c | 20 +++++++--- 7 files changed, 212 insertions(+), 39 deletions(-) create mode 100644 lib/kadm5/ipropd_common.c diff --git a/lib/kadm5/Makefile.am b/lib/kadm5/Makefile.am index 8b523e511..5a3252feb 100644 --- a/lib/kadm5/Makefile.am +++ b/lib/kadm5/Makefile.am @@ -108,9 +108,9 @@ nodist_libkadm5srv_la_SOURCES = \ dist_iprop_log_SOURCES = iprop-log.c nodist_iprop_log_SOURCES = iprop-commands.c -ipropd_master_SOURCES = ipropd_master.c iprop.h kadm5_locl.h +ipropd_master_SOURCES = ipropd_master.c ipropd_common.c iprop.h kadm5_locl.h -ipropd_slave_SOURCES = ipropd_slave.c iprop.h kadm5_locl.h +ipropd_slave_SOURCES = ipropd_slave.c ipropd_common.c iprop.h kadm5_locl.h man_MANS = kadm5_pwcheck.3 iprop.8 iprop-log.8 diff --git a/lib/kadm5/context_s.c b/lib/kadm5/context_s.c index 5dd958556..3d4400eae 100644 --- a/lib/kadm5/context_s.c +++ b/lib/kadm5/context_s.c @@ -54,18 +54,13 @@ set_funcs(kadm5_server_context *c) } static void -set_socket_name(const char *dbname, struct sockaddr_un *un) +set_socket_name(krb5_context context, struct sockaddr_un *un) { - const char *p; + const char *fn = kadm5_log_signal_socket(context); + memset(un, 0, sizeof(*un)); un->sun_family = AF_UNIX; - p = strrchr(dbname, '.'); - if(p == NULL) - snprintf(un->sun_path, sizeof(un->sun_path), "%s.signal", - dbname); - else - snprintf(un->sun_path, sizeof(un->sun_path), "%.*s.signal", - (int)(p - dbname), dbname); + strlcpy (un->sun_path, fn, sizeof(un->sun_path)); } static kadm5_ret_t @@ -120,8 +115,7 @@ find_db_spec(kadm5_server_context *ctx) if (ctx->log_context.log_file == NULL) ctx->log_context.log_file = strdup(HDB_DB_DIR "/log"); - set_socket_name(ctx->config.dbname, - &ctx->log_context.socket_name); + set_socket_name(context, &ctx->log_context.socket_name); return 0; } diff --git a/lib/kadm5/iprop.h b/lib/kadm5/iprop.h index de682f64d..a456335ab 100644 --- a/lib/kadm5/iprop.h +++ b/lib/kadm5/iprop.h @@ -68,4 +68,7 @@ enum iprop_cmd { I_HAVE = 1, I_AM_HERE = 7 }; +extern sig_atomic_t exit_flag; +void setup_signal(void); + #endif /* __IPROP_H__ */ diff --git a/lib/kadm5/ipropd_common.c b/lib/kadm5/ipropd_common.c new file mode 100644 index 000000000..e6561596d --- /dev/null +++ b/lib/kadm5/ipropd_common.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan + * (Royal Institute of Technology, Stockholm, Sweden). + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * 3. Neither the name of the Institute nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include "iprop.h" +RCSID("$Id$"); + +sig_atomic_t exit_flag; + +static RETSIGTYPE +sigterm(int sig) +{ + exit_flag = sig; +} + +void +setup_signal(void) +{ +#ifdef HAVE_SIGACTION + { + struct sigaction sa; + + sa.sa_flags = 0; + sa.sa_handler = sigterm; + sigemptyset(&sa.sa_mask); + + sigaction(SIGINT, &sa, NULL); + sigaction(SIGTERM, &sa, NULL); + sigaction(SIGXCPU, &sa, NULL); + + sa.sa_handler = SIG_IGN; + sigaction(SIGPIPE, &sa, NULL); + } +#else + signal(SIGINT, sigterm); + signal(SIGTERM, sigterm); + signal(SIGXCPU, sigterm); + signal(SIGPIPE, SIG_IGN); +#endif +} diff --git a/lib/kadm5/ipropd_master.c b/lib/kadm5/ipropd_master.c index 8271ab1f9..6b6f9e126 100644 --- a/lib/kadm5/ipropd_master.c +++ b/lib/kadm5/ipropd_master.c @@ -38,25 +38,30 @@ RCSID("$Id$"); static krb5_log_facility *log_facility; -const char *slave_stats_file = KADM5_SLAVE_STATS; +const char *slave_stats_file; const char *slave_time_missing = "2 min"; const char *slave_time_gone = "5 min"; static int time_before_missing; static int time_before_gone; +const char *master_hostname; + static int make_signal_socket (krb5_context context) { struct sockaddr_un addr; + const char *fn; int fd; + fn = kadm5_log_signal_socket(context); + fd = socket (AF_UNIX, SOCK_DGRAM, 0); if (fd < 0) krb5_err (context, 1, errno, "socket AF_UNIX"); memset (&addr, 0, sizeof(addr)); addr.sun_family = AF_UNIX; - strlcpy (addr.sun_path, KADM5_LOG_SIGNAL, sizeof(addr.sun_path)); + strlcpy (addr.sun_path, fn, sizeof(addr.sun_path)); unlink (addr.sun_path); if (bind (fd, (struct sockaddr *)&addr, sizeof(addr)) < 0) krb5_err (context, 1, errno, "bind %s", addr.sun_path); @@ -119,11 +124,20 @@ typedef struct slave slave; static int check_acl (krb5_context context, const char *name) { + const char *fn; FILE *fp; char buf[256]; int ret = 1; - fp = fopen (KADM5_SLAVE_ACL, "r"); + + fn = krb5_config_get_string_default(context, + NULL, + KADM5_SLAVE_ACL, + "kdc", + "iprop-acl", + NULL); + + fp = fopen (fn, "r"); if (fp == NULL) return 1; while (fgets(buf, sizeof(buf), fp) != NULL) { @@ -215,7 +229,11 @@ add_slave (krb5_context context, krb5_keytab keytab, slave **root, int fd) krb5_warn (context, errno, "accept"); goto error; } - gethostname(hostname, sizeof(hostname)); + if (master_hostname) + strlcpy(hostname, master_hostname, sizeof(hostname)); + else + gethostname(hostname, sizeof(hostname)); + ret = krb5_sname_to_principal (context, hostname, IPROP_NAME, KRB5_NT_SRV_HST, &server); if (ret) { @@ -429,6 +447,10 @@ send_diffs (krb5_context context, slave *s, int log_fd, if (s->flags & SLAVE_F_DEAD) return 0; + /* if slave is a fresh client, starting over */ + if (s->version == 0) + return send_complete (context, s, database, current_version); + sp = kadm5_log_goto_end (log_fd); right = krb5_storage_seek(sp, 0, SEEK_CUR); for (;;) { @@ -535,6 +557,40 @@ process_msg (krb5_context context, slave *s, int log_fd, #define SLAVE_STATUS "Status" #define SLAVE_SEEN "Last Seen" +static FILE * +open_stats(krb5_context context) +{ + const char *fn; + + if (slave_stats_file) + fn = slave_stats_file; + else + fn = krb5_config_get_string_default(context, + NULL, + KADM5_SLAVE_STATS, + "kdc", + "iprop-stats", + NULL); + + return fopen(fn, "w"); +} + +static void +write_master_down(krb5_context context) +{ + char str[100]; + time_t t = time(NULL); + FILE *fp; + + fp = open_stats(context); + if (fp == NULL) + return; + krb5_format_time(context, t, str, sizeof(str), TRUE); + fprintf(fp, "master down at %s\n", str); + + fclose(fp); +} + static void write_stats(krb5_context context, slave *slaves, uint32_t current_version) { @@ -543,7 +599,7 @@ write_stats(krb5_context context, slave *slaves, uint32_t current_version) time_t t = time(NULL); FILE *fp; - fp = fopen(slave_stats_file, "w"); + fp = open_stats(context); if (fp == NULL) return; @@ -626,6 +682,8 @@ static struct getargs args[] = { "port ipropd will listen to", "port"}, { "detach", 0, arg_flag, &detach_from_console, "detach from console" }, + { "hostname", 0, arg_string, &master_hostname, + "hostname of master (if not same as hostname)", "hostname" }, { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -656,6 +714,8 @@ main(int argc, char **argv) exit(0); } + setup_signal(); + if (config_file == NULL) config_file = HDB_DB_DIR "/kdc.conf"; @@ -713,9 +773,9 @@ main(int argc, char **argv) signal_fd = make_signal_socket (context); listen_fd = make_listen_socket (context, port_str); - signal (SIGPIPE, SIG_IGN); + krb5_warnx(context, "ipropd-master started"); - for (;;) { + while(exit_flag == 0){ slave *p; fd_set readset; int max_fd = 0; @@ -799,5 +859,15 @@ main(int argc, char **argv) write_stats(context, slaves, current_version); } + if(exit_flag == SIGXCPU) + krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); + else if(exit_flag == SIGINT || exit_flag == SIGTERM) + krb5_warnx(context, "%s terminated", getprogname()); + else + krb5_warnx(context, "%s unexpected exit reason: %d", + getprogname(), exit_flag); + + write_master_down(context); + return 0; } diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c index 6456bf792..f47e4dd0c 100644 --- a/lib/kadm5/ipropd_slave.c +++ b/lib/kadm5/ipropd_slave.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2005 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2007 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -38,6 +38,7 @@ RCSID("$Id$"); static krb5_log_facility *log_facility; static char *server_time_lost = "5 min"; static int time_before_lost; +const char *slave_str = NULL; static int connect_to_master (krb5_context context, const char *master, @@ -80,7 +81,7 @@ connect_to_master (krb5_context context, const char *master, static void get_creds(krb5_context context, const char *keytab_str, - krb5_ccache *cache, const char *host) + krb5_ccache *cache, const char *serverhost) { krb5_keytab keytab; krb5_principal client; @@ -101,14 +102,15 @@ get_creds(krb5_context context, const char *keytab_str, if(ret) krb5_err(context, 1, ret, "%s", keytab_str); - ret = krb5_sname_to_principal (context, NULL, IPROP_NAME, + + ret = krb5_sname_to_principal (context, slave_str, IPROP_NAME, KRB5_NT_SRV_HST, &client); if (ret) krb5_err(context, 1, ret, "krb5_sname_to_principal"); ret = krb5_get_init_creds_opt_alloc(context, &init_opts); if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc"); - asprintf (&server, "%s/%s", IPROP_NAME, host); + asprintf (&server, "%s/%s", IPROP_NAME, serverhost); if (server == NULL) krb5_errx (context, 1, "malloc: no memory"); @@ -186,10 +188,8 @@ receive_loop (krb5_context context, left = krb5_storage_seek (sp, -16, SEEK_CUR); right = krb5_storage_seek (sp, 0, SEEK_END); buf = malloc (right - left); - if (buf == NULL && (right - left) != 0) { - krb5_warnx (context, "malloc: no memory"); - return; - } + if (buf == NULL && (right - left) != 0) + krb5_errx (context, 1, "malloc: no memory"); /* * ...and then write them out to the on-disk log. @@ -217,12 +217,21 @@ receive_loop (krb5_context context, if(krb5_ret_int32 (sp, &vers) != 0) break; - krb5_ret_int32 (sp, ×tamp); - krb5_ret_int32 (sp, &tmp); + ret = krb5_ret_int32 (sp, ×tamp); + if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); + ret = krb5_ret_int32 (sp, &tmp); + if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); op = tmp; - krb5_ret_int32 (sp, &len); + ret = krb5_ret_int32 (sp, &len); + if (ret) krb5_errx(context, 1, "entry %ld: too short", (long)vers); + if (len < 0) + krb5_errx(context, 1, "log is corrupted, " + "negative length of entry version %ld: %ld", + (long)vers, (long)len); cur = krb5_storage_seek(sp, 0, SEEK_CUR); + krb5_warnx (context, "replying entry %d", (int)vers); + ret = kadm5_log_replay (server_context, op, vers, len, sp); if (ret) @@ -232,9 +241,9 @@ receive_loop (krb5_context context, /* * Don't trust the kadm5_log_reply* functions to do the right - * thing and set the offset to the end ourself. + * thing and set the offset to the end of the entry ourself. */ - krb5_storage_seek (sp, cur + 8, SEEK_SET); + krb5_storage_seek (sp, cur + len + 8, SEEK_SET); } } @@ -297,6 +306,8 @@ receive_everything (krb5_context context, int fd, char *dbname; HDB *mydb; + krb5_warnx(context, "receive complete database"); + asprintf(&dbname, "%s-NEW", server_context->db->hdb_name); ret = hdb_create(context, &mydb, dbname); if(ret) @@ -384,6 +395,8 @@ receive_everything (krb5_context context, int fd, ret = mydb->hdb_destroy (context, mydb); if (ret) krb5_err (context, 1, ret, "db->destroy"); + + krb5_warnx(context, "receive complete database, version %ld", (long)vno); } static char *config_file; @@ -405,6 +418,8 @@ static struct getargs args[] = { "port ipropd-slave will connect to", "port"}, { "detach", 0, arg_flag, &detach_from_console, "detach from console" }, + { "hostname", 0, arg_string, &slave_str, + "hostname of slave (if not same as hostname)", "hostname" }, { "version", 0, arg_flag, &version_flag }, { "help", 0, arg_flag, &help_flag } }; @@ -437,6 +452,8 @@ main(int argc, char **argv) exit(0); } + setup_signal(); + if (config_file == NULL) config_file = HDB_DB_DIR "/kdc.conf"; @@ -508,10 +525,12 @@ main(int argc, char **argv) if (ret) krb5_err (context, 1, ret, "krb5_sendauth"); + krb5_warnx(context, "ipropd-slave started"); + ihave (context, auth_context, master_fd, server_context->log_context.version); - for (;;) { + while (exit_flag == 0) { krb5_data out; krb5_storage *sp; int32_t tmp; @@ -571,5 +590,13 @@ main(int argc, char **argv) krb5_data_free (&out); } + if(exit_flag == SIGXCPU) + krb5_warnx(context, "%s CPU time limit exceeded", getprogname()); + else if(exit_flag == SIGINT || exit_flag == SIGTERM) + krb5_warnx(context, "%s terminated", getprogname()); + else + krb5_warnx(context, "%s unexpected exit reason: %d", + getprogname(), exit_flag); + return 0; } diff --git a/lib/kadm5/log.c b/lib/kadm5/log.c index d87fbbded..f21c1550b 100644 --- a/lib/kadm5/log.c +++ b/lib/kadm5/log.c @@ -124,6 +124,7 @@ kadm5_log_reinit (kadm5_server_context *context) kadm5_log_context *log_context = &context->log_context; if (log_context->log_fd != -1) { + flock (log_context->log_fd, LOCK_UN); close (log_context->log_fd); log_context->log_fd = -1; } @@ -708,7 +709,7 @@ kadm5_log_replay_modify (kadm5_server_context *context, } /* - * Add a `nop' operation to the log. + * Add a `nop' operation to the log. Does not close the log. */ kadm5_ret_t @@ -733,9 +734,7 @@ kadm5_log_nop (kadm5_server_context *context) } ret = kadm5_log_flush (log_context, sp); krb5_storage_free (sp); - if (ret) - return ret; - ret = kadm5_log_end (context); + return ret; } @@ -913,7 +912,7 @@ kadm5_log_truncate (kadm5_server_context *server_context) if (ret) return ret; - ret = kadm5_log_set_version (server_context, vno + 1); + ret = kadm5_log_set_version (server_context, vno); if (ret) return ret; @@ -927,3 +926,14 @@ kadm5_log_truncate (kadm5_server_context *server_context) return 0; } + +const char * +kadm5_log_signal_socket(krb5_context context) +{ + return krb5_config_get_string_default(context, + NULL, + KADM5_LOG_SIGNAL, + "kdc", + "signal_socket", + NULL); +}