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 DEBUG(0, ("TALLOC_SIZE failed\n"));
187 /* ace->next = NULL not needed */
188 memcpy(&ace
->prop
, prop
, sizeof(SMB_ACE4PROP_T
));
190 if (acl
->first
==NULL
)
195 acl
->last
->next
= ace
;
203 SMB_ACE4PROP_T
*smb_get_ace4(struct SMB4ACE_T
*ace
)
212 struct SMB4ACE_T
*smb_next_ace4(struct SMB4ACE_T
*ace
)
221 struct SMB4ACE_T
*smb_first_ace4(struct SMB4ACL_T
*acl
)
230 uint32_t smb_get_naces(struct SMB4ACL_T
*acl
)
239 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T
*acl
)
245 return acl
->controlflags
;
248 bool smbacl4_set_controlflags(struct SMB4ACL_T
*acl
, uint16_t controlflags
)
254 acl
->controlflags
= controlflags
;
258 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
259 const struct smb_filename
*smb_fname
,
260 SMB_STRUCT_STAT
*psbuf
)
264 /* Get the stat struct for the owner info. */
265 if (vfs_stat_smb_basename(conn
, smb_fname
, psbuf
) != 0)
267 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
275 static int smbacl4_fGetFileOwner(files_struct
*fsp
, SMB_STRUCT_STAT
*psbuf
)
279 if (fsp
->fh
->fd
== -1) {
280 return smbacl4_GetFileOwner(fsp
->conn
,
281 fsp
->fsp_name
, psbuf
);
283 if (SMB_VFS_FSTAT(fsp
, psbuf
) != 0)
285 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
293 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
294 const struct smbacl4_vfs_params
*params
,
295 struct SMB4ACL_T
*acl
, /* in */
296 struct dom_sid
*psid_owner
, /* in */
297 struct dom_sid
*psid_group
, /* in */
298 bool is_directory
, /* in */
299 struct security_ace
**ppnt_ace_list
, /* out */
300 int *pgood_aces
/* out */
303 struct SMB4ACE_T
*aceint
;
304 struct security_ace
*nt_ace_list
= NULL
;
307 DEBUG(10, ("%s entered\n", __func__
));
309 nt_ace_list
= talloc_zero_array(mem_ctx
, struct security_ace
,
311 if (nt_ace_list
==NULL
)
313 DEBUG(10, ("talloc error with %d aces", acl
->naces
));
318 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
321 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
322 uint32_t win_ace_flags
;
324 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
325 "mask: %x, who: %d\n",
326 ace
->aceType
, ace
->flags
,
327 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
329 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
330 switch (ace
->who
.special_id
) {
331 case SMB_ACE4_WHO_OWNER
:
332 sid_copy(&sid
, psid_owner
);
334 case SMB_ACE4_WHO_GROUP
:
335 sid_copy(&sid
, psid_group
);
337 case SMB_ACE4_WHO_EVERYONE
:
338 sid_copy(&sid
, &global_sid_World
);
341 DEBUG(8, ("invalid special who id %d "
342 "ignored\n", ace
->who
.special_id
));
346 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
347 gid_to_sid(&sid
, ace
->who
.gid
);
349 uid_to_sid(&sid
, ace
->who
.uid
);
352 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
353 sid_string_dbg(&sid
)));
355 if (is_directory
&& (ace
->aceMask
& SMB_ACE4_ADD_FILE
)) {
356 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
359 if (!is_directory
&& params
->map_full_control
) {
361 * Do we have all access except DELETE_CHILD
362 * (not caring about the delete bit).
364 uint32_t test_mask
= ((ace
->aceMask
|SMB_ACE4_DELETE
|SMB_ACE4_DELETE_CHILD
) &
366 if (test_mask
== SMB_ACE4_ALL_MASKS
) {
367 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
371 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
374 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
375 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
377 * GPFS sets inherits dir_inhert and file_inherit flags
378 * to files, too, which confuses windows, and seems to
379 * be wrong anyways. ==> Map these bits away for files.
381 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
382 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
383 SEC_ACE_FLAG_CONTAINER_INHERIT
);
385 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
386 ace
->aceFlags
, win_ace_flags
));
389 /* Windows clients expect SYNC on acls to
390 correctly allow rename. See bug #7909. */
391 /* But not on DENY ace entries. See
393 if(ace
->aceType
== SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE
) {
394 mask
= ace
->aceMask
| SMB_ACE4_SYNCHRONIZE
;
397 /* Mapping of owner@ and group@ to creator owner and
398 creator group. Keep old behavior in mode special. */
399 if (params
->mode
!= e_special
&&
400 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
401 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
402 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
403 DEBUG(10, ("Map special entry\n"));
404 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
405 uint32_t win_ace_flags_current
;
406 DEBUG(10, ("Map current sid\n"));
407 win_ace_flags_current
= win_ace_flags
&
408 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
409 SEC_ACE_FLAG_CONTAINER_INHERIT
);
410 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
412 win_ace_flags_current
);
414 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
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\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_Owner
,
424 win_ace_flags_creator
);
426 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
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 group\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_Group
,
436 win_ace_flags_creator
);
439 DEBUG(10, ("Map normal sid\n"));
440 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
446 nt_ace_list
= talloc_realloc(mem_ctx
, nt_ace_list
, struct security_ace
,
449 /* returns a NULL ace list when good_aces is zero. */
450 if (good_aces
&& nt_ace_list
== NULL
) {
451 DEBUG(10, ("realloc error with %d aces", good_aces
));
456 *ppnt_ace_list
= nt_ace_list
;
457 *pgood_aces
= good_aces
;
462 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
463 const struct smbacl4_vfs_params
*params
,
464 uint32_t security_info
,
466 struct security_descriptor
**ppdesc
,
467 struct SMB4ACL_T
*theacl
)
470 struct dom_sid sid_owner
, sid_group
;
472 struct security_ace
*nt_ace_list
= NULL
;
473 struct security_acl
*psa
= NULL
;
474 TALLOC_CTX
*frame
= talloc_stackframe();
479 return NT_STATUS_ACCESS_DENIED
; /* special because we
480 * need to think through
484 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
485 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
487 ok
= smbacl4_nfs42win(frame
, params
, theacl
, &sid_owner
, &sid_group
,
488 S_ISDIR(sbuf
->st_ex_mode
),
489 &nt_ace_list
, &good_aces
);
491 DEBUG(8,("smbacl4_nfs42win failed\n"));
493 return map_nt_error_from_unix(errno
);
496 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
498 DEBUG(2,("make_sec_acl failed\n"));
500 return NT_STATUS_NO_MEMORY
;
503 DEBUG(10,("after make sec_acl\n"));
504 *ppdesc
= make_sec_desc(
505 mem_ctx
, SD_REVISION
, smbacl4_get_controlflags(theacl
),
506 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
507 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
508 NULL
, psa
, &sd_size
);
510 DEBUG(2,("make_sec_desc failed\n"));
512 return NT_STATUS_NO_MEMORY
;
515 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
517 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
523 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
524 const struct smbacl4_vfs_params
*pparams
,
525 uint32_t security_info
,
527 struct security_descriptor
**ppdesc
,
528 struct SMB4ACL_T
*theacl
)
530 SMB_STRUCT_STAT sbuf
;
531 struct smbacl4_vfs_params params
;
532 SMB_STRUCT_STAT
*psbuf
= NULL
;
534 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
536 if (VALID_STAT(fsp
->fsp_name
->st
)) {
537 psbuf
= &fsp
->fsp_name
->st
;
541 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
542 return map_nt_error_from_unix(errno
);
547 if (pparams
== NULL
) {
548 /* Special behaviours */
549 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
550 return NT_STATUS_NO_MEMORY
;
555 return smb_get_nt_acl_nfs4_common(psbuf
, pparams
, 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 const struct smbacl4_vfs_params
*pparams
,
562 uint32_t security_info
,
564 struct security_descriptor
**ppdesc
,
565 struct SMB4ACL_T
*theacl
)
567 SMB_STRUCT_STAT sbuf
;
568 struct smbacl4_vfs_params params
;
569 const SMB_STRUCT_STAT
*psbuf
= NULL
;
571 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
572 smb_fname
->base_name
));
574 if (VALID_STAT(smb_fname
->st
)) {
575 psbuf
= &smb_fname
->st
;
579 if (smbacl4_GetFileOwner(conn
, smb_fname
, &sbuf
)) {
580 return map_nt_error_from_unix(errno
);
585 if (pparams
== NULL
) {
586 /* Special behaviours */
587 if (smbacl4_get_vfs_params(conn
, ¶ms
)) {
588 return NT_STATUS_NO_MEMORY
;
593 return smb_get_nt_acl_nfs4_common(psbuf
, pparams
, security_info
,
594 mem_ctx
, ppdesc
, theacl
);
597 static void smbacl4_dump_nfs4acl(int level
, struct SMB4ACL_T
*acl
)
599 struct SMB4ACE_T
*aceint
;
601 DEBUG(level
, ("NFS4ACL: size=%d\n", acl
->naces
));
603 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
604 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
606 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
607 "mask=0x%x, id=%d\n",
609 ace
->aceFlags
, ace
->flags
,
616 * Find 2 NFS4 who-special ACE property (non-copy!!!)
617 * match nonzero if "special" and who is equal
618 * return ace if found matching; otherwise NULL
620 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
621 struct SMB4ACL_T
*acl
,
622 SMB_ACE4PROP_T
*aceNew
)
624 struct SMB4ACE_T
*aceint
;
626 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
627 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
629 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
630 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
631 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
632 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
634 if (ace
->flags
== aceNew
->flags
&&
635 ace
->aceType
==aceNew
->aceType
&&
636 ace
->aceFlags
==aceNew
->aceFlags
)
638 /* keep type safety; e.g. gid is an u.short */
639 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
641 if (ace
->who
.special_id
==
642 aceNew
->who
.special_id
)
645 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
647 if (ace
->who
.gid
==aceNew
->who
.gid
)
650 if (ace
->who
.uid
==aceNew
->who
.uid
)
661 static bool smbacl4_fill_ace4(
662 const struct smb_filename
*filename
,
663 const struct smbacl4_vfs_params
*params
,
666 const struct security_ace
*ace_nt
, /* input */
667 SMB_ACE4PROP_T
*ace_v4
/* output */
670 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt
->trustee
)));
672 ZERO_STRUCTP(ace_v4
);
674 /* only ACCESS|DENY supported right now */
675 ace_v4
->aceType
= ace_nt
->type
;
677 ace_v4
->aceFlags
= map_windows_ace_flags_to_nfs4_ace_flags(
680 /* remove inheritance flags on files */
681 if (VALID_STAT(filename
->st
) &&
682 !S_ISDIR(filename
->st
.st_ex_mode
)) {
683 DEBUG(10, ("Removing inheritance flags from a file\n"));
684 ace_v4
->aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
685 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
686 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
687 SMB_ACE4_INHERIT_ONLY_ACE
);
690 ace_v4
->aceMask
= ace_nt
->access_mask
&
691 (SEC_STD_ALL
| SEC_FILE_ALL
);
693 se_map_generic(&ace_v4
->aceMask
, &file_generic_mapping
);
695 if (ace_v4
->aceFlags
!=ace_nt
->flags
)
696 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
697 ace_v4
->aceFlags
, ace_nt
->flags
));
699 if (ace_v4
->aceMask
!=ace_nt
->access_mask
)
700 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
701 ace_v4
->aceMask
, ace_nt
->access_mask
));
703 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
704 ace_v4
->who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
705 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
706 } else if (params
->mode
!=e_special
&&
707 dom_sid_equal(&ace_nt
->trustee
,
708 &global_sid_Creator_Owner
)) {
709 DEBUG(10, ("Map creator owner\n"));
710 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
711 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
712 /* A non inheriting creator owner 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
)) {
718 } else if (params
->mode
!=e_special
&&
719 dom_sid_equal(&ace_nt
->trustee
,
720 &global_sid_Creator_Group
)) {
721 DEBUG(10, ("Map creator owner group\n"));
722 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
723 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
724 /* A non inheriting creator group entry has no effect. */
725 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
726 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
727 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
735 * ID_TYPE_BOTH returns both uid and gid. Explicitly
736 * check for ownerUID to allow the mapping of the
737 * owner to a special entry in this idmap config.
739 if (sid_to_uid(&ace_nt
->trustee
, &uid
) && uid
== ownerUID
) {
740 ace_v4
->who
.uid
= uid
;
741 } else if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
742 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
743 ace_v4
->who
.gid
= gid
;
744 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
745 ace_v4
->who
.uid
= uid
;
746 } else if (dom_sid_compare_domain(&ace_nt
->trustee
,
747 &global_sid_Unix_NFS
) == 0) {
750 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
751 "convert %s to uid or gid\n",
753 sid_string_dbg(&ace_nt
->trustee
)));
758 return true; /* OK */
761 static int smbacl4_MergeIgnoreReject(
762 enum smbacl4_acedup_enum acedup
,
763 struct SMB4ACL_T
*theacl
, /* may modify it */
764 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
770 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
775 case e_merge
: /* "merge" flags */
777 ace4found
->aceFlags
|= ace
->aceFlags
;
778 ace4found
->aceMask
|= ace
->aceMask
;
780 case e_ignore
: /* leave out this record */
783 case e_reject
: /* do an error */
784 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
785 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
795 static int smbacl4_substitute_special(
796 struct SMB4ACL_T
*acl
,
801 struct SMB4ACE_T
*aceint
;
803 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
804 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
806 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
807 "mask: %x, who: %d\n",
808 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
809 ace
->aceMask
, ace
->who
.id
));
811 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
812 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
813 ace
->who
.uid
== ownerUID
) {
814 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
815 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
816 DEBUG(10,("replaced with special owner ace\n"));
819 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
820 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
821 ace
->who
.uid
== ownerGID
) {
822 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
823 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
824 DEBUG(10,("replaced with special group ace\n"));
827 return true; /* OK */
830 static int smbacl4_substitute_simple(
831 struct SMB4ACL_T
*acl
,
836 struct SMB4ACE_T
*aceint
;
838 for (aceint
= acl
->first
; aceint
!= NULL
; aceint
= aceint
->next
) {
839 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
841 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
842 "mask: %x, who: %d\n",
843 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
844 ace
->aceMask
, ace
->who
.id
));
846 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
847 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
848 ace
->who
.uid
== ownerUID
&&
849 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
850 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
851 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
852 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
853 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
854 DEBUG(10,("replaced with special owner ace\n"));
857 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
858 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
859 ace
->who
.uid
== ownerGID
&&
860 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
861 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
862 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
863 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
864 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
865 DEBUG(10,("replaced with special group ace\n"));
868 return true; /* OK */
871 static struct SMB4ACL_T
*smbacl4_win2nfs4(
873 const files_struct
*fsp
,
874 const struct security_acl
*dacl
,
875 const struct smbacl4_vfs_params
*pparams
,
880 struct SMB4ACL_T
*theacl
;
882 const char *filename
= fsp
->fsp_name
->base_name
;
884 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
886 theacl
= smb_create_smb4acl(mem_ctx
);
890 for(i
=0; i
<dacl
->num_aces
; i
++) {
891 SMB_ACE4PROP_T ace_v4
;
892 bool addNewACE
= true;
894 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
896 dacl
->aces
+ i
, &ace_v4
)) {
897 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
899 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
903 if (pparams
->acedup
!=e_dontcare
) {
904 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
905 &ace_v4
, &addNewACE
, i
))
910 smb_add_ace4(theacl
, &ace_v4
);
913 if (pparams
->mode
==e_simple
) {
914 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
917 if (pparams
->mode
==e_special
) {
918 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
924 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
925 const struct smbacl4_vfs_params
*pparams
,
926 uint32_t security_info_sent
,
927 const struct security_descriptor
*psd
,
928 set_nfs4acl_native_fn_t set_nfs4_native
)
930 struct smbacl4_vfs_params params
;
931 struct SMB4ACL_T
*theacl
= NULL
;
934 SMB_STRUCT_STAT sbuf
;
935 bool set_acl_as_root
= false;
936 uid_t newUID
= (uid_t
)-1;
937 gid_t newGID
= (gid_t
)-1;
939 TALLOC_CTX
*frame
= talloc_stackframe();
941 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
943 if ((security_info_sent
& (SECINFO_DACL
|
944 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
946 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
947 security_info_sent
));
949 return NT_STATUS_OK
; /* won't show error - later to be
953 if (pparams
== NULL
) {
954 /* Special behaviours */
955 if (smbacl4_get_vfs_params(fsp
->conn
, ¶ms
)) {
957 return NT_STATUS_NO_MEMORY
;
962 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
964 return map_nt_error_from_unix(errno
);
967 if (pparams
->do_chown
) {
968 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
969 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
970 security_info_sent
, psd
);
971 if (!NT_STATUS_IS_OK(status
)) {
972 DEBUG(8, ("unpack_nt_owners failed"));
976 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
977 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
979 status
= try_chown(fsp
, newUID
, newGID
);
980 if (!NT_STATUS_IS_OK(status
)) {
981 DEBUG(3,("chown %s, %u, %u failed. Error = "
982 "%s.\n", fsp_str_dbg(fsp
),
983 (unsigned int)newUID
,
984 (unsigned int)newGID
,
990 DEBUG(10,("chown %s, %u, %u succeeded.\n",
991 fsp_str_dbg(fsp
), (unsigned int)newUID
,
992 (unsigned int)newGID
));
993 if (smbacl4_GetFileOwner(fsp
->conn
,
997 return map_nt_error_from_unix(errno
);
1000 /* If we successfully chowned, we know we must
1001 * be able to set the acl, so do it as root.
1003 set_acl_as_root
= true;
1007 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
1008 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1009 security_info_sent
));
1011 return NT_STATUS_OK
;
1014 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, pparams
,
1015 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
1018 return map_nt_error_from_unix(errno
);
1021 smbacl4_set_controlflags(theacl
, psd
->type
);
1022 smbacl4_dump_nfs4acl(10, theacl
);
1024 if (set_acl_as_root
) {
1027 result
= set_nfs4_native(handle
, fsp
, theacl
);
1028 saved_errno
= errno
;
1029 if (set_acl_as_root
) {
1036 errno
= saved_errno
;
1037 DEBUG(10, ("set_nfs4_native failed with %s\n",
1039 return map_nt_error_from_unix(errno
);
1042 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1043 return NT_STATUS_OK
;