r21673: Fix Samba 3 data read tests. I can't figure out why the upgrade one is broken...
[ira/wip.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.ROOT         = findnss(nss.getpwnam, "root");
361         subobj.NOBODY       = findnss(nss.getpwnam, "nobody");
362         subobj.NOGROUP      = findnss(nss.getgrnam, "nogroup", "nobody");
363         subobj.WHEEL        = findnss(nss.getgrnam, "wheel", "root");
364         subobj.USERS        = findnss(nss.getgrnam, "users", "guest", "other");
365         subobj.DNSDOMAIN    = strlower(subobj.REALM);
366         subobj.DNSNAME      = sprintf("%s.%s", 
367                                       strlower(subobj.HOSTNAME), 
368                                       subobj.DNSDOMAIN);
369         subobj.BASEDN       = "DC=" + join(",DC=", split(".", subobj.REALM));
370         rdn_list = split(".", subobj.DNSDOMAIN);
371         subobj.DOMAINDN     = "DC=" + join(",DC=", rdn_list);
372         subobj.DOMAINDN_LDB = "users.ldb";
373         subobj.ROOTDN       = subobj.DOMAINDN;
374
375         modules_list        = new Array("rootdse",
376                                         "kludge_acl",
377                                         "paged_results",
378                                         "server_sort",
379                                         "extended_dn",
380                                         "asq",
381                                         "samldb",
382                                         "password_hash",
383                                         "operational",
384                                         "objectclass",
385                                         "rdn_name",
386                                         "show_deleted",
387                                         "partition");
388         subobj.MODULES_LIST = join(",", modules_list);
389
390         return subobj;
391 }
392
393 smbconf_keep = new Array(
394         "dos charset", 
395         "unix charset",
396         "display charset",
397         "comment",
398         "path",
399         "directory",
400         "workgroup",
401         "realm",
402         "netbios name",
403         "netbios aliases",
404         "netbios scope",
405         "server string",
406         "interfaces",
407         "bind interfaces only",
408         "security",
409         "auth methods",
410         "encrypt passwords",
411         "null passwords",
412         "obey pam restrictions",
413         "password server",
414         "smb passwd file",
415         "private dir",
416         "passwd chat",
417         "password level",
418         "lanman auth",
419         "ntlm auth",
420         "client NTLMv2 auth",
421         "client lanman auth",
422         "client plaintext auth",
423         "read only",
424         "hosts allow",
425         "hosts deny",
426         "log level",
427         "debuglevel",
428         "log file",
429         "smb ports",
430         "large readwrite",
431         "max protocol",
432         "min protocol",
433         "unicode",
434         "read raw",
435         "write raw",
436         "disable netbios",
437         "nt status support",
438         "announce version",
439         "announce as",
440         "max mux",
441         "max xmit",
442         "name resolve order",
443         "max wins ttl",
444         "min wins ttl",
445         "time server",
446         "unix extensions",
447         "use spnego",
448         "server signing",
449         "client signing",
450         "max connections",
451         "paranoid server security",
452         "socket options",
453         "strict sync",
454         "max print jobs",
455         "printable",
456         "print ok",
457         "printer name",
458         "printer",
459         "map system",
460         "map hidden",
461         "map archive",
462         "preferred master",
463         "prefered master",
464         "local master",
465         "browseable",
466         "browsable",
467         "wins server",
468         "wins support",
469         "csc policy",
470         "strict locking",
471         "config file",
472         "preload",
473         "auto services",
474         "lock dir",
475         "lock directory",
476         "pid directory",
477         "socket address",
478         "copy",
479         "include",
480         "available",
481         "volume",
482         "fstype",
483         "panic action",
484         "msdfs root",
485         "host msdfs",
486         "winbind separator");
487
488 /*
489    Remove configuration variables not present in Samba4
490         oldconf: Old configuration structure
491         mark: Whether removed configuration variables should be 
492                 kept in the new configuration as "samba3:<name>"
493  */
494 function upgrade_smbconf(oldconf,mark)
495 {
496         var data = oldconf.data();
497         var newconf = param_init();
498
499         for (var s in data) {
500                 for (var p in data[s]) {
501                         var keep = false;
502                         for (var k in smbconf_keep) { 
503                                 if (smbconf_keep[k] == p) {
504                                         keep = true;
505                                         break;
506                                 }
507                         }
508
509                         if (keep) {
510                                 newconf.set(s, p, oldconf.get(s, p));
511                         } else if (mark) {
512                                 newconf.set(s, "samba3:"+p, oldconf.get(s,p));
513                         }
514                 }
515         }
516
517         if (oldconf.get("domain logons") == "True") {
518                 newconf.set("server role", "domain controller");
519         } else {
520                 if (oldconf.get("security") == "user") {
521                         newconf.set("server role", "standalone");
522                 } else {
523                         newconf.set("server role", "member server");
524                 }
525         }
526
527         return newconf;
528 }
529
530 function upgrade(subobj, samba3, message, paths, session_info, credentials)
531 {
532         var ret = 0;
533         var lp = loadparm_init();
534         var samdb = ldb_init();
535         samdb.session_info = session_info;
536         samdb.credentials = credentials;
537         var ok = samdb.connect(paths.samdb);
538         if (!ok) {
539                 info.message("samdb connect failed: " + samdb.errstring() + "\n");
540                 assert(ok);
541         }
542
543         message("Writing configuration\n");
544         var newconf = upgrade_smbconf(samba3.configuration,true);
545         newconf.save(paths.smbconf);
546
547         message("Importing account policies\n");
548         var ldif = upgrade_sam_policy(samba3,subobj.BASEDN);
549         ok = samdb.modify(ldif);
550         if (!ok) {
551                 message("samdb load failed: " + samdb.errstring() + "\n");
552                 assert(ok);
553         }
554         var regdb = ldb_init();
555         ok = regdb.connect(paths.hklm);
556         if (!ok) {
557                 message("registry connect: " + regdb.errstring() + "\n");
558                 assert(ok);
559         }
560
561         ok = regdb.modify(sprintf("
562 dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE
563 replace: type
564 type: 4
565 replace: data
566 data: %d
567 ", samba3.policy.refuse_machine_password_change));
568         if (!ok) {
569                 message("registry load failed: " + regdb.errstring() + "\n");
570                 assert(ok);
571         }
572
573         message("Importing users\n");
574         for (var i in samba3.samaccounts) {
575                 var msg = "... " + samba3.samaccounts[i].username;
576                 var ldif = upgrade_sam_account(samdb,samba3.samaccounts[i],subobj.BASEDN,subobj.DOMAINSID);
577                 ok = samdb.add(ldif);
578                 if (!ok && samdb.errstring() != "Record exists") { 
579                         msg = msg + "... error: " + samdb.errstring();
580                         ret = ret + 1; 
581                 }
582                 message(msg + "\n");
583         }
584
585         message("Importing groups\n");
586         for (var i in samba3.groupmappings) {
587                 var msg = "... " + samba3.groupmappings[i].nt_name;
588                 var ldif = upgrade_sam_group(samba3.groupmappings[i],subobj.BASEDN);
589                 if (ldif != undefined) {
590                         ok = samdb.add(ldif);
591                         if (!ok && samdb.errstring() != "Record exists") { 
592                                 msg = msg + "... error: " + samdb.errstring();
593                                 ret = ret + 1; 
594                         }
595                 }
596                 message(msg + "\n");
597         }
598
599         message("Importing registry data\n");
600         var hives = new Array("hkcr","hkcu","hklm","hkpd","hku","hkpt"); 
601         for (var i in hives) {
602                 var hn = hives[i];
603                 message("... " + hn + "\n");
604                 regdb = ldb_init();
605                 ok = regdb.connect(paths[hn]);
606                 assert(ok);
607                 var ldif = upgrade_registry(samba3.registry, hn, regdb);
608                 for (var j in ldif) {
609                         var msg = "... ... " + j;
610                         ok = regdb.add(ldif[j]);
611                         if (!ok && regdb.errstring() != "Record exists") { 
612                                 msg = msg + "... error: " + regdb.errstring();
613                                 ret = ret + 1; 
614                         }
615                         message(msg + "\n");
616                 }
617         }
618
619
620         message("Importing WINS data\n");
621         var winsdb = ldb_init();
622         ok = winsdb.connect(paths.winsdb);
623         assert(ok);
624         ldb_erase(winsdb);
625
626         var ldif = upgrade_wins(samba3);
627         ok = winsdb.add(ldif);
628         assert(ok);
629
630         // figure out ldapurl, if applicable
631         var ldapurl = undefined;
632         var pdb = samba3.configuration.get_list("passdb backend");
633         if (pdb != undefined) {
634                 for (var b in pdb) {
635                         if (strlen(pdb[b]) >= 7) {
636                                 if (substr(pdb[b], 0, 7) == "ldapsam") {
637                                         ldapurl = substr(pdb[b], 8);
638                                 }
639                         }
640                 }
641         }
642
643         // URL was not specified in passdb backend but ldap /is/ used
644         if (ldapurl == "") {
645                 ldapurl = "ldap://" + samba3.configuration.get("ldap server");
646         }
647
648         // Enable samba3sam module if original passdb backend was ldap
649         if (ldapurl != undefined) {
650                 message("Enabling Samba3 LDAP mappings for SAM database\n");
651
652                 ok = samdb.modify("
653 dn: @MODULES
654 changetype: modify
655 replace: @LIST
656 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
657 ");
658                 if (!ok) {
659                         message("Error enabling samba3sam module: " + samdb.errstring() + "\n");
660                         ret = ret + 1;
661                 }
662
663                 ok = samdb.add(sprintf("
664 dn: @MAP=samba3sam
665 @MAP_URL: %s", ldapurl));
666                 assert(ok);
667
668         }
669
670         return ret;
671 }
672
673 function upgrade_verify(subobj, samba3,paths,message)
674 {
675         message("Verifying account policies\n");
676         var samldb = ldb_init();
677         var ne = 0;
678
679         var ok = samldb.connect(paths.samdb);
680         assert(ok);
681
682         for (var i in samba3.samaccounts) {
683                 var msg = samldb.search("(&(sAMAccountName=" + samba3.samaccounts[i].nt_username + ")(objectclass=user))");
684                 assert(msg.length >= 1);
685         }
686         
687         // FIXME
688 }