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