[krbdev.mit.edu #7157] krb5-1.10.1 iprop fixes

Richard Basch via RT rt-comment at krbdev.mit.edu
Fri Jun 1 18:44:03 EDT 2012


I have been trying to fix the iprop code in a significant way. it has a lot
of issues in a large environment with 30 or so slaves especially with short
polling intervals (Kerberos 1.4 with UMich krep code scaled better).

First and foremost, a tree distribution mechanism is required, i.e. the
master can sync a few systems which in turn can sync others.  This paradigm
will work better with WAN links, especially if you have an organization with
international WAN links.  Second, I removed some bad assumptions (e.g. the
log started with sno=1).  And third, I found a few conditions which iprop
does not handle, and even worse, can leave replicas in an inconsistent state
with respect to the master (e.g. policy changes).

Summary of changes (the patch is ~800 lines long):
-	Kadmind can be started with "-proponly" which will enable iprop
distribution services only (but leave other kadmin services inactive)
-	Policy adds/deletes/changes will re-initialize the ulog so slaves
will receive a consistent copy of the database with the updated policies.
(Full resync is delayed until the next non-policy change is registered in
the ulog.)
-	Fixed several sections of code to not assume the ulog starts with
sno=1 (particularly on downstream slaves); also fixed some edge conditions
to ensure consistency (i.e. ulogsize >= 2, or a math exception would
result).
-	When kpropd invokes ulog_replay() to process the upstream log
entries, it will also populate the local ulog with those same entries.
(Note: Full resync's do not transmit the master's ulog along with the dump.
This would be ideal, but may require a protocol change.)
-	Removed idle timer which was causing spurious UPDATE_BUSY messages
on busy masters with many slaves.
-	Changed ulog_get_entries so it does not wait for a ulog_lock (if it
cannot get a lock, it will return UPDATE_BUSY).
-	Added additional consistency checking of the ulog file to detect
possible corruption.
Changes were made to kpropd, kadmin, kproplog, and some library components
(though nothing which should affect any published API). There were a few
library functions which I had to promote from static visibility.  This
version remains protocol-compatible (adding policy entry encoding or
transmitting the ulog with a full resync would have broken such).

-----Original Message-----
From: Richard Basch [mailto:probe at mail.bright-prospects.com] 
Sent: Friday, June 01, 2012 6:19 PM
To: richard.basch at gs.com; basch at alum.mit.edu
Subject: krb5-1.10.1 20120601.181856

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-31 19:17:17.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, uint32_t
recsize);
 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/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-31 19:17:18.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-06-01 18:16:41.000000000 -0400
@@ -2254,15 +2254,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;
+
     if (v->create_policy == NULL)
         return KRB5_PLUGIN_OP_NOTSUPP;
-    return v->create_policy(kcontext, policy);
+    status = v->create_policy(kcontext, policy);
+
+    /* Because iprop does not support policy changes; force full-resync */
+    if (!status && log_ctx && log_ctx->iproprole == IPROP_MASTER) {
+        kdb_hlog_t *ulog = NULL;
+        if ((ulog = log_ctx->ulog))
+            (void) ulog_init_header(kcontext, 0);
+    }
+
+    ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+    return status;
 }
 
 krb5_error_code
@@ -2282,15 +2297,62 @@
 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;
+    osa_policy_ent_t old_policy = NULL;
 
     status = get_vftabl(kcontext, &v);
     if (status)
         return status;
+
+    status = ulog_lock(kcontext, KRB5_LOCKMODE_EXCLUSIVE);
+    if (status)
+        return status;
+
+    if (log_ctx && log_ctx->iproprole == IPROP_MASTER) {
+        if (v->get_policy)
+            v->get_policy(kcontext, policy->name, &old_policy);
+    }
+
     if (v->put_policy == NULL)
         return KRB5_PLUGIN_OP_NOTSUPP;
-    return v->put_policy(kcontext, policy);
+    status = v->put_policy(kcontext, policy);
+
+    /*
+     * Because iprop does not support policy changes; force full-resync.
+     * However, for policy changes, we need to first check if there were
+     * any "substantive" changes to avoid unnecessary resyncs.
+     */
+    if (!status && log_ctx && log_ctx->iproprole == IPROP_MASTER) {
+        if (old_policy == NULL ||
+            old_policy->version != policy->version ||
+            old_policy->pw_min_life != policy->pw_min_life ||
+            old_policy->pw_max_life != policy->pw_max_life ||
+            old_policy->pw_min_length != policy->pw_min_length ||
+            old_policy->pw_min_classes != policy->pw_min_classes ||
+            old_policy->pw_history_num != policy->pw_history_num) {
+            
+            kdb_hlog_t *ulog;
+            
+            if ((ulog = log_ctx->ulog))
+                (void) ulog_init_header(kcontext, 0);
+        } else if (old_policy->version > 1 && policy->version > 1 &&
+                   !(old_policy->pw_max_fail == policy->pw_max_fail &&
+                     old_policy->pw_failcnt_interval ==
policy->pw_failcnt_interval &&
+                     old_policy->pw_lockout_duration ==
policy->pw_lockout_duration)) {
+
+            kdb_hlog_t *ulog;
+            
+            if ((ulog = log_ctx->ulog))
+                (void) ulog_init_header(kcontext, 0);
+        }
+        if (old_policy)
+            krb5_db_free_policy(kcontext, old_policy);
+    }
+
+    ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+    return status;
 }
 
 krb5_error_code
@@ -2311,15 +2373,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;
+
     if (v->delete_policy == NULL)
         return KRB5_PLUGIN_OP_NOTSUPP;
-    return v->delete_policy(kcontext, policy);
+    status = v->delete_policy(kcontext, policy);
+
+    /* Because iprop does not support policy changes; force full-resync */
+    if (!status && log_ctx && log_ctx->iproprole == IPROP_MASTER) {
+        kdb_hlog_t *ulog = NULL;
+        if ((ulog = log_ctx->ulog))
+            (void) ulog_init_header(kcontext, 0);
+    }
+
+    ulog_lock(kcontext, KRB5_LOCKMODE_UNLOCK);
+    return status;
 }
 
 void
Only in src/lib/kdb: kdb5.c.~1~
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-31 23:14:19.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"
@@ -121,8 +122,8 @@
 
     new_size = sizeof (kdb_hlog_t);
 
-    new_block = (recsize / ULOG_BLOCK) + 1;
-    new_block *= ULOG_BLOCK;
+    new_block = (recsize + ULOG_BLOCK - 1) / ULOG_BLOCK;
+    new_block *= ULOG_BLOCK; /* Should this be min(ULOG_BLOCK, pagesize)?
*/
 
     new_size += ulogentries * new_block;
 
@@ -169,7 +170,7 @@
     kdb_ent_header_t *indx_log;
     uint_t              i, recsize;
     ulong_t             upd_size;
-    krb5_error_code     retval;
+    krb5_error_code     retval = 0;
     kdb_sno_t   cur_sno;
     kdb_log_context     *log_ctx;
     kdb_hlog_t  *ulog = NULL;
@@ -204,9 +205,10 @@
      * We need to overflow our sno, replicas will do full
      * resyncs once they see their sno > than the masters.
      */
-    if (cur_sno == ULONG_MAX)
+    if (cur_sno >= ULONG_MAX || cur_sno <= 0) {
         cur_sno = 1;
-    else
+        ulog->kdb_num = 0;
+    } else
         cur_sno++;
 
     /*
@@ -236,29 +238,36 @@
     if ((retval = ulog_sync_update(ulog, indx_log)))
         return (retval);
 
-    if (ulog->kdb_num < ulogentries)
-        ulog->kdb_num++;
-
     ulog->kdb_last_sno = cur_sno;
     ulog->kdb_last_time = ktime;
 
-    /*
-     * Since this is a circular array, once we circled, kdb_first_sno is
-     * always kdb_entry_sno + 1.
-     */
-    if (cur_sno > ulogentries) {
-        i = upd->kdb_entry_sno % ulogentries;
+    if (ulog->kdb_num < ulogentries)
+        ulog->kdb_num++;
+    else if (ulog->kdb_num == ulogentries) {
+        i = cur_sno % ulogentries;
         indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
         ulog->kdb_first_sno = indx_log->kdb_entry_sno;
         ulog->kdb_first_time = indx_log->kdb_time;
-    } else if (cur_sno == 1) {
-        ulog->kdb_first_sno = 1;
-        ulog->kdb_first_time = indx_log->kdb_time;
     }
 
-    ulog_sync_header(ulog);
+    if (cur_sno == 1 || ulog->kdb_num == 1) {
+        ulog->kdb_first_sno = cur_sno;
+        ulog->kdb_first_time = ktime;
+        ulog->kdb_num = 1;
+    }
+    
+    /*
+     * Integrity check: last - first + 1 = kdb_num
+     */
+    if (ulog->kdb_last_sno - ulog->kdb_first_sno + 1 != ulog->kdb_num ||
+        ulog->kdb_num > ulogentries) {
+        ulog->kdb_state = KDB_CORRUPT;
+        ulog_sync_header(ulog);
+        return (KRB5_LOG_CORRUPT);
+    }
 
-    return (0);
+    retval = ulog_finish_update(context, upd);
+    return (retval);
 }
 
 /*
@@ -295,19 +304,6 @@
 }
 
 /*
- * Set the header log details on the slave and sync it to file.
- */
-static void
-ulog_finish_update_slave(kdb_hlog_t *ulog, kdb_last_t lastentry)
-{
-
-    ulog->kdb_last_sno = lastentry.last_sno;
-    ulog->kdb_last_time = lastentry.last_time;
-
-    ulog_sync_header(ulog);
-}
-
-/*
  * Delete an entry to the update log.
  */
 krb5_error_code
@@ -333,25 +329,21 @@
     int                 i, no_of_updates;
     krb5_error_code     retval;
     krb5_principal      dbprinc = NULL;
-    kdb_last_t          errlast;
     char                *dbprincstr = NULL;
     kdb_log_context     *log_ctx;
     kdb_hlog_t          *ulog = NULL;
 
     INIT_ULOG(context);
+    
+    if (log_ctx && log_ctx->iproprole == IPROP_SLAVE) {
+        if ((retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE)))
+            return (retval);
+    }
 
     no_of_updates = incr_ret->updates.kdb_ulog_t_len;
     upd = incr_ret->updates.kdb_ulog_t_val;
     fupd = upd;
 
-    /*
-     * We reset last_sno and last_time to 0, if krb5_db2_db_put_principal
-     * or krb5_db2_db_delete_principal fail.
-     */
-    errlast.last_sno = (unsigned int)0;
-    errlast.last_time.seconds = (unsigned int)0;
-    errlast.last_time.useconds = (unsigned int)0;
-
     if ((retval = krb5_db_open(context, db_args,
                                KRB5_KDB_OPEN_RW|KRB5_KDB_SRV_TYPE_ADMIN)))
         goto cleanup;
@@ -413,6 +405,82 @@
                 goto cleanup;
         }
 
+        if (log_ctx && log_ctx->iproprole == IPROP_SLAVE &&
+            upd->kdb_entry_sno >= 1 &&
+            ulog->kdb_hmagic == KDB_ULOG_HDR_MAGIC &&
+            ulog->kdb_state == KDB_STABLE) {
+
+            uint32_t		ulogentries, indx, upd_size, recsize;
+            int			ulogfd;
+            kdb_ent_header_t	*indx_log;
+            XDR			xdrs;
+
+            ulogfd = log_ctx->ulogfd;
+            
+            ulogentries = log_ctx->ulogentries;
+            indx = (upd->kdb_entry_sno - 1) % ulogentries;
+
+            upd_size = xdr_sizeof((xdrproc_t)xdr_kdb_incr_update_t, upd);
+            recsize = sizeof(kdb_ent_header_t) + upd_size;
+
+            if (recsize > ulog->kdb_block) {
+                if ((retval = ulog_resize(ulog, ulogentries, ulogfd,
recsize)))
+                    goto cleanup;
+                ulog_sync_header(ulog);
+            }
+
+            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 ((retval = ulog_sync_update(ulog, indx_log)))
+                goto cleanup;
+
+            ulog->kdb_last_sno = upd->kdb_entry_sno;
+            ulog->kdb_last_time = upd->kdb_time;
+
+            if (ulog->kdb_num < 0 || ulog->kdb_num > ulogentries) {
+                ulog->kdb_state = KDB_CORRUPT;
+                retval = KRB5_LOG_CORRUPT;
+                goto cleanup;
+            }
+
+            if (!ulog->kdb_num) {
+                ulog->kdb_first_sno = upd->kdb_entry_sno;
+                ulog->kdb_first_time = upd->kdb_time;
+            }
+            if (ulog->kdb_num < ulogentries)
+                ulog->kdb_num++;
+            else {
+                /* Retrieve new first entry */
+                ulog->kdb_first_sno++;
+                indx = (ulog->kdb_first_sno - 1) % ulogentries;
+                indx_log = (kdb_ent_header_t *)INDEX(ulog, indx);
+
+                if (indx_log->kdb_umagic == KDB_ULOG_MAGIC &&
+                    indx_log->kdb_entry_sno == ulog->kdb_first_sno) {
+                    ulog->kdb_first_time = indx_log->kdb_time;
+                } else {
+                    ulog->kdb_state = KDB_CORRUPT;
+                    retval = KRB5_LOG_CORRUPT;
+                    goto cleanup;
+                }
+            }
+        }
+        
         upd++;
     }
 
@@ -420,11 +488,9 @@
     if (fupd)
         ulog_free_entries(fupd, no_of_updates);
 
-    if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
-        if (retval)
-            ulog_finish_update_slave(ulog, errlast);
-        else
-            ulog_finish_update_slave(ulog, incr_ret->lastentry);
+if (log_ctx && (log_ctx->iproprole == IPROP_SLAVE)) {
+        (void) ulog_sync_header(ulog);
+        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
     }
 
     return (retval);
@@ -441,15 +507,18 @@
 {
     XDR                 xdrs;
     krb5_error_code     retval = 0;
-    unsigned int        i;
+    unsigned int        i, j, 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;
 
+    ulogentries = context->kdblog_context->ulogentries;
+
     for (i = 0; i < ulog->kdb_num; i++) {
-        indx_log = (kdb_ent_header_t *)INDEX(ulog, i);
+        j = (ulog->kdb_first_sno + i - 1) % ulogentries;
+        indx_log = (kdb_ent_header_t *)INDEX(ulog, j);
 
         if (indx_log->kdb_umagic != KDB_ULOG_MAGIC) {
             /*
@@ -502,10 +571,9 @@
              * the pointer in case we subsequently break from loop.
              */
             upd = NULL;
-            if (incr_ret) {
-                free(incr_ret);
-                incr_ret = NULL;
-            }
+            free(incr_ret);
+            incr_ret = NULL;
+
             ulog_set_role(context, IPROP_MASTER);
 
             if (retval)
@@ -574,8 +642,13 @@
             return (errno);
         }
 
-        if ((caller == FKADMIND) || (caller == FKCOMMAND))
+        if (caller == FKADMIND || caller == FKCOMMAND || caller == FKPROPD)
{
+            
+            if (ulogentries < 2)                /* Min log entries = 2 */
+                return (EINVAL);
+            
             ulog_filesize += ulogentries * ULOG_BLOCK;
+        }
 
         if (extend_file_to(ulogfd, ulog_filesize) < 0)
             return errno;
@@ -607,9 +680,6 @@
     }
 
     if (ulog == MAP_FAILED) {
-        /*
-         * Can't map update log file to memory
-         */
         close(ulogfd);
         return (errno);
     }
@@ -626,24 +696,15 @@
     log_ctx->ulogfd = ulogfd;
 
     if (ulog->kdb_hmagic != KDB_ULOG_HDR_MAGIC) {
-        if (ulog->kdb_hmagic == 0) {
-            /*
-             * New update log
-             */
-            (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;
-            if (!(caller == FKPROPLOG))
-                ulog_sync_header(ulog);
+        if (ulog->kdb_hmagic == 0 && caller != FKPROPLOG) {
+            /* New update log */
+            ulog_init_header(context, ULOG_BLOCK);
         } else {
             return (KRB5_LOG_CORRUPT);
         }
     }
 
-    if (caller == FKADMIND) {
+    if (caller == FKADMIND || caller == FKPROPD) {
         retval = ulog_lock(context, KRB5_LOCKMODE_EXCLUSIVE);
         if (retval)
             return retval;
@@ -669,10 +730,8 @@
             ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
             return (KRB5_LOG_ERROR);
         }
-    } else if ((caller == FKPROPLOG) || (caller == FKPROPD)) {
-        /*
-         * kproplog and kpropd don't need to do anything else
-         */
+    } else if (caller == FKPROPLOG) {
+        /* don't need to do anything else */
         return (0);
     }
 
@@ -683,38 +742,66 @@
     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 ||
+        ulog->kdb_last_sno - ulog->kdb_first_sno + 1 != ulog->kdb_num)
+        ulog_init_header(context, ULOG_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;
+        }
+    }
 
-            (void) memset(ulog, 0, sizeof (kdb_hlog_t));
+    ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
 
-            ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
-            ulog->db_version_num = KDB_VERSION;
-            ulog->kdb_state = KDB_STABLE;
-            ulog->kdb_block = ULOG_BLOCK;
+    return (0);
+}
 
-            ulog_sync_header(ulog);
-        }
 
-        /*
-         * Expand ulog if we have specified a greater size
-         */
-        if (ulog->kdb_num < ulogentries) {
-            ulog_filesize += ulogentries * ulog->kdb_block;
+/*
+ * Re-init the log header.
+ */
+krb5_error_code
+ulog_init_header(krb5_context context, uint32_t recsize)
+{
+    kdb_log_context     *log_ctx;
+    kdb_hlog_t          *ulog = NULL;
+    krb5_error_code     retval;
+    uint_t              block_min;
+    
+    
+    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));
 
-            if (extend_file_to(ulogfd, ulog_filesize) < 0) {
-                ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
-                return errno;
-            }
-        }
-    }
-    ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+    ulog->kdb_hmagic = KDB_ULOG_HDR_MAGIC;
+    ulog->db_version_num = KDB_VERSION;
+    ulog->kdb_state = KDB_STABLE;
+
+    block_min = ULOG_BLOCK;  /* Should this be min(ULOG_BLOCK, pagesize)?
*/
+    if (recsize > block_min)
+        ulog->kdb_block = ((recsize + block_min - 1) & (~(block_min-1)));
+    else
+        ulog->kdb_block = block_min;
 
+    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.
  */
@@ -726,10 +813,13 @@
     XDR                 xdrs;
     kdb_ent_header_t    *indx_log;
     kdb_incr_update_t   *upd;
-    uint_t              indx, count, tdiff;
+    uint_t              indx, count;
     uint32_t            sno;
     krb5_error_code     retval;
+#if 0
+    uint_t              tdiff;
     struct timeval      timestamp;
+#endif
     kdb_log_context     *log_ctx;
     kdb_hlog_t          *ulog = NULL;
     uint32_t            ulogentries;
@@ -737,7 +827,18 @@
     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 == EAGAIN
+#endif
+        ) {
+        ulog_handle->ret = UPDATE_BUSY;
+        return (0);
+    }
     if (retval)
         return retval;
 
@@ -750,6 +851,11 @@
         return (KRB5_LOG_CORRUPT);
     }
 
+#if 0
+    /*
+     * This code block causes slaves to deadlock in large environments.
+     */
+    
     gettimeofday(&timestamp, NULL);
 
     tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;
@@ -758,8 +864,28 @@
         (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
         return (0);
     }
+#endif
 
     /*
+     * Special case - no log entries. XXX
+     * A full resync will be required because there is no log timestamp to
+     * match the client state. However, we want to defer a resync with a
+     * client which already has a database since we will otherwise be
+     * looping doing a full resync until the log has at least one entry.
+     * If the master has sno = 0, we have to defer to avoid looping.
+     */
+    if (ulog->kdb_num == 0) {
+        if (last.last_sno || ulog->kdb_last_sno == 0)
+            ulog_handle->ret = UPDATE_BUSY;
+        else {
+            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;
+            ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;
+        }
+        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);
+        return (0);
+    }
+    
+    /*
      * We need to lock out other processes here, such as kadmin.local,
      * since we are looking at the last_sno and looking up updates.  So
      * we can share with other readers.
Only in src/lib/kdb: kdb_log.c.~1~
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-31 19:17:18.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-31 19:17:18.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