r9899: Be more conservative about what is sent to the remote server in ldb_map.
[samba.git] / source / scripting / libjs / upgrade.js
1 /*
2         backend code for upgrading from Samba3
3         Copyright Jelmer Vernooij 2005
4         Released under the GNU GPL v2 or later
5 */
6
7 libinclude("base.js");
8
9 function regkey_to_dn(name)
10 {
11         var dn = "hive=NONE";
12         var i = 0;
13
14         var as = split("/", name);
15
16         for (i in as) {
17                 if (i > 0) {
18                         dn = sprintf("key=%s,", as[i]) + dn;
19                 }
20         }
21
22         return dn;
23 }
24
25 /* Where prefix is any of:
26  * - HKLM
27  *   HKU
28  *   HKCR
29  *   HKPD
30  *   HKPT
31  */
32
33 function upgrade_registry(regdb,prefix,ldb)
34 {
35         assert(regdb != undefined);
36         var prefix_up = strupper(prefix);
37         var ldif = new Array();
38
39         for (var i in regdb.keys) {
40                 var rk = regdb.keys[i];
41                 var pts = split("/", rk.name);
42
43                 /* Only handle selected hive */
44                 if (strupper(pts[0]) != prefix_up) {
45                         continue;
46                 }
47
48                 var keydn = regkey_to_dn(rk.name);
49
50                 var pts = split("/", rk.name);
51
52                 /* Convert key name to dn */
53                 ldif[rk.name] = sprintf("
54 dn: %s
55 name: %s
56
57 ", keydn, pts[0]);
58                 
59                 for (var j in rk.values) {
60                         var rv = rk.values[j];
61
62                         ldif[rk.name + " (" + rv.name + ")"] = sprintf("
63 dn: %s,value=%s
64 value: %s
65 type: %d
66 data:: %s", keydn, rv.name, rv.name, rv.type, ldb.encode(rv.data));
67                 }
68         }
69
70         return ldif;
71 }
72
73 function upgrade_sam_policy(samba3,dn)
74 {
75         var ldif = sprintf("
76 dn: %s
77 changetype: modify
78 replace: minPwdLength
79 minPwdLength: %d
80 pwdHistoryLength: %d
81 minPwdAge: %d
82 maxPwdAge: %d
83 lockoutDuration: %d
84 samba3ResetCountMinutes: %d
85 samba3UserMustLogonToChangePassword: %d
86 samba3BadLockoutMinutes: %d
87 samba3DisconnectTime: %d
88 samba3RefuseMachinePwdChange: %d
89
90 ", dn, samba3.policy.min_password_length, 
91         samba3.policy.password_history, samba3.policy.minimum_password_age,
92         samba3.policy.maximum_password_age, samba3.policy.lockout_duration,
93         samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password,
94         samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time, 
95         samba3.policy.refuse_machine_password_change
96 );
97         
98         return ldif;
99 }
100
101 function upgrade_sam_account(ldb,acc,domaindn,domainsid)
102 {
103         if (acc.nt_username == undefined) {
104                 acc.nt_username = acc.username;
105         }       
106
107         if (acc.nt_username == "") {
108                 acc.nt_username = acc.username;
109         }       
110
111         if (acc.fullname == undefined) {
112                 var pw = nss.getpwnam(acc.fullname);
113                 acc.fullname = pw.pw_gecos;
114         }
115
116         var pts = split(',', acc.fullname);
117         acc.fullname = pts[0];
118         
119         assert(acc.fullname != undefined);
120         assert(acc.nt_username != undefined);
121
122         var ldif = sprintf(
123 "dn: cn=%s,%s
124 objectClass: top
125 objectClass: user
126 lastLogon: %d
127 lastLogoff: %d
128 unixName: %s
129 name: %s
130 sAMAccountName: %s
131 cn: %s
132 description: %s
133 primaryGroupID: %d
134 badPwdcount: %d
135 logonCount: %d
136 samba3Domain: %s
137 samba3DirDrive: %s
138 samba3MungedDial: %s
139 samba3Homedir: %s
140 samba3LogonScript: %s
141 samba3ProfilePath: %s
142 samba3Workstations: %s
143 samba3KickOffTime: %d
144 samba3BadPwdTime: %d
145 samba3PassLastSetTime: %d
146 samba3PassCanChangeTime: %d
147 samba3PassMustChangeTime: %d
148 objectSid: %s-%d
149 ntPwdHash:: %s
150 lmPwdHash:: %s
151
152 ", acc.fullname, domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, 
153
154 acc.fullname, acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count,
155 acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, 
156 acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, 
157 acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid,
158         ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)); 
159
160         return ldif;
161 }
162
163 function upgrade_sam_group(grp,domaindn)
164 {
165         var nss = nss_init();
166
167         var gr;
168         if (grp.sid_name_use == 5) { // Well-known group
169                 return undefined;
170         }
171
172         if (grp.nt_name == "Domain Guests" ||
173             grp.nt_name == "Domain Users" ||
174             grp.nt_name == "Domain Admins") {
175                 return undefined;
176         }
177         
178         if (grp.gid == -1) {
179                 gr = nss.getgrnam(grp.nt_name);
180         } else {
181                 gr = nss.getgrgid(grp.gid);
182         }
183
184         if (gr == undefined) {
185                 grp.unixname = "UNKNOWN";
186         } else {
187                 grp.unixname = gr.gr_name;
188         }
189
190         assert(grp.unixname != undefined);
191         
192         var ldif = sprintf(
193 "dn: cn=%s,%s
194 objectClass: top
195 objectClass: group
196 description: %s
197 cn: %s
198 objectSid: %s
199 unixName: %s
200 samba3SidNameUse: %d
201 ", grp.nt_name, domaindn, 
202 grp.comment, grp.nt_name, grp.sid, grp.unixname, grp.sid_name_use);
203
204         return ldif;
205 }
206
207 function upgrade_winbind(samba3,domaindn)
208 {
209         var ldif = sprintf("
210                 
211 dn: dc=none
212 userHwm: %d
213 groupHwm: %d
214
215 ", samba3.idmap.user_hwm, samba3.idmap.group_hwm);
216
217         for (var i in samba3.idmap.mappings) {
218                 var m = samba3.idmap.mappings[i];
219                 ldif = ldif + sprintf("
220 dn: SID=%s,%s
221 SID: %s
222 type: %d
223 unixID: %d", m.sid, domaindn, m.sid, m.type, m.unix_id);
224         }
225         
226         return ldif;
227 }
228 */
229
230 function upgrade_wins(samba3)
231 {
232         var ldif = "";
233         for (i in samba3.winsentries) {
234                 var e = samba3.winsentries[i];
235                 
236                 ldif = ldif + sprintf("
237 dn: type=%d,name=%s
238 name: %s
239 objectClass: wins
240 nbFlags: %x
241 expires: %s
242 ", e.type, e.name, e.name, e.type, e.nb_flags, sys.ldaptime(e.ttl));
243
244                 for (var i in e.ips) {
245                         ldif = ldif + sprintf("address: %s\n", e.ips[i]);
246                 }
247         }
248
249         return ldif;
250 }
251
252 function upgrade_provision(samba3)
253 {
254         var subobj = new Object();
255         var nss = nss_init();
256         var lp = loadparm_init();
257         var rdn_list;
258
259         var domainname = samba3.configuration.get("workgroup");
260         
261         if (domainname == undefined) {
262                 domainname = samba3.secrets.domains[0].name;
263                 println("No domain specified in smb.conf file, assuming '" + domainname + "'");
264         }
265         
266         var domsec = samba3.find_domainsecrets(domainname);
267         var hostsec = samba3.find_domainsecrets(hostname());
268         var realm = samba3.configuration.get("realm");
269
270         if (realm == undefined) {
271                 realm = domainname;
272                 println("No realm specified in smb.conf file, assuming '" + realm + "'");
273         }
274         random_init(local);
275
276         subobj.REALM        = realm;
277         subobj.DOMAIN       = domainname;
278         subobj.HOSTNAME     = hostname();
279
280         assert(subobj.REALM);
281         assert(subobj.DOMAIN);
282         assert(subobj.HOSTNAME);
283
284         subobj.HOSTIP       = hostip();
285         if (domsec != undefined) {
286                 subobj.DOMAINGUID   = domsec.guid;
287                 subobj.DOMAINSID    = domsec.sid;
288         } else {
289                 println("Can't find domain secrets for '" + domainname + "'; using random SID and GUID");
290                 subobj.DOMAINGUID = randguid();
291                 subobj.DOMAINSID = randsid();
292         }
293         
294         if (hostsec) {
295                 subobj.HOSTGUID     = hostsec.guid;
296         } else {
297                 subobj.HOSTGUID = randguid();
298         }
299         subobj.INVOCATIONID = randguid();
300         subobj.KRBTGTPASS   = randpass(12);
301         subobj.MACHINEPASS  = randpass(12);
302         subobj.ADMINPASS    = randpass(12);
303         subobj.DEFAULTSITE  = "Default-First-Site-Name";
304         subobj.NEWGUID      = randguid;
305         subobj.NTTIME       = nttime;
306         subobj.LDAPTIME     = ldaptime;
307         subobj.DATESTRING   = datestring;
308         subobj.USN          = nextusn;
309         subobj.ROOT         = findnss(nss.getpwnam, "root");
310         subobj.NOBODY       = findnss(nss.getpwnam, "nobody");
311         subobj.NOGROUP      = findnss(nss.getgrnam, "nogroup", "nobody");
312         subobj.WHEEL        = findnss(nss.getgrnam, "wheel", "root");
313         subobj.USERS        = findnss(nss.getgrnam, "users", "guest", "other");
314         subobj.DNSDOMAIN    = strlower(subobj.REALM);
315         subobj.DNSNAME      = sprintf("%s.%s", 
316                                       strlower(subobj.HOSTNAME), 
317                                       subobj.DNSDOMAIN);
318         subobj.BASEDN       = "DC=" + join(",DC=", split(".", subobj.REALM));
319         rdn_list = split(".", subobj.REALM);
320         return subobj;
321 }
322
323 smbconf_keep = new Array(
324         "dos charset", 
325         "unix charset",
326         "display charset",
327         "comment",
328         "path",
329         "directory",
330         "workgroup",
331         "realm",
332         "netbios name",
333         "netbios aliases",
334         "netbios scope",
335         "server string",
336         "interfaces",
337         "bind interfaces only",
338         "security",
339         "auth methods",
340         "encrypt passwords",
341         "null passwords",
342         "obey pam restrictions",
343         "password server",
344         "smb passwd file",
345         "private dir",
346         "passwd chat",
347         "password level",
348         "lanman auth",
349         "ntlm auth",
350         "client NTLMv2 auth",
351         "client lanman auth",
352         "client plaintext auth",
353         "read only",
354         "hosts allow",
355         "hosts deny",
356         "log level",
357         "debuglevel",
358         "log file",
359         "smb ports",
360         "large readwrite",
361         "max protocol",
362         "min protocol",
363         "unicode",
364         "read raw",
365         "write raw",
366         "disable netbios",
367         "nt status support",
368         "announce version",
369         "announce as",
370         "max mux",
371         "max xmit",
372         "name resolve order",
373         "max wins ttl",
374         "min wins ttl",
375         "time server",
376         "unix extensions",
377         "use spnego",
378         "server signing",
379         "client signing",
380         "max connections",
381         "paranoid server security",
382         "socket options",
383         "strict sync",
384         "max print jobs",
385         "printable",
386         "print ok",
387         "printer name",
388         "printer",
389         "map system",
390         "map hidden",
391         "map archive",
392         "domain logons",
393         "preferred master",
394         "prefered master",
395         "local master",
396         "domain master",
397         "browseable",
398         "browsable",
399         "wins server",
400         "wins support",
401         "csc policy",
402         "strict locking",
403         "config file",
404         "preload",
405         "auto services",
406         "lock dir",
407         "lock directory",
408         "pid directory",
409         "socket address",
410         "copy",
411         "include",
412         "available",
413         "volume",
414         "fstype",
415         "panic action",
416         "msdfs root",
417         "host msdfs",
418         "winbind separator");
419
420 /*
421    Remove configuration variables not present in Samba4
422         oldconf: Old configuration structure
423         mark: Whether removed configuration variables should be 
424                 kept in the new configuration as "samba3:<name>"
425  */
426 function upgrade_smbconf(oldconf,mark)
427 {
428         var data = oldconf.data();
429         var newconf = param_init();
430
431         for (var s in data) {
432                 for (var p in data[s]) {
433                         var keep = false;
434                         for (var k in smbconf_keep) { 
435                                 if (smbconf_keep[k] == p) {
436                                         keep = true;
437                                         break;
438                                 }
439                         }
440
441                         if (keep) {
442                                 newconf.set(s, p, oldconf.get(s, p));
443                         } else if (mark) {
444                                 newconf.set(s, "samba3:"+p, oldconf.get(s,p));
445                         }
446                 }
447         }
448
449         return newconf;
450 }
451
452 function upgrade(subobj, samba3, message, paths)
453 {
454         var ret = 0;
455         var lp = loadparm_init();
456         var samdb = ldb_init();
457         var ok = samdb.connect(paths.samdb);
458         assert(ok);
459
460         message("Writing configuration\n");
461         var newconf = upgrade_smbconf(samba3.configuration,true);
462         newconf.save(paths.smbconf);
463
464         message("Importing account policies\n");
465         var ldif = upgrade_sam_policy(samba3,subobj.BASEDN);
466         ok = samdb.modify(ldif);
467         assert(ok);
468
469         message("Importing users\n");
470         for (var i in samba3.samaccounts) {
471                 var msg = "... " + samba3.samaccounts[i].username;
472                 var ldif = upgrade_sam_account(samdb,samba3.samaccounts[i],subobj.BASEDN,subobj.DOMAINSID);
473                 ok = samdb.add(ldif);
474                 if (!ok && samdb.errstring() != "Record exists") { 
475                         msg = msg + "... error: " + samdb.errstring();
476                         ret = ret + 1; 
477                 }
478                 message(msg + "\n");
479         }
480
481         message("Importing groups\n");
482         for (var i in samba3.groupmappings) {
483                 var msg = "... " + samba3.groupmappings[i].nt_name;
484                 var ldif = upgrade_sam_group(samba3.groupmappings[i],subobj.BASEDN);
485                 if (ldif != undefined) {
486                         ok = samdb.add(ldif);
487                         if (!ok && samdb.errstring() != "Record exists") { 
488                                 msg = msg + "... error: " + samdb.errstring();
489                                 ret = ret + 1; 
490                         }
491                 }
492                 message(msg + "\n");
493         }
494
495         message("Importing registry data\n");
496         var hives = new Array("hkcr","hkcu","hklm","hkpd","hku","hkpt"); 
497         for (var i in hives) {
498                 var hn = hives[i];
499                 message("... " + hn + "\n");
500                 var regdb = ldb_init();
501                 ok = regdb.connect(paths[hn]);
502                 assert(ok);
503                 var ldif = upgrade_registry(samba3.registry, hn, regdb);
504                 for (var j in ldif) {
505                         var msg = "... ... " + j;
506                         ok = regdb.add(ldif[j]);
507                         if (!ok && regdb.errstring() != "Record exists") { 
508                                 msg = msg + "... error: " + regdb.errstring();
509                                 ret = ret + 1; 
510                         }
511                         message(msg + "\n");
512                 }
513         }
514
515         message("Importing WINS data\n");
516         var winsdb = ldb_init();
517         ok = winsdb.connect(paths.winsdb);
518         assert(ok);
519         ldb_erase(winsdb);
520
521         var ldif = upgrade_wins(samba3);
522         ok = winsdb.add(ldif);
523         assert(ok);
524
525         // figure out ldapurl, if applicable
526         var ldapurl = undefined;
527         var pdb = samba3.configuration.get_list("passdb backend");
528         if (pdb != undefined) {
529                 for (var b in pdb) {
530                         if (substr(pdb[b], 0, 7) == "ldapsam") {
531                                 ldapurl = substr(pdb[b], 8);
532                         }
533                 }
534         }
535
536         // URL was not specified in passdb backend but ldap /is/ used
537         if (ldapurl == "") {
538                 ldapurl = "ldap://" + samba3.configuration.get("ldap server");
539         }
540
541         // Enable samba3sam module if original passdb backend was ldap
542         if (ldapurl != undefined) {
543                 message("Enabling Samba3 LDAP mappings for SAM database\n");
544
545                 ok = samdb.modify("
546 dn: @MODULES
547 changetype: modify
548 replace: @LIST
549 @LIST: samldb,timestamps,objectguid,rdn_name,samba3sam
550 ");
551                 if (!ok) {
552                         message("Error enabling samba3sam module: " + samdb.errstring() + "\n");
553                         ret = ret + 1;
554                 }
555
556                 ok = samdb.add(sprintf("
557 dn: @MAP=samba3sam
558 @MAP_URL: %s", ldapurl));
559                 assert(ok);
560
561         }
562
563         return ret;
564 }
565
566 function upgrade_verify(subobj, samba3,paths,message)
567 {
568         message("Verifying account policies\n");
569         var samldb = ldb_init();
570         var ne = 0;
571
572         var ok = samldb.connect(paths.samdb);
573         assert(ok);
574
575         for (var i in samba3.samaccounts) {
576                 var msg = samldb.search("(&(sAMAccountName=" + samba3.samaccounts[i].nt_username + ")(objectclass=user))");
577                 assert(msg.length >= 1);
578         }
579         
580         // FIXME
581 }