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