r5169: As provisioning script generates everything under $newdb/ directory, put gener...
[Samba/gbeck.git] / source4 / script / provision.pl
blob239e6ead83edffb087c876aae383ffed18650ac0
1 #!/usr/bin/perl -w
3 use strict;
4 use Socket;
5 use Getopt::Long;
7 my $opt_hostname = `hostname`;
8 chomp $opt_hostname;
9 my $opt_hostip;
10 my $opt_realm;
11 my $opt_domain;
12 my $opt_adminpass;
13 my $opt_nobody;
14 my $opt_nogroup;
15 my $opt_wheel;
16 my $opt_users;
17 my $dnsdomain;
18 my $netbiosname;
19 my $dnsname;
20 my $basedn;
21 my $defaultsite = "Default-First-Site-Name";
22 my $usn = 1;
24 # return the current NTTIME as an integer
25 sub nttime()
27 my $t = time();
28 $t += (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60));
29 $t *= 1.0e7;
30 return sprintf("%lld", $t);
33 # generate a random guid. Not a good algorithm.
34 sub randguid()
36 my $r1 = int(rand(2**32));
37 my $r2 = int(rand(2**16));
38 my $r3 = int(rand(2**16));
39 my $r4 = int(rand(2**16));
40 my $r5 = int(rand(2**32));
41 my $r6 = int(rand(2**16));
42 return sprintf("%08x-%04x-%04x-%04x-%08x%04x", $r1, $r2, $r3, $r4, $r5, $r6);
45 my $opt_domainguid = randguid();
46 my $opt_hostguid = randguid();
47 my $opt_invocationid = randguid();
49 sub randsid()
51 return sprintf("S-1-5-21-%d-%d-%d",
52 int(rand(10**8)), int(rand(10**8)), int(rand(10**8)));
55 my $opt_domainsid = randsid();
57 # generate a random password. Poor algorithm :(
58 sub randpass()
60 my $pass = "";
61 my $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%\$!~";
62 for (my $i=0;$i<8;$i++) {
63 my $c = int(rand(length($chars)));
64 $pass .= substr($chars, $c, 1);
66 return $pass;
69 my $joinpass = randpass();
71 sub ldaptime()
73 my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) = gmtime(time);
74 return sprintf "%04u%02u%02u%02u%02u%02u.0Z",
75 $year+1900, $mon+1, $mday, $hour, $min, $sec;
78 #######################
79 # substitute a single variable
80 sub substitute($)
82 my $var = shift;
84 if ($var eq "BASEDN") {
85 return $basedn;
88 if ($var eq "DOMAINSID") {
89 return $opt_domainsid;
92 if ($var eq "DOMAIN") {
93 return $opt_domain;
96 if ($var eq "REALM") {
97 return $opt_realm;
100 if ($var eq "DNSDOMAIN") {
101 return $dnsdomain;
104 if ($var eq "HOSTNAME") {
105 return $opt_hostname;
108 if ($var eq "NETBIOSNAME") {
109 return $netbiosname;
112 if ($var eq "DNSNAME") {
113 return $dnsname;
116 if ($var eq "HOSTIP") {
117 return $opt_hostip;
120 if ($var eq "LDAPTIME") {
121 return ldaptime();
124 if ($var eq "NEWGUID") {
125 return randguid();
128 if ($var eq "NEWSCHEMAGUID") {
129 return randguid();
132 if ($var eq "DOMAINGUID") {
133 return $opt_domainguid;
136 if ($var eq "HOSTGUID") {
137 return $opt_hostguid;
140 if ($var eq "INVOCATIONID") {
141 return $opt_invocationid;
144 if ($var eq "DEFAULTSITE") {
145 return $defaultsite;
148 if ($var eq "ADMINPASS") {
149 return $opt_adminpass;
152 if ($var eq "RANDPASS") {
153 return randpass();
156 if ($var eq "JOINPASS") {
157 return $joinpass;
160 if ($var eq "NTTIME") {
161 return "" . nttime();
164 if ($var eq "WHEEL") {
165 return $opt_wheel;
168 if ($var eq "NOBODY") {
169 return $opt_nobody;
172 if ($var eq "NOGROUP") {
173 return $opt_nogroup;
176 if ($var eq "USERS") {
177 return $opt_users;
180 if ($var eq "USN") {
181 my $ret = $usn;
182 $usn = $ret + 1;
183 return $ret;
186 die "ERROR: Uknown substitution variable $var\n";
190 ####################################################################
191 # substitute all variables in a string
192 sub apply_substitutions($)
194 my $data = shift;
195 my $res = "";
196 while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
197 my $sub = substitute($2);
198 $res .= "$1$sub";
199 $data = $3;
201 $res .= $data;
202 return $res;
206 #####################################################################
207 # write a string into a file
208 sub FileSave($$)
210 my($filename) = shift;
211 my($v) = shift;
212 local(*FILE);
213 open(FILE, ">$filename") || die "can't open $filename";
214 print FILE $v;
215 close(FILE);
218 #####################################################################
219 # read a file into a string
220 sub FileLoad($)
222 my($filename) = shift;
223 local(*INPUTFILE);
224 open(INPUTFILE, $filename) || return undef;
225 my($saved_delim) = $/;
226 undef $/;
227 my($data) = <INPUTFILE>;
228 close(INPUTFILE);
229 $/ = $saved_delim;
230 return $data;
233 #######################################################################
234 # add a foreign security principle
235 sub add_foreign($$$)
237 my $sid = shift;
238 my $desc = shift;
239 my $unixname = shift;
240 return "
241 dn: CN=$sid,CN=ForeignSecurityPrincipals,\${BASEDN}
242 objectClass: top
243 objectClass: foreignSecurityPrincipal
244 cn: $sid
245 description: $desc
246 instanceType: 4
247 whenCreated: \${LDAPTIME}
248 whenChanged: \${LDAPTIME}
249 uSNCreated: 1
250 uSNChanged: 1
251 showInAdvancedViewOnly: TRUE
252 name: $sid
253 objectGUID: \${NEWGUID}
254 objectSid: $sid
255 objectCategory: CN=Foreign-Security-Principal,CN=Schema,CN=Configuration,\${BASEDN}
256 unixName: $unixname
261 ############################################
262 # show some help
263 sub ShowHelp()
265 print "
266 Samba4 provisioning
268 provision.pl [options]
269 --realm REALM set realm
270 --domain DOMAIN set domain
271 --domain-guid GUID set domainguid (otherwise random)
272 --domain-sid SID set domainsid (otherwise random)
273 --host-name HOSTNAME set hostname
274 --host-ip IPADDRESS set ipaddress
275 --host-guid GUID set hostguid (otherwise random)
276 --invocationid GUID set invocationid (otherwise random)
277 --adminpass PASSWORD choose admin password (otherwise random)
278 --nobody USERNAME choose 'nobody' user
279 --nogroup GROUPNAME choose 'nogroup' group
280 --wheel GROUPNAME choose 'wheel' privileged group
281 --users GROUPNAME choose 'users' group
283 You must provide at least a realm and domain
286 exit(1);
289 my $opt_help;
291 GetOptions(
292 'help|h|?' => \$opt_help,
293 'realm=s' => \$opt_realm,
294 'domain=s' => \$opt_domain,
295 'domain-guid=s' => \$opt_domainguid,
296 'domain-sid=s' => \$opt_domainsid,
297 'host-name=s' => \$opt_hostname,
298 'host-ip=s' => \$opt_hostip,
299 'host-guid=s' => \$opt_hostguid,
300 'invocationid=s' => \$opt_invocationid,
301 'adminpass=s' => \$opt_adminpass,
302 'nobody=s' => \$opt_nobody,
303 'nogroup=s' => \$opt_nogroup,
304 'wheel=s' => \$opt_wheel,
305 'users=s' => \$opt_users,
308 if ($opt_help ||
309 !$opt_realm ||
310 !$opt_domain ||
311 !$opt_hostname) {
312 ShowHelp();
315 $opt_realm=uc($opt_realm);
316 $opt_domain=uc($opt_domain);
317 $opt_hostname=lc($opt_hostname);
318 $netbiosname=uc($opt_hostname);
320 if (!$opt_hostip) {
321 my $hip = gethostbyname($opt_hostname);
322 if (defined $hip) {
323 $opt_hostip = inet_ntoa($hip);
324 } else {
325 $opt_hostip = "<0.0.0.0>";
329 print "Provisioning host '$opt_hostname'[$opt_hostip] for domain '$opt_domain' in realm '$opt_realm'\n";
331 if (!$opt_nobody) {
332 if (defined getpwnam("nobody")) {
333 $opt_nobody = "nobody";
337 if (!$opt_nogroup) {
338 if (defined getgrnam("nogroup")) {
339 $opt_nogroup = "nogroup";
340 } elsif (defined getgrnam("nobody")) {
341 $opt_nogroup = "nobody";
345 if (!$opt_wheel) {
346 if (defined getgrnam("wheel")) {
347 $opt_wheel = "wheel";
348 } elsif (defined getgrnam("root")) {
349 $opt_wheel = "root";
353 if (!$opt_users) {
354 if (defined getgrnam("users")) {
355 $opt_users = "users";
359 $opt_nobody || die "Unable to determine a user for 'nobody'\n";
360 $opt_nogroup || die "Unable to determine a group for 'nogroup'\n";
361 $opt_users || die "Unable to determine a group for 'user'\n";
362 $opt_wheel || die "Unable to determine a group for 'wheel'\n";
364 print "Using nobody='$opt_nobody' nogroup='$opt_nogroup' wheel='$opt_wheel' users='$opt_users'\n";
366 print "generating ldif ...\n";
368 $dnsdomain = lc($opt_realm);
369 $dnsname = lc($opt_hostname).".".$dnsdomain;
370 $basedn = "DC=" . join(",DC=", split(/\./, $opt_realm));
372 my $data = FileLoad("provision.ldif") || die "Unable to load provision.ldif\n";
374 $data .= add_foreign("S-1-5-7", "Anonymous", "\${NOBODY}");
375 $data .= add_foreign("S-1-1-0", "World", "\${NOGROUP}");
376 $data .= add_foreign("S-1-5-2", "Network", "\${NOGROUP}");
377 $data .= add_foreign("S-1-5-18", "System", "root");
378 $data .= add_foreign("S-1-5-11", "Authenticated Users", "\${USERS}");
380 if (!$opt_adminpass) {
381 $opt_adminpass = randpass();
382 print "chose random Administrator password '$opt_adminpass'\n";
385 # allow provisioning to be run from the source directory
386 $ENV{"PATH"} .= ":bin";
389 my $res = apply_substitutions($data);
391 my $newdb = "newdb." . int(rand(1000));
393 print "Putting new database files in $newdb\n";
395 mkdir($newdb) || die "Unable to create temporary directory $newdb\n";
397 FileSave("$newdb/sam.ldif", $res);
399 print "creating $newdb/sam.ldb ...\n";
401 system("ldbadd -H $newdb/sam.ldb $newdb/sam.ldif") == 0 || die "Failed to create sam.ldb\n";
403 $data = FileLoad("rootdse.ldif") || die "Unable to load rootdse.ldif\n";
405 $res = apply_substitutions($data);
407 FileSave("$newdb/rootdse.ldif", $res);
409 print "creating $newdb/rootdse.ldb ...\n";
411 system("ldbadd -H $newdb/rootdse.ldb $newdb/rootdse.ldif") == 0 || die "Failed to create rootdse.ldb\n";
413 $data = FileLoad("secrets.ldif") || die "Unable to load secrets.ldif\n";
415 $res = apply_substitutions($data);
417 FileSave("$newdb/secrets.ldif", $res);
419 print "creating $newdb/secrets.ldb ...\n";
421 system("ldbadd -H $newdb/secrets.ldb $newdb/secrets.ldif") == 0 || die "Failed to create secrets.ldb\n";
423 $data = FileLoad("provision.zone") || die "Unable to load provision.zone\n";
425 $res = apply_substitutions($data);
427 print "saving dns zone to $newdb/$dnsdomain.zone ...\n";
429 FileSave("$newdb/$dnsdomain.zone", $res);
431 print "creating $newdb/hklm.ldb ... \n";
433 system("ldbadd -H $newdb/hklm.ldb hklm.ldif") == 0 || die "Failed to create hklm.ldb\n";
435 print "
437 Installation:
438 - Please move $newdb/*.ldb to the private/ directory of your
439 Samba4 installation
440 - Please use $newdb/dnsdomain.zone in BIND on your dns server