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 "vfs_posix.h"
26 #include "librpc/gen_ndr/xattr.h"
27 #include "libcli/security/security.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)
57 for (i=0;i<acl->num_aces;i++) {
58 struct security_ace *ace = &acl->aces[i];
59 ace->access_mask = pvfs_translate_mask(ace->access_mask);
65 setup a default ACL for a file
67 static NTSTATUS pvfs_default_acl(struct pvfs_state *pvfs,
68 struct ntvfs_request *req,
69 struct pvfs_filename *name, int fd,
70 struct xattr_NTACL *acl)
72 struct security_descriptor *sd;
74 struct security_ace ace;
77 sd = security_descriptor_initialise(req);
79 return NT_STATUS_NO_MEMORY;
82 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
83 if (!NT_STATUS_IS_OK(status)) {
86 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
87 if (!NT_STATUS_IS_OK(status)) {
91 sd->type |= SEC_DESC_DACL_PRESENT;
93 mode = name->st.st_mode;
96 we provide up to 4 ACEs
104 /* setup owner ACE */
105 ace.type = SEC_ACE_TYPE_ACCESS_ALLOWED;
107 ace.trustee = *sd->owner_sid;
110 if (mode & S_IRUSR) {
111 if (mode & S_IWUSR) {
112 ace.access_mask |= SEC_RIGHTS_FILE_ALL;
114 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
117 if (mode & S_IWUSR) {
118 ace.access_mask |= SEC_RIGHTS_FILE_WRITE | SEC_STD_DELETE;
120 if (ace.access_mask) {
121 security_descriptor_dacl_add(sd, &ace);
125 /* setup group ACE */
126 ace.trustee = *sd->group_sid;
128 if (mode & S_IRGRP) {
129 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
131 if (mode & S_IWGRP) {
132 /* note that delete is not granted - this matches posix behaviour */
133 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
135 if (ace.access_mask) {
136 security_descriptor_dacl_add(sd, &ace);
139 /* setup other ACE */
140 ace.trustee = *dom_sid_parse_talloc(req, SID_WORLD);
142 if (mode & S_IROTH) {
143 ace.access_mask |= SEC_RIGHTS_FILE_READ | SEC_FILE_EXECUTE;
145 if (mode & S_IWOTH) {
146 ace.access_mask |= SEC_RIGHTS_FILE_WRITE;
148 if (ace.access_mask) {
149 security_descriptor_dacl_add(sd, &ace);
152 /* setup system ACE */
153 ace.trustee = *dom_sid_parse_talloc(req, SID_NT_SYSTEM);
154 ace.access_mask = SEC_RIGHTS_FILE_ALL;
155 security_descriptor_dacl_add(sd, &ace);
165 omit any security_descriptor elements not specified in the given
168 static void normalise_sd_flags(struct security_descriptor *sd, uint32_t secinfo_flags)
170 if (!(secinfo_flags & SECINFO_OWNER)) {
171 sd->owner_sid = NULL;
173 if (!(secinfo_flags & SECINFO_GROUP)) {
174 sd->group_sid = NULL;
176 if (!(secinfo_flags & SECINFO_DACL)) {
179 if (!(secinfo_flags & SECINFO_SACL)) {
185 answer a setfileinfo for an ACL
187 NTSTATUS pvfs_acl_set(struct pvfs_state *pvfs,
188 struct ntvfs_request *req,
189 struct pvfs_filename *name, int fd,
190 uint32_t access_mask,
191 union smb_setfileinfo *info)
193 struct xattr_NTACL *acl;
194 uint32_t secinfo_flags = info->set_secdesc.in.secinfo_flags;
195 struct security_descriptor *new_sd, *sd, orig_sd;
202 acl = talloc(req, struct xattr_NTACL);
204 return NT_STATUS_NO_MEMORY;
207 status = pvfs_acl_load(pvfs, name, fd, acl);
208 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
209 status = pvfs_default_acl(pvfs, req, name, fd, acl);
211 if (!NT_STATUS_IS_OK(status)) {
215 switch (acl->version) {
220 return NT_STATUS_INVALID_ACL;
223 new_sd = info->set_secdesc.in.sd;
226 old_uid = name->st.st_uid;
227 old_gid = name->st.st_gid;
229 /* only set the elements that have been specified */
230 if (secinfo_flags & SECINFO_OWNER) {
231 if (!(access_mask & SEC_STD_WRITE_OWNER)) {
232 return NT_STATUS_ACCESS_DENIED;
234 if (!dom_sid_equal(sd->owner_sid, new_sd->owner_sid)) {
235 status = sidmap_sid_to_unixuid(pvfs->sidmap, new_sd->owner_sid, &new_uid);
236 NT_STATUS_NOT_OK_RETURN(status);
238 sd->owner_sid = new_sd->owner_sid;
240 if (secinfo_flags & SECINFO_GROUP) {
241 if (!(access_mask & SEC_STD_WRITE_OWNER)) {
242 return NT_STATUS_ACCESS_DENIED;
244 if (!dom_sid_equal(sd->group_sid, new_sd->group_sid)) {
245 status = sidmap_sid_to_unixgid(pvfs->sidmap, new_sd->group_sid, &new_gid);
246 NT_STATUS_NOT_OK_RETURN(status);
248 sd->group_sid = new_sd->group_sid;
250 if (secinfo_flags & SECINFO_DACL) {
251 if (!(access_mask & SEC_STD_WRITE_DAC)) {
252 return NT_STATUS_ACCESS_DENIED;
254 sd->dacl = new_sd->dacl;
255 pvfs_translate_generic_bits(sd->dacl);
257 if (secinfo_flags & SECINFO_SACL) {
258 if (!(access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
259 return NT_STATUS_ACCESS_DENIED;
261 sd->sacl = new_sd->sacl;
262 pvfs_translate_generic_bits(sd->sacl);
265 if (new_uid == old_uid) {
269 if (new_gid == old_gid) {
273 /* if there's something to change try it */
274 if (new_uid != -1 || new_gid != -1) {
277 ret = chown(name->full_name, new_uid, new_gid);
279 ret = fchown(fd, new_uid, new_gid);
282 return pvfs_map_errno(pvfs, errno);
286 /* we avoid saving if the sd is the same. This means when clients
287 copy files and end up copying the default sd that we don't
288 needlessly use xattrs */
289 if (!security_descriptor_equal(sd, &orig_sd)) {
290 status = pvfs_acl_save(pvfs, name, fd, acl);
298 answer a fileinfo query for the ACL
300 NTSTATUS pvfs_acl_query(struct pvfs_state *pvfs,
301 struct ntvfs_request *req,
302 struct pvfs_filename *name, int fd,
303 union smb_fileinfo *info)
305 struct xattr_NTACL *acl;
307 struct security_descriptor *sd;
309 acl = talloc(req, struct xattr_NTACL);
311 return NT_STATUS_NO_MEMORY;
314 status = pvfs_acl_load(pvfs, name, fd, acl);
315 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
316 status = pvfs_default_acl(pvfs, req, name, fd, acl);
318 if (!NT_STATUS_IS_OK(status)) {
322 switch (acl->version) {
327 return NT_STATUS_INVALID_ACL;
330 normalise_sd_flags(sd, info->query_secdesc.in.secinfo_flags);
332 info->query_secdesc.out.sd = sd;
339 default access check function based on unix permissions
340 doing this saves on building a full security descriptor
341 for the common case of access check on files with no
344 NTSTATUS pvfs_access_check_unix(struct pvfs_state *pvfs,
345 struct ntvfs_request *req,
346 struct pvfs_filename *name,
347 uint32_t *access_mask)
349 uid_t uid = geteuid();
350 uint32_t max_bits = SEC_RIGHTS_FILE_READ | SEC_FILE_ALL;
352 if ((pvfs->flags & PVFS_FLAG_READONLY) &&
353 ((*access_mask) & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
354 SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
355 SEC_DIR_DELETE_CHILD))) {
356 return NT_STATUS_ACCESS_DENIED;
359 /* owner and root get extra permissions */
361 max_bits |= SEC_STD_ALL | SEC_FLAG_SYSTEM_SECURITY;
362 } else if (uid == name->st.st_uid) {
363 max_bits |= SEC_STD_ALL;
366 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
367 *access_mask = max_bits;
371 if (uid != 0 && (*access_mask & SEC_FLAG_SYSTEM_SECURITY)) {
372 return NT_STATUS_PRIVILEGE_NOT_HELD;
375 if (*access_mask & ~max_bits) {
376 return NT_STATUS_ACCESS_DENIED;
379 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
386 check the security descriptor on a file, if any
388 *access_mask is modified with the access actually granted
390 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
391 struct ntvfs_request *req,
392 struct pvfs_filename *name,
393 uint32_t *access_mask)
395 struct security_token *token = req->session_info->security_token;
396 struct xattr_NTACL *acl;
398 struct security_descriptor *sd;
400 if ((pvfs->flags & PVFS_FLAG_READONLY) &&
401 ((*access_mask) & (SEC_FILE_WRITE_DATA | SEC_FILE_APPEND_DATA |
402 SEC_FILE_WRITE_EA | SEC_FILE_WRITE_ATTRIBUTE |
403 SEC_DIR_DELETE_CHILD))) {
404 return NT_STATUS_ACCESS_DENIED;
407 acl = talloc(req, struct xattr_NTACL);
409 return NT_STATUS_NO_MEMORY;
412 /* expand the generic access bits to file specific bits */
413 *access_mask = pvfs_translate_mask(*access_mask);
414 *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
416 status = pvfs_acl_load(pvfs, name, -1, acl);
417 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
419 return pvfs_access_check_unix(pvfs, req, name, access_mask);
421 if (!NT_STATUS_IS_OK(status)) {
425 switch (acl->version) {
430 return NT_STATUS_INVALID_ACL;
433 /* check the acl against the required access mask */
434 status = sec_access_check(sd, token, *access_mask, access_mask);
436 /* this bit is always granted, even if not asked for */
437 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
446 a simplified interface to access check, designed for calls that
447 do not take or return an access check mask
449 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
450 struct ntvfs_request *req,
451 struct pvfs_filename *name,
452 uint32_t access_needed)
454 if (access_needed == 0) {
457 return pvfs_access_check(pvfs, req, name, &access_needed);
461 access check for creating a new file/directory
463 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
464 struct ntvfs_request *req,
465 struct pvfs_filename *name,
466 uint32_t *access_mask)
468 struct pvfs_filename *parent;
471 status = pvfs_resolve_parent(pvfs, req, name, &parent);
472 if (!NT_STATUS_IS_OK(status)) {
476 status = pvfs_access_check(pvfs, req, parent, access_mask);
477 if (!NT_STATUS_IS_OK(status)) {
481 if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
482 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
489 access check for creating a new file/directory - no access mask supplied
491 NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs,
492 struct ntvfs_request *req,
493 struct pvfs_filename *name,
494 uint32_t access_mask)
496 struct pvfs_filename *parent;
499 status = pvfs_resolve_parent(pvfs, req, name, &parent);
500 if (!NT_STATUS_IS_OK(status)) {
504 return pvfs_access_check_simple(pvfs, req, parent, access_mask);
509 determine if an ACE is inheritable
511 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
512 const struct security_ace *ace,
516 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
519 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
523 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
524 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
532 this is the core of ACL inheritance. It copies any inheritable
533 aces from the parent SD to the child SD. Note that the algorithm
534 depends on whether the child is a container or not
536 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
537 struct security_descriptor *parent_sd,
538 struct security_descriptor *sd,
543 for (i=0;i<parent_sd->dacl->num_aces;i++) {
544 struct security_ace ace = parent_sd->dacl->aces[i];
546 const struct dom_sid *creator = NULL, *new_id = NULL;
549 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
553 orig_flags = ace.flags;
555 /* see the RAW-ACLS inheritance test for details on these rules */
559 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
561 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
562 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
564 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
569 /* the CREATOR sids are special when inherited */
570 if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) {
571 creator = pvfs->sid_cache.creator_owner;
572 new_id = sd->owner_sid;
573 } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) {
574 creator = pvfs->sid_cache.creator_group;
575 new_id = sd->group_sid;
577 new_id = &ace.trustee;
580 if (creator && container &&
581 (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
582 uint32_t flags = ace.flags;
584 ace.trustee = *new_id;
586 status = security_descriptor_dacl_add(sd, &ace);
587 if (!NT_STATUS_IS_OK(status)) {
591 ace.trustee = *creator;
592 ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY;
593 status = security_descriptor_dacl_add(sd, &ace);
594 } else if (container &&
595 !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
596 status = security_descriptor_dacl_add(sd, &ace);
598 ace.trustee = *new_id;
599 status = security_descriptor_dacl_add(sd, &ace);
602 if (!NT_STATUS_IS_OK(status)) {
613 setup an ACL on a new file/directory based on the inherited ACL from
614 the parent. If there is no inherited ACL then we don't set anything,
615 as the default ACL applies anyway
617 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
618 struct ntvfs_request *req,
619 struct pvfs_filename *name,
622 struct xattr_NTACL *acl;
624 struct pvfs_filename *parent;
625 struct security_descriptor *parent_sd, *sd;
628 /* form the parents path */
629 status = pvfs_resolve_parent(pvfs, req, name, &parent);
630 if (!NT_STATUS_IS_OK(status)) {
634 acl = talloc(req, struct xattr_NTACL);
636 return NT_STATUS_NO_MEMORY;
639 status = pvfs_acl_load(pvfs, parent, -1, acl);
640 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
643 if (!NT_STATUS_IS_OK(status)) {
647 switch (acl->version) {
649 parent_sd = acl->info.sd;
652 return NT_STATUS_INVALID_ACL;
655 if (parent_sd == NULL ||
656 parent_sd->dacl == NULL ||
657 parent_sd->dacl->num_aces == 0) {
658 /* go with the default ACL */
662 /* create the new sd */
663 sd = security_descriptor_initialise(req);
665 return NT_STATUS_NO_MEMORY;
668 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
669 if (!NT_STATUS_IS_OK(status)) {
672 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
673 if (!NT_STATUS_IS_OK(status)) {
677 sd->type |= SEC_DESC_DACL_PRESENT;
679 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
681 /* fill in the aces from the parent */
682 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
683 if (!NT_STATUS_IS_OK(status)) {
687 /* if there is nothing to inherit then we fallback to the
689 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
695 status = pvfs_acl_save(pvfs, name, fd, acl);