r23177: Add in a new provision-backend script. This helps set up the OpenLDAP or...
[Samba.git] / source / scripting / libjs / upgrade.js
blob3504d850f26236e1e1318cd257d0477585f1c832
1 /*
2         backend code for upgrading from Samba3
3         Copyright Jelmer Vernooij 2005
4         Released under the GNU GPL v2 or later
5 */
7 libinclude("base.js");
9 function regkey_to_dn(name)
11         var dn = "hive=NONE";
12         var i = 0;
14         var as = split("/", name);
16         for (i in as) {
17                 if (i > 0) {
18                         dn = sprintf("key=%s,", as[i]) + dn;
19                 }
20         }
22         return dn;
25 /* Where prefix is any of:
26  * - HKLM
27  *   HKU
28  *   HKCR
29  *   HKPD
30  *   HKPT
31  */
33 function upgrade_registry(regdb,prefix,ldb)
35         assert(regdb != undefined);
36         var prefix_up = strupper(prefix);
37         var ldif = new Array();
39         for (var i in regdb.keys) {
40                 var rk = regdb.keys[i];
41                 var pts = split("/", rk.name);
43                 /* Only handle selected hive */
44                 if (strupper(pts[0]) != prefix_up) {
45                         continue;
46                 }
48                 var keydn = regkey_to_dn(rk.name);
50                 var pts = split("/", rk.name);
52                 /* Convert key name to dn */
53                 ldif[rk.name] = sprintf("
54 dn: %s
55 name: %s
57 ", keydn, pts[0]);
58                 
59                 for (var j in rk.values) {
60                         var rv = rk.values[j];
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         }
70         return ldif;
73 function upgrade_sam_policy(samba3,dn)
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
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
95         
96         return ldif;
99 function upgrade_sam_account(ldb,acc,domaindn,domainsid)
101         if (acc.nt_username == undefined) {
102                 acc.nt_username = acc.username;
103         }       
105         if (acc.nt_username == "") {
106                 acc.nt_username = acc.username;
107         }       
109         if (acc.fullname == undefined) {
110                 var pw = nss.getpwnam(acc.fullname);
111                 acc.fullname = pw.pw_gecos;
112         }
114         var pts = split(',', acc.fullname);
115         acc.fullname = pts[0];
117         if (acc.fullname == undefined) {
118                 acc.fullname = acc.username;
119         }
120         
121         assert(acc.fullname != undefined);
122         assert(acc.nt_username != undefined);
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
153 ", ldb.dn_escape(acc.fullname), domaindn, acc.logon_time, acc.logoff_time, acc.username, acc.nt_username, acc.nt_username, 
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)); 
161         return ldif;
164 function upgrade_sam_group(grp,domaindn)
166         var nss = nss_init();
168         var gr;
169         if (grp.sid_name_use == 5) { // Well-known group
170                 return undefined;
171         }
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         }
185         if (gr == undefined) {
186                 grp.unixname = "UNKNOWN";
187         } else {
188                 grp.unixname = gr.gr_name;
189         }
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);
205         return ldif;
208 function upgrade_winbind(samba3,domaindn)
210         var ldif = sprintf("
211                 
212 dn: dc=none
213 userHwm: %d
214 groupHwm: %d
216 ", samba3.idmap.user_hwm, samba3.idmap.group_hwm);
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;
231 function upgrade_wins(samba3)
233         var ldif = "";
234         var version_id = 0;
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);
245                 version_id++;
247                 for (var i in e.ips) {
248                         numIPs++;
249                 }
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                 }
267                 if (ttl > now) {
268                         rState = 0x0;/* active */
269                 } else {
270                         rState = 0x1;/* released */             
271                 }
273                 nType = (sys.bitAND(e.nb_flags,0x60)>>5);
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);
290                 for (var i in e.ips) {
291                         ldif = ldif + sprintf("address: %s\n", e.ips[i]);
292                 }
293         }
295         ldif = ldif + sprintf("
296 dn: CN=VERSION
297 objectClass: winsMaxVersion
298 maxVersion: %llu
299 ", version_id);
301         return ldif;
304 function upgrade_provision(samba3)
306         var subobj = new Object();
307         var nss = nss_init();
308         var lp = loadparm_init();
309         var rdn_list;
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");
322         if (realm == undefined) {
323                 realm = domainname;
324                 println("No realm specified in smb.conf file, assuming '" + realm + "'");
325         }
326         random_init(local);
328         subobj.REALM        = realm;
329         subobj.DOMAIN       = domainname;
330         subobj.HOSTNAME     = hostname();
332         assert(subobj.REALM);
333         assert(subobj.DOMAIN);
334         assert(subobj.HOSTNAME);
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;
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);
390         return subobj;
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");
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)
496         var data = oldconf.data();
497         var newconf = param_init();
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                         }
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         }
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         }
527         return newconf;
530 function upgrade(subobj, samba3, message, paths, session_info, credentials)
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         }
543         message("Writing configuration\n");
544         var newconf = upgrade_smbconf(samba3.configuration,true);
545         newconf.save(paths.smbconf);
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         }
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         }
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         }
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         }
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         }
620         message("Importing WINS data\n");
621         var winsdb = ldb_init();
622         ok = winsdb.connect(paths.winsdb);
623         assert(ok);
624         ldb_erase(winsdb);
626         var ldif = upgrade_wins(samba3);
627         ok = winsdb.add(ldif);
628         assert(ok);
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         }
643         // URL was not specified in passdb backend but ldap /is/ used
644         if (ldapurl == "") {
645                 ldapurl = "ldap://" + samba3.configuration.get("ldap server");
646         }
648         // Enable samba3sam module if original passdb backend was ldap
649         if (ldapurl != undefined) {
650                 message("Enabling Samba3 LDAP mappings for SAM database\n");
652                 ok = samdb.modify("
653 dn: @MODULES
654 changetype: modify
655 replace: @LIST
656 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
658                 if (!ok) {
659                         message("Error enabling samba3sam module: " + samdb.errstring() + "\n");
660                         ret = ret + 1;
661                 }
663                 ok = samdb.add(sprintf("
664 dn: @MAP=samba3sam
665 @MAP_URL: %s", ldapurl));
666                 assert(ok);
668         }
670         return ret;
673 function upgrade_verify(subobj, samba3,paths,message)
675         message("Verifying account policies\n");
676         var samldb = ldb_init();
677         var ne = 0;
679         var ok = samldb.connect(paths.samdb);
680         assert(ok);
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