libndr: Avoid assigning duplicate versions to symbols
[amitay/samba.git] / selftest / target / Samba.pm
1 #!/usr/bin/perl
2 # Bootstrap Samba and run a number of tests against it.
3 # Copyright (C) 2005-2007 Jelmer Vernooij <jelmer@samba.org>
4 # Published under the GNU GPL, v3 or later.
5
6 package Samba;
7
8 use strict;
9 use warnings;
10 use target::Samba3;
11 use target::Samba4;
12 use POSIX;
13 use Cwd qw(abs_path);
14 use IO::Poll qw(POLLIN);
15
16 sub new($$$$$) {
17         my ($classname, $bindir, $srcdir, $server_maxtime,
18             $opt_socket_wrapper_pcap, $opt_socket_wrapper_keep_pcap) = @_;
19
20         my $self = {
21             opt_socket_wrapper_pcap => $opt_socket_wrapper_pcap,
22             opt_socket_wrapper_keep_pcap => $opt_socket_wrapper_keep_pcap,
23         };
24         $self->{samba3} = new Samba3($self, $bindir, $srcdir, $server_maxtime);
25         $self->{samba4} = new Samba4($self, $bindir, $srcdir, $server_maxtime);
26         bless $self;
27         return $self;
28 }
29
30 %Samba::ENV_DEPS = (%Samba3::ENV_DEPS, %Samba4::ENV_DEPS);
31 our %ENV_DEPS;
32
33 %Samba::ENV_DEPS_POST = (%Samba3::ENV_DEPS_POST, %Samba4::ENV_DEPS_POST);
34 our %ENV_DEPS_POST;
35
36 %Samba::ENV_TARGETS = (
37         (map { $_ => "Samba3" } keys %Samba3::ENV_DEPS),
38         (map { $_ => "Samba4" } keys %Samba4::ENV_DEPS),
39 );
40 our %ENV_TARGETS;
41
42 %Samba::ENV_NEEDS_AD_DC = (
43         (map { $_ => 1 } keys %Samba4::ENV_DEPS)
44 );
45 our %ENV_NEEDS_AD_DC;
46 foreach my $env (keys %Samba3::ENV_DEPS) {
47     $ENV_NEEDS_AD_DC{$env} = ($env =~ /^ad_/);
48 }
49
50 sub setup_pcap($$)
51 {
52         my ($self, $name) = @_;
53
54         return unless ($self->{opt_socket_wrapper_pcap});
55         return unless defined($ENV{SOCKET_WRAPPER_PCAP_DIR});
56
57         my $fname = $name;
58         $fname =~ s%[^abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789\-]%_%g;
59
60         my $pcap_file = "$ENV{SOCKET_WRAPPER_PCAP_DIR}/$fname.pcap";
61
62         SocketWrapper::setup_pcap($pcap_file);
63
64         return $pcap_file;
65 }
66
67 sub cleanup_pcap($$$)
68 {
69         my ($self, $pcap_file, $exitcode) = @_;
70
71         return unless ($self->{opt_socket_wrapper_pcap});
72         return if ($self->{opt_socket_wrapper_keep_pcap});
73         return unless ($exitcode == 0);
74         return unless defined($pcap_file);
75
76         unlink($pcap_file);
77 }
78
79 sub setup_env($$$)
80 {
81         my ($self, $envname, $path) = @_;
82
83         my $targetname = $ENV_TARGETS{$envname};
84         if (not defined($targetname)) {
85                 warn("Samba can't provide environment '$envname'");
86                 return "UNKNOWN";
87         }
88
89         my %targetlookup = (
90                 "Samba3" => $self->{samba3},
91                 "Samba4" => $self->{samba4}
92         );
93         my $target = $targetlookup{$targetname};
94
95         if (defined($target->{vars}->{$envname})) {
96                 return $target->{vars}->{$envname};
97         }
98
99         $target->{vars}->{$envname} = "";
100
101         my @dep_vars;
102         foreach(@{$ENV_DEPS{$envname}}) {
103                 my $vars = $self->setup_env($_, $path);
104                 if (defined($vars)) {
105                         push(@dep_vars, $vars);
106                 } else {
107                         warn("Failed setting up $_ as a dependency of $envname");
108                         return undef;
109                 }
110         }
111
112         $ENV{ENVNAME} = $envname;
113         # Avoid hitting system krb5.conf -
114         # An env that needs Kerberos will reset this to the real value.
115         $ENV{KRB5_CONFIG} = "$path/no_krb5.conf";
116         $ENV{RESOLV_CONF} = "$path/no_resolv.conf";
117
118         my $setup_name = $ENV_TARGETS{$envname}."::setup_".$envname;
119         my $setup_sub = \&$setup_name;
120         my $setup_pcap_file = $self->setup_pcap("env-$ENV{ENVNAME}-setup");
121         my $env = &$setup_sub($target, "$path/$envname", @dep_vars);
122         $self->cleanup_pcap($setup_pcap_file, not defined($env));
123         SocketWrapper::setup_pcap(undef);
124
125         if (not defined($env)) {
126                 warn("failed to start up environment '$envname'");
127                 return undef;
128         }
129
130         $target->{vars}->{$envname} = $env;
131         $target->{vars}->{$envname}->{target} = $target;
132
133         foreach(@{$ENV_DEPS_POST{$envname}}) {
134                 if (not defined $_) {
135                         continue;
136                 }
137                 my $vars = $self->setup_env($_, $path);
138                 if (not defined($vars)) {
139                         return undef;
140                 }
141         }
142
143         return $env;
144 }
145
146 sub bindir_path($$) {
147         my ($object, $path) = @_;
148
149         my $valpath = "$object->{bindir}/$path";
150         my $python_cmd = "";
151         my $result = $path;
152         if (defined $ENV{'PYTHON'}) {
153                 $python_cmd = $ENV{'PYTHON'} . " ";
154         }
155
156         if (-f $valpath or -d $valpath) {
157                 $result = $valpath;
158         }
159         # make sure we prepend samba-tool with calling $PYTHON python version
160         if ($path eq "samba-tool") {
161                 $result = $python_cmd . $result;
162         }
163         return $result;
164 }
165
166 sub nss_wrapper_winbind_so_path($) {
167         my ($object) = @_;
168         my $ret = $ENV{NSS_WRAPPER_WINBIND_SO_PATH};
169         if (not defined($ret)) {
170             $ret = bindir_path($object, "shared/libnss_wrapper_winbind.so.2");
171             $ret = abs_path($ret);
172         }
173         return $ret;
174 }
175
176 sub copy_file_content($$)
177 {
178         my ($in, $out) = @_;
179         open(IN, "${in}") or die("failed to open in[${in}] for reading: $!");
180         open(OUT, ">${out}") or die("failed to open out[${out}] for writing: $!");
181         while(<IN>) {
182                 print OUT $_;
183         }
184         close(OUT);
185         close(IN);
186 }
187
188 sub prepare_keyblobs($)
189 {
190         my ($ctx) = @_;
191
192         my $cadir = "$ENV{SRCDIR_ABS}/selftest/manage-ca/CA-samba.example.com";
193         my $cacert = "$cadir/Public/CA-samba.example.com-cert.pem";
194         my $cacrl_pem = "$cadir/Public/CA-samba.example.com-crl.pem";
195         my $dcdnsname = "$ctx->{hostname}.$ctx->{dnsname}";
196         my $dcdir = "$cadir/DCs/$dcdnsname";
197         my $dccert = "$dcdir/DC-$dcdnsname-cert.pem";
198         my $dckey_private = "$dcdir/DC-$dcdnsname-private-key.pem";
199         my $adminprincipalname = "administrator\@$ctx->{dnsname}";
200         my $admindir = "$cadir/Users/$adminprincipalname";
201         my $admincert = "$admindir/USER-$adminprincipalname-cert.pem";
202         my $adminkey_private = "$admindir/USER-$adminprincipalname-private-key.pem";
203         my $pkinitprincipalname = "pkinit\@$ctx->{dnsname}";
204         my $ca_pkinitdir = "$cadir/Users/$pkinitprincipalname";
205         my $pkinitcert = "$ca_pkinitdir/USER-$pkinitprincipalname-cert.pem";
206         my $pkinitkey_private = "$ca_pkinitdir/USER-$pkinitprincipalname-private-key.pem";
207
208         my $tlsdir = "$ctx->{tlsdir}";
209         my $pkinitdir = "$ctx->{prefix_abs}/pkinit";
210         #TLS and PKINIT crypto blobs
211         my $dhfile = "$tlsdir/dhparms.pem";
212         my $cafile = "$tlsdir/ca.pem";
213         my $crlfile = "$tlsdir/crl.pem";
214         my $certfile = "$tlsdir/cert.pem";
215         my $keyfile = "$tlsdir/key.pem";
216         my $admincertfile = "$pkinitdir/USER-$adminprincipalname-cert.pem";
217         my $adminkeyfile = "$pkinitdir/USER-$adminprincipalname-private-key.pem";
218         my $pkinitcertfile = "$pkinitdir/USER-$pkinitprincipalname-cert.pem";
219         my $pkinitkeyfile = "$pkinitdir/USER-$pkinitprincipalname-private-key.pem";
220
221         mkdir($tlsdir, 0700);
222         mkdir($pkinitdir, 0700);
223         my $oldumask = umask;
224         umask 0077;
225
226         # This is specified here to avoid draining entropy on every run
227         # generate by
228         # openssl dhparam -out dhparms.pem -text -2 8192
229         open(DHFILE, ">$dhfile");
230         print DHFILE <<EOF;
231 -----BEGIN DH PARAMETERS-----
232 MIIECAKCBAEAlcpjuJptCzC2bIIApLuyFLw2nODQUztqs/peysY9e3LgWh/xrc87
233 SWJNSUrqFJFh2m357WH0XGcTdTk0b/8aIYIWjbwEhWR/5hZ+1x2TDrX1awkYayAe
234 pr0arycmWHaAmhw+m+dBdj2O2jRMe7gn0ha85JALNl+Z3wv2q2eys8TIiQ2dbHPx
235 XvpMmlAv7QHZnpSpX/XgueQr6T3EYggljppZwk1fe4W2cxBjCv9w/Q83pJXMEVVB
236 WESEQPZC38v6hVIXIlF4J7jXjV3+NtCLL4nvsy0jrLEntyKz5OB8sNPRzJr0Ju2Y
237 yXORCSMMXMygP+dxJtQ6txzQYWyaCYN1HqHDZy3cFL9Qy8kTFqIcW56Lti2GsW/p
238 jSMzEOa1NevhKNFL3dSZJx5m+5ZeMvWXlCqXSptmVdbs5wz5jkMUm/E6pVfM5lyb
239 Ttlcq2iYPqnJz1jcL5xwhoufID8zSJCPJ7C0jb0Ngy5wLIUZfjXJUXxUyxTnNR9i
240 N9Sc+UkDvLxnCW+qzjyPXGlQU1SsJwMLWa2ZecL/uYE4bOdcN3g+5WHkevyDnXqR
241 +yy9x7sGXjBT3bRWK5tVHJWOi6eBu1hp39U6aK8oOJWiUt3vmC2qEdIsT6JaLNNi
242 YKrSfRGBf19IJBaagen1S19bb3dnmwoU1RaWM0EeJQW1oXOBg7zLisB2yuu5azBn
243 tse00+0nc+GbH2y+jP0sE7xil1QeilZl+aQ3tX9vL0cnCa+8602kXxU7P5HaX2+d
244 05pvoHmeZbDV85io36oF976gBYeYN+qAkTUMsIZhuLQDuyn0963XOLyn1Pm6SBrU
245 OkIZXW7WoKEuO/YSfizUIqXwmAMJjnEMJCWG51MZZKx//9Hsdp1RXSm/bRSbvXB7
246 MscjvQYWmfCFnIk8LYnEt3Yey40srEiS9xyZqdrvobxz+sU1XcqR38kpVf4gKASL
247 xURia64s4emuJF+YHIObyydazQ+6/wX/C+m+nyfhuxSO6j1janPwtYbU+Uj3TzeM
248 04K1mpPQpZcaMdZZiNiu7i8VJlOPKAz7aJT8TnMMF5GMyzyLpSMpc+NF9L/BSocV
249 /cUM4wQT2PTHrcyYzmTVH7c9bzBkuxqrwVB1BY1jitDV9LIYIVBglKcX88qrfHIM
250 XiXPAIwGclD59qm2cG8OdM9NA5pNMI119KuUAIJsUdgPbR1LkT2XTT15YVoHmFSQ
251 DlaWOXn4td031jr0EisX8QtFR7+/0Nfoni6ydFGs5fNH/L1ckq6FEO4OhgucJw9H
252 YRmiFlsQBQNny78vNchwZne3ZixkShtGW0hWDdi2n+h7St1peNJCNJjMbEhRsPRx
253 RmNGWh4AL8rho4RO9OBao0MnUdjbbffD+wIBAg==
254 -----END DH PARAMETERS-----
255 EOF
256         close(DHFILE);
257
258         if (! -e ${dckey_private}) {
259                 umask $oldumask;
260                 return;
261         }
262
263         copy_file_content(${cacert}, ${cafile});
264         copy_file_content(${cacrl_pem}, ${crlfile});
265         copy_file_content(${dccert}, ${certfile});
266         copy_file_content(${dckey_private}, ${keyfile});
267         if (-e ${adminkey_private}) {
268                 copy_file_content(${admincert}, ${admincertfile});
269                 copy_file_content(${adminkey_private}, ${adminkeyfile});
270         }
271         if (-e ${pkinitkey_private}) {
272                 copy_file_content(${pkinitcert}, ${pkinitcertfile});
273                 copy_file_content(${pkinitkey_private}, ${pkinitkeyfile});
274         }
275
276         # COMPAT stuff to be removed in a later commit
277         my $kdccertfile = "$tlsdir/kdc.pem";
278         copy_file_content(${dccert}, ${kdccertfile});
279
280         umask $oldumask;
281 }
282
283 sub mk_krb5_conf($$)
284 {
285         my ($ctx) = @_;
286
287         unless (open(KRB5CONF, ">$ctx->{krb5_conf}")) {
288                 warn("can't open $ctx->{krb5_conf}$?");
289                 return undef;
290         }
291
292         my $our_realms_stanza = mk_realms_stanza($ctx->{realm},
293                                                  $ctx->{dnsname},
294                                                  $ctx->{domain},
295                                                  $ctx->{kdc_ipv4});
296         print KRB5CONF "
297 #Generated krb5.conf for $ctx->{realm}
298
299 [libdefaults]
300  default_realm = $ctx->{realm}
301  dns_lookup_realm = false
302  dns_lookup_kdc = true
303  ticket_lifetime = 24h
304  forwardable = yes
305
306  # We are running on the same machine, do not correct
307  # system clock differences
308  kdc_timesync = 0
309
310 ";
311
312         if (defined($ENV{MITKRB5})) {
313                 print KRB5CONF "
314  # Set the grace clocskew to 5 seconds
315  # This is especially required by samba3.raw.session krb5 and
316  # reauth tests when not using Heimdal
317  clockskew = 5
318     ";
319         }
320
321         if (defined($ctx->{krb5_ccname})) {
322                 print KRB5CONF "
323  default_ccache_name = $ctx->{krb5_ccname}
324 ";
325         }
326
327
328         if (defined($ctx->{supported_enctypes})) {
329                 print KRB5CONF "
330  default_etypes = $ctx->{supported_enctypes}
331  default_as_etypes = $ctx->{supported_enctypes}
332  default_tgs_enctypes = $ctx->{supported_enctypes}
333  default_tkt_enctypes = $ctx->{supported_enctypes}
334  permitted_enctypes = $ctx->{supported_enctypes}
335 ";
336         }
337
338         print KRB5CONF "
339 [realms]
340  $our_realms_stanza
341 ";
342
343
344         if (defined($ctx->{tlsdir})) {
345                print KRB5CONF "
346
347 [appdefaults]
348         pkinit_anchors = FILE:$ctx->{tlsdir}/ca.pem
349
350 [kdc]
351         enable-pkinit = true
352         pkinit_identity = FILE:$ctx->{tlsdir}/kdc.pem,$ctx->{tlsdir}/key.pem
353         pkinit_anchors = FILE:$ctx->{tlsdir}/ca.pem
354
355 ";
356         }
357         close(KRB5CONF);
358 }
359
360 sub mk_realms_stanza($$$$)
361 {
362         my ($realm, $dnsname, $domain, $kdc_ipv4) = @_;
363         my $lc_domain = lc($domain);
364
365         # The   pkinit_require_krbtgt_otherName = false
366         # is just because the certificates we have saved
367         # do not have the realm in the subjectAltName
368         # (specially encoded as a principal)
369         # per
370         # https://github.com/heimdal/heimdal/wiki/Setting-up-PK-INIT-and-Certificates
371         my $realms_stanza = "
372  $realm = {
373   kdc = $kdc_ipv4:88
374   admin_server = $kdc_ipv4:88
375   default_domain = $dnsname
376   pkinit_require_krbtgt_otherName = false
377  }
378  $dnsname = {
379   kdc = $kdc_ipv4:88
380   admin_server = $kdc_ipv4:88
381   default_domain = $dnsname
382   pkinit_require_krbtgt_otherName = false
383  }
384  $domain = {
385   kdc = $kdc_ipv4:88
386   admin_server = $kdc_ipv4:88
387   default_domain = $dnsname
388   pkinit_require_krbtgt_otherName = false
389  }
390  $lc_domain = {
391   kdc = $kdc_ipv4:88
392   admin_server = $kdc_ipv4:88
393   default_domain = $dnsname
394   pkinit_require_krbtgt_otherName = false
395  }
396
397 ";
398         return $realms_stanza;
399 }
400
401 sub mk_mitkdc_conf($$)
402 {
403         # samba_kdb_dir is the path to mit_samba.so
404         my ($ctx, $samba_kdb_dir) = @_;
405
406         unless (open(KDCCONF, ">$ctx->{mitkdc_conf}")) {
407                 warn("can't open $ctx->{mitkdc_conf}$?");
408                 return undef;
409         }
410
411         print KDCCONF "
412 # Generated kdc.conf for $ctx->{realm}
413
414 [kdcdefaults]
415         kdc_ports = 88
416         kdc_tcp_ports = 88
417
418 [realms]
419         $ctx->{realm} = {
420         }
421
422         $ctx->{dnsname} = {
423         }
424
425         $ctx->{domain} = {
426         }
427
428 [dbmodules]
429         db_module_dir = $samba_kdb_dir
430
431         $ctx->{realm} = {
432                 db_library = samba
433         }
434
435         $ctx->{dnsname} = {
436                 db_library = samba
437         }
438
439         $ctx->{domain} = {
440                 db_library = samba
441         }
442
443 [logging]
444         kdc = FILE:$ctx->{logdir}/mit_kdc.log
445 ";
446
447         close(KDCCONF);
448 }
449
450 sub mk_resolv_conf($$)
451 {
452         my ($ctx) = @_;
453
454         unless (open(RESOLV_CONF, ">$ctx->{resolv_conf}")) {
455                 warn("can't open $ctx->{resolv_conf}$?");
456                 return undef;
457         }
458
459         print RESOLV_CONF "nameserver $ctx->{dns_ipv4}\n";
460         print RESOLV_CONF "nameserver $ctx->{dns_ipv6}\n";
461         close(RESOLV_CONF);
462 }
463
464 sub realm_to_ip_mappings
465 {
466         # this maps the DNS realms for the various testenvs to the corresponding
467         # PDC (i.e. the first DC created for that realm).
468         my %realm_to_pdc_mapping = (
469                 'adnonssdom.samba.example.com'    => 'addc_no_nss',
470                 'adnontlmdom.samba.example.com'   => 'addc_no_ntlm',
471                 'samba2000.example.com'           => 'dc5',
472                 'samba2003.example.com'           => 'dc6',
473                 'samba2008r2.example.com'         => 'dc7',
474                 'addom.samba.example.com'         => 'addc',
475                 'addom2.samba.example.com'        => 'addcsmb1',
476                 'sub.samba.example.com'           => 'localsubdc',
477                 'chgdcpassword.samba.example.com' => 'chgdcpass',
478                 'backupdom.samba.example.com'     => 'backupfromdc',
479                 'renamedom.samba.example.com'     => 'renamedc',
480                 'labdom.samba.example.com'        => 'labdc',
481                 'schema.samba.example.com'        => 'liveupgrade1dc',
482                 'prockilldom.samba.example.com'   => 'prockilldc',
483                 'proclimit.samba.example.com'     => 'proclimitdc',
484                 'samba.example.com'               => 'localdc',
485                 'fips.samba.example.com'          => 'fipsdc',
486         );
487
488         my @mapping = ();
489
490         # convert the hashmap to a list of key=value strings, where key is the
491         # realm and value is the IP address
492         foreach my $realm (sort(keys %realm_to_pdc_mapping)) {
493                 my $pdc = $realm_to_pdc_mapping{$realm};
494                 my $ipaddr = get_ipv4_addr($pdc);
495                 push(@mapping, "$realm=$ipaddr");
496         }
497         # return the mapping as a single comma-separated string
498         return join(',', @mapping);
499 }
500
501 sub get_interface($)
502 {
503         my ($netbiosname) = @_;
504         $netbiosname = lc($netbiosname);
505
506         # this maps the SOCKET_WRAPPER_DEFAULT_IFACE value for each possible
507         # testenv to the DC's NETBIOS name. This value also corresponds to last
508         # digit of the DC's IP address. Note that the NETBIOS name may differ from
509         # the testenv name.
510         # Note that when adding a DC with a new realm, also update
511         # get_realm_ip_mappings() above.
512         my %testenv_iface_mapping = (
513                 localnt4dc2       => 3,
514                 localnt4member3   => 4,
515                 localshare4       => 5,
516                 # 6 is spare
517                 localktest6       => 7,
518                 maptoguest        => 8,
519                 localnt4dc9       => 9,
520                 # 10 is spare
521
522                 # 11-16 are used by selftest.pl for the client.conf. Most tests only
523                 # use the first .11 IP. However, some tests (like winsreplication) rely
524                 # on the client having multiple IPs.
525                 client            => 11,
526
527                 addc_no_nss       => 17,
528                 addc_no_ntlm      => 18,
529                 idmapadmember     => 19,
530                 idmapridmember    => 20,
531                 localdc           => 21,
532                 localvampiredc    => 22,
533                 s4member          => 23,
534                 localrpcproxy     => 24,
535                 dc5               => 25,
536                 dc6               => 26,
537                 dc7               => 27,
538                 rodc              => 28,
539                 localadmember     => 29,
540                 addc              => 30,
541                 localsubdc        => 31,
542                 chgdcpass         => 32,
543                 promotedvdc       => 33,
544                 rfc2307member     => 34,
545                 fileserver        => 35,
546                 fakednsforwarder1 => 36,
547                 fakednsforwarder2 => 37,
548                 s4member_dflt     => 38,
549                 vampire2000dc     => 39,
550                 backupfromdc      => 40,
551                 restoredc         => 41,
552                 renamedc          => 42,
553                 labdc             => 43,
554                 offlinebackupdc   => 44,
555                 customdc          => 45,
556                 prockilldc        => 46,
557                 proclimitdc       => 47,
558                 liveupgrade1dc    => 48,
559                 liveupgrade2dc    => 49,
560                 ctdb0             => 50,
561                 ctdb1             => 51,
562                 ctdb2             => 52,
563                 fileserversmb1    => 53,
564                 addcsmb1          => 54,
565                 lclnt4dc2smb1     => 55,
566                 fipsdc            => 56,
567
568                 rootdnsforwarder  => 64,
569
570                 # Note: that you also need to update dns_hub.py when adding a new
571                 # multi-DC testenv
572                 # update lib/socket_wrapper/socket_wrapper.c
573                 #  #define MAX_WRAPPED_INTERFACES 64
574                 # if you wish to have more than 64 interfaces
575         );
576
577         if (not defined($testenv_iface_mapping{$netbiosname})) {
578                 die();
579         }
580
581         return $testenv_iface_mapping{$netbiosname};
582 }
583
584 sub get_ipv4_addr
585 {
586         my ($hostname, $iface_num) = @_;
587         my $swiface = Samba::get_interface($hostname);
588
589         # Handle testenvs with multiple different addresses, i.e. IP multihoming.
590         # Currently only the selftest client has multiple IPv4 addresses.
591         if (defined($iface_num)) {
592                 $swiface += $iface_num;
593         }
594
595         return "10.53.57.$swiface";
596 }
597
598 sub get_ipv6_addr
599 {
600         (my $hostname) = @_;
601         my $swiface = Samba::get_interface($hostname);
602
603         return sprintf("fd00:0000:0000:0000:0000:0000:5357:5f%02x", $swiface);
604 }
605
606 # returns the 'interfaces' setting for smb.conf, i.e. the IPv4/IPv6
607 # addresses for testenv
608 sub get_interfaces_config
609 {
610         my ($hostname, $num_ips) = @_;
611         my $interfaces = "";
612
613         # We give the client.conf multiple different IPv4 addresses.
614         # All other testenvs generally just have one IPv4 address.
615         if (! defined($num_ips)) {
616                 $num_ips = 1;
617         }
618         for (my $i = 0; $i < $num_ips; $i++) {
619                 my $ipv4_addr = Samba::get_ipv4_addr($hostname, $i);
620                 if (use_namespaces()) {
621                         # use a /24 subnet with network namespaces
622                         $interfaces .= "$ipv4_addr/24 ";
623                 } else {
624                         $interfaces .= "$ipv4_addr/8 ";
625                 }
626         }
627
628         my $ipv6_addr = Samba::get_ipv6_addr($hostname);
629         $interfaces .= "$ipv6_addr/64";
630
631         return $interfaces;
632 }
633
634 sub cleanup_child($$)
635 {
636     my ($pid, $name) = @_;
637
638     if (!defined($pid)) {
639         print STDERR "cleanup_child: pid not defined ... not calling waitpid\n";
640         return -1;
641     }
642
643     my $childpid = waitpid($pid, WNOHANG);
644
645     if ($childpid == 0) {
646     } elsif ($childpid < 0) {
647         printf STDERR "%s child process %d isn't here any more\n", $name, $pid;
648         return $childpid;
649     } elsif ($? & 127) {
650         printf STDERR "%s child process %d, died with signal %d, %s coredump\n",
651                 $name, $childpid, ($? & 127),  ($? & 128) ? 'with' : 'without';
652     } else {
653         printf STDERR "%s child process %d exited with value %d\n", $name, $childpid, $? >> 8;
654     }
655     return $childpid;
656 }
657
658 sub random_domain_sid()
659 {
660         my $domain_sid = "S-1-5-21-". int(rand(4294967295)) . "-" . int(rand(4294967295)) . "-" . int(rand(4294967295));
661         return $domain_sid;
662 }
663
664 # sets the environment variables ready for running a given process
665 sub set_env_for_process
666 {
667         my ($proc_name, $env_vars, $proc_envs) = @_;
668
669         if (not defined($proc_envs)) {
670                 $proc_envs = get_env_for_process($proc_name, $env_vars);
671         }
672
673         foreach my $key (keys %{ $proc_envs }) {
674                 $ENV{$key} = $proc_envs->{$key};
675         }
676 }
677
678 sub get_env_for_process
679 {
680         my ($proc_name, $env_vars) = @_;
681         my $proc_envs = {
682                 RESOLV_CONF => $env_vars->{RESOLV_CONF},
683                 KRB5_CONFIG => $env_vars->{KRB5_CONFIG},
684                 KRB5CCNAME => "$env_vars->{KRB5_CCACHE}.$proc_name",
685                 SELFTEST_WINBINDD_SOCKET_DIR => $env_vars->{SELFTEST_WINBINDD_SOCKET_DIR},
686                 NMBD_SOCKET_DIR => $env_vars->{NMBD_SOCKET_DIR},
687                 NSS_WRAPPER_PASSWD => $env_vars->{NSS_WRAPPER_PASSWD},
688                 NSS_WRAPPER_GROUP => $env_vars->{NSS_WRAPPER_GROUP},
689                 NSS_WRAPPER_HOSTS => $env_vars->{NSS_WRAPPER_HOSTS},
690                 NSS_WRAPPER_HOSTNAME => $env_vars->{NSS_WRAPPER_HOSTNAME},
691                 NSS_WRAPPER_MODULE_SO_PATH => $env_vars->{NSS_WRAPPER_MODULE_SO_PATH},
692                 NSS_WRAPPER_MODULE_FN_PREFIX => $env_vars->{NSS_WRAPPER_MODULE_FN_PREFIX},
693                 UID_WRAPPER_ROOT => "1",
694                 ENVNAME => "$ENV{ENVNAME}.$proc_name",
695         };
696
697         if (defined($env_vars->{RESOLV_WRAPPER_CONF})) {
698                 $proc_envs->{RESOLV_WRAPPER_CONF} = $env_vars->{RESOLV_WRAPPER_CONF};
699         } else {
700                 $proc_envs->{RESOLV_WRAPPER_HOSTS} = $env_vars->{RESOLV_WRAPPER_HOSTS};
701         }
702         if (defined($env_vars->{GNUTLS_FORCE_FIPS_MODE})) {
703                 $proc_envs->{GNUTLS_FORCE_FIPS_MODE} = $env_vars->{GNUTLS_FORCE_FIPS_MODE};
704         }
705         if (defined($env_vars->{OPENSSL_FORCE_FIPS_MODE})) {
706                 $proc_envs->{OPENSSL_FORCE_FIPS_MODE} = $env_vars->{OPENSSL_FORCE_FIPS_MODE};
707         }
708         return $proc_envs;
709 }
710
711 sub fork_and_exec
712 {
713         my ($self, $env_vars, $daemon_ctx, $STDIN_READER, $child_cleanup) = @_;
714         my $SambaCtx = $self;
715         $SambaCtx = $self->{SambaCtx} if defined($self->{SambaCtx});
716
717         # we close the child's write-end of the pipe and redirect the
718         # read-end to its stdin. That way the daemon will receive an
719         # EOF on stdin when parent selftest process closes its
720         # write-end.
721         $child_cleanup //= sub { close($env_vars->{STDIN_PIPE}) };
722
723         unlink($daemon_ctx->{LOG_FILE});
724         print "STARTING $daemon_ctx->{NAME} for $ENV{ENVNAME}...";
725
726         my $parent_pid = $$;
727         my $pid = fork();
728
729         # exec the daemon in the child process
730         if ($pid == 0) {
731                 my @preargs = ();
732
733                 # redirect the daemon's stdout/stderr to a log file
734                 if (defined($daemon_ctx->{TEE_STDOUT})) {
735                         # in some cases, we want out from samba to go to the log file,
736                         # but also to the users terminal when running 'make test' on the
737                         # command line. This puts it on stderr on the terminal
738                         open STDOUT, "| tee $daemon_ctx->{LOG_FILE} 1>&2";
739                 } else {
740                         open STDOUT, ">$daemon_ctx->{LOG_FILE}";
741                 }
742                 open STDERR, '>&STDOUT';
743
744                 SocketWrapper::set_default_iface($env_vars->{SOCKET_WRAPPER_DEFAULT_IFACE});
745                 if (defined($daemon_ctx->{PCAP_FILE})) {
746                         $SambaCtx->setup_pcap("$daemon_ctx->{PCAP_FILE}");
747                 }
748
749                 # setup ENV variables in the child process
750                 set_env_for_process($daemon_ctx->{NAME}, $env_vars,
751                                     $daemon_ctx->{ENV_VARS});
752
753                 $child_cleanup->();
754
755                 # not all s3 daemons run in all testenvs (e.g. fileserver doesn't
756                 # run winbindd). In which case, the child process just sleeps
757                 if (defined($daemon_ctx->{SKIP_DAEMON})) {
758                         $SIG{USR1} = $SIG{ALRM} = $SIG{INT} = $SIG{QUIT} = $SIG{TERM} = sub {
759                                 my $signame = shift;
760                                 print("Skip $daemon_ctx->{NAME} received signal $signame");
761                                 exit 0;
762                         };
763                         my $poll = IO::Poll->new();
764                         $poll->mask($STDIN_READER, POLLIN);
765                         $poll->poll($self->{server_maxtime});
766                         exit 0;
767                 }
768
769                 $ENV{MAKE_TEST_BINARY} = $daemon_ctx->{BINARY_PATH};
770
771                 open STDIN, ">&", $STDIN_READER or die "can't dup STDIN_READER to STDIN: $!";
772
773                 # if using kernel namespaces, prepend the command so the process runs in
774                 # its own namespace
775                 if (Samba::use_namespaces()) {
776                         @preargs = ns_exec_preargs($parent_pid, $env_vars);
777                 }
778
779                 # the command args are stored as an array reference (because...Perl),
780                 # so convert the reference back to an array
781                 my @full_cmd = @{ $daemon_ctx->{FULL_CMD} };
782
783                 exec(@preargs, @full_cmd) or die("Unable to start $ENV{MAKE_TEST_BINARY}: $!");
784         }
785
786         print "DONE ($pid)\n";
787
788         # if using kernel namespaces, we now establish a connection between the
789         # main selftest namespace (i.e. this process) and the new child namespace
790         if (use_namespaces()) {
791                 ns_child_forked($pid, $env_vars);
792         }
793
794         return $pid;
795 }
796
797 my @exported_envvars = (
798         # domain stuff
799         "DOMAIN",
800         "DNSNAME",
801         "REALM",
802         "DOMSID",
803
804         # stuff related to a trusted domain
805         "TRUST_SERVER",
806         "TRUST_USERNAME",
807         "TRUST_PASSWORD",
808         "TRUST_DOMAIN",
809         "TRUST_REALM",
810         "TRUST_DOMSID",
811
812         # stuff related to a trusted domain, on a trust_member
813         # the domain behind a forest trust (two-way)
814         "TRUST_F_BOTH_SERVER",
815         "TRUST_F_BOTH_SERVER_IP",
816         "TRUST_F_BOTH_SERVER_IPV6",
817         "TRUST_F_BOTH_NETBIOSNAME",
818         "TRUST_F_BOTH_USERNAME",
819         "TRUST_F_BOTH_PASSWORD",
820         "TRUST_F_BOTH_DOMAIN",
821         "TRUST_F_BOTH_REALM",
822
823         # stuff related to a trusted domain, on a trust_member
824         # the domain behind an external trust (two-way)
825         "TRUST_E_BOTH_SERVER",
826         "TRUST_E_BOTH_SERVER_IP",
827         "TRUST_E_BOTH_SERVER_IPV6",
828         "TRUST_E_BOTH_NETBIOSNAME",
829         "TRUST_E_BOTH_USERNAME",
830         "TRUST_E_BOTH_PASSWORD",
831         "TRUST_E_BOTH_DOMAIN",
832         "TRUST_E_BOTH_REALM",
833
834         # domain controller stuff
835         "DC_SERVER",
836         "DC_SERVER_IP",
837         "DC_SERVER_IPV6",
838         "DC_NETBIOSNAME",
839         "DC_NETBIOSALIAS",
840
841         # server stuff
842         "SERVER",
843         "SERVER_IP",
844         "SERVER_IPV6",
845         "NETBIOSNAME",
846         "NETBIOSALIAS",
847         "SAMSID",
848
849         # only use these 2 as a last resort. Some tests need to test both client-
850         # side and server-side. In this case, run as default client, ans access
851         # server's smb.conf as needed, typically using:
852         #  param.LoadParm(filename_for_non_global_lp=os.environ['SERVERCONFFILE'])
853         "SERVERCONFFILE",
854         "DC_SERVERCONFFILE",
855
856         # user stuff
857         "USERNAME",
858         "USERID",
859         "PASSWORD",
860         "DC_USERNAME",
861         "DC_PASSWORD",
862
863         # UID/GID for rfc2307 mapping tests
864         "UID_RFC2307TEST",
865         "GID_RFC2307TEST",
866
867         # misc stuff
868         "KRB5_CONFIG",
869         "KRB5CCNAME",
870         "SELFTEST_WINBINDD_SOCKET_DIR",
871         "NMBD_SOCKET_DIR",
872         "LOCAL_PATH",
873         "DNS_FORWARDER1",
874         "DNS_FORWARDER2",
875         "RESOLV_CONF",
876         "UNACCEPTABLE_PASSWORD",
877         "LOCK_DIR",
878         "SMBD_TEST_LOG",
879
880         # nss_wrapper
881         "NSS_WRAPPER_PASSWD",
882         "NSS_WRAPPER_GROUP",
883         "NSS_WRAPPER_HOSTS",
884         "NSS_WRAPPER_HOSTNAME",
885         "NSS_WRAPPER_MODULE_SO_PATH",
886         "NSS_WRAPPER_MODULE_FN_PREFIX",
887
888         # resolv_wrapper
889         "RESOLV_WRAPPER_CONF",
890         "RESOLV_WRAPPER_HOSTS",
891
892         # crypto libraries
893         "GNUTLS_FORCE_FIPS_MODE",
894         "OPENSSL_FORCE_FIPS_MODE",
895 );
896
897 sub exported_envvars_str
898 {
899         my ($testenv_vars) = @_;
900         my $out = "";
901
902         foreach (@exported_envvars) {
903                 next unless defined($testenv_vars->{$_});
904                 $out .= $_."=".$testenv_vars->{$_}."\n";
905         }
906
907         return $out;
908 }
909
910 sub clear_exported_envvars
911 {
912         foreach (@exported_envvars) {
913                 delete $ENV{$_};
914         }
915 }
916
917 sub export_envvars
918 {
919         my ($testenv_vars) = @_;
920
921         foreach (@exported_envvars) {
922                 if (defined($testenv_vars->{$_})) {
923                         $ENV{$_} = $testenv_vars->{$_};
924                 } else {
925                         delete $ENV{$_};
926                 }
927         }
928 }
929
930 sub export_envvars_to_file
931 {
932         my ($filepath, $testenv_vars) = @_;
933         my $env_str = exported_envvars_str($testenv_vars);
934
935         open(FILE, "> $filepath");
936         print FILE "$env_str";
937         close(FILE);
938 }
939
940 # Returns true if kernel namespaces are being used instead of socket-wrapper.
941 # The default is false.
942 sub use_namespaces
943 {
944         return defined($ENV{USE_NAMESPACES});
945 }
946
947 # returns a given testenv's interface-name (only when USE_NAMESPACES=1)
948 sub ns_interface_name
949 {
950         my ($hostname) = @_;
951
952         # when using namespaces, each testenv has its own vethX interface,
953         # where X = Samba::get_interface(testenv_name)
954         my $iface = get_interface($hostname);
955         return "veth$iface";
956 }
957
958 # Called after a new child namespace has been forked
959 sub ns_child_forked
960 {
961         my ($child_pid, $env_vars) = @_;
962
963         # we only need to do this for the first child forked for this testenv
964         if (defined($env_vars->{NS_PID})) {
965                 return;
966         }
967
968         # store the child PID. It's the only way the main (selftest) namespace can
969         # access the new child (testenv) namespace.
970         $env_vars->{NS_PID} = $child_pid;
971
972         # Add the new child namespace's interface to the main selftest bridge.
973         # This connects together the various testenvs so that selftest can talk to
974         # them all
975         my $iface = ns_interface_name($env_vars->{NETBIOSNAME});
976         system "$ENV{SRCDIR}/selftest/ns/add_bridge_iface.sh $iface-br selftest0";
977 }
978
979 # returns args to prepend to a command in order to execute it the correct
980 # namespace for the testenv (creating a new namespace if needed).
981 # This should only used when USE_NAMESPACES=1 is set.
982 sub ns_exec_preargs
983 {
984         my ($parent_pid, $env_vars) = @_;
985
986         # NS_PID stores the pid of the first child daemon run in this namespace
987         if (defined($env_vars->{NS_PID})) {
988
989                 # the namespace has already been created previously. So we use nsenter
990                 # to execute the command in the given testenv's namespace. We need to
991                 # use the NS_PID to identify this particular namespace
992                 return ("nsenter", "-t", "$env_vars->{NS_PID}", "--net");
993         } else {
994
995                 # We need to create a new namespace for this daemon (i.e. we're
996                 # setting up a new testenv). First, write the environment variables to
997                 # an exports.sh file for this testenv (for convenient access by the
998                 # namespace scripts).
999                 my $exports_file = "$env_vars->{TESTENV_DIR}/exports.sh";
1000                 export_envvars_to_file($exports_file, $env_vars);
1001
1002                 # when using namespaces, each testenv has its own veth interface
1003                 my $interface = ns_interface_name($env_vars->{NETBIOSNAME});
1004
1005                 # we use unshare to create a new network namespace. The start_in_ns.sh
1006                 # helper script gets run first to setup the new namespace's interfaces.
1007                 # (This all gets prepended around the actual command to run in the new
1008                 # namespace)
1009                 return ("unshare", "--net", "$ENV{SRCDIR}/selftest/ns/start_in_ns.sh",
1010                                 $interface, $exports_file, $parent_pid);
1011         }
1012 }
1013
1014
1015 sub check_env {
1016         my ($self, $envvars) = @_;
1017         return 1;
1018 }
1019
1020 sub teardown_env {
1021         my ($self, $env) = @_;
1022         return 1;
1023 }
1024
1025
1026 sub getlog_env {
1027         return '';
1028 }
1029
1030 1;