krb5 commit [krb5-1.13]: Fix compatibility with pre-1.11 iprop dump files

Tom Yu tlyu at mit.edu
Wed Dec 2 14:58:11 EST 2015


https://github.com/krb5/krb5/commit/6f1b25097969b4685263639a5214d440ce233793
commit 6f1b25097969b4685263639a5214d440ce233793
Author: Greg Hudson <ghudson at mit.edu>
Date:   Fri Jul 17 13:03:35 2015 -0400

    Fix compatibility with pre-1.11 iprop dump files
    
    Ticket #7223 added new policy fields and a new dump format version to
    marshal them, but did not add a new iprop dump format version.  As a
    result, slave KDCs running 1.11 or later cannot receive full resyncs
    from master KDCs running 1.10 or earlier.  (Reported by John
    Devitofranceschi.)
    
    Retroactively add support for pre-1.11 policy entries by making
    process_r1_11_policy() read the first ten fields, check whether the
    next whitespace character is a newline, and then read the rest if it
    is not.
    
    (back ported from commit 3c9ab5220bcc3f57641f6f4b6942b17aadb6613d)
    
    ticket: 8286 (new)
    version_fixed: 1.13.3
    status: resolved

 src/kadmin/dbutil/dump.c |   58 +++++++++++++++++++++++++++++++---------------
 src/tests/t_dump.py      |   12 +++++++--
 2 files changed, 48 insertions(+), 22 deletions(-)

diff --git a/src/kadmin/dbutil/dump.c b/src/kadmin/dbutil/dump.c
index bfb8577..07f62e9 100644
--- a/src/kadmin/dbutil/dump.c
+++ b/src/kadmin/dbutil/dump.c
@@ -958,41 +958,61 @@ process_r1_11_policy(krb5_context context, const char *fname, FILE *filep,
     char namebuf[1024];
     char keysaltbuf[KRB5_KDB_MAX_ALLOWED_KS_LEN + 1];
     unsigned int refcnt;
-    int nread, ret = 0;
+    int nread, c, ret = 0;
 
     memset(&rec, 0, sizeof(rec));
 
     (*linenop)++;
     rec.name = namebuf;
-    rec.allowed_keysalts = keysaltbuf;
 
-    nread = fscanf(filep, "%1023s\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t"
-                   "%u\t%u\t%u\t"
-                   K5CONST_WIDTH_SCANF_STR(KRB5_KDB_MAX_ALLOWED_KS_LEN)
-                   "\t%hd", rec.name, &rec.pw_min_life, &rec.pw_max_life,
+    /*
+     * Due to a historical error, iprop dumps use the same version before and
+     * after the 1.11 policy extensions.  So we need to accept both 1.8-format
+     * and 1.11-format policy entries.  Begin by reading the 1.8 fields.
+     */
+    nread = fscanf(filep, "%1023s\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u\t%u",
+                   rec.name, &rec.pw_min_life, &rec.pw_max_life,
                    &rec.pw_min_length, &rec.pw_min_classes,
                    &rec.pw_history_num, &refcnt, &rec.pw_max_fail,
-                   &rec.pw_failcnt_interval, &rec.pw_lockout_duration,
-                   &rec.attributes, &rec.max_life, &rec.max_renewable_life,
-                   rec.allowed_keysalts, &rec.n_tl_data);
+                   &rec.pw_failcnt_interval, &rec.pw_lockout_duration);
     if (nread == EOF)
         return -1;
-    if (nread != 15) {
+    if (nread != 10) {
         fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
         return 1;
     }
 
-    if (rec.allowed_keysalts && !strcmp(rec.allowed_keysalts, "-"))
-        rec.allowed_keysalts = NULL;
+    /* The next character should be a newline (1.8) or a tab (1.11). */
+    c = getc(filep);
+    if (c == EOF)
+        return -1;
+    if (c != '\n') {
+        /* Read the additional 1.11-format fields. */
+        rec.allowed_keysalts = keysaltbuf;
+        nread = fscanf(filep, "%u\t%u\t%u\t"
+                       K5CONST_WIDTH_SCANF_STR(KRB5_KDB_MAX_ALLOWED_KS_LEN)
+                       "\t%hd", &rec.attributes, &rec.max_life,
+                       &rec.max_renewable_life, rec.allowed_keysalts,
+                       &rec.n_tl_data);
+        if (nread == EOF)
+            return -1;
+        if (nread != 5) {
+            fprintf(stderr, _("cannot parse policy (%d read)\n"), nread);
+            return 1;
+        }
 
-    /* Get TL data */
-    ret = alloc_tl_data(rec.n_tl_data, &rec.tl_data);
-    if (ret)
-        goto cleanup;
+        if (rec.allowed_keysalts && !strcmp(rec.allowed_keysalts, "-"))
+            rec.allowed_keysalts = NULL;
 
-    ret = process_tl_data(fname, filep, *linenop, rec.tl_data);
-    if (ret)
-        goto cleanup;
+        /* Get TL data */
+        ret = alloc_tl_data(rec.n_tl_data, &rec.tl_data);
+        if (ret)
+            goto cleanup;
+
+        ret = process_tl_data(fname, filep, *linenop, rec.tl_data);
+        if (ret)
+            goto cleanup;
+    }
 
     ret = krb5_db_create_policy(context, &rec);
     if (ret)
diff --git a/src/tests/t_dump.py b/src/tests/t_dump.py
index edf7a23..42f8f0e 100644
--- a/src/tests/t_dump.py
+++ b/src/tests/t_dump.py
@@ -12,12 +12,15 @@ realm.run_kadminl('addpol fred')
 dumpfile = os.path.join(realm.testdir, 'dump')
 realm.run([kdb5_util, 'dump', dumpfile])
 
-# Write an additional policy record to the dump.
+# Write additional policy records to the dump.  Use the 1.8 format for
+# one of them, to test retroactive compatibility (for issue #8213).
 f = open('testdir/dump', 'a')
+f.write('policy	compat	0	0	3	4	5	0	'
+        '0	0	0\n')
 f.write('policy	barney	0	0	1	1	1	0	'
         '0	0	0	0	0	0	-	1	'
         '2	28	'
-        'fd100f5064625f6372656174696f6e404b5242544553542e434f4d00')
+        'fd100f5064625f6372656174696f6e404b5242544553542e434f4d00\n')
 f.close()
 
 # Destroy and load the database; check that the policies exist.
@@ -33,6 +36,9 @@ if 'Expiration date: [never]' not in out or 'MKey: vno 1' not in out:
 out = realm.run_kadminl('getpols')
 if 'fred\n' not in out or 'barney\n' not in out:
     fail('Missing policy after load')
+out = realm.run_kadminl('getpol compat')
+if 'Number of old keys kept: 5' not in out:
+    fail('Policy (1.8 format) has wrong value after load')
 out = realm.run_kadminl('getpol barney')
 if 'Number of old keys kept: 1' not in out:
     fail('Policy has wrong value after load')
@@ -44,7 +50,7 @@ out = realm.run_kadminl('getprincs')
 if realm.user_princ not in out or realm.host_princ not in out:
     fail('Missing principal after load')
 out = realm.run_kadminl('getpols')
-if 'fred\n' not in out or 'barney\n' not in out:
+if 'compat\n' not in out or 'fred\n' not in out or 'barney\n' not in out:
     fail('Missing policy after second load')
 
 srcdumpdir = os.path.join(srctop, 'tests', 'dumpfiles')


More information about the cvs-krb5 mailing list