f5aaeafe89b8d246b4ff84ca98759081e3bdd205
[sfrench/samba-autobuild/.git] / source4 / scripting / libjs / provision.js
1 /*
2         backend code for provisioning a Samba4 server
3         Copyright Andrew Tridgell 2005
4         Released under the GNU GPL v2 or later
5 */
6
7 /* used to generate sequence numbers for records */
8 provision_next_usn = 1;
9
10 sys = sys_init();
11
12 /*
13   find a user or group from a list of possibilities
14 */
15 function findnss()
16 {
17         var i;
18         assert(arguments.length >= 2);
19         var nssfn = arguments[0];
20         for (i=1;i<arguments.length;i++) {
21                 if (nssfn(arguments[i]) != undefined) {
22                         return arguments[i];
23                 }
24         }
25         printf("Unable to find user/group for %s\n", arguments[1]);
26         assert(i<arguments.length);
27 }
28
29 /*
30    add a foreign security principle
31  */
32 function add_foreign(str, sid, desc, unixname)
33 {
34         var add = "
35 dn: CN=${SID},CN=ForeignSecurityPrincipals,${BASEDN}
36 objectClass: top
37 objectClass: foreignSecurityPrincipal
38 cn: ${SID}
39 description: ${DESC}
40 instanceType: 4
41 whenCreated: ${LDAPTIME}
42 whenChanged: ${LDAPTIME}
43 uSNCreated: 1
44 uSNChanged: 1
45 showInAdvancedViewOnly: TRUE
46 name: ${SID}
47 objectGUID: ${NEWGUID}
48 objectSid: ${SID}
49 objectCategory: CN=Foreign-Security-Principal,CN=Schema,CN=Configuration,${BASEDN}
50 unixName: ${UNIXNAME}
51 ";
52         var sub = new Object();
53         sub.SID = sid;
54         sub.DESC = desc;
55         sub.UNIXNAME = unixname;
56         return str + substitute_var(add, sub);
57 }
58
59 /*
60   return current time as a nt time string
61 */
62 function nttime()
63 {
64         return "" + sys.nttime();
65 }
66
67 /*
68   return current time as a ldap time string
69 */
70 function ldaptime()
71 {
72         return sys.ldaptime(sys.nttime());
73 }
74
75 /*
76   return a date string suitable for a dns zone serial number
77 */
78 function datestring()
79 {
80         var t = sys.gmtime(sys.nttime());
81         return sprintf("%04u%02u%02u%02u",
82                        t.tm_year+1900, t.tm_mon+1, t.tm_mday, t.tm_hour);
83 }
84
85 /*
86   return first host IP
87 */
88 function hostip()
89 {
90         var list = sys.interfaces();
91         return list[0];
92 }
93
94 /*
95   return current time as a ldap time string
96 */
97 function nextusn()
98 {
99         provision_next_usn = provision_next_usn+1;
100         return provision_next_usn;
101 }
102
103 /*
104   return first part of hostname
105 */
106 function hostname()
107 {
108         var s = split(".", sys.hostname());
109         return s[0];
110 }
111
112
113 /*
114   erase an ldb, removing all records
115 */
116 function ldb_erase(ldb)
117 {
118         var attrs = new Array("dn");
119
120         /* delete the specials */
121         ldb.del("@INDEXLIST");
122         ldb.del("@ATTRIBUTES");
123         ldb.del("@SUBCLASSES");
124         ldb.del("@MODULES");
125
126         /* and the rest */
127         var res = ldb.search("(|(objectclass=*)(dn=*))", attrs);
128         var i;
129         for (i=0;i<res.length;i++) {
130                 ldb.del(res[i].dn);
131         }
132         res = ldb.search("(objectclass=*)", attrs);
133         assert(res.length == 0);
134 }
135
136
137 /*
138   setup a ldb in the private dir
139  */
140 function setup_ldb(ldif, dbname, subobj)
141 {
142         var extra = "";
143         var ldb = ldb_init();
144         var lp = loadparm_init();
145
146         if (arguments.length == 4) {
147                 extra = arguments[3];
148         }
149
150         var dbfile = dbname;
151         var src = lp.get("setup directory") + "/" + ldif;
152
153         var data = sys.file_load(src);
154         data = data + extra;
155         data = substitute_var(data, subobj);
156
157         var ok = ldb.connect(dbfile);
158         assert(ok);
159
160         ldb_erase(ldb);
161
162         ok = ldb.add(data);
163         assert(ok);
164 }
165
166 /*
167   setup a file in the private dir
168  */
169 function setup_file(template, fname, subobj)
170 {
171         var lp = loadparm_init();
172         var f = fname;
173         var src = lp.get("setup directory") + "/" + template;
174
175         sys.unlink(f);
176
177         var data = sys.file_load(src);
178         data = substitute_var(data, subobj);
179
180         ok = sys.file_save(f, data);
181         assert(ok);
182 }
183
184 /*
185   provision samba4 - caution, this wipes all existing data!
186 */
187 function provision(subobj, message)
188 {
189         var data = "";
190         var lp = loadparm_init();
191         var sys = sys_init();
192         var smbconf = lp.get("config file");
193
194         /*
195           some options need to be upper/lower case
196         */
197         subobj.REALM       = strlower(subobj.REALM);
198         subobj.HOSTNAME    = strlower(subobj.HOSTNAME);
199         subobj.DOMAIN      = strupper(subobj.DOMAIN);
200         subobj.NETBIOSNAME = strupper(subobj.HOSTNAME);
201
202         data = add_foreign(data, "S-1-5-7",  "Anonymous",           "${NOBODY}");
203         data = add_foreign(data, "S-1-1-0",  "World",               "${NOGROUP}");
204         data = add_foreign(data, "S-1-5-2",  "Network",             "${NOGROUP}");
205         data = add_foreign(data, "S-1-5-18", "System",              "${ROOT}");
206         data = add_foreign(data, "S-1-5-11", "Authenticated Users", "${USERS}");
207
208         provision_next_usn = 1;
209
210         /* only install a new smb.conf if there isn't one there already */
211         var st = sys.stat(smbconf);
212         if (st == undefined) {
213                 message("Setting up smb.conf\n");
214                 setup_file("provision.smb.conf", smbconf, subobj);
215                 lp.reload();
216         }
217         message("Setting up hklm.ldb\n");
218         setup_ldb("hklm.ldif", "hklm.ldb", subobj);
219         message("Setting up sam.ldb\n");
220         setup_ldb("provision.ldif", "sam.ldb", subobj, data);
221         message("Setting up rootdse.ldb\n");
222         setup_ldb("rootdse.ldif", "rootdse.ldb", subobj);
223         message("Setting up secrets.ldb\n");
224         setup_ldb("secrets.ldif", "secrets.ldb", subobj);
225         message("Setting up DNS zone file\n");
226         setup_file("provision.zone", 
227                    lp.get("private dir") + "/" + subobj.DNSDOMAIN + ".zone", 
228                    subobj);
229 }
230
231 /*
232   guess reasonably default options for provisioning
233 */
234 function provision_guess()
235 {
236         var subobj = new Object();
237         var nss = nss_init();
238         var lp = loadparm_init();
239         random_init(local);
240
241         subobj.REALM        = lp.get("realm");
242         subobj.DOMAIN       = lp.get("workgroup");
243         subobj.HOSTNAME     = hostname();
244
245         assert(subobj.REALM);
246         assert(subobj.DOMAIN);
247         assert(subobj.HOSTNAME);
248
249         subobj.HOSTIP       = hostip();
250         subobj.DOMAINGUID   = randguid();
251         subobj.DOMAINSID    = randsid();
252         subobj.HOSTGUID     = randguid();
253         subobj.INVOCATIONID = randguid();
254         subobj.KRBTGTPASS   = randpass(12);
255         subobj.MACHINEPASS  = randpass(12);
256         subobj.ADMINPASS    = randpass(12);
257         subobj.DEFAULTSITE  = "Default-First-Site-Name";
258         subobj.NEWGUID      = randguid;
259         subobj.NTTIME       = nttime;
260         subobj.LDAPTIME     = ldaptime;
261         subobj.DATESTRING   = datestring;
262         subobj.USN          = nextusn;
263         subobj.ROOT         = findnss(nss.getpwnam, "root");
264         subobj.NOBODY       = findnss(nss.getpwnam, "nobody");
265         subobj.NOGROUP      = findnss(nss.getgrnam, "nogroup", "nobody");
266         subobj.WHEEL        = findnss(nss.getgrnam, "wheel", "root");
267         subobj.USERS        = findnss(nss.getgrnam, "users", "guest", "other");
268         subobj.DNSDOMAIN    = strlower(subobj.REALM);
269         subobj.DNSNAME      = sprintf("%s.%s", 
270                                       strlower(subobj.HOSTNAME), 
271                                       subobj.DNSDOMAIN);
272         subobj.BASEDN       = "DC=" + join(",DC=", split(".", subobj.REALM));
273         return subobj;
274 }
275
276 /*
277   search for one attribute as a string
278  */
279 function searchone(ldb, expression, attribute)
280 {
281         var attrs = new Array(attribute);
282         res = ldb.search(expression, attrs);
283         if (res.length != 1 ||
284             res[0][attribute] == undefined) {
285                 return undefined;
286         }
287         return res[0][attribute];
288 }
289
290 /*
291   add a new user record
292 */
293 function newuser(username, unixname, password, message)
294 {
295         var lp = loadparm_init();
296         var samdb = lp.get("sam database");
297         var ldb = ldb_init();
298         random_init(local);
299
300         /* connect to the sam */
301         var ok = ldb.connect(samdb);
302         assert(ok);
303
304         /* find the DNs for the domain and the domain users group */
305         var domain_dn = searchone(ldb, "objectClass=domainDNS", "dn");
306         assert(domain_dn != undefined);
307         var dom_users = searchone(ldb, "name=Domain Users", "dn");
308         assert(dom_users != undefined);
309
310         var user_dn = sprintf("CN=%s,CN=Users,%s", username, domain_dn);
311
312
313         /*
314           the new user record. note the reliance on the samdb module to fill
315           in a sid, guid etc
316         */
317         var ldif = sprintf("
318 dn: %s
319 sAMAccountName: %s
320 name: %s
321 memberOf: %s
322 unixName: %s
323 objectGUID: %s
324 unicodePwd: %s
325 objectClass: user
326 ",
327                            user_dn, username, username, dom_users,
328                            unixname, randguid(), password);
329         /*
330           add the user to the users group as well
331         */
332         var modgroup = sprintf("
333 dn: %s
334 changetype: modify
335 add: member
336 member: %s
337 ", 
338                                dom_users, user_dn);
339
340
341         /*
342           now the real work
343         */
344         message("Adding user %s\n", user_dn);
345         ok = ldb.add(ldif);
346         if (ok != true) {
347                 message("Failed to add %s - %s\n", user_dn, ldb.errstring());
348                 return false;
349         }
350
351         message("Modifying group %s\n", dom_users);
352         ok = ldb.modify(modgroup);
353         if (ok != true) {
354                 message("Failed to modify %s - %s\n", dom_users, ldb.errstring());
355                 return false;
356         }
357
358         return true;
359 }
360
361
362 return 0;