summaryrefslogtreecommitdiffstats
path: root/source4/scripting/python/samba/ntacls.py
blob: 66af5d5336eea9ff7bf97b93c2459e7f5d09a354 (plain)
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
#!/usr/bin/python

# 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/>.
#

import os
import tdb
import samba.xattr_native, samba.xattr_tdb
from samba.dcerpc import security, xattr
from samba.ndr import ndr_pack, ndr_unpack
class XattrBackendError(Exception):
    """A generic xattr backend error."""

def checkset_backend(lp,backend,eadbfile):
	if backend != None:
		if backend == "native":
			lp.set("posix:eadb","")
		elif backend == "tdb":
			if eadbfile != None:
				lp.set("posix:eadb",eadbfile)
			else:
				os.path.abspath(os.path.join(lp.get("private dir"),"eadb.tdb"))
		else:
			raise XattrBackendError("Unvalid xattr backend choice %s"%backend)

def getntacl(lp,file,backend=None,eadbfile=None):
	try:
		checkset_backend(lp,backend,eadbfile)
	except:
		raise
	eadbname = lp.get("posix:eadb")
	if eadbname != None and eadbname != "" :
		try:
			attribute = samba.xattr_tdb.wrap_getxattr(eadbname,file,xattr.XATTR_NTACL_NAME)
		except:
			print "Fail to open %s"%eadbname
			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)
	return ntacl

def setntacl(lp,file,sddl,domsid,backend=None,eadbfile=None):
	try:
		checkset_backend(lp,backend,eadbfile)
	except:
		raise
	ntacl=xattr.NTACL()
	ntacl.version = 1
	sid=security.dom_sid(domsid)
	sd = security.descriptor.from_sddl(sddl, sid)
	ntacl.info = sd
	eadbname = lp.get("posix:eadb")
	if eadbname != None  and eadbname != "":
		try:
			attribute = samba.xattr_tdb.wrap_setxattr(eadbname,file,xattr.XATTR_NTACL_NAME,ndr_pack(ntacl))
		except:
			print "Fail to open %s"%eadbname
			attribute = samba.xattr_native.wrap_setxattr(file,xattr.XATTR_NTACL_NAME,ndr_pack(ntacl))
	else:
		attribute = samba.xattr_native.wrap_setxattr(file,xattr.XATTR_NTACL_NAME,ndr_pack(ntacl))

# Takes the access mask of a DS ACE and transform them in a File ACE mask
def ldapmask2filemask(ldm):
	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
	#filemask = 0

	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

# 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

def dsacl2fsacl(dssddl,domsid):
	sid = security.dom_sid(domsid)
	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
	fdescr.sacl = ref.sacl
	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)

	return fdescr.as_sddl(sid)