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_fname(conn, filename, psbuf) != 0)
287 DEBUG(8, ("vfs_stat_smb_fname 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 theacl being NULL here
332 because this is already checked 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 with %d aces", aclint->naces));
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 *)
477 TALLOC_REALLOC(mem_ctx, nt_ace_list,
478 good_aces * sizeof(struct security_ace));
479 /* returns a NULL ace list when good_aces is zero. */
480 if (good_aces && nt_ace_list == NULL) {
481 DEBUG(10, ("realloc error with %d aces", good_aces));
486 *ppnt_ace_list = nt_ace_list;
487 *pgood_aces = good_aces;
492 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
493 smbacl4_vfs_params *params,
494 uint32 security_info,
496 struct security_descriptor **ppdesc,
500 struct dom_sid sid_owner, sid_group;
502 struct security_ace *nt_ace_list = NULL;
503 struct security_acl *psa = NULL;
504 TALLOC_CTX *frame = talloc_stackframe();
508 return NT_STATUS_ACCESS_DENIED; /* special because we
509 * need to think through
513 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
514 gid_to_sid(&sid_group, sbuf->st_ex_gid);
516 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
517 S_ISDIR(sbuf->st_ex_mode),
518 &nt_ace_list, &good_aces)==false) {
519 DEBUG(8,("smbacl4_nfs42win failed\n"));
521 return map_nt_error_from_unix(errno);
524 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
526 DEBUG(2,("make_sec_acl failed\n"));
528 return NT_STATUS_NO_MEMORY;
531 DEBUG(10,("after make sec_acl\n"));
532 *ppdesc = make_sec_desc(
533 mem_ctx, SD_REVISION, SEC_DESC_SELF_RELATIVE,
534 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
535 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
536 NULL, psa, &sd_size);
538 DEBUG(2,("make_sec_desc failed\n"));
540 return NT_STATUS_NO_MEMORY;
543 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
545 (int)ndr_size_security_descriptor(*ppdesc, 0)));
551 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
552 uint32 security_info,
554 struct security_descriptor **ppdesc,
557 SMB_STRUCT_STAT sbuf;
558 smbacl4_vfs_params params;
560 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
562 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
563 return map_nt_error_from_unix(errno);
566 /* Special behaviours */
567 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, ¶ms)) {
568 return NT_STATUS_NO_MEMORY;
571 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
572 mem_ctx, ppdesc, theacl);
575 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
577 uint32 security_info,
579 struct security_descriptor **ppdesc,
582 SMB_STRUCT_STAT sbuf;
583 smbacl4_vfs_params params;
585 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
587 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
588 return map_nt_error_from_unix(errno);
591 /* Special behaviours */
592 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, ¶ms)) {
593 return NT_STATUS_NO_MEMORY;
596 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
597 mem_ctx, ppdesc, theacl);
600 static void smbacl4_dump_nfs4acl(int level, SMB4ACL_T *theacl)
602 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
603 SMB_ACE4_INT_T *aceint;
605 DEBUG(level, ("NFS4ACL: size=%d\n", aclint->naces));
607 for (aceint = aclint->first;
609 aceint=(SMB_ACE4_INT_T *)aceint->next) {
610 SMB_ACE4PROP_T *ace = &aceint->prop;
612 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
613 "mask=0x%x, id=%d\n",
615 ace->aceFlags, ace->flags,
622 * Find 2 NFS4 who-special ACE property (non-copy!!!)
623 * match nonzero if "special" and who is equal
624 * return ace if found matching; otherwise NULL
626 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
628 SMB_ACE4PROP_T *aceNew)
630 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
631 SMB_ACE4_INT_T *aceint;
633 for (aceint = aclint->first; aceint != NULL;
634 aceint=(SMB_ACE4_INT_T *)aceint->next) {
635 SMB_ACE4PROP_T *ace = &aceint->prop;
637 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
638 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
639 ace->aceType, ace->flags, ace->aceFlags,
640 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
642 if (ace->flags == aceNew->flags &&
643 ace->aceType==aceNew->aceType &&
644 ace->aceFlags==aceNew->aceFlags)
646 /* keep type safety; e.g. gid is an u.short */
647 if (ace->flags & SMB_ACE4_ID_SPECIAL)
649 if (ace->who.special_id ==
650 aceNew->who.special_id)
653 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
655 if (ace->who.gid==aceNew->who.gid)
658 if (ace->who.uid==aceNew->who.uid)
669 static bool smbacl4_fill_ace4(
670 const struct smb_filename *filename,
671 smbacl4_vfs_params *params,
674 const struct security_ace *ace_nt, /* input */
675 SMB_ACE4PROP_T *ace_v4 /* output */
678 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
680 memset(ace_v4, 0, sizeof(SMB_ACE4PROP_T));
682 /* only ACCESS|DENY supported right now */
683 ace_v4->aceType = ace_nt->type;
685 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
688 /* remove inheritance flags on files */
689 if (VALID_STAT(filename->st) &&
690 !S_ISDIR(filename->st.st_ex_mode)) {
691 DEBUG(10, ("Removing inheritance flags from a file\n"));
692 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
693 SMB_ACE4_DIRECTORY_INHERIT_ACE|
694 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
695 SMB_ACE4_INHERIT_ONLY_ACE);
698 ace_v4->aceMask = ace_nt->access_mask &
699 (SEC_STD_ALL | SEC_FILE_ALL);
701 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
703 if (ace_v4->aceFlags!=ace_nt->flags)
704 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
705 ace_v4->aceFlags, ace_nt->flags));
707 if (ace_v4->aceMask!=ace_nt->access_mask)
708 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
709 ace_v4->aceMask, ace_nt->access_mask));
711 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
712 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
713 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
714 } else if (params->mode!=e_special &&
715 dom_sid_equal(&ace_nt->trustee,
716 &global_sid_Creator_Owner)) {
717 DEBUG(10, ("Map creator owner\n"));
718 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
719 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
720 /* A non inheriting creator owner entry has no effect. */
721 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
722 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
723 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
726 } else if (params->mode!=e_special &&
727 dom_sid_equal(&ace_nt->trustee,
728 &global_sid_Creator_Group)) {
729 DEBUG(10, ("Map creator owner group\n"));
730 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
731 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
732 /* A non inheriting creator group entry has no effect. */
733 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
734 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
735 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
742 if (sid_to_gid(&ace_nt->trustee, &gid)) {
743 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
744 ace_v4->who.gid = gid;
745 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
746 ace_v4->who.uid = uid;
748 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
749 "convert %s to uid or gid\n",
751 sid_string_dbg(&ace_nt->trustee)));
756 return true; /* OK */
759 static int smbacl4_MergeIgnoreReject(
760 enum smbacl4_acedup_enum acedup,
761 SMB4ACL_T *theacl, /* may modify it */
762 SMB_ACE4PROP_T *ace, /* the "new" ACE */
768 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
773 case e_merge: /* "merge" flags */
775 ace4found->aceFlags |= ace->aceFlags;
776 ace4found->aceMask |= ace->aceMask;
778 case e_ignore: /* leave out this record */
781 case e_reject: /* do an error */
782 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
783 errno = EINVAL; /* SHOULD be set on any _real_ error */
793 static int smbacl4_substitute_special(
799 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
800 SMB_ACE4_INT_T *aceint;
802 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)aceint->next) {
803 SMB_ACE4PROP_T *ace = &aceint->prop;
805 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
806 "mask: %x, who: %d\n",
807 ace->aceType, ace->flags, ace->aceFlags,
808 ace->aceMask, ace->who.id));
810 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
811 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
812 ace->who.uid == ownerUID) {
813 ace->flags |= SMB_ACE4_ID_SPECIAL;
814 ace->who.special_id = SMB_ACE4_WHO_OWNER;
815 DEBUG(10,("replaced with special owner ace\n"));
818 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
819 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
820 ace->who.uid == ownerGID) {
821 ace->flags |= SMB_ACE4_ID_SPECIAL;
822 ace->who.special_id = SMB_ACE4_WHO_GROUP;
823 DEBUG(10,("replaced with special group ace\n"));
826 return true; /* OK */
829 static int smbacl4_substitute_simple(
835 SMB_ACL4_INT_T *aclint = get_validated_aclint(theacl);
836 SMB_ACE4_INT_T *aceint;
838 for(aceint = aclint->first; aceint!=NULL; aceint=(SMB_ACE4_INT_T *)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 SMB4ACL_T *smbacl4_win2nfs4(
873 const files_struct *fsp,
874 const struct security_acl *dacl,
875 smbacl4_vfs_params *pparams,
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 uint32 security_info_sent,
926 const struct security_descriptor *psd,
927 set_nfs4acl_native_fn_t set_nfs4_native)
929 smbacl4_vfs_params params;
930 SMB4ACL_T *theacl = NULL;
933 SMB_STRUCT_STAT sbuf;
934 bool set_acl_as_root = false;
935 uid_t newUID = (uid_t)-1;
936 gid_t newGID = (gid_t)-1;
938 TALLOC_CTX *frame = talloc_stackframe();
940 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
942 if ((security_info_sent & (SECINFO_DACL |
943 SECINFO_GROUP | SECINFO_OWNER)) == 0)
945 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
946 security_info_sent));
948 return NT_STATUS_OK; /* won't show error - later to be
952 /* Special behaviours */
953 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
954 fsp->conn, ¶ms)) {
956 return NT_STATUS_NO_MEMORY;
959 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
961 return map_nt_error_from_unix(errno);
964 if (params.do_chown) {
965 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
966 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
967 security_info_sent, psd);
968 if (!NT_STATUS_IS_OK(status)) {
969 DEBUG(8, ("unpack_nt_owners failed"));
973 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
974 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
976 status = try_chown(fsp, newUID, newGID);
977 if (!NT_STATUS_IS_OK(status)) {
978 DEBUG(3,("chown %s, %u, %u failed. Error = "
979 "%s.\n", fsp_str_dbg(fsp),
980 (unsigned int)newUID,
981 (unsigned int)newGID,
987 DEBUG(10,("chown %s, %u, %u succeeded.\n",
988 fsp_str_dbg(fsp), (unsigned int)newUID,
989 (unsigned int)newGID));
990 if (smbacl4_GetFileOwner(fsp->conn,
991 fsp->fsp_name->base_name,
994 return map_nt_error_from_unix(errno);
997 /* If we successfully chowned, we know we must
998 * be able to set the acl, so do it as root.
1000 set_acl_as_root = true;
1004 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1005 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1006 security_info_sent));
1008 return NT_STATUS_OK;
1011 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
1012 sbuf.st_ex_uid, sbuf.st_ex_gid);
1015 return map_nt_error_from_unix(errno);
1018 smbacl4_dump_nfs4acl(10, theacl);
1020 if (set_acl_as_root) {
1023 result = set_nfs4_native(handle, fsp, theacl);
1024 saved_errno = errno;
1025 if (set_acl_as_root) {
1032 errno = saved_errno;
1033 DEBUG(10, ("set_nfs4_native failed with %s\n",
1035 return map_nt_error_from_unix(errno);
1038 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1039 return NT_STATUS_OK;