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
;
55 * Gather special parameters for NFS4 ACL handling
57 int smbacl4_get_vfs_params(struct connection_struct
*conn
,
58 struct smbacl4_vfs_params
*params
)
60 static const struct enum_list enum_smbacl4_modes
[] = {
61 { e_simple
, "simple" },
62 { e_special
, "special" },
65 static const struct enum_list enum_smbacl4_acedups
[] = {
66 { e_dontcare
, "dontcare" },
67 { e_reject
, "reject" },
68 { e_ignore
, "ignore" },
76 enumval
= lp_parm_enum(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
, "mode",
77 enum_smbacl4_modes
, e_simple
);
79 DEBUG(10, ("value for %s:mode unknown\n",
80 SMBACL4_PARAM_TYPE_NAME
));
83 params
->mode
= (enum smbacl4_mode_enum
)enumval
;
85 params
->do_chown
= lp_parm_bool(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
,
88 enumval
= lp_parm_enum(SNUM(conn
), SMBACL4_PARAM_TYPE_NAME
, "acedup",
89 enum_smbacl4_acedups
, e_dontcare
);
91 DEBUG(10, ("value for %s:acedup unknown\n",
92 SMBACL4_PARAM_TYPE_NAME
));
95 params
->acedup
= (enum smbacl4_acedup_enum
)enumval
;
97 params
->map_full_control
= lp_acl_map_full_control(SNUM(conn
));
99 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
100 enum_smbacl4_modes
[params
->mode
].name
,
101 params
->do_chown
? "true" : "false",
102 enum_smbacl4_acedups
[params
->acedup
].name
,
103 params
->map_full_control
? "true" : "false"));
108 /************************************************
109 Split the ACE flag mapping between nfs4 and Windows
110 into two separate functions rather than trying to do
111 it inline. Allows us to carefully control what flags
112 are mapped to what in one place.
113 ************************************************/
115 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
116 uint32_t nfs4_ace_flags
)
118 uint32_t win_ace_flags
= 0;
120 /* The nfs4 flags <= 0xf map perfectly. */
121 win_ace_flags
= nfs4_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
122 SEC_ACE_FLAG_CONTAINER_INHERIT
|
123 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
|
124 SEC_ACE_FLAG_INHERIT_ONLY
);
126 /* flags greater than 0xf have diverged :-(. */
127 /* See the nfs4 ace flag definitions here:
128 http://www.ietf.org/rfc/rfc3530.txt.
129 And the Windows ace flag definitions here:
130 librpc/idl/security.idl. */
131 if (nfs4_ace_flags
& SMB_ACE4_INHERITED_ACE
) {
132 win_ace_flags
|= SEC_ACE_FLAG_INHERITED_ACE
;
135 return win_ace_flags
;
138 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags
)
140 uint32_t nfs4_ace_flags
= 0;
142 /* The windows flags <= 0xf map perfectly. */
143 nfs4_ace_flags
= win_ace_flags
& (SMB_ACE4_FILE_INHERIT_ACE
|
144 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
145 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
146 SMB_ACE4_INHERIT_ONLY_ACE
);
148 /* flags greater than 0xf have diverged :-(. */
149 /* See the nfs4 ace flag definitions here:
150 http://www.ietf.org/rfc/rfc3530.txt.
151 And the Windows ace flag definitions here:
152 librpc/idl/security.idl. */
153 if (win_ace_flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
154 nfs4_ace_flags
|= SMB_ACE4_INHERITED_ACE
;
157 return nfs4_ace_flags
;
160 struct SMB4ACL_T
*smb_create_smb4acl(TALLOC_CTX
*mem_ctx
)
162 struct SMB4ACL_T
*theacl
;
164 theacl
= talloc_zero(mem_ctx
, struct SMB4ACL_T
);
167 DEBUG(0, ("TALLOC_SIZE failed\n"));
171 theacl
->controlflags
= SEC_DESC_SELF_RELATIVE
;
172 /* theacl->first, last = NULL not needed */
176 struct SMB4ACE_T
*smb_add_ace4(struct SMB4ACL_T
*acl
, SMB_ACE4PROP_T
*prop
)
178 struct SMB4ACE_T
*ace
;
180 ace
= talloc_zero(acl
, struct SMB4ACE_T
);
183 DBG_ERR("talloc_zero failed\n");
189 if (acl
->first
==NULL
)
194 acl
->last
->next
= ace
;
202 SMB_ACE4PROP_T
*smb_get_ace4(struct SMB4ACE_T
*ace
)
211 struct SMB4ACE_T
*smb_next_ace4(struct SMB4ACE_T
*ace
)
220 struct SMB4ACE_T
*smb_first_ace4(struct SMB4ACL_T
*acl
)
229 uint32_t smb_get_naces(struct SMB4ACL_T
*acl
)
238 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T
*acl
)
244 return acl
->controlflags
;
247 bool smbacl4_set_controlflags(struct SMB4ACL_T
*acl
, uint16_t controlflags
)
253 acl
->controlflags
= controlflags
;
257 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
258 const struct smb_filename
*smb_fname
,
259 SMB_STRUCT_STAT
*psbuf
)
263 /* Get the stat struct for the owner info. */
264 if (vfs_stat_smb_basename(conn
, smb_fname
, psbuf
) != 0)
266 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
274 static int smbacl4_fGetFileOwner(files_struct
*fsp
, SMB_STRUCT_STAT
*psbuf
)
278 if (fsp
->fh
->fd
== -1) {
279 return smbacl4_GetFileOwner(fsp
->conn
,
280 fsp
->fsp_name
, psbuf
);
282 if (SMB_VFS_FSTAT(fsp
, psbuf
) != 0)
284 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
292 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
293 const struct smbacl4_vfs_params
*params
,
294 struct SMB4ACL_T
*acl
, /* in */
295 struct dom_sid
*psid_owner
, /* in */
296 struct dom_sid
*psid_group
, /* in */
297 bool is_directory
, /* in */
298 struct security_ace
**ppnt_ace_list
, /* out */
299 int *pgood_aces
/* out */
302 struct SMB4ACE_T
*aceint
;
303 struct security_ace
*nt_ace_list
= NULL
;
306 DEBUG(10, ("%s entered\n", __func__
));
308 nt_ace_list
= talloc_zero_array(mem_ctx
, struct security_ace
,
310 if (nt_ace_list
==NULL
)
312 DEBUG(10, ("talloc error with %d aces", acl
->naces
));
317 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
320 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
321 uint32_t win_ace_flags
;
323 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
324 "mask: %x, who: %d\n",
325 ace
->aceType
, ace
->flags
,
326 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
328 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
329 switch (ace
->who
.special_id
) {
330 case SMB_ACE4_WHO_OWNER
:
331 sid_copy(&sid
, psid_owner
);
333 case SMB_ACE4_WHO_GROUP
:
334 sid_copy(&sid
, psid_group
);
336 case SMB_ACE4_WHO_EVERYONE
:
337 sid_copy(&sid
, &global_sid_World
);
340 DEBUG(8, ("invalid special who id %d "
341 "ignored\n", ace
->who
.special_id
));
345 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
346 gid_to_sid(&sid
, ace
->who
.gid
);
348 uid_to_sid(&sid
, ace
->who
.uid
);
351 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
352 sid_string_dbg(&sid
)));
354 if (!is_directory
&& params
->map_full_control
) {
356 * Do we have all access except DELETE_CHILD
357 * (not caring about the delete bit).
359 uint32_t test_mask
= ((ace
->aceMask
|SMB_ACE4_DELETE
|SMB_ACE4_DELETE_CHILD
) &
361 if (test_mask
== SMB_ACE4_ALL_MASKS
) {
362 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
366 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
369 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
370 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
372 * GPFS sets inherits dir_inhert and file_inherit flags
373 * to files, too, which confuses windows, and seems to
374 * be wrong anyways. ==> Map these bits away for files.
376 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
377 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
378 SEC_ACE_FLAG_CONTAINER_INHERIT
);
380 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
381 ace
->aceFlags
, win_ace_flags
));
385 /* Mapping of owner@ and group@ to creator owner and
386 creator group. Keep old behavior in mode special. */
387 if (params
->mode
!= e_special
&&
388 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
389 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
390 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
391 DEBUG(10, ("Map special entry\n"));
392 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
393 uint32_t win_ace_flags_current
;
394 DEBUG(10, ("Map current sid\n"));
395 win_ace_flags_current
= win_ace_flags
&
396 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
397 SEC_ACE_FLAG_CONTAINER_INHERIT
);
398 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
400 win_ace_flags_current
);
402 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
403 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
404 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
405 uint32_t win_ace_flags_creator
;
406 DEBUG(10, ("Map creator owner\n"));
407 win_ace_flags_creator
= win_ace_flags
|
408 SMB_ACE4_INHERIT_ONLY_ACE
;
409 init_sec_ace(&nt_ace_list
[good_aces
++],
410 &global_sid_Creator_Owner
,
412 win_ace_flags_creator
);
414 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
415 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
416 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
417 uint32_t win_ace_flags_creator
;
418 DEBUG(10, ("Map creator owner group\n"));
419 win_ace_flags_creator
= win_ace_flags
|
420 SMB_ACE4_INHERIT_ONLY_ACE
;
421 init_sec_ace(&nt_ace_list
[good_aces
++],
422 &global_sid_Creator_Group
,
424 win_ace_flags_creator
);
427 DEBUG(10, ("Map normal sid\n"));
428 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
434 nt_ace_list
= talloc_realloc(mem_ctx
, nt_ace_list
, struct security_ace
,
437 /* returns a NULL ace list when good_aces is zero. */
438 if (good_aces
&& nt_ace_list
== NULL
) {
439 DEBUG(10, ("realloc error with %d aces", good_aces
));
444 *ppnt_ace_list
= nt_ace_list
;
445 *pgood_aces
= good_aces
;
450 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
451 const struct smbacl4_vfs_params
*params
,
452 uint32_t security_info
,
454 struct security_descriptor
**ppdesc
,
455 struct SMB4ACL_T
*theacl
)
458 struct dom_sid sid_owner
, sid_group
;
460 struct security_ace
*nt_ace_list
= NULL
;
461 struct security_acl
*psa
= NULL
;
462 TALLOC_CTX
*frame
= talloc_stackframe();
467 return NT_STATUS_ACCESS_DENIED
; /* special because we
468 * need to think through
472 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
473 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
475 ok
= smbacl4_nfs42win(frame
, params
, theacl
, &sid_owner
, &sid_group
,
476 S_ISDIR(sbuf
->st_ex_mode
),
477 &nt_ace_list
, &good_aces
);
479 DEBUG(8,("smbacl4_nfs42win failed\n"));
481 return map_nt_error_from_unix(errno
);
484 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
486 DEBUG(2,("make_sec_acl failed\n"));
488 return NT_STATUS_NO_MEMORY
;
491 DEBUG(10,("after make sec_acl\n"));
492 *ppdesc
= make_sec_desc(
493 mem_ctx
, SD_REVISION
, smbacl4_get_controlflags(theacl
),
494 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
495 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
496 NULL
, psa
, &sd_size
);
498 DEBUG(2,("make_sec_desc failed\n"));
500 return NT_STATUS_NO_MEMORY
;
503 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
505 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
511 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
512 const struct smbacl4_vfs_params
*pparams
,
513 uint32_t security_info
,
515 struct security_descriptor
**ppdesc
,
516 struct SMB4ACL_T
*theacl
)
518 SMB_STRUCT_STAT sbuf
;
519 struct smbacl4_vfs_params params
;
520 SMB_STRUCT_STAT
*psbuf
= NULL
;
522 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
524 if (VALID_STAT(fsp
->fsp_name
->st
)) {
525 psbuf
= &fsp
->fsp_name
->st
;
529 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
530 return map_nt_error_from_unix(errno
);
535 if (pparams
== NULL
) {
536 /* Special behaviours */
537 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
538 return NT_STATUS_NO_MEMORY
;
543 return smb_get_nt_acl_nfs4_common(psbuf
, pparams
, security_info
,
544 mem_ctx
, ppdesc
, theacl
);
547 NTSTATUS
smb_get_nt_acl_nfs4(struct connection_struct
*conn
,
548 const struct smb_filename
*smb_fname
,
549 const struct smbacl4_vfs_params
*pparams
,
550 uint32_t security_info
,
552 struct security_descriptor
**ppdesc
,
553 struct SMB4ACL_T
*theacl
)
555 SMB_STRUCT_STAT sbuf
;
556 struct smbacl4_vfs_params params
;
557 const SMB_STRUCT_STAT
*psbuf
= NULL
;
559 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
560 smb_fname
->base_name
));
562 if (VALID_STAT(smb_fname
->st
)) {
563 psbuf
= &smb_fname
->st
;
567 if (smbacl4_GetFileOwner(conn
, smb_fname
, &sbuf
)) {
568 return map_nt_error_from_unix(errno
);
573 if (pparams
== NULL
) {
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(conn
, ¶ms
)) {
576 return NT_STATUS_NO_MEMORY
;
581 return smb_get_nt_acl_nfs4_common(psbuf
, pparams
, 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 const struct 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
)) {
723 * ID_TYPE_BOTH returns both uid and gid. Explicitly
724 * check for ownerUID to allow the mapping of the
725 * owner to a special entry in this idmap config.
727 if (sid_to_uid(&ace_nt
->trustee
, &uid
) && uid
== ownerUID
) {
728 ace_v4
->who
.uid
= uid
;
729 } else if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
730 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
731 ace_v4
->who
.gid
= gid
;
732 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
733 ace_v4
->who
.uid
= uid
;
734 } else if (dom_sid_compare_domain(&ace_nt
->trustee
,
735 &global_sid_Unix_NFS
) == 0) {
738 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
739 "convert %s to uid or gid\n",
741 sid_string_dbg(&ace_nt
->trustee
)));
746 return true; /* OK */
749 static int smbacl4_MergeIgnoreReject(
750 enum smbacl4_acedup_enum acedup
,
751 struct SMB4ACL_T
*theacl
, /* may modify it */
752 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
758 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
763 case e_merge
: /* "merge" flags */
765 ace4found
->aceFlags
|= ace
->aceFlags
;
766 ace4found
->aceMask
|= ace
->aceMask
;
768 case e_ignore
: /* leave out this record */
771 case e_reject
: /* do an error */
772 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
773 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
783 static int smbacl4_substitute_special(
784 struct SMB4ACL_T
*acl
,
789 struct SMB4ACE_T
*aceint
;
791 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
792 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
794 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
795 "mask: %x, who: %d\n",
796 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
797 ace
->aceMask
, ace
->who
.id
));
799 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
800 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
801 ace
->who
.uid
== ownerUID
) {
802 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
803 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
804 DEBUG(10,("replaced with special owner ace\n"));
807 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
808 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
809 ace
->who
.uid
== ownerGID
) {
810 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
811 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
812 DEBUG(10,("replaced with special group ace\n"));
815 return true; /* OK */
818 static int smbacl4_substitute_simple(
819 struct SMB4ACL_T
*acl
,
824 struct SMB4ACE_T
*aceint
;
826 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
827 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
829 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
830 "mask: %x, who: %d\n",
831 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
832 ace
->aceMask
, ace
->who
.id
));
834 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
835 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
836 ace
->who
.uid
== ownerUID
&&
837 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
838 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
839 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
840 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
841 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
842 DEBUG(10,("replaced with special owner ace\n"));
845 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
846 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
847 ace
->who
.uid
== ownerGID
&&
848 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
849 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
850 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
851 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
852 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
853 DEBUG(10,("replaced with special group ace\n"));
856 return true; /* OK */
859 static struct SMB4ACL_T
*smbacl4_win2nfs4(
861 const files_struct
*fsp
,
862 const struct security_acl
*dacl
,
863 const struct smbacl4_vfs_params
*pparams
,
868 struct SMB4ACL_T
*theacl
;
870 const char *filename
= fsp
->fsp_name
->base_name
;
872 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
874 theacl
= smb_create_smb4acl(mem_ctx
);
878 for(i
=0; i
<dacl
->num_aces
; i
++) {
879 SMB_ACE4PROP_T ace_v4
;
880 bool addNewACE
= true;
882 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
884 dacl
->aces
+ i
, &ace_v4
)) {
885 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
887 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
891 if (pparams
->acedup
!=e_dontcare
) {
892 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
893 &ace_v4
, &addNewACE
, i
))
898 smb_add_ace4(theacl
, &ace_v4
);
901 if (pparams
->mode
==e_simple
) {
902 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
905 if (pparams
->mode
==e_special
) {
906 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
912 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
913 const struct smbacl4_vfs_params
*pparams
,
914 uint32_t security_info_sent
,
915 const struct security_descriptor
*psd
,
916 set_nfs4acl_native_fn_t set_nfs4_native
)
918 struct smbacl4_vfs_params params
;
919 struct SMB4ACL_T
*theacl
= NULL
;
922 SMB_STRUCT_STAT sbuf
;
923 bool set_acl_as_root
= false;
924 uid_t newUID
= (uid_t
)-1;
925 gid_t newGID
= (gid_t
)-1;
927 TALLOC_CTX
*frame
= talloc_stackframe();
929 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
931 if ((security_info_sent
& (SECINFO_DACL
|
932 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
934 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
935 security_info_sent
));
937 return NT_STATUS_OK
; /* won't show error - later to be
941 if (pparams
== NULL
) {
942 /* Special behaviours */
943 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
945 return NT_STATUS_NO_MEMORY
;
950 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
952 return map_nt_error_from_unix(errno
);
955 if (pparams
->do_chown
) {
956 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
957 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
958 security_info_sent
, psd
);
959 if (!NT_STATUS_IS_OK(status
)) {
960 DEBUG(8, ("unpack_nt_owners failed"));
964 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
965 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
967 status
= try_chown(fsp
, newUID
, newGID
);
968 if (!NT_STATUS_IS_OK(status
)) {
969 DEBUG(3,("chown %s, %u, %u failed. Error = "
970 "%s.\n", fsp_str_dbg(fsp
),
971 (unsigned int)newUID
,
972 (unsigned int)newGID
,
978 DEBUG(10,("chown %s, %u, %u succeeded.\n",
979 fsp_str_dbg(fsp
), (unsigned int)newUID
,
980 (unsigned int)newGID
));
981 if (smbacl4_GetFileOwner(fsp
->conn
,
985 return map_nt_error_from_unix(errno
);
988 /* If we successfully chowned, we know we must
989 * be able to set the acl, so do it as root.
991 set_acl_as_root
= true;
995 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
996 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
997 security_info_sent
));
1002 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, pparams
,
1003 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
1006 return map_nt_error_from_unix(errno
);
1009 smbacl4_set_controlflags(theacl
, psd
->type
);
1010 smbacl4_dump_nfs4acl(10, theacl
);
1012 if (set_acl_as_root
) {
1015 result
= set_nfs4_native(handle
, fsp
, theacl
);
1016 saved_errno
= errno
;
1017 if (set_acl_as_root
) {
1024 errno
= saved_errno
;
1025 DEBUG(10, ("set_nfs4_native failed with %s\n",
1027 return map_nt_error_from_unix(errno
);
1030 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1031 return NT_STATUS_OK
;