4 * Copyright (C) Jim McDonough, 2006
5 * Copyright (C) Christof Schmitt 2019
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
23 #include "nfs4_acls.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/idmap.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "../libcli/security/security.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "system/filesys.h"
31 #include "passdb/lookup_sid.h"
33 #include "lib/param/loadparm.h"
36 #define DBGC_CLASS DBGC_ACLS
38 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
40 extern const struct generic_mapping file_generic_mapping;
45 struct SMB4ACE_T *next;
50 uint16_t controlflags;
52 struct SMB4ACE_T *first;
53 struct SMB4ACE_T *last;
57 * Gather special parameters for NFS4 ACL handling
59 int smbacl4_get_vfs_params(struct connection_struct *conn,
60 struct smbacl4_vfs_params *params)
62 static const struct enum_list enum_smbacl4_modes[] = {
63 { e_simple, "simple" },
64 { e_special, "special" },
67 static const struct enum_list enum_smbacl4_acedups[] = {
68 { e_dontcare, "dontcare" },
69 { e_reject, "reject" },
70 { e_ignore, "ignore" },
76 *params = (struct smbacl4_vfs_params) { 0 };
78 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
79 enum_smbacl4_modes, e_simple);
81 DEBUG(10, ("value for %s:mode unknown\n",
82 SMBACL4_PARAM_TYPE_NAME));
85 params->mode = (enum smbacl4_mode_enum)enumval;
86 if (params->mode == e_special) {
87 DBG_WARNING("nfs4:mode special is deprecated.\n");
90 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
93 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
94 enum_smbacl4_acedups, e_merge);
96 DEBUG(10, ("value for %s:acedup unknown\n",
97 SMBACL4_PARAM_TYPE_NAME));
100 params->acedup = (enum smbacl4_acedup_enum)enumval;
101 if (params->acedup == e_ignore) {
102 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
104 if (params->acedup == e_reject) {
105 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
108 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111 enum_smbacl4_modes[params->mode].name,
112 params->do_chown ? "true" : "false",
113 enum_smbacl4_acedups[params->acedup].name,
114 params->map_full_control ? "true" : "false"));
119 int fstatat_with_cap_dac_override(int fd,
120 const char *pathname,
121 SMB_STRUCT_STAT *sbuf,
123 bool fake_dir_create_times)
127 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
128 ret = sys_fstatat(fd,
132 fake_dir_create_times);
133 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
138 int stat_with_cap_dac_override(struct vfs_handle_struct *handle,
139 struct smb_filename *smb_fname, int flag)
141 bool fake_dctime = lp_fake_directory_create_times(SNUM(handle->conn));
144 struct smb_filename *dir_name = NULL;
145 struct smb_filename *rel_name = NULL;
148 int open_flags = O_PATH;
150 int open_flags = O_RDONLY;
153 status = SMB_VFS_PARENT_PATHNAME(handle->conn,
158 if (!NT_STATUS_IS_OK(status)) {
159 errno = map_errno_from_nt_status(status);
163 fd = open(dir_name->base_name, open_flags, 0);
165 TALLOC_FREE(dir_name);
169 ret = fstatat_with_cap_dac_override(fd,
175 TALLOC_FREE(dir_name);
181 int nfs4_acl_stat(struct vfs_handle_struct *handle,
182 struct smb_filename *smb_fname)
186 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
187 if (ret == -1 && errno == EACCES) {
188 DEBUG(10, ("Trying stat with capability for %s\n",
189 smb_fname->base_name));
190 ret = stat_with_cap_dac_override(handle, smb_fname, 0);
195 int fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
196 bool fake_dir_create_times)
200 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
201 ret = sys_fstat(fd, sbuf, fake_dir_create_times);
202 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
207 int nfs4_acl_fstat(struct vfs_handle_struct *handle,
208 struct files_struct *fsp,
209 SMB_STRUCT_STAT *sbuf)
213 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
214 if (ret == -1 && errno == EACCES) {
216 lp_fake_directory_create_times(SNUM(handle->conn));
218 DBG_DEBUG("fstat for %s failed with EACCES. Trying with "
219 "CAP_DAC_OVERRIDE.\n", fsp->fsp_name->base_name);
220 ret = fstat_with_cap_dac_override(fsp_get_pathref_fd(fsp),
228 /************************************************
229 Split the ACE flag mapping between nfs4 and Windows
230 into two separate functions rather than trying to do
231 it inline. Allows us to carefully control what flags
232 are mapped to what in one place.
233 ************************************************/
235 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
236 uint32_t nfs4_ace_flags)
238 uint32_t win_ace_flags = 0;
240 /* The nfs4 flags <= 0xf map perfectly. */
241 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
242 SEC_ACE_FLAG_CONTAINER_INHERIT|
243 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
244 SEC_ACE_FLAG_INHERIT_ONLY);
246 /* flags greater than 0xf have diverged :-(. */
247 /* See the nfs4 ace flag definitions here:
248 http://www.ietf.org/rfc/rfc3530.txt.
249 And the Windows ace flag definitions here:
250 librpc/idl/security.idl. */
251 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
252 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
255 return win_ace_flags;
258 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
260 uint32_t nfs4_ace_flags = 0;
262 /* The windows flags <= 0xf map perfectly. */
263 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
264 SMB_ACE4_DIRECTORY_INHERIT_ACE|
265 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
266 SMB_ACE4_INHERIT_ONLY_ACE);
268 /* flags greater than 0xf have diverged :-(. */
269 /* See the nfs4 ace flag definitions here:
270 http://www.ietf.org/rfc/rfc3530.txt.
271 And the Windows ace flag definitions here:
272 librpc/idl/security.idl. */
273 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
274 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
277 return nfs4_ace_flags;
280 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
282 struct SMB4ACL_T *theacl;
284 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
287 DEBUG(0, ("TALLOC_SIZE failed\n"));
291 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
292 /* theacl->first, last = NULL not needed */
296 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
298 struct SMB4ACE_T *ace;
300 ace = talloc_zero(acl, struct SMB4ACE_T);
303 DBG_ERR("talloc_zero failed\n");
309 if (acl->first==NULL)
314 acl->last->next = ace;
322 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
331 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
340 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
349 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
358 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
364 return acl->controlflags;
367 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
373 acl->controlflags = controlflags;
377 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
379 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
380 SMB_ACE4_FILE_INHERIT_ACE|
381 SMB_ACE4_DIRECTORY_INHERIT_ACE);
384 static int smbacl4_GetFileOwner(struct connection_struct *conn,
385 const struct smb_filename *smb_fname,
386 SMB_STRUCT_STAT *psbuf)
390 /* Get the stat struct for the owner info. */
391 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
393 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
401 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
404 struct security_ace *last = NULL;
407 if (*good_aces < 2) {
411 last = &nt_ace_list[(*good_aces) - 1];
413 for (i = 0; i < (*good_aces) - 1; i++) {
414 struct security_ace *cur = &nt_ace_list[i];
416 if (cur->type == last->type &&
417 cur->flags == last->flags &&
418 cur->access_mask == last->access_mask &&
419 dom_sid_equal(&cur->trustee, &last->trustee))
421 struct dom_sid_buf sid_buf;
423 DBG_INFO("Removing duplicate entry for SID %s.\n",
424 dom_sid_str_buf(&last->trustee, &sid_buf));
430 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
431 const struct smbacl4_vfs_params *params,
432 struct SMB4ACL_T *acl, /* in */
433 struct dom_sid *psid_owner, /* in */
434 struct dom_sid *psid_group, /* in */
435 bool is_directory, /* in */
436 struct security_ace **ppnt_ace_list, /* out */
437 int *pgood_aces /* out */
440 struct SMB4ACE_T *aceint;
441 struct security_ace *nt_ace_list = NULL;
444 DEBUG(10, ("%s entered\n", __func__));
446 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
448 if (nt_ace_list==NULL)
450 DEBUG(10, ("talloc error with %d aces\n", acl->naces));
455 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
458 struct dom_sid_buf buf;
459 SMB_ACE4PROP_T *ace = &aceint->prop;
460 uint32_t win_ace_flags;
462 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
463 "mask: %x, who: %d\n",
464 ace->aceType, ace->flags,
465 ace->aceFlags, ace->aceMask, ace->who.id));
467 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
468 switch (ace->who.special_id) {
469 case SMB_ACE4_WHO_OWNER:
470 sid_copy(&sid, psid_owner);
472 case SMB_ACE4_WHO_GROUP:
473 sid_copy(&sid, psid_group);
475 case SMB_ACE4_WHO_EVERYONE:
476 sid_copy(&sid, &global_sid_World);
479 DEBUG(8, ("invalid special who id %d "
480 "ignored\n", ace->who.special_id));
484 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
485 gid_to_sid(&sid, ace->who.gid);
487 uid_to_sid(&sid, ace->who.uid);
490 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
491 dom_sid_str_buf(&sid, &buf)));
493 if (!is_directory && params->map_full_control) {
495 * Do we have all access except DELETE_CHILD
496 * (not caring about the delete bit).
498 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
500 if (test_mask == SMB_ACE4_ALL_MASKS) {
501 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
505 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
508 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
509 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
511 * GPFS sets inherits dir_inhert and file_inherit flags
512 * to files, too, which confuses windows, and seems to
513 * be wrong anyways. ==> Map these bits away for files.
515 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
516 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
517 SEC_ACE_FLAG_CONTAINER_INHERIT);
519 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
520 ace->aceFlags, win_ace_flags));
524 /* Mapping of owner@ and group@ to creator owner and
525 creator group. Keep old behavior in mode special. */
526 if (params->mode != e_special &&
527 ace->flags & SMB_ACE4_ID_SPECIAL &&
528 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
529 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
530 DEBUG(10, ("Map special entry\n"));
531 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
532 uint32_t win_ace_flags_current;
533 DEBUG(10, ("Map current sid\n"));
534 win_ace_flags_current = win_ace_flags &
535 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
536 SEC_ACE_FLAG_CONTAINER_INHERIT);
537 init_sec_ace(&nt_ace_list[good_aces++], &sid,
539 win_ace_flags_current);
541 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
542 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
543 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
544 uint32_t win_ace_flags_creator;
545 DEBUG(10, ("Map creator owner\n"));
546 win_ace_flags_creator = win_ace_flags |
547 SMB_ACE4_INHERIT_ONLY_ACE;
548 init_sec_ace(&nt_ace_list[good_aces++],
549 &global_sid_Creator_Owner,
551 win_ace_flags_creator);
553 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
554 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
555 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
556 uint32_t win_ace_flags_creator;
557 DEBUG(10, ("Map creator owner group\n"));
558 win_ace_flags_creator = win_ace_flags |
559 SMB_ACE4_INHERIT_ONLY_ACE;
560 init_sec_ace(&nt_ace_list[good_aces++],
561 &global_sid_Creator_Group,
563 win_ace_flags_creator);
566 DEBUG(10, ("Map normal sid\n"));
567 init_sec_ace(&nt_ace_list[good_aces++], &sid,
572 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
575 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
578 /* returns a NULL ace list when good_aces is zero. */
579 if (good_aces && nt_ace_list == NULL) {
580 DEBUG(10, ("realloc error with %d aces\n", good_aces));
585 *ppnt_ace_list = nt_ace_list;
586 *pgood_aces = good_aces;
591 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
592 const struct smbacl4_vfs_params *params,
593 uint32_t security_info,
595 struct security_descriptor **ppdesc,
596 struct SMB4ACL_T *theacl)
599 struct dom_sid sid_owner, sid_group;
601 struct security_ace *nt_ace_list = NULL;
602 struct security_acl *psa = NULL;
603 TALLOC_CTX *frame = talloc_stackframe();
608 return NT_STATUS_ACCESS_DENIED; /* special because we
609 * need to think through
613 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
614 gid_to_sid(&sid_group, sbuf->st_ex_gid);
616 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
617 S_ISDIR(sbuf->st_ex_mode),
618 &nt_ace_list, &good_aces);
620 DEBUG(8,("smbacl4_nfs42win failed\n"));
622 return map_nt_error_from_unix(errno);
625 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
627 DEBUG(2,("make_sec_acl failed\n"));
629 return NT_STATUS_NO_MEMORY;
632 DEBUG(10,("after make sec_acl\n"));
633 *ppdesc = make_sec_desc(
634 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
635 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
636 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
637 NULL, psa, &sd_size);
639 DEBUG(2,("make_sec_desc failed\n"));
641 return NT_STATUS_NO_MEMORY;
644 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
646 (int)ndr_size_security_descriptor(*ppdesc, 0)));
652 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
653 const struct smbacl4_vfs_params *pparams,
654 uint32_t security_info,
656 struct security_descriptor **ppdesc,
657 struct SMB4ACL_T *theacl)
659 struct smbacl4_vfs_params params;
661 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
663 if (!VALID_STAT(fsp->fsp_name->st)) {
666 status = vfs_stat_fsp(fsp);
667 if (!NT_STATUS_IS_OK(status)) {
672 if (pparams == NULL) {
673 /* Special behaviours */
674 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
675 return NT_STATUS_NO_MEMORY;
680 return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
682 mem_ctx, ppdesc, theacl);
685 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
686 const struct smb_filename *smb_fname,
687 const struct smbacl4_vfs_params *pparams,
688 uint32_t security_info,
690 struct security_descriptor **ppdesc,
691 struct SMB4ACL_T *theacl)
693 SMB_STRUCT_STAT sbuf;
694 struct smbacl4_vfs_params params;
695 const SMB_STRUCT_STAT *psbuf = NULL;
697 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
698 smb_fname->base_name));
700 if (VALID_STAT(smb_fname->st)) {
701 psbuf = &smb_fname->st;
705 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
706 return map_nt_error_from_unix(errno);
711 if (pparams == NULL) {
712 /* Special behaviours */
713 if (smbacl4_get_vfs_params(conn, ¶ms)) {
714 return NT_STATUS_NO_MEMORY;
719 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
720 mem_ctx, ppdesc, theacl);
723 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
725 struct SMB4ACE_T *aceint;
727 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
729 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
730 SMB_ACE4PROP_T *ace = &aceint->prop;
732 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
733 "mask=0x%x, id=%d\n",
735 ace->aceFlags, ace->flags,
742 * Find 2 NFS4 who-special ACE property (non-copy!!!)
743 * match nonzero if "special" and who is equal
744 * return ace if found matching; otherwise NULL
746 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
747 struct SMB4ACL_T *acl,
748 SMB_ACE4PROP_T *aceNew)
750 struct SMB4ACE_T *aceint;
752 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
753 SMB_ACE4PROP_T *ace = &aceint->prop;
755 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
756 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
757 ace->aceType, ace->flags, ace->aceFlags,
758 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
760 if (ace->flags == aceNew->flags &&
761 ace->aceType==aceNew->aceType &&
762 ace->aceFlags==aceNew->aceFlags)
764 /* keep type safety; e.g. gid is an u.short */
765 if (ace->flags & SMB_ACE4_ID_SPECIAL)
767 if (ace->who.special_id ==
768 aceNew->who.special_id)
771 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
773 if (ace->who.gid==aceNew->who.gid)
776 if (ace->who.uid==aceNew->who.uid)
786 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
787 struct SMB4ACL_T *theacl,
792 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
797 case e_merge: /* "merge" flags */
799 ace4found->aceFlags |= ace->aceFlags;
800 ace4found->aceMask |= ace->aceMask;
802 case e_ignore: /* leave out this record */
805 case e_reject: /* do an error */
806 DBG_INFO("ACL rejected by duplicate nt ace.\n");
807 errno = EINVAL; /* SHOULD be set on any _real_ error */
817 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
818 struct SMB4ACL_T *nfs4_acl,
819 SMB_ACE4PROP_T *nfs4_ace)
823 if (acedup != e_dontcare) {
826 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
834 smb_add_ace4(nfs4_acl, nfs4_ace);
840 static int nfs4_acl_add_sec_ace(bool is_directory,
841 const struct smbacl4_vfs_params *params,
844 const struct security_ace *ace_nt,
845 struct SMB4ACL_T *nfs4_acl)
847 struct dom_sid_buf buf;
848 SMB_ACE4PROP_T nfs4_ace = { 0 };
849 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
850 bool add_ace2 = false;
853 DEBUG(10, ("got ace for %s\n",
854 dom_sid_str_buf(&ace_nt->trustee, &buf)));
856 /* only ACCESS|DENY supported right now */
857 nfs4_ace.aceType = ace_nt->type;
860 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
862 /* remove inheritance flags on files */
864 DEBUG(10, ("Removing inheritance flags from a file\n"));
865 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
866 SMB_ACE4_DIRECTORY_INHERIT_ACE|
867 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
868 SMB_ACE4_INHERIT_ONLY_ACE);
871 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
873 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
875 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
876 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
877 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
878 } else if (params->mode!=e_special &&
879 dom_sid_equal(&ace_nt->trustee,
880 &global_sid_Creator_Owner)) {
881 DEBUG(10, ("Map creator owner\n"));
882 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
883 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
884 /* A non inheriting creator owner entry has no effect. */
885 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
886 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
887 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
890 } else if (params->mode!=e_special &&
891 dom_sid_equal(&ace_nt->trustee,
892 &global_sid_Creator_Group)) {
893 DEBUG(10, ("Map creator owner group\n"));
894 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
895 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
896 /* A non inheriting creator group entry has no effect. */
897 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
898 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
899 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
903 struct unixid unixid;
906 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
908 DBG_WARNING("Could not convert %s to uid or gid.\n",
909 dom_sid_str_buf(&ace_nt->trustee, &buf));
913 if (dom_sid_compare_domain(&ace_nt->trustee,
914 &global_sid_Unix_NFS) == 0) {
918 switch (unixid.type) {
920 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
921 nfs4_ace.who.gid = unixid.id;
923 if (ownerUID == unixid.id &&
924 !nfs_ace_is_inherit(&nfs4_ace))
927 * IDMAP_TYPE_BOTH for owner. Add
928 * additional user entry, which can be
929 * mapped to special:owner to reflect
930 * the permissions in the modebits.
932 * This only applies to non-inheriting
933 * entries as only these are replaced
934 * with SPECIAL_OWNER in nfs4:mode=simple.
936 nfs4_ace_2 = (SMB_ACE4PROP_T) {
937 .who.uid = unixid.id,
938 .aceFlags = (nfs4_ace.aceFlags &
939 ~SMB_ACE4_IDENTIFIER_GROUP),
940 .aceMask = nfs4_ace.aceMask,
941 .aceType = nfs4_ace.aceType,
947 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
948 nfs4_ace.who.gid = unixid.id;
951 nfs4_ace.who.uid = unixid.id;
953 case ID_TYPE_NOT_SPECIFIED:
955 DBG_WARNING("Could not convert %s to uid or gid.\n",
956 dom_sid_str_buf(&ace_nt->trustee, &buf));
961 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
970 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
973 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
977 struct SMB4ACE_T *aceint;
979 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
980 SMB_ACE4PROP_T *ace = &aceint->prop;
982 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
983 "mask: %x, who: %d\n",
984 ace->aceType, ace->flags, ace->aceFlags,
985 ace->aceMask, ace->who.id));
987 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
988 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
989 ace->who.uid == ownerUID) {
990 ace->flags |= SMB_ACE4_ID_SPECIAL;
991 ace->who.special_id = SMB_ACE4_WHO_OWNER;
992 DEBUG(10,("replaced with special owner ace\n"));
995 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
996 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
997 ace->who.uid == ownerGID) {
998 ace->flags |= SMB_ACE4_ID_SPECIAL;
999 ace->who.special_id = SMB_ACE4_WHO_GROUP;
1000 DEBUG(10,("replaced with special group ace\n"));
1005 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
1009 struct SMB4ACE_T *aceint;
1011 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
1012 SMB_ACE4PROP_T *ace = &aceint->prop;
1014 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1015 "mask: %x, who: %d\n",
1016 ace->aceType, ace->flags, ace->aceFlags,
1017 ace->aceMask, ace->who.id));
1019 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1020 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1021 ace->who.uid == ownerUID &&
1022 !nfs_ace_is_inherit(ace)) {
1023 ace->flags |= SMB_ACE4_ID_SPECIAL;
1024 ace->who.special_id = SMB_ACE4_WHO_OWNER;
1025 DEBUG(10,("replaced with special owner ace\n"));
1028 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1029 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1030 ace->who.gid == ownerGID &&
1031 !nfs_ace_is_inherit(ace)) {
1032 ace->flags |= SMB_ACE4_ID_SPECIAL;
1033 ace->who.special_id = SMB_ACE4_WHO_GROUP;
1034 DEBUG(10,("replaced with special group ace\n"));
1039 static struct SMB4ACL_T *smbacl4_win2nfs4(
1040 TALLOC_CTX *mem_ctx,
1042 const struct security_acl *dacl,
1043 const struct smbacl4_vfs_params *pparams,
1048 struct SMB4ACL_T *theacl;
1051 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1053 theacl = smb_create_smb4acl(mem_ctx);
1057 for(i=0; i<dacl->num_aces; i++) {
1060 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
1062 dacl->aces + i, theacl);
1068 if (pparams->mode==e_simple) {
1069 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
1072 if (pparams->mode==e_special) {
1073 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
1079 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
1080 const struct smbacl4_vfs_params *pparams,
1081 uint32_t security_info_sent,
1082 const struct security_descriptor *psd,
1083 set_nfs4acl_native_fn_t set_nfs4_native)
1085 struct smbacl4_vfs_params params;
1086 struct SMB4ACL_T *theacl = NULL;
1087 bool result, is_directory;
1089 bool set_acl_as_root = false;
1092 TALLOC_CTX *frame = talloc_stackframe();
1094 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1096 if ((security_info_sent & (SECINFO_DACL |
1097 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1099 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1100 security_info_sent));
1102 return NT_STATUS_OK; /* won't show error - later to be
1106 if (security_descriptor_with_ms_nfs(psd)) {
1108 return NT_STATUS_OK;
1111 if (pparams == NULL) {
1112 /* Special behaviours */
1113 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1115 return NT_STATUS_NO_MEMORY;
1120 status = vfs_stat_fsp(fsp);
1121 if (!NT_STATUS_IS_OK(status)) {
1126 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1128 if (pparams->do_chown) {
1130 * When the chown succeeds, the special entries in the
1131 * file system ACL refer to the new owner. In order to
1132 * apply the complete information from the DACL,
1133 * setting the ACL then has to succeed. Track this
1134 * case with set_acl_as_root and set the ACL as root
1137 status = chown_if_needed(fsp, security_info_sent, psd,
1139 if (!NT_STATUS_IS_OK(status)) {
1145 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1146 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1147 security_info_sent));
1149 return NT_STATUS_OK;
1152 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1153 fsp->fsp_name->st.st_ex_uid,
1154 fsp->fsp_name->st.st_ex_gid);
1157 return map_nt_error_from_unix(errno);
1160 smbacl4_set_controlflags(theacl, psd->type);
1161 smbacl4_dump_nfs4acl(10, theacl);
1163 if (set_acl_as_root) {
1166 result = set_nfs4_native(handle, fsp, theacl);
1167 saved_errno = errno;
1168 if (set_acl_as_root) {
1175 errno = saved_errno;
1176 DEBUG(10, ("set_nfs4_native failed with %s\n",
1178 return map_nt_error_from_unix(errno);
1181 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1182 return NT_STATUS_OK;