mirror of
https://github.com/samba-team/samba.git
synced 2025-03-27 22:50:26 +03:00
s4-provision: set POSIX ACLs to for use with the smbd file server (s3fs)
This handles the fact that smbd will rarely override the POSIX ACL enforced by the kernel. This has caused issues with the creation of group policies by other members of the Domain Admins group. Andrew Bartlett
This commit is contained in:
parent
8518dd6406
commit
a778662da8
@ -534,6 +534,7 @@ sub provision_raw_prepare($$$$$$$$$$)
|
||||
push (@provision_options, "--server-role=\"$ctx->{server_role}\"");
|
||||
push (@provision_options, "--function-level=\"$ctx->{functional_level}\"");
|
||||
push (@provision_options, "--dns-backend=BIND9_DLZ");
|
||||
|
||||
if ($use_ntvfs) {
|
||||
push (@provision_options, "--use-ntvfs");
|
||||
}
|
||||
@ -1205,7 +1206,7 @@ sub provision_fl2000dc($$)
|
||||
"samba2000.example.com",
|
||||
"2000",
|
||||
"locDCpass5",
|
||||
undef, "", 1);
|
||||
undef, "", "", 1);
|
||||
|
||||
unless($self->add_wins_config("$prefix/private")) {
|
||||
warn("Unable to add wins configuration");
|
||||
|
@ -23,6 +23,7 @@ import os
|
||||
import samba.xattr_native, samba.xattr_tdb, samba.posix_eadb
|
||||
from samba.dcerpc import security, xattr
|
||||
from samba.ndr import ndr_pack, ndr_unpack
|
||||
from samba.samba3 import smbd
|
||||
|
||||
class XattrBackendError(Exception):
|
||||
"""A generic xattr backend error."""
|
||||
@ -55,44 +56,51 @@ def checkset_backend(lp, backend, eadbfile):
|
||||
|
||||
|
||||
def getntacl(lp, file, backend=None, eadbfile=None):
|
||||
(backend_obj, dbname) = checkset_backend(lp, backend, eadbfile)
|
||||
if dbname is not None:
|
||||
try:
|
||||
attribute = backend_obj.wrap_getxattr(dbname, file,
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
except Exception:
|
||||
# FIXME: Don't catch all exceptions, just those related to opening
|
||||
# xattrdb
|
||||
print "Fail to open %s" % dbname
|
||||
if use_ntvfs:
|
||||
(backend_obj, dbname) = checkset_backend(lp, backend, eadbfile)
|
||||
if dbname is not None:
|
||||
try:
|
||||
attribute = backend_obj.wrap_getxattr(dbname, file,
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
except Exception:
|
||||
# FIXME: Don't catch all exceptions, just those related to opening
|
||||
# xattrdb
|
||||
print "Fail to open %s" % dbname
|
||||
attribute = samba.xattr_native.wrap_getxattr(file,
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
else:
|
||||
attribute = samba.xattr_native.wrap_getxattr(file,
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
ntacl = ndr_unpack(xattr.NTACL, attribute)
|
||||
return ntacl
|
||||
else:
|
||||
attribute = samba.xattr_native.wrap_getxattr(file,
|
||||
xattr.XATTR_NTACL_NAME)
|
||||
ntacl = ndr_unpack(xattr.NTACL, attribute)
|
||||
return ntacl
|
||||
return smbd.get_nt_acl(file)
|
||||
|
||||
|
||||
def setntacl(lp, file, sddl, domsid, backend=None, eadbfile=None):
|
||||
(backend_obj, dbname) = checkset_backend(lp, backend, eadbfile)
|
||||
ntacl = xattr.NTACL()
|
||||
ntacl.version = 1
|
||||
def setntacl(lp, file, sddl, domsid, backend=None, eadbfile=None, use_ntvfs=True):
|
||||
sid = security.dom_sid(domsid)
|
||||
sd = security.descriptor.from_sddl(sddl, sid)
|
||||
ntacl.info = sd
|
||||
if dbname is not None:
|
||||
try:
|
||||
backend_obj.wrap_setxattr(dbname,
|
||||
file, xattr.XATTR_NTACL_NAME, ndr_pack(ntacl))
|
||||
except Exception:
|
||||
# FIXME: Don't catch all exceptions, just those related to opening
|
||||
# xattrdb
|
||||
print "Fail to open %s" % dbname
|
||||
samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
|
||||
ndr_pack(ntacl))
|
||||
|
||||
if use_ntvfs:
|
||||
(backend_obj, dbname) = checkset_backend(lp, backend, eadbfile)
|
||||
ntacl = xattr.NTACL()
|
||||
ntacl.version = 1
|
||||
ntacl.info = sd
|
||||
if dbname is not None:
|
||||
try:
|
||||
backend_obj.wrap_setxattr(dbname,
|
||||
file, xattr.XATTR_NTACL_NAME, ndr_pack(ntacl))
|
||||
except Exception:
|
||||
# FIXME: Don't catch all exceptions, just those related to opening
|
||||
# xattrdb
|
||||
print "Fail to open %s" % dbname
|
||||
samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
|
||||
ndr_pack(ntacl))
|
||||
else:
|
||||
samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
|
||||
ndr_pack(ntacl))
|
||||
else:
|
||||
samba.xattr_native.wrap_setxattr(file, xattr.XATTR_NTACL_NAME,
|
||||
ndr_pack(ntacl))
|
||||
smbd.set_nt_acl(file, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL, sd)
|
||||
|
||||
|
||||
def ldapmask2filemask(ldm):
|
||||
|
@ -44,7 +44,8 @@ import ldb
|
||||
|
||||
from samba.auth import system_session, admin_session
|
||||
import samba
|
||||
from samba.samba3 import smbd
|
||||
from samba.samba3 import smbd, passdb
|
||||
from samba.samba3 import param as s3param
|
||||
from samba.dsdb import DS_DOMAIN_FUNCTION_2000
|
||||
from samba import (
|
||||
Ldb,
|
||||
@ -1359,16 +1360,16 @@ SYSVOL_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI
|
||||
POLICIES_ACL = "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)(A;OICI;0x001301bf;;;PA)"
|
||||
|
||||
|
||||
def set_dir_acl(path, acl, lp, domsid):
|
||||
setntacl(lp, path, acl, domsid)
|
||||
def set_dir_acl(path, acl, lp, domsid, use_ntvfs):
|
||||
setntacl(lp, path, acl, domsid, use_ntvfs=use_ntvfs)
|
||||
for root, dirs, files in os.walk(path, topdown=False):
|
||||
for name in files:
|
||||
setntacl(lp, os.path.join(root, name), acl, domsid)
|
||||
setntacl(lp, os.path.join(root, name), acl, domsid, use_ntvfs=use_ntvfs)
|
||||
for name in dirs:
|
||||
setntacl(lp, os.path.join(root, name), acl, domsid)
|
||||
setntacl(lp, os.path.join(root, name), acl, domsid, use_ntvfs=use_ntvfs)
|
||||
|
||||
|
||||
def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
|
||||
def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs):
|
||||
"""Set ACL on the sysvol/<dnsname>/Policies folder and the policy
|
||||
folders beneath.
|
||||
|
||||
@ -1382,7 +1383,7 @@ def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
|
||||
|
||||
# Set ACL for GPO root folder
|
||||
root_policy_path = os.path.join(sysvol, dnsdomain, "Policies")
|
||||
setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid))
|
||||
setntacl(lp, root_policy_path, POLICIES_ACL, str(domainsid), use_ntvfs=use_ntvfs)
|
||||
|
||||
res = samdb.search(base="CN=Policies,CN=System,%s"%(domaindn),
|
||||
attrs=["cn", "nTSecurityDescriptor"],
|
||||
@ -1393,11 +1394,11 @@ def set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp):
|
||||
str(policy["nTSecurityDescriptor"])).as_sddl()
|
||||
policy_path = getpolicypath(sysvol, dnsdomain, str(policy["cn"]))
|
||||
set_dir_acl(policy_path, dsacl2fsacl(acl, str(domainsid)), lp,
|
||||
str(domainsid))
|
||||
str(domainsid), use_ntvfs)
|
||||
|
||||
|
||||
def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
|
||||
lp):
|
||||
def setsysvolacl(samdb, netlogon, sysvol, uid, gid, domainsid, dnsdomain, domaindn,
|
||||
lp, use_ntvfs):
|
||||
"""Set the ACL for the sysvol share and the subfolders
|
||||
|
||||
:param samdb: An LDB object on the SAM db
|
||||
@ -1409,27 +1410,49 @@ def setsysvolacl(samdb, netlogon, sysvol, gid, domainsid, dnsdomain, domaindn,
|
||||
:param domaindn: The DN of the domain (ie. DC=...)
|
||||
"""
|
||||
|
||||
if not use_ntvfs:
|
||||
# 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()))
|
||||
|
||||
|
||||
try:
|
||||
os.chown(sysvol, -1, gid)
|
||||
if use_ntvfs:
|
||||
os.chown(sysvol, -1, gid)
|
||||
except OSError:
|
||||
canchown = False
|
||||
else:
|
||||
canchown = True
|
||||
|
||||
# Set the SYSVOL_ACL on the sysvol folder and subfolder (first level)
|
||||
setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid))
|
||||
setntacl(lp,sysvol, SYSVOL_ACL, str(domainsid), use_ntvfs=use_ntvfs)
|
||||
for root, dirs, files in os.walk(sysvol, topdown=False):
|
||||
for name in files:
|
||||
if canchown:
|
||||
if use_ntvfs and canchown:
|
||||
os.chown(os.path.join(root, name), -1, gid)
|
||||
setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
|
||||
setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid), use_ntvfs=use_ntvfs)
|
||||
for name in dirs:
|
||||
if canchown:
|
||||
if use_ntvfs and canchown:
|
||||
os.chown(os.path.join(root, name), -1, gid)
|
||||
setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid))
|
||||
setntacl(lp, os.path.join(root, name), SYSVOL_ACL, str(domainsid), use_ntvfs=use_ntvfs)
|
||||
|
||||
# Set acls on Policy folder and policies folders
|
||||
set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp)
|
||||
set_gpos_acl(sysvol, dnsdomain, domainsid, domaindn, samdb, lp, use_ntvfs)
|
||||
|
||||
|
||||
def interface_ips_v4(lp):
|
||||
@ -1460,7 +1483,7 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
|
||||
invocationid=None, machinepass=None, ntdsguid=None,
|
||||
dns_backend=None, dnspass=None,
|
||||
serverrole=None, dom_for_fun_level=None,
|
||||
am_rodc=False, lp=None):
|
||||
am_rodc=False, lp=None, use_ntvfs=False):
|
||||
# create/adapt the group policy GUIDs
|
||||
# Default GUID for default policy are described at
|
||||
# "How Core Group Policy Works"
|
||||
@ -1492,12 +1515,13 @@ def provision_fill(samdb, secrets_ldb, logger, names, paths,
|
||||
next_rid=next_rid, dc_rid=dc_rid)
|
||||
|
||||
if serverrole == "active directory domain controller":
|
||||
|
||||
# Set up group policies (domain policy and domain controller
|
||||
# policy)
|
||||
create_default_gpo(paths.sysvol, names.dnsdomain, policyguid,
|
||||
policyguid_dc)
|
||||
setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.wheel_gid,
|
||||
domainsid, names.dnsdomain, names.domaindn, lp)
|
||||
setsysvolacl(samdb, paths.netlogon, paths.sysvol, paths.root_uid, paths.wheel_gid,
|
||||
domainsid, names.dnsdomain, names.domaindn, lp, use_ntvfs)
|
||||
|
||||
secretsdb_self_join(secrets_ldb, domain=names.domain,
|
||||
realm=names.realm, dnsdomain=names.dnsdomain,
|
||||
@ -1719,6 +1743,7 @@ def provision(logger, session_info, credentials, smbconf=None,
|
||||
paths = provision_paths_from_lp(lp, names.dnsdomain)
|
||||
|
||||
paths.bind_gid = bind_gid
|
||||
paths.root_uid = root_uid;
|
||||
paths.wheel_gid = wheel_gid
|
||||
|
||||
if hostip is None:
|
||||
@ -1761,6 +1786,9 @@ def provision(logger, session_info, credentials, smbconf=None,
|
||||
os.makedirs(paths.sysvol, 0775)
|
||||
|
||||
if not use_ntvfs and serverrole == "active directory domain controller":
|
||||
s3conf = s3param.get_context()
|
||||
s3conf.load(lp.configfile)
|
||||
|
||||
if paths.sysvol is None:
|
||||
raise MissingShareError("sysvol", paths.smbconf)
|
||||
|
||||
@ -1776,6 +1804,10 @@ def provision(logger, session_info, credentials, smbconf=None,
|
||||
smbd.set_simple_acl(file.name, root_uid, wheel_gid)
|
||||
except Exception:
|
||||
raise ProvisioningError("Your filesystem or build does not support posix ACLs, which s3fs requires. Try the mounting the filesystem with the 'acl' option.")
|
||||
try:
|
||||
smbd.chown(file.name, root_uid, wheel_gid)
|
||||
except Exception:
|
||||
raise ProvisioningError("Unable to chown a file on your filesystem. You may not be running provision as root. ")
|
||||
finally:
|
||||
file.close()
|
||||
|
||||
@ -1871,7 +1903,7 @@ def provision(logger, session_info, credentials, smbconf=None,
|
||||
ntdsguid=ntdsguid, dns_backend=dns_backend,
|
||||
dnspass=dnspass, serverrole=serverrole,
|
||||
dom_for_fun_level=dom_for_fun_level, am_rodc=am_rodc,
|
||||
lp=lp)
|
||||
lp=lp, use_ntvfs=use_ntvfs)
|
||||
|
||||
create_krb5_conf(paths.krb5conf,
|
||||
dnsdomain=names.dnsdomain, hostname=names.hostname,
|
||||
|
Loading…
x
Reference in New Issue
Block a user