r8355: - added a vsprintf() function
[samba.git] / source / setup / provision
1 #!/usr/bin/env smbscript
2 /*
3         provision a Samba4 server
4         Copyright Andrew Tridgell 2005
5         Released under the GNU GPL v2 or later
6 */
7
8 options = new Object();
9 ok = GetOptions(ARGV, options, 
10                 "POPT_AUTOHELP",
11                 "POPT_COMMON_SAMBA",
12                 "POPT_COMMON_VERSION",
13                 'realm=s',
14                 'domain=s',
15                 'domain-guid=s',
16                 'domain-sid=s',
17                 'host-name=s',
18                 'host-ip=s',
19                 'host-guid=s',
20                 'invocationid=s',
21                 'adminpass=s',
22                 'krbtgtpass=s',
23                 'machinepass=s',
24                 'root=s',
25                 'nobody=s',
26                 'nogroup=s',
27                 'wheel=s',
28                 'users=s',
29                 'quiet');
30 if (ok == false) {
31    println("Failed to parse options: " + options.ERROR);
32    return -1;
33 }
34
35 libinclude("base.js");
36
37 /* used to generate sequence numbers for records */
38 next_usn = 1;
39
40 /*
41   print a message if quiet is not set
42 */
43 function message(s) 
44 {
45         if (options["quiet"] == undefined) {
46                 println(s);
47         }
48 }
49
50 /*
51   find a user or group from a list of possibilities
52 */
53 function findnss()
54 {
55         var i;
56         assert(arguments.length >= 2);
57         var nssfn = arguments[0];
58         var name = arguments[1];
59         if (options[name] != undefined) {
60                 return options[name];
61         }
62         for (i=2;i<arguments.length;i++) {
63                 if (nssfn(arguments[i]) != undefined) {
64                         return arguments[i];
65                 }
66         }
67         println("Unable to find user/group for " + name);
68         exit(1);
69 }
70
71 /*
72    add a foreign security principle
73  */
74 function add_foreign(str, sid, desc, unixname)
75 {
76         var add = "
77 dn: CN=${SID},CN=ForeignSecurityPrincipals,${BASEDN}
78 objectClass: top
79 objectClass: foreignSecurityPrincipal
80 cn: ${SID}
81 description: ${DESC}
82 instanceType: 4
83 whenCreated: ${LDAPTIME}
84 whenChanged: ${LDAPTIME}
85 uSNCreated: 1
86 uSNChanged: 1
87 showInAdvancedViewOnly: TRUE
88 name: ${SID}
89 objectGUID: ${NEWGUID}
90 objectSid: ${SID}
91 objectCategory: CN=Foreign-Security-Principal,CN=Schema,CN=Configuration,${BASEDN}
92 unixName: ${UNIXNAME}
93 ";
94         var sub = new Object();
95         sub.SID = sid;
96         sub.DESC = desc;
97         sub.UNIXNAME = unixname;
98         return str + substitute_var(add, sub);
99 }
100
101 /*
102   return current time as a nt time string
103 */
104 function nttime()
105 {
106         return "" + sys_nttime();
107 }
108
109 /*
110   return current time as a ldap time string
111 */
112 function ldaptime()
113 {
114         return sys_ldaptime(sys_nttime());
115 }
116
117 function datestring()
118 {
119         var t = sys_gmtime(sys_nttime());
120         return sprintf("%04u%02u%02u%02u",
121                        t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour);
122 }
123
124 /*
125   return current time as a ldap time string
126 */
127 function nextusn()
128 {
129         next_usn = next_usn+1;
130         return next_usn;
131 }
132
133 /*
134   return first part of hostname
135 */
136 function hostname()
137 {
138         var s = split(".", sys_hostname());
139         return s[0];
140 }
141
142
143 /*
144   setup a ldb in the private dir
145  */
146 function setup_ldb(ldif, dbname, subobj)
147 {
148         var extra = "";
149         if (arguments.length == 4) {
150                 extra = arguments[3];
151         }
152
153         var db = lpGet("private dir") + "/" + dbname;
154         var src = lpGet("setup directory") + "/" + ldif;
155
156         sys_unlink(db);
157
158         var data = sys_file_load(src);
159         data = data + extra;
160         data = substitute_var(data, subobj);
161
162         message("Creating " + db + "\n from " + src);
163         ok = ldbAdd(db, data);
164         assert(ok);
165 }
166
167 /*
168   setup a file in the private dir
169  */
170 function setup_file(template, fname, subobj)
171 {
172         var f = lpGet("private dir") + "/" + fname;
173         var src = lpGet("setup directory") + "/" + template;
174
175         sys_unlink(f);
176
177         var data = sys_file_load(src);
178         data = substitute_var(data, subobj);
179
180         message("Creating " + f + "\n from " + src);
181         ok = sys_file_save(f, data);
182         assert(ok);
183 }
184
185 /*
186  show some help
187 */
188 function ShowHelp()
189 {
190         print("
191 Samba4 provisioning
192
193 provision.pl [options]
194  --realm        REALM           set realm
195  --domain       DOMAIN          set domain
196  --domain-guid  GUID            set domainguid (otherwise random)
197  --domain-sid   SID             set domainsid (otherwise random)
198  --host-name    HOSTNAME        set hostname
199  --host-ip      IPADDRESS       set ipaddress
200  --host-guid    GUID            set hostguid (otherwise random)
201  --invocationid GUID            set invocationid (otherwise random)
202  --adminpass    PASSWORD        choose admin password (otherwise random)
203  --krbtgtpass   PASSWORD        choose krbtgt password (otherwise random)
204  --machinepass  PASSWORD        choose machine password (otherwise random)
205  --root         USERNAME        choose 'root' unix username
206  --nobody       USERNAME        choose 'nobody' user
207  --nogroup      GROUPNAME       choose 'nogroup' group
208  --wheel        GROUPNAME       choose 'wheel' privileged group
209  --users        GROUPNAME       choose 'users' group
210  --quiet                        Be quiet
211
212 You must provide at least a realm and domain
213
214 ");
215         exit(1);
216 }
217
218 if (options['host-name'] == undefined) {
219         options['host-name'] = hostname();
220 }
221
222 /*
223    main program
224 */
225 if (options["realm"] == undefined ||
226     options["domain"] == undefined ||
227     options["host-name"] == undefined) {
228         ShowHelp();
229 }
230
231 options.realm        = strlower(options.realm);
232 options['host-name'] = strlower(options['host-name']);
233 options.domain       = strupper(options.domain);
234 options.netbiosname  = strupper(options['host-name']);
235
236 if (options.hostip == undefined) {
237         var list = sys_interfaces();
238         options.hostip = list[0];
239 }
240
241 message("Provisioning for " + options.domain + " in realm " + options.realm);
242
243 options.root    = findnss(getpwnam, "root", "root");
244 options.nobody  = findnss(getpwnam, "nobody", "nobody");
245 options.nogroup = findnss(getgrnam, "nogroup", "nogroup", "nobody");
246 options.wheel   = findnss(getgrnam, "wheel", "wheel", "root");
247 options.users   = findnss(getgrnam, "users", "users", "guest", "other");
248
249
250 options.dnsdomain = strlower(options.realm);
251 options.dnsname   = strlower(options['host-name']) + "." + options.dnsdomain;
252 options.basedn    = "DC=" + join(",DC=", split(".", options.realm));
253
254 /*
255   setup the substitution object
256 */
257 var subobj = new Object();
258 subobj.DOMAINGUID   = randguid();
259 subobj.DOMAINSID    = randsid();
260 subobj.HOSTGUID     = randguid();
261 subobj.INVOCATIONID = randguid();
262 subobj.KRBTGTPASS   = randpass(12);
263 subobj.MACHINEPASS  = randpass(12);
264 subobj.ADMINPASS    = randpass(12);
265 subobj.DEFAULTSITE  = "Default-First-Site-Name";
266 subobj.NEWGUID      = randguid;
267 subobj.NTTIME       = nttime;
268 subobj.LDAPTIME     = ldaptime;
269 subobj.DATESTRING   = datestring;
270 subobj.USN          = nextusn;
271 for (r in options) {
272         var key = strupper(join("", split("-", r)));
273         subobj[key] = options[r];
274 }
275
276
277 var extradata = "";
278 extradata = add_foreign(extradata, "S-1-5-7",  "Anonymous",           "${NOBODY}");
279 extradata = add_foreign(extradata, "S-1-1-0",  "World",               "${NOGROUP}");
280 extradata = add_foreign(extradata, "S-1-5-2",  "Network",             "${NOGROUP}");
281 extradata = add_foreign(extradata, "S-1-5-18", "System",              "${ROOT}");
282 extradata = add_foreign(extradata, "S-1-5-11", "Authenticated Users", "${USERS}");
283
284 message("Using administrator password: " + subobj.ADMINPASS);
285
286 setup_ldb("hklm.ldif", "hklm.ldb", subobj);
287 setup_ldb("provision.ldif", "sam.ldb", subobj, extradata);
288 setup_ldb("rootdse.ldif", "rootdse.ldb", subobj);
289 setup_ldb("secrets.ldif", "secrets.ldb", subobj);
290 setup_file("provision.zone", subobj.DNSDOMAIN + ".zone", subobj);
291
292 message("All OK");
293 return 0;