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 "librpc/gen_ndr/idmap.h"
25 #include "../libcli/security/dom_sid.h"
26 #include "../libcli/security/security.h"
27 #include "dbwrap/dbwrap.h"
28 #include "dbwrap/dbwrap_open.h"
29 #include "system/filesys.h"
30 #include "passdb/lookup_sid.h"
32 #include "lib/param/loadparm.h"
35 #define DBGC_CLASS DBGC_ACLS
37 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
39 extern const struct generic_mapping file_generic_mapping;
44 struct SMB4ACE_T *next;
49 uint16_t controlflags;
51 struct SMB4ACE_T *first;
52 struct SMB4ACE_T *last;
56 * Gather special parameters for NFS4 ACL handling
58 int smbacl4_get_vfs_params(struct connection_struct *conn,
59 struct smbacl4_vfs_params *params)
61 static const struct enum_list enum_smbacl4_modes[] = {
62 { e_simple, "simple" },
63 { e_special, "special" },
66 static const struct enum_list enum_smbacl4_acedups[] = {
67 { e_dontcare, "dontcare" },
68 { e_reject, "reject" },
69 { e_ignore, "ignore" },
77 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
78 enum_smbacl4_modes, e_simple);
80 DEBUG(10, ("value for %s:mode unknown\n",
81 SMBACL4_PARAM_TYPE_NAME));
84 params->mode = (enum smbacl4_mode_enum)enumval;
86 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
89 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
90 enum_smbacl4_acedups, e_dontcare);
92 DEBUG(10, ("value for %s:acedup unknown\n",
93 SMBACL4_PARAM_TYPE_NAME));
96 params->acedup = (enum smbacl4_acedup_enum)enumval;
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 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
163 struct SMB4ACL_T *theacl;
165 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
168 DEBUG(0, ("TALLOC_SIZE failed\n"));
172 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
173 /* theacl->first, last = NULL not needed */
177 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
179 struct SMB4ACE_T *ace;
181 ace = talloc_zero(acl, struct SMB4ACE_T);
184 DBG_ERR("talloc_zero failed\n");
190 if (acl->first==NULL)
195 acl->last->next = ace;
203 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
212 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
221 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
230 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
239 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
245 return acl->controlflags;
248 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
254 acl->controlflags = controlflags;
258 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
260 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
261 SMB_ACE4_FILE_INHERIT_ACE|
262 SMB_ACE4_DIRECTORY_INHERIT_ACE);
265 static int smbacl4_GetFileOwner(struct connection_struct *conn,
266 const struct smb_filename *smb_fname,
267 SMB_STRUCT_STAT *psbuf)
271 /* Get the stat struct for the owner info. */
272 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
274 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
282 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
286 if (fsp->fh->fd == -1) {
287 return smbacl4_GetFileOwner(fsp->conn,
288 fsp->fsp_name, psbuf);
290 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
292 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
300 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
303 struct security_ace *last = NULL;
306 if (*good_aces < 2) {
310 last = &nt_ace_list[(*good_aces) - 1];
312 for (i = 0; i < (*good_aces) - 1; i++) {
313 struct security_ace *cur = &nt_ace_list[i];
315 if (cur->type == last->type &&
316 cur->flags == last->flags &&
317 cur->access_mask == last->access_mask &&
318 dom_sid_equal(&cur->trustee, &last->trustee))
320 struct dom_sid_buf sid_buf;
322 DBG_INFO("Removing duplicate entry for SID %s.\n",
323 dom_sid_str_buf(&last->trustee, &sid_buf));
329 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
330 const struct smbacl4_vfs_params *params,
331 struct SMB4ACL_T *acl, /* in */
332 struct dom_sid *psid_owner, /* in */
333 struct dom_sid *psid_group, /* in */
334 bool is_directory, /* in */
335 struct security_ace **ppnt_ace_list, /* out */
336 int *pgood_aces /* out */
339 struct SMB4ACE_T *aceint;
340 struct security_ace *nt_ace_list = NULL;
343 DEBUG(10, ("%s entered\n", __func__));
345 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
347 if (nt_ace_list==NULL)
349 DEBUG(10, ("talloc error with %d aces", acl->naces));
354 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
357 struct dom_sid_buf buf;
358 SMB_ACE4PROP_T *ace = &aceint->prop;
359 uint32_t win_ace_flags;
361 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
362 "mask: %x, who: %d\n",
363 ace->aceType, ace->flags,
364 ace->aceFlags, ace->aceMask, ace->who.id));
366 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
367 switch (ace->who.special_id) {
368 case SMB_ACE4_WHO_OWNER:
369 sid_copy(&sid, psid_owner);
371 case SMB_ACE4_WHO_GROUP:
372 sid_copy(&sid, psid_group);
374 case SMB_ACE4_WHO_EVERYONE:
375 sid_copy(&sid, &global_sid_World);
378 DEBUG(8, ("invalid special who id %d "
379 "ignored\n", ace->who.special_id));
383 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
384 gid_to_sid(&sid, ace->who.gid);
386 uid_to_sid(&sid, ace->who.uid);
389 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
390 dom_sid_str_buf(&sid, &buf)));
392 if (!is_directory && params->map_full_control) {
394 * Do we have all access except DELETE_CHILD
395 * (not caring about the delete bit).
397 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
399 if (test_mask == SMB_ACE4_ALL_MASKS) {
400 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
404 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
407 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
408 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
410 * GPFS sets inherits dir_inhert and file_inherit flags
411 * to files, too, which confuses windows, and seems to
412 * be wrong anyways. ==> Map these bits away for files.
414 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
415 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
416 SEC_ACE_FLAG_CONTAINER_INHERIT);
418 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
419 ace->aceFlags, win_ace_flags));
423 /* Mapping of owner@ and group@ to creator owner and
424 creator group. Keep old behavior in mode special. */
425 if (params->mode != e_special &&
426 ace->flags & SMB_ACE4_ID_SPECIAL &&
427 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
428 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
429 DEBUG(10, ("Map special entry\n"));
430 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
431 uint32_t win_ace_flags_current;
432 DEBUG(10, ("Map current sid\n"));
433 win_ace_flags_current = win_ace_flags &
434 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
435 SEC_ACE_FLAG_CONTAINER_INHERIT);
436 init_sec_ace(&nt_ace_list[good_aces++], &sid,
438 win_ace_flags_current);
440 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
441 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
442 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
443 uint32_t win_ace_flags_creator;
444 DEBUG(10, ("Map creator owner\n"));
445 win_ace_flags_creator = win_ace_flags |
446 SMB_ACE4_INHERIT_ONLY_ACE;
447 init_sec_ace(&nt_ace_list[good_aces++],
448 &global_sid_Creator_Owner,
450 win_ace_flags_creator);
452 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
453 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
454 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
455 uint32_t win_ace_flags_creator;
456 DEBUG(10, ("Map creator owner group\n"));
457 win_ace_flags_creator = win_ace_flags |
458 SMB_ACE4_INHERIT_ONLY_ACE;
459 init_sec_ace(&nt_ace_list[good_aces++],
460 &global_sid_Creator_Group,
462 win_ace_flags_creator);
465 DEBUG(10, ("Map normal sid\n"));
466 init_sec_ace(&nt_ace_list[good_aces++], &sid,
471 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
474 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
477 /* returns a NULL ace list when good_aces is zero. */
478 if (good_aces && nt_ace_list == NULL) {
479 DEBUG(10, ("realloc error with %d aces", good_aces));
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 const struct smbacl4_vfs_params *params,
492 uint32_t security_info,
494 struct security_descriptor **ppdesc,
495 struct SMB4ACL_T *theacl)
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();
507 return NT_STATUS_ACCESS_DENIED; /* special because we
508 * need to think through
512 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
513 gid_to_sid(&sid_group, sbuf->st_ex_gid);
515 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
516 S_ISDIR(sbuf->st_ex_mode),
517 &nt_ace_list, &good_aces);
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, smbacl4_get_controlflags(theacl),
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 const struct smbacl4_vfs_params *pparams,
553 uint32_t security_info,
555 struct security_descriptor **ppdesc,
556 struct SMB4ACL_T *theacl)
558 SMB_STRUCT_STAT sbuf;
559 struct smbacl4_vfs_params params;
560 SMB_STRUCT_STAT *psbuf = NULL;
562 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
564 if (VALID_STAT(fsp->fsp_name->st)) {
565 psbuf = &fsp->fsp_name->st;
569 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
570 return map_nt_error_from_unix(errno);
575 if (pparams == NULL) {
576 /* Special behaviours */
577 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
578 return NT_STATUS_NO_MEMORY;
583 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
584 mem_ctx, ppdesc, theacl);
587 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
588 const struct smb_filename *smb_fname,
589 const struct smbacl4_vfs_params *pparams,
590 uint32_t security_info,
592 struct security_descriptor **ppdesc,
593 struct SMB4ACL_T *theacl)
595 SMB_STRUCT_STAT sbuf;
596 struct smbacl4_vfs_params params;
597 const SMB_STRUCT_STAT *psbuf = NULL;
599 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
600 smb_fname->base_name));
602 if (VALID_STAT(smb_fname->st)) {
603 psbuf = &smb_fname->st;
607 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
608 return map_nt_error_from_unix(errno);
613 if (pparams == NULL) {
614 /* Special behaviours */
615 if (smbacl4_get_vfs_params(conn, ¶ms)) {
616 return NT_STATUS_NO_MEMORY;
621 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
622 mem_ctx, ppdesc, theacl);
625 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
627 struct SMB4ACE_T *aceint;
629 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
631 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
632 SMB_ACE4PROP_T *ace = &aceint->prop;
634 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
635 "mask=0x%x, id=%d\n",
637 ace->aceFlags, ace->flags,
644 * Find 2 NFS4 who-special ACE property (non-copy!!!)
645 * match nonzero if "special" and who is equal
646 * return ace if found matching; otherwise NULL
648 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
649 struct SMB4ACL_T *acl,
650 SMB_ACE4PROP_T *aceNew)
652 struct SMB4ACE_T *aceint;
654 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
655 SMB_ACE4PROP_T *ace = &aceint->prop;
657 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
658 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
659 ace->aceType, ace->flags, ace->aceFlags,
660 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
662 if (ace->flags == aceNew->flags &&
663 ace->aceType==aceNew->aceType &&
664 ace->aceFlags==aceNew->aceFlags)
666 /* keep type safety; e.g. gid is an u.short */
667 if (ace->flags & SMB_ACE4_ID_SPECIAL)
669 if (ace->who.special_id ==
670 aceNew->who.special_id)
673 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
675 if (ace->who.gid==aceNew->who.gid)
678 if (ace->who.uid==aceNew->who.uid)
688 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
689 struct SMB4ACL_T *theacl,
694 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
699 case e_merge: /* "merge" flags */
701 ace4found->aceFlags |= ace->aceFlags;
702 ace4found->aceMask |= ace->aceMask;
704 case e_ignore: /* leave out this record */
707 case e_reject: /* do an error */
708 DBG_INFO("ACL rejected by duplicate nt ace.\n");
709 errno = EINVAL; /* SHOULD be set on any _real_ error */
719 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
720 struct SMB4ACL_T *nfs4_acl,
721 SMB_ACE4PROP_T *nfs4_ace)
725 if (acedup != e_dontcare) {
728 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
736 smb_add_ace4(nfs4_acl, nfs4_ace);
742 static int nfs4_acl_add_sec_ace(bool is_directory,
743 const struct smbacl4_vfs_params *params,
746 const struct security_ace *ace_nt,
747 struct SMB4ACL_T *nfs4_acl)
749 struct dom_sid_buf buf;
750 SMB_ACE4PROP_T nfs4_ace = { 0 };
751 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
752 bool add_ace2 = false;
755 DEBUG(10, ("got ace for %s\n",
756 dom_sid_str_buf(&ace_nt->trustee, &buf)));
758 /* only ACCESS|DENY supported right now */
759 nfs4_ace.aceType = ace_nt->type;
762 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
764 /* remove inheritance flags on files */
766 DEBUG(10, ("Removing inheritance flags from a file\n"));
767 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
768 SMB_ACE4_DIRECTORY_INHERIT_ACE|
769 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
770 SMB_ACE4_INHERIT_ONLY_ACE);
773 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
775 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
777 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
778 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
779 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
780 } else if (params->mode!=e_special &&
781 dom_sid_equal(&ace_nt->trustee,
782 &global_sid_Creator_Owner)) {
783 DEBUG(10, ("Map creator owner\n"));
784 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
785 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
786 /* A non inheriting creator owner entry has no effect. */
787 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
788 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
789 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
792 } else if (params->mode!=e_special &&
793 dom_sid_equal(&ace_nt->trustee,
794 &global_sid_Creator_Group)) {
795 DEBUG(10, ("Map creator owner group\n"));
796 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
797 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
798 /* A non inheriting creator group entry has no effect. */
799 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
800 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
801 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
805 struct unixid unixid;
808 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
810 DBG_WARNING("Could not convert %s to uid or gid.\n",
811 dom_sid_str_buf(&ace_nt->trustee, &buf));
815 if (dom_sid_compare_domain(&ace_nt->trustee,
816 &global_sid_Unix_NFS) == 0) {
820 switch (unixid.type) {
822 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
823 nfs4_ace.who.gid = unixid.id;
825 if (ownerUID == unixid.id &&
826 !nfs_ace_is_inherit(&nfs4_ace))
829 * IDMAP_TYPE_BOTH for owner. Add
830 * additional user entry, which can be
831 * mapped to special:owner to reflect
832 * the permissions in the modebits.
834 * This only applies to non-inheriting
835 * entries as only these are replaced
836 * with SPECIAL_OWNER in nfs4:mode=simple.
838 nfs4_ace_2 = (SMB_ACE4PROP_T) {
839 .who.uid = unixid.id,
840 .aceFlags = (nfs4_ace.aceFlags &
841 ~SMB_ACE4_IDENTIFIER_GROUP),
842 .aceMask = nfs4_ace.aceMask,
843 .aceType = nfs4_ace.aceType,
849 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
850 nfs4_ace.who.gid = unixid.id;
853 nfs4_ace.who.uid = unixid.id;
855 case ID_TYPE_NOT_SPECIFIED:
857 DBG_WARNING("Could not convert %s to uid or gid.\n",
858 dom_sid_str_buf(&ace_nt->trustee, &buf));
863 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
872 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
875 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
879 struct SMB4ACE_T *aceint;
881 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
882 SMB_ACE4PROP_T *ace = &aceint->prop;
884 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
885 "mask: %x, who: %d\n",
886 ace->aceType, ace->flags, ace->aceFlags,
887 ace->aceMask, ace->who.id));
889 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
890 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
891 ace->who.uid == ownerUID) {
892 ace->flags |= SMB_ACE4_ID_SPECIAL;
893 ace->who.special_id = SMB_ACE4_WHO_OWNER;
894 DEBUG(10,("replaced with special owner ace\n"));
897 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
898 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
899 ace->who.uid == ownerGID) {
900 ace->flags |= SMB_ACE4_ID_SPECIAL;
901 ace->who.special_id = SMB_ACE4_WHO_GROUP;
902 DEBUG(10,("replaced with special group ace\n"));
905 return true; /* OK */
908 static int smbacl4_substitute_simple(
909 struct SMB4ACL_T *acl,
914 struct SMB4ACE_T *aceint;
916 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
917 SMB_ACE4PROP_T *ace = &aceint->prop;
919 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
920 "mask: %x, who: %d\n",
921 ace->aceType, ace->flags, ace->aceFlags,
922 ace->aceMask, ace->who.id));
924 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
925 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
926 ace->who.uid == ownerUID &&
927 !nfs_ace_is_inherit(ace)) {
928 ace->flags |= SMB_ACE4_ID_SPECIAL;
929 ace->who.special_id = SMB_ACE4_WHO_OWNER;
930 DEBUG(10,("replaced with special owner ace\n"));
933 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
934 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
935 ace->who.gid == ownerGID &&
936 !nfs_ace_is_inherit(ace)) {
937 ace->flags |= SMB_ACE4_ID_SPECIAL;
938 ace->who.special_id = SMB_ACE4_WHO_GROUP;
939 DEBUG(10,("replaced with special group ace\n"));
942 return true; /* OK */
945 static struct SMB4ACL_T *smbacl4_win2nfs4(
948 const struct security_acl *dacl,
949 const struct smbacl4_vfs_params *pparams,
954 struct SMB4ACL_T *theacl;
957 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
959 theacl = smb_create_smb4acl(mem_ctx);
963 for(i=0; i<dacl->num_aces; i++) {
966 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
968 dacl->aces + i, theacl);
974 if (pparams->mode==e_simple) {
975 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
978 if (pparams->mode==e_special) {
979 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
985 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
986 const struct smbacl4_vfs_params *pparams,
987 uint32_t security_info_sent,
988 const struct security_descriptor *psd,
989 set_nfs4acl_native_fn_t set_nfs4_native)
991 struct smbacl4_vfs_params params;
992 struct SMB4ACL_T *theacl = NULL;
993 bool result, is_directory;
995 bool set_acl_as_root = false;
996 uid_t newUID = (uid_t)-1;
997 gid_t newGID = (gid_t)-1;
1000 TALLOC_CTX *frame = talloc_stackframe();
1002 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1004 if ((security_info_sent & (SECINFO_DACL |
1005 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1007 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1008 security_info_sent));
1010 return NT_STATUS_OK; /* won't show error - later to be
1014 if (pparams == NULL) {
1015 /* Special behaviours */
1016 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1018 return NT_STATUS_NO_MEMORY;
1023 status = vfs_stat_fsp(fsp);
1024 if (!NT_STATUS_IS_OK(status)) {
1029 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1031 if (pparams->do_chown) {
1032 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1034 uid_t old_uid = fsp->fsp_name->st.st_ex_uid;
1035 uid_t old_gid = fsp->fsp_name->st.st_ex_uid;
1036 status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1037 security_info_sent, psd);
1038 if (!NT_STATUS_IS_OK(status)) {
1039 DEBUG(8, ("unpack_nt_owners failed"));
1043 if (((newUID != (uid_t)-1) && (old_uid != newUID)) ||
1044 ((newGID != (gid_t)-1) && (old_gid != newGID)))
1046 status = try_chown(fsp, newUID, newGID);
1047 if (!NT_STATUS_IS_OK(status)) {
1048 DEBUG(3,("chown %s, %u, %u failed. Error = "
1049 "%s.\n", fsp_str_dbg(fsp),
1050 (unsigned int)newUID,
1051 (unsigned int)newGID,
1052 nt_errstr(status)));
1057 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1058 fsp_str_dbg(fsp), (unsigned int)newUID,
1059 (unsigned int)newGID));
1062 * Owner change, need to update stat info.
1064 status = vfs_stat_fsp(fsp);
1065 if (!NT_STATUS_IS_OK(status)) {
1070 /* If we successfully chowned, we know we must
1071 * be able to set the acl, so do it as root.
1073 set_acl_as_root = true;
1077 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1078 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1079 security_info_sent));
1081 return NT_STATUS_OK;
1084 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1085 fsp->fsp_name->st.st_ex_uid,
1086 fsp->fsp_name->st.st_ex_gid);
1089 return map_nt_error_from_unix(errno);
1092 smbacl4_set_controlflags(theacl, psd->type);
1093 smbacl4_dump_nfs4acl(10, theacl);
1095 if (set_acl_as_root) {
1098 result = set_nfs4_native(handle, fsp, theacl);
1099 saved_errno = errno;
1100 if (set_acl_as_root) {
1107 errno = saved_errno;
1108 DEBUG(10, ("set_nfs4_native failed with %s\n",
1110 return map_nt_error_from_unix(errno);
1113 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1114 return NT_STATUS_OK;