[krbdev.mit.edu #7141] Kerberos 1.10.1 - iprop issues
Richard Basch via RT
rt-comment at krbdev.mit.edu
Thu May 17 19:43:40 EDT 2012
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(×tamp, 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");
More information about the krb5-bugs
mailing list