summaryrefslogtreecommitdiff
path: root/source4/scripting/python/samba/ntacls.py
blob: 38c31c63c075d9aff02c22823a1233491452e017 (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
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
# 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
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):
    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
    else:
        return smbd.get_nt_acl(file, security.SECINFO_OWNER | security.SECINFO_GROUP | security.SECINFO_DACL | security.SECINFO_SACL)


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)

    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)


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, domsid):
    """
    
    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
    """
    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)