]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Fix compatibility with pre-1.11 iprop dump files 298/head
authorGreg Hudson <ghudson@mit.edu>
Fri, 17 Jul 2015 17:03:35 +0000 (13:03 -0400)
committerGreg Hudson <ghudson@mit.edu>
Mon, 20 Jul 2015 15:29:56 +0000 (11:29 -0400)
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.

ticket: 8213
target_version: 1.13.3

src/kadmin/dbutil/dump.c
src/tests/t_dump.py

index bfb85772b4f0b8f0b6b6d2c38d8acc5ad103f729..07f62e909b0d7658657e00d91af2f00d0870afc2 100644 (file)
@@ -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)
index 6ba0d35f709f31d50b7060bb8b0e19087c10841d..5d3a437625e2b38c7ad317951132f8e316558eb8 100755 (executable)
@@ -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')