wintest Allow 'samba-tool newuser' to run a few times waiting for the RID Set
[kai/samba-autobuild/.git] / wintest / test-s4-howto.py
1 #!/usr/bin/env python
2
3 '''automated testing of the steps of the Samba4 HOWTO'''
4
5 import sys, os
6 import optparse
7 import wintest, pexpect
8
9 def check_prerequesites(t):
10     t.info("Checking prerequesites")
11     t.setvar('HOSTNAME', t.cmd_output("hostname -s").strip())
12     if os.getuid() != 0:
13         raise Exception("You must run this script as root")
14     t.putenv("KRB5_CONFIG", '${PREFIX}/private/krb5.conf')
15     t.run_cmd('ifconfig ${INTERFACE} ${INTERFACE_NET} up')
16     if t.getvar('INTERFACE_IPV6'):
17         t.run_cmd('ifconfig ${INTERFACE} inet6 del ${INTERFACE_IPV6}/64', checkfail=False)
18         t.run_cmd('ifconfig ${INTERFACE} inet6 add ${INTERFACE_IPV6}/64 up')
19
20
21 def build_s4(t):
22     '''build samba4'''
23     t.info('Building s4')
24     t.chdir('${SOURCETREE}/source4')
25     t.putenv('CC', 'ccache gcc')
26     t.run_cmd('make reconfigure || ./configure --enable-auto-reconfigure --enable-developer --prefix=${PREFIX} -C')
27     t.run_cmd('make -j')
28     t.run_cmd('rm -rf ${PREFIX}')
29     t.run_cmd('make -j install')
30
31
32 def provision_s4(t, func_level="2008"):
33     '''provision s4 as a DC'''
34     t.info('Provisioning s4')
35     t.chdir('${PREFIX}')
36     t.del_files(["var", "private"])
37     t.run_cmd("rm -f etc/smb.conf")
38     provision=['sbin/provision',
39                '--realm=${LCREALM}',
40                '--domain=${DOMAIN}',
41                '--adminpass=${PASSWORD1}',
42                '--server-role=domain controller',
43                '--function-level=%s' % func_level,
44                '-d${DEBUGLEVEL}',
45                '--option=interfaces=${INTERFACE}',
46                '--host-ip=${INTERFACE_IP}',
47                '--option=bind interfaces only=yes',
48                '--option=rndc command=${RNDC} -c${PREFIX}/etc/rndc.conf']
49     if t.getvar('INTERFACE_IPV6'):
50         provision.append('--host-ip6=${INTERFACE_IPV6}')
51     t.run_cmd(provision)
52     t.run_cmd('bin/samba-tool newuser testallowed ${PASSWORD1}')
53     t.run_cmd('bin/samba-tool newuser testdenied ${PASSWORD1}')
54     t.run_cmd('bin/samba-tool group addmembers "Allowed RODC Password Replication Group" testallowed')
55
56
57 def start_s4(t):
58     '''startup samba4'''
59     t.info('Starting Samba4')
60     t.chdir("${PREFIX}")
61     t.run_cmd('killall -9 -q samba smbd nmbd winbindd', checkfail=False)
62     t.run_cmd(['sbin/samba',
63              '--option', 'panic action=gnome-terminal -e "gdb --pid %PID%"'])
64     t.port_wait("${INTERFACE_IP}", 139)
65
66 def stop_vms(t):
67     '''Shut down any existing alive VMs, so they don't collide with what we are doing'''
68     t.info('Shutting down any of our VMs already running')
69     vms = t.get_vms()
70     for v in vms:
71         t.vm_poweroff(v, checkfail=False)
72
73 def test_smbclient(t):
74     '''test smbclient'''
75     t.info('Testing smbclient')
76     t.chdir('${PREFIX}')
77     t.cmd_contains("bin/smbclient --version", ["Version 4.0"])
78     t.retry_cmd('bin/smbclient -L ${INTERFACE_IP} -U%', ["netlogon", "sysvol", "IPC Service"])
79     child = t.pexpect_spawn('bin/smbclient //${INTERFACE_IP}/netlogon -Uadministrator%${PASSWORD1}')
80     child.expect("smb:")
81     child.sendline("dir")
82     child.expect("blocks available")
83     child.sendline("mkdir testdir")
84     child.expect("smb:")
85     child.sendline("cd testdir")
86     child.expect('testdir')
87     child.sendline("cd ..")
88     child.sendline("rmdir testdir")
89
90
91 def create_shares(t):
92     '''create some test shares'''
93     t.info("Adding test shares")
94     t.chdir('${PREFIX}')
95     t.write_file("etc/smb.conf", '''
96 [test]
97        path = ${PREFIX}/test
98        read only = no
99 [profiles]
100        path = ${PREFIX}/var/profiles
101        read only = no
102     ''',
103                  mode='a')
104     t.run_cmd("mkdir -p test")
105     t.run_cmd("mkdir -p var/profiles")
106
107
108 def set_nameserver(t, nameserver):
109     '''set the nameserver in resolv.conf'''
110     t.write_file("/etc/resolv.conf.wintest", '''
111 # Generated by wintest, the Samba v Windows automated testing system
112 nameserver %s
113
114 # your original resolv.conf appears below:
115 ''' % t.substitute(nameserver))
116     child = t.pexpect_spawn("cat /etc/resolv.conf", crlf=False)
117     i = child.expect(['your original resolv.conf appears below:', pexpect.EOF])
118     if i == 0:
119         child.expect(pexpect.EOF)
120     contents = child.before.lstrip().replace('\r', '')
121     t.write_file('/etc/resolv.conf.wintest', contents, mode='a')
122     t.write_file('/etc/resolv.conf.wintest-bak', contents)
123     t.run_cmd("mv -f /etc/resolv.conf.wintest /etc/resolv.conf")
124     t.resolv_conf_backup = '/etc/resolv.conf.wintest-bak';
125
126
127 def restore_resolv_conf(t):
128     '''restore the /etc/resolv.conf after testing is complete'''
129     if getattr(t, 'resolv_conf_backup', False):
130         t.info("restoring /etc/resolv.conf")
131         t.run_cmd("mv -f %s /etc/resolv.conf" % t.resolv_conf_backup)
132
133 def rndc_cmd(t, cmd, checkfail=True):
134     '''run a rndc command'''
135     t.run_cmd("${RNDC} -c ${PREFIX}/etc/rndc.conf %s" % cmd, checkfail=checkfail)
136
137
138 def restart_bind(t):
139     '''restart the test environment version of bind'''
140     t.info("Restarting bind9")
141     t.putenv('KEYTAB_FILE', '${PREFIX}/private/dns.keytab')
142     t.putenv('KRB5_KTNAME', '${PREFIX}/private/dns.keytab')
143     t.chdir('${PREFIX}')
144     t.run_cmd("mkdir -p var/named/data")
145     t.run_cmd("chown -R ${BIND_USER} var/named")
146
147     nameserver = t.get_nameserver()
148     if nameserver == t.getvar('INTERFACE_IP'):
149         raise RuntimeError("old /etc/resolv.conf must not contain %s as a nameserver, this will create loops with the generated dns configuration" % nameserver)
150     t.setvar('DNSSERVER', nameserver)
151
152     if t.getvar('INTERFACE_IPV6'):
153         ipv6_listen = 'listen-on-v6 port 53 { ${INTERFACE_IPV6}; };'
154     else:
155         ipv6_listen = ''
156     t.setvar('BIND_LISTEN_IPV6', ipv6_listen)
157
158     t.write_file("etc/named.conf", '''
159 options {
160         listen-on port 53 { ${INTERFACE_IP};  };
161         ${BIND_LISTEN_IPV6}
162         directory       "${PREFIX}/var/named";
163         dump-file       "${PREFIX}/var/named/data/cache_dump.db";
164         pid-file        "${PREFIX}/var/named/named.pid";
165         statistics-file "${PREFIX}/var/named/data/named_stats.txt";
166         memstatistics-file "${PREFIX}/var/named/data/named_mem_stats.txt";
167         allow-query     { any; };
168         recursion yes;
169         tkey-gssapi-credential "DNS/${HOSTNAME}.${LCREALM}";
170         tkey-domain "${REALM}";
171         max-cache-ttl 10;
172         max-ncache-ttl 10;
173
174         forward only;
175         forwarders {
176                   ${DNSSERVER};
177         };
178
179 };
180
181 key "rndc-key" {
182         algorithm hmac-md5;
183         secret "lA/cTrno03mt5Ju17ybEYw==";
184 };
185  
186 controls {
187         inet ${INTERFACE_IP} port 953
188         allow { any; } keys { "rndc-key"; };
189 };
190
191 include "${PREFIX}/private/named.conf";
192 ''')
193
194     # add forwarding for the windows domains
195     domains = t.get_domains()
196     for d in domains:
197         t.write_file('etc/named.conf',
198                      '''
199 zone "%s" IN {
200       type forward;
201       forward only;
202       forwarders {
203          %s;
204       };
205 };
206 ''' % (d, domains[d]),
207                      mode='a')
208
209
210     t.write_file("etc/rndc.conf", '''
211 # Start of rndc.conf
212 key "rndc-key" {
213         algorithm hmac-md5;
214         secret "lA/cTrno03mt5Ju17ybEYw==";
215 };
216
217 options {
218         default-key "rndc-key";
219         default-server  ${INTERFACE_IP};
220         default-port 953;
221 };
222 ''')
223
224     set_nameserver(t, t.getvar('INTERFACE_IP'))
225
226     rndc_cmd(t, "stop", checkfail=False)
227     t.port_wait("${INTERFACE_IP}", 53, wait_for_fail=True)
228     t.bind_child = t.run_child("${BIND9} -u ${BIND_USER} -n 1 -c ${PREFIX}/etc/named.conf -g")
229
230     t.port_wait("${INTERFACE_IP}", 53)
231     rndc_cmd(t, "flush")
232
233
234 def test_dns(t):
235     '''test that DNS is OK'''
236     t.info("Testing DNS")
237     t.cmd_contains("host -t SRV _ldap._tcp.${LCREALM}.",
238                  ['_ldap._tcp.${LCREALM} has SRV record 0 100 389 ${HOSTNAME}.${LCREALM}'])
239     t.cmd_contains("host -t SRV  _kerberos._udp.${LCREALM}.",
240                  ['_kerberos._udp.${LCREALM} has SRV record 0 100 88 ${HOSTNAME}.${LCREALM}'])
241     t.cmd_contains("host -t A ${HOSTNAME}.${LCREALM}",
242                  ['${HOSTNAME}.${LCREALM} has address'])
243
244 def test_kerberos(t):
245     '''test that kerberos is OK'''
246     t.info("Testing kerberos")
247     t.run_cmd("kdestroy")
248     t.kinit("administrator@${REALM}", "${PASSWORD1}")
249     # this copes with the differences between MIT and Heimdal klist
250     t.cmd_contains("klist", ["rincipal", "administrator@${REALM}"])
251
252
253 def test_dyndns(t):
254     '''test that dynamic DNS is working'''
255     t.chdir('${PREFIX}')
256     t.run_cmd("sbin/samba_dnsupdate --fail-immediately")
257     rndc_cmd(t, "flush")
258
259
260 def run_winjoin(t, vm):
261     '''join a windows box to our domain'''
262     t.setwinvars(vm)
263
264     t.info("Joining a windows box to the domain")
265     t.vm_poweroff("${WIN_VM}", checkfail=False)
266     t.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
267     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time=True, set_ip=True)
268     child.sendline("netdom join ${WIN_HOSTNAME} /Domain:${LCREALM} /PasswordD:${PASSWORD1} /UserD:administrator")
269     child.expect("The command completed successfully")
270     child.expect("C:")
271     child.sendline("shutdown /r -t 0")
272     t.wait_reboot()
273     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_USER}", "${WIN_PASS}", set_time=True, set_ip=True)
274     child.sendline("ipconfig /registerdns")
275     child.expect("Registration of the DNS resource records for all adapters of this computer has been initiated. Any errors will be reported in the Event Viewer")
276     child.expect("C:")
277
278 def test_winjoin(t, vm):
279     t.info("Checking the windows join is OK")
280     t.chdir('${PREFIX}')
281     t.port_wait("${WIN_IP}", 139)
282     t.retry_cmd('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Uadministrator@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"], retries=100)
283     t.cmd_contains("host -t A ${WIN_HOSTNAME}.${LCREALM}.", ['has address'])
284     t.cmd_contains('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utestallowed@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
285     t.cmd_contains('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -k no -Utestallowed@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
286     t.cmd_contains('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -k yes -Utestallowed@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
287     child = t.open_telnet("${WIN_HOSTNAME}", "${DOMAIN}\\administrator", "${PASSWORD1}")
288     child.sendline("net use t: \\\\${HOSTNAME}.${LCREALM}\\test")
289     child.expect("The command completed successfully")
290     t.vm_poweroff("${WIN_VM}")
291
292
293 def run_dcpromo(t, vm):
294     '''run a dcpromo on windows'''
295     t.setwinvars(vm)
296
297     t.info("Joining a windows VM ${WIN_VM} to the domain as a DC using dcpromo")
298     t.vm_poweroff("${WIN_VM}", checkfail=False)
299     t.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
300     child = t.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip=True)
301     child.sendline("copy /Y con answers.txt")
302     child.sendline('''
303 [DCINSTALL]
304 RebootOnSuccess=Yes
305 RebootOnCompletion=Yes
306 ReplicaOrNewDomain=Replica
307 ReplicaDomainDNSName=${LCREALM}
308 SiteName=Default-First-Site-Name
309 InstallDNS=No
310 ConfirmGc=Yes
311 CreateDNSDelegation=No
312 UserDomain=${LCREALM}
313 UserName=${LCREALM}\\administrator
314 Password=${PASSWORD1}
315 DatabasePath="C:\Windows\NTDS"
316 LogPath="C:\Windows\NTDS"
317 SYSVOLPath="C:\Windows\SYSVOL"
318 SafeModeAdminPassword=${PASSWORD1}
319 \1a
320 ''')
321     child.expect("copied.")
322     child.expect("C:")
323     child.expect("C:")
324     child.sendline("dcpromo /answer:answers.txt")
325     i = child.expect(["You must restart this computer", "failed", "Active Directory Domain Services was not installed", "C:"], timeout=120)
326     if i == 1 or i == 2:
327         raise Exception("dcpromo failed")
328     t.wait_reboot()
329
330
331 def test_dcpromo(t, vm):
332     '''test that dcpromo worked'''
333     t.info("Checking the dcpromo join is OK")
334     t.chdir('${PREFIX}')
335     t.port_wait("${WIN_IP}", 139)
336     t.retry_cmd("host -t A ${WIN_HOSTNAME}.${LCREALM}. ${INTERFACE_IP}",
337                 ['${WIN_HOSTNAME}.${LCREALM} has address'],
338                 retries=30, delay=10, casefold=True)
339     t.retry_cmd('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Uadministrator@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
340     t.cmd_contains("host -t A ${WIN_HOSTNAME}.${LCREALM}.", ['has address'])
341     t.cmd_contains('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utestallowed@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
342
343     t.cmd_contains("bin/samba-tool drs kcc ${HOSTNAME}.${LCREALM} -Uadministrator@${LCREALM}%${PASSWORD1}", ['Consistency check', 'successful'])
344     t.retry_cmd("bin/samba-tool drs kcc ${WIN_HOSTNAME}.${LCREALM} -Uadministrator@${LCREALM}%${PASSWORD1}", ['Consistency check', 'successful'])
345
346     t.kinit("administrator@${REALM}", "${PASSWORD1}")
347
348     # the first replication will transfer the dnsHostname attribute
349     t.cmd_contains("bin/samba-tool drs replicate ${HOSTNAME}.${LCREALM} ${WIN_HOSTNAME} CN=Configuration,${BASEDN} -k yes", ["was successful"])
350
351     for nc in [ '${BASEDN}', 'CN=Configuration,${BASEDN}', 'CN=Schema,CN=Configuration,${BASEDN}' ]:
352         t.cmd_contains("bin/samba-tool drs replicate ${HOSTNAME}.${LCREALM} ${WIN_HOSTNAME}.${LCREALM} %s -k yes" % nc, ["was successful"])
353         t.cmd_contains("bin/samba-tool drs replicate ${WIN_HOSTNAME}.${LCREALM} ${HOSTNAME}.${LCREALM} %s -k yes" % nc, ["was successful"])
354
355     t.cmd_contains("bin/samba-tool drs showrepl ${HOSTNAME}.${LCREALM} -k yes",
356                  [ "INBOUND NEIGHBORS",
357                    "${BASEDN}",
358                    "Last attempt .* was successful",
359                    "CN=Configuration,${BASEDN}",
360                    "Last attempt .* was successful",
361                    "CN=Configuration,${BASEDN}", # cope with either order
362                    "Last attempt .* was successful",
363                    "OUTBOUND NEIGHBORS",
364                    "${BASEDN}",
365                    "Last success",
366                    "CN=Configuration,${BASEDN}",
367                    "Last success",
368                    "CN=Configuration,${BASEDN}",
369                    "Last success"],
370                    ordered=True,
371                    regex=True)
372
373     t.cmd_contains("bin/samba-tool drs showrepl ${WIN_HOSTNAME}.${LCREALM} -k yes",
374                  [ "INBOUND NEIGHBORS",
375                    "${BASEDN}",
376                    "Last attempt .* was successful",
377                    "CN=Configuration,${BASEDN}",
378                    "Last attempt .* was successful",
379                    "CN=Configuration,${BASEDN}",
380                    "Last attempt .* was successful",
381                    "OUTBOUND NEIGHBORS",
382                    "${BASEDN}",
383                    "Last success",
384                    "CN=Configuration,${BASEDN}",
385                    "Last success",
386                    "CN=Configuration,${BASEDN}",
387                    "Last success" ],
388                    ordered=True,
389                    regex=True)
390
391     child = t.open_telnet("${WIN_HOSTNAME}", "${DOMAIN}\\administrator", "${PASSWORD1}", set_time=True)
392     child.sendline("net use t: \\\\${HOSTNAME}.${LCREALM}\\test")
393     child.expect("The command completed successfully")
394
395     t.run_net_time(child)
396
397     t.info("Checking if showrepl is happy")
398     child.sendline("repadmin /showrepl")
399     child.expect("${BASEDN}")
400     child.expect("was successful")
401     child.expect("CN=Configuration,${BASEDN}")
402     child.expect("was successful")
403     child.expect("CN=Schema,CN=Configuration,${BASEDN}")
404     child.expect("was successful")
405
406     t.info("Checking if new users propogate to windows")
407     t.retry_cmd('bin/samba-tool newuser test2 ${PASSWORD2}', ["created successfully"])
408     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k no", ['Sharename', 'Remote IPC'])
409     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k yes", ['Sharename', 'Remote IPC'])
410
411     t.info("Checking if new users on windows propogate to samba")
412     child.sendline("net user test3 ${PASSWORD3} /add")
413     while True:
414         i = child.expect(["The command completed successfully",
415                           "The directory service was unable to allocate a relative identifier"])
416         if i == 0:
417             break
418         time.sleep(2)
419
420     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${LCREALM} -Utest3%${PASSWORD3} -k no", ['Sharename', 'IPC'])
421     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${LCREALM} -Utest3%${PASSWORD3} -k yes", ['Sharename', 'IPC'])
422
423     t.info("Checking propogation of user deletion")
424     t.run_cmd('bin/samba-tool user delete test2 -Uadministrator@${LCREALM}%${PASSWORD1}')
425     child.sendline("net user test3 /del")
426     child.expect("The command completed successfully")
427
428     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k no", ['LOGON_FAILURE'])
429     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${LCREALM} -Utest3%${PASSWORD3} -k no", ['LOGON_FAILURE'])
430     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k yes", ['LOGON_FAILURE'])
431     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${LCREALM} -Utest3%${PASSWORD3} -k yes", ['LOGON_FAILURE'])
432     t.vm_poweroff("${WIN_VM}")
433
434
435 def run_dcpromo_rodc(t, vm):
436     '''run a RODC dcpromo to join a windows DC to the samba domain'''
437     t.setwinvars(vm)
438     t.info("Joining a w2k8 box to the domain as a RODC")
439     t.vm_poweroff("${WIN_VM}", checkfail=False)
440     t.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
441     child = t.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip=True)
442     child.sendline("copy /Y con answers.txt")
443     child.sendline('''
444 [DCInstall]
445 ReplicaOrNewDomain=ReadOnlyReplica
446 ReplicaDomainDNSName=${LCREALM}
447 PasswordReplicationDenied="BUILTIN\Administrators"
448 PasswordReplicationDenied="BUILTIN\Server Operators"
449 PasswordReplicationDenied="BUILTIN\Backup Operators"
450 PasswordReplicationDenied="BUILTIN\Account Operators"
451 PasswordReplicationDenied="${DOMAIN}\Denied RODC Password Replication Group"
452 PasswordReplicationAllowed="${DOMAIN}\Allowed RODC Password Replication Group"
453 DelegatedAdmin="${DOMAIN}\\Administrator"
454 SiteName=Default-First-Site-Name
455 InstallDNS=No
456 ConfirmGc=Yes
457 CreateDNSDelegation=No
458 UserDomain=${LCREALM}
459 UserName=${LCREALM}\\administrator
460 Password=${PASSWORD1}
461 DatabasePath="C:\Windows\NTDS"
462 LogPath="C:\Windows\NTDS"
463 SYSVOLPath="C:\Windows\SYSVOL"
464 SafeModeAdminPassword=${PASSWORD1}
465 RebootOnCompletion=No
466 \1a
467 ''')
468     child.expect("copied.")
469     child.sendline("dcpromo /answer:answers.txt")
470     i = child.expect(["You must restart this computer", "failed"], timeout=120)
471     if i != 0:
472         raise Exception("dcpromo failed")
473     child.sendline("shutdown -r -t 0")
474     t.wait_reboot()
475
476
477
478 def test_dcpromo_rodc(t, vm):
479     '''test the RODC dcpromo worked'''
480     t.info("Checking the w2k8 RODC join is OK")
481     t.chdir('${PREFIX}')
482     t.port_wait("${WIN_IP}", 139)
483     t.retry_cmd('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Uadministrator@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
484     t.cmd_contains("host -t A ${WIN_HOSTNAME}.${LCREALM}.", ['has address'])
485     t.cmd_contains('bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utestallowed@${LCREALM}%${PASSWORD1}', ["C$", "IPC$", "Sharename"])
486     child = t.open_telnet("${WIN_HOSTNAME}", "${DOMAIN}\\administrator", "${PASSWORD1}", set_time=True)
487     child.sendline("net use t: \\\\${HOSTNAME}.${LCREALM}\\test")
488     child.expect("The command completed successfully")
489
490     t.info("Checking if showrepl is happy")
491     child.sendline("repadmin /showrepl")
492     child.expect("${BASEDN}")
493     child.expect("was successful")
494     child.expect("CN=Configuration,${BASEDN}")
495     child.expect("was successful")
496     child.expect("CN=Configuration,${BASEDN}")
497     child.expect("was successful")
498
499     t.info("Checking if new users are available on windows")
500     t.run_cmd('bin/samba-tool newuser test2 ${PASSWORD2}')
501     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k yes", ['Sharename', 'Remote IPC'])
502     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k no", ['LOGON_FAILURE'])
503     t.retry_cmd("bin/samba-tool drs replicate ${WIN_HOSTNAME}.${LCREALM} ${HOSTNAME}.${LCREALM} ${BASEDN} -k yes", ["was successful"])
504     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k no", ['Sharename', 'Remote IPC'])
505     t.run_cmd('bin/samba-tool user delete test2 -Uadministrator@${LCREALM}%${PASSWORD1}')
506     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k yes", ['LOGON_FAILURE'])
507     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${LCREALM} -Utest2%${PASSWORD2} -k no", ['LOGON_FAILURE'])
508     t.vm_poweroff("${WIN_VM}")
509
510
511 def prep_join_as_dc(t, vm):
512     '''start VM and shutdown Samba in preperation to join a windows domain as a DC'''
513     t.setwinvars(vm)
514     t.info("Starting VMs for joining ${WIN_VM} as a second DC using samba-tool join DC")
515     t.chdir('${PREFIX}')
516     t.run_cmd('killall -9 -q samba smbd nmbd winbindd', checkfail=False)
517     t.vm_poweroff("${WIN_VM}", checkfail=False)
518     t.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
519     rndc_cmd(t, 'flush')
520     t.run_cmd("rm -rf etc/smb.conf private")
521     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_DOMAIN}\\administrator", "${WIN_PASS}", set_time=True)
522     t.get_ipconfig(child)
523
524 def join_as_dc(t, vm):
525     '''join a windows domain as a DC'''
526     t.setwinvars(vm)
527     t.info("Joining ${WIN_VM} as a second DC using samba-tool join DC")
528     t.retry_cmd("bin/samba-tool drs showrepl ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator%${WIN_PASS}", ['INBOUND NEIGHBORS'] )
529     t.run_cmd('bin/samba-tool join ${WIN_REALM} DC -Uadministrator%${WIN_PASS} -d${DEBUGLEVEL} --option=interfaces=${INTERFACE}')
530     t.run_cmd('bin/samba-tool drs kcc ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
531
532
533 def test_join_as_dc(t, vm):
534     '''test the join of a windows domain as a DC'''
535     t.info("Checking the DC join is OK")
536     t.chdir('${PREFIX}')
537     t.retry_cmd('bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}', ["C$", "IPC$", "Sharename"])
538     t.cmd_contains("host -t A ${HOSTNAME}.${WIN_REALM}.", ['has address'])
539     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_DOMAIN}\\administrator", "${WIN_PASS}", set_time=True)
540
541     t.info("Forcing kcc runs, and replication")
542     t.run_cmd('bin/samba-tool drs kcc ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
543     t.run_cmd('bin/samba-tool drs kcc ${HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
544
545     t.kinit("administrator@${WIN_REALM}", "${WIN_PASS}")
546     for nc in [ '${WIN_BASEDN}', 'CN=Configuration,${WIN_BASEDN}', 'CN=Schema,CN=Configuration,${WIN_BASEDN}' ]:
547         t.cmd_contains("bin/samba-tool drs replicate ${HOSTNAME}.${WIN_REALM} ${WIN_HOSTNAME}.${WIN_REALM} %s -k yes" % nc, ["was successful"])
548         t.cmd_contains("bin/samba-tool drs replicate ${WIN_HOSTNAME}.${WIN_REALM} ${HOSTNAME}.${WIN_REALM} %s -k yes" % nc, ["was successful"])
549
550     child.sendline("net use t: \\\\${HOSTNAME}.${WIN_REALM}\\test")
551     child.expect("The command completed successfully")
552
553     t.info("Checking if showrepl is happy")
554     child.sendline("repadmin /showrepl")
555     child.expect("${WIN_BASEDN}")
556     child.expect("was successful")
557     child.expect("CN=Configuration,${WIN_BASEDN}")
558     child.expect("was successful")
559     child.expect("CN=Configuration,${WIN_BASEDN}")
560     child.expect("was successful")
561
562     t.info("Checking if new users propogate to windows")
563     t.run_cmd('bin/samba-tool newuser test2 ${PASSWORD2}')
564     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${WIN_REALM} -Utest2%${PASSWORD2} -k no", ['Sharename', 'Remote IPC'])
565     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${WIN_REALM} -Utest2%${PASSWORD2} -k yes", ['Sharename', 'Remote IPC'])
566
567     t.info("Checking if new users on windows propogate to samba")
568     child.sendline("net user test3 ${PASSWORD3} /add")
569     child.expect("The command completed successfully")
570     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k no", ['Sharename', 'IPC'])
571     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k yes", ['Sharename', 'IPC'])
572
573     t.info("Checking propogation of user deletion")
574     t.run_cmd('bin/samba-tool user delete test2 -Uadministrator@${WIN_REALM}%${WIN_PASS}')
575     child.sendline("net user test3 /del")
576     child.expect("The command completed successfully")
577
578     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${WIN_REALM} -Utest2%${PASSWORD2} -k no", ['LOGON_FAILURE'])
579     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k no", ['LOGON_FAILURE'])
580     t.retry_cmd("bin/smbclient -L ${WIN_HOSTNAME}.${WIN_REALM} -Utest2%${PASSWORD2} -k yes", ['LOGON_FAILURE'])
581     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k yes", ['LOGON_FAILURE'])
582     t.vm_poweroff("${WIN_VM}")
583
584
585 def join_as_rodc(t, vm):
586     '''join a windows domain as a RODC'''
587     t.setwinvars(vm)
588     t.info("Joining ${WIN_VM} as a RODC using samba-tool join DC")
589     t.chdir('${PREFIX}')
590     t.run_cmd('killall -9 -q samba smbd nmbd winbindd', checkfail=False)
591     t.vm_poweroff("${WIN_VM}", checkfail=False)
592     t.vm_restore("${WIN_VM}", "${WIN_SNAPSHOT}")
593     rndc_cmd(t, 'flush')
594     t.run_cmd("rm -rf etc/smb.conf private")
595     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_DOMAIN}\\administrator", "${WIN_PASS}", set_time=True)
596     t.get_ipconfig(child)
597     t.retry_cmd("bin/samba-tool drs showrepl ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator%${WIN_PASS}", ['INBOUND NEIGHBORS'] )
598     t.run_cmd('bin/samba-tool join ${WIN_REALM} RODC -Uadministrator%${WIN_PASS} -d${DEBUGLEVEL} --option=interfaces=${INTERFACE}')
599     t.run_cmd('bin/samba-tool drs kcc ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
600
601
602 def test_join_as_rodc(t, vm):
603     '''test a windows domain RODC join'''
604     t.info("Checking the RODC join is OK")
605     t.chdir('${PREFIX}')
606     t.retry_cmd('bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}', ["C$", "IPC$", "Sharename"])
607     t.cmd_contains("host -t A ${HOSTNAME}.${WIN_REALM}.", ['has address'])
608     child = t.open_telnet("${WIN_HOSTNAME}", "${WIN_DOMAIN}\\administrator", "${WIN_PASS}", set_time=True)
609
610     t.info("Forcing kcc runs, and replication")
611     t.run_cmd('bin/samba-tool drs kcc ${HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
612     t.run_cmd('bin/samba-tool drs kcc ${WIN_HOSTNAME}.${WIN_REALM} -Uadministrator@${WIN_REALM}%${WIN_PASS}')
613
614     t.kinit("administrator@${WIN_REALM}", "${WIN_PASS}")
615     for nc in [ '${WIN_BASEDN}', 'CN=Configuration,${WIN_BASEDN}', 'CN=Schema,CN=Configuration,${WIN_BASEDN}' ]:
616         t.cmd_contains("bin/samba-tool drs replicate ${HOSTNAME}.${WIN_REALM} ${WIN_HOSTNAME}.${WIN_REALM} %s -k yes" % nc, ["was successful"])
617
618     child.sendline("net use t: \\\\${HOSTNAME}.${WIN_REALM}\\test")
619     child.expect("The command completed successfully")
620
621     t.info("Checking if showrepl is happy")
622     child.sendline("repadmin /showrepl")
623     child.expect("DSA invocationID")
624
625     t.cmd_contains("bin/samba-tool drs showrepl ${WIN_HOSTNAME}.${WIN_REALM} -k yes",
626                  [ "INBOUND NEIGHBORS",
627                    "OUTBOUND NEIGHBORS",
628                    "${WIN_BASEDN}",
629                    "Last attempt .* was successful",
630                    "CN=Configuration,${WIN_BASEDN}",
631                    "Last attempt .* was successful",
632                    "CN=Configuration,${WIN_BASEDN}",
633                    "Last attempt .* was successful" ],
634                    ordered=True,
635                    regex=True)
636
637     t.info("Checking if new users on windows propogate to samba")
638     child.sendline("net user test3 ${PASSWORD3} /add")
639     child.expect("The command completed successfully")
640     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k no", ['Sharename', 'IPC'])
641     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k yes", ['Sharename', 'IPC'])
642
643     # should this work?
644     t.info("Checking if new users propogate to windows")
645     t.cmd_contains('bin/samba-tool newuser test2 ${PASSWORD2}', ['No RID Set DN'])
646
647     t.info("Checking propogation of user deletion")
648     child.sendline("net user test3 /del")
649     child.expect("The command completed successfully")
650
651     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k no", ['LOGON_FAILURE'])
652     t.retry_cmd("bin/smbclient -L ${HOSTNAME}.${WIN_REALM} -Utest3%${PASSWORD3} -k yes", ['LOGON_FAILURE'])
653     t.vm_poweroff("${WIN_VM}")
654
655
656 def run_dcpromo_as_first_dc(t, vm, func_level=None):
657     t.setwinvars(vm)
658     t.info("Configuring a windows VM ${WIN_VM} at the first DC in the domain using dcpromo")
659     child = t.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_time=True)
660     child.sendline("dcdiag");
661     if t.get_is_dc(child):
662         return
663
664     if func_level == '2008r2':
665         t.setvar("FUNCTION_LEVEL_INT", str(4))
666     elif func_level == '2003':
667         t.setvar("FUNCTION_LEVEL_INT", str(1))
668     else:
669         t.setvar("FUNCTION_LEVEL_INT", str(0))
670
671     child = t.open_telnet("${WIN_HOSTNAME}", "administrator", "${WIN_PASS}", set_ip=True)
672     child.sendline("dcdiag");
673
674     """This server must therefore not yet be a directory server, so we must promote it"""
675     child.sendline("copy /Y con answers.txt")
676     child.sendline('''
677 [DCInstall]
678 ; New forest promotion
679 ReplicaOrNewDomain=Domain
680 NewDomain=Forest
681 NewDomainDNSName=${WIN_REALM}
682 ForestLevel=${FUNCTION_LEVEL_INT}
683 DomainNetbiosName=${WIN_DOMAIN}
684 DomainLevel=${FUNCTION_LEVEL_INT}
685 InstallDNS=Yes
686 ConfirmGc=Yes
687 CreateDNSDelegation=No
688 DatabasePath="C:\Windows\NTDS"
689 LogPath="C:\Windows\NTDS"
690 SYSVOLPath="C:\Windows\SYSVOL"
691 ; Set SafeModeAdminPassword to the correct value prior to using the unattend file
692 SafeModeAdminPassword=${WIN_PASS}
693 ; Run-time flags (optional)
694 RebootOnCompletion=No
695 \1a
696 ''')
697     child.expect("copied.")
698     child.expect("C:")
699     child.expect("C:")
700     child.sendline("dcpromo /answer:answers.txt")
701     i = child.expect(["You must restart this computer", "failed", "Active Directory Domain Services was not installed", "C:"], timeout=120)
702     if i == 1 or i == 2:
703         raise Exception("dcpromo failed")
704     child.sendline("shutdown -r -t 0")
705     t.port_wait("${WIN_IP}", 139, wait_for_fail=True)
706     t.port_wait("${WIN_IP}", 139)
707
708 def test_howto(t):
709     '''test the Samba4 howto'''
710
711     check_prerequesites(t)
712
713     # we don't need fsync safety in these tests
714     t.putenv('TDB_NO_FSYNC', '1')
715
716     if not t.skip("build"):
717         build_s4(t)
718
719     if not t.skip("provision"):
720         provision_s4(t)
721
722     if not t.skip("create-shares"):
723         create_shares(t)
724
725     if not t.skip("starts4"):
726         start_s4(t)
727     if not t.skip("stop_vms"):
728         stop_vms(t)
729     if not t.skip("smbclient"):
730         test_smbclient(t)
731     if not t.skip("startbind"):
732         restart_bind(t)
733     if not t.skip("dns"):
734         test_dns(t)
735     if not t.skip("kerberos"):
736         test_kerberos(t)
737     if not t.skip("dyndns"):
738         test_dyndns(t)
739
740     if t.have_vm('WINDOWS7') and not t.skip("windows7"):
741         run_winjoin(t, "WINDOWS7")
742         test_winjoin(t, "WINDOWS7")
743
744     if t.have_vm('WINXP') and not t.skip("winxp"):
745         run_winjoin(t, "WINXP")
746         test_winjoin(t, "WINXP")
747
748     if t.have_vm('W2K8R2C') and not t.skip("dcpromo_rodc"):
749         t.info("Testing w2k8r2 RODC dcpromo")
750         run_dcpromo_rodc(t, "W2K8R2C")
751         test_dcpromo_rodc(t, "W2K8R2C")
752
753     if t.have_vm('W2K8R2B') and not t.skip("dcpromo_w2k8r2"):
754         t.info("Testing w2k8r2 dcpromo")
755         run_dcpromo(t, "W2K8R2B")
756         test_dcpromo(t, "W2K8R2B")
757
758     if t.have_vm('W2K8B') and not t.skip("dcpromo_w2k8"):
759         t.info("Testing w2k8 dcpromo")
760         run_dcpromo(t, "W2K8B")
761         test_dcpromo(t, "W2K8B")
762
763     if t.have_vm('W2K3B') and not t.skip("dcpromo_w2k3"):
764         t.info("Testing w2k3 dcpromo")
765         t.info("Changing to 2003 functional level")
766         provision_s4(t, func_level='2003')
767         create_shares(t)
768         start_s4(t)
769         test_smbclient(t)
770         restart_bind(t)
771         test_dns(t)
772         test_kerberos(t)
773         test_dyndns(t)
774         run_dcpromo(t, "W2K3B")
775         test_dcpromo(t, "W2K3B")
776
777     if t.have_vm('W2K8R2A') and not t.skip("join_w2k8r2"):
778         prep_join_as_dc(t, "W2K8R2A")
779         run_dcpromo_as_first_dc(t, "W2K8R2A", func_level='2008r2')
780         join_as_dc(t, "W2K8R2A")
781         create_shares(t)
782         start_s4(t)
783         test_dyndns(t)
784         test_join_as_dc(t, "W2K8R2A")
785
786     if t.have_vm('W2K8R2A') and not t.skip("join_rodc"):
787         prep_join_as_rodc(t, "W2K8R2A")
788         run_dcpromo_as_first_dc(t, "W2K8R2A", func_level='2008r2')
789         join_as_rodc(t, "W2K8R2A")
790         create_shares(t)
791         start_s4(t)
792         test_dyndns(t)
793         test_join_as_rodc(t, "W2K8R2A")
794
795     if t.have_vm('W2K3A') and not t.skip("join_w2k3"):
796         prep_join_as_dc(t, "W2K3A")
797         run_dcpromo_as_first_dc(t, "W2K3A", func_level='2003')
798         join_as_dc(t, "W2K3A")
799         create_shares(t)
800         start_s4(t)
801         test_dyndns(t)
802         test_join_as_dc(t, "W2K3A")
803
804     t.info("Howto test: All OK")
805
806
807 def test_cleanup(t):
808     '''cleanup after tests'''
809     t.info("Cleaning up ...")
810     restore_resolv_conf(t)
811     if getattr(t, 'bind_child', False):
812         t.bind_child.kill()
813
814
815 if __name__ == '__main__':
816     parser = optparse.OptionParser("test-howto.py")
817     parser.add_option("--conf", type='string', default='', help='config file')
818     parser.add_option("--skip", type='string', default='', help='list of steps to skip (comma separated)')
819     parser.add_option("--vms", type='string', default=None, help='list of VMs to use (comma separated)')
820     parser.add_option("--list", action='store_true', default=False, help='list the available steps')
821     parser.add_option("--rebase", action='store_true', default=False, help='do a git pull --rebase')
822     parser.add_option("--clean", action='store_true', default=False, help='clean the tree')
823     parser.add_option("--prefix", type='string', default=None, help='override install prefix')
824     parser.add_option("--sourcetree", type='string', default=None, help='override sourcetree location')
825     parser.add_option("--nocleanup", action='store_true', default=False, help='disable cleanup code')
826
827     opts, args = parser.parse_args()
828
829     if not opts.conf:
830         print("Please specify a config file with --conf")
831         sys.exit(1)
832
833     t = wintest.wintest()
834     t.load_config(opts.conf)
835
836     t.set_skip(opts.skip)
837     t.set_vms(opts.vms)
838
839     if opts.list:
840         t.list_steps_mode()
841
842     if opts.prefix:
843         t.setvar('PREFIX', opts.prefix)
844
845     if opts.sourcetree:
846         t.setvar('SOURCETREE', opts.sourcetree)
847
848     if opts.rebase:
849         t.info('rebasing')
850         t.chdir('${SOURCETREE}')
851         t.run_cmd('git pull --rebase')
852
853     if opts.clean:
854         t.info('rebasing')
855         t.chdir('${SOURCETREE}/source4')
856         t.run_cmd('rm -rf bin')
857
858     try:
859         test_howto(t)
860     except:
861         if not opts.nocleanup:
862             test_cleanup(t)
863         raise
864
865     if not opts.nocleanup:
866         test_cleanup(t)
867     t.info("S4 howto test: All OK")