4 * Copyright (C) Jim McDonough, 2006
5 * Copyright (C) Christof Schmitt 2019
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "smbd/smbd.h"
23 #include "nfs4_acls.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/idmap.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "../libcli/security/security.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "system/filesys.h"
31 #include "passdb/lookup_sid.h"
33 #include "lib/param/loadparm.h"
36 #define DBGC_CLASS DBGC_ACLS
38 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
40 extern const struct generic_mapping file_generic_mapping;
45 struct SMB4ACE_T *next;
50 uint16_t controlflags;
52 struct SMB4ACE_T *first;
53 struct SMB4ACE_T *last;
57 * Gather special parameters for NFS4 ACL handling
59 int smbacl4_get_vfs_params(struct connection_struct *conn,
60 struct smbacl4_vfs_params *params)
62 static const struct enum_list enum_smbacl4_modes[] = {
63 { e_simple, "simple" },
64 { e_special, "special" },
67 static const struct enum_list enum_smbacl4_acedups[] = {
68 { e_dontcare, "dontcare" },
69 { e_reject, "reject" },
70 { e_ignore, "ignore" },
76 *params = (struct smbacl4_vfs_params) { 0 };
78 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
79 enum_smbacl4_modes, e_simple);
81 DEBUG(10, ("value for %s:mode unknown\n",
82 SMBACL4_PARAM_TYPE_NAME));
85 params->mode = (enum smbacl4_mode_enum)enumval;
86 if (params->mode == e_special) {
87 DBG_WARNING("nfs4:mode special is deprecated.\n");
90 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
93 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
94 enum_smbacl4_acedups, e_dontcare);
96 DEBUG(10, ("value for %s:acedup unknown\n",
97 SMBACL4_PARAM_TYPE_NAME));
100 params->acedup = (enum smbacl4_acedup_enum)enumval;
101 if (params->acedup == e_ignore) {
102 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
104 if (params->acedup == e_reject) {
105 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
108 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111 enum_smbacl4_modes[params->mode].name,
112 params->do_chown ? "true" : "false",
113 enum_smbacl4_acedups[params->acedup].name,
114 params->map_full_control ? "true" : "false"));
119 /************************************************
120 Split the ACE flag mapping between nfs4 and Windows
121 into two separate functions rather than trying to do
122 it inline. Allows us to carefully control what flags
123 are mapped to what in one place.
124 ************************************************/
126 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
127 uint32_t nfs4_ace_flags)
129 uint32_t win_ace_flags = 0;
131 /* The nfs4 flags <= 0xf map perfectly. */
132 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
133 SEC_ACE_FLAG_CONTAINER_INHERIT|
134 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
135 SEC_ACE_FLAG_INHERIT_ONLY);
137 /* flags greater than 0xf have diverged :-(. */
138 /* See the nfs4 ace flag definitions here:
139 http://www.ietf.org/rfc/rfc3530.txt.
140 And the Windows ace flag definitions here:
141 librpc/idl/security.idl. */
142 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
143 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
146 return win_ace_flags;
149 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
151 uint32_t nfs4_ace_flags = 0;
153 /* The windows flags <= 0xf map perfectly. */
154 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
155 SMB_ACE4_DIRECTORY_INHERIT_ACE|
156 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
157 SMB_ACE4_INHERIT_ONLY_ACE);
159 /* flags greater than 0xf have diverged :-(. */
160 /* See the nfs4 ace flag definitions here:
161 http://www.ietf.org/rfc/rfc3530.txt.
162 And the Windows ace flag definitions here:
163 librpc/idl/security.idl. */
164 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
165 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
168 return nfs4_ace_flags;
171 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
173 struct SMB4ACL_T *theacl;
175 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
178 DEBUG(0, ("TALLOC_SIZE failed\n"));
182 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
183 /* theacl->first, last = NULL not needed */
187 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 struct SMB4ACE_T *ace;
191 ace = talloc_zero(acl, struct SMB4ACE_T);
194 DBG_ERR("talloc_zero failed\n");
200 if (acl->first==NULL)
205 acl->last->next = ace;
213 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
222 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
231 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
240 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
249 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
255 return acl->controlflags;
258 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
264 acl->controlflags = controlflags;
268 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
270 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
271 SMB_ACE4_FILE_INHERIT_ACE|
272 SMB_ACE4_DIRECTORY_INHERIT_ACE);
275 static int smbacl4_GetFileOwner(struct connection_struct *conn,
276 const struct smb_filename *smb_fname,
277 SMB_STRUCT_STAT *psbuf)
281 /* Get the stat struct for the owner info. */
282 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
284 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
292 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
296 if (fsp->fh->fd == -1) {
297 return smbacl4_GetFileOwner(fsp->conn,
298 fsp->fsp_name, psbuf);
300 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
302 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
310 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
313 struct security_ace *last = NULL;
316 if (*good_aces < 2) {
320 last = &nt_ace_list[(*good_aces) - 1];
322 for (i = 0; i < (*good_aces) - 1; i++) {
323 struct security_ace *cur = &nt_ace_list[i];
325 if (cur->type == last->type &&
326 cur->flags == last->flags &&
327 cur->access_mask == last->access_mask &&
328 dom_sid_equal(&cur->trustee, &last->trustee))
330 struct dom_sid_buf sid_buf;
332 DBG_INFO("Removing duplicate entry for SID %s.\n",
333 dom_sid_str_buf(&last->trustee, &sid_buf));
339 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
340 const struct smbacl4_vfs_params *params,
341 struct SMB4ACL_T *acl, /* in */
342 struct dom_sid *psid_owner, /* in */
343 struct dom_sid *psid_group, /* in */
344 bool is_directory, /* in */
345 struct security_ace **ppnt_ace_list, /* out */
346 int *pgood_aces /* out */
349 struct SMB4ACE_T *aceint;
350 struct security_ace *nt_ace_list = NULL;
353 DEBUG(10, ("%s entered\n", __func__));
355 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
357 if (nt_ace_list==NULL)
359 DEBUG(10, ("talloc error with %d aces", acl->naces));
364 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
367 struct dom_sid_buf buf;
368 SMB_ACE4PROP_T *ace = &aceint->prop;
369 uint32_t win_ace_flags;
371 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
372 "mask: %x, who: %d\n",
373 ace->aceType, ace->flags,
374 ace->aceFlags, ace->aceMask, ace->who.id));
376 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
377 switch (ace->who.special_id) {
378 case SMB_ACE4_WHO_OWNER:
379 sid_copy(&sid, psid_owner);
381 case SMB_ACE4_WHO_GROUP:
382 sid_copy(&sid, psid_group);
384 case SMB_ACE4_WHO_EVERYONE:
385 sid_copy(&sid, &global_sid_World);
388 DEBUG(8, ("invalid special who id %d "
389 "ignored\n", ace->who.special_id));
393 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
394 gid_to_sid(&sid, ace->who.gid);
396 uid_to_sid(&sid, ace->who.uid);
399 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
400 dom_sid_str_buf(&sid, &buf)));
402 if (!is_directory && params->map_full_control) {
404 * Do we have all access except DELETE_CHILD
405 * (not caring about the delete bit).
407 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
409 if (test_mask == SMB_ACE4_ALL_MASKS) {
410 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
414 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
417 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
418 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
420 * GPFS sets inherits dir_inhert and file_inherit flags
421 * to files, too, which confuses windows, and seems to
422 * be wrong anyways. ==> Map these bits away for files.
424 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
425 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
426 SEC_ACE_FLAG_CONTAINER_INHERIT);
428 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
429 ace->aceFlags, win_ace_flags));
433 /* Mapping of owner@ and group@ to creator owner and
434 creator group. Keep old behavior in mode special. */
435 if (params->mode != e_special &&
436 ace->flags & SMB_ACE4_ID_SPECIAL &&
437 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
438 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
439 DEBUG(10, ("Map special entry\n"));
440 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
441 uint32_t win_ace_flags_current;
442 DEBUG(10, ("Map current sid\n"));
443 win_ace_flags_current = win_ace_flags &
444 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
445 SEC_ACE_FLAG_CONTAINER_INHERIT);
446 init_sec_ace(&nt_ace_list[good_aces++], &sid,
448 win_ace_flags_current);
450 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
451 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
452 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
453 uint32_t win_ace_flags_creator;
454 DEBUG(10, ("Map creator owner\n"));
455 win_ace_flags_creator = win_ace_flags |
456 SMB_ACE4_INHERIT_ONLY_ACE;
457 init_sec_ace(&nt_ace_list[good_aces++],
458 &global_sid_Creator_Owner,
460 win_ace_flags_creator);
462 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
463 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
464 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
465 uint32_t win_ace_flags_creator;
466 DEBUG(10, ("Map creator owner group\n"));
467 win_ace_flags_creator = win_ace_flags |
468 SMB_ACE4_INHERIT_ONLY_ACE;
469 init_sec_ace(&nt_ace_list[good_aces++],
470 &global_sid_Creator_Group,
472 win_ace_flags_creator);
475 DEBUG(10, ("Map normal sid\n"));
476 init_sec_ace(&nt_ace_list[good_aces++], &sid,
481 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
484 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
487 /* returns a NULL ace list when good_aces is zero. */
488 if (good_aces && nt_ace_list == NULL) {
489 DEBUG(10, ("realloc error with %d aces", good_aces));
494 *ppnt_ace_list = nt_ace_list;
495 *pgood_aces = good_aces;
500 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
501 const struct smbacl4_vfs_params *params,
502 uint32_t security_info,
504 struct security_descriptor **ppdesc,
505 struct SMB4ACL_T *theacl)
508 struct dom_sid sid_owner, sid_group;
510 struct security_ace *nt_ace_list = NULL;
511 struct security_acl *psa = NULL;
512 TALLOC_CTX *frame = talloc_stackframe();
517 return NT_STATUS_ACCESS_DENIED; /* special because we
518 * need to think through
522 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
523 gid_to_sid(&sid_group, sbuf->st_ex_gid);
525 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
526 S_ISDIR(sbuf->st_ex_mode),
527 &nt_ace_list, &good_aces);
529 DEBUG(8,("smbacl4_nfs42win failed\n"));
531 return map_nt_error_from_unix(errno);
534 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
536 DEBUG(2,("make_sec_acl failed\n"));
538 return NT_STATUS_NO_MEMORY;
541 DEBUG(10,("after make sec_acl\n"));
542 *ppdesc = make_sec_desc(
543 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
544 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
545 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
546 NULL, psa, &sd_size);
548 DEBUG(2,("make_sec_desc failed\n"));
550 return NT_STATUS_NO_MEMORY;
553 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
555 (int)ndr_size_security_descriptor(*ppdesc, 0)));
561 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
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;
570 SMB_STRUCT_STAT *psbuf = NULL;
572 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
574 if (VALID_STAT(fsp->fsp_name->st)) {
575 psbuf = &fsp->fsp_name->st;
579 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
580 return map_nt_error_from_unix(errno);
585 if (pparams == NULL) {
586 /* Special behaviours */
587 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
588 return NT_STATUS_NO_MEMORY;
593 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
594 mem_ctx, ppdesc, theacl);
597 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
598 const struct smb_filename *smb_fname,
599 const struct smbacl4_vfs_params *pparams,
600 uint32_t security_info,
602 struct security_descriptor **ppdesc,
603 struct SMB4ACL_T *theacl)
605 SMB_STRUCT_STAT sbuf;
606 struct smbacl4_vfs_params params;
607 const SMB_STRUCT_STAT *psbuf = NULL;
609 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
610 smb_fname->base_name));
612 if (VALID_STAT(smb_fname->st)) {
613 psbuf = &smb_fname->st;
617 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
618 return map_nt_error_from_unix(errno);
623 if (pparams == NULL) {
624 /* Special behaviours */
625 if (smbacl4_get_vfs_params(conn, ¶ms)) {
626 return NT_STATUS_NO_MEMORY;
631 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
632 mem_ctx, ppdesc, theacl);
635 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
637 struct SMB4ACE_T *aceint;
639 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
641 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
642 SMB_ACE4PROP_T *ace = &aceint->prop;
644 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
645 "mask=0x%x, id=%d\n",
647 ace->aceFlags, ace->flags,
654 * Find 2 NFS4 who-special ACE property (non-copy!!!)
655 * match nonzero if "special" and who is equal
656 * return ace if found matching; otherwise NULL
658 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
659 struct SMB4ACL_T *acl,
660 SMB_ACE4PROP_T *aceNew)
662 struct SMB4ACE_T *aceint;
664 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
665 SMB_ACE4PROP_T *ace = &aceint->prop;
667 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
668 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
669 ace->aceType, ace->flags, ace->aceFlags,
670 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
672 if (ace->flags == aceNew->flags &&
673 ace->aceType==aceNew->aceType &&
674 ace->aceFlags==aceNew->aceFlags)
676 /* keep type safety; e.g. gid is an u.short */
677 if (ace->flags & SMB_ACE4_ID_SPECIAL)
679 if (ace->who.special_id ==
680 aceNew->who.special_id)
683 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
685 if (ace->who.gid==aceNew->who.gid)
688 if (ace->who.uid==aceNew->who.uid)
698 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
699 struct SMB4ACL_T *theacl,
704 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
709 case e_merge: /* "merge" flags */
711 ace4found->aceFlags |= ace->aceFlags;
712 ace4found->aceMask |= ace->aceMask;
714 case e_ignore: /* leave out this record */
717 case e_reject: /* do an error */
718 DBG_INFO("ACL rejected by duplicate nt ace.\n");
719 errno = EINVAL; /* SHOULD be set on any _real_ error */
729 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
730 struct SMB4ACL_T *nfs4_acl,
731 SMB_ACE4PROP_T *nfs4_ace)
735 if (acedup != e_dontcare) {
738 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
746 smb_add_ace4(nfs4_acl, nfs4_ace);
752 static int nfs4_acl_add_sec_ace(bool is_directory,
753 const struct smbacl4_vfs_params *params,
756 const struct security_ace *ace_nt,
757 struct SMB4ACL_T *nfs4_acl)
759 struct dom_sid_buf buf;
760 SMB_ACE4PROP_T nfs4_ace = { 0 };
761 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
762 bool add_ace2 = false;
765 DEBUG(10, ("got ace for %s\n",
766 dom_sid_str_buf(&ace_nt->trustee, &buf)));
768 /* only ACCESS|DENY supported right now */
769 nfs4_ace.aceType = ace_nt->type;
772 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
774 /* remove inheritance flags on files */
776 DEBUG(10, ("Removing inheritance flags from a file\n"));
777 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
778 SMB_ACE4_DIRECTORY_INHERIT_ACE|
779 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
780 SMB_ACE4_INHERIT_ONLY_ACE);
783 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
785 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
787 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
788 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
789 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
790 } else if (params->mode!=e_special &&
791 dom_sid_equal(&ace_nt->trustee,
792 &global_sid_Creator_Owner)) {
793 DEBUG(10, ("Map creator owner\n"));
794 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
795 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
796 /* A non inheriting creator owner entry has no effect. */
797 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
798 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
799 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
802 } else if (params->mode!=e_special &&
803 dom_sid_equal(&ace_nt->trustee,
804 &global_sid_Creator_Group)) {
805 DEBUG(10, ("Map creator owner group\n"));
806 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
807 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
808 /* A non inheriting creator group entry has no effect. */
809 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
810 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
811 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
815 struct unixid unixid;
818 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
820 DBG_WARNING("Could not convert %s to uid or gid.\n",
821 dom_sid_str_buf(&ace_nt->trustee, &buf));
825 if (dom_sid_compare_domain(&ace_nt->trustee,
826 &global_sid_Unix_NFS) == 0) {
830 switch (unixid.type) {
832 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
833 nfs4_ace.who.gid = unixid.id;
835 if (ownerUID == unixid.id &&
836 !nfs_ace_is_inherit(&nfs4_ace))
839 * IDMAP_TYPE_BOTH for owner. Add
840 * additional user entry, which can be
841 * mapped to special:owner to reflect
842 * the permissions in the modebits.
844 * This only applies to non-inheriting
845 * entries as only these are replaced
846 * with SPECIAL_OWNER in nfs4:mode=simple.
848 nfs4_ace_2 = (SMB_ACE4PROP_T) {
849 .who.uid = unixid.id,
850 .aceFlags = (nfs4_ace.aceFlags &
851 ~SMB_ACE4_IDENTIFIER_GROUP),
852 .aceMask = nfs4_ace.aceMask,
853 .aceType = nfs4_ace.aceType,
859 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
860 nfs4_ace.who.gid = unixid.id;
863 nfs4_ace.who.uid = unixid.id;
865 case ID_TYPE_NOT_SPECIFIED:
867 DBG_WARNING("Could not convert %s to uid or gid.\n",
868 dom_sid_str_buf(&ace_nt->trustee, &buf));
873 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
882 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
885 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
889 struct SMB4ACE_T *aceint;
891 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
892 SMB_ACE4PROP_T *ace = &aceint->prop;
894 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
895 "mask: %x, who: %d\n",
896 ace->aceType, ace->flags, ace->aceFlags,
897 ace->aceMask, ace->who.id));
899 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
900 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
901 ace->who.uid == ownerUID) {
902 ace->flags |= SMB_ACE4_ID_SPECIAL;
903 ace->who.special_id = SMB_ACE4_WHO_OWNER;
904 DEBUG(10,("replaced with special owner ace\n"));
907 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
908 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
909 ace->who.uid == ownerGID) {
910 ace->flags |= SMB_ACE4_ID_SPECIAL;
911 ace->who.special_id = SMB_ACE4_WHO_GROUP;
912 DEBUG(10,("replaced with special group ace\n"));
917 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
921 struct SMB4ACE_T *aceint;
923 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
924 SMB_ACE4PROP_T *ace = &aceint->prop;
926 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
927 "mask: %x, who: %d\n",
928 ace->aceType, ace->flags, ace->aceFlags,
929 ace->aceMask, ace->who.id));
931 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
932 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
933 ace->who.uid == ownerUID &&
934 !nfs_ace_is_inherit(ace)) {
935 ace->flags |= SMB_ACE4_ID_SPECIAL;
936 ace->who.special_id = SMB_ACE4_WHO_OWNER;
937 DEBUG(10,("replaced with special owner ace\n"));
940 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
941 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
942 ace->who.gid == ownerGID &&
943 !nfs_ace_is_inherit(ace)) {
944 ace->flags |= SMB_ACE4_ID_SPECIAL;
945 ace->who.special_id = SMB_ACE4_WHO_GROUP;
946 DEBUG(10,("replaced with special group ace\n"));
951 static struct SMB4ACL_T *smbacl4_win2nfs4(
954 const struct security_acl *dacl,
955 const struct smbacl4_vfs_params *pparams,
960 struct SMB4ACL_T *theacl;
963 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
965 theacl = smb_create_smb4acl(mem_ctx);
969 for(i=0; i<dacl->num_aces; i++) {
972 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
974 dacl->aces + i, theacl);
980 if (pparams->mode==e_simple) {
981 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
984 if (pparams->mode==e_special) {
985 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
991 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
992 const struct smbacl4_vfs_params *pparams,
993 uint32_t security_info_sent,
994 const struct security_descriptor *psd,
995 set_nfs4acl_native_fn_t set_nfs4_native)
997 struct smbacl4_vfs_params params;
998 struct SMB4ACL_T *theacl = NULL;
999 bool result, is_directory;
1001 bool set_acl_as_root = false;
1002 uid_t newUID = (uid_t)-1;
1003 gid_t newGID = (gid_t)-1;
1006 TALLOC_CTX *frame = talloc_stackframe();
1008 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1010 if ((security_info_sent & (SECINFO_DACL |
1011 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1013 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1014 security_info_sent));
1016 return NT_STATUS_OK; /* won't show error - later to be
1020 if (pparams == NULL) {
1021 /* Special behaviours */
1022 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
1024 return NT_STATUS_NO_MEMORY;
1029 status = vfs_stat_fsp(fsp);
1030 if (!NT_STATUS_IS_OK(status)) {
1035 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1037 if (pparams->do_chown) {
1038 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
1040 uid_t old_uid = fsp->fsp_name->st.st_ex_uid;
1041 uid_t old_gid = fsp->fsp_name->st.st_ex_uid;
1042 status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
1043 security_info_sent, psd);
1044 if (!NT_STATUS_IS_OK(status)) {
1045 DEBUG(8, ("unpack_nt_owners failed"));
1049 if (((newUID != (uid_t)-1) && (old_uid != newUID)) ||
1050 ((newGID != (gid_t)-1) && (old_gid != newGID)))
1052 status = try_chown(fsp, newUID, newGID);
1053 if (!NT_STATUS_IS_OK(status)) {
1054 DEBUG(3,("chown %s, %u, %u failed. Error = "
1055 "%s.\n", fsp_str_dbg(fsp),
1056 (unsigned int)newUID,
1057 (unsigned int)newGID,
1058 nt_errstr(status)));
1063 DEBUG(10,("chown %s, %u, %u succeeded.\n",
1064 fsp_str_dbg(fsp), (unsigned int)newUID,
1065 (unsigned int)newGID));
1068 * Owner change, need to update stat info.
1070 status = vfs_stat_fsp(fsp);
1071 if (!NT_STATUS_IS_OK(status)) {
1076 /* If we successfully chowned, we know we must
1077 * be able to set the acl, so do it as root.
1079 set_acl_as_root = true;
1083 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1084 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1085 security_info_sent));
1087 return NT_STATUS_OK;
1090 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1091 fsp->fsp_name->st.st_ex_uid,
1092 fsp->fsp_name->st.st_ex_gid);
1095 return map_nt_error_from_unix(errno);
1098 smbacl4_set_controlflags(theacl, psd->type);
1099 smbacl4_dump_nfs4acl(10, theacl);
1101 if (set_acl_as_root) {
1104 result = set_nfs4_native(handle, fsp, theacl);
1105 saved_errno = errno;
1106 if (set_acl_as_root) {
1113 errno = saved_errno;
1114 DEBUG(10, ("set_nfs4_native failed with %s\n",
1116 return map_nt_error_from_unix(errno);
1119 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1120 return NT_STATUS_OK;