4 * Copyright (C) Jim McDonough, 2006
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 3 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "smbd/smbd.h"
22 #include "nfs4_acls.h"
23 #include "librpc/gen_ndr/ndr_security.h"
24 #include "librpc/gen_ndr/idmap.h"
25 #include "../libcli/security/dom_sid.h"
26 #include "../libcli/security/security.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "system/filesys.h"
30 #include "passdb/lookup_sid.h"
32 #include "lib/param/loadparm.h"
35 #define DBGC_CLASS DBGC_ACLS
37 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
39 extern const struct generic_mapping file_generic_mapping;
44 struct SMB4ACE_T *next;
49 uint16_t controlflags;
51 struct SMB4ACE_T *first;
52 struct SMB4ACE_T *last;
56 * Gather special parameters for NFS4 ACL handling
58 int smbacl4_get_vfs_params(struct connection_struct *conn,
59 struct smbacl4_vfs_params *params)
61 static const struct enum_list enum_smbacl4_modes[] = {
62 { e_simple, "simple" },
63 { e_special, "special" },
66 static const struct enum_list enum_smbacl4_acedups[] = {
67 { e_dontcare, "dontcare" },
68 { e_reject, "reject" },
69 { e_ignore, "ignore" },
75 *params = (struct smbacl4_vfs_params) { 0 };
77 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
78 enum_smbacl4_modes, e_simple);
80 DEBUG(10, ("value for %s:mode unknown\n",
81 SMBACL4_PARAM_TYPE_NAME));
84 params->mode = (enum smbacl4_mode_enum)enumval;
85 if (params->mode == e_special) {
86 DBG_WARNING("nfs4:mode special is deprecated.\n");
89 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
92 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
93 enum_smbacl4_acedups, e_dontcare);
95 DEBUG(10, ("value for %s:acedup unknown\n",
96 SMBACL4_PARAM_TYPE_NAME));
99 params->acedup = (enum smbacl4_acedup_enum)enumval;
101 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
103 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
104 enum_smbacl4_modes[params->mode].name,
105 params->do_chown ? "true" : "false",
106 enum_smbacl4_acedups[params->acedup].name,
107 params->map_full_control ? "true" : "false"));
112 /************************************************
113 Split the ACE flag mapping between nfs4 and Windows
114 into two separate functions rather than trying to do
115 it inline. Allows us to carefully control what flags
116 are mapped to what in one place.
117 ************************************************/
119 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
120 uint32_t nfs4_ace_flags)
122 uint32_t win_ace_flags = 0;
124 /* The nfs4 flags <= 0xf map perfectly. */
125 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
126 SEC_ACE_FLAG_CONTAINER_INHERIT|
127 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
128 SEC_ACE_FLAG_INHERIT_ONLY);
130 /* flags greater than 0xf have diverged :-(. */
131 /* See the nfs4 ace flag definitions here:
132 http://www.ietf.org/rfc/rfc3530.txt.
133 And the Windows ace flag definitions here:
134 librpc/idl/security.idl. */
135 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
136 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
139 return win_ace_flags;
142 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
144 uint32_t nfs4_ace_flags = 0;
146 /* The windows flags <= 0xf map perfectly. */
147 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
148 SMB_ACE4_DIRECTORY_INHERIT_ACE|
149 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
150 SMB_ACE4_INHERIT_ONLY_ACE);
152 /* flags greater than 0xf have diverged :-(. */
153 /* See the nfs4 ace flag definitions here:
154 http://www.ietf.org/rfc/rfc3530.txt.
155 And the Windows ace flag definitions here:
156 librpc/idl/security.idl. */
157 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
158 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
161 return nfs4_ace_flags;
164 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
166 struct SMB4ACL_T *theacl;
168 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
171 DEBUG(0, ("TALLOC_SIZE failed\n"));
175 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
176 /* theacl->first, last = NULL not needed */
180 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
182 struct SMB4ACE_T *ace;
184 ace = talloc_zero(acl, struct SMB4ACE_T);
187 DBG_ERR("talloc_zero failed\n");
193 if (acl->first==NULL)
198 acl->last->next = ace;
206 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
215 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
224 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
233 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
242 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
248 return acl->controlflags;
251 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
257 acl->controlflags = controlflags;
261 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
263 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
264 SMB_ACE4_FILE_INHERIT_ACE|
265 SMB_ACE4_DIRECTORY_INHERIT_ACE);
268 static int smbacl4_GetFileOwner(struct connection_struct *conn,
269 const struct smb_filename *smb_fname,
270 SMB_STRUCT_STAT *psbuf)
274 /* Get the stat struct for the owner info. */
275 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
277 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
285 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
289 if (fsp->fh->fd == -1) {
290 return smbacl4_GetFileOwner(fsp->conn,
291 fsp->fsp_name, psbuf);
293 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
295 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
303 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
306 struct security_ace *last = NULL;
309 if (*good_aces < 2) {
313 last = &nt_ace_list[(*good_aces) - 1];
315 for (i = 0; i < (*good_aces) - 1; i++) {
316 struct security_ace *cur = &nt_ace_list[i];
318 if (cur->type == last->type &&
319 cur->flags == last->flags &&
320 cur->access_mask == last->access_mask &&
321 dom_sid_equal(&cur->trustee, &last->trustee))
323 struct dom_sid_buf sid_buf;
325 DBG_INFO("Removing duplicate entry for SID %s.\n",
326 dom_sid_str_buf(&last->trustee, &sid_buf));
332 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
333 const struct smbacl4_vfs_params *params,
334 struct SMB4ACL_T *acl, /* in */
335 struct dom_sid *psid_owner, /* in */
336 struct dom_sid *psid_group, /* in */
337 bool is_directory, /* in */
338 struct security_ace **ppnt_ace_list, /* out */
339 int *pgood_aces /* out */
342 struct SMB4ACE_T *aceint;
343 struct security_ace *nt_ace_list = NULL;
346 DEBUG(10, ("%s entered\n", __func__));
348 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
350 if (nt_ace_list==NULL)
352 DEBUG(10, ("talloc error with %d aces", acl->naces));
357 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
360 struct dom_sid_buf buf;
361 SMB_ACE4PROP_T *ace = &aceint->prop;
362 uint32_t win_ace_flags;
364 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
365 "mask: %x, who: %d\n",
366 ace->aceType, ace->flags,
367 ace->aceFlags, ace->aceMask, ace->who.id));
369 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
370 switch (ace->who.special_id) {
371 case SMB_ACE4_WHO_OWNER:
372 sid_copy(&sid, psid_owner);
374 case SMB_ACE4_WHO_GROUP:
375 sid_copy(&sid, psid_group);
377 case SMB_ACE4_WHO_EVERYONE:
378 sid_copy(&sid, &global_sid_World);
381 DEBUG(8, ("invalid special who id %d "
382 "ignored\n", ace->who.special_id));
386 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
387 gid_to_sid(&sid, ace->who.gid);
389 uid_to_sid(&sid, ace->who.uid);
392 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
393 dom_sid_str_buf(&sid, &buf)));
395 if (!is_directory && params->map_full_control) {
397 * Do we have all access except DELETE_CHILD
398 * (not caring about the delete bit).
400 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
402 if (test_mask == SMB_ACE4_ALL_MASKS) {
403 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
407 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
410 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
411 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
413 * GPFS sets inherits dir_inhert and file_inherit flags
414 * to files, too, which confuses windows, and seems to
415 * be wrong anyways. ==> Map these bits away for files.
417 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
418 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
419 SEC_ACE_FLAG_CONTAINER_INHERIT);
421 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
422 ace->aceFlags, win_ace_flags));
426 /* Mapping of owner@ and group@ to creator owner and
427 creator group. Keep old behavior in mode special. */
428 if (params->mode != e_special &&
429 ace->flags & SMB_ACE4_ID_SPECIAL &&
430 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
431 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
432 DEBUG(10, ("Map special entry\n"));
433 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
434 uint32_t win_ace_flags_current;
435 DEBUG(10, ("Map current sid\n"));
436 win_ace_flags_current = win_ace_flags &
437 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
438 SEC_ACE_FLAG_CONTAINER_INHERIT);
439 init_sec_ace(&nt_ace_list[good_aces++], &sid,
441 win_ace_flags_current);
443 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
444 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
445 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
446 uint32_t win_ace_flags_creator;
447 DEBUG(10, ("Map creator owner\n"));
448 win_ace_flags_creator = win_ace_flags |
449 SMB_ACE4_INHERIT_ONLY_ACE;
450 init_sec_ace(&nt_ace_list[good_aces++],
451 &global_sid_Creator_Owner,
453 win_ace_flags_creator);
455 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
456 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
457 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
458 uint32_t win_ace_flags_creator;
459 DEBUG(10, ("Map creator owner group\n"));
460 win_ace_flags_creator = win_ace_flags |
461 SMB_ACE4_INHERIT_ONLY_ACE;
462 init_sec_ace(&nt_ace_list[good_aces++],
463 &global_sid_Creator_Group,
465 win_ace_flags_creator);
468 DEBUG(10, ("Map normal sid\n"));
469 init_sec_ace(&nt_ace_list[good_aces++], &sid,
474 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
477 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
480 /* returns a NULL ace list when good_aces is zero. */
481 if (good_aces && nt_ace_list == NULL) {
482 DEBUG(10, ("realloc error with %d aces", good_aces));
487 *ppnt_ace_list = nt_ace_list;
488 *pgood_aces = good_aces;
493 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
494 const struct smbacl4_vfs_params *params,
495 uint32_t security_info,
497 struct security_descriptor **ppdesc,
498 struct SMB4ACL_T *theacl)
501 struct dom_sid sid_owner, sid_group;
503 struct security_ace *nt_ace_list = NULL;
504 struct security_acl *psa = NULL;
505 TALLOC_CTX *frame = talloc_stackframe();
510 return NT_STATUS_ACCESS_DENIED; /* special because we
511 * need to think through
515 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
516 gid_to_sid(&sid_group, sbuf->st_ex_gid);
518 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
519 S_ISDIR(sbuf->st_ex_mode),
520 &nt_ace_list, &good_aces);
522 DEBUG(8,("smbacl4_nfs42win failed\n"));
524 return map_nt_error_from_unix(errno);
527 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
529 DEBUG(2,("make_sec_acl failed\n"));
531 return NT_STATUS_NO_MEMORY;
534 DEBUG(10,("after make sec_acl\n"));
535 *ppdesc = make_sec_desc(
536 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
537 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
538 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
539 NULL, psa, &sd_size);
541 DEBUG(2,("make_sec_desc failed\n"));
543 return NT_STATUS_NO_MEMORY;
546 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
548 (int)ndr_size_security_descriptor(*ppdesc, 0)));
554 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
555 const struct smbacl4_vfs_params *pparams,
556 uint32_t security_info,
558 struct security_descriptor **ppdesc,
559 struct SMB4ACL_T *theacl)
561 SMB_STRUCT_STAT sbuf;
562 struct smbacl4_vfs_params params;
563 SMB_STRUCT_STAT *psbuf = NULL;
565 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
567 if (VALID_STAT(fsp->fsp_name->st)) {
568 psbuf = &fsp->fsp_name->st;
572 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
573 return map_nt_error_from_unix(errno);
578 if (pparams == NULL) {
579 /* Special behaviours */
580 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
581 return NT_STATUS_NO_MEMORY;
586 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
587 mem_ctx, ppdesc, theacl);
590 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
591 const struct smb_filename *smb_fname,
592 const struct smbacl4_vfs_params *pparams,
593 uint32_t security_info,
595 struct security_descriptor **ppdesc,
596 struct SMB4ACL_T *theacl)
598 SMB_STRUCT_STAT sbuf;
599 struct smbacl4_vfs_params params;
600 const SMB_STRUCT_STAT *psbuf = NULL;
602 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
603 smb_fname->base_name));
605 if (VALID_STAT(smb_fname->st)) {
606 psbuf = &smb_fname->st;
610 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
611 return map_nt_error_from_unix(errno);
616 if (pparams == NULL) {
617 /* Special behaviours */
618 if (smbacl4_get_vfs_params(conn, ¶ms)) {
619 return NT_STATUS_NO_MEMORY;
624 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
625 mem_ctx, ppdesc, theacl);
628 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
630 struct SMB4ACE_T *aceint;
632 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
634 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
635 SMB_ACE4PROP_T *ace = &aceint->prop;
637 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
638 "mask=0x%x, id=%d\n",
640 ace->aceFlags, ace->flags,
647 * Find 2 NFS4 who-special ACE property (non-copy!!!)
648 * match nonzero if "special" and who is equal
649 * return ace if found matching; otherwise NULL
651 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
652 struct SMB4ACL_T *acl,
653 SMB_ACE4PROP_T *aceNew)
655 struct SMB4ACE_T *aceint;
657 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
658 SMB_ACE4PROP_T *ace = &aceint->prop;
660 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
661 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
662 ace->aceType, ace->flags, ace->aceFlags,
663 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
665 if (ace->flags == aceNew->flags &&
666 ace->aceType==aceNew->aceType &&
667 ace->aceFlags==aceNew->aceFlags)
669 /* keep type safety; e.g. gid is an u.short */
670 if (ace->flags & SMB_ACE4_ID_SPECIAL)
672 if (ace->who.special_id ==
673 aceNew->who.special_id)
676 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
678 if (ace->who.gid==aceNew->who.gid)
681 if (ace->who.uid==aceNew->who.uid)
691 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
692 struct SMB4ACL_T *theacl,
697 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
702 case e_merge: /* "merge" flags */
704 ace4found->aceFlags |= ace->aceFlags;
705 ace4found->aceMask |= ace->aceMask;
707 case e_ignore: /* leave out this record */
710 case e_reject: /* do an error */
711 DBG_INFO("ACL rejected by duplicate nt ace.\n");
712 errno = EINVAL; /* SHOULD be set on any _real_ error */
722 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
723 struct SMB4ACL_T *nfs4_acl,
724 SMB_ACE4PROP_T *nfs4_ace)
728 if (acedup != e_dontcare) {
731 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
739 smb_add_ace4(nfs4_acl, nfs4_ace);
745 static int nfs4_acl_add_sec_ace(bool is_directory,
746 const struct smbacl4_vfs_params *params,
749 const struct security_ace *ace_nt,
750 struct SMB4ACL_T *nfs4_acl)
752 struct dom_sid_buf buf;
753 SMB_ACE4PROP_T nfs4_ace = { 0 };
754 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
755 bool add_ace2 = false;
758 DEBUG(10, ("got ace for %s\n",
759 dom_sid_str_buf(&ace_nt->trustee, &buf)));
761 /* only ACCESS|DENY supported right now */
762 nfs4_ace.aceType = ace_nt->type;
765 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
767 /* remove inheritance flags on files */
769 DEBUG(10, ("Removing inheritance flags from a file\n"));
770 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
771 SMB_ACE4_DIRECTORY_INHERIT_ACE|
772 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
773 SMB_ACE4_INHERIT_ONLY_ACE);
776 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
778 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
780 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
781 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
782 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
783 } else if (params->mode!=e_special &&
784 dom_sid_equal(&ace_nt->trustee,
785 &global_sid_Creator_Owner)) {
786 DEBUG(10, ("Map creator owner\n"));
787 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
788 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
789 /* A non inheriting creator owner entry has no effect. */
790 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
791 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
792 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
795 } else if (params->mode!=e_special &&
796 dom_sid_equal(&ace_nt->trustee,
797 &global_sid_Creator_Group)) {
798 DEBUG(10, ("Map creator owner group\n"));
799 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
800 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
801 /* A non inheriting creator group entry has no effect. */
802 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
803 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
804 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
808 struct unixid unixid;
811 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
813 DBG_WARNING("Could not convert %s to uid or gid.\n",
814 dom_sid_str_buf(&ace_nt->trustee, &buf));
818 if (dom_sid_compare_domain(&ace_nt->trustee,
819 &global_sid_Unix_NFS) == 0) {
823 switch (unixid.type) {
825 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
826 nfs4_ace.who.gid = unixid.id;
828 if (ownerUID == unixid.id &&
829 !nfs_ace_is_inherit(&nfs4_ace))
832 * IDMAP_TYPE_BOTH for owner. Add
833 * additional user entry, which can be
834 * mapped to special:owner to reflect
835 * the permissions in the modebits.
837 * This only applies to non-inheriting
838 * entries as only these are replaced
839 * with SPECIAL_OWNER in nfs4:mode=simple.
841 nfs4_ace_2 = (SMB_ACE4PROP_T) {
842 .who.uid = unixid.id,
843 .aceFlags = (nfs4_ace.aceFlags &
844 ~SMB_ACE4_IDENTIFIER_GROUP),
845 .aceMask = nfs4_ace.aceMask,
846 .aceType = nfs4_ace.aceType,
852 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
853 nfs4_ace.who.gid = unixid.id;
856 nfs4_ace.who.uid = unixid.id;
858 case ID_TYPE_NOT_SPECIFIED:
860 DBG_WARNING("Could not convert %s to uid or gid.\n",
861 dom_sid_str_buf(&ace_nt->trustee, &buf));
866 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
875 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
878 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
882 struct SMB4ACE_T *aceint;
884 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
885 SMB_ACE4PROP_T *ace = &aceint->prop;
887 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
888 "mask: %x, who: %d\n",
889 ace->aceType, ace->flags, ace->aceFlags,
890 ace->aceMask, ace->who.id));
892 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
893 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
894 ace->who.uid == ownerUID) {
895 ace->flags |= SMB_ACE4_ID_SPECIAL;
896 ace->who.special_id = SMB_ACE4_WHO_OWNER;
897 DEBUG(10,("replaced with special owner ace\n"));
900 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
901 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
902 ace->who.uid == ownerGID) {
903 ace->flags |= SMB_ACE4_ID_SPECIAL;
904 ace->who.special_id = SMB_ACE4_WHO_GROUP;
905 DEBUG(10,("replaced with special group ace\n"));
910 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
914 struct SMB4ACE_T *aceint;
916 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
917 SMB_ACE4PROP_T *ace = &aceint->prop;
919 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
920 "mask: %x, who: %d\n",
921 ace->aceType, ace->flags, ace->aceFlags,
922 ace->aceMask, ace->who.id));
924 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
925 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
926 ace->who.uid == ownerUID &&
927 !nfs_ace_is_inherit(ace)) {
928 ace->flags |= SMB_ACE4_ID_SPECIAL;
929 ace->who.special_id = SMB_ACE4_WHO_OWNER;
930 DEBUG(10,("replaced with special owner ace\n"));
933 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
934 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
935 ace->who.gid == ownerGID &&
936 !nfs_ace_is_inherit(ace)) {
937 ace->flags |= SMB_ACE4_ID_SPECIAL;
938 ace->who.special_id = SMB_ACE4_WHO_GROUP;
939 DEBUG(10,("replaced with special group ace\n"));
944 static struct SMB4ACL_T *smbacl4_win2nfs4(
947 const struct security_acl *dacl,
948 const struct smbacl4_vfs_params *pparams,
953 struct SMB4ACL_T *theacl;
956 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
958 theacl = smb_create_smb4acl(mem_ctx);
962 for(i=0; i<dacl->num_aces; i++) {
965 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
967 dacl->aces + i, theacl);
973 if (pparams->mode==e_simple) {
974 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
977 if (pparams->mode==e_special) {
978 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
984 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
985 const struct smbacl4_vfs_params *pparams,
986 uint32_t security_info_sent,
987 const struct security_descriptor *psd,
988 set_nfs4acl_native_fn_t set_nfs4_native)
990 struct smbacl4_vfs_params params;
991 struct SMB4ACL_T *theacl = NULL;
992 bool result, is_directory;
994 bool set_acl_as_root = false;
995 uid_t newUID = (uid_t)-1;
996 gid_t newGID = (gid_t)-1;
999 TALLOC_CTX *frame = talloc_stackframe();
1001 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1003 if ((security_info_sent & (SECINFO_DACL |
1004 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1006 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1007 security_info_sent));
1009 return NT_STATUS_OK; /* won't show error - later to be
1013 if (pparams == NULL) {
1014 /* Special behaviours */
1015 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1017 return NT_STATUS_NO_MEMORY;
1022 status = vfs_stat_fsp(fsp);
1023 if (!NT_STATUS_IS_OK(status)) {
1028 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1030 if (pparams->do_chown) {
1031 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1033 uid_t old_uid = fsp->fsp_name->st.st_ex_uid;
1034 uid_t old_gid = fsp->fsp_name->st.st_ex_uid;
1035 status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1036 security_info_sent, psd);
1037 if (!NT_STATUS_IS_OK(status)) {
1038 DEBUG(8, ("unpack_nt_owners failed"));
1042 if (((newUID != (uid_t)-1) && (old_uid != newUID)) ||
1043 ((newGID != (gid_t)-1) && (old_gid != newGID)))
1045 status = try_chown(fsp, newUID, newGID);
1046 if (!NT_STATUS_IS_OK(status)) {
1047 DEBUG(3,("chown %s, %u, %u failed. Error = "
1048 "%s.\n", fsp_str_dbg(fsp),
1049 (unsigned int)newUID,
1050 (unsigned int)newGID,
1051 nt_errstr(status)));
1056 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1057 fsp_str_dbg(fsp), (unsigned int)newUID,
1058 (unsigned int)newGID));
1061 * Owner change, need to update stat info.
1063 status = vfs_stat_fsp(fsp);
1064 if (!NT_STATUS_IS_OK(status)) {
1069 /* If we successfully chowned, we know we must
1070 * be able to set the acl, so do it as root.
1072 set_acl_as_root = true;
1076 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1077 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1078 security_info_sent));
1080 return NT_STATUS_OK;
1083 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1084 fsp->fsp_name->st.st_ex_uid,
1085 fsp->fsp_name->st.st_ex_gid);
1088 return map_nt_error_from_unix(errno);
1091 smbacl4_set_controlflags(theacl, psd->type);
1092 smbacl4_dump_nfs4acl(10, theacl);
1094 if (set_acl_as_root) {
1097 result = set_nfs4_native(handle, fsp, theacl);
1098 saved_errno = errno;
1099 if (set_acl_as_root) {
1106 errno = saved_errno;
1107 DEBUG(10, ("set_nfs4_native failed with %s\n",
1109 return map_nt_error_from_unix(errno);
1112 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1113 return NT_STATUS_OK;