r12945: Try to move closer to getting Samba3 import working again.
[kai/samba.git] / source4 / 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
89 ", dn, samba3.policy.min_password_length, 
90         samba3.policy.password_history, samba3.policy.minimum_password_age,
91         samba3.policy.maximum_password_age, samba3.policy.lockout_duration,
92         samba3.policy.reset_count_minutes, samba3.policy.user_must_logon_to_change_password,
93         samba3.policy.bad_lockout_minutes, samba3.policy.disconnect_time
94 );
95         
96         return ldif;
97 }
98
99 function upgrade_sam_account(ldb,acc,domaindn,domainsid)
100 {
101         if (acc.nt_username == undefined) {
102                 acc.nt_username = acc.username;
103         }       
104
105         if (acc.nt_username == "") {
106                 acc.nt_username = acc.username;
107         }       
108
109         if (acc.fullname == undefined) {
110                 var pw = nss.getpwnam(acc.fullname);
111                 acc.fullname = pw.pw_gecos;
112         }
113
114         var pts = split(',', acc.fullname);
115         acc.fullname = pts[0];
116
117         if (acc.fullname == undefined) {
118                 acc.fullname = acc.username;
119         }
120         
121         assert(acc.fullname != undefined);
122         assert(acc.nt_username != undefined);
123
124         var ldif = sprintf(
125 "dn: cn=%s,%s
126 objectClass: top
127 objectClass: user
128 lastLogon: %d
129 lastLogoff: %d
130 unixName: %s
131 sAMAccountName: %s
132 cn: %s
133 description: %s
134 primaryGroupID: %d
135 badPwdcount: %d
136 logonCount: %d
137 samba3Domain: %s
138 samba3DirDrive: %s
139 samba3MungedDial: %s
140 samba3Homedir: %s
141 samba3LogonScript: %s
142 samba3ProfilePath: %s
143 samba3Workstations: %s
144 samba3KickOffTime: %d
145 samba3BadPwdTime: %d
146 samba3PassLastSetTime: %d
147 samba3PassCanChangeTime: %d
148 samba3PassMustChangeTime: %d
149 objectSid: %s-%d
150 lmPwdHash:: %s
151 ntPwdHash:: %s
152
153 ", ldb.dn_escape(acc.fullname), domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, 
154
155 acc.acct_desc, acc.group_rid, acc.bad_password_count, acc.logon_count,
156 acc.domain, acc.dir_drive, acc.munged_dial, acc.homedir, acc.logon_script, 
157 acc.profile_path, acc.workstations, acc.kickoff_time, acc.bad_password_time, 
158 acc.pass_last_set_time, acc.pass_can_change_time, acc.pass_must_change_time, domainsid, acc.user_rid,
159         ldb.encode(acc.lm_pw), ldb.encode(acc.nt_pw)); 
160
161         return ldif;
162 }
163
164 function upgrade_sam_group(grp,domaindn)
165 {
166         var nss = nss_init();
167
168         var gr;
169         if (grp.sid_name_use == 5) { // Well-known group
170                 return undefined;
171         }
172
173         if (grp.nt_name == "Domain Guests" ||
174             grp.nt_name == "Domain Users" ||
175             grp.nt_name == "Domain Admins") {
176                 return undefined;
177         }
178         
179         if (grp.gid == -1) {
180                 gr = nss.getgrnam(grp.nt_name);
181         } else {
182                 gr = nss.getgrgid(grp.gid);
183         }
184
185         if (gr == undefined) {
186                 grp.unixname = "UNKNOWN";
187         } else {
188                 grp.unixname = gr.gr_name;
189         }
190
191         assert(grp.unixname != undefined);
192         
193         var ldif = sprintf(
194 "dn: cn=%s,%s
195 objectClass: top
196 objectClass: group
197 description: %s
198 cn: %s
199 objectSid: %s
200 unixName: %s
201 samba3SidNameUse: %d
202 ", grp.nt_name, domaindn, 
203 grp.comment, grp.nt_name, grp.sid, grp.unixname, grp.sid_name_use);
204
205         return ldif;
206 }
207
208 function upgrade_winbind(samba3,domaindn)
209 {
210         var ldif = sprintf("
211                 
212 dn: dc=none
213 userHwm: %d
214 groupHwm: %d
215
216 ", samba3.idmap.user_hwm, samba3.idmap.group_hwm);
217
218         for (var i in samba3.idmap.mappings) {
219                 var m = samba3.idmap.mappings[i];
220                 ldif = ldif + sprintf("
221 dn: SID=%s,%s
222 SID: %s
223 type: %d
224 unixID: %d", m.sid, domaindn, m.sid, m.type, m.unix_id);
225         }
226         
227         return ldif;
228 }
229 */
230
231 function upgrade_wins(samba3)
232 {
233         var ldif = "";
234         var version_id = 0;
235
236         for (i in samba3.winsentries) {
237                 var rType;
238                 var rState;
239                 var nType;
240                 var numIPs = 0;
241                 var e = samba3.winsentries[i];
242                 var now = sys.nttime();
243                 var ttl = sys.unix2nttime(e.ttl);
244
245                 version_id++;
246
247                 for (var i in e.ips) {
248                         numIPs++;
249                 }
250
251                 if (e.type == 0x1C) {
252                         rType = 0x2;
253                 } else if (sys.bitAND(e.type, 0x80)) {
254                         if (numIPs > 1) {
255                                 rType = 0x2;
256                         } else {
257                                 rType = 0x1;
258                         }
259                 } else {
260                         if (numIPs > 1) {
261                                 rType = 0x3;
262                         } else {
263                                 rType = 0x0;
264                         }
265                 }
266
267                 if (ttl > now) {
268                         rState = 0x0;/* active */
269                 } else {
270                         rState = 0x1;/* released */             
271                 }
272
273                 nType = (sys.bitAND(e.nb_flags,0x60)>>5);
274
275                 ldif = ldif + sprintf("
276 dn: name:%s,type=0x%02X
277 type: 0x%02X
278 name: %s
279 objectClass: winsRecord
280 recordType: %u
281 recordState: %u
282 nodeType: %u
283 isStatic: 0
284 expireTime: %s
285 versionID: %llu
286 ", e.name, e.type, e.type, e.name, 
287    rType, rState, nType, 
288    sys.ldaptime(ttl), version_id);
289
290                 for (var i in e.ips) {
291                         ldif = ldif + sprintf("address: %s\n", e.ips[i]);
292                 }
293         }
294
295         ldif = ldif + sprintf("
296 dn: CN=VERSION
297 objectClass: winsMaxVersion
298 maxVersion: %llu
299 ", version_id);
300
301         return ldif;
302 }
303
304 function upgrade_provision(samba3)
305 {
306         var subobj = new Object();
307         var nss = nss_init();
308         var lp = loadparm_init();
309         var rdn_list;
310
311         var domainname = samba3.configuration.get("workgroup");
312         
313         if (domainname == undefined) {
314                 domainname = samba3.secrets.domains[0].name;
315                 println("No domain specified in smb.conf file, assuming '" + domainname + "'");
316         }
317         
318         var domsec = samba3.find_domainsecrets(domainname);
319         var hostsec = samba3.find_domainsecrets(hostname());
320         var realm = samba3.configuration.get("realm");
321
322         if (realm == undefined) {
323                 realm = domainname;
324                 println("No realm specified in smb.conf file, assuming '" + realm + "'");
325         }
326         random_init(local);
327
328         subobj.REALM        = realm;
329         subobj.DOMAIN       = domainname;
330         subobj.HOSTNAME     = hostname();
331
332         assert(subobj.REALM);
333         assert(subobj.DOMAIN);
334         assert(subobj.HOSTNAME);
335
336         subobj.HOSTIP       = hostip();
337         if (domsec != undefined) {
338                 subobj.DOMAINGUID   = domsec.guid;
339                 subobj.DOMAINSID    = domsec.sid;
340         } else {
341                 println("Can't find domain secrets for '" + domainname + "'; using random SID and GUID");
342                 subobj.DOMAINGUID = randguid();
343                 subobj.DOMAINSID = randsid();
344         }
345         
346         if (hostsec) {
347                 subobj.HOSTGUID     = hostsec.guid;
348         } else {
349                 subobj.HOSTGUID = randguid();
350         }
351         subobj.INVOCATIONID = randguid();
352         subobj.KRBTGTPASS   = randpass(12);
353         subobj.MACHINEPASS  = randpass(12);
354         subobj.ADMINPASS    = randpass(12);
355         subobj.DEFAULTSITE  = "Default-First-Site-Name";
356         subobj.NEWGUID      = randguid;
357         subobj.NTTIME       = nttime;
358         subobj.LDAPTIME     = ldaptime;
359         subobj.DATESTRING   = datestring;
360         subobj.USN          = nextusn;
361         subobj.ROOT         = findnss(nss.getpwnam, "root");
362         subobj.NOBODY       = findnss(nss.getpwnam, "nobody");
363         subobj.NOGROUP      = findnss(nss.getgrnam, "nogroup", "nobody");
364         subobj.WHEEL        = findnss(nss.getgrnam, "wheel", "root");
365         subobj.USERS        = findnss(nss.getgrnam, "users", "guest", "other");
366         subobj.DNSDOMAIN    = strlower(subobj.REALM);
367         subobj.DNSNAME      = sprintf("%s.%s", 
368                                       strlower(subobj.HOSTNAME), 
369                                       subobj.DNSDOMAIN);
370         subobj.BASEDN       = "DC=" + join(",DC=", split(".", subobj.REALM));
371         rdn_list = split(".", subobj.REALM);
372         return subobj;
373 }
374
375 smbconf_keep = new Array(
376         "dos charset", 
377         "unix charset",
378         "display charset",
379         "comment",
380         "path",
381         "directory",
382         "workgroup",
383         "realm",
384         "netbios name",
385         "netbios aliases",
386         "netbios scope",
387         "server string",
388         "interfaces",
389         "bind interfaces only",
390         "security",
391         "auth methods",
392         "encrypt passwords",
393         "null passwords",
394         "obey pam restrictions",
395         "password server",
396         "smb passwd file",
397         "private dir",
398         "passwd chat",
399         "password level",
400         "lanman auth",
401         "ntlm auth",
402         "client NTLMv2 auth",
403         "client lanman auth",
404         "client plaintext auth",
405         "read only",
406         "hosts allow",
407         "hosts deny",
408         "log level",
409         "debuglevel",
410         "log file",
411         "smb ports",
412         "large readwrite",
413         "max protocol",
414         "min protocol",
415         "unicode",
416         "read raw",
417         "write raw",
418         "disable netbios",
419         "nt status support",
420         "announce version",
421         "announce as",
422         "max mux",
423         "max xmit",
424         "name resolve order",
425         "max wins ttl",
426         "min wins ttl",
427         "time server",
428         "unix extensions",
429         "use spnego",
430         "server signing",
431         "client signing",
432         "max connections",
433         "paranoid server security",
434         "socket options",
435         "strict sync",
436         "max print jobs",
437         "printable",
438         "print ok",
439         "printer name",
440         "printer",
441         "map system",
442         "map hidden",
443         "map archive",
444         "preferred master",
445         "prefered master",
446         "local master",
447         "browseable",
448         "browsable",
449         "wins server",
450         "wins support",
451         "csc policy",
452         "strict locking",
453         "config file",
454         "preload",
455         "auto services",
456         "lock dir",
457         "lock directory",
458         "pid directory",
459         "socket address",
460         "copy",
461         "include",
462         "available",
463         "volume",
464         "fstype",
465         "panic action",
466         "msdfs root",
467         "host msdfs",
468         "winbind separator");
469
470 /*
471    Remove configuration variables not present in Samba4
472         oldconf: Old configuration structure
473         mark: Whether removed configuration variables should be 
474                 kept in the new configuration as "samba3:<name>"
475  */
476 function upgrade_smbconf(oldconf,mark)
477 {
478         var data = oldconf.data();
479         var newconf = param_init();
480
481         for (var s in data) {
482                 for (var p in data[s]) {
483                         var keep = false;
484                         for (var k in smbconf_keep) { 
485                                 if (smbconf_keep[k] == p) {
486                                         keep = true;
487                                         break;
488                                 }
489                         }
490
491                         if (keep) {
492                                 newconf.set(s, p, oldconf.get(s, p));
493                         } else if (mark) {
494                                 newconf.set(s, "samba3:"+p, oldconf.get(s,p));
495                         }
496                 }
497         }
498
499         if (oldconf.get("domain logons") == "True") {
500                 if (oldconf.get("domain master") == "True") {
501                         newconf.set("server role", "pdc");
502                 } else {
503                         newconf.set("server role", "bdc");
504                 }
505         } else {
506                 if (oldconf.get("domain master") == "True") {
507                         newconf.set("server role", "standalone");
508                 } else {
509                         newconf.set("server role", "member server");
510                 }
511         }
512
513         return newconf;
514 }
515
516 function upgrade(subobj, samba3, message, paths, session_info, credentials)
517 {
518         var ret = 0;
519         var lp = loadparm_init();
520         var samdb = ldb_init();
521         samdb.session_info = session_info;
522         samdb.credentials = credentials;
523         var ok = samdb.connect(paths.samdb);
524         if (!ok) {
525                 info.message("samdb connect failed: " + samdb.errstring() + "\n");
526                 assert(ok);
527         }
528
529         message("Writing configuration\n");
530         var newconf = upgrade_smbconf(samba3.configuration,true);
531         newconf.save(paths.smbconf);
532
533         message("Importing account policies\n");
534         var ldif = upgrade_sam_policy(samba3,subobj.BASEDN);
535         ok = samdb.modify(ldif);
536         if (!ok) {
537                 message("samdb load failed: " + samdb.errstring() + "\n");
538                 assert(ok);
539         }
540         var regdb = ldb_init();
541         ok = regdb.connect(paths.hklm);
542         if (!ok) {
543                 message("registry connect: " + regdb.errstring() + "\n");
544                 assert(ok);
545         }
546
547         ok = regdb.modify(sprintf("
548 dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE
549 replace: type
550 type: 4
551 replace: data
552 data: %d
553 ", samba3.policy.refuse_machine_password_change));
554         if (!ok) {
555                 message("registry load failed: " + regdb.errstring() + "\n");
556                 assert(ok);
557         }
558
559         message("Importing users\n");
560         for (var i in samba3.samaccounts) {
561                 var msg = "... " + samba3.samaccounts[i].username;
562                 var ldif = upgrade_sam_account(samdb,samba3.samaccounts[i],subobj.BASEDN,subobj.DOMAINSID);
563                 ok = samdb.add(ldif);
564                 if (!ok && samdb.errstring() != "Record exists") { 
565                         msg = msg + "... error: " + samdb.errstring();
566                         ret = ret + 1; 
567                 }
568                 message(msg + "\n");
569         }
570
571         message("Importing groups\n");
572         for (var i in samba3.groupmappings) {
573                 var msg = "... " + samba3.groupmappings[i].nt_name;
574                 var ldif = upgrade_sam_group(samba3.groupmappings[i],subobj.BASEDN);
575                 if (ldif != undefined) {
576                         ok = samdb.add(ldif);
577                         if (!ok && samdb.errstring() != "Record exists") { 
578                                 msg = msg + "... error: " + samdb.errstring();
579                                 ret = ret + 1; 
580                         }
581                 }
582                 message(msg + "\n");
583         }
584
585         message("Importing registry data\n");
586         var hives = new Array("hkcr","hkcu","hklm","hkpd","hku","hkpt"); 
587         for (var i in hives) {
588                 var hn = hives[i];
589                 message("... " + hn + "\n");
590                 regdb = ldb_init();
591                 ok = regdb.connect(paths[hn]);
592                 assert(ok);
593                 var ldif = upgrade_registry(samba3.registry, hn, regdb);
594                 for (var j in ldif) {
595                         var msg = "... ... " + j;
596                         ok = regdb.add(ldif[j]);
597                         if (!ok && regdb.errstring() != "Record exists") { 
598                                 msg = msg + "... error: " + regdb.errstring();
599                                 ret = ret + 1; 
600                         }
601                         message(msg + "\n");
602                 }
603         }
604
605
606         message("Importing WINS data\n");
607         var winsdb = ldb_init();
608         ok = winsdb.connect(paths.winsdb);
609         assert(ok);
610         ldb_erase(winsdb);
611
612         var ldif = upgrade_wins(samba3);
613         ok = winsdb.add(ldif);
614         assert(ok);
615
616         // figure out ldapurl, if applicable
617         var ldapurl = undefined;
618         var pdb = samba3.configuration.get_list("passdb backend");
619         if (pdb != undefined) {
620                 for (var b in pdb) {
621                         if (strlen(pdb[b]) >= 7) {
622                                 if (substr(pdb[b], 0, 7) == "ldapsam") {
623                                         ldapurl = substr(pdb[b], 8);
624                                 }
625                         }
626                 }
627         }
628
629         // URL was not specified in passdb backend but ldap /is/ used
630         if (ldapurl == "") {
631                 ldapurl = "ldap://" + samba3.configuration.get("ldap server");
632         }
633
634         // Enable samba3sam module if original passdb backend was ldap
635         if (ldapurl != undefined) {
636                 message("Enabling Samba3 LDAP mappings for SAM database\n");
637
638                 ok = samdb.modify("
639 dn: @MODULES
640 changetype: modify
641 replace: @LIST
642 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
643 ");
644                 if (!ok) {
645                         message("Error enabling samba3sam module: " + samdb.errstring() + "\n");
646                         ret = ret + 1;
647                 }
648
649                 ok = samdb.add(sprintf("
650 dn: @MAP=samba3sam
651 @MAP_URL: %s", ldapurl));
652                 assert(ok);
653
654         }
655
656         return ret;
657 }
658
659 function upgrade_verify(subobj, samba3,paths,message)
660 {
661         message("Verifying account policies\n");
662         var samldb = ldb_init();
663         var ne = 0;
664
665         var ok = samldb.connect(paths.samdb);
666         assert(ok);
667
668         for (var i in samba3.samaccounts) {
669                 var msg = samldb.search("(&(sAMAccountName=" + samba3.samaccounts[i].nt_username + ")(objectclass=user))");
670                 assert(msg.length >= 1);
671         }
672         
673         // FIXME
674 }