Example #1
0
File: ntacl.py Project: sYnfo/samba
    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")
Example #2
0
File: ntacl.py Project: sYnfo/samba
    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])
Example #4
0
    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))
Example #5
0
 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")
Example #6
0
    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))
Example #7
0
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
Example #8
0
 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")
Example #9
0
    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")
Example #10
0
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)
Example #11
0
    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")
Example #12
0
    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)
Example #13
0
 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
Example #14
0
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))
Example #15
0
    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)
Example #16
0
    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))
Example #17
0
    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)
Example #18
0
 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")
Example #19
0
    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")
Example #20
0
    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)
Example #21
0
 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
Example #22
0
    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")
Example #23
0
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")
Example #24
0
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))
Example #25
0
    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)
Example #26
0
    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")
Example #27
0
File: ntacl.py Project: sYnfo/samba
    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)
Example #28
0
    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)
Example #29
0
 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
Example #30
0
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))
Example #31
0
    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)
Example #32
0
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}
Example #33
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}
Example #34
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
Example #35
0
    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])
Example #36
0
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)
Example #37
0
    # 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",
Example #38
0
File: upgrade.py Project: hef/samba
    # 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")
Example #39
0
    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)
Example #40
0
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)
Example #41
0
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'
Example #42
0
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,
        )
Example #43
0
    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)
Example #44
0
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)