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 if (mode & S_IWUSR) {
110 ace.access_mask |= SEC_RIGHTS_FILE_ALL;
112 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
115 if (mode & S_IWUSR) {
116 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
118 if (ace.access_mask) {
119 security_descriptor_dacl_add(sd, &ace);
123 /* setup group ACE */
124 ace.trustee = *sd->group_sid;
126 if (mode & S_IRGRP) {
127 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
129 if (mode & S_IWGRP) {
130 /* note that delete is not granted - this matches posix behaviour */
131 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
133 if (ace.access_mask) {
134 security_descriptor_dacl_add(sd, &ace);
137 /* setup other ACE */
138 ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
140 if (mode & S_IROTH) {
141 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
143 if (mode & S_IWOTH) {
144 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
146 if (ace.access_mask) {
147 security_descriptor_dacl_add(sd, &ace);
150 /* setup system ACE */
151 ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
152 ace.access_mask = SEC_RIGHTS_FILE_ALL;
153 security_descriptor_dacl_add(sd, &ace);
163 omit any security_descriptor elements not specified in the given
166 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
168 if (!(secinfo_flags & SECINFO_OWNER)) {
169 sd->owner_sid = NULL;
171 if (!(secinfo_flags & SECINFO_GROUP)) {
172 sd->group_sid = NULL;
174 if (!(secinfo_flags & SECINFO_DACL)) {
177 if (!(secinfo_flags & SECINFO_SACL)) {
183 answer a setfileinfo for an ACL
185 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
186 struct smbsrv_request *req,
187 struct pvfs_filename *name, int fd,
188 union smb_setfileinfo *info)
190 struct xattr_NTACL *acl;
191 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
192 struct security_descriptor *new_sd, *sd;
195 acl = talloc_p(req, struct xattr_NTACL);
197 return NT_STATUS_NO_MEMORY;
200 status = pvfs_acl_load(pvfs, name, fd, acl);
201 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
202 status = pvfs_default_acl(pvfs, req, name, fd, acl);
204 if (!NT_STATUS_IS_OK(status)) {
208 switch (acl->version) {
213 return NT_STATUS_INVALID_ACL;
216 new_sd = info->set_secdesc.in.sd;
218 /* only set the elements that have been specified */
219 if (secinfo_flags & SECINFO_OWNER) {
220 sd->owner_sid = new_sd->owner_sid;
222 if (secinfo_flags & SECINFO_GROUP) {
223 sd->group_sid = new_sd->group_sid;
225 if (secinfo_flags & SECINFO_DACL) {
226 sd->dacl = new_sd->dacl;
227 pvfs_translate_generic_bits(sd->dacl);
229 if (secinfo_flags & SECINFO_SACL) {
230 sd->sacl = new_sd->sacl;
231 pvfs_translate_generic_bits(sd->sacl);
234 status = pvfs_acl_save(pvfs, name, fd, acl);
241 answer a fileinfo query for the ACL
243 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
244 struct smbsrv_request *req,
245 struct pvfs_filename *name, int fd,
246 union smb_fileinfo *info)
248 struct xattr_NTACL *acl;
250 struct security_descriptor *sd;
252 acl = talloc_p(req, struct xattr_NTACL);
254 return NT_STATUS_NO_MEMORY;
257 status = pvfs_acl_load(pvfs, name, fd, acl);
258 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
259 status = pvfs_default_acl(pvfs, req, name, fd, acl);
261 if (!NT_STATUS_IS_OK(status)) {
265 switch (acl->version) {
270 return NT_STATUS_INVALID_ACL;
273 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
275 info->query_secdesc.out.sd = sd;
282 default access check function based on unix permissions
283 doing this saves on building a full security descriptor
284 for the common case of access check on files with no
287 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
288 struct smbsrv_request *req,
289 struct pvfs_filename *name,
290 uint32_t *access_mask)
292 uid_t uid = geteuid();
293 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
295 /* owner and root get extra permissions */
296 if (uid == 0 || uid == name->st.st_uid) {
297 max_bits |= SEC_STD_ALL;
300 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
301 *access_mask = max_bits;
305 if (*access_mask & ~max_bits) {
306 return NT_STATUS_ACCESS_DENIED;
314 check the security descriptor on a file, if any
316 *access_mask is modified with the access actually granted
318 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
319 struct smbsrv_request *req,
320 struct pvfs_filename *name,
321 uint32_t *access_mask)
323 struct security_token *token = req->session->session_info->security_token;
324 struct xattr_NTACL *acl;
326 struct security_descriptor *sd;
328 acl = talloc_p(req, struct xattr_NTACL);
330 return NT_STATUS_NO_MEMORY;
333 status = pvfs_acl_load(pvfs, name, -1, acl);
334 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
336 return pvfs_access_check_unix(pvfs, req, name, access_mask);
338 if (!NT_STATUS_IS_OK(status)) {
342 switch (acl->version) {
347 return NT_STATUS_INVALID_ACL;
350 /* expand the generic access bits to file specific bits */
351 *access_mask = pvfs_translate_mask(*access_mask);
353 /* check the acl against the required access mask */
354 status = sec_access_check(sd, token, *access_mask, access_mask);
356 /* this bit is always granted, even if not asked for */
357 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
366 a simplified interface to access check, designed for calls that
367 do not take or return an access check mask
369 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
370 struct smbsrv_request *req,
371 struct pvfs_filename *name,
372 uint32_t access_needed)
374 if (access_needed == 0) {
377 return pvfs_access_check(pvfs, req, name, &access_needed);
381 access check for creating a new file/directory
383 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
384 struct smbsrv_request *req,
385 struct pvfs_filename *name)
387 struct pvfs_filename *parent;
390 status = pvfs_resolve_parent(pvfs, req, name, &parent);
391 if (!NT_STATUS_IS_OK(status)) {
395 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
400 determine if an ACE is inheritable
402 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
403 const struct security_ace *ace,
407 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
410 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
414 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
415 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
423 this is the core of ACL inheritance. It copies any inheritable
424 aces from the parent SD to the child SD. Note that the algorithm
425 depends on whether the child is a container or not
427 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
428 struct security_descriptor *parent_sd,
429 struct security_descriptor *sd,
434 for (i=0;i<parent_sd->dacl->num_aces;i++) {
435 struct security_ace ace = parent_sd->dacl->aces[i];
438 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
442 /* see the RAW-ACLS inheritance test for details on these rules */
446 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
448 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
449 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
451 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
456 status = security_descriptor_dacl_add(sd, &ace);
457 if (!NT_STATUS_IS_OK(status)) {
468 setup an ACL on a new file/directory based on the inherited ACL from
469 the parent. If there is no inherited ACL then we don't set anything,
470 as the default ACL applies anyway
472 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
473 struct smbsrv_request *req,
474 struct pvfs_filename *name,
477 struct xattr_NTACL *acl;
479 struct pvfs_filename *parent;
480 struct security_descriptor *parent_sd, *sd;
483 /* form the parents path */
484 status = pvfs_resolve_parent(pvfs, req, name, &parent);
485 if (!NT_STATUS_IS_OK(status)) {
489 acl = talloc_p(req, struct xattr_NTACL);
491 return NT_STATUS_NO_MEMORY;
494 status = pvfs_acl_load(pvfs, parent, -1, acl);
495 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
498 if (!NT_STATUS_IS_OK(status)) {
502 switch (acl->version) {
504 parent_sd = acl->info.sd;
507 return NT_STATUS_INVALID_ACL;
510 if (parent_sd == NULL ||
511 parent_sd->dacl == NULL ||
512 parent_sd->dacl->num_aces == 0) {
513 /* go with the default ACL */
517 /* create the new sd */
518 sd = security_descriptor_initialise(req);
520 return NT_STATUS_NO_MEMORY;
523 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
524 if (!NT_STATUS_IS_OK(status)) {
527 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
528 if (!NT_STATUS_IS_OK(status)) {
532 sd->type |= SEC_DESC_DACL_PRESENT;
534 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
536 /* fill in the aces from the parent */
537 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
538 if (!NT_STATUS_IS_OK(status)) {
542 /* if there is nothing to inherit then we fallback to the
544 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
550 status = pvfs_acl_save(pvfs, name, fd, acl);