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;
54 enum smbacl4_mode_enum {e_simple=0, e_special=1};
55 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
57 struct smbacl4_vfs_params {
58 enum smbacl4_mode_enum mode;
60 enum smbacl4_acedup_enum acedup;
61 bool map_full_control;
65 * Gather special parameters for NFS4 ACL handling
67 static int smbacl4_get_vfs_params(
68 struct connection_struct *conn,
69 struct smbacl4_vfs_params *params
72 static const struct enum_list enum_smbacl4_modes[] = {
73 { e_simple, "simple" },
74 { e_special, "special" },
77 static const struct enum_list enum_smbacl4_acedups[] = {
78 { e_dontcare, "dontcare" },
79 { e_reject, "reject" },
80 { e_ignore, "ignore" },
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
89 enum_smbacl4_modes, e_simple);
91 DEBUG(10, ("value for %s:mode unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
95 params->mode = (enum smbacl4_mode_enum)enumval;
97 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
100 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
101 enum_smbacl4_acedups, e_dontcare);
103 DEBUG(10, ("value for %s:acedup unknown\n",
104 SMBACL4_PARAM_TYPE_NAME));
107 params->acedup = (enum smbacl4_acedup_enum)enumval;
109 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
111 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
112 enum_smbacl4_modes[params->mode].name,
113 params->do_chown ? "true" : "false",
114 enum_smbacl4_acedups[params->acedup].name,
115 params->map_full_control ? "true" : "false"));
120 /************************************************
121 Split the ACE flag mapping between nfs4 and Windows
122 into two separate functions rather than trying to do
123 it inline. Allows us to carefully control what flags
124 are mapped to what in one place.
125 ************************************************/
127 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
128 uint32_t nfs4_ace_flags)
130 uint32_t win_ace_flags = 0;
132 /* The nfs4 flags <= 0xf map perfectly. */
133 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
134 SEC_ACE_FLAG_CONTAINER_INHERIT|
135 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
136 SEC_ACE_FLAG_INHERIT_ONLY);
138 /* flags greater than 0xf have diverged :-(. */
139 /* See the nfs4 ace flag definitions here:
140 http://www.ietf.org/rfc/rfc3530.txt.
141 And the Windows ace flag definitions here:
142 librpc/idl/security.idl. */
143 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
144 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
147 return win_ace_flags;
150 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
152 uint32_t nfs4_ace_flags = 0;
154 /* The windows flags <= 0xf map perfectly. */
155 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
156 SMB_ACE4_DIRECTORY_INHERIT_ACE|
157 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
158 SMB_ACE4_INHERIT_ONLY_ACE);
160 /* flags greater than 0xf have diverged :-(. */
161 /* See the nfs4 ace flag definitions here:
162 http://www.ietf.org/rfc/rfc3530.txt.
163 And the Windows ace flag definitions here:
164 librpc/idl/security.idl. */
165 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
166 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
169 return nfs4_ace_flags;
172 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
174 struct SMB4ACL_T *theacl;
176 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
179 DEBUG(0, ("TALLOC_SIZE failed\n"));
183 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
184 /* theacl->first, last = NULL not needed */
188 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
190 struct SMB4ACE_T *ace;
192 ace = talloc_zero(acl, struct SMB4ACE_T);
195 DEBUG(0, ("TALLOC_SIZE failed\n"));
199 /* ace->next = NULL not needed */
200 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
202 if (acl->first==NULL)
207 acl->last->next = ace;
215 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
224 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
233 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
242 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
251 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
257 return acl->controlflags;
260 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
266 acl->controlflags = controlflags;
270 static int smbacl4_GetFileOwner(struct connection_struct *conn,
271 const struct smb_filename *smb_fname,
272 SMB_STRUCT_STAT *psbuf)
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
279 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
287 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
291 if (fsp->fh->fd == -1) {
292 return smbacl4_GetFileOwner(fsp->conn,
293 fsp->fsp_name, psbuf);
295 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
297 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
305 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
306 const struct smbacl4_vfs_params *params,
307 struct SMB4ACL_T *acl, /* in */
308 struct dom_sid *psid_owner, /* in */
309 struct dom_sid *psid_group, /* in */
310 bool is_directory, /* in */
311 struct security_ace **ppnt_ace_list, /* out */
312 int *pgood_aces /* out */
315 struct SMB4ACE_T *aceint;
316 struct security_ace *nt_ace_list = NULL;
319 DEBUG(10, ("%s entered\n", __func__));
321 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
323 if (nt_ace_list==NULL)
325 DEBUG(10, ("talloc error with %d aces", acl->naces));
330 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
333 SMB_ACE4PROP_T *ace = &aceint->prop;
334 uint32_t win_ace_flags;
336 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
337 "mask: %x, who: %d\n",
338 ace->aceType, ace->flags,
339 ace->aceFlags, ace->aceMask, ace->who.id));
341 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
342 switch (ace->who.special_id) {
343 case SMB_ACE4_WHO_OWNER:
344 sid_copy(&sid, psid_owner);
346 case SMB_ACE4_WHO_GROUP:
347 sid_copy(&sid, psid_group);
349 case SMB_ACE4_WHO_EVERYONE:
350 sid_copy(&sid, &global_sid_World);
353 DEBUG(8, ("invalid special who id %d "
354 "ignored\n", ace->who.special_id));
358 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
359 gid_to_sid(&sid, ace->who.gid);
361 uid_to_sid(&sid, ace->who.uid);
364 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
365 sid_string_dbg(&sid)));
367 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
368 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
371 if (!is_directory && params->map_full_control) {
373 * Do we have all access except DELETE_CHILD
374 * (not caring about the delete bit).
376 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
378 if (test_mask == SMB_ACE4_ALL_MASKS) {
379 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
383 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
386 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
389 * GPFS sets inherits dir_inhert and file_inherit flags
390 * to files, too, which confuses windows, and seems to
391 * be wrong anyways. ==> Map these bits away for files.
393 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395 SEC_ACE_FLAG_CONTAINER_INHERIT);
397 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398 ace->aceFlags, win_ace_flags));
401 /* Windows clients expect SYNC on acls to
402 correctly allow rename. See bug #7909. */
403 /* But not on DENY ace entries. See
405 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
409 /* Mapping of owner@ and group@ to creator owner and
410 creator group. Keep old behavior in mode special. */
411 if (params->mode != e_special &&
412 ace->flags & SMB_ACE4_ID_SPECIAL &&
413 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
414 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
415 DEBUG(10, ("Map special entry\n"));
416 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
417 uint32_t win_ace_flags_current;
418 DEBUG(10, ("Map current sid\n"));
419 win_ace_flags_current = win_ace_flags &
420 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
421 SEC_ACE_FLAG_CONTAINER_INHERIT);
422 init_sec_ace(&nt_ace_list[good_aces++], &sid,
424 win_ace_flags_current);
426 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
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\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_Owner,
436 win_ace_flags_creator);
438 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
439 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
440 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
441 uint32_t win_ace_flags_creator;
442 DEBUG(10, ("Map creator owner group\n"));
443 win_ace_flags_creator = win_ace_flags |
444 SMB_ACE4_INHERIT_ONLY_ACE;
445 init_sec_ace(&nt_ace_list[good_aces++],
446 &global_sid_Creator_Group,
448 win_ace_flags_creator);
451 DEBUG(10, ("Map normal sid\n"));
452 init_sec_ace(&nt_ace_list[good_aces++], &sid,
458 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
461 /* returns a NULL ace list when good_aces is zero. */
462 if (good_aces && nt_ace_list == NULL) {
463 DEBUG(10, ("realloc error with %d aces", good_aces));
468 *ppnt_ace_list = nt_ace_list;
469 *pgood_aces = good_aces;
474 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
475 const struct smbacl4_vfs_params *params,
476 uint32_t security_info,
478 struct security_descriptor **ppdesc,
479 struct SMB4ACL_T *theacl)
482 struct dom_sid sid_owner, sid_group;
484 struct security_ace *nt_ace_list = NULL;
485 struct security_acl *psa = NULL;
486 TALLOC_CTX *frame = talloc_stackframe();
491 return NT_STATUS_ACCESS_DENIED; /* special because we
492 * need to think through
496 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497 gid_to_sid(&sid_group, sbuf->st_ex_gid);
499 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
500 S_ISDIR(sbuf->st_ex_mode),
501 &nt_ace_list, &good_aces);
503 DEBUG(8,("smbacl4_nfs42win failed\n"));
505 return map_nt_error_from_unix(errno);
508 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
510 DEBUG(2,("make_sec_acl failed\n"));
512 return NT_STATUS_NO_MEMORY;
515 DEBUG(10,("after make sec_acl\n"));
516 *ppdesc = make_sec_desc(
517 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
518 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
519 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
520 NULL, psa, &sd_size);
522 DEBUG(2,("make_sec_desc failed\n"));
524 return NT_STATUS_NO_MEMORY;
527 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
529 (int)ndr_size_security_descriptor(*ppdesc, 0)));
535 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
536 const struct smbacl4_vfs_params *pparams,
537 uint32_t security_info,
539 struct security_descriptor **ppdesc,
540 struct SMB4ACL_T *theacl)
542 SMB_STRUCT_STAT sbuf;
543 struct smbacl4_vfs_params params;
545 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
547 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
548 return map_nt_error_from_unix(errno);
551 /* Special behaviours */
552 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
553 return NT_STATUS_NO_MEMORY;
556 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
557 mem_ctx, ppdesc, theacl);
560 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
561 const struct smb_filename *smb_fname,
562 const struct smbacl4_vfs_params *pparams,
563 uint32_t security_info,
565 struct security_descriptor **ppdesc,
566 struct SMB4ACL_T *theacl)
568 SMB_STRUCT_STAT sbuf;
569 struct smbacl4_vfs_params params;
571 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
572 smb_fname->base_name));
574 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
575 return map_nt_error_from_unix(errno);
578 /* Special behaviours */
579 if (smbacl4_get_vfs_params(conn, ¶ms)) {
580 return NT_STATUS_NO_MEMORY;
583 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
584 mem_ctx, ppdesc, theacl);
587 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
589 struct SMB4ACE_T *aceint;
591 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
593 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
594 SMB_ACE4PROP_T *ace = &aceint->prop;
596 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
597 "mask=0x%x, id=%d\n",
599 ace->aceFlags, ace->flags,
606 * Find 2 NFS4 who-special ACE property (non-copy!!!)
607 * match nonzero if "special" and who is equal
608 * return ace if found matching; otherwise NULL
610 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
611 struct SMB4ACL_T *acl,
612 SMB_ACE4PROP_T *aceNew)
614 struct SMB4ACE_T *aceint;
616 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
617 SMB_ACE4PROP_T *ace = &aceint->prop;
619 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
620 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
621 ace->aceType, ace->flags, ace->aceFlags,
622 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
624 if (ace->flags == aceNew->flags &&
625 ace->aceType==aceNew->aceType &&
626 ace->aceFlags==aceNew->aceFlags)
628 /* keep type safety; e.g. gid is an u.short */
629 if (ace->flags & SMB_ACE4_ID_SPECIAL)
631 if (ace->who.special_id ==
632 aceNew->who.special_id)
635 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
637 if (ace->who.gid==aceNew->who.gid)
640 if (ace->who.uid==aceNew->who.uid)
651 static bool smbacl4_fill_ace4(
652 const struct smb_filename *filename,
653 const struct smbacl4_vfs_params *params,
656 const struct security_ace *ace_nt, /* input */
657 SMB_ACE4PROP_T *ace_v4 /* output */
660 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
662 ZERO_STRUCTP(ace_v4);
664 /* only ACCESS|DENY supported right now */
665 ace_v4->aceType = ace_nt->type;
667 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
670 /* remove inheritance flags on files */
671 if (VALID_STAT(filename->st) &&
672 !S_ISDIR(filename->st.st_ex_mode)) {
673 DEBUG(10, ("Removing inheritance flags from a file\n"));
674 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
675 SMB_ACE4_DIRECTORY_INHERIT_ACE|
676 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
677 SMB_ACE4_INHERIT_ONLY_ACE);
680 ace_v4->aceMask = ace_nt->access_mask &
681 (SEC_STD_ALL | SEC_FILE_ALL);
683 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
685 if (ace_v4->aceFlags!=ace_nt->flags)
686 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
687 ace_v4->aceFlags, ace_nt->flags));
689 if (ace_v4->aceMask!=ace_nt->access_mask)
690 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
691 ace_v4->aceMask, ace_nt->access_mask));
693 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
694 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
695 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
696 } else if (params->mode!=e_special &&
697 dom_sid_equal(&ace_nt->trustee,
698 &global_sid_Creator_Owner)) {
699 DEBUG(10, ("Map creator owner\n"));
700 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
701 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
702 /* A non inheriting creator owner entry has no effect. */
703 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
704 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
705 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
708 } else if (params->mode!=e_special &&
709 dom_sid_equal(&ace_nt->trustee,
710 &global_sid_Creator_Group)) {
711 DEBUG(10, ("Map creator owner group\n"));
712 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
713 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
714 /* A non inheriting creator group entry has no effect. */
715 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
716 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
717 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
724 if (sid_to_gid(&ace_nt->trustee, &gid)) {
725 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
726 ace_v4->who.gid = gid;
727 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
728 ace_v4->who.uid = uid;
729 } else if (dom_sid_compare_domain(&ace_nt->trustee,
730 &global_sid_Unix_NFS) == 0) {
733 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
734 "convert %s to uid or gid\n",
736 sid_string_dbg(&ace_nt->trustee)));
741 return true; /* OK */
744 static int smbacl4_MergeIgnoreReject(
745 enum smbacl4_acedup_enum acedup,
746 struct SMB4ACL_T *theacl, /* may modify it */
747 SMB_ACE4PROP_T *ace, /* the "new" ACE */
753 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
758 case e_merge: /* "merge" flags */
760 ace4found->aceFlags |= ace->aceFlags;
761 ace4found->aceMask |= ace->aceMask;
763 case e_ignore: /* leave out this record */
766 case e_reject: /* do an error */
767 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
768 errno = EINVAL; /* SHOULD be set on any _real_ error */
778 static int smbacl4_substitute_special(
779 struct SMB4ACL_T *acl,
784 struct SMB4ACE_T *aceint;
786 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
787 SMB_ACE4PROP_T *ace = &aceint->prop;
789 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
790 "mask: %x, who: %d\n",
791 ace->aceType, ace->flags, ace->aceFlags,
792 ace->aceMask, ace->who.id));
794 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
795 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
796 ace->who.uid == ownerUID) {
797 ace->flags |= SMB_ACE4_ID_SPECIAL;
798 ace->who.special_id = SMB_ACE4_WHO_OWNER;
799 DEBUG(10,("replaced with special owner ace\n"));
802 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
803 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
804 ace->who.uid == ownerGID) {
805 ace->flags |= SMB_ACE4_ID_SPECIAL;
806 ace->who.special_id = SMB_ACE4_WHO_GROUP;
807 DEBUG(10,("replaced with special group ace\n"));
810 return true; /* OK */
813 static int smbacl4_substitute_simple(
814 struct SMB4ACL_T *acl,
819 struct SMB4ACE_T *aceint;
821 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
822 SMB_ACE4PROP_T *ace = &aceint->prop;
824 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
825 "mask: %x, who: %d\n",
826 ace->aceType, ace->flags, ace->aceFlags,
827 ace->aceMask, ace->who.id));
829 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
830 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
831 ace->who.uid == ownerUID &&
832 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
833 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
834 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
835 ace->flags |= SMB_ACE4_ID_SPECIAL;
836 ace->who.special_id = SMB_ACE4_WHO_OWNER;
837 DEBUG(10,("replaced with special owner ace\n"));
840 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
841 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
842 ace->who.uid == ownerGID &&
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_GROUP;
848 DEBUG(10,("replaced with special group ace\n"));
851 return true; /* OK */
854 static struct SMB4ACL_T *smbacl4_win2nfs4(
856 const files_struct *fsp,
857 const struct security_acl *dacl,
858 const struct smbacl4_vfs_params *pparams,
863 struct SMB4ACL_T *theacl;
865 const char *filename = fsp->fsp_name->base_name;
867 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
869 theacl = smb_create_smb4acl(mem_ctx);
873 for(i=0; i<dacl->num_aces; i++) {
874 SMB_ACE4PROP_T ace_v4;
875 bool addNewACE = true;
877 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
879 dacl->aces + i, &ace_v4)) {
880 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
882 sid_string_dbg(&((dacl->aces+i)->trustee))));
886 if (pparams->acedup!=e_dontcare) {
887 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
888 &ace_v4, &addNewACE, i))
893 smb_add_ace4(theacl, &ace_v4);
896 if (pparams->mode==e_simple) {
897 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
900 if (pparams->mode==e_special) {
901 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
907 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
908 const struct smbacl4_vfs_params *pparams,
909 uint32_t security_info_sent,
910 const struct security_descriptor *psd,
911 set_nfs4acl_native_fn_t set_nfs4_native)
913 struct smbacl4_vfs_params params;
914 struct SMB4ACL_T *theacl = NULL;
917 SMB_STRUCT_STAT sbuf;
918 bool set_acl_as_root = false;
919 uid_t newUID = (uid_t)-1;
920 gid_t newGID = (gid_t)-1;
922 TALLOC_CTX *frame = talloc_stackframe();
924 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
926 if ((security_info_sent & (SECINFO_DACL |
927 SECINFO_GROUP | SECINFO_OWNER)) == 0)
929 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
930 security_info_sent));
932 return NT_STATUS_OK; /* won't show error - later to be
936 /* Special behaviours */
937 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
939 return NT_STATUS_NO_MEMORY;
942 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
944 return map_nt_error_from_unix(errno);
947 if (params.do_chown) {
948 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
949 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
950 security_info_sent, psd);
951 if (!NT_STATUS_IS_OK(status)) {
952 DEBUG(8, ("unpack_nt_owners failed"));
956 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
957 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
959 status = try_chown(fsp, newUID, newGID);
960 if (!NT_STATUS_IS_OK(status)) {
961 DEBUG(3,("chown %s, %u, %u failed. Error = "
962 "%s.\n", fsp_str_dbg(fsp),
963 (unsigned int)newUID,
964 (unsigned int)newGID,
970 DEBUG(10,("chown %s, %u, %u succeeded.\n",
971 fsp_str_dbg(fsp), (unsigned int)newUID,
972 (unsigned int)newGID));
973 if (smbacl4_GetFileOwner(fsp->conn,
977 return map_nt_error_from_unix(errno);
980 /* If we successfully chowned, we know we must
981 * be able to set the acl, so do it as root.
983 set_acl_as_root = true;
987 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
988 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
989 security_info_sent));
994 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
995 sbuf.st_ex_uid, sbuf.st_ex_gid);
998 return map_nt_error_from_unix(errno);
1001 smbacl4_set_controlflags(theacl, psd->type);
1002 smbacl4_dump_nfs4acl(10, theacl);
1004 if (set_acl_as_root) {
1007 result = set_nfs4_native(handle, fsp, theacl);
1008 saved_errno = errno;
1009 if (set_acl_as_root) {
1016 errno = saved_errno;
1017 DEBUG(10, ("set_nfs4_native failed with %s\n",
1019 return map_nt_error_from_unix(errno);
1022 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1023 return NT_STATUS_OK;