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