s4:upgrade.py - the import of WINS databases don't seem to work always
[Samba/ekacnet.git] / source4 / scripting / python / samba / upgrade.py
blob89cf767dae31ee2afef1979784623147d674dd99
1 #!/usr/bin/python
3 # backend code for upgrading from Samba3
4 # Copyright Jelmer Vernooij 2005-2007
5 # Released under the GNU GPL v3 or later
8 """Support code for upgrading from Samba 3 to Samba 4."""
10 __docformat__ = "restructuredText"
12 from provision import provision, FILL_DRS
13 import grp
14 import ldb
15 import time
16 import pwd
17 import registry
18 from samba import Ldb
19 from samba.param import LoadParm
21 def import_sam_policy(samldb, policy, dn):
22 """Import a Samba 3 policy database."""
23 samldb.modify_ldif("""
24 dn: %s
25 changetype: modify
26 replace: minPwdLength
27 minPwdLength: %d
28 pwdHistoryLength: %d
29 minPwdAge: %d
30 maxPwdAge: %d
31 lockoutDuration: %d
32 samba3ResetCountMinutes: %d
33 samba3UserMustLogonToChangePassword: %d
34 samba3BadLockoutMinutes: %d
35 samba3DisconnectTime: %d
37 """ % (dn, policy.min_password_length,
38 policy.password_history, policy.minimum_password_age,
39 policy.maximum_password_age, policy.lockout_duration,
40 policy.reset_count_minutes, policy.user_must_logon_to_change_password,
41 policy.bad_lockout_minutes, policy.disconnect_time))
44 def import_sam_account(samldb,acc,domaindn,domainsid):
45 """Import a Samba 3 SAM account.
47 :param samldb: Samba 4 SAM Database handle
48 :param acc: Samba 3 account
49 :param domaindn: Domain DN
50 :param domainsid: Domain SID."""
51 if acc.nt_username is None or acc.nt_username == "":
52 acc.nt_username = acc.username
54 if acc.fullname is None:
55 try:
56 acc.fullname = pwd.getpwnam(acc.username)[4].split(",")[0]
57 except KeyError:
58 pass
60 if acc.fullname is None:
61 acc.fullname = acc.username
63 assert acc.fullname is not None
64 assert acc.nt_username is not None
66 samldb.add({
67 "dn": "cn=%s,%s" % (acc.fullname, domaindn),
68 "objectClass": ["top", "user"],
69 "lastLogon": str(acc.logon_time),
70 "lastLogoff": str(acc.logoff_time),
71 "unixName": acc.username,
72 "sAMAccountName": acc.nt_username,
73 "cn": acc.nt_username,
74 "description": acc.acct_desc,
75 "primaryGroupID": str(acc.group_rid),
76 "badPwdcount": str(acc.bad_password_count),
77 "logonCount": str(acc.logon_count),
78 "samba3Domain": acc.domain,
79 "samba3DirDrive": acc.dir_drive,
80 "samba3MungedDial": acc.munged_dial,
81 "samba3Homedir": acc.homedir,
82 "samba3LogonScript": acc.logon_script,
83 "samba3ProfilePath": acc.profile_path,
84 "samba3Workstations": acc.workstations,
85 "samba3KickOffTime": str(acc.kickoff_time),
86 "samba3BadPwdTime": str(acc.bad_password_time),
87 "samba3PassLastSetTime": str(acc.pass_last_set_time),
88 "samba3PassCanChangeTime": str(acc.pass_can_change_time),
89 "samba3PassMustChangeTime": str(acc.pass_must_change_time),
90 "objectSid": "%s-%d" % (domainsid, acc.user_rid),
91 "lmPwdHash:": acc.lm_password,
92 "ntPwdHash:": acc.nt_password,
96 def import_sam_group(samldb, sid, gid, sid_name_use, nt_name, comment, domaindn):
97 """Upgrade a SAM group.
99 :param samldb: SAM database.
100 :param gid: Group GID
101 :param sid_name_use: SID name use
102 :param nt_name: NT Group Name
103 :param comment: NT Group Comment
104 :param domaindn: Domain DN
107 if sid_name_use == 5: # Well-known group
108 return None
110 if nt_name in ("Domain Guests", "Domain Users", "Domain Admins"):
111 return None
113 if gid == -1:
114 gr = grp.getgrnam(nt_name)
115 else:
116 gr = grp.getgrgid(gid)
118 if gr is None:
119 unixname = "UNKNOWN"
120 else:
121 unixname = gr.gr_name
123 assert unixname is not None
125 samldb.add({
126 "dn": "cn=%s,%s" % (nt_name, domaindn),
127 "objectClass": ["top", "group"],
128 "description": comment,
129 "cn": nt_name,
130 "objectSid": sid,
131 "unixName": unixname,
132 "samba3SidNameUse": str(sid_name_use)
136 def import_idmap(samdb,samba3_idmap,domaindn):
137 """Import idmap data.
139 :param samdb: SamDB handle.
140 :param samba3_idmap: Samba 3 IDMAP database to import from
141 :param domaindn: Domain DN.
143 samdb.add({
144 "dn": domaindn,
145 "userHwm": str(samba3_idmap.get_user_hwm()),
146 "groupHwm": str(samba3_idmap.get_group_hwm())})
148 for uid in samba3_idmap.uids():
149 samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_user_sid(uid), domaindn),
150 "SID": samba3_idmap.get_user_sid(uid),
151 "type": "user",
152 "unixID": str(uid)})
154 for gid in samba3_idmap.uids():
155 samdb.add({"dn": "SID=%s,%s" % (samba3_idmap.get_group_sid(gid), domaindn),
156 "SID": samba3_idmap.get_group_sid(gid),
157 "type": "group",
158 "unixID": str(gid)})
161 def import_wins(samba4_winsdb, samba3_winsdb):
162 """Import settings from a Samba3 WINS database.
164 :param samba4_winsdb: WINS database to import to
165 :param samba3_winsdb: WINS database to import from
167 version_id = 0
169 for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items():
170 version_id+=1
172 type = int(name.split("#", 1)[1], 16)
174 if type == 0x1C:
175 rType = 0x2
176 elif type & 0x80:
177 if len(ips) > 1:
178 rType = 0x2
179 else:
180 rType = 0x1
181 else:
182 if len(ips) > 1:
183 rType = 0x3
184 else:
185 rType = 0x0
187 if ttl > time.time():
188 rState = 0x0 # active
189 else:
190 rState = 0x1 # released
192 nType = ((nb_flags & 0x60)>>5)
194 samba4_winsdb.add({"dn": "name=%s,type=0x%s" % tuple(name.split("#")),
195 "type": name.split("#")[1],
196 "name": name.split("#")[0],
197 "objectClass": "winsRecord",
198 "recordType": str(rType),
199 "recordState": str(rState),
200 "nodeType": str(nType),
201 "expireTime": ldb.timestring(ttl),
202 "isStatic": "0",
203 "versionID": str(version_id),
204 "address": ips})
206 samba4_winsdb.add({"dn": "cn=VERSION",
207 "cn": "VERSION",
208 "objectClass": "winsMaxVersion",
209 "maxVersion": str(version_id)})
211 def upgrade_provision(samba3, setup_dir, message, credentials, session_info, smbconf, targetdir):
212 oldconf = samba3.get_conf()
214 if oldconf.get("domain logons") == "True":
215 serverrole = "domain controller"
216 else:
217 if oldconf.get("security") == "user":
218 serverrole = "standalone"
219 else:
220 serverrole = "member server"
222 domainname = oldconf.get("workgroup")
223 if domainname:
224 domainname = str(domainname)
225 realm = oldconf.get("realm")
226 netbiosname = oldconf.get("netbios name")
228 secrets_db = samba3.get_secrets_db()
230 if domainname is None:
231 domainname = secrets_db.domains()[0]
232 message("No domain specified in smb.conf file, assuming '%s'" % domainname)
234 if realm is None:
235 realm = domainname.lower()
236 message("No realm specified in smb.conf file, assuming '%s'\n" % realm)
238 domainguid = secrets_db.get_domain_guid(domainname)
239 domainsid = secrets_db.get_sid(domainname)
240 if domainsid is None:
241 message("Can't find domain secrets for '%s'; using random SID\n" % domainname)
243 if netbiosname is not None:
244 machinepass = secrets_db.get_machine_password(netbiosname)
245 else:
246 machinepass = None
248 result = provision(setup_dir=setup_dir, message=message,
249 samdb_fill=FILL_DRS, smbconf=smbconf, session_info=session_info,
250 credentials=credentials, realm=realm,
251 domain=domainname, domainsid=domainsid, domainguid=domainguid,
252 machinepass=machinepass, serverrole=serverrole, targetdir=targetdir)
254 # FIXME: import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db())
256 # FIXME: import_registry(registry.Registry(), samba3.get_registry())
258 # FIXME: import_idmap(samdb,samba3.get_idmap_db(),domaindn)
260 groupdb = samba3.get_groupmapping_db()
261 for sid in groupdb.groupsids():
262 (gid, sid_name_use, nt_name, comment) = groupdb.get_group(sid)
263 # FIXME: import_sam_group(samdb, sid, gid, sid_name_use, nt_name, comment, domaindn)
265 # FIXME: Aliases
267 passdb = samba3.get_sam_db()
268 for name in passdb:
269 user = passdb[name]
270 #FIXME: import_sam_account(result.samdb, user, domaindn, domainsid)
272 if hasattr(passdb, 'ldap_url'):
273 message("Enabling Samba3 LDAP mappings for SAM database")
275 enable_samba3sam(result.samdb, passdb.ldap_url)
278 def enable_samba3sam(samdb, ldapurl):
279 """Enable Samba 3 LDAP URL database.
281 :param samdb: SAM Database.
282 :param ldapurl: Samba 3 LDAP URL
284 samdb.modify_ldif("""
285 dn: @MODULES
286 changetype: modify
287 replace: @LIST
288 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
289 """)
291 samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl})
294 smbconf_keep = [
295 "dos charset",
296 "unix charset",
297 "display charset",
298 "comment",
299 "path",
300 "directory",
301 "workgroup",
302 "realm",
303 "netbios name",
304 "netbios aliases",
305 "netbios scope",
306 "server string",
307 "interfaces",
308 "bind interfaces only",
309 "security",
310 "auth methods",
311 "encrypt passwords",
312 "null passwords",
313 "obey pam restrictions",
314 "password server",
315 "smb passwd file",
316 "private dir",
317 "passwd chat",
318 "password level",
319 "lanman auth",
320 "ntlm auth",
321 "client NTLMv2 auth",
322 "client lanman auth",
323 "client plaintext auth",
324 "read only",
325 "hosts allow",
326 "hosts deny",
327 "log level",
328 "debuglevel",
329 "log file",
330 "smb ports",
331 "large readwrite",
332 "max protocol",
333 "min protocol",
334 "unicode",
335 "read raw",
336 "write raw",
337 "disable netbios",
338 "nt status support",
339 "announce version",
340 "announce as",
341 "max mux",
342 "max xmit",
343 "name resolve order",
344 "max wins ttl",
345 "min wins ttl",
346 "time server",
347 "unix extensions",
348 "use spnego",
349 "server signing",
350 "client signing",
351 "max connections",
352 "paranoid server security",
353 "socket options",
354 "strict sync",
355 "max print jobs",
356 "printable",
357 "print ok",
358 "printer name",
359 "printer",
360 "map system",
361 "map hidden",
362 "map archive",
363 "preferred master",
364 "prefered master",
365 "local master",
366 "browseable",
367 "browsable",
368 "wins server",
369 "wins support",
370 "csc policy",
371 "strict locking",
372 "preload",
373 "auto services",
374 "lock dir",
375 "lock directory",
376 "pid directory",
377 "socket address",
378 "copy",
379 "include",
380 "available",
381 "volume",
382 "fstype",
383 "panic action",
384 "msdfs root",
385 "host msdfs",
386 "winbind separator"]
388 def upgrade_smbconf(oldconf,mark):
389 """Remove configuration variables not present in Samba4
391 :param oldconf: Old configuration structure
392 :param mark: Whether removed configuration variables should be
393 kept in the new configuration as "samba3:<name>"
395 data = oldconf.data()
396 newconf = LoadParm()
398 for s in data:
399 for p in data[s]:
400 keep = False
401 for k in smbconf_keep:
402 if smbconf_keep[k] == p:
403 keep = True
404 break
406 if keep:
407 newconf.set(s, p, oldconf.get(s, p))
408 elif mark:
409 newconf.set(s, "samba3:"+p, oldconf.get(s,p))
411 return newconf
413 SAMBA3_PREDEF_NAMES = {
414 'HKLM': registry.HKEY_LOCAL_MACHINE,
417 def import_registry(samba4_registry, samba3_regdb):
418 """Import a Samba 3 registry database into the Samba 4 registry.
420 :param samba4_registry: Samba 4 registry handle.
421 :param samba3_regdb: Samba 3 registry database handle.
423 def ensure_key_exists(keypath):
424 (predef_name, keypath) = keypath.split("/", 1)
425 predef_id = SAMBA3_PREDEF_NAMES[predef_name]
426 keypath = keypath.replace("/", "\\")
427 return samba4_registry.create_key(predef_id, keypath)
429 for key in samba3_regdb.keys():
430 key_handle = ensure_key_exists(key)
431 for subkey in samba3_regdb.subkeys(key):
432 ensure_key_exists(subkey)
433 for (value_name, (value_type, value_data)) in samba3_regdb.values(key).items():
434 key_handle.set_value(value_name, value_type, value_data)