diff options
| author | Andrew Bartlett <abartlet@samba.org> | 2012-08-23 10:37:46 +1000 | 
|---|---|---|
| committer | Andrew Bartlett <abartlet@samba.org> | 2012-08-23 15:02:26 +0200 | 
| commit | ebcdc4a36be9b79325b11ec0c44a43db93e29519 (patch) | |
| tree | 6973d52f33386d3d55f4cd812e2985e3994e7e5f /source4/scripting/python | |
| parent | 0aed29105e9d8ddcd27a70d7af820da8813ca47b (diff) | |
| download | samba-ebcdc4a36be9b79325b11ec0c44a43db93e29519.tar.gz samba-ebcdc4a36be9b79325b11ec0c44a43db93e29519.tar.bz2 samba-ebcdc4a36be9b79325b11ec0c44a43db93e29519.zip | |
s4-samba-tool: Add samba-tool ntacl sysvolcheck command
This command verifies that the current on-disk ACLs match the directory and
the defaults from provision.
Unlike sysvolreset, this does not change any of the permissions.
Andrew Bartlett
Diffstat (limited to 'source4/scripting/python')
| -rw-r--r-- | source4/scripting/python/samba/netcmd/ntacl.py | 34 | ||||
| -rw-r--r-- | source4/scripting/python/samba/provision/__init__.py | 110 | 
2 files changed, 143 insertions, 1 deletions
| diff --git a/source4/scripting/python/samba/netcmd/ntacl.py b/source4/scripting/python/samba/netcmd/ntacl.py index 81217b76d6..4a0c91c289 100644 --- a/source4/scripting/python/samba/netcmd/ntacl.py +++ b/source4/scripting/python/samba/netcmd/ntacl.py @@ -179,6 +179,39 @@ class cmd_ntacl_sysvolreset(Command):                                 lp.get("realm").lower(), samdb.domain_dn(),                                  lp, use_ntvfs=use_ntvfs) +class cmd_ntacl_sysvolcheck(Command): +    """Check sysvol ACLs match defaults (including correct ACLs on GPOs)""" +    synopsis = "%prog <file> [options]" + +    takes_optiongroups = { +        "sambaopts": options.SambaOptions, +        "credopts": options.CredentialsOptions, +        "versionopts": options.VersionOptions, +        } + +    def run(self,  +            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, e: +            raise CommandError("Unable to open samdb:", e) + +        domain_sid = security.dom_sid(samdb.domain_sid) + +        provision.checksysvolacl(samdb, netlogon, sysvol, +                                 domain_sid,  +                                 lp.get("realm").lower(), samdb.domain_dn(),  +                                 lp) +  class cmd_ntacl(SuperCommand):      """NT ACLs manipulation""" @@ -187,4 +220,5 @@ class cmd_ntacl(SuperCommand):      subcommands["set"] = cmd_ntacl_set()      subcommands["get"] = cmd_ntacl_get()      subcommands["sysvolreset"] = cmd_ntacl_sysvolreset() +    subcommands["sysvolcheck"] = cmd_ntacl_sysvolcheck() diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py index 4762e5b162..ed46b4040d 100644 --- a/source4/scripting/python/samba/provision/__init__.py +++ b/source4/scripting/python/samba/provision/__init__.py @@ -69,7 +69,7 @@ from samba.dsdb import (      )  from samba.idmap import IDmapDB  from samba.ms_display_specifiers import read_ms_ldif -from samba.ntacls import setntacl, dsacl2fsacl +from samba.ntacls import setntacl, getntacl, dsacl2fsacl  from samba.ndr import ndr_pack, ndr_unpack  from samba.provision.backend import (      ExistingBackend, @@ -1455,6 +1455,114 @@ def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain, domain      # Set acls on Policy folder and policies folders      set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs) +def acl_type(direct_db_access): +    if direct_db_access: +        return "DB" +    else: +        return "VFS" + +def check_dir_acl(path, acl, lp, domainsid, direct_db_access): +    fsacl = getntacl(lp, path, direct_db_access=direct_db_access) +    fsacl_sddl = fsacl.as_sddl(domainsid) +    if fsacl_sddl != acl: +        raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), path, fsacl_sddl, acl)) +         +    for root, dirs, files in os.walk(path, topdown=False): +        for name in files: +            fsacl = getntacl(lp, os.path.join(root, name), direct_db_access=direct_db_access) +            if fsacl is None: +                raise ProvisioningError('%s ACL on GPO file %s %s not found!' % (acl_type(direct_db_access), os.path.join(root, name))) +            fsacl_sddl = fsacl.as_sddl(domainsid) +            if fsacl_sddl != acl: +                raise ProvisioningError('%s ACL on GPO file %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl, acl)) + +        for name in files: +            fsacl = getntacl(lp, os.path.join(root, name), direct_db_access=direct_db_access) +            if fsacl is None: +                raise ProvisioningError('%s ACL on GPO directory %s %s not found!' % (acl_type(direct_db_access), os.path.join(root, name))) +            fsacl_sddl = fsacl.as_sddl(domainsid) +            if fsacl_sddl != acl: +                raise ProvisioningError('%s ACL on GPO directory %s %s does not match expected value %s from GPO object' % (acl_type(direct_db_access), os.path.join(root, name), fsacl, acl)) + + +def check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, direct_db_access): +    """Set ACL on the sysvol/<dnsname>/Policies folder and the policy +    folders beneath. + +    :param sysvol: Physical path for the sysvol folder +    :param dnsdomain: The DNS name of the domain +    :param domainsid: The SID of the domain +    :param domaindn: The DN of the domain (ie. DC=...) +    :param samdb: An LDB object on the SAM db +    :param lp: an LP object +    """ + +    # Set ACL for GPO root folder +    root_policy_path = os.path.join(sysvol, dnsdomain, "Policies") +    fsacl = getntacl(lp, root_policy_path, direct_db_access=direct_db_access) +    if fsacl is None: +        raise ProvisioningError('DB ACL on policy root %s %s not found!' % (acl_type(direct_db_access), root_policy_path)) +    fsacl_sddl = fsacl.as_sddl(domainsid) +    if fsacl_sddl != POLICIES_ACL: +        raise ProvisioningError('%s ACL on policy root %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), policy_root, fsacl_sddl, acl)) +    res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn), +                        attrs=["cn", "nTSecurityDescriptor"], +                        expression="", scope=ldb.SCOPE_ONELEVEL) + +    for policy in res: +        acl = ndr_unpack(security.descriptor, +                         str(policy["nTSecurityDescriptor"])).as_sddl() +        policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"])) +        check_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp, +                      domainsid, direct_db_access) + + +def checksysvolacl(samdb, netlogon, sysvol, domainsid, dnsdomain, domaindn, +    lp): +    """Set the ACL for the sysvol share and the subfolders + +    :param samdb: An LDB object on the SAM db +    :param netlogon: Physical path for the netlogon folder +    :param sysvol: Physical path for the sysvol folder +    :param uid: The UID of the "Administrator" user +    :param gid: The GID of the "Domain adminstrators" group +    :param domainsid: The SID of the domain +    :param dnsdomain: The DNS name of the domain +    :param domaindn: The DN of the domain (ie. DC=...) +    """ + +    # This will ensure that the smbd code we are running when setting ACLs is initialised with the smb.conf +    s3conf = s3param.get_context() +    s3conf.load(lp.configfile) +    # ensure we are using the right samba4 passdb backend, no matter what +    s3conf.set("passdb backend", "samba4:%s" % samdb.url) +    # ensure that we init the samba4 backend, so the domain sid is marked in secrets.tdb +    s4_passdb = passdb.PDB(s3conf.get("passdb backend")) + +    # now ensure everything matches correctly, to avoid wierd issues +    if passdb.get_global_sam_sid() != domainsid: +        raise ProvisioningError('SID as seen by smbd [%s] does not match SID as seen by the provision script [%s]!' % (passdb.get_global_sam_sid(), domainsid)) + +    domain_info = s4_passdb.domain_info() +    if domain_info["dom_sid"] != domainsid: +        raise ProvisioningError('SID as seen by pdb_samba4 [%s] does not match SID as seen by the provision script [%s]!' % (domain_info["dom_sid"], domainsid)) + +    if domain_info["dns_domain"].upper() != dnsdomain.upper(): +        raise ProvisioningError('Realm as seen by pdb_samba4 [%s] does not match Realm as seen by the provision script [%s]!' % (domain_info["dns_domain"].upper(), dnsdomain.upper())) + +    # Set the SYSVOL_ACL on the sysvol folder and subfolder (first level) +    for direct_db_access in [True, False]: +        for dir_path in [os.path.join(sysvol, dnsdomain), netlogon]: +            fsacl = getntacl(lp, dir_path, direct_db_access=direct_db_access) +            if fsacl is None: +                raise ProvisioningError('%s ACL on sysvol directory %s not found!' % (acl_type(direct_db_access), dir_path)) +            fsacl_sddl = fsacl.as_sddl(domainsid) +            if fsacl_sddl != SYSVOL_ACL: +                raise ProvisioningError('%s ACL on sysvol directory %s %s does not match expected value %s from provision' % (acl_type(direct_db_access), dir_path, fsacl_sddl, SYSVOL_ACL)) + +        # Check acls on Policy folder and policies folders +        check_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, direct_db_access) +  def interface_ips_v4(lp):      '''return only IPv4 IPs''' | 
