def run(self, acl, file, use_ntvfs=False, use_s3fs=False, quiet=False,xattr_backend=None,eadb_file=None, credopts=None, sambaopts=None, versionopts=None, service=None): logger = self.get_logger() lp = sambaopts.get_loadparm() try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False try: domain_sid = security.dom_sid(samdb.domain_sid) except: raise CommandError("Unable to read domain SID from configuration files") s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) setntacl(lp, file, acl, str(domain_sid), xattr_backend, eadb_file, use_ntvfs=use_ntvfs, service=service) if use_ntvfs: logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL")
def run(self, file, use_ntvfs=False, use_s3fs=False, as_sddl=False, xattr_backend=None, eadb_file=None, credopts=None, sambaopts=None, versionopts=None, service=None): lp = sambaopts.get_loadparm() try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) acl = getntacl(lp, file, xattr_backend, eadb_file, direct_db_access=use_ntvfs, service=service) if as_sddl: try: domain_sid = security.dom_sid(samdb.domain_sid) except: raise CommandError("Unable to read domain SID from configuration files") self.outf.write(acl.as_sddl(domain_sid)+"\n") else: self.outf.write(ndr_print(acl))
def test_OpenClose(self): lp = s3param.get_context() lp.load(os.getenv("SMB_CONF_PATH")) creds = credentials.Credentials() creds.guess(lp) creds.set_username(os.getenv("USERNAME")) creds.set_password(os.getenv("PASSWORD")) c = libsmb_samba_internal.Conn(os.getenv("SERVER_IP"), "tmp", creds) mythreads = [] for i in range(3): t = LibsmbTestCase.OpenClose(c, "test" + str(i), 10) mythreads.append(t) for t in mythreads: t.start() for t in mythreads: t.join() if t.exc: raise t.exc[0](t.exc[1])
def run(self, file, credopts=None, sambaopts=None, versionopts=None): lp = sambaopts.get_loadparm() s3conf = s3param.get_context() s3conf.load(lp.configfile) dosinfo = getdosinfo(lp, file) if dosinfo: self.outf.write(ndr_print(dosinfo))
def setUp(self): super(PosixAclMappingTests, self).setUp() s3conf = s3param.get_context() s3conf.load(self.get_loadparm().configfile) s3conf.set("xattr_tdb:file", os.path.join(self.tempdir,"xattr.tdb")) self.lp = s3conf self.tempf = os.path.join(self.tempdir, "test") open(self.tempf, 'w').write("empty")
def getntacl_util(path): s3conf = s3param.get_context() s3conf.load("/etc/samba/smb.conf") sd = smbd.get_nt_acl(path, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, service=None) return sd
def setUp(self): super(PosixAclMappingTests, self).setUp() s3conf = s3param.get_context() s3conf.load(self.get_loadparm().configfile) s3conf.set("xattr_tdb:file", os.path.join(self.tempdir, "xattr.tdb")) self.lp = s3conf self.tempf = os.path.join(self.tempdir, "test") open(self.tempf, 'w').write("empty")
def __init__(self, service, smb_conf_path, dom_sid): self.service = service self.dom_sid = dom_sid # this is important to help smbd find services. self.lp = s3param.get_context() self.lp.load(smb_conf_path) self.use_ntvfs = "smb" in self.lp.get("server services")
def test_setntacl(rootpath, sddl): s3conf = s3param.get_context() s3conf.load("/etc/samba/smb.conf") sd = security.descriptor.from_sddl(sddl, security.dom_sid()) smbd.set_nt_acl(rootpath, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, sd, service=None)
def prep_creds(self): lp = s3param.get_context() lp.load(os.getenv("SMB_CONF_PATH")) creds = credentials.Credentials() creds.guess(lp) creds.set_username(os.getenv("USERNAME")) creds.set_password(os.getenv("PASSWORD")) return (lp,creds)
def __init__(self, smbconf=None): param, passdb = _samba_modules() lp = param.get_context() if smbconf is None: lp.load_default() else: lp.load(smbconf) passdb.set_secrets_dir(lp.get("private dir")) self._pdb = passdb.PDB(lp.get("passdb backend")) self._passdb = passdb
def check_refresh_gpo_list(dc_hostname, lp, creds, gpos): # the SMB bindings rely on having a s3 loadparm s3_lp = s3param.get_context() s3_lp.load(lp.configfile) conn = libsmb.Conn(dc_hostname, 'sysvol', lp=s3_lp, creds=creds, sign=True) cache_path = lp.cache_path('gpo_cache') for gpo in gpos: if not gpo.file_sys_path: continue cache_gpo_dir(conn, cache_path, check_safe_path(gpo.file_sys_path))
def setUp(self): super(SMBTests, self).setUp() self.server = os.environ["SERVER"] creds = self.insta_creds(template=self.get_credentials()) # create an SMB connection to the server lp = s3param.get_context() lp.load(os.getenv("SMB_CONF_PATH")) self.smb_conn = libsmb.Conn(self.server, "sysvol", lp, creds) self.smb_conn.mkdir(test_dir)
def run(self, file, use_ntvfs=False, use_s3fs=False, as_sddl=False, xattr_backend=None, eadb_file=None, credopts=None, sambaopts=None, versionopts=None, service=None): lp = sambaopts.get_loadparm() is_ad_dc = False server_role = lp.server_role() if server_role == "ROLE_ACTIVE_DIRECTORY_DC": is_ad_dc = True if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False s3conf = s3param.get_context() s3conf.load(lp.configfile) if is_ad_dc: try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) # ensure we are using the right samba_dsdb passdb backend, no # matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) acl = getntacl(lp, file, xattr_backend, eadb_file, direct_db_access=use_ntvfs, service=service, session_info=system_session_unix()) if as_sddl: try: if is_ad_dc: domain_sid = security.dom_sid(samdb.domain_sid) else: domain_sid = passdb.get_domain_sid() except: raise CommandError("Unable to read domain SID from " "configuration files") self.outf.write(acl.as_sddl(domain_sid) + "\n") else: self.outf.write(ndr_print(acl))
def __init__(self, smbconfpath, s3_lp_ctx=None): """Open the configuration and data for a Samba 3 installation. :param smbconfpath: Path to the smb.conf file. :param s3_lp_ctx: Samba3 Loadparm context """ self.smbconfpath = smbconfpath if s3_lp_ctx: self.lp = s3_lp_ctx else: self.lp = s3param.get_context() self.lp.load(smbconfpath)
def setUp(self): super(SmbCaclsBlockboxTestBase, self).setUp() self.lp = s3param.get_context() self.server = os.environ["SERVER"] self.user = os.environ["USER"] self.passwd = os.environ["PASSWORD"] self.creds = Credentials() self.creds.guess(self.lp) self.creds.set_username(self.user) self.creds.set_password(self.passwd) self.testdir = os.getenv("TESTDIR", "smbcacls") self.share = os.getenv("SHARE", "tmp")
def setUp(self): super (PassdbTestCase, self).setUp() os.system("cp -r %s %s" % (DATADIR, self.tempdir)) datadir = os.path.join(self.tempdir, "samba3") self.lp = s3param.get_context() self.lp.load(os.path.join(datadir, "smb.conf")) self.lp.set("private dir", datadir) self.lp.set("state directory", datadir) self.lp.set("lock directory", datadir) passdb.set_secrets_dir(datadir) self.pdb = passdb.PDB("tdbsam")
def __init__(self, target_hostname, pipename, creds, impersonation_level, lp): lp3 = s3param.get_context() lp3.load(lp.configfile) self.smbconn = libsmb_samba_internal.Conn(target_hostname, 'IPC$', credentials=creds, sign=True) self.smbfid = self.smbconn.create(pipename, DesiredAccess=0x12019f, ShareAccess=0x7, CreateDisposition=1, CreateOptions=0x400040, ImpersonationLevel=impersonation_level) return
def setUp(self): super(PassdbTestCase, self).setUp() os.system("cp -r %s %s" % (DATADIR, self.tempdir)) datadir = os.path.join(self.tempdir, "samba3") self.lp = s3param.get_context() self.lp.load(os.path.join(datadir, "smb.conf")) self.lp.set("private dir", datadir) self.lp.set("state directory", datadir) self.lp.set("lock directory", datadir) passdb.set_secrets_dir(datadir) self.pdb = passdb.PDB("tdbsam")
class cmd_ntacl_set(Command): """Set ACLs on a file.""" synopsis = "%prog <acl> <file> [options]" takes_optiongroups = { "sambaopts": options.SambaOptions, "credopts": options.CredentialsOptions, "versionopts": options.VersionOptions, } takes_options = [ Option("--quiet", help="Be quiet", action="store_true"), Option("--xattr-backend", type="choice", help="xattr backend type (native fs or tdb)", choices=["native","tdb"]), Option("--eadb-file", help="Name of the tdb file where attributes are stored", type="string"), Option("--use-ntvfs", help="Set the ACLs directly to the TDB or xattr for use with the ntvfs file server", action="store_true"), Option("--use-s3fs", help="Set the ACLs for use with the default s3fs file server via the VFS layer", action="store_true") ] takes_args = ["acl","file"] def run(self, acl, file, use_ntvfs=False, use_s3fs=False, quiet=False,xattr_backend=None,eadb_file=None, credopts=None, sambaopts=None, versionopts=None): logger = self.get_logger() lp = sambaopts.get_loadparm() try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception, e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False try: domain_sid = security.dom_sid(samdb.domain_sid) except: raise CommandError("Unable to read domain SID from configuration files") s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) setntacl(lp, file, acl, str(domain_sid), xattr_backend, eadb_file, use_ntvfs=use_ntvfs) if use_ntvfs: logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL")
class cmd_ntacl_get(Command): """Get ACLs of a file.""" synopsis = "%prog <file> [options]" takes_optiongroups = { "sambaopts": options.SambaOptions, "credopts": options.CredentialsOptions, "versionopts": options.VersionOptions, } takes_options = [ Option("--as-sddl", help="Output ACL in the SDDL format", action="store_true"), Option("--xattr-backend", type="choice", help="xattr backend type (native fs or tdb)", choices=["native","tdb"]), Option("--eadb-file", help="Name of the tdb file where attributes are stored", type="string"), Option("--use-ntvfs", help="Get the ACLs directly from the TDB or xattr used with the ntvfs file server", action="store_true"), Option("--use-s3fs", help="Get the ACLs for use via the VFS layer used by the default s3fs file server", action="store_true") ] takes_args = ["file"] def run(self, file, use_ntvfs=False, use_s3fs=False, as_sddl=False, xattr_backend=None, eadb_file=None, credopts=None, sambaopts=None, versionopts=None): lp = sambaopts.get_loadparm() try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception, e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) acl = getntacl(lp, file, xattr_backend, eadb_file, direct_db_access=use_ntvfs) if as_sddl: try: domain_sid = security.dom_sid(samdb.domain_sid) except: raise CommandError("Unable to read domain SID from configuration files") self.outf.write(acl.as_sddl(domain_sid)+"\n") else: self.outf.write(ndr_print(acl))
def run(self, use_ntvfs=False, use_s3fs=False, credopts=None, sambaopts=None, versionopts=None): lp = sambaopts.get_loadparm() path = lp.private_path("secrets.ldb") creds = credopts.get_credentials(lp) creds.set_kerberos_state(DONT_USE_KERBEROS) logger = self.get_logger() netlogon = lp.get("path", "netlogon") sysvol = lp.get("path", "sysvol") try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False domain_sid = security.dom_sid(samdb.domain_sid) s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) LA_sid = security.dom_sid(str(domain_sid) + "-" + str(security.DOMAIN_RID_ADMINISTRATOR)) BA_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS) s4_passdb = passdb.PDB(s3conf.get("passdb backend")) # These assertions correct for current ad_dc selftest # configuration. When other environments have a broad range of # groups mapped via passdb, we can relax some of these checks (LA_uid, LA_type) = s4_passdb.sid_to_id(LA_sid) if (LA_type != idmap.ID_TYPE_UID and LA_type != idmap.ID_TYPE_BOTH): raise CommandError("SID %s is not mapped to a UID" % LA_sid) (BA_gid, BA_type) = s4_passdb.sid_to_id(BA_sid) if (BA_type != idmap.ID_TYPE_GID and BA_type != idmap.ID_TYPE_BOTH): raise CommandError("SID %s is not mapped to a GID" % BA_sid) if use_ntvfs: logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL") provision.setsysvolacl(samdb, netlogon, sysvol, LA_uid, BA_gid, domain_sid, lp.get("realm").lower(), samdb.domain_dn(), lp, use_ntvfs=use_ntvfs)
def run(self, acl, file, use_ntvfs=False, use_s3fs=False, quiet=False, xattr_backend=None, eadb_file=None, credopts=None, sambaopts=None, versionopts=None, service=None): logger = self.get_logger() lp = sambaopts.get_loadparm() is_ad_dc = False server_role = lp.server_role() if server_role == "ROLE_ACTIVE_DIRECTORY_DC": is_ad_dc = True if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False s3conf = s3param.get_context() s3conf.load(lp.configfile) if is_ad_dc: try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) # ensure we are using the right samba_dsdb passdb backend, no # matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) try: if is_ad_dc: domain_sid = security.dom_sid(samdb.domain_sid) else: domain_sid = passdb.get_domain_sid() except: raise CommandError("Unable to read domain SID from configuration " "files") setntacl(lp, file, acl, str(domain_sid), xattr_backend, eadb_file, use_ntvfs=use_ntvfs, service=service, session_info=system_session_unix()) if use_ntvfs: logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL")
def run(self, use_ntvfs=False, use_s3fs=False, credopts=None, sambaopts=None, versionopts=None): lp = sambaopts.get_loadparm() path = lp.private_path("secrets.ldb") creds = credopts.get_credentials(lp) creds.set_kerberos_state(DONT_USE_KERBEROS) logger = self.get_logger() netlogon = lp.get("path", "netlogon") sysvol = lp.get("path", "sysvol") try: samdb = SamDB(session_info=system_session(), lp=lp) except Exception as e: raise CommandError("Unable to open samdb:", e) if not use_ntvfs and not use_s3fs: use_ntvfs = "smb" in lp.get("server services") elif use_s3fs: use_ntvfs = False domain_sid = security.dom_sid(samdb.domain_sid) s3conf = s3param.get_context() s3conf.load(lp.configfile) # ensure we are using the right samba_dsdb passdb backend, no matter what s3conf.set("passdb backend", "samba_dsdb:%s" % samdb.url) LA_sid = security.dom_sid(str(domain_sid) +"-"+str(security.DOMAIN_RID_ADMINISTRATOR)) BA_sid = security.dom_sid(security.SID_BUILTIN_ADMINISTRATORS) s4_passdb = passdb.PDB(s3conf.get("passdb backend")) # These assertions correct for current ad_dc selftest # configuration. When other environments have a broad range of # groups mapped via passdb, we can relax some of these checks (LA_uid,LA_type) = s4_passdb.sid_to_id(LA_sid) if (LA_type != idmap.ID_TYPE_UID and LA_type != idmap.ID_TYPE_BOTH): raise CommandError("SID %s is not mapped to a UID" % LA_sid) (BA_gid,BA_type) = s4_passdb.sid_to_id(BA_sid) if (BA_type != idmap.ID_TYPE_GID and BA_type != idmap.ID_TYPE_BOTH): raise CommandError("SID %s is not mapped to a GID" % BA_sid) if use_ntvfs: logger.warning("Please note that POSIX permissions have NOT been changed, only the stored NT ACL") provision.setsysvolacl(samdb, netlogon, sysvol, LA_uid, BA_gid, domain_sid, lp.get("realm").lower(), samdb.domain_dn(), lp, use_ntvfs=use_ntvfs)
def connect(self, host=None, share=None, username=None, password=None): self._lp = s3param.get_context() self._lp.load_default() self._cred = credentials.Credentials() self._cred.guess(self._lp) if username is not None: self._cred.set_username(username) if password is not None: self._cred.set_password(password) self._host = host self._share = share self._connection = libsmb.Conn(host, share, self._lp, self._cred)
def __init__(self, target_hostname, pipename, creds, impersonation_level, lp): lp3 = s3param.get_context() lp3.load(lp.configfile) saved_signing_state = creds.get_smb_ipc_signing() creds.set_smb_ipc_signing(SMB_SIGNING_REQUIRED) self.smbconn = libsmb.Conn(target_hostname, 'IPC$', lp3, creds=creds, ipc=True) creds.set_smb_ipc_signing(saved_signing_state) self.smbfid = self.smbconn.create(pipename, DesiredAccess=0x12019f, ShareAccess=0x7, CreateDisposition=1, CreateOptions=0x400040, ImpersonationLevel=impersonation_level) return
def check_refresh_gpo_list(dc_hostname, lp, creds, gpos): # the SMB bindings rely on having a s3 loadparm s3_lp = s3param.get_context() s3_lp.load(lp.configfile) # Force signing for the connection saved_signing_state = creds.get_smb_signing() creds.set_smb_signing(SMB_SIGNING_REQUIRED) conn = libsmb.Conn(dc_hostname, 'sysvol', lp=s3_lp, creds=creds) # Reset signing state creds.set_smb_signing(saved_signing_state) cache_path = lp.cache_path('gpo_cache') for gpo in gpos: if not gpo.file_sys_path: continue cache_gpo_dir(conn, cache_path, check_safe_path(gpo.file_sys_path))
def test_SMB3EncryptionRequired(self): test_dir = 'testing_%d' % random.randint(0, 0xFFFF) lp = s3param.get_context() lp.load(os.getenv("SMB_CONF_PATH")) creds = credentials.Credentials() creds.guess(lp) creds.set_username(os.getenv("USERNAME")) creds.set_password(os.getenv("PASSWORD")) creds.set_smb_encryption(SMB_ENCRYPTION_REQUIRED) c = libsmb.Conn(os.getenv("SERVER_IP"), "tmp", lp, creds) c.mkdir(test_dir) c.rmdir(test_dir)
def replacentacl(rootpath, ck_uid, sddl): s3conf = s3param.get_context() s3conf.load("/etc/samba/smb.conf") sd = security.descriptor.from_sddl(sddl, security.dom_sid()) smbd_set_ntacl(rootpath, sd) if os.path.isfile(rootpath): return {'status': 0} sd_dic = ntacl_parser_from_sd(sd) fsd_dic = get_sd_file(sd_dic) dsd_dic = get_sd_dir(sd_dic) for f in os.listdir(rootpath): subpath = rootpath + "/" + f if os.path.isfile(subpath): replacentacl_file(subpath, fsd_dic) else: replacentacl_dir(subpath, dsd_dic) return {'status': 0}
def setntacl(rootpath, sddl): print rootpath, sddl s3conf = s3param.get_context() s3conf.load("/etc/samba/smb.conf") sd = security.descriptor.from_sddl(sddl, security.dom_sid()) smbd.set_nt_acl(rootpath, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, sd, service=None) sd_dic = ntacl_parser_from_sd(sd) fsd_dic = get_sd_file(sd_dic) dsd_dic = get_sd_dir(sd_dic) for f in os.listdir(rootpath): subpath = rootpath + "/" + f if os.path.isfile(subpath): setntacl_file(subpath, fsd_dic) else: setntacl_dir(subpath, dsd_dic) return {'status': 0}
def _get_smb_connection(self, service='SysVol'): # Create options like if we were using command line parser = optparse.OptionParser() sambaopts = options.SambaOptions(parser) # Samba options parm = sambaopts.get_loadparm() s3_lp = s3param.get_context() s3_lp.load(parm.configfile) # Build credentials from credential options creds = Credentials() # Credentials need username and realm to be not empty strings to work creds.set_username('NOTEMPTY') creds.set_realm('NOTEMPTY') # Connect to SMB using kerberos creds.set_kerberos_state(MUST_USE_KERBEROS) # Create connection conn = libsmb.Conn(self._get_server_name(), service, lp=parm, creds=creds, sign=False) return conn
def test_OpenClose(self): lp = s3param.get_context() lp.load(os.getenv("SMB_CONF_PATH")) creds = credentials.Credentials() creds.set_username(os.getenv("USERNAME")) creds.set_password(os.getenv("PASSWORD")) c = libsmb_samba_internal.Conn(os.getenv("SERVER_IP"), "tmp", creds) mythreads = [] for i in range(3): t = LibsmbTestCase.OpenClose(c, "test" + str(i), 10) mythreads.append(t) for t in mythreads: t.start() for t in mythreads: t.join() if t.exc: raise t.exc[0](t.exc[1])
def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, useeadb=False): """Upgrade from samba3 database to samba4 AD database :param samba3: samba3 object :param logger: Logger object :param targetdir: samba4 database directory :param session_info: Session information """ if samba3.lp.get("domain logons"): serverrole = "domain controller" else: if samba3.lp.get("security") == "user": serverrole = "standalone" else: serverrole = "member server" domainname = samba3.lp.get("workgroup") realm = samba3.lp.get("realm") netbiosname = samba3.lp.get("netbios name") # secrets db secrets_db = samba3.get_secrets_db() if not domainname: domainname = secrets_db.domains()[0] logger.warning("No workgroup specified in smb.conf file, assuming '%s'", domainname) if not realm: if serverrole == "domain controller": 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.") else: realm = domainname.upper() logger.warning("No realm specified in smb.conf file, assuming '%s'", realm) # Find machine account and password machinepass = None machinerid = None machinesid = None next_rid = 1000 try: machinepass = secrets_db.get_machine_password(netbiosname) except: pass # We must close the direct pytdb database before the C code loads it secrets_db.close() # Connect to old password backend passdb.set_secrets_dir(samba3.lp.get("private dir")) s3db = samba3.get_sam_db() # Get domain sid try: domainsid = passdb.get_global_sam_sid() except passdb.error: raise Exception("Can't find domain sid for '%s', Exiting." % domainname) # Get machine account, sid, rid try: machineacct = s3db.getsampwnam('%s$' % netbiosname) machinesid, machinerid = machineacct.user_sid.split() except: pass # Export account policy logger.info("Exporting account policy") policy = s3db.get_account_policy() # Export groups from old passdb backend logger.info("Exporting groups") grouplist = s3db.enum_group_mapping() groupmembers = {} for group in grouplist: sid, rid = group.sid.split() if sid == domainsid: if rid >= next_rid: next_rid = rid + 1 # Get members for each group/alias if group.sid_name_use == lsa.SID_NAME_ALIAS: members = s3db.enum_aliasmem(group.sid) elif group.sid_name_use == lsa.SID_NAME_DOM_GRP: try: members = s3db.enum_group_members(group.sid) except: continue groupmembers[group.nt_name] = members elif group.sid_name_use == lsa.SID_NAME_WKN_GRP: (group_dom_sid, rid) = group.sid.split() if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)): logger.warn("Ignoring 'well known' group '%s' (should already be in AD, and have no members)", group.nt_name) continue # A number of buggy databases mix up well known groups and aliases. members = s3db.enum_aliasmem(group.sid) else: logger.warn("Ignoring group '%s' with sid_name_use=%d", group.nt_name, group.sid_name_use) continue # Export users from old passdb backend logger.info("Exporting users") userlist = s3db.search_users(0) userdata = {} uids = {} admin_user = None for entry in userlist: if machinerid and machinerid == entry['rid']: continue username = entry['account_name'] if entry['rid'] < 1000: logger.info(" Skipping wellknown rid=%d (for username=%s)", entry['rid'], username) continue if entry['rid'] >= next_rid: next_rid = entry['rid'] + 1 user = s3db.getsampwnam(username) acct_type = (user.acct_ctrl & (samr.ACB_NORMAL|samr.ACB_WSTRUST|samr.ACB_SVRTRUST|samr.ACB_DOMTRUST)) if (acct_type == samr.ACB_NORMAL or acct_type == samr.ACB_WSTRUST or acct_type == samr.ACB_SVRTRUST): pass elif acct_type == samr.ACB_DOMTRUST: logger.warn(" Skipping inter-domain trust from domain %s, this trust must be re-created as an AD trust" % username[:-1]) continue elif acct_type == (samr.ACB_NORMAL|samr.ACB_WSTRUST) and username[-1] == '$': 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) user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL) else: raise ProvisioningError("""Failed to upgrade due to invalid account %s, account control flags 0x%08X must have exactly one of ACB_NORMAL (N, 0x%08X), ACB_WSTRUST (W 0x%08X), ACB_SVRTRUST (S 0x%08X) or ACB_DOMTRUST (D 0x%08X). Please fix this account before attempting to upgrade again """ % (user.acct_flags, username, samr.ACB_NORMAL, samr.ACB_WSTRUST, samr.ACB_SVRTRUST, samr.ACB_DOMTRUST)) userdata[username] = user try: uids[username] = s3db.sid_to_id(user.user_sid)[0] except: try: uids[username] = pwd.getpwnam(username).pw_uid except: pass if not admin_user and username.lower() == 'root': admin_user = username if username.lower() == 'administrator': admin_user = username logger.info("Next rid = %d", next_rid) # Check for same username/groupname group_names = set(map(lambda g: g.nt_name, grouplist)) user_names = set(map(lambda u: u['account_name'], userlist)) common_names = group_names.intersection(user_names) if common_names: logger.error("Following names are both user names and group names:") for name in common_names: logger.error(" %s" % name) raise ProvisioningError("Please remove common user/group names before upgrade.") # Check for same user sid/group sid group_sids = set(map(lambda g: str(g.sid), grouplist)) user_sids = set(map(lambda u: "%s-%u" % (domainsid, u['rid']), userlist)) common_sids = group_sids.intersection(user_sids) if common_sids: logger.error("Following sids are both user and group sids:") for sid in common_sids: logger.error(" %s" % str(sid)) raise ProvisioningError("Please remove duplicate sid entries before upgrade.") # Do full provision result = provision(logger, session_info, None, targetdir=targetdir, realm=realm, domain=domainname, domainsid=str(domainsid), next_rid=next_rid, dc_rid=machinerid, hostname=netbiosname, machinepass=machinepass, serverrole=serverrole, samdb_fill=FILL_FULL, useeadb=useeadb) # Import WINS database logger.info("Importing WINS database") import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Export groups to samba4 backend logger.info("Importing groups") for g in grouplist: # Ignore uninitialized groups (gid = -1) if g.gid != 0xffffffff: add_idmap_entry(result.idmap, g.sid, g.gid, "GID", logger) add_group_from_mapping_entry(result.samdb, g, logger) # Export users to samba4 backend logger.info("Importing users") for username in userdata: if username.lower() == 'administrator' or username.lower() == 'root': continue s4_passdb.add_sam_account(userdata[username]) if username in uids: add_idmap_entry(result.idmap, userdata[username].user_sid, uids[username], "UID", logger) logger.info("Adding users to groups") for g in grouplist: if g.nt_name in groupmembers: add_users_to_group(result.samdb, g, groupmembers[g.nt_name], logger) # Set password for administrator if admin_user: logger.info("Setting password for administrator") admin_userdata = s4_passdb.getsampwnam("administrator") admin_userdata.nt_passwd = userdata[admin_user].nt_passwd if userdata[admin_user].lanman_passwd: admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd admin_userdata.pass_last_set_time = userdata[admin_user].pass_last_set_time if userdata[admin_user].pw_history: admin_userdata.pw_history = userdata[admin_user].pw_history s4_passdb.update_sam_account(admin_userdata) logger.info("Administrator password has been set to password of user '%s'", admin_user)
# Import WINS database logger.info("Importing WINS database") if samba3_winsdb: import_wins(Ldb(result.paths.winsdb), samba3_winsdb) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Export groups to samba4 backend logger.info("Importing groups") for g in grouplist: # Ignore uninitialized groups (gid = -1) if g.gid != -1: add_group_from_mapping_entry(result.samdb, g, logger) add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, "ID_TYPE_GID",
# Import WINS database logger.info("Importing WINS database") if samba3_winsdb: import_wins(Ldb(result.paths.winsdb), samba3_winsdb) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() logger.info("Adding groups") try: # Export groups to samba4 backend logger.info("Importing groups")
def run(self, smbconf=None, targetdir=None, dbdir=None, testparm=None, quiet=False, verbose=False, use_xattrs=None, sambaopts=None, versionopts=None): if not os.path.exists(smbconf): raise CommandError("File %s does not exist" % smbconf) if testparm and not os.path.exists(testparm): raise CommandError("Testparm utility %s does not exist" % testparm) if dbdir and not os.path.exists(dbdir): raise CommandError("Directory %s does not exist" % dbdir) if not dbdir and not testparm: raise CommandError("Please specify either dbdir or testparm") logger = self.get_logger() if verbose: logger.setLevel(logging.DEBUG) elif quiet: logger.setLevel(logging.WARNING) else: logger.setLevel(logging.INFO) if dbdir and testparm: logger.warning( "both dbdir and testparm specified, ignoring dbdir.") dbdir = None lp = sambaopts.get_loadparm() s3conf = s3param.get_context() if sambaopts.realm: s3conf.set("realm", sambaopts.realm) eadb = True if use_xattrs == "yes": eadb = False elif use_xattrs == "auto" and not s3conf.get("posix:eadb"): if targetdir: tmpfile = tempfile.NamedTemporaryFile( prefix=os.path.abspath(targetdir)) else: tmpfile = tempfile.NamedTemporaryFile(prefix=os.path.abspath( os.path.dirname(lp.get("private dir")))) try: samba.ntacls.setntacl(lp, tmpfile.name, "O:S-1-5-32G:S-1-5-32", "S-1-5-32", "native") eadb = False except: # FIXME: Don't catch all exceptions here logger.info( "You are not root or your system do not support xattr, using tdb backend for attributes. " "If you intend to use this provision in production, rerun the script as root on a system supporting xattrs." ) tmpfile.close() # Set correct default values from dbdir or testparm paths = {} if dbdir: paths["state directory"] = dbdir paths["private dir"] = dbdir paths["lock directory"] = dbdir else: paths["state directory"] = get_testparm_var( testparm, smbconf, "state directory") paths["private dir"] = get_testparm_var(testparm, smbconf, "private dir") paths["lock directory"] = get_testparm_var(testparm, smbconf, "lock directory") # "testparm" from Samba 3 < 3.4.x is not aware of the parameter # "state directory", instead make use of "lock directory" if len(paths["state directory"]) == 0: paths["state directory"] = paths["lock directory"] for p in paths: s3conf.set(p, paths[p]) # load smb.conf parameters logger.info("Reading smb.conf") s3conf.load(smbconf) samba3 = Samba3(smbconf, s3conf) logger.info("Provisioning") upgrade_from_samba3(samba3, logger, targetdir, session_info=system_session(), useeadb=eadb)
def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, useeadb=False, dns_backend=None, use_ntvfs=False): """Upgrade from samba3 database to samba4 AD database :param samba3: samba3 object :param logger: Logger object :param targetdir: samba4 database directory :param session_info: Session information """ serverrole = samba3.lp.server_role() domainname = samba3.lp.get("workgroup") realm = samba3.lp.get("realm") netbiosname = samba3.lp.get("netbios name") if samba3.lp.get("ldapsam:trusted") is None: samba3.lp.set("ldapsam:trusted", "yes") # secrets db try: secrets_db = samba3.get_secrets_db() except IOError as e: 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))) if not domainname: domainname = secrets_db.domains()[0] logger.warning( "No workgroup specified in smb.conf file, assuming '%s'", domainname) if not realm: if serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC": 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." ) else: realm = domainname.upper() logger.warning( "No realm specified in smb.conf file, assuming '%s'", realm) # Find machine account and password next_rid = 1000 try: machinepass = secrets_db.get_machine_password(netbiosname) except KeyError: machinepass = None if samba3.lp.get("passdb backend").split(":")[0].strip() == "ldapsam": base_dn = samba3.lp.get("ldap suffix") ldapuser = samba3.lp.get("ldap admin dn") ldappass = secrets_db.get_ldap_bind_pw(ldapuser) if ldappass is None: raise ProvisioningError( "ldapsam passdb backend detected but no LDAP Bind PW found in secrets.tdb for user %s. Please point this tool at the secrets.tdb that was used by the previous installation." ) ldappass = ldappass.decode('utf-8').strip('\x00') ldap = True else: ldapuser = None ldappass = None ldap = False # We must close the direct pytdb database before the C code loads it secrets_db.close() # Connect to old password backend passdb.set_secrets_dir(samba3.lp.get("private dir")) s3db = samba3.get_sam_db() # Get domain sid try: domainsid = passdb.get_global_sam_sid() except passdb.error: raise Exception("Can't find domain sid for '%s', Exiting." % domainname) # Get machine account, sid, rid try: machineacct = s3db.getsampwnam('%s$' % netbiosname) except passdb.error: machinerid = None machinesid = None else: machinesid, machinerid = machineacct.user_sid.split() # Export account policy logger.info("Exporting account policy") policy = s3db.get_account_policy() # Export groups from old passdb backend logger.info("Exporting groups") grouplist = s3db.enum_group_mapping() groupmembers = {} for group in grouplist: sid, rid = group.sid.split() if sid == domainsid: if rid >= next_rid: next_rid = rid + 1 # Get members for each group/alias if group.sid_name_use == lsa.SID_NAME_ALIAS: try: members = s3db.enum_aliasmem(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn( "Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue elif group.sid_name_use == lsa.SID_NAME_DOM_GRP: try: members = s3db.enum_group_members(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn( "Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue elif group.sid_name_use == lsa.SID_NAME_WKN_GRP: (group_dom_sid, rid) = group.sid.split() if (group_dom_sid != security.dom_sid(security.SID_BUILTIN)): logger.warn( "Ignoring 'well known' group '%s' (should already be in AD, and have no members)", group.nt_name) continue # A number of buggy databases mix up well known groups and aliases. try: members = s3db.enum_aliasmem(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn( "Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue else: logger.warn("Ignoring group '%s' %s with sid_name_use=%d", group.nt_name, group.sid, group.sid_name_use) continue # Export users from old passdb backend logger.info("Exporting users") userlist = s3db.search_users(0) userdata = {} uids = {} admin_user = None for entry in userlist: if machinerid and machinerid == entry['rid']: continue username = entry['account_name'] if entry['rid'] < 1000: logger.info(" Skipping wellknown rid=%d (for username=%s)", entry['rid'], username) continue if entry['rid'] >= next_rid: next_rid = entry['rid'] + 1 user = s3db.getsampwnam(username) acct_type = (user.acct_ctrl & (samr.ACB_NORMAL | samr.ACB_WSTRUST | samr.ACB_SVRTRUST | samr.ACB_DOMTRUST)) if acct_type == samr.ACB_SVRTRUST: logger.warn( " Demoting BDC account trust for %s, this DC must be elevated to an AD DC using 'samba-tool domain dcpromo'" % username[:-1]) user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_SVRTRUST) | samr.ACB_WSTRUST elif acct_type == samr.ACB_DOMTRUST: logger.warn( " Skipping inter-domain trust from domain %s, this trust must be re-created as an AD trust" % username[:-1]) continue elif acct_type == (samr.ACB_WSTRUST) and username[-1] != '$': logger.warn( " Skipping account %s that has ACB_WSTRUST (W) set but does not end in $. This account can not have worked, and is probably left over from a misconfiguration." % username) continue elif acct_type == (samr.ACB_NORMAL | samr.ACB_WSTRUST) and username[-1] == '$': 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) user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL) elif acct_type == (samr.ACB_NORMAL | samr.ACB_SVRTRUST) and username[-1] == '$': 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) user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_NORMAL) elif acct_type == 0 and username[-1] != '$': user.acct_ctrl = (user.acct_ctrl | samr.ACB_NORMAL) elif (acct_type == samr.ACB_NORMAL or acct_type == samr.ACB_WSTRUST): pass else: raise ProvisioningError( """Failed to upgrade due to invalid account %s, account control flags 0x%08X must have exactly one of ACB_NORMAL (N, 0x%08X), ACB_WSTRUST (W 0x%08X), ACB_SVRTRUST (S 0x%08X) or ACB_DOMTRUST (D 0x%08X). Please fix this account before attempting to upgrade again """ % (username, user.acct_ctrl, samr.ACB_NORMAL, samr.ACB_WSTRUST, samr.ACB_SVRTRUST, samr.ACB_DOMTRUST)) userdata[username] = user try: uids[username] = s3db.sid_to_id(user.user_sid)[0] except passdb.error: try: uids[username] = pwd.getpwnam(username).pw_uid except KeyError: pass if not admin_user and username.lower() == 'root': admin_user = username if username.lower() == 'administrator': admin_user = username try: group_memberships = s3db.enum_group_memberships(user) for group in group_memberships: if str(group) in groupmembers: if user.user_sid not in groupmembers[str(group)]: groupmembers[str(group)].append(user.user_sid) else: groupmembers[str(group)] = [user.user_sid] except passdb.error as e: logger.warn("Ignoring group memberships of '%s' %s: %s", username, user.user_sid, e) logger.info("Next rid = %d", next_rid) # Check for same username/groupname group_names = set([g.nt_name for g in grouplist]) user_names = set([u['account_name'] for u in userlist]) common_names = group_names.intersection(user_names) if common_names: logger.error("Following names are both user names and group names:") for name in common_names: logger.error(" %s" % name) raise ProvisioningError( "Please remove common user/group names before upgrade.") # Check for same user sid/group sid group_sids = set([str(g.sid) for g in grouplist]) if len(grouplist) != len(group_sids): raise ProvisioningError( "Please remove duplicate group sid entries before upgrade.") user_sids = set(["%s-%u" % (domainsid, u['rid']) for u in userlist]) if len(userlist) != len(user_sids): raise ProvisioningError( "Please remove duplicate user sid entries before upgrade.") common_sids = group_sids.intersection(user_sids) if common_sids: logger.error("Following sids are both user and group sids:") for sid in common_sids: logger.error(" %s" % str(sid)) raise ProvisioningError( "Please remove duplicate sid entries before upgrade.") # Get posix attributes from ldap or the os homes = {} shells = {} pgids = {} if ldap: creds = Credentials() creds.guess(samba3.lp) creds.set_bind_dn(ldapuser) creds.set_password(ldappass) urls = samba3.lp.get("passdb backend").split(":", 1)[1].strip('"') for url in urls.split(): try: ldb_object = Ldb(url, credentials=creds) except ldb.LdbError as e: raise ProvisioningError( "Could not open ldb connection to %s, the error message is: %s" % (url, e)) else: break logger.info("Exporting posix attributes") userlist = s3db.search_users(0) for entry in userlist: username = entry['account_name'] if username in uids.keys(): try: if ldap: homes[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "homeDirectory") else: homes[username] = pwd.getpwnam(username).pw_dir except KeyError: pass except IndexError: pass try: if ldap: shells[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "loginShell") else: shells[username] = pwd.getpwnam(username).pw_shell except KeyError: pass except IndexError: pass try: if ldap: pgids[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "gidNumber") else: pgids[username] = pwd.getpwnam(username).pw_gid except KeyError: pass except IndexError: pass logger.info("Reading WINS database") samba3_winsdb = None try: samba3_winsdb = samba3.get_wins_db() except IOError as e: logger.warn('Cannot open wins database, Ignoring: %s', str(e)) if not (serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC"): dns_backend = "NONE" # If we found an admin user, set a fake pw that we will override. # This avoids us printing out an admin password that we won't actually # set. if admin_user: adminpass = generate_random_password(12, 32) else: adminpass = None # Do full provision result = provision(logger, session_info, targetdir=targetdir, realm=realm, domain=domainname, domainsid=domainsid, next_rid=next_rid, dc_rid=machinerid, adminpass=adminpass, dom_for_fun_level=dsdb.DS_DOMAIN_FUNCTION_2003, hostname=netbiosname.lower(), machinepass=machinepass, serverrole=serverrole, samdb_fill=FILL_FULL, useeadb=useeadb, dns_backend=dns_backend, use_rfc2307=True, use_ntvfs=use_ntvfs, skip_sysvolacl=True) result.report_logger(logger) # Import WINS database logger.info("Importing WINS database") if samba3_winsdb: import_wins(Ldb(result.paths.winsdb), samba3_winsdb) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() logger.info("Adding groups") try: # Export groups to samba4 backend logger.info("Importing groups") for g in grouplist: # Ignore uninitialized groups (gid = -1) if g.gid != -1: add_group_from_mapping_entry(result.samdb, g, logger) add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, "ID_TYPE_GID", logger) add_posix_attrs(samdb=result.samdb, sid=g.sid, name=g.nt_name, nisdomain=domainname.lower(), xid_type="ID_TYPE_GID", logger=logger) except: # We need this, so that we do not give even more errors due to not cancelling the transaction result.samdb.transaction_cancel() raise logger.info("Committing 'add groups' transaction to disk") result.samdb.transaction_commit() logger.info("Adding users") # Export users to samba4 backend logger.info("Importing users") for username in userdata: if username.lower() == 'administrator': if userdata[username].user_sid != dom_sid(str(domainsid) + "-500"): logger.error( "User 'Administrator' in your existing directory has SID %s, expected it to be %s" % (userdata[username].user_sid, dom_sid(str(domainsid) + "-500"))) raise ProvisioningError( "User 'Administrator' in your existing directory does not have SID ending in -500" ) if username.lower() == 'root': if userdata[username].user_sid == dom_sid(str(domainsid) + "-500"): logger.warn('User root has been replaced by Administrator') else: logger.warn( 'User root has been kept in the directory, it should be removed in favour of the Administrator user' ) s4_passdb.add_sam_account(userdata[username]) if username in uids: add_ad_posix_idmap_entry(result.samdb, userdata[username].user_sid, uids[username], "ID_TYPE_UID", logger) if (username in homes) and (homes[username] is not None) and \ (username in shells) and (shells[username] is not None) and \ (username in pgids) and (pgids[username] is not None): 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) logger.info("Adding users to groups") # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() try: for g in grouplist: if str(g.sid) in groupmembers: add_users_to_group(result.samdb, g, groupmembers[str(g.sid)], logger) except: # We need this, so that we do not give even more errors due to not cancelling the transaction result.samdb.transaction_cancel() raise logger.info("Committing 'add users to groups' transaction to disk") result.samdb.transaction_commit() # Set password for administrator if admin_user: logger.info("Setting password for administrator") admin_userdata = s4_passdb.getsampwnam("administrator") admin_userdata.nt_passwd = userdata[admin_user].nt_passwd if userdata[admin_user].lanman_passwd: admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd admin_userdata.pass_last_set_time = userdata[ admin_user].pass_last_set_time if userdata[admin_user].pw_history: admin_userdata.pw_history = userdata[admin_user].pw_history s4_passdb.update_sam_account(admin_userdata) logger.info( "Administrator password has been set to password of user '%s'", admin_user) if result.server_role == "active directory domain controller": setsysvolacl(result.samdb, result.paths.netlogon, result.paths.sysvol, result.paths.root_uid, result.paths.root_gid, security.dom_sid(result.domainsid), result.names.dnsdomain, result.names.domaindn, result.lp, use_ntvfs)
try: from samba.samba3 import param except ImportError: param = None LOGLEVEL_MAP = { '0': 'NONE', '1': 'MINIMUM', '2': 'NORMAL', '3': 'FULL', '10': 'DEBUG', } RE_NETBIOSNAME = re.compile(r"^[a-zA-Z0-9\.\-_!@#\$%^&\(\)'\{\}~]{1,15}$") LP_CTX = param.get_context() class SMBHAMODE(enum.IntEnum): """ 'standalone' - Not an HA system. 'legacy' - Two samba instances simultaneously running on active and standby controllers with no shared state. 'unified' - Single set of state files migrating between controllers. Single netbios name. """ STANDALONE = 0 LEGACY = 1 UNIFIED = 2 class SMBCmd(enum.Enum): NET = 'net'
def upgrade_from_samba3(samba3, logger, targetdir, session_info=None, useeadb=False, dns_backend=None, use_ntvfs=False): """Upgrade from samba3 database to samba4 AD database :param samba3: samba3 object :param logger: Logger object :param targetdir: samba4 database directory :param session_info: Session information """ serverrole = samba3.lp.server_role() domainname = samba3.lp.get("workgroup") realm = samba3.lp.get("realm") netbiosname = samba3.lp.get("netbios name") if samba3.lp.get("ldapsam:trusted") is None: samba3.lp.set("ldapsam:trusted", "yes") # secrets db try: secrets_db = samba3.get_secrets_db() except IOError as e: 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)) ) if not domainname: domainname = secrets_db.domains()[0] logger.warning("No workgroup specified in smb.conf file, assuming '%s'", domainname) if not realm: if serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC": 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." ) else: realm = domainname.upper() logger.warning("No realm specified in smb.conf file, assuming '%s'", realm) # Find machine account and password next_rid = 1000 try: machinepass = secrets_db.get_machine_password(netbiosname) except KeyError: machinepass = None if samba3.lp.get("passdb backend").split(":")[0].strip() == "ldapsam": base_dn = samba3.lp.get("ldap suffix") ldapuser = samba3.lp.get("ldap admin dn") ldappass = secrets_db.get_ldap_bind_pw(ldapuser) if ldappass is None: raise ProvisioningError( "ldapsam passdb backend detected but no LDAP Bind PW found in secrets.tdb for user %s. Please point this tool at the secrets.tdb that was used by the previous installation." ) ldappass = ldappass.strip("\x00") ldap = True else: ldapuser = None ldappass = None ldap = False # We must close the direct pytdb database before the C code loads it secrets_db.close() # Connect to old password backend passdb.set_secrets_dir(samba3.lp.get("private dir")) s3db = samba3.get_sam_db() # Get domain sid try: domainsid = passdb.get_global_sam_sid() except passdb.error: raise Exception("Can't find domain sid for '%s', Exiting." % domainname) # Get machine account, sid, rid try: machineacct = s3db.getsampwnam("%s$" % netbiosname) except passdb.error: machinerid = None machinesid = None else: machinesid, machinerid = machineacct.user_sid.split() # Export account policy logger.info("Exporting account policy") policy = s3db.get_account_policy() # Export groups from old passdb backend logger.info("Exporting groups") grouplist = s3db.enum_group_mapping() groupmembers = {} for group in grouplist: sid, rid = group.sid.split() if sid == domainsid: if rid >= next_rid: next_rid = rid + 1 # Get members for each group/alias if group.sid_name_use == lsa.SID_NAME_ALIAS: try: members = s3db.enum_aliasmem(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn("Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue elif group.sid_name_use == lsa.SID_NAME_DOM_GRP: try: members = s3db.enum_group_members(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn("Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue elif group.sid_name_use == lsa.SID_NAME_WKN_GRP: (group_dom_sid, rid) = group.sid.split() if group_dom_sid != security.dom_sid(security.SID_BUILTIN): logger.warn( "Ignoring 'well known' group '%s' (should already be in AD, and have no members)", group.nt_name ) continue # A number of buggy databases mix up well known groups and aliases. try: members = s3db.enum_aliasmem(group.sid) groupmembers[str(group.sid)] = members except passdb.error as e: logger.warn("Ignoring group '%s' %s listed but then not found: %s", group.nt_name, group.sid, e) continue else: logger.warn("Ignoring group '%s' %s with sid_name_use=%d", group.nt_name, group.sid, group.sid_name_use) continue # Export users from old passdb backend logger.info("Exporting users") userlist = s3db.search_users(0) userdata = {} uids = {} admin_user = None for entry in userlist: if machinerid and machinerid == entry["rid"]: continue username = entry["account_name"] if entry["rid"] < 1000: logger.info(" Skipping wellknown rid=%d (for username=%s)", entry["rid"], username) continue if entry["rid"] >= next_rid: next_rid = entry["rid"] + 1 user = s3db.getsampwnam(username) acct_type = user.acct_ctrl & (samr.ACB_NORMAL | samr.ACB_WSTRUST | samr.ACB_SVRTRUST | samr.ACB_DOMTRUST) if acct_type == samr.ACB_SVRTRUST: logger.warn( " Demoting BDC account trust for %s, this DC must be elevated to an AD DC using 'samba-tool domain dcpromo'" % username[:-1] ) user.acct_ctrl = (user.acct_ctrl & ~samr.ACB_SVRTRUST) | samr.ACB_WSTRUST elif acct_type == samr.ACB_DOMTRUST: logger.warn( " Skipping inter-domain trust from domain %s, this trust must be re-created as an AD trust" % username[:-1] ) continue elif acct_type == (samr.ACB_WSTRUST) and username[-1] != "$": logger.warn( " Skipping account %s that has ACB_WSTRUST (W) set but does not end in $. This account can not have worked, and is probably left over from a misconfiguration." % username ) continue elif acct_type == (samr.ACB_NORMAL | samr.ACB_WSTRUST) and username[-1] == "$": 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 ) user.acct_ctrl = user.acct_ctrl & ~samr.ACB_NORMAL elif acct_type == (samr.ACB_NORMAL | samr.ACB_SVRTRUST) and username[-1] == "$": 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 ) user.acct_ctrl = user.acct_ctrl & ~samr.ACB_NORMAL elif acct_type == 0 and username[-1] != "$": user.acct_ctrl = user.acct_ctrl | samr.ACB_NORMAL elif acct_type == samr.ACB_NORMAL or acct_type == samr.ACB_WSTRUST: pass else: raise ProvisioningError( """Failed to upgrade due to invalid account %s, account control flags 0x%08X must have exactly one of ACB_NORMAL (N, 0x%08X), ACB_WSTRUST (W 0x%08X), ACB_SVRTRUST (S 0x%08X) or ACB_DOMTRUST (D 0x%08X). Please fix this account before attempting to upgrade again """ % (username, user.acct_ctrl, samr.ACB_NORMAL, samr.ACB_WSTRUST, samr.ACB_SVRTRUST, samr.ACB_DOMTRUST) ) userdata[username] = user try: uids[username] = s3db.sid_to_id(user.user_sid)[0] except passdb.error: try: uids[username] = pwd.getpwnam(username).pw_uid except KeyError: pass if not admin_user and username.lower() == "root": admin_user = username if username.lower() == "administrator": admin_user = username try: group_memberships = s3db.enum_group_memberships(user) for group in group_memberships: if str(group) in groupmembers: if user.user_sid not in groupmembers[str(group)]: groupmembers[str(group)].append(user.user_sid) else: groupmembers[str(group)] = [user.user_sid] except passdb.error as e: logger.warn("Ignoring group memberships of '%s' %s: %s", username, user.user_sid, e) logger.info("Next rid = %d", next_rid) # Check for same username/groupname group_names = set([g.nt_name for g in grouplist]) user_names = set([u["account_name"] for u in userlist]) common_names = group_names.intersection(user_names) if common_names: logger.error("Following names are both user names and group names:") for name in common_names: logger.error(" %s" % name) raise ProvisioningError("Please remove common user/group names before upgrade.") # Check for same user sid/group sid group_sids = set([str(g.sid) for g in grouplist]) if len(grouplist) != len(group_sids): raise ProvisioningError("Please remove duplicate group sid entries before upgrade.") user_sids = set(["%s-%u" % (domainsid, u["rid"]) for u in userlist]) if len(userlist) != len(user_sids): raise ProvisioningError("Please remove duplicate user sid entries before upgrade.") common_sids = group_sids.intersection(user_sids) if common_sids: logger.error("Following sids are both user and group sids:") for sid in common_sids: logger.error(" %s" % str(sid)) raise ProvisioningError("Please remove duplicate sid entries before upgrade.") # Get posix attributes from ldap or the os homes = {} shells = {} pgids = {} if ldap: creds = Credentials() creds.guess(samba3.lp) creds.set_bind_dn(ldapuser) creds.set_password(ldappass) urls = samba3.lp.get("passdb backend").split(":", 1)[1].strip('"') for url in urls.split(): try: ldb_object = Ldb(url, credentials=creds) except ldb.LdbError as e: raise ProvisioningError("Could not open ldb connection to %s, the error message is: %s" % (url, e)) else: break logger.info("Exporting posix attributes") userlist = s3db.search_users(0) for entry in userlist: username = entry["account_name"] if username in uids.keys(): try: if ldap: homes[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "homeDirectory" ) else: homes[username] = pwd.getpwnam(username).pw_dir except KeyError: pass except IndexError: pass try: if ldap: shells[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "loginShell" ) else: shells[username] = pwd.getpwnam(username).pw_shell except KeyError: pass except IndexError: pass try: if ldap: pgids[username] = get_posix_attr_from_ldap_backend( logger, ldb_object, base_dn, username, "gidNumber" ) else: pgids[username] = pwd.getpwnam(username).pw_gid except KeyError: pass except IndexError: pass logger.info("Reading WINS database") samba3_winsdb = None try: samba3_winsdb = samba3.get_wins_db() except IOError as e: logger.warn("Cannot open wins database, Ignoring: %s", str(e)) if not (serverrole == "ROLE_DOMAIN_BDC" or serverrole == "ROLE_DOMAIN_PDC"): dns_backend = "NONE" # If we found an admin user, set a fake pw that we will override. # This avoids us printing out an admin password that we won't actually # set. if admin_user: adminpass = generate_random_password(12, 32) else: adminpass = None # Do full provision result = provision( logger, session_info, targetdir=targetdir, realm=realm, domain=domainname, domainsid=domainsid, next_rid=next_rid, dc_rid=machinerid, adminpass=adminpass, dom_for_fun_level=dsdb.DS_DOMAIN_FUNCTION_2003, hostname=netbiosname.lower(), machinepass=machinepass, serverrole=serverrole, samdb_fill=FILL_FULL, useeadb=useeadb, dns_backend=dns_backend, use_rfc2307=True, use_ntvfs=use_ntvfs, skip_sysvolacl=True, ) result.report_logger(logger) # Import WINS database logger.info("Importing WINS database") if samba3_winsdb: import_wins(Ldb(result.paths.winsdb), samba3_winsdb) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() logger.info("Adding groups") try: # Export groups to samba4 backend logger.info("Importing groups") for g in grouplist: # Ignore uninitialized groups (gid = -1) if g.gid != -1: add_group_from_mapping_entry(result.samdb, g, logger) add_ad_posix_idmap_entry(result.samdb, g.sid, g.gid, "ID_TYPE_GID", logger) add_posix_attrs( samdb=result.samdb, sid=g.sid, name=g.nt_name, nisdomain=domainname.lower(), xid_type="ID_TYPE_GID", logger=logger, ) except: # We need this, so that we do not give even more errors due to not cancelling the transaction result.samdb.transaction_cancel() raise logger.info("Committing 'add groups' transaction to disk") result.samdb.transaction_commit() logger.info("Adding users") # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() try: # Export users to samba4 backend logger.info("Importing users") for username in userdata: if username.lower() == "administrator": if userdata[username].user_sid != dom_sid(str(domainsid) + "-500"): logger.error( "User 'Administrator' in your existing directory has SID %s, expected it to be %s" % (userdata[username].user_sid, dom_sid(str(domainsid) + "-500")) ) raise ProvisioningError( "User 'Administrator' in your existing directory does not have SID ending in -500" ) if username.lower() == "root": if userdata[username].user_sid == dom_sid(str(domainsid) + "-500"): logger.warn("User root has been replaced by Administrator") else: logger.warn( "User root has been kept in the directory, it should be removed in favour of the Administrator user" ) s4_passdb.add_sam_account(userdata[username]) if username in uids: add_ad_posix_idmap_entry( result.samdb, userdata[username].user_sid, uids[username], "ID_TYPE_UID", logger ) if ( (username in homes) and (homes[username] is not None) and (username in shells) and (shells[username] is not None) and (username in pgids) and (pgids[username] is not None) ): 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, ) except: # We need this, so that we do not give even more errors due to not cancelling the transaction result.samdb.transaction_cancel() raise logger.info("Committing 'add users' transaction to disk") result.samdb.transaction_commit() logger.info("Adding users to groups") # Start a new transaction (should speed this up a little, due to index churn) result.samdb.transaction_start() try: for g in grouplist: if str(g.sid) in groupmembers: add_users_to_group(result.samdb, g, groupmembers[str(g.sid)], logger) except: # We need this, so that we do not give even more errors due to not cancelling the transaction result.samdb.transaction_cancel() raise logger.info("Committing 'add users to groups' transaction to disk") result.samdb.transaction_commit() # Set password for administrator if admin_user: logger.info("Setting password for administrator") admin_userdata = s4_passdb.getsampwnam("administrator") admin_userdata.nt_passwd = userdata[admin_user].nt_passwd if userdata[admin_user].lanman_passwd: admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd admin_userdata.pass_last_set_time = userdata[admin_user].pass_last_set_time if userdata[admin_user].pw_history: admin_userdata.pw_history = userdata[admin_user].pw_history s4_passdb.update_sam_account(admin_userdata) logger.info("Administrator password has been set to password of user '%s'", admin_user) if result.server_role == "active directory domain controller": setsysvolacl( result.samdb, result.paths.netlogon, result.paths.sysvol, result.paths.root_uid, result.paths.root_gid, security.dom_sid(result.domainsid), result.names.dnsdomain, result.names.domaindn, result.lp, use_ntvfs, )
def run(self, smbconf=None, targetdir=None, dbdir=None, testparm=None, quiet=False, verbose=False, use_xattrs=None, sambaopts=None, versionopts=None): if not os.path.exists(smbconf): raise CommandError("File %s does not exist" % smbconf) if testparm and not os.path.exists(testparm): raise CommandError("Testparm utility %s does not exist" % testparm) if dbdir and not os.path.exists(dbdir): raise CommandError("Directory %s does not exist" % dbdir) if not dbdir and not testparm: raise CommandError("Please specify either dbdir or testparm") logger = self.get_logger() if verbose: logger.setLevel(logging.DEBUG) elif quiet: logger.setLevel(logging.WARNING) else: logger.setLevel(logging.INFO) if dbdir and testparm: logger.warning("both dbdir and testparm specified, ignoring dbdir.") dbdir = None lp = sambaopts.get_loadparm() s3conf = s3param.get_context() if sambaopts.realm: s3conf.set("realm", sambaopts.realm) if targetdir is not None: if not os.path.isdir(targetdir): os.mkdir(targetdir) eadb = True if use_xattrs == "yes": eadb = False elif use_xattrs == "auto" and not s3conf.get("posix:eadb"): if targetdir: tmpfile = tempfile.NamedTemporaryFile(dir=os.path.abspath(targetdir)) else: tmpfile = tempfile.NamedTemporaryFile(dir=os.path.abspath(os.path.dirname(lp.get("private dir")))) try: try: samba.ntacls.setntacl(lp, tmpfile.name, "O:S-1-5-32G:S-1-5-32", "S-1-5-32", "native") eadb = False except Exception: # FIXME: Don't catch all exceptions here logger.info("You are not root or your system do not support xattr, using tdb backend for attributes. " "If you intend to use this provision in production, rerun the script as root on a system supporting xattrs.") finally: tmpfile.close() # Set correct default values from dbdir or testparm paths = {} if dbdir: paths["state directory"] = dbdir paths["private dir"] = dbdir paths["lock directory"] = dbdir else: paths["state directory"] = get_testparm_var(testparm, smbconf, "state directory") paths["private dir"] = get_testparm_var(testparm, smbconf, "private dir") paths["lock directory"] = get_testparm_var(testparm, smbconf, "lock directory") # "testparm" from Samba 3 < 3.4.x is not aware of the parameter # "state directory", instead make use of "lock directory" if len(paths["state directory"]) == 0: paths["state directory"] = paths["lock directory"] for p in paths: s3conf.set(p, paths[p]) # load smb.conf parameters logger.info("Reading smb.conf") s3conf.load(smbconf) samba3 = Samba3(smbconf, s3conf) logger.info("Provisioning") upgrade_from_samba3(samba3, logger, targetdir, session_info=system_session(), useeadb=eadb)
def upgrade_from_samba3(samba3, logger, targetdir, session_info=None): """Upgrade from samba3 database to samba4 AD database :param samba3: samba3 object :param logger: Logger object :param targetdir: samba4 database directory :param session_info: Session information """ if samba3.lp.get("domain logons"): serverrole = "domain controller" else: if samba3.lp.get("security") == "user": serverrole = "standalone" else: serverrole = "member server" domainname = samba3.lp.get("workgroup") realm = samba3.lp.get("realm") netbiosname = samba3.lp.get("netbios name") # secrets db secrets_db = samba3.get_secrets_db() if not domainname: domainname = secrets_db.domains()[0] logger.warning("No workgroup specified in smb.conf file, assuming '%s'", domainname) if not realm: if serverrole == "domain controller": logger.warning("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 (generally it's the upcased DNS domainname).") return else: realm = domainname.upper() logger.warning("No realm specified in smb.conf file, assuming '%s'", realm) # Find machine account and password machinepass = None machinerid = None machinesid = None next_rid = 1000 try: machinepass = secrets_db.get_machine_password(netbiosname) except: pass # We must close the direct pytdb database before the C code loads it secrets_db.close() # Connect to old password backend passdb.set_secrets_dir(samba3.lp.get("private dir")) s3db = samba3.get_sam_db() # Get domain sid try: domainsid = passdb.get_global_sam_sid() except passdb.error: raise Exception("Can't find domain sid for '%s', Exiting." % domainname) # Get machine account, sid, rid try: machineacct = s3db.getsampwnam('%s$' % netbiosname) machinesid, machinerid = machineacct.user_sid.split() except: pass # Export account policy logger.info("Exporting account policy") policy = s3db.get_account_policy() # Export groups from old passdb backend logger.info("Exporting groups") grouplist = s3db.enum_group_mapping() groupmembers = {} for group in grouplist: sid, rid = group.sid.split() if sid == domainsid: if rid >= next_rid: next_rid = rid + 1 # Get members for each group/alias if group.sid_name_use == lsa.SID_NAME_ALIAS: members = s3db.enum_aliasmem(group.sid) elif group.sid_name_use == lsa.SID_NAME_DOM_GRP: try: members = s3db.enum_group_members(group.sid) except: continue elif group.sid_name_use == lsa.SID_NAME_WKN_GRP: logger.warn("Ignoring 'well known' group '%s' (should already be in AD, and have no members)", group.nt_name, group.sid_name_use) continue else: logger.warn("Ignoring group '%s' with sid_name_use=%d", group.nt_name, group.sid_name_use) continue groupmembers[group.nt_name] = members # Export users from old passdb backend logger.info("Exporting users") userlist = s3db.search_users(0) userdata = {} uids = {} admin_user = None for entry in userlist: if machinerid and machinerid == entry['rid']: continue username = entry['account_name'] if entry['rid'] < 1000: logger.info(" Skipping wellknown rid=%d (for username=%s)", entry['rid'], username) continue if entry['rid'] >= next_rid: next_rid = entry['rid'] + 1 userdata[username] = s3db.getsampwnam(username) try: uids[username] = s3db.sid_to_id(userdata[username].user_sid)[0] except: try: uids[username] = pwd.getpwnam(username).pw_uid except: pass if not admin_user and username.lower() == 'root': admin_user = username if username.lower() == 'administrator': admin_user = username logger.info("Next rid = %d", next_rid) # Do full provision result = provision(logger, session_info, None, targetdir=targetdir, realm=realm, domain=domainname, domainsid=str(domainsid), next_rid=next_rid, dc_rid=machinerid, hostname=netbiosname, machinepass=machinepass, serverrole=serverrole, samdb_fill=FILL_FULL) # Import WINS database logger.info("Importing WINS database") import_wins(Ldb(result.paths.winsdb), samba3.get_wins_db()) # Set Account policy logger.info("Importing Account policy") import_sam_policy(result.samdb, policy, logger) # Migrate IDMAP database logger.info("Importing idmap database") import_idmap(result.idmap, samba3, logger) # Set the s3 context for samba4 configuration new_lp_ctx = s3param.get_context() new_lp_ctx.load(result.lp.configfile) new_lp_ctx.set("private dir", result.lp.get("private dir")) new_lp_ctx.set("state directory", result.lp.get("state directory")) new_lp_ctx.set("lock directory", result.lp.get("lock directory")) # Connect to samba4 backend s4_passdb = passdb.PDB(new_lp_ctx.get("passdb backend")) # Export groups to samba4 backend logger.info("Importing groups") for g in grouplist: # Ignore uninitialized groups (gid = -1) if g.gid != 0xffffffff: add_idmap_entry(result.idmap, g.sid, g.gid, "GID", logger) add_group_from_mapping_entry(result.samdb, g, logger) # Export users to samba4 backend logger.info("Importing users") for username in userdata: if username.lower() == 'administrator' or username.lower() == 'root': continue s4_passdb.add_sam_account(userdata[username]) if username in uids: add_idmap_entry(result.idmap, userdata[username].user_sid, uids[username], "UID", logger) logger.info("Adding users to groups") for g in grouplist: if g.nt_name in groupmembers: add_users_to_group(result.samdb, g, groupmembers[g.nt_name], logger) # Set password for administrator if admin_user: logger.info("Setting password for administrator") admin_userdata = s4_passdb.getsampwnam("administrator") admin_userdata.nt_passwd = userdata[admin_user].nt_passwd if userdata[admin_user].lanman_passwd: admin_userdata.lanman_passwd = userdata[admin_user].lanman_passwd admin_userdata.pass_last_set_time = userdata[admin_user].pass_last_set_time if userdata[admin_user].pw_history: admin_userdata.pw_history = userdata[admin_user].pw_history s4_passdb.update_sam_account(admin_userdata) logger.info("Administrator password has been set to password of user '%s'", admin_user)