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
;
40 #define SMB_ACE4_INT_MAGIC 0x76F8A967
41 typedef struct _SMB_ACE4_INT_T
48 #define SMB_ACL4_INT_MAGIC 0x29A3E792
49 typedef struct _SMB_ACL4_INT_T
53 SMB_ACE4_INT_T
*first
;
57 enum smbacl4_mode_enum
{e_simple
=0, e_special
=1};
58 enum smbacl4_acedup_enum
{e_dontcare
=0, e_reject
=1, e_ignore
=2, e_merge
=3};
60 typedef struct _smbacl4_vfs_params
{
61 enum smbacl4_mode_enum mode
;
63 enum smbacl4_acedup_enum acedup
;
64 bool map_full_control
;
68 * Gather special parameters for NFS4 ACL handling
70 static int smbacl4_get_vfs_params(
71 const char *type_name
,
72 struct connection_struct
*conn
,
73 smbacl4_vfs_params
*params
76 static const struct enum_list enum_smbacl4_modes
[] = {
77 { e_simple
, "simple" },
78 { e_special
, "special" },
81 static const struct enum_list enum_smbacl4_acedups
[] = {
82 { e_dontcare
, "dontcare" },
83 { e_reject
, "reject" },
84 { e_ignore
, "ignore" },
89 memset(params
, 0, sizeof(smbacl4_vfs_params
));
90 params
->mode
= (enum smbacl4_mode_enum
)lp_parm_enum(
91 SNUM(conn
), type_name
,
92 "mode", enum_smbacl4_modes
, e_simple
);
93 params
->do_chown
= lp_parm_bool(SNUM(conn
), type_name
,
95 params
->acedup
= (enum smbacl4_acedup_enum
)lp_parm_enum(
96 SNUM(conn
), type_name
,
97 "acedup", enum_smbacl4_acedups
, e_dontcare
);
98 params
->map_full_control
= lp_acl_map_full_control(SNUM(conn
));
100 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
101 enum_smbacl4_modes
[params
->mode
].name
,
102 params
->do_chown
? "true" : "false",
103 enum_smbacl4_acedups
[params
->acedup
].name
,
104 params
->map_full_control
? "true" : "false"));
109 /************************************************
110 Split the ACE flag mapping between nfs4 and Windows
111 into two separate functions rather than trying to do
112 it inline. Allows us to carefully control what flags
113 are mapped to what in one place.
114 ************************************************/
116 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
117 uint32_t nfs4_ace_flags
)
119 uint32_t win_ace_flags
= 0;
121 /* The nfs4 flags <= 0xf map perfectly. */
122 win_ace_flags
= nfs4_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
123 SEC_ACE_FLAG_CONTAINER_INHERIT
|
124 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
|
125 SEC_ACE_FLAG_INHERIT_ONLY
);
127 /* flags greater than 0xf have diverged :-(. */
128 /* See the nfs4 ace flag definitions here:
129 http://www.ietf.org/rfc/rfc3530.txt.
130 And the Windows ace flag definitions here:
131 librpc/idl/security.idl. */
132 if (nfs4_ace_flags
& SMB_ACE4_INHERITED_ACE
) {
133 win_ace_flags
|= SEC_ACE_FLAG_INHERITED_ACE
;
136 return win_ace_flags
;
139 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags
)
141 uint32_t nfs4_ace_flags
= 0;
143 /* The windows flags <= 0xf map perfectly. */
144 nfs4_ace_flags
= win_ace_flags
& (SMB_ACE4_FILE_INHERIT_ACE
|
145 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
146 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
147 SMB_ACE4_INHERIT_ONLY_ACE
);
149 /* flags greater than 0xf have diverged :-(. */
150 /* See the nfs4 ace flag definitions here:
151 http://www.ietf.org/rfc/rfc3530.txt.
152 And the Windows ace flag definitions here:
153 librpc/idl/security.idl. */
154 if (win_ace_flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
155 nfs4_ace_flags
|= SMB_ACE4_INHERITED_ACE
;
158 return nfs4_ace_flags
;
161 static SMB_ACL4_INT_T
*get_validated_aclint(SMB4ACL_T
*theacl
)
163 SMB_ACL4_INT_T
*aclint
= (SMB_ACL4_INT_T
*)theacl
;
166 DEBUG(2, ("acl is NULL\n"));
170 if (aclint
->magic
!=SMB_ACL4_INT_MAGIC
)
172 DEBUG(2, ("aclint bad magic 0x%x\n", aclint
->magic
));
179 static SMB_ACE4_INT_T
*get_validated_aceint(SMB4ACE_T
*ace
)
181 SMB_ACE4_INT_T
*aceint
= (SMB_ACE4_INT_T
*)ace
;
184 DEBUG(2, ("ace is NULL\n"));
188 if (aceint
->magic
!=SMB_ACE4_INT_MAGIC
)
190 DEBUG(2, ("aceint bad magic 0x%x\n", aceint
->magic
));
197 SMB4ACL_T
*smb_create_smb4acl(TALLOC_CTX
*mem_ctx
)
199 SMB_ACL4_INT_T
*theacl
= (SMB_ACL4_INT_T
*)TALLOC_ZERO_SIZE(
200 mem_ctx
, sizeof(SMB_ACL4_INT_T
));
203 DEBUG(0, ("TALLOC_SIZE failed\n"));
207 theacl
->magic
= SMB_ACL4_INT_MAGIC
;
208 /* theacl->first, last = NULL not needed */
209 return (SMB4ACL_T
*)theacl
;
212 SMB4ACE_T
*smb_add_ace4(SMB4ACL_T
*theacl
, SMB_ACE4PROP_T
*prop
)
214 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
217 ace
= (SMB_ACE4_INT_T
*)TALLOC_ZERO_SIZE(
218 theacl
, sizeof(SMB_ACE4_INT_T
));
221 DEBUG(0, ("TALLOC_SIZE failed\n"));
225 ace
->magic
= SMB_ACE4_INT_MAGIC
;
226 /* ace->next = NULL not needed */
227 memcpy(&ace
->prop
, prop
, sizeof(SMB_ACE4PROP_T
));
229 if (aclint
->first
==NULL
)
234 aclint
->last
->next
= (void *)ace
;
239 return (SMB4ACE_T
*)ace
;
242 SMB_ACE4PROP_T
*smb_get_ace4(SMB4ACE_T
*ace
)
244 SMB_ACE4_INT_T
*aceint
= get_validated_aceint(ace
);
248 return &aceint
->prop
;
251 SMB4ACE_T
*smb_next_ace4(SMB4ACE_T
*ace
)
253 SMB_ACE4_INT_T
*aceint
= get_validated_aceint(ace
);
257 return (SMB4ACE_T
*)aceint
->next
;
260 SMB4ACE_T
*smb_first_ace4(SMB4ACL_T
*theacl
)
262 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
266 return (SMB4ACE_T
*)aclint
->first
;
269 uint32
smb_get_naces(SMB4ACL_T
*theacl
)
271 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
275 return aclint
->naces
;
278 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
279 const char *filename
,
280 SMB_STRUCT_STAT
*psbuf
)
282 memset(psbuf
, 0, sizeof(SMB_STRUCT_STAT
));
284 /* Get the stat struct for the owner info. */
285 if (vfs_stat_smb_basename(conn
, filename
, psbuf
) != 0)
287 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
295 static int smbacl4_fGetFileOwner(files_struct
*fsp
, SMB_STRUCT_STAT
*psbuf
)
297 memset(psbuf
, 0, sizeof(SMB_STRUCT_STAT
));
299 if (fsp
->fh
->fd
== -1) {
300 return smbacl4_GetFileOwner(fsp
->conn
,
301 fsp
->fsp_name
->base_name
, psbuf
);
303 if (SMB_VFS_FSTAT(fsp
, psbuf
) != 0)
305 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
313 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
314 smbacl4_vfs_params
*params
,
315 SMB4ACL_T
*theacl
, /* in */
316 struct dom_sid
*psid_owner
, /* in */
317 struct dom_sid
*psid_group
, /* in */
318 bool is_directory
, /* in */
319 struct security_ace
**ppnt_ace_list
, /* out */
320 int *pgood_aces
/* out */
323 SMB_ACL4_INT_T
*aclint
= (SMB_ACL4_INT_T
*)theacl
;
324 SMB_ACE4_INT_T
*aceint
;
325 struct security_ace
*nt_ace_list
= NULL
;
328 DEBUG(10, ("smbacl_nfs42win entered\n"));
330 aclint
= get_validated_aclint(theacl
);
331 /* We do not check for naces being 0 or theacl being NULL here
332 because it is done upstream in smb_get_nt_acl_nfs4().
333 We reserve twice the number of input aces because one nfs4
334 ace might result in 2 nt aces.*/
335 nt_ace_list
= (struct security_ace
*)TALLOC_ZERO_SIZE(
336 mem_ctx
, 2 * aclint
->naces
* sizeof(struct security_ace
));
337 if (nt_ace_list
==NULL
)
339 DEBUG(10, ("talloc error"));
344 for (aceint
=aclint
->first
;
346 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
349 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
350 uint32_t win_ace_flags
;
352 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
353 "mask: %x, who: %d\n",
354 aceint
->magic
, ace
->aceType
, ace
->flags
,
355 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
357 SMB_ASSERT(aceint
->magic
==SMB_ACE4_INT_MAGIC
);
359 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
360 switch (ace
->who
.special_id
) {
361 case SMB_ACE4_WHO_OWNER
:
362 sid_copy(&sid
, psid_owner
);
364 case SMB_ACE4_WHO_GROUP
:
365 sid_copy(&sid
, psid_group
);
367 case SMB_ACE4_WHO_EVERYONE
:
368 sid_copy(&sid
, &global_sid_World
);
371 DEBUG(8, ("invalid special who id %d "
372 "ignored\n", ace
->who
.special_id
));
376 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
377 gid_to_sid(&sid
, ace
->who
.gid
);
379 uid_to_sid(&sid
, ace
->who
.uid
);
382 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
383 sid_string_dbg(&sid
)));
385 if (is_directory
&& (ace
->aceMask
& SMB_ACE4_ADD_FILE
)) {
386 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
389 if (!is_directory
&& params
->map_full_control
) {
391 * Do we have all access except DELETE_CHILD
392 * (not caring about the delete bit).
394 uint32_t test_mask
= ((ace
->aceMask
|SMB_ACE4_DELETE
|SMB_ACE4_DELETE_CHILD
) &
396 if (test_mask
== SMB_ACE4_ALL_MASKS
) {
397 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
401 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
404 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
405 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
407 * GPFS sets inherits dir_inhert and file_inherit flags
408 * to files, too, which confuses windows, and seems to
409 * be wrong anyways. ==> Map these bits away for files.
411 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
412 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
413 SEC_ACE_FLAG_CONTAINER_INHERIT
);
415 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
416 ace
->aceFlags
, win_ace_flags
));
419 /* Windows clients expect SYNC on acls to
420 correctly allow rename. See bug #7909. */
421 /* But not on DENY ace entries. See
423 if(ace
->aceType
== SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE
) {
424 mask
= ace
->aceMask
| SMB_ACE4_SYNCHRONIZE
;
427 /* Mapping of owner@ and group@ to creator owner and
428 creator group. Keep old behavior in mode special. */
429 if (params
->mode
!= e_special
&&
430 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
431 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
432 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
433 DEBUG(10, ("Map special entry\n"));
434 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
435 uint32_t win_ace_flags_current
;
436 DEBUG(10, ("Map current sid\n"));
437 win_ace_flags_current
= win_ace_flags
&
438 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
439 SEC_ACE_FLAG_CONTAINER_INHERIT
);
440 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
442 win_ace_flags_current
);
444 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
445 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
446 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
447 uint32_t win_ace_flags_creator
;
448 DEBUG(10, ("Map creator owner\n"));
449 win_ace_flags_creator
= win_ace_flags
|
450 SMB_ACE4_INHERIT_ONLY_ACE
;
451 init_sec_ace(&nt_ace_list
[good_aces
++],
452 &global_sid_Creator_Owner
,
454 win_ace_flags_creator
);
456 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
457 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
458 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
459 uint32_t win_ace_flags_creator
;
460 DEBUG(10, ("Map creator owner group\n"));
461 win_ace_flags_creator
= win_ace_flags
|
462 SMB_ACE4_INHERIT_ONLY_ACE
;
463 init_sec_ace(&nt_ace_list
[good_aces
++],
464 &global_sid_Creator_Group
,
466 win_ace_flags_creator
);
469 DEBUG(10, ("Map normal sid\n"));
470 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
476 nt_ace_list
= (struct security_ace
*)TALLOC_REALLOC(mem_ctx
,
478 good_aces
* sizeof(struct security_ace
));
479 if (nt_ace_list
== NULL
) {
484 *ppnt_ace_list
= nt_ace_list
;
485 *pgood_aces
= good_aces
;
490 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
491 smbacl4_vfs_params
*params
,
492 uint32 security_info
,
494 struct security_descriptor
**ppdesc
,
498 struct dom_sid sid_owner
, sid_group
;
500 struct security_ace
*nt_ace_list
= NULL
;
501 struct security_acl
*psa
= NULL
;
502 TALLOC_CTX
*frame
= talloc_stackframe();
504 if (theacl
==NULL
|| smb_get_naces(theacl
)==0) {
506 return NT_STATUS_ACCESS_DENIED
; /* special because we
507 * shouldn't alloc 0 for
511 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
512 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
514 if (smbacl4_nfs42win(mem_ctx
, params
, theacl
, &sid_owner
, &sid_group
,
515 S_ISDIR(sbuf
->st_ex_mode
),
516 &nt_ace_list
, &good_aces
)==false) {
517 DEBUG(8,("smbacl4_nfs42win failed\n"));
519 return map_nt_error_from_unix(errno
);
522 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
524 DEBUG(2,("make_sec_acl failed\n"));
526 return NT_STATUS_NO_MEMORY
;
529 DEBUG(10,("after make sec_acl\n"));
530 *ppdesc
= make_sec_desc(
531 mem_ctx
, SD_REVISION
, SEC_DESC_SELF_RELATIVE
,
532 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
533 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
534 NULL
, psa
, &sd_size
);
536 DEBUG(2,("make_sec_desc failed\n"));
538 return NT_STATUS_NO_MEMORY
;
541 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
543 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
549 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
550 uint32 security_info
,
552 struct security_descriptor
**ppdesc
,
555 SMB_STRUCT_STAT sbuf
;
556 smbacl4_vfs_params params
;
558 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
560 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
561 return map_nt_error_from_unix(errno
);
564 /* Special behaviours */
565 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
, fsp
->conn
, ¶ms
)) {
566 return NT_STATUS_NO_MEMORY
;
569 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
570 mem_ctx
, ppdesc
, theacl
);
573 NTSTATUS
smb_get_nt_acl_nfs4(struct connection_struct
*conn
,
575 uint32 security_info
,
577 struct security_descriptor
**ppdesc
,
580 SMB_STRUCT_STAT sbuf
;
581 smbacl4_vfs_params params
;
583 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name
));
585 if (smbacl4_GetFileOwner(conn
, name
, &sbuf
)) {
586 return map_nt_error_from_unix(errno
);
589 /* Special behaviours */
590 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
, conn
, ¶ms
)) {
591 return NT_STATUS_NO_MEMORY
;
594 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
595 mem_ctx
, ppdesc
, theacl
);
598 static void smbacl4_dump_nfs4acl(int level
, SMB4ACL_T
*theacl
)
600 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
601 SMB_ACE4_INT_T
*aceint
;
603 DEBUG(level
, ("NFS4ACL: size=%d\n", aclint
->naces
));
605 for (aceint
= aclint
->first
;
607 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
608 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
610 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
611 "mask=0x%x, id=%d\n",
613 ace
->aceFlags
, ace
->flags
,
620 * Find 2 NFS4 who-special ACE property (non-copy!!!)
621 * match nonzero if "special" and who is equal
622 * return ace if found matching; otherwise NULL
624 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
626 SMB_ACE4PROP_T
*aceNew
)
628 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
629 SMB_ACE4_INT_T
*aceint
;
631 for (aceint
= aclint
->first
; aceint
!= NULL
;
632 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
633 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
635 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
636 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
637 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
638 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
640 if (ace
->flags
== aceNew
->flags
&&
641 ace
->aceType
==aceNew
->aceType
&&
642 ace
->aceFlags
==aceNew
->aceFlags
)
644 /* keep type safety; e.g. gid is an u.short */
645 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
647 if (ace
->who
.special_id
==
648 aceNew
->who
.special_id
)
651 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
653 if (ace
->who
.gid
==aceNew
->who
.gid
)
656 if (ace
->who
.uid
==aceNew
->who
.uid
)
667 static bool smbacl4_fill_ace4(
668 const struct smb_filename
*filename
,
669 smbacl4_vfs_params
*params
,
672 const struct security_ace
*ace_nt
, /* input */
673 SMB_ACE4PROP_T
*ace_v4
/* output */
676 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt
->trustee
)));
678 memset(ace_v4
, 0, sizeof(SMB_ACE4PROP_T
));
680 /* only ACCESS|DENY supported right now */
681 ace_v4
->aceType
= ace_nt
->type
;
683 ace_v4
->aceFlags
= map_windows_ace_flags_to_nfs4_ace_flags(
686 /* remove inheritance flags on files */
687 if (VALID_STAT(filename
->st
) &&
688 !S_ISDIR(filename
->st
.st_ex_mode
)) {
689 DEBUG(10, ("Removing inheritance flags from a file\n"));
690 ace_v4
->aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
691 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
692 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
693 SMB_ACE4_INHERIT_ONLY_ACE
);
696 ace_v4
->aceMask
= ace_nt
->access_mask
&
697 (SEC_STD_ALL
| SEC_FILE_ALL
);
699 se_map_generic(&ace_v4
->aceMask
, &file_generic_mapping
);
701 if (ace_v4
->aceFlags
!=ace_nt
->flags
)
702 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
703 ace_v4
->aceFlags
, ace_nt
->flags
));
705 if (ace_v4
->aceMask
!=ace_nt
->access_mask
)
706 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
707 ace_v4
->aceMask
, ace_nt
->access_mask
));
709 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
710 ace_v4
->who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
711 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
712 } else if (params
->mode
!=e_special
&&
713 dom_sid_equal(&ace_nt
->trustee
,
714 &global_sid_Creator_Owner
)) {
715 DEBUG(10, ("Map creator owner\n"));
716 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
717 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
718 /* A non inheriting creator owner entry has no effect. */
719 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
720 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
721 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
724 } else if (params
->mode
!=e_special
&&
725 dom_sid_equal(&ace_nt
->trustee
,
726 &global_sid_Creator_Group
)) {
727 DEBUG(10, ("Map creator owner group\n"));
728 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
729 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
730 /* A non inheriting creator group entry has no effect. */
731 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
732 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
733 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
740 if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
741 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
742 ace_v4
->who
.gid
= gid
;
743 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
744 ace_v4
->who
.uid
= uid
;
746 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
747 "convert %s to uid or gid\n",
749 sid_string_dbg(&ace_nt
->trustee
)));
754 return true; /* OK */
757 static int smbacl4_MergeIgnoreReject(
758 enum smbacl4_acedup_enum acedup
,
759 SMB4ACL_T
*theacl
, /* may modify it */
760 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
766 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
771 case e_merge
: /* "merge" flags */
773 ace4found
->aceFlags
|= ace
->aceFlags
;
774 ace4found
->aceMask
|= ace
->aceMask
;
776 case e_ignore
: /* leave out this record */
779 case e_reject
: /* do an error */
780 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
781 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
791 static int smbacl4_substitute_special(
797 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
798 SMB_ACE4_INT_T
*aceint
;
800 for(aceint
= aclint
->first
; aceint
!=NULL
; aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
801 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
803 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
804 "mask: %x, who: %d\n",
805 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
806 ace
->aceMask
, ace
->who
.id
));
808 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
809 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
810 ace
->who
.uid
== ownerUID
) {
811 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
812 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
813 DEBUG(10,("replaced with special owner ace\n"));
816 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
817 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
818 ace
->who
.uid
== ownerGID
) {
819 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
820 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
821 DEBUG(10,("replaced with special group ace\n"));
824 return true; /* OK */
827 static int smbacl4_substitute_simple(
833 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
834 SMB_ACE4_INT_T
*aceint
;
836 for(aceint
= aclint
->first
; aceint
!=NULL
; aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
837 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
839 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
840 "mask: %x, who: %d\n",
841 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
842 ace
->aceMask
, ace
->who
.id
));
844 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
845 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
846 ace
->who
.uid
== ownerUID
&&
847 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
848 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
849 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
850 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
851 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
852 DEBUG(10,("replaced with special owner ace\n"));
855 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
856 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
857 ace
->who
.uid
== ownerGID
&&
858 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
859 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
860 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
861 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
862 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
863 DEBUG(10,("replaced with special group ace\n"));
866 return true; /* OK */
869 static SMB4ACL_T
*smbacl4_win2nfs4(
871 const files_struct
*fsp
,
872 const struct security_acl
*dacl
,
873 smbacl4_vfs_params
*pparams
,
880 const char *filename
= fsp
->fsp_name
->base_name
;
882 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
884 theacl
= smb_create_smb4acl(mem_ctx
);
888 for(i
=0; i
<dacl
->num_aces
; i
++) {
889 SMB_ACE4PROP_T ace_v4
;
890 bool addNewACE
= true;
892 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
894 dacl
->aces
+ i
, &ace_v4
)) {
895 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
897 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
901 if (pparams
->acedup
!=e_dontcare
) {
902 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
903 &ace_v4
, &addNewACE
, i
))
908 smb_add_ace4(theacl
, &ace_v4
);
911 if (pparams
->mode
==e_simple
) {
912 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
915 if (pparams
->mode
==e_special
) {
916 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
922 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
923 uint32 security_info_sent
,
924 const struct security_descriptor
*psd
,
925 set_nfs4acl_native_fn_t set_nfs4_native
)
927 smbacl4_vfs_params params
;
928 SMB4ACL_T
*theacl
= NULL
;
931 SMB_STRUCT_STAT sbuf
;
932 bool set_acl_as_root
= false;
933 uid_t newUID
= (uid_t
)-1;
934 gid_t newGID
= (gid_t
)-1;
936 TALLOC_CTX
*frame
= talloc_stackframe();
938 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
940 if ((security_info_sent
& (SECINFO_DACL
|
941 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
943 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
944 security_info_sent
));
946 return NT_STATUS_OK
; /* won't show error - later to be
950 /* Special behaviours */
951 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
,
952 fsp
->conn
, ¶ms
)) {
954 return NT_STATUS_NO_MEMORY
;
957 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
959 return map_nt_error_from_unix(errno
);
962 if (params
.do_chown
) {
963 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
964 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
965 security_info_sent
, psd
);
966 if (!NT_STATUS_IS_OK(status
)) {
967 DEBUG(8, ("unpack_nt_owners failed"));
971 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
972 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
974 status
= try_chown(fsp
, newUID
, newGID
);
975 if (!NT_STATUS_IS_OK(status
)) {
976 DEBUG(3,("chown %s, %u, %u failed. Error = "
977 "%s.\n", fsp_str_dbg(fsp
),
978 (unsigned int)newUID
,
979 (unsigned int)newGID
,
985 DEBUG(10,("chown %s, %u, %u succeeded.\n",
986 fsp_str_dbg(fsp
), (unsigned int)newUID
,
987 (unsigned int)newGID
));
988 if (smbacl4_GetFileOwner(fsp
->conn
,
989 fsp
->fsp_name
->base_name
,
992 return map_nt_error_from_unix(errno
);
995 /* If we successfully chowned, we know we must
996 * be able to set the acl, so do it as root.
998 set_acl_as_root
= true;
1002 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
1003 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1004 security_info_sent
));
1006 return NT_STATUS_OK
;
1009 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, ¶ms
,
1010 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
1013 return map_nt_error_from_unix(errno
);
1016 smbacl4_dump_nfs4acl(10, theacl
);
1018 if (set_acl_as_root
) {
1021 result
= set_nfs4_native(handle
, fsp
, theacl
);
1022 saved_errno
= errno
;
1023 if (set_acl_as_root
) {
1030 errno
= saved_errno
;
1031 DEBUG(10, ("set_nfs4_native failed with %s\n",
1033 return map_nt_error_from_unix(errno
);
1036 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1037 return NT_STATUS_OK
;