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 fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
120 bool fake_dir_create_times)
124 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
125 ret = sys_fstat(fd, sbuf, fake_dir_create_times);
126 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
131 /************************************************
132 Split the ACE flag mapping between nfs4 and Windows
133 into two separate functions rather than trying to do
134 it inline. Allows us to carefully control what flags
135 are mapped to what in one place.
136 ************************************************/
138 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
139 uint32_t nfs4_ace_flags)
141 uint32_t win_ace_flags = 0;
143 /* The nfs4 flags <= 0xf map perfectly. */
144 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
145 SEC_ACE_FLAG_CONTAINER_INHERIT|
146 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
147 SEC_ACE_FLAG_INHERIT_ONLY);
149 /* flags greater than 0xf have diverged :-(. */
150 /* See the nfs4 ace flag definitions here:
151 http://www.ietf.org/rfc/rfc3530.txt.
152 And the Windows ace flag definitions here:
153 librpc/idl/security.idl. */
154 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
155 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
158 return win_ace_flags;
161 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
163 uint32_t nfs4_ace_flags = 0;
165 /* The windows flags <= 0xf map perfectly. */
166 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
167 SMB_ACE4_DIRECTORY_INHERIT_ACE|
168 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
169 SMB_ACE4_INHERIT_ONLY_ACE);
171 /* flags greater than 0xf have diverged :-(. */
172 /* See the nfs4 ace flag definitions here:
173 http://www.ietf.org/rfc/rfc3530.txt.
174 And the Windows ace flag definitions here:
175 librpc/idl/security.idl. */
176 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
177 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
180 return nfs4_ace_flags;
183 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
185 struct SMB4ACL_T *theacl;
187 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
190 DEBUG(0, ("TALLOC_SIZE failed\n"));
194 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
195 /* theacl->first, last = NULL not needed */
199 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
201 struct SMB4ACE_T *ace;
203 ace = talloc_zero(acl, struct SMB4ACE_T);
206 DBG_ERR("talloc_zero failed\n");
212 if (acl->first==NULL)
217 acl->last->next = ace;
225 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
234 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
243 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
252 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
261 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
267 return acl->controlflags;
270 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
276 acl->controlflags = controlflags;
280 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
282 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
283 SMB_ACE4_FILE_INHERIT_ACE|
284 SMB_ACE4_DIRECTORY_INHERIT_ACE);
287 static int smbacl4_GetFileOwner(struct connection_struct *conn,
288 const struct smb_filename *smb_fname,
289 SMB_STRUCT_STAT *psbuf)
293 /* Get the stat struct for the owner info. */
294 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
296 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
304 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
307 struct security_ace *last = NULL;
310 if (*good_aces < 2) {
314 last = &nt_ace_list[(*good_aces) - 1];
316 for (i = 0; i < (*good_aces) - 1; i++) {
317 struct security_ace *cur = &nt_ace_list[i];
319 if (cur->type == last->type &&
320 cur->flags == last->flags &&
321 cur->access_mask == last->access_mask &&
322 dom_sid_equal(&cur->trustee, &last->trustee))
324 struct dom_sid_buf sid_buf;
326 DBG_INFO("Removing duplicate entry for SID %s.\n",
327 dom_sid_str_buf(&last->trustee, &sid_buf));
333 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
334 const struct smbacl4_vfs_params *params,
335 struct SMB4ACL_T *acl, /* in */
336 struct dom_sid *psid_owner, /* in */
337 struct dom_sid *psid_group, /* in */
338 bool is_directory, /* in */
339 struct security_ace **ppnt_ace_list, /* out */
340 int *pgood_aces /* out */
343 struct SMB4ACE_T *aceint;
344 struct security_ace *nt_ace_list = NULL;
347 DEBUG(10, ("%s entered\n", __func__));
349 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
351 if (nt_ace_list==NULL)
353 DEBUG(10, ("talloc error with %d aces\n", acl->naces));
358 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
361 struct dom_sid_buf buf;
362 SMB_ACE4PROP_T *ace = &aceint->prop;
363 uint32_t win_ace_flags;
365 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
366 "mask: %x, who: %d\n",
367 ace->aceType, ace->flags,
368 ace->aceFlags, ace->aceMask, ace->who.id));
370 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
371 switch (ace->who.special_id) {
372 case SMB_ACE4_WHO_OWNER:
373 sid_copy(&sid, psid_owner);
375 case SMB_ACE4_WHO_GROUP:
376 sid_copy(&sid, psid_group);
378 case SMB_ACE4_WHO_EVERYONE:
379 sid_copy(&sid, &global_sid_World);
382 DEBUG(8, ("invalid special who id %d "
383 "ignored\n", ace->who.special_id));
387 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
388 gid_to_sid(&sid, ace->who.gid);
390 uid_to_sid(&sid, ace->who.uid);
393 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
394 dom_sid_str_buf(&sid, &buf)));
396 if (!is_directory && params->map_full_control) {
398 * Do we have all access except DELETE_CHILD
399 * (not caring about the delete bit).
401 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
403 if (test_mask == SMB_ACE4_ALL_MASKS) {
404 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
408 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
411 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
412 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
414 * GPFS sets inherits dir_inhert and file_inherit flags
415 * to files, too, which confuses windows, and seems to
416 * be wrong anyways. ==> Map these bits away for files.
418 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
419 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
420 SEC_ACE_FLAG_CONTAINER_INHERIT);
422 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
423 ace->aceFlags, win_ace_flags));
427 /* Mapping of owner@ and group@ to creator owner and
428 creator group. Keep old behavior in mode special. */
429 if (params->mode != e_special &&
430 ace->flags & SMB_ACE4_ID_SPECIAL &&
431 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
432 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
433 DEBUG(10, ("Map special entry\n"));
434 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
435 uint32_t win_ace_flags_current;
436 DEBUG(10, ("Map current sid\n"));
437 win_ace_flags_current = win_ace_flags &
438 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
439 SEC_ACE_FLAG_CONTAINER_INHERIT);
440 init_sec_ace(&nt_ace_list[good_aces++], &sid,
442 win_ace_flags_current);
444 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
445 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
446 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
447 uint32_t win_ace_flags_creator;
448 DEBUG(10, ("Map creator owner\n"));
449 win_ace_flags_creator = win_ace_flags |
450 SMB_ACE4_INHERIT_ONLY_ACE;
451 init_sec_ace(&nt_ace_list[good_aces++],
452 &global_sid_Creator_Owner,
454 win_ace_flags_creator);
456 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
457 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
458 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
459 uint32_t win_ace_flags_creator;
460 DEBUG(10, ("Map creator owner group\n"));
461 win_ace_flags_creator = win_ace_flags |
462 SMB_ACE4_INHERIT_ONLY_ACE;
463 init_sec_ace(&nt_ace_list[good_aces++],
464 &global_sid_Creator_Group,
466 win_ace_flags_creator);
469 DEBUG(10, ("Map normal sid\n"));
470 init_sec_ace(&nt_ace_list[good_aces++], &sid,
475 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
478 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
481 /* returns a NULL ace list when good_aces is zero. */
482 if (good_aces && nt_ace_list == NULL) {
483 DEBUG(10, ("realloc error with %d aces\n", good_aces));
488 *ppnt_ace_list = nt_ace_list;
489 *pgood_aces = good_aces;
494 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
495 const struct smbacl4_vfs_params *params,
496 uint32_t security_info,
498 struct security_descriptor **ppdesc,
499 struct SMB4ACL_T *theacl)
502 struct dom_sid sid_owner, sid_group;
504 struct security_ace *nt_ace_list = NULL;
505 struct security_acl *psa = NULL;
506 TALLOC_CTX *frame = talloc_stackframe();
511 return NT_STATUS_ACCESS_DENIED; /* special because we
512 * need to think through
516 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
517 gid_to_sid(&sid_group, sbuf->st_ex_gid);
519 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
520 S_ISDIR(sbuf->st_ex_mode),
521 &nt_ace_list, &good_aces);
523 DEBUG(8,("smbacl4_nfs42win failed\n"));
525 return map_nt_error_from_unix(errno);
528 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
530 DEBUG(2,("make_sec_acl failed\n"));
532 return NT_STATUS_NO_MEMORY;
535 DEBUG(10,("after make sec_acl\n"));
536 *ppdesc = make_sec_desc(
537 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
538 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
539 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
540 NULL, psa, &sd_size);
542 DEBUG(2,("make_sec_desc failed\n"));
544 return NT_STATUS_NO_MEMORY;
547 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
549 (int)ndr_size_security_descriptor(*ppdesc, 0)));
555 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
556 const struct smbacl4_vfs_params *pparams,
557 uint32_t security_info,
559 struct security_descriptor **ppdesc,
560 struct SMB4ACL_T *theacl)
562 struct smbacl4_vfs_params params;
564 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
566 if (!VALID_STAT(fsp->fsp_name->st)) {
569 status = vfs_stat_fsp(fsp);
570 if (!NT_STATUS_IS_OK(status)) {
575 if (pparams == NULL) {
576 /* Special behaviours */
577 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
578 return NT_STATUS_NO_MEMORY;
583 return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
585 mem_ctx, ppdesc, theacl);
588 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
589 const struct smb_filename *smb_fname,
590 const struct smbacl4_vfs_params *pparams,
591 uint32_t security_info,
593 struct security_descriptor **ppdesc,
594 struct SMB4ACL_T *theacl)
596 SMB_STRUCT_STAT sbuf;
597 struct smbacl4_vfs_params params;
598 const SMB_STRUCT_STAT *psbuf = NULL;
600 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
601 smb_fname->base_name));
603 if (VALID_STAT(smb_fname->st)) {
604 psbuf = &smb_fname->st;
608 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
609 return map_nt_error_from_unix(errno);
614 if (pparams == NULL) {
615 /* Special behaviours */
616 if (smbacl4_get_vfs_params(conn, ¶ms)) {
617 return NT_STATUS_NO_MEMORY;
622 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
623 mem_ctx, ppdesc, theacl);
626 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
628 struct SMB4ACE_T *aceint;
630 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
632 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
633 SMB_ACE4PROP_T *ace = &aceint->prop;
635 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
636 "mask=0x%x, id=%d\n",
638 ace->aceFlags, ace->flags,
645 * Find 2 NFS4 who-special ACE property (non-copy!!!)
646 * match nonzero if "special" and who is equal
647 * return ace if found matching; otherwise NULL
649 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
650 struct SMB4ACL_T *acl,
651 SMB_ACE4PROP_T *aceNew)
653 struct SMB4ACE_T *aceint;
655 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
656 SMB_ACE4PROP_T *ace = &aceint->prop;
658 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
659 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
660 ace->aceType, ace->flags, ace->aceFlags,
661 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
663 if (ace->flags == aceNew->flags &&
664 ace->aceType==aceNew->aceType &&
665 ace->aceFlags==aceNew->aceFlags)
667 /* keep type safety; e.g. gid is an u.short */
668 if (ace->flags & SMB_ACE4_ID_SPECIAL)
670 if (ace->who.special_id ==
671 aceNew->who.special_id)
674 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
676 if (ace->who.gid==aceNew->who.gid)
679 if (ace->who.uid==aceNew->who.uid)
689 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
690 struct SMB4ACL_T *theacl,
695 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
700 case e_merge: /* "merge" flags */
702 ace4found->aceFlags |= ace->aceFlags;
703 ace4found->aceMask |= ace->aceMask;
705 case e_ignore: /* leave out this record */
708 case e_reject: /* do an error */
709 DBG_INFO("ACL rejected by duplicate nt ace.\n");
710 errno = EINVAL; /* SHOULD be set on any _real_ error */
720 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
721 struct SMB4ACL_T *nfs4_acl,
722 SMB_ACE4PROP_T *nfs4_ace)
726 if (acedup != e_dontcare) {
729 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
737 smb_add_ace4(nfs4_acl, nfs4_ace);
743 static int nfs4_acl_add_sec_ace(bool is_directory,
744 const struct smbacl4_vfs_params *params,
747 const struct security_ace *ace_nt,
748 struct SMB4ACL_T *nfs4_acl)
750 struct dom_sid_buf buf;
751 SMB_ACE4PROP_T nfs4_ace = { 0 };
752 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
753 bool add_ace2 = false;
756 DEBUG(10, ("got ace for %s\n",
757 dom_sid_str_buf(&ace_nt->trustee, &buf)));
759 /* only ACCESS|DENY supported right now */
760 nfs4_ace.aceType = ace_nt->type;
763 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
765 /* remove inheritance flags on files */
767 DEBUG(10, ("Removing inheritance flags from a file\n"));
768 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
769 SMB_ACE4_DIRECTORY_INHERIT_ACE|
770 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
771 SMB_ACE4_INHERIT_ONLY_ACE);
774 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
776 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
778 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
779 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
780 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
781 } else if (params->mode!=e_special &&
782 dom_sid_equal(&ace_nt->trustee,
783 &global_sid_Creator_Owner)) {
784 DEBUG(10, ("Map creator owner\n"));
785 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
786 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
787 /* A non inheriting creator owner entry has no effect. */
788 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
789 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
790 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
793 } else if (params->mode!=e_special &&
794 dom_sid_equal(&ace_nt->trustee,
795 &global_sid_Creator_Group)) {
796 DEBUG(10, ("Map creator owner group\n"));
797 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
798 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
799 /* A non inheriting creator group entry has no effect. */
800 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
801 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
802 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
806 struct unixid unixid;
809 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
811 DBG_WARNING("Could not convert %s to uid or gid.\n",
812 dom_sid_str_buf(&ace_nt->trustee, &buf));
816 if (dom_sid_compare_domain(&ace_nt->trustee,
817 &global_sid_Unix_NFS) == 0) {
821 switch (unixid.type) {
823 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
824 nfs4_ace.who.gid = unixid.id;
826 if (ownerUID == unixid.id &&
827 !nfs_ace_is_inherit(&nfs4_ace))
830 * IDMAP_TYPE_BOTH for owner. Add
831 * additional user entry, which can be
832 * mapped to special:owner to reflect
833 * the permissions in the modebits.
835 * This only applies to non-inheriting
836 * entries as only these are replaced
837 * with SPECIAL_OWNER in nfs4:mode=simple.
839 nfs4_ace_2 = (SMB_ACE4PROP_T) {
840 .who.uid = unixid.id,
841 .aceFlags = (nfs4_ace.aceFlags &
842 ~SMB_ACE4_IDENTIFIER_GROUP),
843 .aceMask = nfs4_ace.aceMask,
844 .aceType = nfs4_ace.aceType,
850 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
851 nfs4_ace.who.gid = unixid.id;
854 nfs4_ace.who.uid = unixid.id;
856 case ID_TYPE_NOT_SPECIFIED:
858 DBG_WARNING("Could not convert %s to uid or gid.\n",
859 dom_sid_str_buf(&ace_nt->trustee, &buf));
864 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
873 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
876 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
880 struct SMB4ACE_T *aceint;
882 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
883 SMB_ACE4PROP_T *ace = &aceint->prop;
885 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
886 "mask: %x, who: %d\n",
887 ace->aceType, ace->flags, ace->aceFlags,
888 ace->aceMask, ace->who.id));
890 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
891 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
892 ace->who.uid == ownerUID) {
893 ace->flags |= SMB_ACE4_ID_SPECIAL;
894 ace->who.special_id = SMB_ACE4_WHO_OWNER;
895 DEBUG(10,("replaced with special owner ace\n"));
898 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
899 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
900 ace->who.uid == ownerGID) {
901 ace->flags |= SMB_ACE4_ID_SPECIAL;
902 ace->who.special_id = SMB_ACE4_WHO_GROUP;
903 DEBUG(10,("replaced with special group ace\n"));
908 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
912 struct SMB4ACE_T *aceint;
914 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
915 SMB_ACE4PROP_T *ace = &aceint->prop;
917 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
918 "mask: %x, who: %d\n",
919 ace->aceType, ace->flags, ace->aceFlags,
920 ace->aceMask, ace->who.id));
922 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
923 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
924 ace->who.uid == ownerUID &&
925 !nfs_ace_is_inherit(ace)) {
926 ace->flags |= SMB_ACE4_ID_SPECIAL;
927 ace->who.special_id = SMB_ACE4_WHO_OWNER;
928 DEBUG(10,("replaced with special owner ace\n"));
931 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
932 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
933 ace->who.gid == ownerGID &&
934 !nfs_ace_is_inherit(ace)) {
935 ace->flags |= SMB_ACE4_ID_SPECIAL;
936 ace->who.special_id = SMB_ACE4_WHO_GROUP;
937 DEBUG(10,("replaced with special group ace\n"));
942 static struct SMB4ACL_T *smbacl4_win2nfs4(
945 const struct security_acl *dacl,
946 const struct smbacl4_vfs_params *pparams,
951 struct SMB4ACL_T *theacl;
954 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
956 theacl = smb_create_smb4acl(mem_ctx);
960 for(i=0; i<dacl->num_aces; i++) {
963 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
965 dacl->aces + i, theacl);
971 if (pparams->mode==e_simple) {
972 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
975 if (pparams->mode==e_special) {
976 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
982 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
983 const struct smbacl4_vfs_params *pparams,
984 uint32_t security_info_sent,
985 const struct security_descriptor *psd,
986 set_nfs4acl_native_fn_t set_nfs4_native)
988 struct smbacl4_vfs_params params;
989 struct SMB4ACL_T *theacl = NULL;
990 bool result, is_directory;
992 bool set_acl_as_root = false;
995 TALLOC_CTX *frame = talloc_stackframe();
997 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
999 if ((security_info_sent & (SECINFO_DACL |
1000 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1002 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1003 security_info_sent));
1005 return NT_STATUS_OK; /* won't show error - later to be
1009 if (security_descriptor_with_ms_nfs(psd)) {
1011 return NT_STATUS_OK;
1014 if (pparams == NULL) {
1015 /* Special behaviours */
1016 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1018 return NT_STATUS_NO_MEMORY;
1023 status = vfs_stat_fsp(fsp);
1024 if (!NT_STATUS_IS_OK(status)) {
1029 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1031 if (pparams->do_chown) {
1033 * When the chown succeeds, the special entries in the
1034 * file system ACL refer to the new owner. In order to
1035 * apply the complete information from the DACL,
1036 * setting the ACL then has to succeed. Track this
1037 * case with set_acl_as_root and set the ACL as root
1040 status = chown_if_needed(fsp, security_info_sent, psd,
1042 if (!NT_STATUS_IS_OK(status)) {
1048 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1049 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1050 security_info_sent));
1052 return NT_STATUS_OK;
1055 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1056 fsp->fsp_name->st.st_ex_uid,
1057 fsp->fsp_name->st.st_ex_gid);
1060 return map_nt_error_from_unix(errno);
1063 smbacl4_set_controlflags(theacl, psd->type);
1064 smbacl4_dump_nfs4acl(10, theacl);
1066 if (set_acl_as_root) {
1069 result = set_nfs4_native(handle, fsp, theacl);
1070 saved_errno = errno;
1071 if (set_acl_as_root) {
1078 errno = saved_errno;
1079 DEBUG(10, ("set_nfs4_native failed with %s\n",
1081 return map_nt_error_from_unix(errno);
1084 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1085 return NT_STATUS_OK;