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 static 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 int nfs4_acl_lstat(struct vfs_handle_struct
*handle
,
229 struct smb_filename
*smb_fname
)
233 ret
= SMB_VFS_NEXT_LSTAT(handle
, smb_fname
);
234 if (ret
== -1 && errno
== EACCES
) {
235 DEBUG(10, ("Trying lstat with capability for %s\n",
236 smb_fname
->base_name
));
237 ret
= stat_with_cap_dac_override(handle
, smb_fname
,
238 AT_SYMLINK_NOFOLLOW
);
243 int nfs4_acl_fstatat(struct vfs_handle_struct
*handle
,
244 const struct files_struct
*dirfsp
,
245 const struct smb_filename
*smb_fname
,
246 SMB_STRUCT_STAT
*sbuf
,
251 ret
= SMB_VFS_NEXT_FSTATAT(handle
, dirfsp
, smb_fname
, sbuf
, flags
);
252 if (ret
== -1 && errno
== EACCES
) {
254 lp_fake_directory_create_times(SNUM(handle
->conn
));
256 DBG_DEBUG("fstatat for %s failed with EACCES. Trying with "
257 "CAP_DAC_OVERRIDE.\n", dirfsp
->fsp_name
->base_name
);
258 ret
= fstatat_with_cap_dac_override(fsp_get_pathref_fd(dirfsp
),
259 smb_fname
->base_name
,
268 /************************************************
269 Split the ACE flag mapping between nfs4 and Windows
270 into two separate functions rather than trying to do
271 it inline. Allows us to carefully control what flags
272 are mapped to what in one place.
273 ************************************************/
275 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
276 uint32_t nfs4_ace_flags
)
278 uint32_t win_ace_flags
= 0;
280 /* The nfs4 flags <= 0xf map perfectly. */
281 win_ace_flags
= nfs4_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
282 SEC_ACE_FLAG_CONTAINER_INHERIT
|
283 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
|
284 SEC_ACE_FLAG_INHERIT_ONLY
);
286 /* flags greater than 0xf have diverged :-(. */
287 /* See the nfs4 ace flag definitions here:
288 http://www.ietf.org/rfc/rfc3530.txt.
289 And the Windows ace flag definitions here:
290 librpc/idl/security.idl. */
291 if (nfs4_ace_flags
& SMB_ACE4_INHERITED_ACE
) {
292 win_ace_flags
|= SEC_ACE_FLAG_INHERITED_ACE
;
295 return win_ace_flags
;
298 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags
)
300 uint32_t nfs4_ace_flags
= 0;
302 /* The windows flags <= 0xf map perfectly. */
303 nfs4_ace_flags
= win_ace_flags
& (SMB_ACE4_FILE_INHERIT_ACE
|
304 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
305 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
306 SMB_ACE4_INHERIT_ONLY_ACE
);
308 /* flags greater than 0xf have diverged :-(. */
309 /* See the nfs4 ace flag definitions here:
310 http://www.ietf.org/rfc/rfc3530.txt.
311 And the Windows ace flag definitions here:
312 librpc/idl/security.idl. */
313 if (win_ace_flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
314 nfs4_ace_flags
|= SMB_ACE4_INHERITED_ACE
;
317 return nfs4_ace_flags
;
320 struct SMB4ACL_T
*smb_create_smb4acl(TALLOC_CTX
*mem_ctx
)
322 struct SMB4ACL_T
*theacl
;
324 theacl
= talloc_zero(mem_ctx
, struct SMB4ACL_T
);
327 DEBUG(0, ("TALLOC_SIZE failed\n"));
331 theacl
->controlflags
= SEC_DESC_SELF_RELATIVE
;
332 /* theacl->first, last = NULL not needed */
336 struct SMB4ACE_T
*smb_add_ace4(struct SMB4ACL_T
*acl
, SMB_ACE4PROP_T
*prop
)
338 struct SMB4ACE_T
*ace
;
340 ace
= talloc_zero(acl
, struct SMB4ACE_T
);
343 DBG_ERR("talloc_zero failed\n");
349 if (acl
->first
==NULL
)
354 acl
->last
->next
= ace
;
362 SMB_ACE4PROP_T
*smb_get_ace4(struct SMB4ACE_T
*ace
)
371 struct SMB4ACE_T
*smb_next_ace4(struct SMB4ACE_T
*ace
)
380 struct SMB4ACE_T
*smb_first_ace4(struct SMB4ACL_T
*acl
)
389 uint32_t smb_get_naces(struct SMB4ACL_T
*acl
)
398 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T
*acl
)
404 return acl
->controlflags
;
407 bool smbacl4_set_controlflags(struct SMB4ACL_T
*acl
, uint16_t controlflags
)
413 acl
->controlflags
= controlflags
;
417 bool nfs_ace_is_inherit(SMB_ACE4PROP_T
*ace
)
419 return ace
->aceFlags
& (SMB_ACE4_INHERIT_ONLY_ACE
|
420 SMB_ACE4_FILE_INHERIT_ACE
|
421 SMB_ACE4_DIRECTORY_INHERIT_ACE
);
424 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
425 const struct smb_filename
*smb_fname
,
426 SMB_STRUCT_STAT
*psbuf
)
430 /* Get the stat struct for the owner info. */
431 if (vfs_stat_smb_basename(conn
, smb_fname
, psbuf
) != 0)
433 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
441 static void check_for_duplicate_sec_ace(struct security_ace
*nt_ace_list
,
444 struct security_ace
*last
= NULL
;
447 if (*good_aces
< 2) {
451 last
= &nt_ace_list
[(*good_aces
) - 1];
453 for (i
= 0; i
< (*good_aces
) - 1; i
++) {
454 struct security_ace
*cur
= &nt_ace_list
[i
];
456 if (cur
->type
== last
->type
&&
457 cur
->flags
== last
->flags
&&
458 cur
->access_mask
== last
->access_mask
&&
459 dom_sid_equal(&cur
->trustee
, &last
->trustee
))
461 struct dom_sid_buf sid_buf
;
463 DBG_INFO("Removing duplicate entry for SID %s.\n",
464 dom_sid_str_buf(&last
->trustee
, &sid_buf
));
470 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
471 const struct smbacl4_vfs_params
*params
,
472 struct SMB4ACL_T
*acl
, /* in */
473 struct dom_sid
*psid_owner
, /* in */
474 struct dom_sid
*psid_group
, /* in */
475 bool is_directory
, /* in */
476 struct security_ace
**ppnt_ace_list
, /* out */
477 int *pgood_aces
/* out */
480 struct SMB4ACE_T
*aceint
;
481 struct security_ace
*nt_ace_list
= NULL
;
484 DEBUG(10, ("%s entered\n", __func__
));
486 nt_ace_list
= talloc_zero_array(mem_ctx
, struct security_ace
,
488 if (nt_ace_list
==NULL
)
490 DEBUG(10, ("talloc error with %d aces", acl
->naces
));
495 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
498 struct dom_sid_buf buf
;
499 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
500 uint32_t win_ace_flags
;
502 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
503 "mask: %x, who: %d\n",
504 ace
->aceType
, ace
->flags
,
505 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
507 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
508 switch (ace
->who
.special_id
) {
509 case SMB_ACE4_WHO_OWNER
:
510 sid_copy(&sid
, psid_owner
);
512 case SMB_ACE4_WHO_GROUP
:
513 sid_copy(&sid
, psid_group
);
515 case SMB_ACE4_WHO_EVERYONE
:
516 sid_copy(&sid
, &global_sid_World
);
519 DEBUG(8, ("invalid special who id %d "
520 "ignored\n", ace
->who
.special_id
));
524 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
525 gid_to_sid(&sid
, ace
->who
.gid
);
527 uid_to_sid(&sid
, ace
->who
.uid
);
530 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
531 dom_sid_str_buf(&sid
, &buf
)));
533 if (!is_directory
&& params
->map_full_control
) {
535 * Do we have all access except DELETE_CHILD
536 * (not caring about the delete bit).
538 uint32_t test_mask
= ((ace
->aceMask
|SMB_ACE4_DELETE
|SMB_ACE4_DELETE_CHILD
) &
540 if (test_mask
== SMB_ACE4_ALL_MASKS
) {
541 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
545 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
548 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
549 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
551 * GPFS sets inherits dir_inhert and file_inherit flags
552 * to files, too, which confuses windows, and seems to
553 * be wrong anyways. ==> Map these bits away for files.
555 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
556 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
557 SEC_ACE_FLAG_CONTAINER_INHERIT
);
559 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
560 ace
->aceFlags
, win_ace_flags
));
564 /* Mapping of owner@ and group@ to creator owner and
565 creator group. Keep old behavior in mode special. */
566 if (params
->mode
!= e_special
&&
567 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
568 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
569 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
570 DEBUG(10, ("Map special entry\n"));
571 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
572 uint32_t win_ace_flags_current
;
573 DEBUG(10, ("Map current sid\n"));
574 win_ace_flags_current
= win_ace_flags
&
575 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
576 SEC_ACE_FLAG_CONTAINER_INHERIT
);
577 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
579 win_ace_flags_current
);
581 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
582 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
583 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
584 uint32_t win_ace_flags_creator
;
585 DEBUG(10, ("Map creator owner\n"));
586 win_ace_flags_creator
= win_ace_flags
|
587 SMB_ACE4_INHERIT_ONLY_ACE
;
588 init_sec_ace(&nt_ace_list
[good_aces
++],
589 &global_sid_Creator_Owner
,
591 win_ace_flags_creator
);
593 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
594 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
595 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
596 uint32_t win_ace_flags_creator
;
597 DEBUG(10, ("Map creator owner group\n"));
598 win_ace_flags_creator
= win_ace_flags
|
599 SMB_ACE4_INHERIT_ONLY_ACE
;
600 init_sec_ace(&nt_ace_list
[good_aces
++],
601 &global_sid_Creator_Group
,
603 win_ace_flags_creator
);
606 DEBUG(10, ("Map normal sid\n"));
607 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
612 check_for_duplicate_sec_ace(nt_ace_list
, &good_aces
);
615 nt_ace_list
= talloc_realloc(mem_ctx
, nt_ace_list
, struct security_ace
,
618 /* returns a NULL ace list when good_aces is zero. */
619 if (good_aces
&& nt_ace_list
== NULL
) {
620 DEBUG(10, ("realloc error with %d aces", good_aces
));
625 *ppnt_ace_list
= nt_ace_list
;
626 *pgood_aces
= good_aces
;
631 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
632 const struct smbacl4_vfs_params
*params
,
633 uint32_t security_info
,
635 struct security_descriptor
**ppdesc
,
636 struct SMB4ACL_T
*theacl
)
639 struct dom_sid sid_owner
, sid_group
;
641 struct security_ace
*nt_ace_list
= NULL
;
642 struct security_acl
*psa
= NULL
;
643 TALLOC_CTX
*frame
= talloc_stackframe();
648 return NT_STATUS_ACCESS_DENIED
; /* special because we
649 * need to think through
653 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
654 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
656 ok
= smbacl4_nfs42win(frame
, params
, theacl
, &sid_owner
, &sid_group
,
657 S_ISDIR(sbuf
->st_ex_mode
),
658 &nt_ace_list
, &good_aces
);
660 DEBUG(8,("smbacl4_nfs42win failed\n"));
662 return map_nt_error_from_unix(errno
);
665 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
667 DEBUG(2,("make_sec_acl failed\n"));
669 return NT_STATUS_NO_MEMORY
;
672 DEBUG(10,("after make sec_acl\n"));
673 *ppdesc
= make_sec_desc(
674 mem_ctx
, SD_REVISION
, smbacl4_get_controlflags(theacl
),
675 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
676 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
677 NULL
, psa
, &sd_size
);
679 DEBUG(2,("make_sec_desc failed\n"));
681 return NT_STATUS_NO_MEMORY
;
684 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
686 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
692 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
693 const struct smbacl4_vfs_params
*pparams
,
694 uint32_t security_info
,
696 struct security_descriptor
**ppdesc
,
697 struct SMB4ACL_T
*theacl
)
699 struct smbacl4_vfs_params params
;
701 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
703 if (!VALID_STAT(fsp
->fsp_name
->st
)) {
706 status
= vfs_stat_fsp(fsp
);
707 if (!NT_STATUS_IS_OK(status
)) {
712 if (pparams
== NULL
) {
713 /* Special behaviours */
714 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
715 return NT_STATUS_NO_MEMORY
;
720 return smb_get_nt_acl_nfs4_common(&fsp
->fsp_name
->st
, pparams
,
722 mem_ctx
, ppdesc
, theacl
);
725 NTSTATUS
smb_get_nt_acl_nfs4(struct connection_struct
*conn
,
726 const struct smb_filename
*smb_fname
,
727 const struct smbacl4_vfs_params
*pparams
,
728 uint32_t security_info
,
730 struct security_descriptor
**ppdesc
,
731 struct SMB4ACL_T
*theacl
)
733 SMB_STRUCT_STAT sbuf
;
734 struct smbacl4_vfs_params params
;
735 const SMB_STRUCT_STAT
*psbuf
= NULL
;
737 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
738 smb_fname
->base_name
));
740 if (VALID_STAT(smb_fname
->st
)) {
741 psbuf
= &smb_fname
->st
;
745 if (smbacl4_GetFileOwner(conn
, smb_fname
, &sbuf
)) {
746 return map_nt_error_from_unix(errno
);
751 if (pparams
== NULL
) {
752 /* Special behaviours */
753 if (smbacl4_get_vfs_params(conn
, ¶ms
)) {
754 return NT_STATUS_NO_MEMORY
;
759 return smb_get_nt_acl_nfs4_common(psbuf
, pparams
, security_info
,
760 mem_ctx
, ppdesc
, theacl
);
763 static void smbacl4_dump_nfs4acl(int level
, struct SMB4ACL_T
*acl
)
765 struct SMB4ACE_T
*aceint
;
767 DEBUG(level
, ("NFS4ACL: size=%d\n", acl
->naces
));
769 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
770 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
772 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
773 "mask=0x%x, id=%d\n",
775 ace
->aceFlags
, ace
->flags
,
782 * Find 2 NFS4 who-special ACE property (non-copy!!!)
783 * match nonzero if "special" and who is equal
784 * return ace if found matching; otherwise NULL
786 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
787 struct SMB4ACL_T
*acl
,
788 SMB_ACE4PROP_T
*aceNew
)
790 struct SMB4ACE_T
*aceint
;
792 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
793 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
795 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
796 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
797 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
798 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
800 if (ace
->flags
== aceNew
->flags
&&
801 ace
->aceType
==aceNew
->aceType
&&
802 ace
->aceFlags
==aceNew
->aceFlags
)
804 /* keep type safety; e.g. gid is an u.short */
805 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
807 if (ace
->who
.special_id
==
808 aceNew
->who
.special_id
)
811 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
813 if (ace
->who
.gid
==aceNew
->who
.gid
)
816 if (ace
->who
.uid
==aceNew
->who
.uid
)
826 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup
,
827 struct SMB4ACL_T
*theacl
,
832 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
837 case e_merge
: /* "merge" flags */
839 ace4found
->aceFlags
|= ace
->aceFlags
;
840 ace4found
->aceMask
|= ace
->aceMask
;
842 case e_ignore
: /* leave out this record */
845 case e_reject
: /* do an error */
846 DBG_INFO("ACL rejected by duplicate nt ace.\n");
847 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
857 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup
,
858 struct SMB4ACL_T
*nfs4_acl
,
859 SMB_ACE4PROP_T
*nfs4_ace
)
863 if (acedup
!= e_dontcare
) {
866 ret
= smbacl4_MergeIgnoreReject(acedup
, nfs4_acl
,
874 smb_add_ace4(nfs4_acl
, nfs4_ace
);
880 static int nfs4_acl_add_sec_ace(bool is_directory
,
881 const struct smbacl4_vfs_params
*params
,
884 const struct security_ace
*ace_nt
,
885 struct SMB4ACL_T
*nfs4_acl
)
887 struct dom_sid_buf buf
;
888 SMB_ACE4PROP_T nfs4_ace
= { 0 };
889 SMB_ACE4PROP_T nfs4_ace_2
= { 0 };
890 bool add_ace2
= false;
893 DEBUG(10, ("got ace for %s\n",
894 dom_sid_str_buf(&ace_nt
->trustee
, &buf
)));
896 /* only ACCESS|DENY supported right now */
897 nfs4_ace
.aceType
= ace_nt
->type
;
900 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt
->flags
);
902 /* remove inheritance flags on files */
904 DEBUG(10, ("Removing inheritance flags from a file\n"));
905 nfs4_ace
.aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
906 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
907 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
908 SMB_ACE4_INHERIT_ONLY_ACE
);
911 nfs4_ace
.aceMask
= ace_nt
->access_mask
& (SEC_STD_ALL
| SEC_FILE_ALL
);
913 se_map_generic(&nfs4_ace
.aceMask
, &file_generic_mapping
);
915 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
916 nfs4_ace
.who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
917 nfs4_ace
.flags
|= SMB_ACE4_ID_SPECIAL
;
918 } else if (params
->mode
!=e_special
&&
919 dom_sid_equal(&ace_nt
->trustee
,
920 &global_sid_Creator_Owner
)) {
921 DEBUG(10, ("Map creator owner\n"));
922 nfs4_ace
.who
.special_id
= SMB_ACE4_WHO_OWNER
;
923 nfs4_ace
.flags
|= SMB_ACE4_ID_SPECIAL
;
924 /* A non inheriting creator owner entry has no effect. */
925 nfs4_ace
.aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
926 if (!(nfs4_ace
.aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
927 && !(nfs4_ace
.aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
930 } else if (params
->mode
!=e_special
&&
931 dom_sid_equal(&ace_nt
->trustee
,
932 &global_sid_Creator_Group
)) {
933 DEBUG(10, ("Map creator owner group\n"));
934 nfs4_ace
.who
.special_id
= SMB_ACE4_WHO_GROUP
;
935 nfs4_ace
.flags
|= SMB_ACE4_ID_SPECIAL
;
936 /* A non inheriting creator group entry has no effect. */
937 nfs4_ace
.aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
938 if (!(nfs4_ace
.aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
939 && !(nfs4_ace
.aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
943 struct unixid unixid
;
946 ok
= sids_to_unixids(&ace_nt
->trustee
, 1, &unixid
);
948 DBG_WARNING("Could not convert %s to uid or gid.\n",
949 dom_sid_str_buf(&ace_nt
->trustee
, &buf
));
953 if (dom_sid_compare_domain(&ace_nt
->trustee
,
954 &global_sid_Unix_NFS
) == 0) {
958 switch (unixid
.type
) {
960 nfs4_ace
.aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
961 nfs4_ace
.who
.gid
= unixid
.id
;
963 if (ownerUID
== unixid
.id
&&
964 !nfs_ace_is_inherit(&nfs4_ace
))
967 * IDMAP_TYPE_BOTH for owner. Add
968 * additional user entry, which can be
969 * mapped to special:owner to reflect
970 * the permissions in the modebits.
972 * This only applies to non-inheriting
973 * entries as only these are replaced
974 * with SPECIAL_OWNER in nfs4:mode=simple.
976 nfs4_ace_2
= (SMB_ACE4PROP_T
) {
977 .who
.uid
= unixid
.id
,
978 .aceFlags
= (nfs4_ace
.aceFlags
&
979 ~SMB_ACE4_IDENTIFIER_GROUP
),
980 .aceMask
= nfs4_ace
.aceMask
,
981 .aceType
= nfs4_ace
.aceType
,
987 nfs4_ace
.aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
988 nfs4_ace
.who
.gid
= unixid
.id
;
991 nfs4_ace
.who
.uid
= unixid
.id
;
993 case ID_TYPE_NOT_SPECIFIED
:
995 DBG_WARNING("Could not convert %s to uid or gid.\n",
996 dom_sid_str_buf(&ace_nt
->trustee
, &buf
));
1001 ret
= nfs4_acl_add_ace(params
->acedup
, nfs4_acl
, &nfs4_ace
);
1010 return nfs4_acl_add_ace(params
->acedup
, nfs4_acl
, &nfs4_ace_2
);
1013 static void smbacl4_substitute_special(struct SMB4ACL_T
*acl
,
1017 struct SMB4ACE_T
*aceint
;
1019 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
1020 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
1022 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1023 "mask: %x, who: %d\n",
1024 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
1025 ace
->aceMask
, ace
->who
.id
));
1027 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
1028 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
1029 ace
->who
.uid
== ownerUID
) {
1030 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
1031 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
1032 DEBUG(10,("replaced with special owner ace\n"));
1035 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
1036 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
1037 ace
->who
.uid
== ownerGID
) {
1038 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
1039 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
1040 DEBUG(10,("replaced with special group ace\n"));
1045 static void smbacl4_substitute_simple(struct SMB4ACL_T
*acl
,
1049 struct SMB4ACE_T
*aceint
;
1051 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
1052 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
1054 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1055 "mask: %x, who: %d\n",
1056 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
1057 ace
->aceMask
, ace
->who
.id
));
1059 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
1060 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
1061 ace
->who
.uid
== ownerUID
&&
1062 !nfs_ace_is_inherit(ace
)) {
1063 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
1064 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
1065 DEBUG(10,("replaced with special owner ace\n"));
1068 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
1069 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
1070 ace
->who
.gid
== ownerGID
&&
1071 !nfs_ace_is_inherit(ace
)) {
1072 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
1073 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
1074 DEBUG(10,("replaced with special group ace\n"));
1079 static struct SMB4ACL_T
*smbacl4_win2nfs4(
1080 TALLOC_CTX
*mem_ctx
,
1082 const struct security_acl
*dacl
,
1083 const struct smbacl4_vfs_params
*pparams
,
1088 struct SMB4ACL_T
*theacl
;
1091 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1093 theacl
= smb_create_smb4acl(mem_ctx
);
1097 for(i
=0; i
<dacl
->num_aces
; i
++) {
1100 ret
= nfs4_acl_add_sec_ace(is_directory
, pparams
,
1102 dacl
->aces
+ i
, theacl
);
1108 if (pparams
->mode
==e_simple
) {
1109 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
1112 if (pparams
->mode
==e_special
) {
1113 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
1119 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
1120 const struct smbacl4_vfs_params
*pparams
,
1121 uint32_t security_info_sent
,
1122 const struct security_descriptor
*psd
,
1123 set_nfs4acl_native_fn_t set_nfs4_native
)
1125 struct smbacl4_vfs_params params
;
1126 struct SMB4ACL_T
*theacl
= NULL
;
1127 bool result
, is_directory
;
1129 bool set_acl_as_root
= false;
1132 TALLOC_CTX
*frame
= talloc_stackframe();
1134 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
1136 if ((security_info_sent
& (SECINFO_DACL
|
1137 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
1139 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1140 security_info_sent
));
1142 return NT_STATUS_OK
; /* won't show error - later to be
1146 if (security_descriptor_with_ms_nfs(psd
)) {
1148 return NT_STATUS_OK
;
1151 if (pparams
== NULL
) {
1152 /* Special behaviours */
1153 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
1155 return NT_STATUS_NO_MEMORY
;
1160 status
= vfs_stat_fsp(fsp
);
1161 if (!NT_STATUS_IS_OK(status
)) {
1166 is_directory
= S_ISDIR(fsp
->fsp_name
->st
.st_ex_mode
);
1168 if (pparams
->do_chown
) {
1170 * When the chown succeeds, the special entries in the
1171 * file system ACL refer to the new owner. In order to
1172 * apply the complete information from the DACL,
1173 * setting the ACL then has to succeed. Track this
1174 * case with set_acl_as_root and set the ACL as root
1177 status
= chown_if_needed(fsp
, security_info_sent
, psd
,
1179 if (!NT_STATUS_IS_OK(status
)) {
1185 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
1186 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1187 security_info_sent
));
1189 return NT_STATUS_OK
;
1192 theacl
= smbacl4_win2nfs4(frame
, is_directory
, psd
->dacl
, pparams
,
1193 fsp
->fsp_name
->st
.st_ex_uid
,
1194 fsp
->fsp_name
->st
.st_ex_gid
);
1197 return map_nt_error_from_unix(errno
);
1200 smbacl4_set_controlflags(theacl
, psd
->type
);
1201 smbacl4_dump_nfs4acl(10, theacl
);
1203 if (set_acl_as_root
) {
1206 result
= set_nfs4_native(handle
, fsp
, theacl
);
1207 saved_errno
= errno
;
1208 if (set_acl_as_root
) {
1215 errno
= saved_errno
;
1216 DEBUG(10, ("set_nfs4_native failed with %s\n",
1218 return map_nt_error_from_unix(errno
);
1221 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1222 return NT_STATUS_OK
;