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 /************************************************
208 Split the ACE flag mapping between nfs4 and Windows
209 into two separate functions rather than trying to do
210 it inline. Allows us to carefully control what flags
211 are mapped to what in one place.
212 ************************************************/
214 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
215 uint32_t nfs4_ace_flags)
217 uint32_t win_ace_flags = 0;
219 /* The nfs4 flags <= 0xf map perfectly. */
220 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
221 SEC_ACE_FLAG_CONTAINER_INHERIT|
222 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
223 SEC_ACE_FLAG_INHERIT_ONLY);
225 /* flags greater than 0xf have diverged :-(. */
226 /* See the nfs4 ace flag definitions here:
227 http://www.ietf.org/rfc/rfc3530.txt.
228 And the Windows ace flag definitions here:
229 librpc/idl/security.idl. */
230 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
231 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
234 return win_ace_flags;
237 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
239 uint32_t nfs4_ace_flags = 0;
241 /* The windows flags <= 0xf map perfectly. */
242 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
243 SMB_ACE4_DIRECTORY_INHERIT_ACE|
244 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
245 SMB_ACE4_INHERIT_ONLY_ACE);
247 /* flags greater than 0xf have diverged :-(. */
248 /* See the nfs4 ace flag definitions here:
249 http://www.ietf.org/rfc/rfc3530.txt.
250 And the Windows ace flag definitions here:
251 librpc/idl/security.idl. */
252 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
253 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
256 return nfs4_ace_flags;
259 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
261 struct SMB4ACL_T *theacl;
263 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
266 DEBUG(0, ("TALLOC_SIZE failed\n"));
270 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
271 /* theacl->first, last = NULL not needed */
275 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
277 struct SMB4ACE_T *ace;
279 ace = talloc_zero(acl, struct SMB4ACE_T);
282 DBG_ERR("talloc_zero failed\n");
288 if (acl->first==NULL)
293 acl->last->next = ace;
301 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
310 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
319 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
328 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
337 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
343 return acl->controlflags;
346 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
352 acl->controlflags = controlflags;
356 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
358 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
359 SMB_ACE4_FILE_INHERIT_ACE|
360 SMB_ACE4_DIRECTORY_INHERIT_ACE);
363 static int smbacl4_GetFileOwner(struct connection_struct *conn,
364 const struct smb_filename *smb_fname,
365 SMB_STRUCT_STAT *psbuf)
369 /* Get the stat struct for the owner info. */
370 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
372 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
380 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
383 struct security_ace *last = NULL;
386 if (*good_aces < 2) {
390 last = &nt_ace_list[(*good_aces) - 1];
392 for (i = 0; i < (*good_aces) - 1; i++) {
393 struct security_ace *cur = &nt_ace_list[i];
395 if (cur->type == last->type &&
396 cur->flags == last->flags &&
397 cur->access_mask == last->access_mask &&
398 dom_sid_equal(&cur->trustee, &last->trustee))
400 struct dom_sid_buf sid_buf;
402 DBG_INFO("Removing duplicate entry for SID %s.\n",
403 dom_sid_str_buf(&last->trustee, &sid_buf));
409 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
410 const struct smbacl4_vfs_params *params,
411 struct SMB4ACL_T *acl, /* in */
412 struct dom_sid *psid_owner, /* in */
413 struct dom_sid *psid_group, /* in */
414 bool is_directory, /* in */
415 struct security_ace **ppnt_ace_list, /* out */
416 int *pgood_aces /* out */
419 struct SMB4ACE_T *aceint;
420 struct security_ace *nt_ace_list = NULL;
423 DEBUG(10, ("%s entered\n", __func__));
425 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
427 if (nt_ace_list==NULL)
429 DEBUG(10, ("talloc error with %d aces", acl->naces));
434 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
437 struct dom_sid_buf buf;
438 SMB_ACE4PROP_T *ace = &aceint->prop;
439 uint32_t win_ace_flags;
441 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
442 "mask: %x, who: %d\n",
443 ace->aceType, ace->flags,
444 ace->aceFlags, ace->aceMask, ace->who.id));
446 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
447 switch (ace->who.special_id) {
448 case SMB_ACE4_WHO_OWNER:
449 sid_copy(&sid, psid_owner);
451 case SMB_ACE4_WHO_GROUP:
452 sid_copy(&sid, psid_group);
454 case SMB_ACE4_WHO_EVERYONE:
455 sid_copy(&sid, &global_sid_World);
458 DEBUG(8, ("invalid special who id %d "
459 "ignored\n", ace->who.special_id));
463 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
464 gid_to_sid(&sid, ace->who.gid);
466 uid_to_sid(&sid, ace->who.uid);
469 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
470 dom_sid_str_buf(&sid, &buf)));
472 if (!is_directory && params->map_full_control) {
474 * Do we have all access except DELETE_CHILD
475 * (not caring about the delete bit).
477 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
479 if (test_mask == SMB_ACE4_ALL_MASKS) {
480 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
484 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
487 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
488 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
490 * GPFS sets inherits dir_inhert and file_inherit flags
491 * to files, too, which confuses windows, and seems to
492 * be wrong anyways. ==> Map these bits away for files.
494 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
495 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
496 SEC_ACE_FLAG_CONTAINER_INHERIT);
498 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
499 ace->aceFlags, win_ace_flags));
503 /* Mapping of owner@ and group@ to creator owner and
504 creator group. Keep old behavior in mode special. */
505 if (params->mode != e_special &&
506 ace->flags & SMB_ACE4_ID_SPECIAL &&
507 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
508 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
509 DEBUG(10, ("Map special entry\n"));
510 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
511 uint32_t win_ace_flags_current;
512 DEBUG(10, ("Map current sid\n"));
513 win_ace_flags_current = win_ace_flags &
514 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
515 SEC_ACE_FLAG_CONTAINER_INHERIT);
516 init_sec_ace(&nt_ace_list[good_aces++], &sid,
518 win_ace_flags_current);
520 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
521 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
522 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
523 uint32_t win_ace_flags_creator;
524 DEBUG(10, ("Map creator owner\n"));
525 win_ace_flags_creator = win_ace_flags |
526 SMB_ACE4_INHERIT_ONLY_ACE;
527 init_sec_ace(&nt_ace_list[good_aces++],
528 &global_sid_Creator_Owner,
530 win_ace_flags_creator);
532 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
533 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
534 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
535 uint32_t win_ace_flags_creator;
536 DEBUG(10, ("Map creator owner group\n"));
537 win_ace_flags_creator = win_ace_flags |
538 SMB_ACE4_INHERIT_ONLY_ACE;
539 init_sec_ace(&nt_ace_list[good_aces++],
540 &global_sid_Creator_Group,
542 win_ace_flags_creator);
545 DEBUG(10, ("Map normal sid\n"));
546 init_sec_ace(&nt_ace_list[good_aces++], &sid,
551 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
554 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
557 /* returns a NULL ace list when good_aces is zero. */
558 if (good_aces && nt_ace_list == NULL) {
559 DEBUG(10, ("realloc error with %d aces", good_aces));
564 *ppnt_ace_list = nt_ace_list;
565 *pgood_aces = good_aces;
570 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
571 const struct smbacl4_vfs_params *params,
572 uint32_t security_info,
574 struct security_descriptor **ppdesc,
575 struct SMB4ACL_T *theacl)
578 struct dom_sid sid_owner, sid_group;
580 struct security_ace *nt_ace_list = NULL;
581 struct security_acl *psa = NULL;
582 TALLOC_CTX *frame = talloc_stackframe();
587 return NT_STATUS_ACCESS_DENIED; /* special because we
588 * need to think through
592 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
593 gid_to_sid(&sid_group, sbuf->st_ex_gid);
595 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
596 S_ISDIR(sbuf->st_ex_mode),
597 &nt_ace_list, &good_aces);
599 DEBUG(8,("smbacl4_nfs42win failed\n"));
601 return map_nt_error_from_unix(errno);
604 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
606 DEBUG(2,("make_sec_acl failed\n"));
608 return NT_STATUS_NO_MEMORY;
611 DEBUG(10,("after make sec_acl\n"));
612 *ppdesc = make_sec_desc(
613 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
614 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
615 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
616 NULL, psa, &sd_size);
618 DEBUG(2,("make_sec_desc failed\n"));
620 return NT_STATUS_NO_MEMORY;
623 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
625 (int)ndr_size_security_descriptor(*ppdesc, 0)));
631 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
632 const struct smbacl4_vfs_params *pparams,
633 uint32_t security_info,
635 struct security_descriptor **ppdesc,
636 struct SMB4ACL_T *theacl)
638 struct smbacl4_vfs_params params;
640 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
642 if (!VALID_STAT(fsp->fsp_name->st)) {
645 status = vfs_stat_fsp(fsp);
646 if (!NT_STATUS_IS_OK(status)) {
651 if (pparams == NULL) {
652 /* Special behaviours */
653 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
654 return NT_STATUS_NO_MEMORY;
659 return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
661 mem_ctx, ppdesc, theacl);
664 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
665 const struct smb_filename *smb_fname,
666 const struct smbacl4_vfs_params *pparams,
667 uint32_t security_info,
669 struct security_descriptor **ppdesc,
670 struct SMB4ACL_T *theacl)
672 SMB_STRUCT_STAT sbuf;
673 struct smbacl4_vfs_params params;
674 const SMB_STRUCT_STAT *psbuf = NULL;
676 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
677 smb_fname->base_name));
679 if (VALID_STAT(smb_fname->st)) {
680 psbuf = &smb_fname->st;
684 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
685 return map_nt_error_from_unix(errno);
690 if (pparams == NULL) {
691 /* Special behaviours */
692 if (smbacl4_get_vfs_params(conn, ¶ms)) {
693 return NT_STATUS_NO_MEMORY;
698 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
699 mem_ctx, ppdesc, theacl);
702 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
704 struct SMB4ACE_T *aceint;
706 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
708 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
709 SMB_ACE4PROP_T *ace = &aceint->prop;
711 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
712 "mask=0x%x, id=%d\n",
714 ace->aceFlags, ace->flags,
721 * Find 2 NFS4 who-special ACE property (non-copy!!!)
722 * match nonzero if "special" and who is equal
723 * return ace if found matching; otherwise NULL
725 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
726 struct SMB4ACL_T *acl,
727 SMB_ACE4PROP_T *aceNew)
729 struct SMB4ACE_T *aceint;
731 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
732 SMB_ACE4PROP_T *ace = &aceint->prop;
734 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
735 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
736 ace->aceType, ace->flags, ace->aceFlags,
737 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
739 if (ace->flags == aceNew->flags &&
740 ace->aceType==aceNew->aceType &&
741 ace->aceFlags==aceNew->aceFlags)
743 /* keep type safety; e.g. gid is an u.short */
744 if (ace->flags & SMB_ACE4_ID_SPECIAL)
746 if (ace->who.special_id ==
747 aceNew->who.special_id)
750 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
752 if (ace->who.gid==aceNew->who.gid)
755 if (ace->who.uid==aceNew->who.uid)
765 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
766 struct SMB4ACL_T *theacl,
771 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
776 case e_merge: /* "merge" flags */
778 ace4found->aceFlags |= ace->aceFlags;
779 ace4found->aceMask |= ace->aceMask;
781 case e_ignore: /* leave out this record */
784 case e_reject: /* do an error */
785 DBG_INFO("ACL rejected by duplicate nt ace.\n");
786 errno = EINVAL; /* SHOULD be set on any _real_ error */
796 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
797 struct SMB4ACL_T *nfs4_acl,
798 SMB_ACE4PROP_T *nfs4_ace)
802 if (acedup != e_dontcare) {
805 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
813 smb_add_ace4(nfs4_acl, nfs4_ace);
819 static int nfs4_acl_add_sec_ace(bool is_directory,
820 const struct smbacl4_vfs_params *params,
823 const struct security_ace *ace_nt,
824 struct SMB4ACL_T *nfs4_acl)
826 struct dom_sid_buf buf;
827 SMB_ACE4PROP_T nfs4_ace = { 0 };
828 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
829 bool add_ace2 = false;
832 DEBUG(10, ("got ace for %s\n",
833 dom_sid_str_buf(&ace_nt->trustee, &buf)));
835 /* only ACCESS|DENY supported right now */
836 nfs4_ace.aceType = ace_nt->type;
839 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
841 /* remove inheritance flags on files */
843 DEBUG(10, ("Removing inheritance flags from a file\n"));
844 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
845 SMB_ACE4_DIRECTORY_INHERIT_ACE|
846 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
847 SMB_ACE4_INHERIT_ONLY_ACE);
850 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
852 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
854 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
855 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
856 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
857 } else if (params->mode!=e_special &&
858 dom_sid_equal(&ace_nt->trustee,
859 &global_sid_Creator_Owner)) {
860 DEBUG(10, ("Map creator owner\n"));
861 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
862 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
863 /* A non inheriting creator owner entry has no effect. */
864 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
865 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
866 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
869 } else if (params->mode!=e_special &&
870 dom_sid_equal(&ace_nt->trustee,
871 &global_sid_Creator_Group)) {
872 DEBUG(10, ("Map creator owner group\n"));
873 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
874 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
875 /* A non inheriting creator group entry has no effect. */
876 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
877 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
878 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
882 struct unixid unixid;
885 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
887 DBG_WARNING("Could not convert %s to uid or gid.\n",
888 dom_sid_str_buf(&ace_nt->trustee, &buf));
892 if (dom_sid_compare_domain(&ace_nt->trustee,
893 &global_sid_Unix_NFS) == 0) {
897 switch (unixid.type) {
899 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
900 nfs4_ace.who.gid = unixid.id;
902 if (ownerUID == unixid.id &&
903 !nfs_ace_is_inherit(&nfs4_ace))
906 * IDMAP_TYPE_BOTH for owner. Add
907 * additional user entry, which can be
908 * mapped to special:owner to reflect
909 * the permissions in the modebits.
911 * This only applies to non-inheriting
912 * entries as only these are replaced
913 * with SPECIAL_OWNER in nfs4:mode=simple.
915 nfs4_ace_2 = (SMB_ACE4PROP_T) {
916 .who.uid = unixid.id,
917 .aceFlags = (nfs4_ace.aceFlags &
918 ~SMB_ACE4_IDENTIFIER_GROUP),
919 .aceMask = nfs4_ace.aceMask,
920 .aceType = nfs4_ace.aceType,
926 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
927 nfs4_ace.who.gid = unixid.id;
930 nfs4_ace.who.uid = unixid.id;
932 case ID_TYPE_NOT_SPECIFIED:
934 DBG_WARNING("Could not convert %s to uid or gid.\n",
935 dom_sid_str_buf(&ace_nt->trustee, &buf));
940 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
949 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
952 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
956 struct SMB4ACE_T *aceint;
958 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
959 SMB_ACE4PROP_T *ace = &aceint->prop;
961 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
962 "mask: %x, who: %d\n",
963 ace->aceType, ace->flags, ace->aceFlags,
964 ace->aceMask, ace->who.id));
966 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
967 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
968 ace->who.uid == ownerUID) {
969 ace->flags |= SMB_ACE4_ID_SPECIAL;
970 ace->who.special_id = SMB_ACE4_WHO_OWNER;
971 DEBUG(10,("replaced with special owner ace\n"));
974 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
975 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
976 ace->who.uid == ownerGID) {
977 ace->flags |= SMB_ACE4_ID_SPECIAL;
978 ace->who.special_id = SMB_ACE4_WHO_GROUP;
979 DEBUG(10,("replaced with special group ace\n"));
984 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
988 struct SMB4ACE_T *aceint;
990 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
991 SMB_ACE4PROP_T *ace = &aceint->prop;
993 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
994 "mask: %x, who: %d\n",
995 ace->aceType, ace->flags, ace->aceFlags,
996 ace->aceMask, ace->who.id));
998 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
999 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1000 ace->who.uid == ownerUID &&
1001 !nfs_ace_is_inherit(ace)) {
1002 ace->flags |= SMB_ACE4_ID_SPECIAL;
1003 ace->who.special_id = SMB_ACE4_WHO_OWNER;
1004 DEBUG(10,("replaced with special owner ace\n"));
1007 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1008 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1009 ace->who.gid == ownerGID &&
1010 !nfs_ace_is_inherit(ace)) {
1011 ace->flags |= SMB_ACE4_ID_SPECIAL;
1012 ace->who.special_id = SMB_ACE4_WHO_GROUP;
1013 DEBUG(10,("replaced with special group ace\n"));
1018 static struct SMB4ACL_T *smbacl4_win2nfs4(
1019 TALLOC_CTX *mem_ctx,
1021 const struct security_acl *dacl,
1022 const struct smbacl4_vfs_params *pparams,
1027 struct SMB4ACL_T *theacl;
1030 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1032 theacl = smb_create_smb4acl(mem_ctx);
1036 for(i=0; i<dacl->num_aces; i++) {
1039 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
1041 dacl->aces + i, theacl);
1047 if (pparams->mode==e_simple) {
1048 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
1051 if (pparams->mode==e_special) {
1052 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
1058 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
1059 const struct smbacl4_vfs_params *pparams,
1060 uint32_t security_info_sent,
1061 const struct security_descriptor *psd,
1062 set_nfs4acl_native_fn_t set_nfs4_native)
1064 struct smbacl4_vfs_params params;
1065 struct SMB4ACL_T *theacl = NULL;
1066 bool result, is_directory;
1068 bool set_acl_as_root = false;
1071 TALLOC_CTX *frame = talloc_stackframe();
1073 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1075 if ((security_info_sent & (SECINFO_DACL |
1076 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1078 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1079 security_info_sent));
1081 return NT_STATUS_OK; /* won't show error - later to be
1085 if (security_descriptor_with_ms_nfs(psd)) {
1087 return NT_STATUS_OK;
1090 if (pparams == NULL) {
1091 /* Special behaviours */
1092 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1094 return NT_STATUS_NO_MEMORY;
1099 status = vfs_stat_fsp(fsp);
1100 if (!NT_STATUS_IS_OK(status)) {
1105 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1107 if (pparams->do_chown) {
1109 * When the chown succeeds, the special entries in the
1110 * file system ACL refer to the new owner. In order to
1111 * apply the complete information from the DACL,
1112 * setting the ACL then has to succeed. Track this
1113 * case with set_acl_as_root and set the ACL as root
1116 status = chown_if_needed(fsp, security_info_sent, psd,
1118 if (!NT_STATUS_IS_OK(status)) {
1124 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1125 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1126 security_info_sent));
1128 return NT_STATUS_OK;
1131 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1132 fsp->fsp_name->st.st_ex_uid,
1133 fsp->fsp_name->st.st_ex_gid);
1136 return map_nt_error_from_unix(errno);
1139 smbacl4_set_controlflags(theacl, psd->type);
1140 smbacl4_dump_nfs4acl(10, theacl);
1142 if (set_acl_as_root) {
1145 result = set_nfs4_native(handle, fsp, theacl);
1146 saved_errno = errno;
1147 if (set_acl_as_root) {
1154 errno = saved_errno;
1155 DEBUG(10, ("set_nfs4_native failed with %s\n",
1157 return map_nt_error_from_unix(errno);
1160 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1161 return NT_STATUS_OK;