r4748: removed unnecessary distinguishedName from provisioning
[sfrench/samba-autobuild/.git] / source4 / script / provision.pl
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Socket;
5 use Getopt::Long;
6
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
23 # return the current NTTIME as an integer
24 sub nttime()
25 {
26         my $t = time();
27         $t += (369.0*365.25*24*60*60-(3.0*24*60*60+6.0*60*60));
28         $t *= 1.0e7;
29         return sprintf("%lld", $t);
30 }
31
32 # generate a random guid. Not a good algorithm.
33 sub randguid()
34 {
35         my $r1 = int(rand(2**32));
36         my $r2 = int(rand(2**16));
37         my $r3 = int(rand(2**16));
38         my $r4 = int(rand(2**16));
39         my $r5 = int(rand(2**32));
40         my $r6 = int(rand(2**16));
41         return sprintf("%08x-%04x-%04x-%04x-%08x%04x", $r1, $r2, $r3, $r4, $r5, $r6);
42 }
43
44 my $opt_domainguid = randguid();
45 my $hostguid = randguid();
46
47 sub randsid()
48 {
49         return sprintf("S-1-5-21-%d-%d-%d", 
50                        int(rand(10**8)), int(rand(10**8)), int(rand(10**8)));
51 }
52
53 my $opt_domainsid = randsid();
54
55 # generate a random password. Poor algorithm :(
56 sub randpass()
57 {
58         my $pass = "";
59         my $chars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ%\$!~";
60         for (my $i=0;$i<8;$i++) {
61                 my $c = int(rand(length($chars)));
62                 $pass .= substr($chars, $c, 1);
63         }
64         return $pass;
65 }
66
67 sub ldaptime()
68 {
69         my ($sec,$min,$hour,$mday,$mon,$year,$wday,$yday) =  gmtime(time);
70         return sprintf "%04u%02u%02u%02u%02u%02u.0Z",
71         $year+1900, $mon+1, $mday, $hour, $min, $sec;
72 }
73
74 #######################
75 # substitute a single variable
76 sub substitute($)
77 {
78         my $var = shift;
79
80         if ($var eq "BASEDN") {
81                 return $basedn;
82         }
83
84         if ($var eq "DOMAINSID") {
85                 return $opt_domainsid;
86         }
87
88         if ($var eq "DOMAIN") {
89                 return $opt_domain;
90         }
91
92         if ($var eq "REALM") {
93                 return $opt_realm;
94         }
95
96         if ($var eq "DNSDOMAIN") {
97                 return $dnsdomain;
98         }
99
100         if ($var eq "HOSTNAME") {
101                 return $opt_hostname;
102         }
103
104         if ($var eq "NETBIOSNAME") {
105                 return $netbiosname;
106         }
107
108         if ($var eq "DNSNAME") {
109                 return $dnsname;
110         }
111
112         if ($var eq "HOSTIP") {
113                 return $opt_hostip;
114         }
115
116         if ($var eq "LDAPTIME") {
117                 return ldaptime();
118         }
119
120         if ($var eq "NEWGUID") {
121                 return randguid();
122         }
123
124         if ($var eq "DOMAINGUID") {
125                 return $opt_domainguid;
126         }
127
128         if ($var eq "HOSTGUID") {
129                 return $hostguid;
130         }
131
132         if ($var eq "DEFAULTSITE") {
133                 return $defaultsite;
134         }
135
136         if ($var eq "ADMINPASS") {
137                 return $opt_adminpass;
138         }
139
140         if ($var eq "RANDPASS") {
141             return randpass();
142         }
143
144         if ($var eq "NTTIME") {
145                 return "" . nttime();
146         }
147
148         if ($var eq "WHEEL") {
149                 return $opt_wheel;
150         }
151
152         if ($var eq "NOBODY") {
153                 return $opt_nobody;
154         }
155
156         if ($var eq "NOGROUP") {
157                 return $opt_nogroup;
158         }
159
160         if ($var eq "USERS") {
161                 return $opt_users;
162         }
163
164         die "ERROR: Uknown substitution variable $var\n";
165 }
166
167 #####################################################################
168 # write a string into a file
169 sub FileSave($$)
170 {
171     my($filename) = shift;
172     my($v) = shift;
173     local(*FILE);
174     open(FILE, ">$filename") || die "can't open $filename";    
175     print FILE $v;
176     close(FILE);
177 }
178
179 #####################################################################
180 # read a file into a string
181 sub FileLoad($)
182 {
183     my($filename) = shift;
184     local(*INPUTFILE);
185     open(INPUTFILE, $filename) || return undef;
186     my($saved_delim) = $/;
187     undef $/;
188     my($data) = <INPUTFILE>;
189     close(INPUTFILE);
190     $/ = $saved_delim;
191     return $data;
192 }
193
194 #######################################################################
195 # add a foreign security principle
196 sub add_foreign($$$)
197 {
198         my $sid = shift;
199         my $desc = shift;
200         my $unixname = shift;
201         return "
202 dn: CN=$sid,CN=ForeignSecurityPrincipals,\${BASEDN}
203 objectClass: top
204 objectClass: foreignSecurityPrincipal
205 cn: $sid
206 description: $desc
207 instanceType: 4
208 whenCreated: \${LDAPTIME}
209 whenChanged: \${LDAPTIME}
210 uSNCreated: 1
211 uSNChanged: 1
212 showInAdvancedViewOnly: TRUE
213 name: $sid
214 objectGUID: \${NEWGUID}
215 objectSid: $sid
216 objectCategory: CN=Foreign-Security-Principal,CN=Schema,CN=Configuration,\${BASEDN}
217 unixName: $unixname
218
219 ";
220 }
221
222 ############################################
223 # show some help
224 sub ShowHelp()
225 {
226         print "
227 Samba4 provisioning
228
229 provision.pl [options]
230   --realm     REALM        set realm
231   --domain    DOMAIN       set domain
232   --hostname  HOSTNAME     set hostname
233   --hostip    IPADDRESS    set ipaddress
234   --adminpass PASSWORD     choose admin password (otherwise random)
235   --nobody    USERNAME     choose 'nobody' user
236   --nogroup   GROUPNAME    choose 'nogroup' group
237   --wheel     GROUPNAME    choose 'wheel' privileged group
238   --users     GROUPNAME    choose 'users' group
239
240 You must provide at least a realm and domain
241
242 ";
243         exit(1);
244 }
245
246 my $opt_help;
247
248 GetOptions(
249             'help|h|?' => \$opt_help, 
250             'realm=s' => \$opt_realm,
251             'domain=s' => \$opt_domain,
252             'domain-guid=s' => \$opt_domainguid,
253             'domain-sid=s' => \$opt_domainsid,
254             'hostname=s' => \$opt_hostname,
255             'hostip=s' => \$opt_hostip,
256             'adminpass=s' => \$opt_adminpass,
257             'nobody=s' => \$opt_nobody,
258             'nogroup=s' => \$opt_nogroup,
259             'wheel=s' => \$opt_wheel,
260             'users=s' => \$opt_users,
261             );
262
263 if ($opt_help || 
264     !$opt_realm ||
265     !$opt_domain ||
266     !$opt_hostname) {
267         ShowHelp();
268 }
269
270 $opt_realm=uc($opt_realm);
271 $opt_domain=uc($opt_domain);
272 $opt_hostname=lc($opt_hostname);
273 $netbiosname=uc($opt_hostname);
274
275 if (!$opt_hostip) {
276         my $hip = gethostbyname($opt_hostname);
277         if (defined $hip) {
278                 $opt_hostip = inet_ntoa($hip);
279         } else {
280                 $opt_hostip = "<0.0.0.0>";
281         }
282 }
283
284 print "Provisioning host '$opt_hostname'[$opt_hostip] for domain '$opt_domain' in realm '$opt_realm'\n";
285
286 if (!$opt_nobody) {
287         if (defined getpwnam("nobody")) {
288                 $opt_nobody = "nobody";
289         }
290 }
291
292 if (!$opt_nogroup) {
293         if (defined getgrnam("nogroup")) {
294                 $opt_nogroup = "nogroup";
295         } elsif (defined getgrnam("nobody")) {
296                 $opt_nogroup = "nobody";
297         }
298 }
299
300 if (!$opt_wheel) {
301         if (defined getgrnam("wheel")) {
302                 $opt_wheel = "wheel";
303         } elsif (defined getgrnam("root")) {
304                 $opt_wheel = "root";
305         }
306 }
307
308 if (!$opt_users) {
309         if (defined getgrnam("users")) {
310                 $opt_users = "users";
311         }
312 }
313
314 $opt_nobody || die "Unable to determine a user for 'nobody'\n";
315 $opt_nogroup || die "Unable to determine a group for 'nogroup'\n";
316 $opt_users || die "Unable to determine a group for 'user'\n";
317 $opt_wheel || die "Unable to determine a group for 'wheel'\n";
318
319 print "Using nobody='$opt_nobody'  nogroup='$opt_nogroup'  wheel='$opt_wheel'  users='$opt_users'\n";
320
321 print "generating ldif ...\n";
322
323 $dnsdomain = lc($opt_realm);
324 $dnsname = lc($opt_hostname).".".$dnsdomain;
325 $basedn = "DC=" . join(",DC=", split(/\./, $opt_realm));
326
327 my $data = FileLoad("provision.ldif") || die "Unable to load provision.ldif\n";
328
329 $data .= add_foreign("S-1-5-7", "Anonymous", "\${NOBODY}");
330 $data .= add_foreign("S-1-1-0", "World", "\${NOGROUP}");
331 $data .= add_foreign("S-1-5-2", "Network", "\${NOGROUP}");
332 $data .= add_foreign("S-1-5-18", "System", "root");
333 $data .= add_foreign("S-1-5-11", "Authenticated Users", "\${USERS}");
334
335 if (!$opt_adminpass) {
336         $opt_adminpass = randpass();
337         print "chose random Administrator password '$opt_adminpass'\n";
338 }
339
340 my $res = "";
341
342 print "applying substitutions ...\n";
343
344 while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
345         my $sub = substitute($2);
346         $res .= "$1$sub";
347         $data = $3;
348 }
349 $res .= $data;
350
351 print "saving ldif to newsam.ldif ...\n";
352
353 FileSave("newsam.ldif", $res);
354
355 unlink("newsam.ldb");
356
357 print "creating newsam.ldb ...\n";
358
359 # allow provisioning to be run from the source directory
360 $ENV{"PATH"} .= ":bin";
361
362 system("ldbadd -H newsam.ldb newsam.ldif");
363
364 print "done\n";
365
366 $data = FileLoad("rootdse.ldif") || die "Unable to load rootdse.ldif\n";
367
368 $res = "";
369
370 print "applying substitutions ...\n";
371
372 while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
373         my $sub = substitute($2);
374         $res .= "$1$sub";
375         $data = $3;
376 }
377 $res .= $data;
378
379 print "saving ldif to newrootdse.ldif ...\n";
380
381 FileSave("newrootdse.ldif", $res);
382
383 unlink("newrootdse.ldb");
384
385 print "creating newrootdse.ldb ...\n";
386
387 system("ldbadd -H newrootdse.ldb newrootdse.ldif");
388
389 print "done\n";
390
391 $data = FileLoad("secrets.ldif") || die "Unable to load secrets.ldif\n";
392
393 $res = "";
394
395 print "applying substitutions ...\n";
396
397 while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
398         my $sub = substitute($2);
399         $res .= "$1$sub";
400         $data = $3;
401 }
402 $res .= $data;
403
404 print "saving ldif to newsecrets.ldif ...\n";
405
406 FileSave("newsecrets.ldif", $res);
407
408 unlink("newsecrets.ldb");
409
410 print "creating newsecrets.ldb ...\n";
411
412 system("ldbadd -H newsecrets.ldb newsecrets.ldif");
413
414 print "done\n";
415
416 print "generating dns zone file ...\n";
417
418 $data = FileLoad("provision.zone") || die "Unable to load provision.zone\n";
419
420 $res = "";
421
422 print "applying substitutions ...\n";
423
424 while ($data =~ /(.*?)\$\{(\w*)\}(.*)/s) {
425         my $sub = substitute($2);
426         $res .= "$1$sub";
427         $data = $3;
428 }
429 $res .= $data;
430
431 print "saving dns zone to newdns.zone ...\n";
432
433 FileSave("$dnsdomain.zone", $res);
434
435 print "done\n";
436
437 unlink("newhklm.ldb");
438
439 print "creating newhklm.ldb ... \n";
440
441 system("ldbadd -H newhklm.ldb hklm.ldif");
442
443 print "done\n";
444
445 print "
446
447 Installation:
448 - Please move newsam.ldb to sam.ldb in the private/ directory of your
449   Samba4 installation
450 - Please move newrootdse.ldb to rootdse.ldb in the private/ directory
451   of your Samba4 installation
452 - Please move newsecrets.ldb to secrets.ldb in the private/ directory
453   of your Samba4 installation
454 - Please move newhklm.ldb to hklm.ldb in the private/ directory
455   of your Samba4 installation
456 - Please use $dnsdomain.zone to in BIND dns server
457 ";
458
459