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
;
67 * Gather special parameters for NFS4 ACL handling
69 static int smbacl4_get_vfs_params(
70 const char *type_name
,
71 struct connection_struct
*conn
,
72 smbacl4_vfs_params
*params
75 static const struct enum_list enum_smbacl4_modes
[] = {
76 { e_simple
, "simple" },
77 { e_special
, "special" },
80 static const struct enum_list enum_smbacl4_acedups
[] = {
81 { e_dontcare
, "dontcare" },
82 { e_reject
, "reject" },
83 { e_ignore
, "ignore" },
88 memset(params
, 0, sizeof(smbacl4_vfs_params
));
89 params
->mode
= (enum smbacl4_mode_enum
)lp_parm_enum(
90 SNUM(conn
), type_name
,
91 "mode", enum_smbacl4_modes
, e_simple
);
92 params
->do_chown
= lp_parm_bool(SNUM(conn
), type_name
,
94 params
->acedup
= (enum smbacl4_acedup_enum
)lp_parm_enum(
95 SNUM(conn
), type_name
,
96 "acedup", enum_smbacl4_acedups
, e_dontcare
);
98 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s\n",
99 enum_smbacl4_modes
[params
->mode
].name
,
100 params
->do_chown
? "true" : "false",
101 enum_smbacl4_acedups
[params
->acedup
].name
));
106 /************************************************
107 Split the ACE flag mapping between nfs4 and Windows
108 into two separate functions rather than trying to do
109 it inline. Allows us to carefully control what flags
110 are mapped to what in one place.
111 ************************************************/
113 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
114 uint32_t nfs4_ace_flags
)
116 uint32_t win_ace_flags
= 0;
118 /* The nfs4 flags <= 0xf map perfectly. */
119 win_ace_flags
= nfs4_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
120 SEC_ACE_FLAG_CONTAINER_INHERIT
|
121 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT
|
122 SEC_ACE_FLAG_INHERIT_ONLY
);
124 /* flags greater than 0xf have diverged :-(. */
125 /* See the nfs4 ace flag definitions here:
126 http://www.ietf.org/rfc/rfc3530.txt.
127 And the Windows ace flag definitions here:
128 librpc/idl/security.idl. */
129 if (nfs4_ace_flags
& SMB_ACE4_INHERITED_ACE
) {
130 win_ace_flags
|= SEC_ACE_FLAG_INHERITED_ACE
;
133 return win_ace_flags
;
136 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags
)
138 uint32_t nfs4_ace_flags
= 0;
140 /* The windows flags <= 0xf map perfectly. */
141 nfs4_ace_flags
= win_ace_flags
& (SMB_ACE4_FILE_INHERIT_ACE
|
142 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
143 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
144 SMB_ACE4_INHERIT_ONLY_ACE
);
146 /* flags greater than 0xf have diverged :-(. */
147 /* See the nfs4 ace flag definitions here:
148 http://www.ietf.org/rfc/rfc3530.txt.
149 And the Windows ace flag definitions here:
150 librpc/idl/security.idl. */
151 if (win_ace_flags
& SEC_ACE_FLAG_INHERITED_ACE
) {
152 nfs4_ace_flags
|= SMB_ACE4_INHERITED_ACE
;
155 return nfs4_ace_flags
;
158 static SMB_ACL4_INT_T
*get_validated_aclint(SMB4ACL_T
*theacl
)
160 SMB_ACL4_INT_T
*aclint
= (SMB_ACL4_INT_T
*)theacl
;
163 DEBUG(2, ("acl is NULL\n"));
167 if (aclint
->magic
!=SMB_ACL4_INT_MAGIC
)
169 DEBUG(2, ("aclint bad magic 0x%x\n", aclint
->magic
));
176 static SMB_ACE4_INT_T
*get_validated_aceint(SMB4ACE_T
*ace
)
178 SMB_ACE4_INT_T
*aceint
= (SMB_ACE4_INT_T
*)ace
;
181 DEBUG(2, ("ace is NULL\n"));
185 if (aceint
->magic
!=SMB_ACE4_INT_MAGIC
)
187 DEBUG(2, ("aceint bad magic 0x%x\n", aceint
->magic
));
194 SMB4ACL_T
*smb_create_smb4acl(TALLOC_CTX
*mem_ctx
)
196 SMB_ACL4_INT_T
*theacl
= (SMB_ACL4_INT_T
*)TALLOC_ZERO_SIZE(
197 mem_ctx
, sizeof(SMB_ACL4_INT_T
));
200 DEBUG(0, ("TALLOC_SIZE failed\n"));
204 theacl
->magic
= SMB_ACL4_INT_MAGIC
;
205 /* theacl->first, last = NULL not needed */
206 return (SMB4ACL_T
*)theacl
;
209 SMB4ACE_T
*smb_add_ace4(SMB4ACL_T
*theacl
, SMB_ACE4PROP_T
*prop
)
211 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
214 ace
= (SMB_ACE4_INT_T
*)TALLOC_ZERO_SIZE(
215 theacl
, sizeof(SMB_ACE4_INT_T
));
218 DEBUG(0, ("TALLOC_SIZE failed\n"));
222 ace
->magic
= SMB_ACE4_INT_MAGIC
;
223 /* ace->next = NULL not needed */
224 memcpy(&ace
->prop
, prop
, sizeof(SMB_ACE4PROP_T
));
226 if (aclint
->first
==NULL
)
231 aclint
->last
->next
= (void *)ace
;
236 return (SMB4ACE_T
*)ace
;
239 SMB_ACE4PROP_T
*smb_get_ace4(SMB4ACE_T
*ace
)
241 SMB_ACE4_INT_T
*aceint
= get_validated_aceint(ace
);
245 return &aceint
->prop
;
248 SMB4ACE_T
*smb_next_ace4(SMB4ACE_T
*ace
)
250 SMB_ACE4_INT_T
*aceint
= get_validated_aceint(ace
);
254 return (SMB4ACE_T
*)aceint
->next
;
257 SMB4ACE_T
*smb_first_ace4(SMB4ACL_T
*theacl
)
259 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
263 return (SMB4ACE_T
*)aclint
->first
;
266 uint32
smb_get_naces(SMB4ACL_T
*theacl
)
268 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
272 return aclint
->naces
;
275 static int smbacl4_GetFileOwner(struct connection_struct
*conn
,
276 const char *filename
,
277 SMB_STRUCT_STAT
*psbuf
)
279 memset(psbuf
, 0, sizeof(SMB_STRUCT_STAT
));
281 /* Get the stat struct for the owner info. */
282 if (vfs_stat_smb_fname(conn
, filename
, psbuf
) != 0)
284 DEBUG(8, ("vfs_stat_smb_fname failed with error %s\n",
292 static int smbacl4_fGetFileOwner(files_struct
*fsp
, SMB_STRUCT_STAT
*psbuf
)
294 memset(psbuf
, 0, sizeof(SMB_STRUCT_STAT
));
296 if (fsp
->fh
->fd
== -1) {
297 return smbacl4_GetFileOwner(fsp
->conn
,
298 fsp
->fsp_name
->base_name
, psbuf
);
300 if (SMB_VFS_FSTAT(fsp
, psbuf
) != 0)
302 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
310 static bool smbacl4_nfs42win(TALLOC_CTX
*mem_ctx
,
311 smbacl4_vfs_params
*params
,
312 SMB4ACL_T
*theacl
, /* in */
313 struct dom_sid
*psid_owner
, /* in */
314 struct dom_sid
*psid_group
, /* in */
315 bool is_directory
, /* in */
316 struct security_ace
**ppnt_ace_list
, /* out */
317 int *pgood_aces
/* out */
320 SMB_ACL4_INT_T
*aclint
= (SMB_ACL4_INT_T
*)theacl
;
321 SMB_ACE4_INT_T
*aceint
;
322 struct security_ace
*nt_ace_list
= NULL
;
325 DEBUG(10, ("smbacl_nfs42win entered\n"));
327 aclint
= get_validated_aclint(theacl
);
328 /* We do not check for naces being 0 or theacl being NULL here
329 because it is done upstream in smb_get_nt_acl_nfs4().
330 We reserve twice the number of input aces because one nfs4
331 ace might result in 2 nt aces.*/
332 nt_ace_list
= (struct security_ace
*)TALLOC_ZERO_SIZE(
333 mem_ctx
, 2 * aclint
->naces
* sizeof(struct security_ace
));
334 if (nt_ace_list
==NULL
)
336 DEBUG(10, ("talloc error"));
341 for (aceint
=aclint
->first
;
343 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
346 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
347 uint32_t win_ace_flags
;
349 DEBUG(10, ("magic: 0x%x, type: %d, iflags: %x, flags: %x, "
350 "mask: %x, who: %d\n",
351 aceint
->magic
, ace
->aceType
, ace
->flags
,
352 ace
->aceFlags
, ace
->aceMask
, ace
->who
.id
));
354 SMB_ASSERT(aceint
->magic
==SMB_ACE4_INT_MAGIC
);
356 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
) {
357 switch (ace
->who
.special_id
) {
358 case SMB_ACE4_WHO_OWNER
:
359 sid_copy(&sid
, psid_owner
);
361 case SMB_ACE4_WHO_GROUP
:
362 sid_copy(&sid
, psid_group
);
364 case SMB_ACE4_WHO_EVERYONE
:
365 sid_copy(&sid
, &global_sid_World
);
368 DEBUG(8, ("invalid special who id %d "
369 "ignored\n", ace
->who
.special_id
));
373 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) {
374 gid_to_sid(&sid
, ace
->who
.gid
);
376 uid_to_sid(&sid
, ace
->who
.uid
);
379 DEBUG(10, ("mapped %d to %s\n", ace
->who
.id
,
380 sid_string_dbg(&sid
)));
382 if (is_directory
&& (ace
->aceMask
& SMB_ACE4_ADD_FILE
)) {
383 ace
->aceMask
|= SMB_ACE4_DELETE_CHILD
;
386 win_ace_flags
= map_nfs4_ace_flags_to_windows_ace_flags(
389 (win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
390 SEC_ACE_FLAG_CONTAINER_INHERIT
))) {
392 * GPFS sets inherits dir_inhert and file_inherit flags
393 * to files, too, which confuses windows, and seems to
394 * be wrong anyways. ==> Map these bits away for files.
396 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
397 win_ace_flags
&= ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
398 SEC_ACE_FLAG_CONTAINER_INHERIT
);
400 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
401 ace
->aceFlags
, win_ace_flags
));
404 /* Windows clients expect SYNC on acls to
405 correctly allow rename. See bug #7909. */
406 /* But not on DENY ace entries. See
408 if(ace
->aceType
== SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE
) {
409 mask
= ace
->aceMask
| SMB_ACE4_SYNCHRONIZE
;
412 /* Mapping of owner@ and group@ to creator owner and
413 creator group. Keep old behavior in mode special. */
414 if (params
->mode
!= e_special
&&
415 ace
->flags
& SMB_ACE4_ID_SPECIAL
&&
416 (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
||
417 ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
)) {
418 DEBUG(10, ("Map special entry\n"));
419 if (!(win_ace_flags
& SEC_ACE_FLAG_INHERIT_ONLY
)) {
420 uint32_t win_ace_flags_current
;
421 DEBUG(10, ("Map current sid\n"));
422 win_ace_flags_current
= win_ace_flags
&
423 ~(SEC_ACE_FLAG_OBJECT_INHERIT
|
424 SEC_ACE_FLAG_CONTAINER_INHERIT
);
425 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
427 win_ace_flags_current
);
429 if (ace
->who
.special_id
== SMB_ACE4_WHO_OWNER
&&
430 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
431 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
432 uint32_t win_ace_flags_creator
;
433 DEBUG(10, ("Map creator owner\n"));
434 win_ace_flags_creator
= win_ace_flags
|
435 SMB_ACE4_INHERIT_ONLY_ACE
;
436 init_sec_ace(&nt_ace_list
[good_aces
++],
437 &global_sid_Creator_Owner
,
439 win_ace_flags_creator
);
441 if (ace
->who
.special_id
== SMB_ACE4_WHO_GROUP
&&
442 win_ace_flags
& (SEC_ACE_FLAG_OBJECT_INHERIT
|
443 SEC_ACE_FLAG_CONTAINER_INHERIT
)) {
444 uint32_t win_ace_flags_creator
;
445 DEBUG(10, ("Map creator owner group\n"));
446 win_ace_flags_creator
= win_ace_flags
|
447 SMB_ACE4_INHERIT_ONLY_ACE
;
448 init_sec_ace(&nt_ace_list
[good_aces
++],
449 &global_sid_Creator_Group
,
451 win_ace_flags_creator
);
454 DEBUG(10, ("Map normal sid\n"));
455 init_sec_ace(&nt_ace_list
[good_aces
++], &sid
,
461 nt_ace_list
= (struct security_ace
*)TALLOC_REALLOC(mem_ctx
,
463 good_aces
* sizeof(struct security_ace
));
464 if (nt_ace_list
== NULL
) {
469 *ppnt_ace_list
= nt_ace_list
;
470 *pgood_aces
= good_aces
;
475 static NTSTATUS
smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT
*sbuf
,
476 smbacl4_vfs_params
*params
,
477 uint32 security_info
,
479 struct security_descriptor
**ppdesc
,
483 struct dom_sid sid_owner
, sid_group
;
485 struct security_ace
*nt_ace_list
= NULL
;
486 struct security_acl
*psa
= NULL
;
487 TALLOC_CTX
*frame
= talloc_stackframe();
489 if (theacl
==NULL
|| smb_get_naces(theacl
)==0) {
491 return NT_STATUS_ACCESS_DENIED
; /* special because we
492 * shouldn't alloc 0 for
496 uid_to_sid(&sid_owner
, sbuf
->st_ex_uid
);
497 gid_to_sid(&sid_group
, sbuf
->st_ex_gid
);
499 if (smbacl4_nfs42win(mem_ctx
, params
, theacl
, &sid_owner
, &sid_group
,
500 S_ISDIR(sbuf
->st_ex_mode
),
501 &nt_ace_list
, &good_aces
)==false) {
502 DEBUG(8,("smbacl4_nfs42win failed\n"));
504 return map_nt_error_from_unix(errno
);
507 psa
= make_sec_acl(frame
, NT4_ACL_REVISION
, good_aces
, nt_ace_list
);
509 DEBUG(2,("make_sec_acl failed\n"));
511 return NT_STATUS_NO_MEMORY
;
514 DEBUG(10,("after make sec_acl\n"));
515 *ppdesc
= make_sec_desc(
516 mem_ctx
, SD_REVISION
, SEC_DESC_SELF_RELATIVE
,
517 (security_info
& SECINFO_OWNER
) ? &sid_owner
: NULL
,
518 (security_info
& SECINFO_GROUP
) ? &sid_group
: NULL
,
519 NULL
, psa
, &sd_size
);
521 DEBUG(2,("make_sec_desc failed\n"));
523 return NT_STATUS_NO_MEMORY
;
526 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
528 (int)ndr_size_security_descriptor(*ppdesc
, 0)));
534 NTSTATUS
smb_fget_nt_acl_nfs4(files_struct
*fsp
,
535 uint32 security_info
,
537 struct security_descriptor
**ppdesc
,
540 SMB_STRUCT_STAT sbuf
;
541 smbacl4_vfs_params params
;
543 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
545 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
546 return map_nt_error_from_unix(errno
);
549 /* Special behaviours */
550 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
, fsp
->conn
, ¶ms
)) {
551 return NT_STATUS_NO_MEMORY
;
554 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
555 mem_ctx
, ppdesc
, theacl
);
558 NTSTATUS
smb_get_nt_acl_nfs4(struct connection_struct
*conn
,
560 uint32 security_info
,
562 struct security_descriptor
**ppdesc
,
565 SMB_STRUCT_STAT sbuf
;
566 smbacl4_vfs_params params
;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name
));
570 if (smbacl4_GetFileOwner(conn
, name
, &sbuf
)) {
571 return map_nt_error_from_unix(errno
);
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
, conn
, ¶ms
)) {
576 return NT_STATUS_NO_MEMORY
;
579 return smb_get_nt_acl_nfs4_common(&sbuf
, ¶ms
, security_info
,
580 mem_ctx
, ppdesc
, theacl
);
583 static void smbacl4_dump_nfs4acl(int level
, SMB4ACL_T
*theacl
)
585 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
586 SMB_ACE4_INT_T
*aceint
;
588 DEBUG(level
, ("NFS4ACL: size=%d\n", aclint
->naces
));
590 for (aceint
= aclint
->first
;
592 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
593 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
595 DEBUG(level
, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
596 "mask=0x%x, id=%d\n",
598 ace
->aceFlags
, ace
->flags
,
605 * Find 2 NFS4 who-special ACE property (non-copy!!!)
606 * match nonzero if "special" and who is equal
607 * return ace if found matching; otherwise NULL
609 static SMB_ACE4PROP_T
*smbacl4_find_equal_special(
611 SMB_ACE4PROP_T
*aceNew
)
613 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
614 SMB_ACE4_INT_T
*aceint
;
616 for (aceint
= aclint
->first
; aceint
!= NULL
;
617 aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
618 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
620 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
621 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
622 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
623 aceNew
->aceType
, aceNew
->flags
,aceNew
->aceFlags
));
625 if (ace
->flags
== aceNew
->flags
&&
626 ace
->aceType
==aceNew
->aceType
&&
627 ace
->aceFlags
==aceNew
->aceFlags
)
629 /* keep type safety; e.g. gid is an u.short */
630 if (ace
->flags
& SMB_ACE4_ID_SPECIAL
)
632 if (ace
->who
.special_id
==
633 aceNew
->who
.special_id
)
636 if (ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
)
638 if (ace
->who
.gid
==aceNew
->who
.gid
)
641 if (ace
->who
.uid
==aceNew
->who
.uid
)
652 static bool smbacl4_fill_ace4(
653 const struct smb_filename
*filename
,
654 smbacl4_vfs_params
*params
,
657 const struct security_ace
*ace_nt
, /* input */
658 SMB_ACE4PROP_T
*ace_v4
/* output */
661 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt
->trustee
)));
663 memset(ace_v4
, 0, sizeof(SMB_ACE4PROP_T
));
665 /* only ACCESS|DENY supported right now */
666 ace_v4
->aceType
= ace_nt
->type
;
668 ace_v4
->aceFlags
= map_windows_ace_flags_to_nfs4_ace_flags(
671 /* remove inheritance flags on files */
672 if (VALID_STAT(filename
->st
) &&
673 !S_ISDIR(filename
->st
.st_ex_mode
)) {
674 DEBUG(10, ("Removing inheritance flags from a file\n"));
675 ace_v4
->aceFlags
&= ~(SMB_ACE4_FILE_INHERIT_ACE
|
676 SMB_ACE4_DIRECTORY_INHERIT_ACE
|
677 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE
|
678 SMB_ACE4_INHERIT_ONLY_ACE
);
681 ace_v4
->aceMask
= ace_nt
->access_mask
&
682 (SEC_STD_ALL
| SEC_FILE_ALL
);
684 se_map_generic(&ace_v4
->aceMask
, &file_generic_mapping
);
686 if (ace_v4
->aceFlags
!=ace_nt
->flags
)
687 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
688 ace_v4
->aceFlags
, ace_nt
->flags
));
690 if (ace_v4
->aceMask
!=ace_nt
->access_mask
)
691 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
692 ace_v4
->aceMask
, ace_nt
->access_mask
));
694 if (dom_sid_equal(&ace_nt
->trustee
, &global_sid_World
)) {
695 ace_v4
->who
.special_id
= SMB_ACE4_WHO_EVERYONE
;
696 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
697 } else if (params
->mode
!=e_special
&&
698 dom_sid_equal(&ace_nt
->trustee
,
699 &global_sid_Creator_Owner
)) {
700 DEBUG(10, ("Map creator owner\n"));
701 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
702 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
703 /* A non inheriting creator owner entry has no effect. */
704 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
705 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
706 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
709 } else if (params
->mode
!=e_special
&&
710 dom_sid_equal(&ace_nt
->trustee
,
711 &global_sid_Creator_Group
)) {
712 DEBUG(10, ("Map creator owner group\n"));
713 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
714 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
715 /* A non inheriting creator group entry has no effect. */
716 ace_v4
->aceFlags
|= SMB_ACE4_INHERIT_ONLY_ACE
;
717 if (!(ace_v4
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)
718 && !(ace_v4
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
)) {
725 if (sid_to_gid(&ace_nt
->trustee
, &gid
)) {
726 ace_v4
->aceFlags
|= SMB_ACE4_IDENTIFIER_GROUP
;
728 if (params
->mode
==e_special
&& gid
==ownerGID
) {
729 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
730 ace_v4
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
732 ace_v4
->who
.gid
= gid
;
734 } else if (sid_to_uid(&ace_nt
->trustee
, &uid
)) {
735 if (params
->mode
==e_special
&& uid
==ownerUID
) {
736 ace_v4
->flags
|= SMB_ACE4_ID_SPECIAL
;
737 ace_v4
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
739 ace_v4
->who
.uid
= uid
;
742 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
743 "convert %s to uid or gid\n",
745 sid_string_dbg(&ace_nt
->trustee
)));
750 return true; /* OK */
753 static int smbacl4_MergeIgnoreReject(
754 enum smbacl4_acedup_enum acedup
,
755 SMB4ACL_T
*theacl
, /* may modify it */
756 SMB_ACE4PROP_T
*ace
, /* the "new" ACE */
762 SMB_ACE4PROP_T
*ace4found
= smbacl4_find_equal_special(theacl
, ace
);
767 case e_merge
: /* "merge" flags */
769 ace4found
->aceFlags
|= ace
->aceFlags
;
770 ace4found
->aceMask
|= ace
->aceMask
;
772 case e_ignore
: /* leave out this record */
775 case e_reject
: /* do an error */
776 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i
));
777 errno
= EINVAL
; /* SHOULD be set on any _real_ error */
787 static int smbacl4_substitute_special(
793 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
794 SMB_ACE4_INT_T
*aceint
;
796 for(aceint
= aclint
->first
; aceint
!=NULL
; aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
797 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
799 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
800 "mask: %x, who: %d\n",
801 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
802 ace
->aceMask
, ace
->who
.id
));
804 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
805 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
806 ace
->who
.uid
== ownerUID
) {
807 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
808 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
809 DEBUG(10,("replaced with special owner ace\n"));
812 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
813 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
814 ace
->who
.uid
== ownerGID
) {
815 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
816 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
817 DEBUG(10,("replaced with special group ace\n"));
820 return true; /* OK */
823 static int smbacl4_substitute_simple(
829 SMB_ACL4_INT_T
*aclint
= get_validated_aclint(theacl
);
830 SMB_ACE4_INT_T
*aceint
;
832 for(aceint
= aclint
->first
; aceint
!=NULL
; aceint
=(SMB_ACE4_INT_T
*)aceint
->next
) {
833 SMB_ACE4PROP_T
*ace
= &aceint
->prop
;
835 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
836 "mask: %x, who: %d\n",
837 ace
->aceType
, ace
->flags
, ace
->aceFlags
,
838 ace
->aceMask
, ace
->who
.id
));
840 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
841 !(ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
) &&
842 ace
->who
.uid
== ownerUID
&&
843 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
844 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
845 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
846 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
847 ace
->who
.special_id
= SMB_ACE4_WHO_OWNER
;
848 DEBUG(10,("replaced with special owner ace\n"));
851 if (!(ace
->flags
& SMB_ACE4_ID_SPECIAL
) &&
852 ace
->aceFlags
& SMB_ACE4_IDENTIFIER_GROUP
&&
853 ace
->who
.uid
== ownerGID
&&
854 !(ace
->aceFlags
& SMB_ACE4_INHERIT_ONLY_ACE
) &&
855 !(ace
->aceFlags
& SMB_ACE4_FILE_INHERIT_ACE
) &&
856 !(ace
->aceFlags
& SMB_ACE4_DIRECTORY_INHERIT_ACE
)) {
857 ace
->flags
|= SMB_ACE4_ID_SPECIAL
;
858 ace
->who
.special_id
= SMB_ACE4_WHO_GROUP
;
859 DEBUG(10,("replaced with special group ace\n"));
862 return true; /* OK */
865 static SMB4ACL_T
*smbacl4_win2nfs4(
867 const files_struct
*fsp
,
868 const struct security_acl
*dacl
,
869 smbacl4_vfs_params
*pparams
,
876 const char *filename
= fsp
->fsp_name
->base_name
;
878 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
880 theacl
= smb_create_smb4acl(mem_ctx
);
884 for(i
=0; i
<dacl
->num_aces
; i
++) {
885 SMB_ACE4PROP_T ace_v4
;
886 bool addNewACE
= true;
888 if (!smbacl4_fill_ace4(fsp
->fsp_name
, pparams
,
890 dacl
->aces
+ i
, &ace_v4
)) {
891 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
893 sid_string_dbg(&((dacl
->aces
+i
)->trustee
))));
897 if (pparams
->acedup
!=e_dontcare
) {
898 if (smbacl4_MergeIgnoreReject(pparams
->acedup
, theacl
,
899 &ace_v4
, &addNewACE
, i
))
904 smb_add_ace4(theacl
, &ace_v4
);
907 if (pparams
->mode
==e_simple
) {
908 smbacl4_substitute_simple(theacl
, ownerUID
, ownerGID
);
911 if (pparams
->mode
==e_special
) {
912 smbacl4_substitute_special(theacl
, ownerUID
, ownerGID
);
918 NTSTATUS
smb_set_nt_acl_nfs4(vfs_handle_struct
*handle
, files_struct
*fsp
,
919 uint32 security_info_sent
,
920 const struct security_descriptor
*psd
,
921 set_nfs4acl_native_fn_t set_nfs4_native
)
923 smbacl4_vfs_params params
;
924 SMB4ACL_T
*theacl
= NULL
;
927 SMB_STRUCT_STAT sbuf
;
928 bool set_acl_as_root
= false;
929 uid_t newUID
= (uid_t
)-1;
930 gid_t newGID
= (gid_t
)-1;
932 TALLOC_CTX
*frame
= talloc_stackframe();
934 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp
)));
936 if ((security_info_sent
& (SECINFO_DACL
|
937 SECINFO_GROUP
| SECINFO_OWNER
)) == 0)
939 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
940 security_info_sent
));
942 return NT_STATUS_OK
; /* won't show error - later to be
946 /* Special behaviours */
947 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME
,
948 fsp
->conn
, ¶ms
)) {
950 return NT_STATUS_NO_MEMORY
;
953 if (smbacl4_fGetFileOwner(fsp
, &sbuf
)) {
955 return map_nt_error_from_unix(errno
);
958 if (params
.do_chown
) {
959 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
960 NTSTATUS status
= unpack_nt_owners(fsp
->conn
, &newUID
, &newGID
,
961 security_info_sent
, psd
);
962 if (!NT_STATUS_IS_OK(status
)) {
963 DEBUG(8, ("unpack_nt_owners failed"));
967 if (((newUID
!= (uid_t
)-1) && (sbuf
.st_ex_uid
!= newUID
)) ||
968 ((newGID
!= (gid_t
)-1) && (sbuf
.st_ex_gid
!= newGID
))) {
970 status
= try_chown(fsp
, newUID
, newGID
);
971 if (!NT_STATUS_IS_OK(status
)) {
972 DEBUG(3,("chown %s, %u, %u failed. Error = "
973 "%s.\n", fsp_str_dbg(fsp
),
974 (unsigned int)newUID
,
975 (unsigned int)newGID
,
981 DEBUG(10,("chown %s, %u, %u succeeded.\n",
982 fsp_str_dbg(fsp
), (unsigned int)newUID
,
983 (unsigned int)newGID
));
984 if (smbacl4_GetFileOwner(fsp
->conn
,
985 fsp
->fsp_name
->base_name
,
988 return map_nt_error_from_unix(errno
);
990 /* If we successfully chowned, we know we must
991 * be able to set the acl, so do it as root.
993 set_acl_as_root
= true;
997 if (!(security_info_sent
& SECINFO_DACL
) || psd
->dacl
==NULL
) {
998 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
999 security_info_sent
));
1001 return NT_STATUS_OK
;
1004 theacl
= smbacl4_win2nfs4(frame
, fsp
, psd
->dacl
, ¶ms
,
1005 sbuf
.st_ex_uid
, sbuf
.st_ex_gid
);
1008 return map_nt_error_from_unix(errno
);
1011 smbacl4_dump_nfs4acl(10, theacl
);
1013 if (set_acl_as_root
) {
1016 result
= set_nfs4_native(handle
, fsp
, theacl
);
1017 saved_errno
= errno
;
1018 if (set_acl_as_root
) {
1025 errno
= saved_errno
;
1026 DEBUG(10, ("set_nfs4_native failed with %s\n",
1028 return map_nt_error_from_unix(errno
);
1031 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1032 return NT_STATUS_OK
;