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 "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
31 #include "lib/param/loadparm.h"
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping
;
43 struct SMB4ACE_T
*next
;
48 uint16_t controlflags
;
50 struct SMB4ACE_T
*first
;
51 struct SMB4ACE_T
*last
;
54 enum smbacl4_mode_enum
{e_simple
=0, e_special
=1};
55 enum smbacl4_acedup_enum
{e_dontcare
=0, e_reject
=1, e_ignore
=2, e_merge
=3};
57 typedef struct _smbacl4_vfs_params
{
58 enum smbacl4_mode_enum mode
;
60 enum smbacl4_acedup_enum acedup
;
61 bool map_full_control
;
65 * Gather special parameters for NFS4 ACL handling
67 static int smbacl4_get_vfs_params(
68 struct connection_struct
*conn
,
69 smbacl4_vfs_params
*params
72 static const struct enum_list enum_smbacl4_modes
[] = {
73 { e_simple
, "simple" },
74 { e_special
, "special" },
77 static const struct enum_list enum_smbacl4_acedups
[] = {
78 { e_dontcare
, "dontcare" },
79 { e_reject
, "reject" },
80 { e_ignore
, "ignore" },
88 enumval
= lp_parm_enum(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
, "mode",
89 enum_smbacl4_modes
, e_simple
);
91 DEBUG(10, ("value for %s:mode unknown\n",
92 SMBACL4_PARAM_TYPE_NAME
));
95 params
->mode
= (enum smbacl4_mode_enum
)enumval
;
97 params
->do_chown
= lp_parm_bool(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
,
100 enumval
= lp_parm_enum(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
, "acedup",
101 enum_smbacl4_acedups
, e_dontcare
);
103 DEBUG(10, ("value for %s:acedup unknown\n",
104 SMBACL4_PARAM_TYPE_NAME
));
107 params
->acedup
= (enum smbacl4_acedup_enum
)enumval
;
109 params
->map_full_control
= lp_acl_map_full_control(SNUM(conn
));
111 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
112 enum_smbacl4_modes
[params
->mode
].name
,
113 params
->do_chown
? "true" : "false",
114 enum_smbacl4_acedups
[params
->acedup
].name
,
115 params
->map_full_control
? "true" : "false"));
120 /************************************************
121 Split the ACE flag mapping between nfs4 and Windows
122 into two separate functions rather than trying to do
123 it inline. Allows us to carefully control what flags
124 are mapped to what in one place.
125 ************************************************/
127 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
128 uint32_t nfs4_ace_flags
)
130 uint32_t win_ace_flags
= 0;
132 /* The nfs4 flags <= 0xf map perfectly. */
133 win_ace_flags
= nfs4_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
134 SEC_ACE_FLAG_CONTAINER_INHERIT
|
135 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
|
136 SEC_ACE_FLAG_INHERIT_ONLY
);
138 /* flags greater than 0xf have diverged :-(. */
139 /* See the nfs4 ace flag definitions here:
140 http://www.ietf.org/rfc/rfc3530.txt.
141 And the Windows ace flag definitions here:
142 librpc/idl/security.idl. */
143 if (nfs4_ace_flags
& SMB_ACE4_INHERITED_ACE
) {
144 win_ace_flags
|= SEC_ACE_FLAG_INHERITED_ACE
;
147 return win_ace_flags
;
150 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags
)
152 uint32_t nfs4_ace_flags
= 0;
154 /* The windows flags <= 0xf map perfectly. */
155 nfs4_ace_flags
= win_ace_flags
& (SMB_ACE4_FILE_INHERIT_ACE
|
156 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
157 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
158 SMB_ACE4_INHERIT_ONLY_ACE
);
160 /* flags greater than 0xf have diverged :-(. */
161 /* See the nfs4 ace flag definitions here:
162 http://www.ietf.org/rfc/rfc3530.txt.
163 And the Windows ace flag definitions here:
164 librpc/idl/security.idl. */
165 if (win_ace_flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
166 nfs4_ace_flags
|= SMB_ACE4_INHERITED_ACE
;
169 return nfs4_ace_flags
;
172 struct SMB4ACL_T
*smb_create_smb4acl(TALLOC_CTX
*mem_ctx
)
174 struct SMB4ACL_T
*theacl
;
176 theacl
= talloc_zero(mem_ctx
, struct SMB4ACL_T
);
179 DEBUG(0, ("TALLOC_SIZE failed\n"));
183 theacl
->controlflags
= SEC_DESC_SELF_RELATIVE
;
184 /* theacl->first, last = NULL not needed */
188 struct SMB4ACE_T
*smb_add_ace4(struct SMB4ACL_T
*acl
, SMB_ACE4PROP_T
*prop
)
190 struct SMB4ACE_T
*ace
;
192 ace
= talloc_zero(acl
, struct SMB4ACE_T
);
195 DEBUG(0, ("TALLOC_SIZE failed\n"));
199 /* ace->next = NULL not needed */
200 memcpy(&ace
->prop
, prop
, sizeof(SMB_ACE4PROP_T
));
202 if (acl
->first
==NULL
)
207 acl
->last
->next
= ace
;
215 SMB_ACE4PROP_T
*smb_get_ace4(struct SMB4ACE_T
*ace
)
224 struct SMB4ACE_T
*smb_next_ace4(struct SMB4ACE_T
*ace
)
233 struct SMB4ACE_T
*smb_first_ace4(struct SMB4ACL_T
*acl
)
242 uint32_t smb_get_naces(struct SMB4ACL_T
*acl
)
251 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T
*acl
)
257 return acl
->controlflags
;
260 bool smbacl4_set_controlflags(struct SMB4ACL_T
*acl
, uint16_t controlflags
)
266 acl
->controlflags
= controlflags
;
270 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
271 const struct smb_filename
*smb_fname
,
272 SMB_STRUCT_STAT
*psbuf
)
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn
, smb_fname
, psbuf
) != 0)
279 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
287 static int smbacl4_fGetFileOwner(files_struct
*fsp
, SMB_STRUCT_STAT
*psbuf
)
291 if (fsp
->fh
->fd
== -1) {
292 return smbacl4_GetFileOwner(fsp
->conn
,
293 fsp
->fsp_name
, psbuf
);
295 if (SMB_VFS_FSTAT(fsp
, psbuf
) != 0)
297 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
305 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
306 smbacl4_vfs_params
*params
,
307 struct SMB4ACL_T
*acl
, /* in */
308 struct dom_sid
*psid_owner
, /* in */
309 struct dom_sid
*psid_group
, /* in */
310 bool is_directory
, /* in */
311 struct security_ace
**ppnt_ace_list
, /* out */
312 int *pgood_aces
/* out */
315 struct SMB4ACE_T
*aceint
;
316 struct security_ace
*nt_ace_list
= NULL
;
319 DEBUG(10, ("%s entered\n", __func__
));
321 nt_ace_list
= talloc_zero_array(mem_ctx
, struct security_ace
,
323 if (nt_ace_list
==NULL
)
325 DEBUG(10, ("talloc error with %d aces", acl
->naces
));
330 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
333 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
334 uint32_t win_ace_flags
;
336 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
337 "mask: %x, who: %d\n",
338 ace
->aceType
, ace
->flags
,
339 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
341 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
342 switch (ace
->who
.special_id
) {
343 case SMB_ACE4_WHO_OWNER
:
344 sid_copy(&sid
, psid_owner
);
346 case SMB_ACE4_WHO_GROUP
:
347 sid_copy(&sid
, psid_group
);
349 case SMB_ACE4_WHO_EVERYONE
:
350 sid_copy(&sid
, &global_sid_World
);
353 DEBUG(8, ("invalid special who id %d "
354 "ignored\n", ace
->who
.special_id
));
358 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
359 gid_to_sid(&sid
, ace
->who
.gid
);
361 uid_to_sid(&sid
, ace
->who
.uid
);
364 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
365 sid_string_dbg(&sid
)));
367 if (is_directory
&& (ace
->aceMask
& SMB_ACE4_ADD_FILE
)) {
368 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
371 if (!is_directory
&& params
->map_full_control
) {
373 * Do we have all access except DELETE_CHILD
374 * (not caring about the delete bit).
376 uint32_t test_mask
= ((ace
->aceMask
|SMB_ACE4_DELETE
|SMB_ACE4_DELETE_CHILD
) &
378 if (test_mask
== SMB_ACE4_ALL_MASKS
) {
379 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
383 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
386 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
387 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
389 * GPFS sets inherits dir_inhert and file_inherit flags
390 * to files, too, which confuses windows, and seems to
391 * be wrong anyways. ==> Map these bits away for files.
393 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
395 SEC_ACE_FLAG_CONTAINER_INHERIT
);
397 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398 ace
->aceFlags
, win_ace_flags
));
401 /* Windows clients expect SYNC on acls to
402 correctly allow rename. See bug #7909. */
403 /* But not on DENY ace entries. See
405 if(ace
->aceType
== SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE
) {
406 mask
= ace
->aceMask
| SMB_ACE4_SYNCHRONIZE
;
409 /* Mapping of owner@ and group@ to creator owner and
410 creator group. Keep old behavior in mode special. */
411 if (params
->mode
!= e_special
&&
412 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
413 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
414 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
415 DEBUG(10, ("Map special entry\n"));
416 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
417 uint32_t win_ace_flags_current
;
418 DEBUG(10, ("Map current sid\n"));
419 win_ace_flags_current
= win_ace_flags
&
420 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
421 SEC_ACE_FLAG_CONTAINER_INHERIT
);
422 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
424 win_ace_flags_current
);
426 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
427 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
428 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
429 uint32_t win_ace_flags_creator
;
430 DEBUG(10, ("Map creator owner\n"));
431 win_ace_flags_creator
= win_ace_flags
|
432 SMB_ACE4_INHERIT_ONLY_ACE
;
433 init_sec_ace(&nt_ace_list
[good_aces
++],
434 &global_sid_Creator_Owner
,
436 win_ace_flags_creator
);
438 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
439 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
440 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
441 uint32_t win_ace_flags_creator
;
442 DEBUG(10, ("Map creator owner group\n"));
443 win_ace_flags_creator
= win_ace_flags
|
444 SMB_ACE4_INHERIT_ONLY_ACE
;
445 init_sec_ace(&nt_ace_list
[good_aces
++],
446 &global_sid_Creator_Group
,
448 win_ace_flags_creator
);
451 DEBUG(10, ("Map normal sid\n"));
452 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
458 nt_ace_list
= talloc_realloc(mem_ctx
, nt_ace_list
, struct security_ace
,
461 /* returns a NULL ace list when good_aces is zero. */
462 if (good_aces
&& nt_ace_list
== NULL
) {
463 DEBUG(10, ("realloc error with %d aces", good_aces
));
468 *ppnt_ace_list
= nt_ace_list
;
469 *pgood_aces
= good_aces
;
474 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
475 smbacl4_vfs_params
*params
,
476 uint32_t security_info
,
478 struct security_descriptor
**ppdesc
,
479 struct SMB4ACL_T
*theacl
)
482 struct dom_sid sid_owner
, sid_group
;
484 struct security_ace
*nt_ace_list
= NULL
;
485 struct security_acl
*psa
= NULL
;
486 TALLOC_CTX
*frame
= talloc_stackframe();
491 return NT_STATUS_ACCESS_DENIED
; /* special because we
492 * need to think through
496 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
497 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
499 ok
= smbacl4_nfs42win(frame
, params
, theacl
, &sid_owner
, &sid_group
,
500 S_ISDIR(sbuf
->st_ex_mode
),
501 &nt_ace_list
, &good_aces
);
503 DEBUG(8,("smbacl4_nfs42win failed\n"));
505 return map_nt_error_from_unix(errno
);
508 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
510 DEBUG(2,("make_sec_acl failed\n"));
512 return NT_STATUS_NO_MEMORY
;
515 DEBUG(10,("after make sec_acl\n"));
516 *ppdesc
= make_sec_desc(
517 mem_ctx
, SD_REVISION
, smbacl4_get_controlflags(theacl
),
518 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
519 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
520 NULL
, psa
, &sd_size
);
522 DEBUG(2,("make_sec_desc failed\n"));
524 return NT_STATUS_NO_MEMORY
;
527 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
529 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
535 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
536 uint32_t security_info
,
538 struct security_descriptor
**ppdesc
,
539 struct SMB4ACL_T
*theacl
)
541 SMB_STRUCT_STAT sbuf
;
542 smbacl4_vfs_params params
;
544 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
546 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
547 return map_nt_error_from_unix(errno
);
550 /* Special behaviours */
551 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
552 return NT_STATUS_NO_MEMORY
;
555 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
556 mem_ctx
, ppdesc
, theacl
);
559 NTSTATUS
smb_get_nt_acl_nfs4(struct connection_struct
*conn
,
560 const struct smb_filename
*smb_fname
,
561 uint32_t security_info
,
563 struct security_descriptor
**ppdesc
,
564 struct SMB4ACL_T
*theacl
)
566 SMB_STRUCT_STAT sbuf
;
567 smbacl4_vfs_params params
;
569 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
570 smb_fname
->base_name
));
572 if (smbacl4_GetFileOwner(conn
, smb_fname
, &sbuf
)) {
573 return map_nt_error_from_unix(errno
);
576 /* Special behaviours */
577 if (smbacl4_get_vfs_params(conn
, ¶ms
)) {
578 return NT_STATUS_NO_MEMORY
;
581 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
582 mem_ctx
, ppdesc
, theacl
);
585 static void smbacl4_dump_nfs4acl(int level
, struct SMB4ACL_T
*acl
)
587 struct SMB4ACE_T
*aceint
;
589 DEBUG(level
, ("NFS4ACL: size=%d\n", acl
->naces
));
591 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
592 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
594 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
595 "mask=0x%x, id=%d\n",
597 ace
->aceFlags
, ace
->flags
,
604 * Find 2 NFS4 who-special ACE property (non-copy!!!)
605 * match nonzero if "special" and who is equal
606 * return ace if found matching; otherwise NULL
608 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
609 struct SMB4ACL_T
*acl
,
610 SMB_ACE4PROP_T
*aceNew
)
612 struct SMB4ACE_T
*aceint
;
614 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
615 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
617 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
618 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
619 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
620 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
622 if (ace
->flags
== aceNew
->flags
&&
623 ace
->aceType
==aceNew
->aceType
&&
624 ace
->aceFlags
==aceNew
->aceFlags
)
626 /* keep type safety; e.g. gid is an u.short */
627 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
629 if (ace
->who
.special_id
==
630 aceNew
->who
.special_id
)
633 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
635 if (ace
->who
.gid
==aceNew
->who
.gid
)
638 if (ace
->who
.uid
==aceNew
->who
.uid
)
649 static bool smbacl4_fill_ace4(
650 const struct smb_filename
*filename
,
651 smbacl4_vfs_params
*params
,
654 const struct security_ace
*ace_nt
, /* input */
655 SMB_ACE4PROP_T
*ace_v4
/* output */
658 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt
->trustee
)));
660 ZERO_STRUCTP(ace_v4
);
662 /* only ACCESS|DENY supported right now */
663 ace_v4
->aceType
= ace_nt
->type
;
665 ace_v4
->aceFlags
= map_windows_ace_flags_to_nfs4_ace_flags(
668 /* remove inheritance flags on files */
669 if (VALID_STAT(filename
->st
) &&
670 !S_ISDIR(filename
->st
.st_ex_mode
)) {
671 DEBUG(10, ("Removing inheritance flags from a file\n"));
672 ace_v4
->aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
673 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
674 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
675 SMB_ACE4_INHERIT_ONLY_ACE
);
678 ace_v4
->aceMask
= ace_nt
->access_mask
&
679 (SEC_STD_ALL
| SEC_FILE_ALL
);
681 se_map_generic(&ace_v4
->aceMask
, &file_generic_mapping
);
683 if (ace_v4
->aceFlags
!=ace_nt
->flags
)
684 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
685 ace_v4
->aceFlags
, ace_nt
->flags
));
687 if (ace_v4
->aceMask
!=ace_nt
->access_mask
)
688 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
689 ace_v4
->aceMask
, ace_nt
->access_mask
));
691 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
692 ace_v4
->who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
693 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
694 } else if (params
->mode
!=e_special
&&
695 dom_sid_equal(&ace_nt
->trustee
,
696 &global_sid_Creator_Owner
)) {
697 DEBUG(10, ("Map creator owner\n"));
698 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
699 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
700 /* A non inheriting creator owner entry has no effect. */
701 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
702 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
703 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
706 } else if (params
->mode
!=e_special
&&
707 dom_sid_equal(&ace_nt
->trustee
,
708 &global_sid_Creator_Group
)) {
709 DEBUG(10, ("Map creator owner group\n"));
710 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
711 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
712 /* A non inheriting creator group entry has no effect. */
713 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
714 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
715 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
722 if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
723 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
724 ace_v4
->who
.gid
= gid
;
725 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
726 ace_v4
->who
.uid
= uid
;
727 } else if (dom_sid_compare_domain(&ace_nt
->trustee
,
728 &global_sid_Unix_NFS
) == 0) {
731 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
732 "convert %s to uid or gid\n",
734 sid_string_dbg(&ace_nt
->trustee
)));
739 return true; /* OK */
742 static int smbacl4_MergeIgnoreReject(
743 enum smbacl4_acedup_enum acedup
,
744 struct SMB4ACL_T
*theacl
, /* may modify it */
745 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
751 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
756 case e_merge
: /* "merge" flags */
758 ace4found
->aceFlags
|= ace
->aceFlags
;
759 ace4found
->aceMask
|= ace
->aceMask
;
761 case e_ignore
: /* leave out this record */
764 case e_reject
: /* do an error */
765 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
766 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
776 static int smbacl4_substitute_special(
777 struct SMB4ACL_T
*acl
,
782 struct SMB4ACE_T
*aceint
;
784 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
785 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
787 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
788 "mask: %x, who: %d\n",
789 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
790 ace
->aceMask
, ace
->who
.id
));
792 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
793 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
794 ace
->who
.uid
== ownerUID
) {
795 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
796 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
797 DEBUG(10,("replaced with special owner ace\n"));
800 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
801 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
802 ace
->who
.uid
== ownerGID
) {
803 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
804 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
805 DEBUG(10,("replaced with special group ace\n"));
808 return true; /* OK */
811 static int smbacl4_substitute_simple(
812 struct SMB4ACL_T
*acl
,
817 struct SMB4ACE_T
*aceint
;
819 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
820 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
822 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
823 "mask: %x, who: %d\n",
824 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
825 ace
->aceMask
, ace
->who
.id
));
827 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
828 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
829 ace
->who
.uid
== ownerUID
&&
830 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
831 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
832 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
833 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
834 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
835 DEBUG(10,("replaced with special owner ace\n"));
838 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
839 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
840 ace
->who
.uid
== ownerGID
&&
841 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
842 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
843 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
844 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
845 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
846 DEBUG(10,("replaced with special group ace\n"));
849 return true; /* OK */
852 static struct SMB4ACL_T
*smbacl4_win2nfs4(
854 const files_struct
*fsp
,
855 const struct security_acl
*dacl
,
856 smbacl4_vfs_params
*pparams
,
861 struct SMB4ACL_T
*theacl
;
863 const char *filename
= fsp
->fsp_name
->base_name
;
865 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
867 theacl
= smb_create_smb4acl(mem_ctx
);
871 for(i
=0; i
<dacl
->num_aces
; i
++) {
872 SMB_ACE4PROP_T ace_v4
;
873 bool addNewACE
= true;
875 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
877 dacl
->aces
+ i
, &ace_v4
)) {
878 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
880 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
884 if (pparams
->acedup
!=e_dontcare
) {
885 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
886 &ace_v4
, &addNewACE
, i
))
891 smb_add_ace4(theacl
, &ace_v4
);
894 if (pparams
->mode
==e_simple
) {
895 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
898 if (pparams
->mode
==e_special
) {
899 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
905 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
906 uint32_t security_info_sent
,
907 const struct security_descriptor
*psd
,
908 set_nfs4acl_native_fn_t set_nfs4_native
)
910 smbacl4_vfs_params params
;
911 struct SMB4ACL_T
*theacl
= NULL
;
914 SMB_STRUCT_STAT sbuf
;
915 bool set_acl_as_root
= false;
916 uid_t newUID
= (uid_t
)-1;
917 gid_t newGID
= (gid_t
)-1;
919 TALLOC_CTX
*frame
= talloc_stackframe();
921 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
923 if ((security_info_sent
& (SECINFO_DACL
|
924 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
926 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
927 security_info_sent
));
929 return NT_STATUS_OK
; /* won't show error - later to be
933 /* Special behaviours */
934 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
936 return NT_STATUS_NO_MEMORY
;
939 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
941 return map_nt_error_from_unix(errno
);
944 if (params
.do_chown
) {
945 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
946 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
947 security_info_sent
, psd
);
948 if (!NT_STATUS_IS_OK(status
)) {
949 DEBUG(8, ("unpack_nt_owners failed"));
953 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
954 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
956 status
= try_chown(fsp
, newUID
, newGID
);
957 if (!NT_STATUS_IS_OK(status
)) {
958 DEBUG(3,("chown %s, %u, %u failed. Error = "
959 "%s.\n", fsp_str_dbg(fsp
),
960 (unsigned int)newUID
,
961 (unsigned int)newGID
,
967 DEBUG(10,("chown %s, %u, %u succeeded.\n",
968 fsp_str_dbg(fsp
), (unsigned int)newUID
,
969 (unsigned int)newGID
));
970 if (smbacl4_GetFileOwner(fsp
->conn
,
974 return map_nt_error_from_unix(errno
);
977 /* If we successfully chowned, we know we must
978 * be able to set the acl, so do it as root.
980 set_acl_as_root
= true;
984 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
985 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
986 security_info_sent
));
991 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, ¶ms
,
992 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
995 return map_nt_error_from_unix(errno
);
998 smbacl4_set_controlflags(theacl
, psd
->type
);
999 smbacl4_dump_nfs4acl(10, theacl
);
1001 if (set_acl_as_root
) {
1004 result
= set_nfs4_native(handle
, fsp
, theacl
);
1005 saved_errno
= errno
;
1006 if (set_acl_as_root
) {
1013 errno
= saved_errno
;
1014 DEBUG(10, ("set_nfs4_native failed with %s\n",
1016 return map_nt_error_from_unix(errno
);
1019 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1020 return NT_STATUS_OK
;