1 # backend code for upgrading from Samba3
2 # Copyright Jelmer Vernooij 2005-2007
3 # Copyright Andrew Bartlett 2011
5 # This program is free software; you can redistribute it and/or modify
6 # it under the terms of the GNU General Public License as published by
7 # the Free Software Foundation; either version 3 of the License, or
8 # (at your option) any later version.
10 # This program is distributed in the hope that it will be useful,
11 # but WITHOUT ANY WARRANTY; without even the implied warranty of
12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 # GNU General Public License for more details.
15 # You should have received a copy of the GNU General Public License
16 # along with this program. If not, see <http://www.gnu.org/licenses/>.
19 """Support code for upgrading from Samba 3 to Samba 4."""
21 __docformat__ = "restructuredText"
27 from samba import Ldb, registry
28 from samba.param import LoadParm
29 from samba.provision import provision, FILL_FULL, ProvisioningError
30 from samba.samba3 import passdb
31 from samba.samba3 import param as s3param
32 from samba.dcerpc import lsa, samr, security
33 from samba.dcerpc.security import dom_sid
34 from samba.credentials import Credentials
35 from samba.auth import system_session
36 from samba import dsdb
37 from samba.ndr import ndr_pack
38 from samba import unix2nttime
41 def import_sam_policy(samdb, policy, logger):
42 """Import a Samba 3 policy.
44 :param samdb: Samba4 SAM database
45 :param policy: Samba3 account policy
46 :param logger: Logger object
49 # Following entries are used -
50 # min password length, password history, minimum password age,
51 # maximum password age, lockout duration
53 # Following entries are not used -
54 # reset count minutes, user must logon to change password,
55 # bad lockout minutes, disconnect time
58 m.dn = samdb.get_default_basedn()
59 m['a01'] = ldb.MessageElement(str(policy['min password length']),
60 ldb.FLAG_MOD_REPLACE, 'minPwdLength')
61 m['a02'] = ldb.MessageElement(str(policy['password history']),
62 ldb.FLAG_MOD_REPLACE, 'pwdHistoryLength')
64 min_pw_age_unix = policy['minimum password age']
65 min_pw_age_nt = int(-min_pw_age_unix * (1e7))
66 m['a03'] = ldb.MessageElement(str(min_pw_age_nt), ldb.FLAG_MOD_REPLACE,
69 max_pw_age_unix = policy['maximum password age']
70 if max_pw_age_unix == -1 or max_pw_age_unix == 0:
71 max_pw_age_nt = -0x8000000000000000
73 max_pw_age_nt = int(-max_pw_age_unix * (1e7))
75 m['a04'] = ldb.MessageElement(str(max_pw_age_nt), ldb.FLAG_MOD_REPLACE,
78 lockout_duration_mins = policy['lockout duration']
79 lockout_duration_nt = unix2nttime(lockout_duration_mins * 60)
81 m['a05'] = ldb.MessageElement(str(lockout_duration_nt),
82 ldb.FLAG_MOD_REPLACE, 'lockoutDuration')
86 except ldb.LdbError, e:
87 logger.warn("Could not set account policy, (%s)", str(e))
89 def add_posix_attrs(logger, samdb, sid, name, nisdomain, xid_type, home=None, shell=None, pgid=None):
90 """Add posix attributes for the user/group
92 :param samdb: Samba4 sam.ldb database
93 :param sid: user/group sid
94 :param sid: user/group name
95 :param nisdomain: name of the (fake) NIS domain
96 :param xid_type: type of id (ID_TYPE_UID/ID_TYPE_GID)
97 :param home: user homedir (Unix homepath)
98 :param shell: user shell
99 :param pgid: users primary group id
104 m.dn = ldb.Dn(samdb, "<SID=%s>" % str(sid))
105 if xid_type == "ID_TYPE_UID":
106 m['unixHomeDirectory'] = ldb.MessageElement(
107 str(home), ldb.FLAG_MOD_REPLACE, 'unixHomeDirectory')
108 m['loginShell'] = ldb.MessageElement(
109 str(shell), ldb.FLAG_MOD_REPLACE, 'loginShell')
110 m['gidNumber'] = ldb.MessageElement(
111 str(pgid), ldb.FLAG_MOD_REPLACE, 'gidNumber')
113 m['msSFU30NisDomain'] = ldb.MessageElement(
114 str(nisdomain), ldb.FLAG_MOD_REPLACE, 'msSFU30NisDomain')
117 except ldb.LdbError, e:
119 'Could not add posix attrs for AD entry for sid=%s, (%s)',
122 def add_ad_posix_idmap_entry(samdb, sid, xid, xid_type, logger):
123 """Create idmap entry
125 :param samdb: Samba4 sam.ldb database
126 :param sid: user/group sid
127 :param xid: user/group id
128 :param xid_type: type of id (ID_TYPE_UID/ID_TYPE_GID)
129 :param logger: Logger object
134 m.dn = ldb.Dn(samdb, "<SID=%s>" % str(sid))
135 if xid_type == "ID_TYPE_UID":
136 m['uidNumber'] = ldb.MessageElement(
137 str(xid), ldb.FLAG_MOD_REPLACE, 'uidNumber')
138 m['objectClass'] = ldb.MessageElement(
139 "posixAccount", ldb.FLAG_MOD_ADD, 'objectClass')
140 elif xid_type == "ID_TYPE_GID":
141 m['gidNumber'] = ldb.MessageElement(
142 str(xid), ldb.FLAG_MOD_REPLACE, 'gidNumber')
143 m['objectClass'] = ldb.MessageElement(
144 "posixGroup", ldb.FLAG_MOD_ADD, 'objectClass')
147 except ldb.LdbError, e:
149 'Could not modify AD idmap entry for sid=%s, id=%s, type=%s (%s)',
150 str(sid), str(xid), xid_type, str(e))
152 def add_idmap_entry(idmapdb, sid, xid, xid_type, logger):
153 """Create idmap entry
155 :param idmapdb: Samba4 IDMAP database
156 :param sid: user/group sid
157 :param xid: user/group id
158 :param xid_type: type of id (ID_TYPE_UID/ID_TYPE_GID)
159 :param logger: Logger object
162 # First try to see if we already have this entry
164 msg = idmapdb.search(expression='objectSid=%s' % str(sid))
172 m['xidNumber'] = ldb.MessageElement(
173 str(xid), ldb.FLAG_MOD_REPLACE, 'xidNumber')
174 m['type'] = ldb.MessageElement(
175 xid_type, ldb.FLAG_MOD_REPLACE, 'type')
177 except ldb.LdbError, e:
179 'Could not modify idmap entry for sid=%s, id=%s, type=%s (%s)',
180 str(sid), str(xid), xid_type, str(e))
183 idmapdb.add({"dn": "CN=%s" % str(sid),
185 "objectClass": "sidMap",
186 "objectSid": ndr_pack(sid),
188 "xidNumber": str(xid)})
189 except ldb.LdbError, e:
191 'Could not add idmap entry for sid=%s, id=%s, type=%s (%s)',
192 str(sid), str(xid), xid_type, str(e))
195 def import_idmap(idmapdb, samba3, logger):
196 """Import idmap data.
198 :param idmapdb: Samba4 IDMAP database
199 :param samba3_idmap: Samba3 IDMAP database to import from
200 :param logger: Logger object
204 samba3_idmap = samba3.get_idmap_db()
206 logger.warn('Cannot open idmap database, Ignoring: %s', str(e))
209 currentxid = max(samba3_idmap.get_user_hwm(), samba3_idmap.get_group_hwm())
210 lowerbound = currentxid
214 m.dn = ldb.Dn(idmapdb, 'CN=CONFIG')
215 m['lowerbound'] = ldb.MessageElement(
216 str(lowerbound), ldb.FLAG_MOD_REPLACE, 'lowerBound')
217 m['xidNumber'] = ldb.MessageElement(
218 str(currentxid), ldb.FLAG_MOD_REPLACE, 'xidNumber')
221 for id_type, xid in samba3_idmap.ids():
223 xid_type = 'ID_TYPE_UID'
224 elif id_type == 'GID':
225 xid_type = 'ID_TYPE_GID'
227 logger.warn('Wrong type of entry in idmap (%s), Ignoring', id_type)
230 sid = samba3_idmap.get_sid(xid, id_type)
231 add_idmap_entry(idmapdb, dom_sid(sid), xid, xid_type, logger)
234 def add_group_from_mapping_entry(samdb, groupmap, logger):
235 """Add or modify group from group mapping entry
237 param samdb: Samba4 SAM database
238 param groupmap: Groupmap entry
239 param logger: Logger object
242 # First try to see if we already have this entry
245 base='<SID=%s>' % str(groupmap.sid), scope=ldb.SCOPE_BASE)
247 except ldb.LdbError, (ecode, emsg):
248 if ecode == ldb.ERR_NO_SUCH_OBJECT:
251 raise ldb.LdbError(ecode, emsg)
254 logger.warn('Group already exists sid=%s, groupname=%s existing_groupname=%s, Ignoring.',
255 str(groupmap.sid), groupmap.nt_name, msg[0]['sAMAccountName'][0])
257 if groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP:
258 # In a lot of Samba3 databases, aliases are marked as well known groups
259 (group_dom_sid, rid) = groupmap.sid.split()
260 if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)):
264 m.dn = ldb.Dn(samdb, "CN=%s,CN=Users,%s" % (groupmap.nt_name, samdb.get_default_basedn()))
265 m['cn'] = ldb.MessageElement(groupmap.nt_name, ldb.FLAG_MOD_ADD, 'cn')
266 m['objectClass'] = ldb.MessageElement('group', ldb.FLAG_MOD_ADD, 'objectClass')
267 m['objectSid'] = ldb.MessageElement(ndr_pack(groupmap.sid), ldb.FLAG_MOD_ADD,
269 m['sAMAccountName'] = ldb.MessageElement(groupmap.nt_name, ldb.FLAG_MOD_ADD,
273 m['description'] = ldb.MessageElement(groupmap.comment, ldb.FLAG_MOD_ADD,
276 # Fix up incorrect 'well known' groups that are actually builtin (per test above) to be aliases
277 if groupmap.sid_name_use == lsa.SID_NAME_ALIAS or groupmap.sid_name_use == lsa.SID_NAME_WKN_GRP:
278 m['groupType'] = ldb.MessageElement(str(dsdb.GTYPE_SECURITY_DOMAIN_LOCAL_GROUP),
279 ldb.FLAG_MOD_ADD, 'groupType')
282 samdb.add(m, controls=["relax:0"])
283 except ldb.LdbError, e:
284 logger.warn('Could not add group name=%s (%s)', groupmap.nt_name, str(e))
287 def add_users_to_group(samdb, group, members, logger):
288 """Add user/member to group/alias
290 param samdb: Samba4 SAM database
291 param group: Groupmap object
292 param members: List of member SIDs
293 param logger: Logger object
295 for member_sid in members:
297 m.dn = ldb.Dn(samdb, "<SID=%s>" % str(group.sid))
298 m['a01'] = ldb.MessageElement("<SID=%s>" % str(member_sid), ldb.FLAG_MOD_ADD, 'member')
302 except ldb.LdbError, (ecode, emsg):
303 if ecode == ldb.ERR_ENTRY_ALREADY_EXISTS:
304 logger.debug("skipped re-adding member '%s' to group '%s': %s", member_sid, group.sid, emsg)
305 elif ecode == ldb.ERR_NO_SUCH_OBJECT:
306 raise ProvisioningError("Could not add member '%s' to group '%s' as either group or user record doesn't exist: %s" % (member_sid, group.sid, emsg))
308 raise ProvisioningError("Could not add member '%s' to group '%s': %s" % (member_sid, group.sid, emsg))
311 def import_wins(samba4_winsdb, samba3_winsdb):
312 """Import settings from a Samba3 WINS database.
314 :param samba4_winsdb: WINS database to import to
315 :param samba3_winsdb: WINS database to import from
320 for (name, (ttl, ips, nb_flags)) in samba3_winsdb.items():
323 type = int(name.split("#", 1)[1], 16)
338 if ttl > time.time():
339 rState = 0x0 # active
341 rState = 0x1 # released
343 nType = ((nb_flags & 0x60) >> 5)
345 samba4_winsdb.add({"dn": "name=%s,type=0x%s" % tuple(name.split("#")),
346 "type": name.split("#")[1],
347 "name": name.split("#")[0],
348 "objectClass": "winsRecord",
349 "recordType": str(rType),
350 "recordState": str(rState),
351 "nodeType": str(nType),
352 "expireTime": ldb.timestring(ttl),
354 "versionID": str(version_id),
357 samba4_winsdb.add({"dn": "cn=VERSION",
359 "objectClass": "winsMaxVersion",
360 "maxVersion": str(version_id)})
363 def enable_samba3sam(samdb, ldapurl):
364 """Enable Samba 3 LDAP URL database.
366 :param samdb: SAM Database.
367 :param ldapurl: Samba 3 LDAP URL
369 samdb.modify_ldif("""
373 @LIST: samldb,operational,objectguid,rdn_name,samba3sam
376 samdb.add({"dn": "@MAP=samba3sam", "@MAP_URL": ldapurl})
393 "bind interfaces only",
398 "obey pam restrictions",
406 "client NTLMv2 auth",
407 "client lanman auth",
408 "client plaintext auth",
426 "name resolve order",
435 "paranoid server security",
472 def upgrade_smbconf(oldconf, mark):
473 """Remove configuration variables not present in Samba4
475 :param oldconf: Old configuration structure
476 :param mark: Whether removed configuration variables should be
477 kept in the new configuration as "samba3:<name>"
479 data = oldconf.data()
485 for k in smbconf_keep:
486 if smbconf_keep[k] == p:
491 newconf.set(s, p, oldconf.get(s, p))
493 newconf.set(s, "samba3:" + p, oldconf.get(s, p))
497 SAMBA3_PREDEF_NAMES = {
498 'HKLM': registry.HKEY_LOCAL_MACHINE,
502 def import_registry(samba4_registry, samba3_regdb):
503 """Import a Samba 3 registry database into the Samba 4 registry.
505 :param samba4_registry: Samba 4 registry handle.
506 :param samba3_regdb: Samba 3 registry database handle.
508 def ensure_key_exists(keypath):
509 (predef_name, keypath) = keypath.split("/", 1)
510 predef_id = SAMBA3_PREDEF_NAMES[predef_name]
511 keypath = keypath.replace("/", "\\")
512 return samba4_registry.create_key(predef_id, keypath)
514 for key in samba3_regdb.keys():
515 key_handle = ensure_key_exists(key)
516 for subkey in samba3_regdb.subkeys(key):
517 ensure_key_exists(subkey)
518 for (value_name, (value_type, value_data)) in samba3_regdb.values(key).items():
519 key_handle.set_value(value_name, value_type, value_data)
521 def get_posix_attr_from_ldap_backend(logger, ldb_object, base_dn, user, attr):
522 """Get posix attributes from a samba3 ldap backend
523 :param ldbs: a list of ldb connection objects
524 :param base_dn: the base_dn of the connection
525 :param user: the user to get the attribute for
526 :param attr: the attribute to be retrieved
529 msg = ldb_object.search(base_dn, scope=ldb.SCOPE_SUBTREE,
530 expression=("(&(objectClass=posixAccount)(uid=%s))"
531 % (user)), attrs=[attr])
532 except ldb.LdbError, e:
533 logger.warning("Failed to retrieve attribute %s for user %s, the error is: %s", attr, user, e)
536 return msg[0][attr][0]
538 logger.warning("LDAP entry for user %s contains more than one %s", user, attr)
541 def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, useeadb=False, dns_backend=None):
542 """Upgrade from samba3 database to samba4 AD database
544 :param samba3: samba3 object
545 :param logger: Logger object
546 :param targetdir: samba4 database directory
547 :param session_info: Session information
549 serverrole = samba3.lp.server_role()
551 domainname = samba3.lp.get("workgroup")
552 realm = samba3.lp.get("realm")
553 netbiosname = samba3.lp.get("netbios name")
555 if samba3.lp.get("ldapsam:trusted") is None:
556 samba3.lp.set("ldapsam:trusted", "yes")
560 secrets_db = samba3.get_secrets_db()
562 raise ProvisioningError("Could not open '%s', the Samba3 secrets database: %s. Perhaps you specified the incorrect smb.conf, --testparm or --dbdir option?" % (samba3.privatedir_path("secrets.tdb"), str(e)))
565 domainname = secrets_db.domains()[0]
566 logger.warning("No workgroup specified in smb.conf file, assuming '%s'",
570 if serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC":
571 raise ProvisioningError("No realm specified in smb.conf file and being a DC. That upgrade path doesn't work! Please add a 'realm' directive to your old smb.conf to let us know which one you want to use (it is the DNS name of the AD domain you wish to create.")
573 realm = domainname.upper()
574 logger.warning("No realm specified in smb.conf file, assuming '%s'",
577 # Find machine account and password
581 machinepass = secrets_db.get_machine_password(netbiosname)
585 if samba3.lp.get("passdb backend").split(":")[0].strip() == "ldapsam":
586 base_dn = samba3.lp.get("ldap suffix")
587 ldapuser = samba3.lp.get("ldap admin dn")
588 ldappass = (secrets_db.get_ldap_bind_pw(ldapuser)).strip('\x00')
595 # We must close the direct pytdb database before the C code loads it
598 # Connect to old password backend
599 passdb.set_secrets_dir(samba3.lp.get("private dir"))
600 s3db = samba3.get_sam_db()
604 domainsid = passdb.get_global_sam_sid()
606 raise Exception("Can't find domain sid for '%s', Exiting." % domainname)
608 # Get machine account, sid, rid
610 machineacct = s3db.getsampwnam('%s$' % netbiosname)
615 machinesid, machinerid = machineacct.user_sid.split()
617 # Export account policy
618 logger.info("Exporting account policy")
619 policy = s3db.get_account_policy()
621 # Export groups from old passdb backend
622 logger.info("Exporting groups")
623 grouplist = s3db.enum_group_mapping()
625 for group in grouplist:
626 sid, rid = group.sid.split()
631 # Get members for each group/alias
632 if group.sid_name_use == lsa.SID_NAME_ALIAS:
634 members = s3db.enum_aliasmem(group.sid)
635 groupmembers[str(group.sid)] = members
636 except passdb.error, e:
637 logger.warn("Ignoring group '%s' %s listed but then not found: %s",
638 group.nt_name, group.sid, e)
640 elif group.sid_name_use == lsa.SID_NAME_DOM_GRP:
642 members = s3db.enum_group_members(group.sid)
643 groupmembers[str(group.sid)] = members
644 except passdb.error, e:
645 logger.warn("Ignoring group '%s' %s listed but then not found: %s",
646 group.nt_name, group.sid, e)
648 elif group.sid_name_use == lsa.SID_NAME_WKN_GRP:
649 (group_dom_sid, rid) = group.sid.split()
650 if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)):
651 logger.warn("Ignoring 'well known' group '%s' (should already be in AD, and have no members)",
654 # A number of buggy databases mix up well known groups and aliases.
656 members = s3db.enum_aliasmem(group.sid)
657 groupmembers[str(group.sid)] = members
658 except passdb.error, e:
659 logger.warn("Ignoring group '%s' %s listed but then not found: %s",
660 group.nt_name, group.sid, e)
663 logger.warn("Ignoring group '%s' %s with sid_name_use=%d",
664 group.nt_name, group.sid, group.sid_name_use)
667 # Export users from old passdb backend
668 logger.info("Exporting users")
669 userlist = s3db.search_users(0)
673 for entry in userlist:
674 if machinerid and machinerid == entry['rid']:
676 username = entry['account_name']
677 if entry['rid'] < 1000:
678 logger.info(" Skipping wellknown rid=%d (for username=%s)", entry['rid'], username)
680 if entry['rid'] >= next_rid:
681 next_rid = entry['rid'] + 1
683 user = s3db.getsampwnam(username)
684 acct_type = (user.acct_ctrl & (samr.ACB_NORMAL|samr.ACB_WSTRUST|samr.ACB_SVRTRUST|samr.ACB_DOMTRUST))
685 if (acct_type == samr.ACB_NORMAL or acct_type == samr.ACB_WSTRUST):
688 elif acct_type == samr.ACB_SVRTRUST:
689 logger.warn(" Demoting BDC account trust for %s, this DC must be elevated to an AD DC using 'samba-tool domain promote'" % username[:-1])
690 user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_SVRTRUST) | samr.ACB_WSTRUST
692 elif acct_type == samr.ACB_DOMTRUST:
693 logger.warn(" Skipping inter-domain trust from domain %s, this trust must be re-created as an AD trust" % username[:-1])
695 elif acct_type == (samr.ACB_NORMAL|samr.ACB_WSTRUST) and username[-1] == '$':
696 logger.warn(" Fixing account %s which had both ACB_NORMAL (U) and ACB_WSTRUST (W) set. Account will be marked as ACB_WSTRUST (W), i.e. as a domain member" % username)
697 user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL)
699 elif acct_type == (samr.ACB_NORMAL|samr.ACB_SVRTRUST) and username[-1] == '$':
700 logger.warn(" Fixing account %s which had both ACB_NORMAL (U) and ACB_SVRTRUST (S) set. Account will be marked as ACB_WSTRUST (S), i.e. as a domain member" % username)
701 user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL)
704 raise ProvisioningError("""Failed to upgrade due to invalid account %s, account control flags 0x%08X must have exactly one of
705 ACB_NORMAL (N, 0x%08X), ACB_WSTRUST (W 0x%08X), ACB_SVRTRUST (S 0x%08X) or ACB_DOMTRUST (D 0x%08X).
707 Please fix this account before attempting to upgrade again
709 % (user.acct_flags, username,
710 samr.ACB_NORMAL, samr.ACB_WSTRUST, samr.ACB_SVRTRUST, samr.ACB_DOMTRUST))
712 userdata[username] = user
714 uids[username] = s3db.sid_to_id(user.user_sid)[0]
717 uids[username] = pwd.getpwnam(username).pw_uid
721 if not admin_user and username.lower() == 'root':
722 admin_user = username
723 if username.lower() == 'administrator':
724 admin_user = username
727 group_memberships = s3db.enum_group_memberships(user);
728 for group in group_memberships:
729 if str(group) in groupmembers:
730 if user.user_sid not in groupmembers[str(group)]:
731 groupmembers[str(group)].append(user.user_sid)
733 groupmembers[str(group)] = [user.user_sid];
734 except passdb.error, e:
735 logger.warn("Ignoring group memberships of '%s' %s: %s",
736 username, user.user_sid, e)
738 logger.info("Next rid = %d", next_rid)
740 # Check for same username/groupname
741 group_names = set([g.nt_name for g in grouplist])
742 user_names = set([u['account_name'] for u in userlist])
743 common_names = group_names.intersection(user_names)
745 logger.error("Following names are both user names and group names:")
746 for name in common_names:
747 logger.error(" %s" % name)
748 raise ProvisioningError("Please remove common user/group names before upgrade.")
750 # Check for same user sid/group sid
751 group_sids = set([str(g.sid) for g in grouplist])
752 if len(grouplist) != len(group_sids):
753 raise ProvisioningError("Please remove duplicate group sid entries before upgrade.")
754 user_sids = set(["%s-%u" % (domainsid, u['rid']) for u in userlist])
755 if len(userlist) != len(user_sids):
756 raise ProvisioningError("Please remove duplicate user sid entries before upgrade.")
757 common_sids = group_sids.intersection(user_sids)
759 logger.error("Following sids are both user and group sids:")
760 for sid in common_sids:
761 logger.error(" %s" % str(sid))
762 raise ProvisioningError("Please remove duplicate sid entries before upgrade.")
764 if not (serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC"):
768 result = provision(logger, session_info, None,
769 targetdir=targetdir, realm=realm, domain=domainname,
770 domainsid=str(domainsid), next_rid=next_rid,
772 dom_for_fun_level=dsdb.DS_DOMAIN_FUNCTION_2003,
773 hostname=netbiosname.lower(), machinepass=machinepass,
774 serverrole=serverrole, samdb_fill=FILL_FULL,
775 useeadb=useeadb, dns_backend=dns_backend, use_rfc2307=True)
776 result.report_logger(logger)
778 # Import WINS database
779 logger.info("Importing WINS database")
783 samba3_winsdb = samba3.get_wins_db()
785 logger.warn('Cannot open wins database, Ignoring: %s', str(e))
788 import_wins(Ldb(result.paths.winsdb), samba3_winsdb)
791 logger.info("Importing Account policy")
792 import_sam_policy(result.samdb, policy, logger)
794 # Migrate IDMAP database
795 logger.info("Importing idmap database")
796 import_idmap(result.idmap, samba3, logger)
798 # Get posix attributes from ldap or the os
803 creds = Credentials()
804 creds.guess(result.lp)
805 creds.set_bind_dn(ldapuser)
806 creds.set_password(ldappass)
807 urls = samba3.lp.get("passdb backend").split(":",1)[1].strip('"')
808 for url in urls.split():
810 ldb_object = Ldb(url, session_info=system_session(result.lp), credentials=creds, lp=result.lp)
811 except ldb.LdbError, e:
812 logger.warning("Could not open ldb connection to %s, the error message is: %s", url, e)
815 logger.info("Exporting posix attributes")
816 userlist = s3db.search_users(0)
817 for entry in userlist:
818 username = entry['account_name']
819 if username in uids.keys():
821 homes[username] = get_posix_attr_from_ldap_backend(logger, ldb_object, base_dn, username, "homeDirectory")
822 shells[username] = get_posix_attr_from_ldap_backend(logger, ldb_object, base_dn, username, "loginShell")
823 pgids[username] = get_posix_attr_from_ldap_backend(logger, ldb_object, base_dn, username, "gidNumber")
826 homes[username] = pwd.getpwnam(username).pw_dir
830 shells[username] = pwd.getpwnam(username).pw_shell
834 pgids[username] = pwd.getpwnam(username).pw_gid
838 # Set the s3 context for samba4 configuration
839 new_lp_ctx = s3param.get_context()
840 new_lp_ctx.load(result.lp.configfile)
841 new_lp_ctx.set("private dir", result.lp.get("private dir"))
842 new_lp_ctx.set("state directory", result.lp.get("state directory"))
843 new_lp_ctx.set("lock directory", result.lp.get("lock directory"))
845 # Connect to samba4 backend
846 s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend"))
848 # Export groups to samba4 backend
849 logger.info("Importing groups")
851 # Ignore uninitialized groups (gid = -1)
853 add_group_from_mapping_entry(result.samdb, g, logger)
854 add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, "ID_TYPE_GID", logger)
855 add_posix_attrs(samdb=result.samdb, sid=g.sid, name=g.nt_name, nisdomain=domainname.lower(), xid_type="ID_TYPE_GID", logger=logger)
857 # Export users to samba4 backend
858 logger.info("Importing users")
859 for username in userdata:
860 if username.lower() == 'administrator':
861 if userdata[username].user_sid != dom_sid(str(domainsid) + "-500"):
862 raise ProvisioningError("User 'Administrator' in your existing directory does not have SID ending in -500")
863 if username.lower() == 'root':
864 if userdata[username].user_sid == dom_sid(str(domainsid) + "-500"):
865 logger.warn('User root has been replaced by Administrator')
867 logger.warn('User root has been kept in the directory, it should be removed in favour of the Administrator user')
869 s4_passdb.add_sam_account(userdata[username])
871 add_ad_posix_idmap_entry(result.samdb, userdata[username].user_sid, uids[username], "ID_TYPE_UID", logger)
872 if (username in homes) and (homes[username] != None) and \
873 (username in shells) and (shells[username] != None) and \
874 (username in pgids) and (pgids[username] != None):
875 add_posix_attrs(samdb=result.samdb, sid=userdata[username].user_sid, name=username, nisdomain=domainname.lower(), xid_type="ID_TYPE_UID", home=homes[username], shell=shells[username], pgid=pgids[username], logger=logger)
877 logger.info("Adding users to groups")
879 if str(g.sid) in groupmembers:
880 add_users_to_group(result.samdb, g, groupmembers[str(g.sid)], logger)
882 # Set password for administrator
884 logger.info("Setting password for administrator")
885 admin_userdata = s4_passdb.getsampwnam("administrator")
886 admin_userdata.nt_passwd = userdata[admin_user].nt_passwd
887 if userdata[admin_user].lanman_passwd:
888 admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd
889 admin_userdata.pass_last_set_time = userdata[admin_user].pass_last_set_time
890 if userdata[admin_user].pw_history:
891 admin_userdata.pw_history = userdata[admin_user].pw_history
892 s4_passdb.update_sam_account(admin_userdata)
893 logger.info("Administrator password has been set to password of user '%s'", admin_user)
895 # FIXME: import_registry(registry.Registry(), samba3.get_registry())