Skip Menu |
 

Date: Thu, 17 May 2012 19:27:18 -0400
From: Richard Basch <basch@alum.mit.edu>
Subject: Kerberos
To: krb5-bugs@mit.edu, krbdev@mit.edu
Download (untitled) / with headers
text/plain 21.3KiB
The attached patch fixes a few issues:
- Some error handlers forgot to check whether the variable was set before
trying to free memory.
- In the iprop code, there is a static variable, which makes it unsafe for
concurrent threads to perform a full resync.
- The iprop code is not scalable
- There is an artificial limit on how soon two iprop queries may
arrive (with 30+ slaves, UPDATE_BUSY is common)
- It is currently not possible to setup a tree hierarchy for iprop
(i.e. reduce WAN usage)
- The iprop code does not handle "policy" changes (add, update, delete).
- After a database load or other operation which re-initializes the ulog,
any slaves of that server will continually process full-resyncs until such
time as there is an "update" made in the ulog. A zero-length ulog causes
issues.

The attached patch introduces a tree replication strategy to iprop.
- Allow kadmind to be invoked with -proponly (it does not initialize other
kadmin services), which can be used on slaves.
- Create ulog entries on slaves when ulog_replay occurs.
Note: Several code changes were required since this means the log does not
always start at 1 and there may be gaps before the first entry. Thus the
ulog index is computed solely based on ((kdb serial - 1) % ulogsize).
Various routines were modified in kproplog, ulog_check(), etc. to eliminate
the assumption the log is populated from 0 .. ulog->kdb_num.
- When a policy change occurs, reinitialize the ulog so slaves are forced to
resync. This is required to ensure there is no inconsistency if a policy is
added on the master and then principals are associated with the new policy
(the current iprop method would leave the slaves in a divergent state from
the master).
Note: it would be better to propagate the policy change, but that requires
changing the current iprop protocol.
- Eliminate the check which prohibits multiple iprop queries within a
limited time.
- Enforce only one slave can receive a full resync at a time.
This is to ensure a production environment will not have multiple
slaves out of commission concurrently.
Note: Tree replication will propagate faster as the limit is
enforced only at the each node level.
- If ulog is empty, iprop will return UPDATE_BUSY rather than go into an
endless cycle of UPDATE_FULL_RESYNC_NEEDED.


diff -ru src.orig/include/kdb_log.h src/include/kdb_log.h
--- src.orig/include/kdb_log.h 2010-07-06 17:53:23.000000000 -0400
+++ src/include/kdb_log.h 2012-05-17 12:52:54.000000000 -0400
@@ -71,6 +71,7 @@
const char *logname, uint32_t entries,
int caller,
char **db_args);
+extern krb5_error_code ulog_init_header(krb5_context context);
extern krb5_error_code ulog_add_update(krb5_context context,
kdb_incr_update_t *upd);
extern krb5_error_code ulog_delete_update(krb5_context context,
diff -ru src.orig/kadmin/server/ipropd_svc.c src/kadmin/server/ipropd_svc.c
--- src.orig/kadmin/server/ipropd_svc.c 2011-11-07 17:35:48.000000000 -0500
+++ src/kadmin/server/ipropd_svc.c 2012-05-17 15:35:44.000000000 -0400
@@ -37,6 +37,8 @@
extern short l_port;
static char abuf[33];

+static int kdb_fullresync_in_progress = 0;
+
/* Result is stored in a static buffer and is invalidated by the next call.
*/
static const char *client_addr(struct svc_req *svc) {
strlcpy(abuf, inet_ntoa(svc->rq_xprt->xp_raddr.sin_addr),
sizeof(abuf));
@@ -187,6 +189,15 @@

kret = ulog_get_entries(handle->context, *arg, &ret);

+ /*
+ * Only permit one full resync at a time.
+ * First, we do not want to disrupt the functionality of multiple
slaves.
+ * Second, static variables are used within the full resync function
+ * which limits concurrency.
+ */
+ if ((ret.ret == UPDATE_FULL_RESYNC_NEEDED) &&
kdb_fullresync_in_progress)
+ ret.ret = UPDATE_BUSY;
+
if (ret.ret == UPDATE_OK) {
(void) snprintf(obuf, sizeof (obuf),
_("%s; Incoming SerialNo=%lu; Outgoing
SerialNo=%lu"),
@@ -270,6 +281,11 @@
krb5_klog_syslog(LOG_ERR,
_("%s: server handle is NULL"),
whoami);
+ return (&ret);
+ }
+
+ if (kdb_fullresync_in_progress++) {
+ ret.ret = UPDATE_BUSY;
goto out;
}

@@ -421,14 +437,22 @@
}

out:
+ /* Even if we were busy, we inrecemented first; it is safe to decrement
*/
+ if (kdb_fullresync_in_progress)
+ kdb_fullresync_in_progress--;
+
if (nofork)
debprret(whoami, ret.ret, 0);
- free(client_name);
- free(service_name);
+ if (client_name)
+ free(client_name);
+ if (service_name)
+ free(service_name);
if (name)
gss_release_name(&min_stat, &name);
- free(tmpf);
- free(ubuf);
+ if (tmpf)
+ free(tmpf);
+ if (ubuf)
+ free(ubuf);
return (&ret);
}

diff -ru src.orig/kadmin/server/ovsec_kadmd.c
src/kadmin/server/ovsec_kadmd.c
--- src.orig/kadmin/server/ovsec_kadmd.c 2011-09-21
12:29:00.000000000 -0400
+++ src/kadmin/server/ovsec_kadmd.c 2012-05-15 15:21:29.000000000 -0400
@@ -110,6 +110,7 @@
fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m]
[-nofork] "
"[-port port-number]\n"
"\t\t[-P pid_file]\n"
+ "\t\t[-proponly]\n"
"\nwhere,\n\t[-x db_args]* - any number of database "
"specific arguments.\n"
"\t\t\tLook at each database documentation for "
@@ -204,6 +205,7 @@
static krb5_context hctx;

int nofork = 0;
+int prop_only = 0;

int main(int argc, char *argv[])
{
@@ -287,6 +289,8 @@
} else if (strcmp(*argv, "-passwordserver") == 0) {
kadm5_set_use_password_server ();
#endif
+ } else if (strcmp(*argv, "-proponly") == 0) {
+ prop_only = 1;
} else if(strcmp(*argv, "-port") == 0) {
argc--; argv++;
if(!argc)
@@ -382,10 +386,15 @@
}

#define server_handle ((kadm5_server_handle_t)global_server_handle)
- if ((ret = loop_add_udp_port(server_handle->params.kpasswd_port))
+ if (prop_only
+ || (ret = loop_add_udp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_tcp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_rpc_service(server_handle->params.kadmind_port,
KADM, KADMVERS, kadm_1))
+ )
+ /* Do nothing; our error handling will follow */
+ 1;
+ if (ret
#ifndef DISABLE_IPROP
|| (server_handle->params.iprop_enabled
? (ret = loop_add_rpc_service(server_handle->params.iprop_port,
diff -ru src.orig/lib/kdb/kdb5.c src/lib/kdb/kdb5.c
--- src.orig/lib/kdb/kdb5.c 2011-10-04 16:16:07.000000000 -0400
+++ src/lib/kdb/kdb5.c 2012-05-17 12:51:57.000000000 -0400
@@ -41,6 +41,7 @@
#include <string.h>
#include <k5-int.h>
#include <osconf.h>
+#include <sys/mman.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -2254,15 +2255,30 @@
krb5_error_code
krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->create_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->create_policy(kcontext, policy);
+ status = v->create_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2282,15 +2298,31 @@
krb5_error_code
krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->put_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->put_policy(kcontext, policy);
+ status = v->put_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2311,15 +2343,31 @@
krb5_error_code
krb5_db_delete_policy(krb5_context kcontext, char *policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->delete_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->delete_policy(kcontext, policy);
+ status = v->delete_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

void
diff -ru src.orig/lib/kdb/kdb_log.c src/lib/kdb/kdb_log.c
--- src.orig/lib/kdb/kdb_log.c 2011-06-10 14:17:37.000000000 -0400
+++ src/lib/kdb/kdb_log.c 2012-05-17 16:09:06.000000000 -0400
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <limits.h>
#include <syslog.h>
+#include <errno.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -413,6 +414,64 @@
goto cleanup;
}

+ // XXX XXX
+ if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
+ uint32_t ulogentries = log_ctx->ulogentries;
+ int ulogfd = log_ctx->ulogfd;
+ uint_t indx = (upd->kdb_entry_sno - 1) % ulogentries;
+ ulong_t upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t,
upd);
+ uint_t recsize = sizeof (kdb_ent_header_t) + upd_size;
+ kdb_ent_header_t *indx_log;
+ XDR xdrs;
+
+ if (recsize > ulog->kdb_block) {
+ if ((retval = ulog_resize(ulog, ulogentries, ulogfd,
recsize)))
+ goto cleanup;
+ ulog->kdb_first_sno = 0;
+ }
+
+ ulog->kdb_state = KDB_UNSTABLE;
+
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ (void) memset(indx_log, 0, ulog->kdb_block);
+
+ indx_log->kdb_umagic = KDB_ULOG_MAGIC;
+ indx_log->kdb_entry_size = upd_size;
+ indx_log->kdb_entry_sno = upd->kdb_entry_sno;
+ indx_log->kdb_time = upd->kdb_time;
+ indx_log->kdb_commit = TRUE;
+
+ xdrmem_create(&xdrs, (char *)indx_log->entry_data,
+ indx_log->kdb_entry_size, XDR_ENCODE);
+ if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
+ retval = KRB5_LOG_CONV;
+ goto cleanup;
+ }
+
+ if (ulog->kdb_num < ulogentries)
+ ulog->kdb_num++;
+
+ ulog->kdb_last_sno = upd->kdb_entry_sno;
+ ulog->kdb_last_time = upd->kdb_time;
+
+ if (! ulog->kdb_first_sno) {
+ ulog->kdb_first_sno = upd->kdb_entry_sno;
+ ulog->kdb_first_time = upd->kdb_time;
+ }
+ if (ulog->kdb_last_sno - ulog->kdb_first_sno >= ulogentries) {
+ indx = upd->kdb_entry_sno % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ ulog->kdb_first_sno = indx_log->kdb_entry_sno;
+ ulog->kdb_first_time = indx_log->kdb_time;
+ }
+
+ retval = ulog_finish_update(context, upd);
+ //retval = ulog_sync_update(ulog, indx_log);
+ if (retval)
+ goto cleanup;
+ }
+ // XXX XXX
+
upd++;
}

@@ -441,17 +500,34 @@
{
XDR xdrs;
krb5_error_code retval = 0;
- unsigned int i;
+ unsigned int i, ulogentries;
kdb_ent_header_t *indx_log;
kdb_incr_update_t *upd = NULL;
kdb_incr_result_t *incr_ret = NULL;

ulog->kdb_state = KDB_STABLE;

- for (i = 0; i < ulog->kdb_num; i++) {
- indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
+ if (ulog->kdb_num == 0)
+ goto error; /* Nothing to check; return OK */

- if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) {
+ ulogentries = context->kdblog_context->ulogentries;
+
+ if ((ulogentries <= 0)
+ || (ulog->kdb_first_sno <= 0) || (ulog->kdb_last_sno <= 0)
+ || (ulog->kdb_num > ulogentries)
+ || (ulog->kdb_last_sno - ulog->kdb_first_sno + 1 != ulog->kdb_num))
+ {
+ ulog->kdb_state = KDB_CORRUPT;
+ retval = KRB5_LOG_CORRUPT;
+ goto error;
+ }
+
+ for (i = ulog->kdb_first_sno; i <= ulog->kdb_last_sno; i++) {
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, ((i - 1) %
ulogentries));
+
+ if ((indx_log->kdb_umagic != KDB_ULOG_MAGIC)
+ || (indx_log->kdb_entry_sno != i))
+ {
/*
* Update entry corrupted we should scream and die
*/
@@ -529,7 +605,8 @@
if (upd)
ulog_free_entries(upd, 1);

- free(incr_ret);
+ if (incr_ret)
+ free(incr_ret);

ulog_sync_header(ulog);

@@ -574,7 +651,7 @@
return (errno);
}

- if ((caller == FKADMIND) || (caller == FKCOMMAND))
+ if ((caller == FKADMIND) || (caller == FKPROPD) || (caller ==
FKCOMMAND))
ulog_filesize += ulogentries * ULOG_BLOCK;

if (extend_file_to(ulogfd, ulog_filesize) < 0)
@@ -643,7 +720,7 @@
}
}

- if (caller == FKADMIND) {
+ if ((caller == FKADMIND) || (caller == FKPROPD)) {
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
@@ -683,11 +760,25 @@
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
- if (ulog->kdb_num != ulogentries) {
- if ((ulog->kdb_num != 0) &&
- ((ulog->kdb_last_sno > ulog->kdb_num) ||
- (ulog->kdb_num > ulogentries))) {

+ if (ulog->kdb_num > ulogentries) {
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+ }
+ if (ulog->kdb_num && (ulog->kdb_num != ulogentries)) {
+ uint_t indx;
+ kdb_ent_header_t *indx_log;
+
+ indx = (ulog->kdb_last_sno - 1) % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+
+ if (indx_log->kdb_entry_sno != ulog->kdb_last_sno) {
(void) memset(ulog, 0, sizeof (kdb_hlog_t));

ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
@@ -697,25 +788,57 @@

ulog_sync_header(ulog);
}
+ }

- /*
- * Expand ulog if we have specified a greater size
- */
- if (ulog->kdb_num < ulogentries) {
- ulog_filesize += ulogentries * ulog->kdb_block;
+ /*
+ * Expand ulog if we have specified a greater size
+ */
+ if (ulog->kdb_num < ulogentries) {
+ ulog_filesize += ulogentries * ulog->kdb_block;

- if (extend_file_to(ulogfd, ulog_filesize) < 0) {
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
- return errno;
- }
+ if (extend_file_to(ulogfd, ulog_filesize) < 0) {
+ ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return errno;
}
}
+
ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

return (0);
}

/*
+ *
+ */
+krb5_error_code
+ulog_init_header(krb5_context context)
+{
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog = NULL;
+ krb5_error_code retval;
+
+
+ INIT_ULOG(context);
+
+ /* The caller should already have a lock, but ensure it is "exclusive".
*/
+ if ((retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ return retval;
+
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+
+ /* The caller is responsible for unlocking... */
+ return (0);
+}
+
+
+/*
* Get the last set of updates seen, (last+1) to n is returned.
*/
krb5_error_code
@@ -737,7 +860,20 @@
INIT_ULOG(context);
ulogentries = log_ctx->ulogentries;

- retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
+ retval = ulog_lock(context, KRB5_LOCKMODE_SHARED |
KRB5_LOCKMODE_DONTBLOCK);
+ if (0
+#ifdef EWOULDBLOCK
+ || (retval == EWOULDBLOCK)
+#endif
+#ifdef EAGAIN
+ || (retval == EWOULDBLOCK)
+#endif
+ ) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }
+
if (retval)
return retval;

@@ -750,6 +886,9 @@
return (KRB5_LOG_CORRUPT);
}

+#if 0
+ /* This code block causes deadlock issues with lots of slaves. */
+
gettimeofday(&timestamp, NULL);

tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
@@ -758,6 +897,18 @@
(void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
return (0);
}
+#endif
+
+ /*
+ * Special case - no log entries. The first sync should be a full
+ * resync since we can't compare timestamps, but we don't want to
+ * loop doing full resyncs until there is a log update.
+ */
+ if (last.last_sno && (ulog->kdb_num == 0)) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }

/*
* We need to lock out other processes here, such as kadmin.local,
Only in src/lib/kdb: kdb_log.c.~1~
Only in src/plugins/kdb/ldap/ldap_util: RCS
diff -ru src.orig/slave/kpropd.c src/slave/kpropd.c
--- src.orig/slave/kpropd.c 2011-06-30 23:26:58.000000000 -0400
+++ src/slave/kpropd.c 2012-05-17 13:58:08.000000000 -0400
@@ -146,6 +146,7 @@
char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
char *kerb_database = NULL;
char *acl_file_name = KPROPD_ACL_FILE;
+char *admin_server = NULL;

krb5_address *sender_addr;
krb5_address *receiver_addr;
@@ -179,6 +180,7 @@
progname);
fprintf(stderr, _("\t[-F kerberos_db_file ] [-p
kdb5_util_pathname]\n"));
fprintf(stderr, _("\t[-x db_args]* [-P port] [-a acl_file]\n"));
+ fprintf(stderr, _("\t[-A admin_server]\n"));
exit(1);
}

@@ -1046,6 +1048,15 @@
word++;
while (word && (ch = *word++)) {
switch(ch){
+ case 'A':
+ if (*word)
+ admin_server = word;
+ else
+ admin_server = *argv++;
+ if (!admin_server)
+ usage();
+ word = 0;
+ break;
case 'f':
if (*word)
file = word;
@@ -1193,6 +1204,11 @@
com_err(progname, retval, _("while initializing"));
exit(1);
}
+ if (admin_server) {
+ char *x = params.admin_server;
+ params.admin_server = admin_server;
+ admin_server = x;
+ }
if (params.iprop_enabled == TRUE) {
ulog_set_role(kpropd_context, IPROP_SLAVE);

diff -ru src.orig/slave/kproplog.c src/slave/kproplog.c
--- src.orig/slave/kproplog.c 2011-06-10 14:17:59.000000000 -0400
+++ src/slave/kproplog.c 2012-05-16 20:09:24.000000000 -0400
@@ -399,11 +399,13 @@
* Print the update entry information
*/
static void
-print_update(kdb_hlog_t *ulog, uint32_t entry, unsigned int verbose)
+print_update(krb5_context kcontext, uint32_t entry, unsigned int verbose)
{
XDR xdrs;
uint32_t start_sno, i, j, indx;
char *dbprinc;
+ uint32_t ulogentries =
kcontext->kdblog_context->ulogentries;
+ kdb_hlog_t *ulog = kcontext->kdblog_context->ulog;
kdb_ent_header_t *indx_log;
kdb_incr_update_t upd;

@@ -413,7 +415,7 @@
start_sno = ulog->kdb_first_sno - 1;

for (i = start_sno; i < ulog->kdb_last_sno; i++) {
- indx = i % ulog->kdb_num;
+ indx = i % ulogentries;

indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

@@ -538,7 +540,7 @@
(void) printf(_("\nKerberos update log (%s)\n"),
params.iprop_logfile);

- if (ulog_map(context, params.iprop_logfile, 0, FKPROPLOG, db_args)) {
+ if (ulog_map(context, params.iprop_logfile, params.iprop_ulogsize,
FKPROPLOG, db_args)) {
(void) fprintf(stderr, _("Unable to map log file %s\n\n"),
params.iprop_logfile);
exit(1);
@@ -609,7 +611,7 @@
}

if ((!headeronly) && ulog->kdb_num) {
- print_update(ulog, entry, verbose);
+ print_update(context, entry, verbose);
}

(void) printf("\n");
Date: Thu, 17 May 2012 19:30:35 -0400
From: Richard Basch <basch@alum.mit.edu>
Subject: Kerberos 1.10.1 - iprop issues
To: krbdev@mit.edu, krb5-bugs@mit.edu
Download (untitled) / with headers
text/plain 21.4KiB
Sorry, my original email forgot to mention the reference source... 1.10.1.

The attached patch fixes a few issues:
- Some error handlers forgot to check whether the variable was set before
trying to free memory.
- In the iprop code, there is a static variable, which makes it unsafe for
concurrent threads to perform a full resync.
- The iprop code is not scalable
- There is an artificial limit on how soon two iprop queries may
arrive (with 30+ slaves, UPDATE_BUSY is common)
- It is currently not possible to setup a tree hierarchy for iprop
(i.e. reduce WAN usage)
- The iprop code does not handle "policy" changes (add, update, delete).
- After a database load or other operation which re-initializes the ulog,
any slaves of that server will continually process full-resyncs until such
time as there is an "update" made in the ulog. A zero-length ulog causes
issues.

The attached patch introduces a tree replication strategy to iprop.
- Allow kadmind to be invoked with -proponly (it does not initialize other
kadmin services), which can be used on slaves.
- Create ulog entries on slaves when ulog_replay occurs.
Note: Several code changes were required since this means the log does not
always start at 1 and there may be gaps before the first entry. Thus the
ulog index is computed solely based on ((kdb serial - 1) % ulogsize).
Various routines were modified in kproplog, ulog_check(), etc. to eliminate
the assumption the log is populated from 0 .. ulog->kdb_num.
- When a policy change occurs, reinitialize the ulog so slaves are forced to
resync. This is required to ensure there is no inconsistency if a policy is
added on the master and then principals are associated with the new policy
(the current iprop method would leave the slaves in a divergent state from
the master).
Note: it would be better to propagate the policy change, but that requires
changing the current iprop protocol.
- Eliminate the check which prohibits multiple iprop queries within a
limited time.
- Enforce only one slave can receive a full resync at a time.
This is to ensure a production environment will not have multiple
slaves out of commission concurrently.
Note: Tree replication will propagate faster as the limit is
enforced only at the each node level.
- If ulog is empty, iprop will return UPDATE_BUSY rather than go into an
endless cycle of UPDATE_FULL_RESYNC_NEEDED.


diff -ru src.orig/include/kdb_log.h src/include/kdb_log.h
--- src.orig/include/kdb_log.h 2010-07-06 17:53:23.000000000 -0400
+++ src/include/kdb_log.h 2012-05-17 12:52:54.000000000 -0400
@@ -71,6 +71,7 @@
const char *logname, uint32_t entries,
int caller,
char **db_args);
+extern krb5_error_code ulog_init_header(krb5_context context);
extern krb5_error_code ulog_add_update(krb5_context context,
kdb_incr_update_t *upd);
extern krb5_error_code ulog_delete_update(krb5_context context,
diff -ru src.orig/kadmin/server/ipropd_svc.c src/kadmin/server/ipropd_svc.c
--- src.orig/kadmin/server/ipropd_svc.c 2011-11-07 17:35:48.000000000 -0500
+++ src/kadmin/server/ipropd_svc.c 2012-05-17 15:35:44.000000000 -0400
@@ -37,6 +37,8 @@
extern short l_port;
static char abuf[33];

+static int kdb_fullresync_in_progress = 0;
+
/* Result is stored in a static buffer and is invalidated by the next call.
*/
static const char *client_addr(struct svc_req *svc) {
strlcpy(abuf, inet_ntoa(svc->rq_xprt->xp_raddr.sin_addr),
sizeof(abuf));
@@ -187,6 +189,15 @@

kret = ulog_get_entries(handle->context, *arg, &ret);

+ /*
+ * Only permit one full resync at a time.
+ * First, we do not want to disrupt the functionality of multiple
slaves.
+ * Second, static variables are used within the full resync function
+ * which limits concurrency.
+ */
+ if ((ret.ret == UPDATE_FULL_RESYNC_NEEDED) &&
kdb_fullresync_in_progress)
+ ret.ret = UPDATE_BUSY;
+
if (ret.ret == UPDATE_OK) {
(void) snprintf(obuf, sizeof (obuf),
_("%s; Incoming SerialNo=%lu; Outgoing
SerialNo=%lu"),
@@ -270,6 +281,11 @@
krb5_klog_syslog(LOG_ERR,
_("%s: server handle is NULL"),
whoami);
+ return (&ret);
+ }
+
+ if (kdb_fullresync_in_progress++) {
+ ret.ret = UPDATE_BUSY;
goto out;
}

@@ -421,14 +437,22 @@
}

out:
+ /* Even if we were busy, we inrecemented first; it is safe to decrement
*/
+ if (kdb_fullresync_in_progress)
+ kdb_fullresync_in_progress--;
+
if (nofork)
debprret(whoami, ret.ret, 0);
- free(client_name);
- free(service_name);
+ if (client_name)
+ free(client_name);
+ if (service_name)
+ free(service_name);
if (name)
gss_release_name(&min_stat, &name);
- free(tmpf);
- free(ubuf);
+ if (tmpf)
+ free(tmpf);
+ if (ubuf)
+ free(ubuf);
return (&ret);
}

diff -ru src.orig/kadmin/server/ovsec_kadmd.c
src/kadmin/server/ovsec_kadmd.c
--- src.orig/kadmin/server/ovsec_kadmd.c 2011-09-21
12:29:00.000000000 -0400
+++ src/kadmin/server/ovsec_kadmd.c 2012-05-15 15:21:29.000000000 -0400
@@ -110,6 +110,7 @@
fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m]
[-nofork] "
"[-port port-number]\n"
"\t\t[-P pid_file]\n"
+ "\t\t[-proponly]\n"
"\nwhere,\n\t[-x db_args]* - any number of database "
"specific arguments.\n"
"\t\t\tLook at each database documentation for "
@@ -204,6 +205,7 @@
static krb5_context hctx;

int nofork = 0;
+int prop_only = 0;

int main(int argc, char *argv[])
{
@@ -287,6 +289,8 @@
} else if (strcmp(*argv, "-passwordserver") == 0) {
kadm5_set_use_password_server ();
#endif
+ } else if (strcmp(*argv, "-proponly") == 0) {
+ prop_only = 1;
} else if(strcmp(*argv, "-port") == 0) {
argc--; argv++;
if(!argc)
@@ -382,10 +386,15 @@
}

#define server_handle ((kadm5_server_handle_t)global_server_handle)
- if ((ret = loop_add_udp_port(server_handle->params.kpasswd_port))
+ if (prop_only
+ || (ret = loop_add_udp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_tcp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_rpc_service(server_handle->params.kadmind_port,
KADM, KADMVERS, kadm_1))
+ )
+ /* Do nothing; our error handling will follow */
+ 1;
+ if (ret
#ifndef DISABLE_IPROP
|| (server_handle->params.iprop_enabled
? (ret = loop_add_rpc_service(server_handle->params.iprop_port,
diff -ru src.orig/lib/kdb/kdb5.c src/lib/kdb/kdb5.c
--- src.orig/lib/kdb/kdb5.c 2011-10-04 16:16:07.000000000 -0400
+++ src/lib/kdb/kdb5.c 2012-05-17 12:51:57.000000000 -0400
@@ -41,6 +41,7 @@
#include <string.h>
#include <k5-int.h>
#include <osconf.h>
+#include <sys/mman.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -2254,15 +2255,30 @@
krb5_error_code
krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->create_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->create_policy(kcontext, policy);
+ status = v->create_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2282,15 +2298,31 @@
krb5_error_code
krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->put_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->put_policy(kcontext, policy);
+ status = v->put_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2311,15 +2343,31 @@
krb5_error_code
krb5_db_delete_policy(krb5_context kcontext, char *policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->delete_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->delete_policy(kcontext, policy);
+ status = v->delete_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

void
diff -ru src.orig/lib/kdb/kdb_log.c src/lib/kdb/kdb_log.c
--- src.orig/lib/kdb/kdb_log.c 2011-06-10 14:17:37.000000000 -0400
+++ src/lib/kdb/kdb_log.c 2012-05-17 16:09:06.000000000 -0400
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <limits.h>
#include <syslog.h>
+#include <errno.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -413,6 +414,64 @@
goto cleanup;
}

+ // XXX XXX
+ if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
+ uint32_t ulogentries = log_ctx->ulogentries;
+ int ulogfd = log_ctx->ulogfd;
+ uint_t indx = (upd->kdb_entry_sno - 1) % ulogentries;
+ ulong_t upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t,
upd);
+ uint_t recsize = sizeof (kdb_ent_header_t) + upd_size;
+ kdb_ent_header_t *indx_log;
+ XDR xdrs;
+
+ if (recsize > ulog->kdb_block) {
+ if ((retval = ulog_resize(ulog, ulogentries, ulogfd,
recsize)))
+ goto cleanup;
+ ulog->kdb_first_sno = 0;
+ }
+
+ ulog->kdb_state = KDB_UNSTABLE;
+
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ (void) memset(indx_log, 0, ulog->kdb_block);
+
+ indx_log->kdb_umagic = KDB_ULOG_MAGIC;
+ indx_log->kdb_entry_size = upd_size;
+ indx_log->kdb_entry_sno = upd->kdb_entry_sno;
+ indx_log->kdb_time = upd->kdb_time;
+ indx_log->kdb_commit = TRUE;
+
+ xdrmem_create(&xdrs, (char *)indx_log->entry_data,
+ indx_log->kdb_entry_size, XDR_ENCODE);
+ if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
+ retval = KRB5_LOG_CONV;
+ goto cleanup;
+ }
+
+ if (ulog->kdb_num < ulogentries)
+ ulog->kdb_num++;
+
+ ulog->kdb_last_sno = upd->kdb_entry_sno;
+ ulog->kdb_last_time = upd->kdb_time;
+
+ if (! ulog->kdb_first_sno) {
+ ulog->kdb_first_sno = upd->kdb_entry_sno;
+ ulog->kdb_first_time = upd->kdb_time;
+ }
+ if (ulog->kdb_last_sno - ulog->kdb_first_sno >= ulogentries) {
+ indx = upd->kdb_entry_sno % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ ulog->kdb_first_sno = indx_log->kdb_entry_sno;
+ ulog->kdb_first_time = indx_log->kdb_time;
+ }
+
+ retval = ulog_finish_update(context, upd);
+ //retval = ulog_sync_update(ulog, indx_log);
+ if (retval)
+ goto cleanup;
+ }
+ // XXX XXX
+
upd++;
}

@@ -441,17 +500,34 @@
{
XDR xdrs;
krb5_error_code retval = 0;
- unsigned int i;
+ unsigned int i, ulogentries;
kdb_ent_header_t *indx_log;
kdb_incr_update_t *upd = NULL;
kdb_incr_result_t *incr_ret = NULL;

ulog->kdb_state = KDB_STABLE;

- for (i = 0; i < ulog->kdb_num; i++) {
- indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
+ if (ulog->kdb_num == 0)
+ goto error; /* Nothing to check; return OK */

- if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) {
+ ulogentries = context->kdblog_context->ulogentries;
+
+ if ((ulogentries <= 0)
+ || (ulog->kdb_first_sno <= 0) || (ulog->kdb_last_sno <= 0)
+ || (ulog->kdb_num > ulogentries)
+ || (ulog->kdb_last_sno - ulog->kdb_first_sno + 1 != ulog->kdb_num))
+ {
+ ulog->kdb_state = KDB_CORRUPT;
+ retval = KRB5_LOG_CORRUPT;
+ goto error;
+ }
+
+ for (i = ulog->kdb_first_sno; i <= ulog->kdb_last_sno; i++) {
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, ((i - 1) %
ulogentries));
+
+ if ((indx_log->kdb_umagic != KDB_ULOG_MAGIC)
+ || (indx_log->kdb_entry_sno != i))
+ {
/*
* Update entry corrupted we should scream and die
*/
@@ -529,7 +605,8 @@
if (upd)
ulog_free_entries(upd, 1);

- free(incr_ret);
+ if (incr_ret)
+ free(incr_ret);

ulog_sync_header(ulog);

@@ -574,7 +651,7 @@
return (errno);
}

- if ((caller == FKADMIND) || (caller == FKCOMMAND))
+ if ((caller == FKADMIND) || (caller == FKPROPD) || (caller ==
FKCOMMAND))
ulog_filesize += ulogentries * ULOG_BLOCK;

if (extend_file_to(ulogfd, ulog_filesize) < 0)
@@ -643,7 +720,7 @@
}
}

- if (caller == FKADMIND) {
+ if ((caller == FKADMIND) || (caller == FKPROPD)) {
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
@@ -683,11 +760,25 @@
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
- if (ulog->kdb_num != ulogentries) {
- if ((ulog->kdb_num != 0) &&
- ((ulog->kdb_last_sno > ulog->kdb_num) ||
- (ulog->kdb_num > ulogentries))) {

+ if (ulog->kdb_num > ulogentries) {
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+ }
+ if (ulog->kdb_num && (ulog->kdb_num != ulogentries)) {
+ uint_t indx;
+ kdb_ent_header_t *indx_log;
+
+ indx = (ulog->kdb_last_sno - 1) % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+
+ if (indx_log->kdb_entry_sno != ulog->kdb_last_sno) {
(void) memset(ulog, 0, sizeof (kdb_hlog_t));

ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
@@ -697,25 +788,57 @@

ulog_sync_header(ulog);
}
+ }

- /*
- * Expand ulog if we have specified a greater size
- */
- if (ulog->kdb_num < ulogentries) {
- ulog_filesize += ulogentries * ulog->kdb_block;
+ /*
+ * Expand ulog if we have specified a greater size
+ */
+ if (ulog->kdb_num < ulogentries) {
+ ulog_filesize += ulogentries * ulog->kdb_block;

- if (extend_file_to(ulogfd, ulog_filesize) < 0) {
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
- return errno;
- }
+ if (extend_file_to(ulogfd, ulog_filesize) < 0) {
+ ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return errno;
}
}
+
ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

return (0);
}

/*
+ *
+ */
+krb5_error_code
+ulog_init_header(krb5_context context)
+{
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog = NULL;
+ krb5_error_code retval;
+
+
+ INIT_ULOG(context);
+
+ /* The caller should already have a lock, but ensure it is "exclusive".
*/
+ if ((retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ return retval;
+
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+
+ /* The caller is responsible for unlocking... */
+ return (0);
+}
+
+
+/*
* Get the last set of updates seen, (last+1) to n is returned.
*/
krb5_error_code
@@ -737,7 +860,20 @@
INIT_ULOG(context);
ulogentries = log_ctx->ulogentries;

- retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
+ retval = ulog_lock(context, KRB5_LOCKMODE_SHARED |
KRB5_LOCKMODE_DONTBLOCK);
+ if (0
+#ifdef EWOULDBLOCK
+ || (retval == EWOULDBLOCK)
+#endif
+#ifdef EAGAIN
+ || (retval == EWOULDBLOCK)
+#endif
+ ) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }
+
if (retval)
return retval;

@@ -750,6 +886,9 @@
return (KRB5_LOG_CORRUPT);
}

+#if 0
+ /* This code block causes deadlock issues with lots of slaves. */
+
gettimeofday(&timestamp, NULL);

tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
@@ -758,6 +897,18 @@
(void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
return (0);
}
+#endif
+
+ /*
+ * Special case - no log entries. The first sync should be a full
+ * resync since we can't compare timestamps, but we don't want to
+ * loop doing full resyncs until there is a log update.
+ */
+ if (last.last_sno && (ulog->kdb_num == 0)) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }

/*
* We need to lock out other processes here, such as kadmin.local,
Only in src/lib/kdb: kdb_log.c.~1~
Only in src/plugins/kdb/ldap/ldap_util: RCS
diff -ru src.orig/slave/kpropd.c src/slave/kpropd.c
--- src.orig/slave/kpropd.c 2011-06-30 23:26:58.000000000 -0400
+++ src/slave/kpropd.c 2012-05-17 13:58:08.000000000 -0400
@@ -146,6 +146,7 @@
char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
char *kerb_database = NULL;
char *acl_file_name = KPROPD_ACL_FILE;
+char *admin_server = NULL;

krb5_address *sender_addr;
krb5_address *receiver_addr;
@@ -179,6 +180,7 @@
progname);
fprintf(stderr, _("\t[-F kerberos_db_file ] [-p
kdb5_util_pathname]\n"));
fprintf(stderr, _("\t[-x db_args]* [-P port] [-a acl_file]\n"));
+ fprintf(stderr, _("\t[-A admin_server]\n"));
exit(1);
}

@@ -1046,6 +1048,15 @@
word++;
while (word && (ch = *word++)) {
switch(ch){
+ case 'A':
+ if (*word)
+ admin_server = word;
+ else
+ admin_server = *argv++;
+ if (!admin_server)
+ usage();
+ word = 0;
+ break;
case 'f':
if (*word)
file = word;
@@ -1193,6 +1204,11 @@
com_err(progname, retval, _("while initializing"));
exit(1);
}
+ if (admin_server) {
+ char *x = params.admin_server;
+ params.admin_server = admin_server;
+ admin_server = x;
+ }
if (params.iprop_enabled == TRUE) {
ulog_set_role(kpropd_context, IPROP_SLAVE);

diff -ru src.orig/slave/kproplog.c src/slave/kproplog.c
--- src.orig/slave/kproplog.c 2011-06-10 14:17:59.000000000 -0400
+++ src/slave/kproplog.c 2012-05-16 20:09:24.000000000 -0400
@@ -399,11 +399,13 @@
* Print the update entry information
*/
static void
-print_update(kdb_hlog_t *ulog, uint32_t entry, unsigned int verbose)
+print_update(krb5_context kcontext, uint32_t entry, unsigned int verbose)
{
XDR xdrs;
uint32_t start_sno, i, j, indx;
char *dbprinc;
+ uint32_t ulogentries =
kcontext->kdblog_context->ulogentries;
+ kdb_hlog_t *ulog = kcontext->kdblog_context->ulog;
kdb_ent_header_t *indx_log;
kdb_incr_update_t upd;

@@ -413,7 +415,7 @@
start_sno = ulog->kdb_first_sno - 1;

for (i = start_sno; i < ulog->kdb_last_sno; i++) {
- indx = i % ulog->kdb_num;
+ indx = i % ulogentries;

indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

@@ -538,7 +540,7 @@
(void) printf(_("\nKerberos update log (%s)\n"),
params.iprop_logfile);

- if (ulog_map(context, params.iprop_logfile, 0, FKPROPLOG, db_args)) {
+ if (ulog_map(context, params.iprop_logfile, params.iprop_ulogsize,
FKPROPLOG, db_args)) {
(void) fprintf(stderr, _("Unable to map log file %s\n\n"),
params.iprop_logfile);
exit(1);
@@ -609,7 +611,7 @@
}

if ((!headeronly) && ulog->kdb_num) {
- print_update(ulog, entry, verbose);
+ print_update(context, entry, verbose);
}

(void) printf("\n");
Just a quick response without having done more than glance at the patch:
it's our current practice to call free() without checking for null, as C89
guarantees that free() is a no-op in that case. Similarly for
krb5_free_foo().
Date: Sat, 19 May 2012 16:41:19 -0400
From: Richard Basch <basch@alum.mit.edu>
Subject: RE: [krbdev.mit.edu #7140] krb5-1.10.1 iprop issues
To: ghudson@mit.edu, rt-comment@krbdev.mit.edu
RT-Send-Cc:
Fair enough... I still remember those null dereference SIGSEGV crashes from
the 80s and early 90s, before c89 was ubiquitous.

However, what was more interesting was the code in some affected sections
had some "if (ptr) free(ptr)" clauses pre-existing, so I figured you were
still coding defensively for pre-c89 compilers (what I saw in the code was a
mix of "blind " and "conditional" free statements). Basically, it should be
consistent... either all "blind" or all "conditional".


Show quoted text
-----Original Message-----
From: Greg Hudson via RT [mailto:rt-comment@krbdev.mit.edu]
Sent: Thursday, May 17, 2012 8:09 PM
To: basch@alum.mit.edu
Subject: [krbdev.mit.edu #7140] krb5-1.10.1 iprop issues

Just a quick response without having done more than glance at the patch:
it's our current practice to call free() without checking for null, as C89
guarantees that free() is a no-op in that case. Similarly for
krb5_free_foo().
Date: Sun, 20 May 2012 15:33:56 -0400
From: Richard Basch <basch@alum.mit.edu>
Subject: RE: Kerberos 1.10.1 - iprop issues
To: "'Richard Basch'" <basch@alum.mit.edu>, krbdev@MIT.EDU, krb5-bugs@MIT.EDU
Download (untitled) / with headers
text/plain 21.7KiB
Another patch will be forthcoming... there seems to be a sporadic "log
corruption" condition, under load.

Show quoted text
-----Original Message-----
From: Richard Basch [mailto:basch@alum.mit.edu]
Sent: Thursday, May 17, 2012 7:31 PM
To: 'krbdev@mit.edu'; 'krb5-bugs@mit.edu'
Subject: Kerberos 1.10.1 - iprop issues

Sorry, my original email forgot to mention the reference source... 1.10.1.

The attached patch fixes a few issues:
- Some error handlers forgot to check whether the variable was set before
trying to free memory.
- In the iprop code, there is a static variable, which makes it unsafe for
concurrent threads to perform a full resync.
- The iprop code is not scalable
- There is an artificial limit on how soon two iprop queries may
arrive (with 30+ slaves, UPDATE_BUSY is common)
- It is currently not possible to setup a tree hierarchy for iprop
(i.e. reduce WAN usage)
- The iprop code does not handle "policy" changes (add, update, delete).
- After a database load or other operation which re-initializes the ulog,
any slaves of that server will continually process full-resyncs until such
time as there is an "update" made in the ulog. A zero-length ulog causes
issues.

The attached patch introduces a tree replication strategy to iprop.
- Allow kadmind to be invoked with -proponly (it does not initialize other
kadmin services), which can be used on slaves.
- Create ulog entries on slaves when ulog_replay occurs.
Note: Several code changes were required since this means the log does not
always start at 1 and there may be gaps before the first entry. Thus the
ulog index is computed solely based on ((kdb serial - 1) % ulogsize).
Various routines were modified in kproplog, ulog_check(), etc. to eliminate
the assumption the log is populated from 0 .. ulog->kdb_num.
- When a policy change occurs, reinitialize the ulog so slaves are forced to
resync. This is required to ensure there is no inconsistency if a policy is
added on the master and then principals are associated with the new policy
(the current iprop method would leave the slaves in a divergent state from
the master).
Note: it would be better to propagate the policy change, but that requires
changing the current iprop protocol.
- Eliminate the check which prohibits multiple iprop queries within a
limited time.
- Enforce only one slave can receive a full resync at a time.
This is to ensure a production environment will not have multiple
slaves out of commission concurrently.
Note: Tree replication will propagate faster as the limit is
enforced only at the each node level.
- If ulog is empty, iprop will return UPDATE_BUSY rather than go into an
endless cycle of UPDATE_FULL_RESYNC_NEEDED.


diff -ru src.orig/include/kdb_log.h src/include/kdb_log.h
--- src.orig/include/kdb_log.h 2010-07-06 17:53:23.000000000 -0400
+++ src/include/kdb_log.h 2012-05-17 12:52:54.000000000 -0400
@@ -71,6 +71,7 @@
const char *logname, uint32_t entries,
int caller,
char **db_args);
+extern krb5_error_code ulog_init_header(krb5_context context);
extern krb5_error_code ulog_add_update(krb5_context context,
kdb_incr_update_t *upd);
extern krb5_error_code ulog_delete_update(krb5_context context,
diff -ru src.orig/kadmin/server/ipropd_svc.c src/kadmin/server/ipropd_svc.c
--- src.orig/kadmin/server/ipropd_svc.c 2011-11-07 17:35:48.000000000 -0500
+++ src/kadmin/server/ipropd_svc.c 2012-05-17 15:35:44.000000000 -0400
@@ -37,6 +37,8 @@
extern short l_port;
static char abuf[33];

+static int kdb_fullresync_in_progress = 0;
+
/* Result is stored in a static buffer and is invalidated by the next call.
*/
static const char *client_addr(struct svc_req *svc) {
strlcpy(abuf, inet_ntoa(svc->rq_xprt->xp_raddr.sin_addr),
sizeof(abuf));
@@ -187,6 +189,15 @@

kret = ulog_get_entries(handle->context, *arg, &ret);

+ /*
+ * Only permit one full resync at a time.
+ * First, we do not want to disrupt the functionality of multiple
slaves.
+ * Second, static variables are used within the full resync function
+ * which limits concurrency.
+ */
+ if ((ret.ret == UPDATE_FULL_RESYNC_NEEDED) &&
kdb_fullresync_in_progress)
+ ret.ret = UPDATE_BUSY;
+
if (ret.ret == UPDATE_OK) {
(void) snprintf(obuf, sizeof (obuf),
_("%s; Incoming SerialNo=%lu; Outgoing
SerialNo=%lu"),
@@ -270,6 +281,11 @@
krb5_klog_syslog(LOG_ERR,
_("%s: server handle is NULL"),
whoami);
+ return (&ret);
+ }
+
+ if (kdb_fullresync_in_progress++) {
+ ret.ret = UPDATE_BUSY;
goto out;
}

@@ -421,14 +437,22 @@
}

out:
+ /* Even if we were busy, we inrecemented first; it is safe to decrement
*/
+ if (kdb_fullresync_in_progress)
+ kdb_fullresync_in_progress--;
+
if (nofork)
debprret(whoami, ret.ret, 0);
- free(client_name);
- free(service_name);
+ if (client_name)
+ free(client_name);
+ if (service_name)
+ free(service_name);
if (name)
gss_release_name(&min_stat, &name);
- free(tmpf);
- free(ubuf);
+ if (tmpf)
+ free(tmpf);
+ if (ubuf)
+ free(ubuf);
return (&ret);
}

diff -ru src.orig/kadmin/server/ovsec_kadmd.c
src/kadmin/server/ovsec_kadmd.c
--- src.orig/kadmin/server/ovsec_kadmd.c 2011-09-21
12:29:00.000000000 -0400
+++ src/kadmin/server/ovsec_kadmd.c 2012-05-15 15:21:29.000000000 -0400
@@ -110,6 +110,7 @@
fprintf(stderr, _("Usage: kadmind [-x db_args]* [-r realm] [-m]
[-nofork] "
"[-port port-number]\n"
"\t\t[-P pid_file]\n"
+ "\t\t[-proponly]\n"
"\nwhere,\n\t[-x db_args]* - any number of database "
"specific arguments.\n"
"\t\t\tLook at each database documentation for "
@@ -204,6 +205,7 @@
static krb5_context hctx;

int nofork = 0;
+int prop_only = 0;

int main(int argc, char *argv[])
{
@@ -287,6 +289,8 @@
} else if (strcmp(*argv, "-passwordserver") == 0) {
kadm5_set_use_password_server ();
#endif
+ } else if (strcmp(*argv, "-proponly") == 0) {
+ prop_only = 1;
} else if(strcmp(*argv, "-port") == 0) {
argc--; argv++;
if(!argc)
@@ -382,10 +386,15 @@
}

#define server_handle ((kadm5_server_handle_t)global_server_handle)
- if ((ret = loop_add_udp_port(server_handle->params.kpasswd_port))
+ if (prop_only
+ || (ret = loop_add_udp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_tcp_port(server_handle->params.kpasswd_port))
|| (ret = loop_add_rpc_service(server_handle->params.kadmind_port,
KADM, KADMVERS, kadm_1))
+ )
+ /* Do nothing; our error handling will follow */
+ 1;
+ if (ret
#ifndef DISABLE_IPROP
|| (server_handle->params.iprop_enabled
? (ret = loop_add_rpc_service(server_handle->params.iprop_port,
diff -ru src.orig/lib/kdb/kdb5.c src/lib/kdb/kdb5.c
--- src.orig/lib/kdb/kdb5.c 2011-10-04 16:16:07.000000000 -0400
+++ src/lib/kdb/kdb5.c 2012-05-17 12:51:57.000000000 -0400
@@ -41,6 +41,7 @@
#include <string.h>
#include <k5-int.h>
#include <osconf.h>
+#include <sys/mman.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -2254,15 +2255,30 @@
krb5_error_code
krb5_db_create_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->create_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->create_policy(kcontext, policy);
+ status = v->create_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2282,15 +2298,31 @@
krb5_error_code
krb5_db_put_policy(krb5_context kcontext, osa_policy_ent_t policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->put_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->put_policy(kcontext, policy);
+ status = v->put_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

krb5_error_code
@@ -2311,15 +2343,31 @@
krb5_error_code
krb5_db_delete_policy(krb5_context kcontext, char *policy)
{
+ kdb_log_context *log_ctx = kcontext->kdblog_context;
krb5_error_code status = 0;
kdb_vftabl *v;

status = get_vftabl(kcontext, &v);
if (status)
return status;
+
+ status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+ if (status)
+ return status;
+
+ /* Because iprop does not support policy changes; force full-resync */
+ if (log_ctx && (log_ctx->iproprole == IPROP_MASTER)) {
+ kdb_hlog_t *ulog = NULL;
+ if ((ulog = log_ctx->ulog))
+ (void) ulog_init_header(kcontext);
+ }
+
if (v->delete_policy == NULL)
return KRB5_PLUGIN_OP_NOTSUPP;
- return v->delete_policy(kcontext, policy);
+ status = v->delete_policy(kcontext, policy);
+
+ ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+ return status;
}

void
diff -ru src.orig/lib/kdb/kdb_log.c src/lib/kdb/kdb_log.c
--- src.orig/lib/kdb/kdb_log.c 2011-06-10 14:17:37.000000000 -0400
+++ src/lib/kdb/kdb_log.c 2012-05-17 16:09:06.000000000 -0400
@@ -15,6 +15,7 @@
#include <stdlib.h>
#include <limits.h>
#include <syslog.h>
+#include <errno.h>
#include "kdb5.h"
#include "kdb_log.h"
#include "kdb5int.h"
@@ -413,6 +414,64 @@
goto cleanup;
}

+ // XXX XXX
+ if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
+ uint32_t ulogentries = log_ctx->ulogentries;
+ int ulogfd = log_ctx->ulogfd;
+ uint_t indx = (upd->kdb_entry_sno - 1) % ulogentries;
+ ulong_t upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t,
upd);
+ uint_t recsize = sizeof (kdb_ent_header_t) + upd_size;
+ kdb_ent_header_t *indx_log;
+ XDR xdrs;
+
+ if (recsize > ulog->kdb_block) {
+ if ((retval = ulog_resize(ulog, ulogentries, ulogfd,
recsize)))
+ goto cleanup;
+ ulog->kdb_first_sno = 0;
+ }
+
+ ulog->kdb_state = KDB_UNSTABLE;
+
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ (void) memset(indx_log, 0, ulog->kdb_block);
+
+ indx_log->kdb_umagic = KDB_ULOG_MAGIC;
+ indx_log->kdb_entry_size = upd_size;
+ indx_log->kdb_entry_sno = upd->kdb_entry_sno;
+ indx_log->kdb_time = upd->kdb_time;
+ indx_log->kdb_commit = TRUE;
+
+ xdrmem_create(&xdrs, (char *)indx_log->entry_data,
+ indx_log->kdb_entry_size, XDR_ENCODE);
+ if (!xdr_kdb_incr_update_t(&xdrs, upd)) {
+ retval = KRB5_LOG_CONV;
+ goto cleanup;
+ }
+
+ if (ulog->kdb_num < ulogentries)
+ ulog->kdb_num++;
+
+ ulog->kdb_last_sno = upd->kdb_entry_sno;
+ ulog->kdb_last_time = upd->kdb_time;
+
+ if (! ulog->kdb_first_sno) {
+ ulog->kdb_first_sno = upd->kdb_entry_sno;
+ ulog->kdb_first_time = upd->kdb_time;
+ }
+ if (ulog->kdb_last_sno - ulog->kdb_first_sno >= ulogentries) {
+ indx = upd->kdb_entry_sno % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+ ulog->kdb_first_sno = indx_log->kdb_entry_sno;
+ ulog->kdb_first_time = indx_log->kdb_time;
+ }
+
+ retval = ulog_finish_update(context, upd);
+ //retval = ulog_sync_update(ulog, indx_log);
+ if (retval)
+ goto cleanup;
+ }
+ // XXX XXX
+
upd++;
}

@@ -441,17 +500,34 @@
{
XDR xdrs;
krb5_error_code retval = 0;
- unsigned int i;
+ unsigned int i, ulogentries;
kdb_ent_header_t *indx_log;
kdb_incr_update_t *upd = NULL;
kdb_incr_result_t *incr_ret = NULL;

ulog->kdb_state = KDB_STABLE;

- for (i = 0; i < ulog->kdb_num; i++) {
- indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
+ if (ulog->kdb_num == 0)
+ goto error; /* Nothing to check; return OK */

- if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) {
+ ulogentries = context->kdblog_context->ulogentries;
+
+ if ((ulogentries <= 0)
+ || (ulog->kdb_first_sno <= 0) || (ulog->kdb_last_sno <= 0)
+ || (ulog->kdb_num > ulogentries)
+ || (ulog->kdb_last_sno - ulog->kdb_first_sno + 1 != ulog->kdb_num))
+ {
+ ulog->kdb_state = KDB_CORRUPT;
+ retval = KRB5_LOG_CORRUPT;
+ goto error;
+ }
+
+ for (i = ulog->kdb_first_sno; i <= ulog->kdb_last_sno; i++) {
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, ((i - 1) %
ulogentries));
+
+ if ((indx_log->kdb_umagic != KDB_ULOG_MAGIC)
+ || (indx_log->kdb_entry_sno != i))
+ {
/*
* Update entry corrupted we should scream and die
*/
@@ -529,7 +605,8 @@
if (upd)
ulog_free_entries(upd, 1);

- free(incr_ret);
+ if (incr_ret)
+ free(incr_ret);

ulog_sync_header(ulog);

@@ -574,7 +651,7 @@
return (errno);
}

- if ((caller == FKADMIND) || (caller == FKCOMMAND))
+ if ((caller == FKADMIND) || (caller == FKPROPD) || (caller ==
FKCOMMAND))
ulog_filesize += ulogentries * ULOG_BLOCK;

if (extend_file_to(ulogfd, ulog_filesize) < 0)
@@ -643,7 +720,7 @@
}
}

- if (caller == FKADMIND) {
+ if ((caller == FKADMIND) || (caller == FKPROPD)) {
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
@@ -683,11 +760,25 @@
retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
if (retval)
return retval;
- if (ulog->kdb_num != ulogentries) {
- if ((ulog->kdb_num != 0) &&
- ((ulog->kdb_last_sno > ulog->kdb_num) ||
- (ulog->kdb_num > ulogentries))) {

+ if (ulog->kdb_num > ulogentries) {
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+ }
+ if (ulog->kdb_num && (ulog->kdb_num != ulogentries)) {
+ uint_t indx;
+ kdb_ent_header_t *indx_log;
+
+ indx = (ulog->kdb_last_sno - 1) % ulogentries;
+ indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+
+ if (indx_log->kdb_entry_sno != ulog->kdb_last_sno) {
(void) memset(ulog, 0, sizeof (kdb_hlog_t));

ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
@@ -697,25 +788,57 @@

ulog_sync_header(ulog);
}
+ }

- /*
- * Expand ulog if we have specified a greater size
- */
- if (ulog->kdb_num < ulogentries) {
- ulog_filesize += ulogentries * ulog->kdb_block;
+ /*
+ * Expand ulog if we have specified a greater size
+ */
+ if (ulog->kdb_num < ulogentries) {
+ ulog_filesize += ulogentries * ulog->kdb_block;

- if (extend_file_to(ulogfd, ulog_filesize) < 0) {
- ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
- return errno;
- }
+ if (extend_file_to(ulogfd, ulog_filesize) < 0) {
+ ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return errno;
}
}
+
ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

return (0);
}

/*
+ *
+ */
+krb5_error_code
+ulog_init_header(krb5_context context)
+{
+ kdb_log_context *log_ctx;
+ kdb_hlog_t *ulog = NULL;
+ krb5_error_code retval;
+
+
+ INIT_ULOG(context);
+
+ /* The caller should already have a lock, but ensure it is "exclusive".
*/
+ if ((retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+ return retval;
+
+ (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+
+ ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+ ulog->db_version_num = KDB_VERSION;
+ ulog->kdb_state = KDB_STABLE;
+ ulog->kdb_block = ULOG_BLOCK;
+
+ ulog_sync_header(ulog);
+
+ /* The caller is responsible for unlocking... */
+ return (0);
+}
+
+
+/*
* Get the last set of updates seen, (last+1) to n is returned.
*/
krb5_error_code
@@ -737,7 +860,20 @@
INIT_ULOG(context);
ulogentries = log_ctx->ulogentries;

- retval = ulog_lock(context, KRB5_LOCKMODE_SHARED);
+ retval = ulog_lock(context, KRB5_LOCKMODE_SHARED |
KRB5_LOCKMODE_DONTBLOCK);
+ if (0
+#ifdef EWOULDBLOCK
+ || (retval == EWOULDBLOCK)
+#endif
+#ifdef EAGAIN
+ || (retval == EWOULDBLOCK)
+#endif
+ ) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }
+
if (retval)
return retval;

@@ -750,6 +886,9 @@
return (KRB5_LOG_CORRUPT);
}

+#if 0
+ /* This code block causes deadlock issues with lots of slaves. */
+
gettimeofday(&timestamp, NULL);

tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
@@ -758,6 +897,18 @@
(void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
return (0);
}
+#endif
+
+ /*
+ * Special case - no log entries. The first sync should be a full
+ * resync since we can't compare timestamps, but we don't want to
+ * loop doing full resyncs until there is a log update.
+ */
+ if (last.last_sno && (ulog->kdb_num == 0)) {
+ ulog_handle->ret = UPDATE_BUSY;
+ (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+ return (0);
+ }

/*
* We need to lock out other processes here, such as kadmin.local,
Only in src/lib/kdb: kdb_log.c.~1~
Only in src/plugins/kdb/ldap/ldap_util: RCS
diff -ru src.orig/slave/kpropd.c src/slave/kpropd.c
--- src.orig/slave/kpropd.c 2011-06-30 23:26:58.000000000 -0400
+++ src/slave/kpropd.c 2012-05-17 13:58:08.000000000 -0400
@@ -146,6 +146,7 @@
char *kdb5_util = KPROPD_DEFAULT_KDB5_UTIL;
char *kerb_database = NULL;
char *acl_file_name = KPROPD_ACL_FILE;
+char *admin_server = NULL;

krb5_address *sender_addr;
krb5_address *receiver_addr;
@@ -179,6 +180,7 @@
progname);
fprintf(stderr, _("\t[-F kerberos_db_file ] [-p
kdb5_util_pathname]\n"));
fprintf(stderr, _("\t[-x db_args]* [-P port] [-a acl_file]\n"));
+ fprintf(stderr, _("\t[-A admin_server]\n"));
exit(1);
}

@@ -1046,6 +1048,15 @@
word++;
while (word && (ch = *word++)) {
switch(ch){
+ case 'A':
+ if (*word)
+ admin_server = word;
+ else
+ admin_server = *argv++;
+ if (!admin_server)
+ usage();
+ word = 0;
+ break;
case 'f':
if (*word)
file = word;
@@ -1193,6 +1204,11 @@
com_err(progname, retval, _("while initializing"));
exit(1);
}
+ if (admin_server) {
+ char *x = params.admin_server;
+ params.admin_server = admin_server;
+ admin_server = x;
+ }
if (params.iprop_enabled == TRUE) {
ulog_set_role(kpropd_context, IPROP_SLAVE);

diff -ru src.orig/slave/kproplog.c src/slave/kproplog.c
--- src.orig/slave/kproplog.c 2011-06-10 14:17:59.000000000 -0400
+++ src/slave/kproplog.c 2012-05-16 20:09:24.000000000 -0400
@@ -399,11 +399,13 @@
* Print the update entry information
*/
static void
-print_update(kdb_hlog_t *ulog, uint32_t entry, unsigned int verbose)
+print_update(krb5_context kcontext, uint32_t entry, unsigned int verbose)
{
XDR xdrs;
uint32_t start_sno, i, j, indx;
char *dbprinc;
+ uint32_t ulogentries =
kcontext->kdblog_context->ulogentries;
+ kdb_hlog_t *ulog = kcontext->kdblog_context->ulog;
kdb_ent_header_t *indx_log;
kdb_incr_update_t upd;

@@ -413,7 +415,7 @@
start_sno = ulog->kdb_first_sno - 1;

for (i = start_sno; i < ulog->kdb_last_sno; i++) {
- indx = i % ulog->kdb_num;
+ indx = i % ulogentries;

indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);

@@ -538,7 +540,7 @@
(void) printf(_("\nKerberos update log (%s)\n"),
params.iprop_logfile);

- if (ulog_map(context, params.iprop_logfile, 0, FKPROPLOG, db_args)) {
+ if (ulog_map(context, params.iprop_logfile, params.iprop_ulogsize,
FKPROPLOG, db_args)) {
(void) fprintf(stderr, _("Unable to map log file %s\n\n"),
params.iprop_logfile);
exit(1);
@@ -609,7 +611,7 @@
}

if ((!headeronly) && ulog->kdb_num) {
- print_update(ulog, entry, verbose);
+ print_update(context, entry, verbose);
}

(void) printf("\n");