1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
|
# Unix SMB/CIFS implementation.
# Copyright (C) Matthieu Patou <mat@matws.net> 2009-2010
#
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
"""NT Acls."""
import os
import samba.xattr_native, samba.xattr_tdb, samba.posix_eadb
from samba.dcerpc import security, xattr, idmap
from samba.ndr import ndr_pack, ndr_unpack
from samba.samba3 import smbd
class XattrBackendError(Exception):
"""A generic xattr backend error."""
def checkset_backend(lp, backend, eadbfile):
'''return the path to the eadb, or None'''
if backend is None:
xattr_tdb = lp.get("xattr_tdb:file")
if xattr_tdb is not None:
return (samba.xattr_tdb, lp.get("xattr_tdb:file"))
posix_eadb = lp.get("posix:eadb")
if posix_eadb is not None:
return (samba.posix_eadb, lp.get("posix:eadb"))
return (None, None)
elif backend == "native":
return (None, None)
elif backend == "eadb":
if eadbfile is not None:
return (samba.posix_eadb, eadbfile)
else:
return (samba.posix_eadb, os.path.abspath(os.path.join(lp.get("private dir"), "eadb.tdb")))
elif backend == "tdb":
if eadbfile is not None:
return (samba.xattr_tdb, eadbfile)
else:
return (samba.xattr_tdb, os.path.abspath(os.path.join(lp.get("state dir"), "xattr.tdb")))
else:
raise XattrBackendError("Invalid xattr backend choice %s"%backend)
def getntacl(lp, file, backend=None, eadbfile=None, direct_db_access=True, service=None):
if direct_db_access:
(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)
ntacl = ndr_unpack(xattr.NTACL, attribute)
if ntacl.version == 1:
return ntacl.info
elif ntacl.version == 2:
return ntacl.info.sd
elif ntacl.version == 3:
return ntacl.info.sd
elif ntacl.version == 4:
return ntacl.info.sd
else:
return smbd.get_nt_acl(file, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, service=service)
def setntacl(lp, file, sddl, domsid, backend=None, eadbfile=None, use_ntvfs=True, skip_invalid_chown=False, passdb=None, service=None):
assert(isinstance(domsid, str) or isinstance(domsid, security.dom_sid))
if isinstance(domsid, str):
sid = security.dom_sid(domsid)
elif isinstance(domsid, security.dom_sid):
sid = domsid
domsid = str(sid)
assert(isinstance(sddl, str) or isinstance(sddl, security.descriptor))
if isinstance(sddl, str):
sd = security.descriptor.from_sddl(sddl, sid)
elif isinstance(sddl, security.descriptor):
sd = sddl
sddl = sd.as_sddl(sid)
if not use_ntvfs and skip_invalid_chown:
# Check if the owner can be resolved as a UID
(owner_id, owner_type) = passdb.sid_to_id(sd.owner_sid)
if ((owner_type != idmap.ID_TYPE_UID) and (owner_type != idmap.ID_TYPE_BOTH)):
# Check if this particular owner SID was domain admins,
# because we special-case this as mapping to
# 'administrator' instead.
if sd.owner_sid == security.dom_sid("%s-%d" % (domsid, security.DOMAIN_RID_ADMINS)):
administrator = security.dom_sid("%s-%d" % (domsid, security.DOMAIN_RID_ADMINISTRATOR))
(admin_id, admin_type) = passdb.sid_to_id(administrator)
# Confirm we have a UID for administrator
if ((admin_type == idmap.ID_TYPE_UID) or (admin_type == idmap.ID_TYPE_BOTH)):
# Set it, changing the owner to 'administrator' rather than domain admins
sd2 = sd
sd2.owner_sid = administrator
smbd.set_nt_acl(file, security.SECINFO_OWNER |security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, sd2, service=service)
# and then set an NTVFS ACL (which does not set the posix ACL) to pretend the owner really was set
use_ntvfs = True
else:
raise XattrBackendError("Unable to find UID for domain administrator %s, got id %d of type %d" % (administrator, admin_id, admin_type))
else:
# For all other owning users, reset the owner to root
# and then set the ACL without changing the owner
#
# This won't work in test environments, as it tries a real (rather than xattr-based fake) chown
os.chown(file, 0, 0)
smbd.set_nt_acl(file, security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, sd, service=service)
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:
smbd.set_nt_acl(file, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL, sd, service=service)
def ldapmask2filemask(ldm):
"""Takes the access mask of a DS ACE and transform them in a File ACE mask.
"""
RIGHT_DS_CREATE_CHILD = 0x00000001
RIGHT_DS_DELETE_CHILD = 0x00000002
RIGHT_DS_LIST_CONTENTS = 0x00000004
ACTRL_DS_SELF = 0x00000008
RIGHT_DS_READ_PROPERTY = 0x00000010
RIGHT_DS_WRITE_PROPERTY = 0x00000020
RIGHT_DS_DELETE_TREE = 0x00000040
RIGHT_DS_LIST_OBJECT = 0x00000080
RIGHT_DS_CONTROL_ACCESS = 0x00000100
FILE_READ_DATA = 0x0001
FILE_LIST_DIRECTORY = 0x0001
FILE_WRITE_DATA = 0x0002
FILE_ADD_FILE = 0x0002
FILE_APPEND_DATA = 0x0004
FILE_ADD_SUBDIRECTORY = 0x0004
FILE_CREATE_PIPE_INSTANCE = 0x0004
FILE_READ_EA = 0x0008
FILE_WRITE_EA = 0x0010
FILE_EXECUTE = 0x0020
FILE_TRAVERSE = 0x0020
FILE_DELETE_CHILD = 0x0040
FILE_READ_ATTRIBUTES = 0x0080
FILE_WRITE_ATTRIBUTES = 0x0100
DELETE = 0x00010000
READ_CONTROL = 0x00020000
WRITE_DAC = 0x00040000
WRITE_OWNER = 0x00080000
SYNCHRONIZE = 0x00100000
STANDARD_RIGHTS_ALL = 0x001F0000
filemask = ldm & STANDARD_RIGHTS_ALL
if (ldm & RIGHT_DS_READ_PROPERTY) and (ldm & RIGHT_DS_LIST_CONTENTS):
filemask = filemask | (SYNCHRONIZE | FILE_LIST_DIRECTORY |
FILE_READ_ATTRIBUTES | FILE_READ_EA |
FILE_READ_DATA | FILE_EXECUTE)
if ldm & RIGHT_DS_WRITE_PROPERTY:
filemask = filemask | (SYNCHRONIZE | FILE_WRITE_DATA |
FILE_APPEND_DATA | FILE_WRITE_EA |
FILE_WRITE_ATTRIBUTES | FILE_ADD_FILE |
FILE_ADD_SUBDIRECTORY)
if ldm & RIGHT_DS_CREATE_CHILD:
filemask = filemask | (FILE_ADD_SUBDIRECTORY | FILE_ADD_FILE)
if ldm & RIGHT_DS_DELETE_CHILD:
filemask = filemask | FILE_DELETE_CHILD
return filemask
def dsacl2fsacl(dssddl, sid, as_sddl=True):
"""
This function takes an the SDDL representation of a DS
ACL and return the SDDL representation of this ACL adapted
for files. It's used for Policy object provision
"""
ref = security.descriptor.from_sddl(dssddl, sid)
fdescr = security.descriptor()
fdescr.owner_sid = ref.owner_sid
fdescr.group_sid = ref.group_sid
fdescr.type = ref.type
fdescr.revision = ref.revision
aces = ref.dacl.aces
for i in range(0, len(aces)):
ace = aces[i]
if not ace.type & security.SEC_ACE_TYPE_ACCESS_ALLOWED_OBJECT and str(ace.trustee) != security.SID_BUILTIN_PREW2K:
# if fdescr.type & security.SEC_DESC_DACL_AUTO_INHERITED:
ace.flags = ace.flags | security.SEC_ACE_FLAG_OBJECT_INHERIT | security.SEC_ACE_FLAG_CONTAINER_INHERIT
if str(ace.trustee) == security.SID_CREATOR_OWNER:
# For Creator/Owner the IO flag is set as this ACE has only a sense for child objects
ace.flags = ace.flags | security.SEC_ACE_FLAG_INHERIT_ONLY
ace.access_mask = ldapmask2filemask(ace.access_mask)
fdescr.dacl_add(ace)
if not as_sddl:
return fdescr
return fdescr.as_sddl(sid)
|