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 /* owner and root get extra permissions */
353 if (uid == 0 || uid == name->st.st_uid) {
354 max_bits |= SEC_STD_ALL;
357 if (*access_mask == SEC_FLAG_MAXIMUM_ALLOWED) {
358 *access_mask = max_bits;
362 if (*access_mask & ~max_bits) {
363 return NT_STATUS_ACCESS_DENIED;
366 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
373 check the security descriptor on a file, if any
375 *access_mask is modified with the access actually granted
377 NTSTATUS pvfs_access_check(struct pvfs_state *pvfs,
378 struct ntvfs_request *req,
379 struct pvfs_filename *name,
380 uint32_t *access_mask)
382 struct security_token *token = req->session_info->security_token;
383 struct xattr_NTACL *acl;
385 struct security_descriptor *sd;
387 acl = talloc(req, struct xattr_NTACL);
389 return NT_STATUS_NO_MEMORY;
392 /* expand the generic access bits to file specific bits */
393 *access_mask = pvfs_translate_mask(*access_mask);
394 *access_mask &= ~SEC_FILE_READ_ATTRIBUTE;
396 status = pvfs_acl_load(pvfs, name, -1, acl);
397 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
399 return pvfs_access_check_unix(pvfs, req, name, access_mask);
401 if (!NT_STATUS_IS_OK(status)) {
405 switch (acl->version) {
410 return NT_STATUS_INVALID_ACL;
413 /* check the acl against the required access mask */
414 status = sec_access_check(sd, token, *access_mask, access_mask);
416 /* this bit is always granted, even if not asked for */
417 *access_mask |= SEC_FILE_READ_ATTRIBUTE;
426 a simplified interface to access check, designed for calls that
427 do not take or return an access check mask
429 NTSTATUS pvfs_access_check_simple(struct pvfs_state *pvfs,
430 struct ntvfs_request *req,
431 struct pvfs_filename *name,
432 uint32_t access_needed)
434 if (access_needed == 0) {
437 return pvfs_access_check(pvfs, req, name, &access_needed);
441 access check for creating a new file/directory
443 NTSTATUS pvfs_access_check_create(struct pvfs_state *pvfs,
444 struct ntvfs_request *req,
445 struct pvfs_filename *name,
446 uint32_t *access_mask)
448 struct pvfs_filename *parent;
451 status = pvfs_resolve_parent(pvfs, req, name, &parent);
452 if (!NT_STATUS_IS_OK(status)) {
456 status = pvfs_access_check(pvfs, req, parent, access_mask);
457 if (!NT_STATUS_IS_OK(status)) {
461 if (! ((*access_mask) & SEC_DIR_ADD_FILE)) {
462 return pvfs_access_check_simple(pvfs, req, parent, SEC_DIR_ADD_FILE);
469 access check for creating a new file/directory - no access mask supplied
471 NTSTATUS pvfs_access_check_parent(struct pvfs_state *pvfs,
472 struct ntvfs_request *req,
473 struct pvfs_filename *name,
474 uint32_t access_mask)
476 struct pvfs_filename *parent;
479 status = pvfs_resolve_parent(pvfs, req, name, &parent);
480 if (!NT_STATUS_IS_OK(status)) {
484 return pvfs_access_check_simple(pvfs, req, parent, access_mask);
489 determine if an ACE is inheritable
491 static BOOL pvfs_inheritable_ace(struct pvfs_state *pvfs,
492 const struct security_ace *ace,
496 return (ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) != 0;
499 if (ace->flags & SEC_ACE_FLAG_CONTAINER_INHERIT) {
503 if ((ace->flags & SEC_ACE_FLAG_OBJECT_INHERIT) &&
504 !(ace->flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
512 this is the core of ACL inheritance. It copies any inheritable
513 aces from the parent SD to the child SD. Note that the algorithm
514 depends on whether the child is a container or not
516 static NTSTATUS pvfs_acl_inherit_aces(struct pvfs_state *pvfs,
517 struct security_descriptor *parent_sd,
518 struct security_descriptor *sd,
523 for (i=0;i<parent_sd->dacl->num_aces;i++) {
524 struct security_ace ace = parent_sd->dacl->aces[i];
526 const struct dom_sid *creator = NULL, *new_id = NULL;
529 if (!pvfs_inheritable_ace(pvfs, &ace, container)) {
533 orig_flags = ace.flags;
535 /* see the RAW-ACLS inheritance test for details on these rules */
539 ace.flags &= ~SEC_ACE_FLAG_INHERIT_ONLY;
541 if (!(ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
542 ace.flags |= SEC_ACE_FLAG_INHERIT_ONLY;
544 if (ace.flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT) {
549 /* the CREATOR sids are special when inherited */
550 if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_owner)) {
551 creator = pvfs->sid_cache.creator_owner;
552 new_id = sd->owner_sid;
553 } else if (dom_sid_equal(&ace.trustee, pvfs->sid_cache.creator_group)) {
554 creator = pvfs->sid_cache.creator_group;
555 new_id = sd->group_sid;
557 new_id = &ace.trustee;
560 if (creator && container &&
561 (ace.flags & SEC_ACE_FLAG_CONTAINER_INHERIT)) {
562 uint32_t flags = ace.flags;
564 ace.trustee = *new_id;
566 status = security_descriptor_dacl_add(sd, &ace);
567 if (!NT_STATUS_IS_OK(status)) {
571 ace.trustee = *creator;
572 ace.flags = flags | SEC_ACE_FLAG_INHERIT_ONLY;
573 status = security_descriptor_dacl_add(sd, &ace);
574 } else if (container &&
575 !(orig_flags & SEC_ACE_FLAG_NO_PROPAGATE_INHERIT)) {
576 status = security_descriptor_dacl_add(sd, &ace);
578 ace.trustee = *new_id;
579 status = security_descriptor_dacl_add(sd, &ace);
582 if (!NT_STATUS_IS_OK(status)) {
593 setup an ACL on a new file/directory based on the inherited ACL from
594 the parent. If there is no inherited ACL then we don't set anything,
595 as the default ACL applies anyway
597 NTSTATUS pvfs_acl_inherit(struct pvfs_state *pvfs,
598 struct ntvfs_request *req,
599 struct pvfs_filename *name,
602 struct xattr_NTACL *acl;
604 struct pvfs_filename *parent;
605 struct security_descriptor *parent_sd, *sd;
608 /* form the parents path */
609 status = pvfs_resolve_parent(pvfs, req, name, &parent);
610 if (!NT_STATUS_IS_OK(status)) {
614 acl = talloc(req, struct xattr_NTACL);
616 return NT_STATUS_NO_MEMORY;
619 status = pvfs_acl_load(pvfs, parent, -1, acl);
620 if (NT_STATUS_EQUAL(status, NT_STATUS_NOT_FOUND)) {
623 if (!NT_STATUS_IS_OK(status)) {
627 switch (acl->version) {
629 parent_sd = acl->info.sd;
632 return NT_STATUS_INVALID_ACL;
635 if (parent_sd == NULL ||
636 parent_sd->dacl == NULL ||
637 parent_sd->dacl->num_aces == 0) {
638 /* go with the default ACL */
642 /* create the new sd */
643 sd = security_descriptor_initialise(req);
645 return NT_STATUS_NO_MEMORY;
648 status = sidmap_uid_to_sid(pvfs->sidmap, sd, name->st.st_uid, &sd->owner_sid);
649 if (!NT_STATUS_IS_OK(status)) {
652 status = sidmap_gid_to_sid(pvfs->sidmap, sd, name->st.st_gid, &sd->group_sid);
653 if (!NT_STATUS_IS_OK(status)) {
657 sd->type |= SEC_DESC_DACL_PRESENT;
659 container = (name->dos.attrib & FILE_ATTRIBUTE_DIRECTORY) ? True:False;
661 /* fill in the aces from the parent */
662 status = pvfs_acl_inherit_aces(pvfs, parent_sd, sd, container);
663 if (!NT_STATUS_IS_OK(status)) {
667 /* if there is nothing to inherit then we fallback to the
669 if (sd->dacl == NULL || sd->dacl->num_aces == 0) {
675 status = pvfs_acl_save(pvfs, name, fd, acl);