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