r8639: moved loadparm calls into an ejs object
[samba.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 = lp.get("private dir") + "/" + 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
191         /*
192           some options need to be upper/lower case
193         */
194         subobj.REALM       = strlower(subobj.REALM);
195         subobj.HOSTNAME    = strlower(subobj.HOSTNAME);
196         subobj.DOMAIN      = strupper(subobj.DOMAIN);
197         subobj.NETBIOSNAME = strupper(subobj.HOSTNAME);
198
199         data = add_foreign(data, "S-1-5-7",  "Anonymous",           "${NOBODY}");
200         data = add_foreign(data, "S-1-1-0",  "World",               "${NOGROUP}");
201         data = add_foreign(data, "S-1-5-2",  "Network",             "${NOGROUP}");
202         data = add_foreign(data, "S-1-5-18", "System",              "${ROOT}");
203         data = add_foreign(data, "S-1-5-11", "Authenticated Users", "${USERS}");
204
205         provision_next_usn = 1;
206
207         message("Setting up hklm.ldb\n");
208         setup_ldb("hklm.ldif", "hklm.ldb", subobj);
209         message("Setting up sam.ldb\n");
210         setup_ldb("provision.ldif", "sam.ldb", subobj, data);
211         message("Setting up rootdse.ldb\n");
212         setup_ldb("rootdse.ldif", "rootdse.ldb", subobj);
213         message("Setting up secrets.ldb\n");
214         setup_ldb("secrets.ldif", "secrets.ldb", subobj);
215         message("Setting up DNS zone file\n");
216         setup_file("provision.zone", subobj.DNSDOMAIN + ".zone", subobj);
217 }
218
219 /*
220   guess reasonably default options for provisioning
221 */
222 function provision_guess()
223 {
224         var subobj = new Object();
225         var nss = nss_init();
226         var lp = loadparm_init();
227
228         subobj.REALM        = lp.get("realm");
229         subobj.DOMAIN       = lp.get("workgroup");
230         subobj.HOSTNAME     = hostname();
231         subobj.HOSTIP       = hostip();
232         subobj.DOMAINGUID   = randguid();
233         subobj.DOMAINSID    = randsid();
234         subobj.HOSTGUID     = randguid();
235         subobj.INVOCATIONID = randguid();
236         subobj.KRBTGTPASS   = randpass(12);
237         subobj.MACHINEPASS  = randpass(12);
238         subobj.ADMINPASS    = randpass(12);
239         subobj.DEFAULTSITE  = "Default-First-Site-Name";
240         subobj.NEWGUID      = randguid;
241         subobj.NTTIME       = nttime;
242         subobj.LDAPTIME     = ldaptime;
243         subobj.DATESTRING   = datestring;
244         subobj.USN          = nextusn;
245         subobj.ROOT         = findnss(nss.getpwnam, "root");
246         subobj.NOBODY       = findnss(nss.getpwnam, "nobody");
247         subobj.NOGROUP      = findnss(nss.getgrnam, "nogroup", "nobody");
248         subobj.WHEEL        = findnss(nss.getgrnam, "wheel", "root");
249         subobj.USERS        = findnss(nss.getgrnam, "users", "guest", "other");
250         subobj.DNSDOMAIN    = strlower(subobj.REALM);
251         subobj.DNSNAME      = sprintf("%s.%s", 
252                                       strlower(subobj.HOSTNAME), 
253                                       subobj.DNSDOMAIN);
254         subobj.BASEDN       = "DC=" + join(",DC=", split(".", subobj.REALM));
255         return subobj;
256 }
257
258 /*
259   search for one attribute as a string
260  */
261 function searchone(ldb, expression, attribute)
262 {
263         var attrs = new Array(attribute);
264         res = ldb.search(expression, attrs);
265         if (res.length != 1 ||
266             res[0][attribute] == undefined) {
267                 return undefined;
268         }
269         return res[0][attribute];
270 }
271
272 /*
273   add a new user record
274 */
275 function newuser(username, unixname, password, message)
276 {
277         var lp = loadparm_init();
278         var samdb = lp.get("sam database");
279         var ldb = ldb_init();
280
281         /* connect to the sam */
282         var ok = ldb.connect(samdb);
283         assert(ok);
284
285         /* find the DNs for the domain and the domain users group */
286         var domain_dn = searchone(ldb, "objectClass=domainDNS", "dn");
287         assert(domain_dn != undefined);
288         var dom_users = searchone(ldb, "name=Domain Users", "dn");
289         assert(dom_users != undefined);
290
291         var user_dn = sprintf("CN=%s,CN=Users,%s", username, domain_dn);
292
293
294         /*
295           the new user record. note the reliance on the samdb module to fill
296           in a sid, guid etc
297         */
298         var ldif = sprintf("
299 dn: %s
300 sAMAccountName: %s
301 name: %s
302 memberOf: %s
303 unixName: %s
304 objectGUID: %s
305 unicodePwd: %s
306 objectClass: user
307 ",
308                            user_dn, username, username, dom_users,
309                            unixname, randguid(), password);
310         /*
311           add the user to the users group as well
312         */
313         var modgroup = sprintf("
314 dn: %s
315 changetype: modify
316 add: member
317 member: %s
318 ", 
319                                dom_users, user_dn);
320
321
322         /*
323           now the real work
324         */
325         message("Adding user %s\n", user_dn);
326         ok = ldb.add(ldif);
327         if (ok != true) {
328                 message("Failed to add %s - %s\n", user_dn, ldb.errstring());
329                 return false;
330         }
331
332         message("Modifying group %s\n", dom_users);
333         ok = ldb.modify(modgroup);
334         if (ok != true) {
335                 message("Failed to modify %s - %s\n", dom_users, ldb.errstring());
336                 return false;
337         }
338
339         return true;
340 }
341
342
343 return 0;