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

Richard Basch via RT rt-comment at krbdev.mit.edu
Sun Jun 3 15:34:41 EDT 2012


Resending and in-lining the code (vs. attaching the patch file) since it is
not clear if attachments are accepted.

 

The main difference since my last patch is the ability for an intermediate
slave in the hierarchy to respond to lower leaf nodes immediately after it
has itself performed a full resync and prior to accumulating any entries in
its ulog (obviously, any nodes it services will perform a full resync).

 

Summary of changes

==================

* Kadmind can be started with "-proponly" to enable iprop distribution
services only (without other kadmin services). Kpropd can be started with
"-A server" to specify an alternate admin_server with which to communicate
for iprop services.

* Policy adds/deletes/changes will re-initialize the ulog so slaves will
initiate a resync and receive a consistent copy of the database with the
updated policies. The full resync occurs after the next non-policy change.

* When kpropd invokes ulog_replay() to process the upstream log entries, it
will also populate the local ulog.

* Changed ulog_get_entries so it does not wait for a ulog_lock (if it cannot
get a lock, it will return UPDATE_BUSY). Removed the idle timer check which
caused spurious UPDATE_BUSY messages on busy masters with many slaves
(slaves could deadlock for extended periods of time without receiving
updates).

* Added consistency checking of the ulog file to detect possible corruption.

 

No protocol or API changes were introduced, though I did have to remove the
"static" keyword of some functions to allow them to be used by other library
functions in different source files. New command-line arguments were
introduced in kpropd & kadmind to support tree replication. No functional
changes were made to kproplog, though some ulog parsing functions did
require some minor logic revision.

 

 

 

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-06-03 02:16:28.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,11 @@

      * 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 ||

+        ulog->kdb_num > ulogentries) {

         cur_sno = 1;

-    else

+        ulog->kdb_num = 0;

+    } else

         cur_sno++;

     /*

@@ -215,9 +218,7 @@

     upd->kdb_entry_sno = cur_sno;

     i = (cur_sno - 1) % ulogentries;

-

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

-

     (void) memset(indx_log, 0, ulog->kdb_block);

     indx_log->kdb_umagic = KDB_ULOG_MAGIC;

@@ -227,6 +228,7 @@

     indx_log->kdb_commit = upd->kdb_commit = FALSE;

     ulog->kdb_state = KDB_UNSTABLE;

+    ulog_sync_header(ulog);

     xdrmem_create(&xdrs, (char *)indx_log->entry_data,

                   indx_log->kdb_entry_size, XDR_ENCODE);

@@ -236,29 +238,29 @@

     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 {

+        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);

-

-    return (0);

+    /*

+     * Make sure the first entry is populated in the ulog.

+     */

+    if (cur_sno == 1 || ulog->kdb_first_sno == 0) {

+        ulog->kdb_first_sno = cur_sno;

+        ulog->kdb_first_time = ktime;

+        ulog->kdb_num = 1;

+    }

+    

+    retval = ulog_finish_update(context, upd);

+    return (retval);

}

 /*

@@ -295,19 +297,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 +322,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 +398,91 @@

                 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;

+            }

+

+            /*

+             * Allow the first entry to not reside in the ulog.

+             * As the first update is received, populate the first entry

+             * with the last serial info received from the full resync.

+             */

+            if (ulog->kdb_first_sno == 0 && ulog->kdb_num == 0) {

+                ulog->kdb_first_sno = ulog->kdb_last_sno;

+                ulog->kdb_first_time = ulog->kdb_last_time;

+            }

+            

+            if (ulog->kdb_num < ulogentries)

+                ulog->kdb_num++;

+            else {

+                /*

+                 * Because the first_sno may or may not have been in the
ulog,

+                 * we have to calculate the value when the ulog is full.

+                 */

+                ulog->kdb_first_sno = ulog->kdb_last_sno - ulogentries + 1;

+                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 +490,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 +509,37 @@

{

     XDR                 xdrs;

     krb5_error_code     retval = 0;

-    unsigned int        i;

+    unsigned int        i, j, ulogentries, start_sno;

     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;

+

+    /*

+     * Edge condition/optimization.

+     * Reset ulog->kdb_first_* to equal the last entry if the log is empty.

+     */

+    if (ulog->kdb_num == 0 && ulog->kdb_first_sno == 0 &&

+        ulog->kdb_last_sno > 0) {

+        

+        ulog->kdb_first_sno = ulog->kdb_last_sno;

+        ulog->kdb_first_time = ulog->kdb_last_time;

+    }

+    

+    start_sno = ulog->kdb_first_sno;

+    /*

+     * kdb_first_sno might not be in the ulog if we were previously a
slave.

+     * However, the next entry should be.

+     */

+    if (ulog->kdb_num && ulog->kdb_last_sno - start_sno + 1 !=
ulog->kdb_num)

+        start_sno++;

+    

     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 +592,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 +663,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 +701,6 @@

     }

     if (ulog == MAP_FAILED) {

-        /*

-         * Can't map update log file to memory

-         */

         close(ulogfd);

         return (errno);

     }

@@ -626,24 +717,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 +751,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 +763,65 @@

     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_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 +833,9 @@

     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;

-    struct timeval      timestamp;

     kdb_log_context     *log_ctx;

     kdb_hlog_t          *ulog = NULL;

     uint32_t            ulogentries;

@@ -737,7 +843,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,15 +867,43 @@

         return (KRB5_LOG_CORRUPT);

     }

-    gettimeofday(&timestamp, NULL);

+#if 0

+    /*

+     * This code block causes slaves to deadlock in large environments.

+     */

+    {

+        uint_t              tdiff;

+        struct timeval      timestamp;

+        

+        gettimeofday(&timestamp, NULL);

+        

+        tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;

+        if (tdiff <= ULOG_IDLE_TIME) {

+            ulog_handle->ret = UPDATE_BUSY;

+            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+            return (0);

+        }

+    }

+#endif

-    tdiff = timestamp.tv_sec - ulog->kdb_last_time.seconds;

-    if (tdiff <= ULOG_IDLE_TIME) {

+    /*

+     * Defer a full resync when no log history is present to avoid looping.

+     *

+     */

+    if (ulog->kdb_num == 0 && ulog->kdb_last_sno == 0) {

         ulog_handle->ret = UPDATE_BUSY;

         (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

         return (0);

+    } else if (ulog->kdb_last_sno <= 0) {

+        /*

+         * This should never happen. last_sno should only be zero if there

+         * are no log entries, and should never be negative.

+         */

+        ulog_handle->ret = UPDATE_ERROR;

+        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+        return (KRB5_LOG_CORRUPT);

     }

-

+    

     /*

      * 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

@@ -778,108 +923,119 @@

         (last.last_sno < ulog->kdb_first_sno) ||

         (last.last_sno == 0)) {

         ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

+        ulog_handle->lastentry.last_time = ulog->kdb_last_time;

+        

         (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

         (void) krb5_db_unlock(context);

         ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;

         return (0);

-    } else if (last.last_sno <= ulog->kdb_last_sno) {

-        sno = last.last_sno;

-

-        indx = (sno - 1) % ulogentries;

-

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

-

-        /*

-         * Validate the time stamp just to make sure it was the same sno

-         */

-        if ((indx_log->kdb_time.seconds == last.last_time.seconds) &&

-            (indx_log->kdb_time.useconds == last.last_time.useconds)) {

-

-            /*

-             * If we have the same sno we return success

-             */

-            if (last.last_sno == ulog->kdb_last_sno) {

-                (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

-                (void) krb5_db_unlock(context);

-                ulog_handle->ret = UPDATE_NIL;

-                return (0);

-            }

-

-            count = ulog->kdb_last_sno - sno;

-

-            ulog_handle->updates.kdb_ulog_t_val =

-                (kdb_incr_update_t *)malloc(

-                    sizeof (kdb_incr_update_t) * count);

-

-            upd = ulog_handle->updates.kdb_ulog_t_val;

-

-            if (upd == NULL) {

-                (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

-                (void) krb5_db_unlock(context);

-                ulog_handle->ret = UPDATE_ERROR;

-                return (errno);

-            }

-

-            while (sno < ulog->kdb_last_sno) {

-                indx = sno % ulogentries;

-

-                indx_log = (kdb_ent_header_t *)

-                    INDEX(ulog, indx);

-

-                (void) memset(upd, 0,

-                              sizeof (kdb_incr_update_t));

-                xdrmem_create(&xdrs,

-                              (char *)indx_log->entry_data,

-                              indx_log->kdb_entry_size, XDR_DECODE);

-                if (!xdr_kdb_incr_update_t(&xdrs, upd)) {

-                    (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

-                    (void) krb5_db_unlock(context);

-                    ulog_handle->ret = UPDATE_ERROR;

-                    return (KRB5_LOG_CONV);

-                }

-                /*

-                 * Mark commitment since we didn't

-                 * want to decode and encode the

-                 * incr update record the first time.

-                 */

-                upd->kdb_commit = indx_log->kdb_commit;

-

-                upd++;

-                sno++;

-            } /* while */

-

-            ulog_handle->updates.kdb_ulog_t_len = count;

-

-            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

-            ulog_handle->lastentry.last_time.seconds =

-                ulog->kdb_last_time.seconds;

-            ulog_handle->lastentry.last_time.useconds =

-                ulog->kdb_last_time.useconds;

-            ulog_handle->ret = UPDATE_OK;

+    }

+    sno = last.last_sno;

+        

+    /*

+     * Validate the client state, including timestamp, against the ulog.

+     * Note: The first entry may or may not be in the ulog, since we

+     * may be a downstream slave.

+     */

+    if (sno == ulog->kdb_last_sno) {

+        if (last.last_time.seconds == ulog->kdb_last_time.seconds &&

+            last.last_time.useconds == ulog->kdb_last_time.useconds) {

+            

             (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

             (void) krb5_db_unlock(context);

-

+            ulog_handle->ret = UPDATE_NIL;

             return (0);

         } else {

-            /*

-             * We have time stamp mismatch or we no longer have

-             * the slave's last sno, so we brute force it

-             */

+            

+            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

+            ulog_handle->lastentry.last_time = ulog->kdb_last_time;

+            

+            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+            (void) krb5_db_unlock(context);

+            ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;

+            return (0);

+        }

+    }

+    if (sno == ulog->kdb_first_sno) {

+        if (last.last_time.seconds != ulog->kdb_first_time.seconds ||

+            last.last_time.useconds != ulog->kdb_first_time.useconds) {

+            

+            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

+            ulog_handle->lastentry.last_time = ulog->kdb_last_time;

+            

+            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+            (void) krb5_db_unlock(context);

+            ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;

+            return (0);

+        }

+    } else {

+        indx = (sno - 1) % ulogentries;

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

+        

+        if (indx_log->kdb_time.seconds != last.last_time.seconds ||

+            indx_log->kdb_time.useconds != last.last_time.useconds) {

+            

+            ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

             (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

             (void) krb5_db_unlock(context);

             ulog_handle->ret = UPDATE_FULL_RESYNC_NEEDED;

-

             return (0);

         }

     }

     /*

-     * Should never get here, return error

+     * We have now determined the client needs a list of incremental
updates.

      */

+    count = ulog->kdb_last_sno - sno;

+                

+    ulog_handle->updates.kdb_ulog_t_val =

+        (kdb_incr_update_t *)malloc(sizeof (kdb_incr_update_t) * count);

+                

+    upd = ulog_handle->updates.kdb_ulog_t_val;

+    

+    if (upd == NULL) {

+        (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+        (void) krb5_db_unlock(context);

+        ulog_handle->ret = UPDATE_ERROR;

+        return (errno);

+    }

+    

+    while (sno < ulog->kdb_last_sno) {

+        indx = sno % ulogentries;

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

+        

+        (void) memset(upd, 0, sizeof (kdb_incr_update_t));

+        xdrmem_create(&xdrs,

+                      (char *)indx_log->entry_data,

+                      indx_log->kdb_entry_size, XDR_DECODE);

+        if (!xdr_kdb_incr_update_t(&xdrs, upd)) {

+            (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

+            (void) krb5_db_unlock(context);

+

+            ulog_free_entries(ulog_handle->updates.kdb_ulog_t_val,

+                              sno - last.last_sno);

+            ulog_handle->updates.kdb_ulog_t_val = NULL;

+            

+            ulog_handle->ret = UPDATE_ERROR;

+            return (KRB5_LOG_CONV);

+        }

+        upd->kdb_commit = indx_log->kdb_commit;

+

+        upd++;

+        sno++;

+    } /* while */

+

+    ulog_handle->updates.kdb_ulog_t_len = count;

+    

+    ulog_handle->lastentry.last_sno = ulog->kdb_last_sno;

+    ulog_handle->lastentry.last_time = ulog->kdb_last_time;

+    ulog_handle->ret = UPDATE_OK;

+    

     (void) ulog_lock(context, KRB5_LOCKMODE_UNLOCK);

-    ulog_handle->ret = UPDATE_ERROR;

-    return (KRB5_LOG_ERROR);

+    (void) krb5_db_unlock(context);

+    

+    return (0);

}

 krb5_error_code

Only in src/lib/kdb: kdb_log.c.~1~

Only in src/lib/kdb: kdb_log.c.~2~

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-06-03 01:21:36.000000000 -0400

@@ -399,22 +399,23 @@

  * 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;

-    if (entry && (entry < ulog->kdb_num))

+    if (entry > 0 && entry < ulog->kdb_num)

         start_sno = ulog->kdb_last_sno - entry;

     else

-        start_sno = ulog->kdb_first_sno - 1;

+        start_sno = ulog->kdb_last_sno - ulog->kdb_num;

     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 +539,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 +610,7 @@

     }

     if ((!headeronly) && ulog->kdb_num) {

-        print_update(ulog, entry, verbose);

+        print_update(context, entry, verbose);

     }

     (void) printf("\n");

Only in src/slave: kproplog.c.~1~

 

 




More information about the krb5-bugs mailing list