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