b356971dbb955af2a3c6f5efe53dff0feb50c0b6
[platform/upstream/krb5.git] / src / tests / t_iprop.py
1 import os
2 import re
3
4 from k5test import *
5
6 # On macOS with System Integrity Protection enabled, this script hangs
7 # in the wait_for_prop() call after starting the first kpropd process,
8 # most likely due to signal restrictions preventing the listening
9 # child from informing the parent that a full resync was processed.
10 if which('csrutil'):
11     out = subprocess.check_output(['csrutil', 'status'],
12                                   universal_newlines=True)
13     if 'status: enabled' in out:
14         skip_rest('iprop tests', 'System Integrity Protection is enabled')
15
16 # Read lines from kpropd output until we are synchronized.  Error if
17 # full_expected is true and we didn't see a full propagation or vice
18 # versa.
19 def wait_for_prop(kpropd, full_expected, expected_old, expected_new):
20     output('*** Waiting for sync from kpropd\n')
21     full_seen = sleep_seen = False
22     old_sno = new_sno = -1
23     while True:
24         line = kpropd.stdout.readline()
25         if line == '':
26             fail('kpropd process exited unexpectedly')
27         output('kpropd: ' + line)
28
29         m = re.match(r'Calling iprop_get_updates_1 \(sno=(\d+) ', line)
30         if m:
31             if not full_seen:
32                 old_sno = int(m.group(1))
33             # Also record this as the new sno, in case we get back
34             # UPDATE_NIL.
35             new_sno = int(m.group(1))
36
37         m = re.match(r'Got incremental updates \(sno=(\d+) ', line)
38         if m:
39             new_sno = int(m.group(1))
40
41         if 'KDC is synchronized' in line or 'Incremental updates:' in line:
42             break
43
44         # After a full resync request, these lines could appear in
45         # either order.
46         if 'Waiting for' in line:
47             sleep_seen = True
48         if 'load process for full propagation completed' in line:
49             full_seen = True
50
51         # Detect some failure conditions.
52         if 'Still waiting for full resync' in line:
53             fail('kadmind gave consecutive full resyncs')
54         if 'Rejected connection' in line:
55             fail('kpropd rejected kprop connection')
56         if 'get updates failed' in line:
57             fail('iprop_get_updates failed')
58         if 'permission denied' in line:
59             fail('kadmind denied update')
60         if ('error from primary' in line or
61             'error returned from primary' in line):
62             fail('kadmind reported error')
63         if 'invalid return' in line:
64             fail('kadmind returned invalid result')
65
66     if full_expected and not full_seen:
67         fail('Expected full dump but saw only incremental')
68     if full_seen and not full_expected:
69         fail('Expected incremental prop but saw full dump')
70     if old_sno != expected_old:
71          fail('Expected old serial %d from kpropd sync' % expected_old)
72     if new_sno != expected_new:
73          fail('Expected new serial %d from kpropd sync' % expected_new)
74
75     # Wait until kpropd is sleeping before continuing, to avoid races.
76     # (This is imperfect since there's there is a short window between
77     # the fprintf and the sleep; kpropd will need design changes to
78     # fix that.)
79     while True:
80         line = kpropd.stdout.readline()
81         output('kpropd: ' + line)
82         if 'Waiting for' in line:
83             break
84     output('*** Sync complete\n')
85
86 # Verify the output of kproplog against the expected number of
87 # entries, first and last serial number, and a list of principal names
88 # for the update entrires.
89 def check_ulog(num, first, last, entries, env=None):
90     out = realm.run([kproplog], env=env)
91     if 'Number of entries : ' + str(num) + '\n' not in out:
92         fail('Expected %d entries' % num)
93     if last:
94         firststr = first and str(first) or 'None'
95         if 'First serial # : ' + firststr + '\n' not in out:
96             fail('Expected first serial number %d' % first)
97     laststr = last and str(last) or 'None'
98     if 'Last serial # : ' + laststr + '\n' not in out:
99         fail('Expected last serial number %d' % last)
100     assert(len(entries) == num)
101     ser = first - 1
102     entindex = 0
103     for line in out.splitlines():
104         m = re.match(r'\tUpdate serial # : (\d+)$', line)
105         if m:
106             ser = ser + 1
107             if m.group(1) != str(ser):
108                 fail('Expected serial number %d in update entry' % ser)
109         m = re.match(r'\tUpdate principal : (.*)$', line)
110         if m:
111             eprinc = entries[ser - first]
112             if eprinc == None:
113                 fail('Expected dummy update entry %d' % ser)
114             elif m.group(1) != eprinc:
115                 fail('Expected princ %s in update entry %d' % (eprinc, ser))
116         if line == '\tDummy entry':
117             eprinc = entries[ser - first]
118             if eprinc != None:
119                 fail('Expected princ %s in update entry %d' % (eprinc, ser))
120
121 # replica1 will receive updates from primary, and replica2 will
122 # receive updates from replica1.  Because of the awkward way iprop and
123 # kprop port configuration currently works, we need separate config
124 # files for the replica and primary sides of replica1, but they use
125 # the same DB and ulog file.
126 conf = {'realms': {'$realm': {'iprop_enable': 'true',
127                               'iprop_logfile': '$testdir/db.ulog'}}}
128 conf_rep1 = {'realms': {'$realm': {'iprop_replica_poll': '600',
129                                    'iprop_logfile': '$testdir/ulog.replica1'}},
130              'dbmodules': {'db': {'database_name': '$testdir/db.replica1'}}}
131 conf_rep1m = {'realms': {'$realm': {'iprop_logfile': '$testdir/ulog.replica1',
132                                     'iprop_port': '$port8'}},
133               'dbmodules': {'db': {'database_name': '$testdir/db.replica1'}}}
134 conf_rep2 = {'realms': {'$realm': {'iprop_replica_poll': '600',
135                                    'iprop_logfile': '$testdir/ulog.replica2',
136                                    'iprop_port': '$port8'}},
137              'dbmodules': {'db': {'database_name': '$testdir/db.replica2'}}}
138
139 conf_foo = {'libdefaults': {'default_realm': 'FOO'},
140             'domain_realm': {hostname: 'FOO'}}
141 conf_rep3 = {'realms': {'$realm': {'iprop_replica_poll': '600',
142                                    'iprop_logfile': '$testdir/ulog.replica3',
143                                    'iprop_port': '$port8'},
144                         'FOO': {'iprop_logfile': '$testdir/ulog.replica3'}},
145             'dbmodules': {'db': {'database_name': '$testdir/db.replica3'}}}
146
147 krb5_conf_rep4 = {'domain_realm': {hostname: 'FOO'}}
148 conf_rep4 = {'realms': {'$realm': {'iprop_replica_poll': '600',
149                                    'iprop_logfile': '$testdir/ulog.replica4',
150                                    'iprop_port': '$port8'}},
151              'dbmodules': {'db': {'database_name': '$testdir/db.replica4'}}}
152
153 for realm in multidb_realms(kdc_conf=conf, create_user=False,
154                             start_kadmind=True):
155     replica1 = realm.special_env('replica1', True, kdc_conf=conf_rep1)
156     replica1m = realm.special_env('replica1m', True, krb5_conf=conf_foo,
157                                   kdc_conf=conf_rep1m)
158     replica2 = realm.special_env('replica2', True, kdc_conf=conf_rep2)
159
160     # A default_realm and domain_realm that do not match the KDC's
161     # realm.  The FOO realm iprop_logfile setting is needed to run
162     # kproplog during a replica3 test, since kproplog has no realm
163     # option.
164     replica3 = realm.special_env('replica3', True, krb5_conf=conf_foo,
165                                  kdc_conf=conf_rep3)
166
167     # A default realm and a domain realm map that differ.
168     replica4 = realm.special_env('replica4', True, krb5_conf=krb5_conf_rep4,
169                                  kdc_conf=conf_rep4)
170
171     # Define some principal names.  pr3 is long enough to cause internal
172     # reallocs, but not long enough to grow the basic ulog entry size.
173     pr1 = 'wakawaka@' + realm.realm
174     pr2 = 'w@' + realm.realm
175     c = 'chocolate-flavored-school-bus'
176     cs = c + '/'
177     pr3 = (cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + cs + c +
178            '@' + realm.realm)
179
180     # Create the kpropd ACL file.
181     acl_file = os.path.join(realm.testdir, 'kpropd-acl')
182     acl = open(acl_file, 'w')
183     acl.write(realm.host_princ + '\n')
184     acl.close()
185
186     ulog = os.path.join(realm.testdir, 'db.ulog')
187     if not os.path.exists(ulog):
188         fail('update log not created: ' + ulog)
189
190     # Create the principal used to authenticate kpropd to kadmind.
191     kiprop_princ = 'kiprop/' + hostname
192     realm.addprinc(kiprop_princ)
193     realm.extract_keytab(kiprop_princ, realm.keytab)
194
195     # Create the initial replica databases.
196     dumpfile = os.path.join(realm.testdir, 'dump')
197     realm.run([kdb5_util, 'dump', dumpfile])
198     realm.run([kdb5_util, 'load', dumpfile], replica1)
199     realm.run([kdb5_util, 'load', dumpfile], replica2)
200     realm.run([kdb5_util, '-r', realm.realm, 'load', dumpfile], replica3)
201     realm.run([kdb5_util, 'load', dumpfile], replica4)
202
203     # Reinitialize the primary ulog so we know exactly what to expect
204     # in it.
205     realm.run([kproplog, '-R'])
206     check_ulog(1, 1, 1, [None])
207
208     # Make some changes to the primary DB.
209     realm.addprinc(pr1)
210     realm.addprinc(pr3)
211     realm.addprinc(pr2)
212     realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
213     realm.run([kadminl, 'modprinc', '+allow_tix', pr2])
214     check_ulog(6, 1, 6, [None, pr1, pr3, pr2, pr2, pr2])
215
216     # Start kpropd for replica1 and get a full dump from primary.
217     mark('propagate M->1 full')
218     kpropd1 = realm.start_kpropd(replica1, ['-d'])
219     wait_for_prop(kpropd1, True, 1, 6)
220     out = realm.run([kadminl, 'listprincs'], env=replica1)
221     if pr1 not in out or pr2 not in out or pr3 not in out:
222         fail('replica1 does not have all principals from primary')
223     check_ulog(1, 6, 6, [None], replica1)
224
225     # Make a change and check that it propagates incrementally.
226     mark('propagate M->1 incremental')
227     realm.run([kadminl, 'modprinc', '-allow_tix', pr2])
228     check_ulog(7, 1, 7, [None, pr1, pr3, pr2, pr2, pr2, pr2])
229     kpropd1.send_signal(signal.SIGUSR1)
230     wait_for_prop(kpropd1, False, 6, 7)
231     check_ulog(2, 6, 7, [None, pr2], replica1)
232     realm.run([kadminl, 'getprinc', pr2], env=replica1,
233               expected_msg='Attributes: DISALLOW_ALL_TIX')
234
235     # Start kadmind -proponly for replica1.  (Use the replica1m
236     # environment which defines iprop_port to $port8.)
237     replica1_out_dump_path = os.path.join(realm.testdir, 'dump.replica1.out')
238     replica2_in_dump_path = os.path.join(realm.testdir, 'dump.replica2.in')
239     replica2_kprop_port = str(realm.portbase + 9)
240     kadmind_proponly = realm.start_server([kadmind, '-r', realm.realm,
241                                            '-nofork', '-proponly',
242                                            '-p', kdb5_util,
243                                            '-K', kprop, '-k',
244                                            replica2_kprop_port,
245                                            '-F', replica1_out_dump_path],
246                                           'starting...', replica1m)
247
248     # Test similar default_realm and domain_realm map settings with -r realm.
249     mark('propagate 1->3 full')
250     replica3_in_dump_path = os.path.join(realm.testdir, 'dump.replica3.in')
251     kpropd3 = realm.start_server([kpropd, '-d', '-D', '-r', realm.realm, '-P',
252                                   replica2_kprop_port, '-f',
253                                   replica3_in_dump_path, '-p', kdb5_util, '-a',
254                                   acl_file, '-A', hostname], 'ready', replica3)
255     wait_for_prop(kpropd3, True, 1, 7)
256     out = realm.run([kadminl, '-r', realm.realm, 'listprincs'], env=replica3)
257     if pr1 not in out or pr2 not in out or pr3 not in out:
258         fail('replica3 does not have all principals from replica1')
259     check_ulog(1, 7, 7, [None], env=replica3)
260
261     # Test an incremental propagation for the kpropd -r case.
262     mark('propagate M->1->3 incremental')
263     realm.run([kadminl, 'modprinc', '-maxlife', '20 minutes', pr1])
264     check_ulog(8, 1, 8, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1])
265     kpropd1.send_signal(signal.SIGUSR1)
266     wait_for_prop(kpropd1, False, 7, 8)
267     check_ulog(3, 6, 8, [None, pr2, pr1], replica1)
268     realm.run([kadminl, 'getprinc', pr1], env=replica1,
269               expected_msg='Maximum ticket life: 0 days 00:20:00')
270     kpropd3.send_signal(signal.SIGUSR1)
271     wait_for_prop(kpropd3, False, 7, 8)
272     check_ulog(2, 7, 8, [None, pr1], replica3)
273     realm.run([kadminl, '-r', realm.realm, 'getprinc', pr1], env=replica3,
274               expected_msg='Maximum ticket life: 0 days 00:20:00')
275     stop_daemon(kpropd3)
276
277     # Test dissimilar default_realm and domain_realm map settings (no
278     # -r realm).
279     mark('propagate 1->4 full')
280     replica4_in_dump_path = os.path.join(realm.testdir, 'dump.replica4.in')
281     kpropd4 = realm.start_server([kpropd, '-d', '-D', '-P',
282                                   replica2_kprop_port, '-f',
283                                   replica4_in_dump_path, '-p', kdb5_util,
284                                   '-a', acl_file, '-A', hostname], 'ready',
285                                  replica4)
286     wait_for_prop(kpropd4, True, 1, 8)
287     out = realm.run([kadminl, 'listprincs'], env=replica4)
288     if pr1 not in out or pr2 not in out or pr3 not in out:
289         fail('replica4 does not have all principals from replica1')
290     stop_daemon(kpropd4)
291
292     # Start kpropd for replica2.  The -A option isn't needed since
293     # we're talking to the same host as primary (we specify it anyway
294     # to exercise the code), but replica2 defines iprop_port to $port8
295     # so it will talk to replica1.  Get a full dump from replica1.
296     mark('propagate 1->2 full')
297     kpropd2 = realm.start_server([kpropd, '-d', '-D', '-P',
298                                   replica2_kprop_port, '-f',
299                                   replica2_in_dump_path, '-p', kdb5_util,
300                                   '-a', acl_file, '-A', hostname], 'ready',
301                                  replica2)
302     wait_for_prop(kpropd2, True, 1, 8)
303     check_ulog(2, 7, 8, [None, pr1], replica2)
304     out = realm.run([kadminl, 'listprincs'], env=replica1)
305     if pr1 not in out or pr2 not in out or pr3 not in out:
306         fail('replica2 does not have all principals from replica1')
307
308     # Make another change and check that it propagates incrementally
309     # to both replicas.
310     mark('propagate M->1->2 incremental')
311     realm.run([kadminl, 'modprinc', '-maxrenewlife', '22 hours', pr1])
312     check_ulog(9, 1, 9, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1])
313     kpropd1.send_signal(signal.SIGUSR1)
314     wait_for_prop(kpropd1, False, 8, 9)
315     check_ulog(4, 6, 9, [None, pr2, pr1, pr1], replica1)
316     realm.run([kadminl, 'getprinc', pr1], env=replica1,
317               expected_msg='Maximum renewable life: 0 days 22:00:00\n')
318     kpropd2.send_signal(signal.SIGUSR1)
319     wait_for_prop(kpropd2, False, 8, 9)
320     check_ulog(3, 7, 9, [None, pr1, pr1], replica2)
321     realm.run([kadminl, 'getprinc', pr1], env=replica2,
322               expected_msg='Maximum renewable life: 0 days 22:00:00\n')
323
324     # Reset the ulog on replica1 to force a full resync from primary.
325     # The resync will use the old dump file and then propagate
326     # changes.  replica2 should still be in sync with replica1 after
327     # the resync, so make sure it doesn't take a full resync.
328     mark('propagate M->1->2 full')
329     realm.run([kproplog, '-R'], replica1)
330     check_ulog(1, 1, 1, [None], replica1)
331     kpropd1.send_signal(signal.SIGUSR1)
332     wait_for_prop(kpropd1, True, 1, 9)
333     check_ulog(4, 6, 9, [None, pr2, pr1, pr1], replica1)
334     kpropd2.send_signal(signal.SIGUSR1)
335     wait_for_prop(kpropd2, False, 9, 9)
336     check_ulog(3, 7, 9, [None, pr1, pr1], replica2)
337
338     # Make another change and check that it propagates incrementally to
339     # both replicas.
340     mark('propagate M->1->2 incremental (after reset)')
341     realm.run([kadminl, 'modprinc', '+allow_tix', pr2])
342     check_ulog(10, 1, 10, [None, pr1, pr3, pr2, pr2, pr2, pr2, pr1, pr1, pr2])
343     kpropd1.send_signal(signal.SIGUSR1)
344     wait_for_prop(kpropd1, False, 9, 10)
345     check_ulog(5, 6, 10, [None, pr2, pr1, pr1, pr2], replica1)
346     realm.run([kadminl, 'getprinc', pr2], env=replica1,
347               expected_msg='Attributes:\n')
348     kpropd2.send_signal(signal.SIGUSR1)
349     wait_for_prop(kpropd2, False, 9, 10)
350     check_ulog(4, 7, 10, [None, pr1, pr1, pr2], replica2)
351     realm.run([kadminl, 'getprinc', pr2], env=replica2,
352               expected_msg='Attributes:\n')
353
354     # Create a policy and check that it propagates via full resync.
355     mark('propagate M->1->2 full (new policy)')
356     realm.run([kadminl, 'addpol', '-minclasses', '2', 'testpol'])
357     check_ulog(1, 1, 1, [None])
358     kpropd1.send_signal(signal.SIGUSR1)
359     wait_for_prop(kpropd1, True, 10, 1)
360     check_ulog(1, 1, 1, [None], replica1)
361     realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
362               expected_msg='Minimum number of password character classes: 2')
363     kpropd2.send_signal(signal.SIGUSR1)
364     wait_for_prop(kpropd2, True, 10, 1)
365     check_ulog(1, 1, 1, [None], replica2)
366     realm.run([kadminl, 'getpol', 'testpol'], env=replica2,
367               expected_msg='Minimum number of password character classes: 2')
368
369     # Modify the policy and test that it also propagates via full resync.
370     mark('propagate M->1->2 full (policy change)')
371     realm.run([kadminl, 'modpol', '-minlength', '17', 'testpol'])
372     check_ulog(1, 1, 1, [None])
373     kpropd1.send_signal(signal.SIGUSR1)
374     wait_for_prop(kpropd1, True, 1, 1)
375     check_ulog(1, 1, 1, [None], replica1)
376     realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
377               expected_msg='Minimum password length: 17')
378     kpropd2.send_signal(signal.SIGUSR1)
379     wait_for_prop(kpropd2, True, 1, 1)
380     check_ulog(1, 1, 1, [None], replica2)
381     realm.run([kadminl, 'getpol', 'testpol'], env=replica2,
382               expected_msg='Minimum password length: 17')
383
384     # Delete the policy and test that it propagates via full resync.
385     mark('propgate M->1->2 full (policy delete)')
386     realm.run([kadminl, 'delpol', 'testpol'])
387     check_ulog(1, 1, 1, [None])
388     kpropd1.send_signal(signal.SIGUSR1)
389     wait_for_prop(kpropd1, True, 1, 1)
390     check_ulog(1, 1, 1, [None], replica1)
391     realm.run([kadminl, 'getpol', 'testpol'], env=replica1, expected_code=1,
392               expected_msg='Policy does not exist')
393     kpropd2.send_signal(signal.SIGUSR1)
394     wait_for_prop(kpropd2, True, 1, 1)
395     check_ulog(1, 1, 1, [None], replica2)
396     realm.run([kadminl, 'getpol', 'testpol'], env=replica2, expected_code=1,
397               expected_msg='Policy does not exist')
398
399     # Modify a principal on the primary and test that it propagates
400     # incrementally.
401     mark('propagate M->1->2 incremental (after policy changes)')
402     realm.run([kadminl, 'modprinc', '-maxlife', '10 minutes', pr1])
403     check_ulog(2, 1, 2, [None, pr1])
404     kpropd1.send_signal(signal.SIGUSR1)
405     wait_for_prop(kpropd1, False, 1, 2)
406     check_ulog(2, 1, 2, [None, pr1], replica1)
407     realm.run([kadminl, 'getprinc', pr1], env=replica1,
408               expected_msg='Maximum ticket life: 0 days 00:10:00')
409     kpropd2.send_signal(signal.SIGUSR1)
410     wait_for_prop(kpropd2, False, 1, 2)
411     check_ulog(2, 1, 2, [None, pr1], replica2)
412     realm.run([kadminl, 'getprinc', pr1], env=replica2,
413               expected_msg='Maximum ticket life: 0 days 00:10:00')
414
415     # Delete a principal and test that it propagates incrementally.
416     mark('propagate M->1->2 incremental (princ delete)')
417     realm.run([kadminl, 'delprinc', pr3])
418     check_ulog(3, 1, 3, [None, pr1, pr3])
419     kpropd1.send_signal(signal.SIGUSR1)
420     wait_for_prop(kpropd1, False, 2, 3)
421     check_ulog(3, 1, 3, [None, pr1, pr3], replica1)
422     realm.run([kadminl, 'getprinc', pr3], env=replica1, expected_code=1,
423               expected_msg='Principal does not exist')
424     kpropd2.send_signal(signal.SIGUSR1)
425     wait_for_prop(kpropd2, False, 2, 3)
426     check_ulog(3, 1, 3, [None, pr1, pr3], replica2)
427     realm.run([kadminl, 'getprinc', pr3], env=replica2, expected_code=1,
428               expected_msg='Principal does not exist')
429
430     # Rename a principal and test that it propagates incrementally.
431     mark('propagate M->1->2 incremental (princ rename)')
432     renpr = "quacked@" + realm.realm
433     realm.run([kadminl, 'renprinc', pr1, renpr])
434     check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr])
435     kpropd1.send_signal(signal.SIGUSR1)
436     wait_for_prop(kpropd1, False, 3, 6)
437     check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], replica1)
438     realm.run([kadminl, 'getprinc', pr1], env=replica1, expected_code=1,
439               expected_msg='Principal does not exist')
440     realm.run([kadminl, 'getprinc', renpr], env=replica1)
441     kpropd2.send_signal(signal.SIGUSR1)
442     wait_for_prop(kpropd2, False, 3, 6)
443     check_ulog(6, 1, 6, [None, pr1, pr3, renpr, pr1, renpr], replica2)
444     realm.run([kadminl, 'getprinc', pr1], env=replica2, expected_code=1,
445               expected_msg='Principal does not exist')
446     realm.run([kadminl, 'getprinc', renpr], env=replica2)
447
448     pr1 = renpr
449
450     # Reset the ulog on the primary to force a full resync.
451     mark('propagate M->1->2 full (ulog reset)')
452     realm.run([kproplog, '-R'])
453     check_ulog(1, 1, 1, [None])
454     kpropd1.send_signal(signal.SIGUSR1)
455     wait_for_prop(kpropd1, True, 6, 1)
456     check_ulog(1, 1, 1, [None], replica1)
457     kpropd2.send_signal(signal.SIGUSR1)
458     wait_for_prop(kpropd2, True, 6, 1)
459     check_ulog(1, 1, 1, [None], replica2)
460
461     # Stop the kprop daemons so we can test kpropd -t.
462     realm.stop_kpropd(kpropd1)
463     stop_daemon(kpropd2)
464     stop_daemon(kadmind_proponly)
465     mark('kpropd -t')
466
467     # Test the case where no updates are needed.
468     out = realm.run_kpropd_once(replica1, ['-d'])
469     if 'KDC is synchronized' not in out:
470         fail('Expected synchronized from kpropd -t')
471     check_ulog(1, 1, 1, [None], replica1)
472
473     # Make a change on the primary and fetch it incrementally.
474     realm.run([kadminl, 'modprinc', '-maxlife', '5 minutes', pr1])
475     check_ulog(2, 1, 2, [None, pr1])
476     out = realm.run_kpropd_once(replica1, ['-d'])
477     if 'Got incremental updates (sno=2 ' not in out:
478         fail('Expected full dump and synchronized from kpropd -t')
479     check_ulog(2, 1, 2, [None, pr1], replica1)
480     realm.run([kadminl, 'getprinc', pr1], env=replica1,
481               expected_msg='Maximum ticket life: 0 days 00:05:00')
482
483     # Propagate a policy change via full resync.
484     realm.run([kadminl, 'addpol', '-minclasses', '3', 'testpol'])
485     check_ulog(1, 1, 1, [None])
486     out = realm.run_kpropd_once(replica1, ['-d'])
487     if ('Full propagation transfer finished' not in out or
488         'KDC is synchronized' not in out):
489         fail('Expected full dump and synchronized from kpropd -t')
490     check_ulog(1, 1, 1, [None], replica1)
491     realm.run([kadminl, 'getpol', 'testpol'], env=replica1,
492               expected_msg='Minimum number of password character classes: 3')
493
494 success('iprop tests')