aboutsummaryrefslogtreecommitdiff
path: root/lib/kadm5/ipropd_slave.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/kadm5/ipropd_slave.c')
-rw-r--r--lib/kadm5/ipropd_slave.c186
1 files changed, 147 insertions, 39 deletions
diff --git a/lib/kadm5/ipropd_slave.c b/lib/kadm5/ipropd_slave.c
index c5c65f6c1834..e572bffa7de4 100644
--- a/lib/kadm5/ipropd_slave.c
+++ b/lib/kadm5/ipropd_slave.c
@@ -38,12 +38,18 @@ RCSID("$Id$");
static const char *config_name = "ipropd-slave";
static int verbose;
+static int async_hdb = 0;
+static int no_keytab_flag;
+static char *ccache_str;
+static char *keytab_str;
static krb5_log_facility *log_facility;
static char five_min[] = "5 min";
static char *server_time_lost = five_min;
static int time_before_lost;
-const char *slave_str = NULL;
+static const char *slave_str;
+static const char *pidfile_basename;
+static char *realm;
static int
connect_to_master (krb5_context context, const char *master,
@@ -112,8 +118,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 *serverhost)
+get_creds(krb5_context context, krb5_ccache *cache, const char *serverhost)
{
krb5_keytab keytab;
krb5_principal client;
@@ -124,21 +129,43 @@ get_creds(krb5_context context, const char *keytab_str,
char keytab_buf[256];
int aret;
+ if (no_keytab_flag) {
+ /* We're using an externally refreshed ccache */
+ if (*cache == NULL) {
+ if (ccache_str == NULL)
+ ret = krb5_cc_default(context, cache);
+ else
+ ret = krb5_cc_resolve(context, ccache_str, cache);
+ if (ret)
+ krb5_err(context, 1, ret, "Could not resolve the default cache");
+ }
+ return;
+ }
+
if (keytab_str == NULL) {
ret = krb5_kt_default_name (context, keytab_buf, sizeof(keytab_buf));
- if (ret)
- krb5_err (context, 1, ret, "krb5_kt_default_name");
- keytab_str = keytab_buf;
+ if (ret == 0) {
+ keytab_str = keytab_buf;
+ } else {
+ krb5_warn(context, ret, "Using HDBGET: as the default keytab");
+ keytab_str = "HDBGET:";
+ }
}
+ if (*cache)
+ krb5_cc_destroy(context, *cache);
+ *cache = NULL;
+
ret = krb5_kt_resolve(context, keytab_str, &keytab);
if(ret)
krb5_err(context, 1, ret, "%s", keytab_str);
-
- ret = krb5_sname_to_principal (context, slave_str, IPROP_NAME,
- KRB5_NT_SRV_HST, &client);
+ 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");
+ if (realm)
+ ret = krb5_principal_set_realm(context, client, realm);
+ if (ret) krb5_err(context, 1, ret, "krb5_principal_set_realm");
ret = krb5_get_init_creds_opt_alloc(context, &init_opts);
if (ret) krb5_err(context, 1, ret, "krb5_get_init_creds_opt_alloc");
@@ -179,6 +206,8 @@ ihave(krb5_context context, krb5_auth_context auth_context,
krb5_data data;
sp = krb5_storage_from_mem(buf, 8);
+ if (sp == NULL)
+ krb5_err(context, IPROPD_RESTART_SLOW, ENOMEM, "Out of memory");
ret = krb5_store_uint32(sp, I_HAVE);
if (ret == 0)
ret = krb5_store_uint32(sp, version);
@@ -225,10 +254,8 @@ append_to_log_file(krb5_context context,
return EOVERFLOW;
buf = malloc(len);
- if (buf == NULL && len != 0) {
- krb5_warn(context, errno, "malloc: no memory");
- return ENOMEM;
- }
+ if (buf == NULL && len != 0)
+ return krb5_enomem(context);
if (krb5_storage_seek(sp, start, SEEK_SET) != start) {
krb5_errx(context, IPROPD_RESTART,
@@ -258,6 +285,10 @@ append_to_log_file(krb5_context context,
ret = fsync(server_context->log_context.log_fd);
if (ret == 0)
return 0;
+ krb5_warn(context, ret,
+ "Failed to write iprop log fd %d %llu bytes at offset %lld: %d",
+ server_context->log_context.log_fd, (unsigned long long)len,
+ (long long)log_off, ret);
/*
* Attempt to recover from this. First, truncate the log file
@@ -307,9 +338,9 @@ append_to_log_file(krb5_context context,
}
static int
-receive_loop (krb5_context context,
- krb5_storage *sp,
- kadm5_server_context *server_context)
+receive_loop(krb5_context context,
+ krb5_storage *sp,
+ kadm5_server_context *server_context)
{
int ret;
off_t left, right, off;
@@ -318,6 +349,11 @@ receive_loop (krb5_context context,
if (verbose)
krb5_warnx(context, "receiving diffs");
+ ret = kadm5_log_exclusivelock(server_context);
+ if (ret)
+ krb5_err(context, IPROPD_RESTART, ret,
+ "Failed to lock iprop log for writes");
+
/*
* Seek to the first entry in the message from the master that is
* past the current version of the local database.
@@ -420,21 +456,27 @@ receive(krb5_context context,
kadm5_server_context *server_context)
{
krb5_error_code ret, ret2;
+ HDB *mydb = server_context->db;
- ret = server_context->db->hdb_open(context,
- server_context->db,
- O_RDWR | O_CREAT, 0600);
+ ret = mydb->hdb_open(context, server_context->db, O_RDWR | O_CREAT, 0600);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->open");
+ (void) mydb->hdb_set_sync(context, mydb, !async_hdb);
ret2 = receive_loop(context, sp, server_context);
if (ret2)
krb5_warn(context, ret2, "receive from ipropd-master had errors");
- ret = server_context->db->hdb_close(context, server_context->db);
+ ret = mydb->hdb_close(context, server_context->db);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "db->close");
+ (void) kadm5_log_sharedlock(server_context);
+ if (verbose)
+ krb5_warnx(context, "downgraded iprop log lock to shared");
+ kadm5_log_signal_master(server_context);
+ if (verbose)
+ krb5_warnx(context, "signaled master for hierarchical iprop");
return ret2;
}
@@ -483,6 +525,9 @@ reinit_log(krb5_context context,
ret = kadm5_log_reinit(server_context, vno);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "kadm5_log_reinit");
+ (void) kadm5_log_sharedlock(server_context);
+ if (verbose)
+ krb5_warnx(context, "downgraded iprop log lock to shared");
}
@@ -502,7 +547,18 @@ receive_everything(krb5_context context, int fd,
krb5_warnx(context, "receive complete database");
- ret = asprintf(&dbname, "%s-NEW", server_context->db->hdb_name);
+ ret = kadm5_log_exclusivelock(server_context);
+ if (ret)
+ krb5_err(context, IPROPD_RESTART, ret,
+ "Failed to lock iprop log for writes");
+ if (server_context->db->hdb_method_name) {
+ ret = asprintf(&dbname, "%.*s:%s-NEW",
+ (int) strlen(server_context->db->hdb_method_name) - 1,
+ server_context->db->hdb_method_name,
+ server_context->db->hdb_name);
+ } else {
+ ret = asprintf(&dbname, "%s-NEW", server_context->db->hdb_name);
+ }
if (ret == -1)
krb5_err(context, IPROPD_RESTART, ENOMEM, "asprintf");
ret = hdb_create(context, &mydb, dbname);
@@ -539,7 +595,7 @@ receive_everything(krb5_context context, int fd,
krb5_ret_uint32(sp, &opcode);
if (opcode == ONE_PRINC) {
krb5_data fake_data;
- hdb_entry_ex entry;
+ hdb_entry entry;
krb5_storage_free(sp);
@@ -548,7 +604,7 @@ receive_everything(krb5_context context, int fd,
memset(&entry, 0, sizeof(entry));
- ret = hdb_value2entry(context, &fake_data, &entry.entry);
+ ret = hdb_value2entry(context, &fake_data, &entry);
if (ret)
krb5_err(context, IPROPD_RESTART, ret, "hdb_value2entry");
ret = mydb->hdb_store(server_context->context,
@@ -557,7 +613,7 @@ receive_everything(krb5_context context, int fd,
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "hdb_store");
- hdb_free_entry(context, &entry);
+ hdb_free_entry(context, mydb, &entry);
krb5_data_free(&data);
} else if (opcode == NOW_YOU_HAVE)
;
@@ -574,7 +630,7 @@ receive_everything(krb5_context context, int fd,
reinit_log(context, server_context, vno);
- ret = mydb->hdb_set_sync(context, mydb, 1);
+ ret = mydb->hdb_set_sync(context, mydb, !async_hdb);
if (ret)
krb5_err(context, IPROPD_RESTART_SLOW, ret, "failed to sync the received HDB");
ret = mydb->hdb_close(context, mydb);
@@ -631,9 +687,8 @@ slave_status(krb5_context context,
(void) unlink(file);
return;
}
- krb5_warnx(context, "slave status change: %s", status);
-
rk_dumpdata(file, status, len);
+ krb5_warnx(context, "slave status change: %s", status);
free(status);
}
@@ -652,12 +707,11 @@ is_up_to_date(krb5_context context, const char *file,
(unsigned long)server_context->log_context.version, buf);
}
+static char *database;
static char *status_file;
static char *config_file;
-static char *realm;
static int version_flag;
static int help_flag;
-static char *keytab_str;
static char *port_str;
static int detach_from_console;
static int daemon_child = -1;
@@ -665,8 +719,13 @@ static int daemon_child = -1;
static struct getargs args[] = {
{ "config-file", 'c', arg_string, &config_file, NULL, NULL },
{ "realm", 'r', arg_string, &realm, NULL, NULL },
+ { "database", 'd', arg_string, &database, "database", "file"},
+ { "no-keytab", 0, arg_flag, &no_keytab_flag,
+ "use externally refreshed cache", NULL },
+ { "ccache", 0, arg_string, &ccache_str,
+ "client credentials", "CCACHE" },
{ "keytab", 'k', arg_string, &keytab_str,
- "keytab to get authentication from", "kspec" },
+ "client credentials keytab", "KEYTAB" },
{ "time-lost", 0, arg_string, &server_time_lost,
"time before server is considered lost", "time" },
{ "status-file", 0, arg_string, &status_file,
@@ -675,8 +734,11 @@ static struct getargs args[] = {
"port ipropd-slave will connect to", "port"},
{ "detach", 0, arg_flag, &detach_from_console,
"detach from console", NULL },
- { "daemon-child", 0 , arg_integer, &daemon_child,
+ { "daemon-child", 0, arg_integer, &daemon_child,
"private argument, do not use", NULL },
+ { "pidfile-basename", 0, arg_string, &pidfile_basename,
+ "basename of pidfile; private argument for testing", "NAME" },
+ { "async-hdb", 'a', arg_flag, &async_hdb, NULL, NULL },
{ "hostname", 0, arg_string, rk_UNCONST(&slave_str),
"hostname of slave (if not same as hostname)", "hostname" },
{ "verbose", 0, arg_flag, &verbose, NULL, NULL },
@@ -703,7 +765,7 @@ main(int argc, char **argv)
kadm5_server_context *server_context;
kadm5_config_params conf;
int master_fd;
- krb5_ccache ccache;
+ krb5_ccache ccache = NULL;
krb5_principal server;
char **files;
int optidx = 0;
@@ -730,8 +792,8 @@ main(int argc, char **argv)
}
if (detach_from_console && daemon_child == -1)
- roken_detach_prep(argc, argv, "--daemon-child");
- rk_pidfile(NULL);
+ daemon_child = roken_detach_prep(argc, argv, "--daemon-child");
+ rk_pidfile(pidfile_basename);
ret = krb5_init_context(&context);
if (ret)
@@ -787,6 +849,10 @@ main(int argc, char **argv)
conf.mask |= KADM5_CONFIG_REALM;
conf.realm = realm;
}
+ if (database) {
+ conf.mask |= KADM5_CONFIG_DBNAME;
+ conf.dbname = database;
+ }
ret = kadm5_init_with_password_ctx (context,
KADM5_ADMIN_SERVICE,
NULL,
@@ -800,11 +866,24 @@ main(int argc, char **argv)
slave_status(context, status_file, "creating log file");
- ret = kadm5_log_init (server_context);
+ ret = server_context->db->hdb_open(context,
+ server_context->db,
+ O_RDWR | O_CREAT, 0600);
+ if (ret)
+ krb5_err (context, 1, ret, "db->open");
+
+ ret = kadm5_log_init(server_context);
+ if (ret)
+ krb5_err(context, 1, ret, "kadm5_log_init");
+ (void) kadm5_log_sharedlock(server_context);
+ if (verbose)
+ krb5_warnx(context, "downgraded iprop log lock to shared");
+
+ ret = server_context->db->hdb_close(context, server_context->db);
if (ret)
- krb5_err (context, 1, ret, "kadm5_log_init");
+ krb5_err(context, 1, ret, "db->close");
- get_creds(context, keytab_str, &ccache, master);
+ get_creds(context, &ccache, master);
ret = krb5_sname_to_principal (context, master, IPROP_NAME,
KRB5_NT_SRV_HST, &server);
@@ -869,9 +948,8 @@ main(int argc, char **argv)
if (auth_context) {
krb5_auth_con_free(context, auth_context);
auth_context = NULL;
- krb5_cc_destroy(context, ccache);
- get_creds(context, keytab_str, &ccache, master);
}
+ get_creds(context, &ccache, master);
if (verbose)
krb5_warnx(context, "authenticating to master");
ret = krb5_sendauth (context, &auth_context, &master_fd,
@@ -969,11 +1047,35 @@ main(int argc, char **argv)
continue;
}
+ /*
+ * It's unclear why we open th HDB and call kadm5_log_init() here.
+ *
+ * We don't need it to process the log entries we receive in the
+ * FOR_YOU case: we already call kadm5_log_recover() in receive() /
+ * receive_loop(). Maybe it's just just in case, though at the
+ * cost of synchronization with ipropd-master if we're running one
+ * for hierarchical iprop.
+ */
+ ret = server_context->db->hdb_open(context,
+ server_context->db,
+ O_RDWR | O_CREAT, 0600);
+ if (ret)
+ krb5_err (context, 1, ret, "db->open while handling a "
+ "message from the master");
ret = kadm5_log_init(server_context);
if (ret) {
krb5_err(context, IPROPD_RESTART, ret, "kadm5_log_init while "
"handling a message from the master");
}
+ (void) kadm5_log_sharedlock(server_context);
+ if (verbose)
+ krb5_warnx(context, "downgraded iprop log lock to shared");
+
+ ret = server_context->db->hdb_close (context, server_context->db);
+ if (ret)
+ krb5_err (context, 1, ret, "db->close while handling a "
+ "message from the master");
+
switch (tmp) {
case FOR_YOU :
if (verbose)
@@ -999,6 +1101,7 @@ main(int argc, char **argv)
krb5_warnx(context, "master sent us a full dump");
ret = receive_everything(context, master_fd, server_context,
auth_context);
+ (void) kadm5_log_sharedlock(server_context);
if (ret == 0) {
ret = ihave(context, auth_context, master_fd,
server_context->log_context.version);
@@ -1007,6 +1110,11 @@ main(int argc, char **argv)
connected = FALSE;
else
is_up_to_date(context, status_file, server_context);
+ if (verbose)
+ krb5_warnx(context, "downgraded iprop log lock to shared");
+ kadm5_log_signal_master(server_context);
+ if (verbose)
+ krb5_warnx(context, "signaled master for hierarchical iprop");
break;
case ARE_YOU_THERE :
if (verbose)