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 char *filename
,
272 SMB_STRUCT_STAT
*psbuf
)
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn
, filename
, 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
->base_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
,
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", name
));
571 if (smbacl4_GetFileOwner(conn
, name
, &sbuf
)) {
572 return map_nt_error_from_unix(errno
);
575 /* Special behaviours */
576 if (smbacl4_get_vfs_params(conn
, ¶ms
)) {
577 return NT_STATUS_NO_MEMORY
;
580 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
581 mem_ctx
, ppdesc
, theacl
);
584 static void smbacl4_dump_nfs4acl(int level
, struct SMB4ACL_T
*acl
)
586 struct SMB4ACE_T
*aceint
;
588 DEBUG(level
, ("NFS4ACL: size=%d\n", acl
->naces
));
590 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
591 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
593 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
594 "mask=0x%x, id=%d\n",
596 ace
->aceFlags
, ace
->flags
,
603 * Find 2 NFS4 who-special ACE property (non-copy!!!)
604 * match nonzero if "special" and who is equal
605 * return ace if found matching; otherwise NULL
607 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
608 struct SMB4ACL_T
*acl
,
609 SMB_ACE4PROP_T
*aceNew
)
611 struct SMB4ACE_T
*aceint
;
613 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
614 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
616 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
617 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
618 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
619 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
621 if (ace
->flags
== aceNew
->flags
&&
622 ace
->aceType
==aceNew
->aceType
&&
623 ace
->aceFlags
==aceNew
->aceFlags
)
625 /* keep type safety; e.g. gid is an u.short */
626 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
628 if (ace
->who
.special_id
==
629 aceNew
->who
.special_id
)
632 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
634 if (ace
->who
.gid
==aceNew
->who
.gid
)
637 if (ace
->who
.uid
==aceNew
->who
.uid
)
648 static bool smbacl4_fill_ace4(
649 const struct smb_filename
*filename
,
650 smbacl4_vfs_params
*params
,
653 const struct security_ace
*ace_nt
, /* input */
654 SMB_ACE4PROP_T
*ace_v4
/* output */
657 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt
->trustee
)));
659 ZERO_STRUCTP(ace_v4
);
661 /* only ACCESS|DENY supported right now */
662 ace_v4
->aceType
= ace_nt
->type
;
664 ace_v4
->aceFlags
= map_windows_ace_flags_to_nfs4_ace_flags(
667 /* remove inheritance flags on files */
668 if (VALID_STAT(filename
->st
) &&
669 !S_ISDIR(filename
->st
.st_ex_mode
)) {
670 DEBUG(10, ("Removing inheritance flags from a file\n"));
671 ace_v4
->aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
672 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
673 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
674 SMB_ACE4_INHERIT_ONLY_ACE
);
677 ace_v4
->aceMask
= ace_nt
->access_mask
&
678 (SEC_STD_ALL
| SEC_FILE_ALL
);
680 se_map_generic(&ace_v4
->aceMask
, &file_generic_mapping
);
682 if (ace_v4
->aceFlags
!=ace_nt
->flags
)
683 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
684 ace_v4
->aceFlags
, ace_nt
->flags
));
686 if (ace_v4
->aceMask
!=ace_nt
->access_mask
)
687 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
688 ace_v4
->aceMask
, ace_nt
->access_mask
));
690 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
691 ace_v4
->who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
692 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
693 } else if (params
->mode
!=e_special
&&
694 dom_sid_equal(&ace_nt
->trustee
,
695 &global_sid_Creator_Owner
)) {
696 DEBUG(10, ("Map creator owner\n"));
697 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
698 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
699 /* A non inheriting creator owner entry has no effect. */
700 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
701 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
702 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
705 } else if (params
->mode
!=e_special
&&
706 dom_sid_equal(&ace_nt
->trustee
,
707 &global_sid_Creator_Group
)) {
708 DEBUG(10, ("Map creator owner group\n"));
709 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
710 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
711 /* A non inheriting creator group entry has no effect. */
712 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
713 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
714 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
721 if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
722 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
723 ace_v4
->who
.gid
= gid
;
724 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
725 ace_v4
->who
.uid
= uid
;
726 } else if (dom_sid_compare_domain(&ace_nt
->trustee
,
727 &global_sid_Unix_NFS
) == 0) {
730 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
731 "convert %s to uid or gid\n",
733 sid_string_dbg(&ace_nt
->trustee
)));
738 return true; /* OK */
741 static int smbacl4_MergeIgnoreReject(
742 enum smbacl4_acedup_enum acedup
,
743 struct SMB4ACL_T
*theacl
, /* may modify it */
744 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
750 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
755 case e_merge
: /* "merge" flags */
757 ace4found
->aceFlags
|= ace
->aceFlags
;
758 ace4found
->aceMask
|= ace
->aceMask
;
760 case e_ignore
: /* leave out this record */
763 case e_reject
: /* do an error */
764 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
765 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
775 static int smbacl4_substitute_special(
776 struct SMB4ACL_T
*acl
,
781 struct SMB4ACE_T
*aceint
;
783 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
784 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
786 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
787 "mask: %x, who: %d\n",
788 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
789 ace
->aceMask
, ace
->who
.id
));
791 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
792 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
793 ace
->who
.uid
== ownerUID
) {
794 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
795 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
796 DEBUG(10,("replaced with special owner ace\n"));
799 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
800 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
801 ace
->who
.uid
== ownerGID
) {
802 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
803 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
804 DEBUG(10,("replaced with special group ace\n"));
807 return true; /* OK */
810 static int smbacl4_substitute_simple(
811 struct SMB4ACL_T
*acl
,
816 struct SMB4ACE_T
*aceint
;
818 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
819 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
821 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
822 "mask: %x, who: %d\n",
823 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
824 ace
->aceMask
, ace
->who
.id
));
826 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
827 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
828 ace
->who
.uid
== ownerUID
&&
829 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
830 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
831 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
832 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
833 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
834 DEBUG(10,("replaced with special owner ace\n"));
837 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
838 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
839 ace
->who
.uid
== ownerGID
&&
840 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
841 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
842 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
843 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
844 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
845 DEBUG(10,("replaced with special group ace\n"));
848 return true; /* OK */
851 static struct SMB4ACL_T
*smbacl4_win2nfs4(
853 const files_struct
*fsp
,
854 const struct security_acl
*dacl
,
855 smbacl4_vfs_params
*pparams
,
860 struct SMB4ACL_T
*theacl
;
862 const char *filename
= fsp
->fsp_name
->base_name
;
864 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
866 theacl
= smb_create_smb4acl(mem_ctx
);
870 for(i
=0; i
<dacl
->num_aces
; i
++) {
871 SMB_ACE4PROP_T ace_v4
;
872 bool addNewACE
= true;
874 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
876 dacl
->aces
+ i
, &ace_v4
)) {
877 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
879 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
883 if (pparams
->acedup
!=e_dontcare
) {
884 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
885 &ace_v4
, &addNewACE
, i
))
890 smb_add_ace4(theacl
, &ace_v4
);
893 if (pparams
->mode
==e_simple
) {
894 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
897 if (pparams
->mode
==e_special
) {
898 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
904 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
905 uint32_t security_info_sent
,
906 const struct security_descriptor
*psd
,
907 set_nfs4acl_native_fn_t set_nfs4_native
)
909 smbacl4_vfs_params params
;
910 struct SMB4ACL_T
*theacl
= NULL
;
913 SMB_STRUCT_STAT sbuf
;
914 bool set_acl_as_root
= false;
915 uid_t newUID
= (uid_t
)-1;
916 gid_t newGID
= (gid_t
)-1;
918 TALLOC_CTX
*frame
= talloc_stackframe();
920 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
922 if ((security_info_sent
& (SECINFO_DACL
|
923 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
925 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
926 security_info_sent
));
928 return NT_STATUS_OK
; /* won't show error - later to be
932 /* Special behaviours */
933 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
935 return NT_STATUS_NO_MEMORY
;
938 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
940 return map_nt_error_from_unix(errno
);
943 if (params
.do_chown
) {
944 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
945 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
946 security_info_sent
, psd
);
947 if (!NT_STATUS_IS_OK(status
)) {
948 DEBUG(8, ("unpack_nt_owners failed"));
952 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
953 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
955 status
= try_chown(fsp
, newUID
, newGID
);
956 if (!NT_STATUS_IS_OK(status
)) {
957 DEBUG(3,("chown %s, %u, %u failed. Error = "
958 "%s.\n", fsp_str_dbg(fsp
),
959 (unsigned int)newUID
,
960 (unsigned int)newGID
,
966 DEBUG(10,("chown %s, %u, %u succeeded.\n",
967 fsp_str_dbg(fsp
), (unsigned int)newUID
,
968 (unsigned int)newGID
));
969 if (smbacl4_GetFileOwner(fsp
->conn
,
970 fsp
->fsp_name
->base_name
,
973 return map_nt_error_from_unix(errno
);
976 /* If we successfully chowned, we know we must
977 * be able to set the acl, so do it as root.
979 set_acl_as_root
= true;
983 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
984 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
985 security_info_sent
));
990 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, ¶ms
,
991 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
994 return map_nt_error_from_unix(errno
);
997 smbacl4_set_controlflags(theacl
, psd
->type
);
998 smbacl4_dump_nfs4acl(10, theacl
);
1000 if (set_acl_as_root
) {
1003 result
= set_nfs4_native(handle
, fsp
, theacl
);
1004 saved_errno
= errno
;
1005 if (set_acl_as_root
) {
1012 errno
= saved_errno
;
1013 DEBUG(10, ("set_nfs4_native failed with %s\n",
1015 return map_nt_error_from_unix(errno
);
1018 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1019 return NT_STATUS_OK
;