a8f717badcdf7e6f90892ab43321997d8e127a8e
[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)
517 {
518         var ret = 0;
519         var lp = loadparm_init();
520         var samdb = ldb_init();
521         var ok = samdb.connect(paths.samdb);
522         assert(ok);
523
524         message("Writing configuration\n");
525         var newconf = upgrade_smbconf(samba3.configuration,true);
526         newconf.save(paths.smbconf);
527
528         message("Importing account policies\n");
529         var ldif = upgrade_sam_policy(samba3,subobj.BASEDN);
530         ok = samdb.modify(ldif);
531         assert(ok);
532
533         var regdb = ldb_init();
534         ok = regdb.connect(paths.hklm);
535         assert(ok);
536         ok = regdb.modify(sprintf("
537 dn: value=RefusePasswordChange,key=Parameters,key=Netlogon,key=Services,key=CurrentControlSet,key=System,HIVE=NONE
538 replace: type
539 type: 4
540 replace: data
541 data: %d
542 ", samba3.policy.refuse_machine_password_change));
543         assert(ok);
544
545         message("Importing users\n");
546         for (var i in samba3.samaccounts) {
547                 var msg = "... " + samba3.samaccounts[i].username;
548                 var ldif = upgrade_sam_account(samdb,samba3.samaccounts[i],subobj.BASEDN,subobj.DOMAINSID);
549                 ok = samdb.add(ldif);
550                 if (!ok && samdb.errstring() != "Record exists") { 
551                         msg = msg + "... error: " + samdb.errstring();
552                         ret = ret + 1; 
553                 }
554                 message(msg + "\n");
555         }
556
557         message("Importing groups\n");
558         for (var i in samba3.groupmappings) {
559                 var msg = "... " + samba3.groupmappings[i].nt_name;
560                 var ldif = upgrade_sam_group(samba3.groupmappings[i],subobj.BASEDN);
561                 if (ldif != undefined) {
562                         ok = samdb.add(ldif);
563                         if (!ok && samdb.errstring() != "Record exists") { 
564                                 msg = msg + "... error: " + samdb.errstring();
565                                 ret = ret + 1; 
566                         }
567                 }
568                 message(msg + "\n");
569         }
570
571         message("Importing registry data\n");
572         var hives = new Array("hkcr","hkcu","hklm","hkpd","hku","hkpt"); 
573         for (var i in hives) {
574                 var hn = hives[i];
575                 message("... " + hn + "\n");
576                 regdb = ldb_init();
577                 ok = regdb.connect(paths[hn]);
578                 assert(ok);
579                 var ldif = upgrade_registry(samba3.registry, hn, regdb);
580                 for (var j in ldif) {
581                         var msg = "... ... " + j;
582                         ok = regdb.add(ldif[j]);
583                         if (!ok && regdb.errstring() != "Record exists") { 
584                                 msg = msg + "... error: " + regdb.errstring();
585                                 ret = ret + 1; 
586                         }
587                         message(msg + "\n");
588                 }
589         }
590
591
592         message("Importing WINS data\n");
593         var winsdb = ldb_init();
594         ok = winsdb.connect(paths.winsdb);
595         assert(ok);
596         ldb_erase(winsdb);
597
598         var ldif = upgrade_wins(samba3);
599         ok = winsdb.add(ldif);
600         assert(ok);
601
602         // figure out ldapurl, if applicable
603         var ldapurl = undefined;
604         var pdb = samba3.configuration.get_list("passdb backend");
605         if (pdb != undefined) {
606                 for (var b in pdb) {
607                         if (strlen(pdb[b]) >= 7) {
608                                 if (substr(pdb[b], 0, 7) == "ldapsam") {
609                                         ldapurl = substr(pdb[b], 8);
610                                 }
611                         }
612                 }
613         }
614
615         // URL was not specified in passdb backend but ldap /is/ used
616         if (ldapurl == "") {
617                 ldapurl = "ldap://" + samba3.configuration.get("ldap server");
618         }
619
620         // Enable samba3sam module if original passdb backend was ldap
621         if (ldapurl != undefined) {
622                 message("Enabling Samba3 LDAP mappings for SAM database\n");
623
624                 ok = samdb.modify("
625 dn: @MODULES
626 changetype: modify
627 replace: @LIST
628 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
629 ");
630                 if (!ok) {
631                         message("Error enabling samba3sam module: " + samdb.errstring() + "\n");
632                         ret = ret + 1;
633                 }
634
635                 ok = samdb.add(sprintf("
636 dn: @MAP=samba3sam
637 @MAP_URL: %s", ldapurl));
638                 assert(ok);
639
640         }
641
642         return ret;
643 }
644
645 function upgrade_verify(subobj, samba3,paths,message)
646 {
647         message("Verifying account policies\n");
648         var samldb = ldb_init();
649         var ne = 0;
650
651         var ok = samldb.connect(paths.samdb);
652         assert(ok);
653
654         for (var i in samba3.samaccounts) {
655                 var msg = samldb.search("(&(sAMAccountName=" + samba3.samaccounts[i].nt_username + ")(objectclass=user))");
656                 assert(msg.length >= 1);
657         }
658         
659         // FIXME
660 }