summaryrefslogtreecommitdiff
path: root/source4
diff options
context:
space:
mode:
authorAndrew Bartlett <abartlet@samba.org>2012-08-02 16:15:27 +1000
committerAndrew Bartlett <abartlet@samba.org>2012-08-23 15:02:26 +0200
commita778662da8b1dfc65bde55644703f2a3146ef7a8 (patch)
treef82c688633b91dc884d817cd45d35eeed1015bea /source4
parent8518dd6406c0132dfd8c44e084c2b39792974f2c (diff)
downloadsamba-a778662da8b1dfc65bde55644703f2a3146ef7a8.tar.gz
samba-a778662da8b1dfc65bde55644703f2a3146ef7a8.tar.bz2
samba-a778662da8b1dfc65bde55644703f2a3146ef7a8.zip
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
Diffstat (limited to 'source4')
-rw-r--r--source4/scripting/python/samba/ntacls.py70
-rw-r--r--source4/scripting/python/samba/provision/__init__.py74
2 files changed, 92 insertions, 52 deletions
diff --git a/source4/scripting/python/samba/ntacls.py b/source4/scripting/python/samba/ntacls.py
index e3d24fa365..64dfd17d64 100644
--- a/source4/scripting/python/samba/ntacls.py
+++ b/source4/scripting/python/samba/ntacls.py
@@ -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):
diff --git a/source4/scripting/python/samba/provision/__init__.py b/source4/scripting/python/samba/provision/__init__.py
index 02ebf68310..fd71631ee7 100644
--- a/source4/scripting/python/samba/provision/__init__.py
+++ b/source4/scripting/python/samba/provision/__init__.py
@@ -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,