2 Unix SMB/CIFS implementation.
4 POSIX NTVFS backend - ACL support
6 Copyright (C) Andrew Tridgell 2004
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
24 #include "auth/auth.h"
25 #include "system/filesys.h"
26 #include "vfs_posix.h"
27 #include "librpc/gen_ndr/ndr_xattr.h"
31 map a single access_mask from generic to specific bits for files/dirs
33 static uint32_t pvfs_translate_mask(uint32_t access_mask)
35 if (access_mask & SEC_MASK_GENERIC) {
36 if (access_mask & SEC_GENERIC_READ) access_mask |= SEC_RIGHTS_FILE_READ;
37 if (access_mask & SEC_GENERIC_WRITE) access_mask |= SEC_RIGHTS_FILE_WRITE;
38 if (access_mask & SEC_GENERIC_EXECUTE) access_mask |= SEC_RIGHTS_FILE_EXECUTE;
39 if (access_mask & SEC_GENERIC_ALL) access_mask |= SEC_RIGHTS_FILE_ALL;
40 access_mask &= ~SEC_MASK_GENERIC;
47 map any generic access bits in the given acl
48 this relies on the fact that the mappings for files and directories
51 static void pvfs_translate_generic_bits(struct security_acl *acl)
55 for (i=0;i<acl->num_aces;i++) {
56 struct security_ace *ace = &acl->aces[i];
57 ace->access_mask = pvfs_translate_mask(ace->access_mask);
63 setup a default ACL for a file
65 static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
66 struct smbsrv_request *req,
67 struct pvfs_filename *name, int fd,
68 struct xattr_NTACL *acl)
70 struct security_descriptor *sd;
72 struct security_ace ace;
75 sd = security_descriptor_initialise(req);
77 return NT_STATUS_NO_MEMORY;
80 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
81 if (!NT_STATUS_IS_OK(status)) {
84 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
85 if (!NT_STATUS_IS_OK(status)) {
89 sd->type |= SEC_DESC_DACL_PRESENT;
91 mode = name->st.st_mode;
94 we provide up to 4 ACEs
102 /* setup owner ACE */
103 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
105 ace.trustee = *sd->owner_sid;
108 if (mode & S_IRUSR) {
109 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
111 if (mode & S_IWUSR) {
112 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
114 if (ace.access_mask) {
115 security_descriptor_dacl_add(sd, &ace);
119 /* setup group ACE */
120 ace.trustee = *sd->group_sid;
122 if (mode & S_IRGRP) {
123 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
125 if (mode & S_IWGRP) {
126 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
128 if (ace.access_mask) {
129 security_descriptor_dacl_add(sd, &ace);
132 /* setup other ACE */
133 ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
135 if (mode & S_IROTH) {
136 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
138 if (mode & S_IWOTH) {
139 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
141 if (ace.access_mask) {
142 security_descriptor_dacl_add(sd, &ace);
145 /* setup system ACE */
146 ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
147 ace.access_mask = SEC_RIGHTS_FILE_ALL;
148 security_descriptor_dacl_add(sd, &ace);
158 omit any security_descriptor elements not specified in the given
161 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
163 if (!(secinfo_flags & SECINFO_OWNER)) {
164 sd->owner_sid = NULL;
166 if (!(secinfo_flags & SECINFO_GROUP)) {
167 sd->group_sid = NULL;
169 if (!(secinfo_flags & SECINFO_DACL)) {
172 if (!(secinfo_flags & SECINFO_SACL)) {
178 answer a setfileinfo for an ACL
180 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
181 struct smbsrv_request *req,
182 struct pvfs_filename *name, int fd,
183 union smb_setfileinfo *info)
185 struct xattr_NTACL *acl;
186 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
187 struct security_descriptor *new_sd, *sd;
190 acl = talloc_p(req, struct xattr_NTACL);
192 return NT_STATUS_NO_MEMORY;
195 status = pvfs_acl_load(pvfs, name, fd, acl);
196 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
197 status = pvfs_default_acl(pvfs, req, name, fd, acl);
199 if (!NT_STATUS_IS_OK(status)) {
203 switch (acl->version) {
208 return NT_STATUS_INVALID_ACL;
211 new_sd = info->set_secdesc.in.sd;
213 /* only set the elements that have been specified */
214 if (secinfo_flags & SECINFO_OWNER) {
215 sd->owner_sid = new_sd->owner_sid;
217 if (secinfo_flags & SECINFO_GROUP) {
218 sd->group_sid = new_sd->group_sid;
220 if (secinfo_flags & SECINFO_DACL) {
221 sd->dacl = new_sd->dacl;
222 pvfs_translate_generic_bits(sd->dacl);
224 if (secinfo_flags & SECINFO_SACL) {
225 sd->sacl = new_sd->sacl;
226 pvfs_translate_generic_bits(sd->sacl);
229 status = pvfs_acl_save(pvfs, name, fd, acl);
236 answer a fileinfo query for the ACL
238 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
239 struct smbsrv_request *req,
240 struct pvfs_filename *name, int fd,
241 union smb_fileinfo *info)
243 struct xattr_NTACL *acl;
245 struct security_descriptor *sd;
247 acl = talloc_p(req, struct xattr_NTACL);
249 return NT_STATUS_NO_MEMORY;
252 status = pvfs_acl_load(pvfs, name, fd, acl);
253 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
254 status = pvfs_default_acl(pvfs, req, name, fd, acl);
256 if (!NT_STATUS_IS_OK(status)) {
260 switch (acl->version) {
265 return NT_STATUS_INVALID_ACL;
268 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
270 info->query_secdesc.out.sd = sd;
277 default access check function based on unix permissions
278 doing this saves on building a full security descriptor
279 for the common case of access check on files with no
282 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
283 struct smbsrv_request *req,
284 struct pvfs_filename *name,
285 uint32_t *access_mask)
287 uid_t uid = geteuid();
288 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
290 /* owner and root get extra permissions */
291 if (uid == 0 || uid == name->st.st_uid) {
292 max_bits |= SEC_STD_ALL;
295 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
296 *access_mask = max_bits;
300 if (*access_mask & ~max_bits) {
301 return NT_STATUS_ACCESS_DENIED;
309 check the security descriptor on a file, if any
311 *access_mask is modified with the access actually granted
313 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
314 struct smbsrv_request *req,
315 struct pvfs_filename *name,
316 uint32_t *access_mask)
318 struct security_token *token = req->session->session_info->security_token;
319 struct xattr_NTACL *acl;
321 struct security_descriptor *sd;
323 acl = talloc_p(req, struct xattr_NTACL);
325 return NT_STATUS_NO_MEMORY;
328 status = pvfs_acl_load(pvfs, name, -1, acl);
329 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
331 return pvfs_access_check_unix(pvfs, req, name, access_mask);
333 if (!NT_STATUS_IS_OK(status)) {
337 switch (acl->version) {
342 return NT_STATUS_INVALID_ACL;
345 /* expand the generic access bits to file specific bits */
346 *access_mask = pvfs_translate_mask(*access_mask);
348 /* check the acl against the required access mask */
349 status = sec_access_check(sd, token, *access_mask, access_mask);
351 /* this bit is always granted, even if not asked for */
352 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
361 a simplified interface to access check, designed for calls that
362 do not take or return an access check mask
364 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
365 struct smbsrv_request *req,
366 struct pvfs_filename *name,
367 uint32_t access_needed)
369 return pvfs_access_check(pvfs, req, name, &access_needed);