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 static int smbacl4_GetFileOwner(struct connection_struct *conn,
259 const struct smb_filename *smb_fname,
260 SMB_STRUCT_STAT *psbuf)
264 /* Get the stat struct for the owner info. */
265 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
267 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
275 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
279 if (fsp->fh->fd == -1) {
280 return smbacl4_GetFileOwner(fsp->conn,
281 fsp->fsp_name, psbuf);
283 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
285 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
293 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
294 const struct smbacl4_vfs_params *params,
295 struct SMB4ACL_T *acl, /* in */
296 struct dom_sid *psid_owner, /* in */
297 struct dom_sid *psid_group, /* in */
298 bool is_directory, /* in */
299 struct security_ace **ppnt_ace_list, /* out */
300 int *pgood_aces /* out */
303 struct SMB4ACE_T *aceint;
304 struct security_ace *nt_ace_list = NULL;
307 DEBUG(10, ("%s entered\n", __func__));
309 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
311 if (nt_ace_list==NULL)
313 DEBUG(10, ("talloc error with %d aces", acl->naces));
318 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
321 struct dom_sid_buf buf;
322 SMB_ACE4PROP_T *ace = &aceint->prop;
323 uint32_t win_ace_flags;
325 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
326 "mask: %x, who: %d\n",
327 ace->aceType, ace->flags,
328 ace->aceFlags, ace->aceMask, ace->who.id));
330 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
331 switch (ace->who.special_id) {
332 case SMB_ACE4_WHO_OWNER:
333 sid_copy(&sid, psid_owner);
335 case SMB_ACE4_WHO_GROUP:
336 sid_copy(&sid, psid_group);
338 case SMB_ACE4_WHO_EVERYONE:
339 sid_copy(&sid, &global_sid_World);
342 DEBUG(8, ("invalid special who id %d "
343 "ignored\n", ace->who.special_id));
347 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
348 gid_to_sid(&sid, ace->who.gid);
350 uid_to_sid(&sid, ace->who.uid);
353 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
354 dom_sid_str_buf(&sid, &buf)));
356 if (!is_directory && params->map_full_control) {
358 * Do we have all access except DELETE_CHILD
359 * (not caring about the delete bit).
361 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
363 if (test_mask == SMB_ACE4_ALL_MASKS) {
364 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
368 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
371 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
372 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
374 * GPFS sets inherits dir_inhert and file_inherit flags
375 * to files, too, which confuses windows, and seems to
376 * be wrong anyways. ==> Map these bits away for files.
378 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
379 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
380 SEC_ACE_FLAG_CONTAINER_INHERIT);
382 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
383 ace->aceFlags, win_ace_flags));
387 /* Mapping of owner@ and group@ to creator owner and
388 creator group. Keep old behavior in mode special. */
389 if (params->mode != e_special &&
390 ace->flags & SMB_ACE4_ID_SPECIAL &&
391 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
392 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
393 DEBUG(10, ("Map special entry\n"));
394 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
395 uint32_t win_ace_flags_current;
396 DEBUG(10, ("Map current sid\n"));
397 win_ace_flags_current = win_ace_flags &
398 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
399 SEC_ACE_FLAG_CONTAINER_INHERIT);
400 init_sec_ace(&nt_ace_list[good_aces++], &sid,
402 win_ace_flags_current);
404 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
405 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
406 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
407 uint32_t win_ace_flags_creator;
408 DEBUG(10, ("Map creator owner\n"));
409 win_ace_flags_creator = win_ace_flags |
410 SMB_ACE4_INHERIT_ONLY_ACE;
411 init_sec_ace(&nt_ace_list[good_aces++],
412 &global_sid_Creator_Owner,
414 win_ace_flags_creator);
416 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
417 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
418 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
419 uint32_t win_ace_flags_creator;
420 DEBUG(10, ("Map creator owner group\n"));
421 win_ace_flags_creator = win_ace_flags |
422 SMB_ACE4_INHERIT_ONLY_ACE;
423 init_sec_ace(&nt_ace_list[good_aces++],
424 &global_sid_Creator_Group,
426 win_ace_flags_creator);
429 DEBUG(10, ("Map normal sid\n"));
430 init_sec_ace(&nt_ace_list[good_aces++], &sid,
436 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
439 /* returns a NULL ace list when good_aces is zero. */
440 if (good_aces && nt_ace_list == NULL) {
441 DEBUG(10, ("realloc error with %d aces", good_aces));
446 *ppnt_ace_list = nt_ace_list;
447 *pgood_aces = good_aces;
452 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
453 const struct smbacl4_vfs_params *params,
454 uint32_t security_info,
456 struct security_descriptor **ppdesc,
457 struct SMB4ACL_T *theacl)
460 struct dom_sid sid_owner, sid_group;
462 struct security_ace *nt_ace_list = NULL;
463 struct security_acl *psa = NULL;
464 TALLOC_CTX *frame = talloc_stackframe();
469 return NT_STATUS_ACCESS_DENIED; /* special because we
470 * need to think through
474 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
475 gid_to_sid(&sid_group, sbuf->st_ex_gid);
477 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
478 S_ISDIR(sbuf->st_ex_mode),
479 &nt_ace_list, &good_aces);
481 DEBUG(8,("smbacl4_nfs42win failed\n"));
483 return map_nt_error_from_unix(errno);
486 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
488 DEBUG(2,("make_sec_acl failed\n"));
490 return NT_STATUS_NO_MEMORY;
493 DEBUG(10,("after make sec_acl\n"));
494 *ppdesc = make_sec_desc(
495 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
496 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
497 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
498 NULL, psa, &sd_size);
500 DEBUG(2,("make_sec_desc failed\n"));
502 return NT_STATUS_NO_MEMORY;
505 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
507 (int)ndr_size_security_descriptor(*ppdesc, 0)));
513 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
514 const struct smbacl4_vfs_params *pparams,
515 uint32_t security_info,
517 struct security_descriptor **ppdesc,
518 struct SMB4ACL_T *theacl)
520 SMB_STRUCT_STAT sbuf;
521 struct smbacl4_vfs_params params;
522 SMB_STRUCT_STAT *psbuf = NULL;
524 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
526 if (VALID_STAT(fsp->fsp_name->st)) {
527 psbuf = &fsp->fsp_name->st;
531 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
532 return map_nt_error_from_unix(errno);
537 if (pparams == NULL) {
538 /* Special behaviours */
539 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
540 return NT_STATUS_NO_MEMORY;
545 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
546 mem_ctx, ppdesc, theacl);
549 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
550 const struct smb_filename *smb_fname,
551 const struct smbacl4_vfs_params *pparams,
552 uint32_t security_info,
554 struct security_descriptor **ppdesc,
555 struct SMB4ACL_T *theacl)
557 SMB_STRUCT_STAT sbuf;
558 struct smbacl4_vfs_params params;
559 const SMB_STRUCT_STAT *psbuf = NULL;
561 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
562 smb_fname->base_name));
564 if (VALID_STAT(smb_fname->st)) {
565 psbuf = &smb_fname->st;
569 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
570 return map_nt_error_from_unix(errno);
575 if (pparams == NULL) {
576 /* Special behaviours */
577 if (smbacl4_get_vfs_params(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 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(
653 const struct smbacl4_vfs_params *params,
656 const struct security_ace *ace_nt, /* input */
657 SMB_ACE4PROP_T *ace_v4 /* output */
660 struct dom_sid_buf buf;
662 DEBUG(10, ("got ace for %s\n",
663 dom_sid_str_buf(&ace_nt->trustee, &buf)));
665 ZERO_STRUCTP(ace_v4);
667 /* only ACCESS|DENY supported right now */
668 ace_v4->aceType = ace_nt->type;
670 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
673 /* remove inheritance flags on files */
675 DEBUG(10, ("Removing inheritance flags from a file\n"));
676 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
677 SMB_ACE4_DIRECTORY_INHERIT_ACE|
678 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
679 SMB_ACE4_INHERIT_ONLY_ACE);
682 ace_v4->aceMask = ace_nt->access_mask &
683 (SEC_STD_ALL | SEC_FILE_ALL);
685 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
687 if (ace_v4->aceFlags!=ace_nt->flags)
688 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
689 ace_v4->aceFlags, ace_nt->flags));
691 if (ace_v4->aceMask!=ace_nt->access_mask)
692 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
693 ace_v4->aceMask, ace_nt->access_mask));
695 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
696 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
697 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
698 } else if (params->mode!=e_special &&
699 dom_sid_equal(&ace_nt->trustee,
700 &global_sid_Creator_Owner)) {
701 DEBUG(10, ("Map creator owner\n"));
702 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
703 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
704 /* A non inheriting creator owner entry has no effect. */
705 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
706 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
707 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
710 } else if (params->mode!=e_special &&
711 dom_sid_equal(&ace_nt->trustee,
712 &global_sid_Creator_Group)) {
713 DEBUG(10, ("Map creator owner group\n"));
714 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
715 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
716 /* A non inheriting creator group entry has no effect. */
717 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
718 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
719 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
723 struct unixid unixid;
726 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
728 DBG_WARNING("Could not convert %s to uid or gid.\n",
729 dom_sid_str_buf(&ace_nt->trustee, &buf));
733 if (unixid.type == ID_TYPE_GID || unixid.type == ID_TYPE_BOTH) {
734 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
735 ace_v4->who.gid = unixid.id;
736 } else if (unixid.type == ID_TYPE_UID) {
737 ace_v4->who.uid = unixid.id;
738 } else if (dom_sid_compare_domain(&ace_nt->trustee,
739 &global_sid_Unix_NFS) == 0) {
742 DEBUG(1, ("nfs4_acls.c: could not "
743 "convert %s to uid or gid\n",
744 dom_sid_str_buf(&ace_nt->trustee, &buf)));
749 return true; /* OK */
752 static int smbacl4_MergeIgnoreReject(
753 enum smbacl4_acedup_enum acedup,
754 struct SMB4ACL_T *theacl, /* may modify it */
755 SMB_ACE4PROP_T *ace, /* the "new" ACE */
761 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
766 case e_merge: /* "merge" flags */
768 ace4found->aceFlags |= ace->aceFlags;
769 ace4found->aceMask |= ace->aceMask;
771 case e_ignore: /* leave out this record */
774 case e_reject: /* do an error */
775 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
776 errno = EINVAL; /* SHOULD be set on any _real_ error */
786 static int smbacl4_substitute_special(
787 struct SMB4ACL_T *acl,
792 struct SMB4ACE_T *aceint;
794 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
795 SMB_ACE4PROP_T *ace = &aceint->prop;
797 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
798 "mask: %x, who: %d\n",
799 ace->aceType, ace->flags, ace->aceFlags,
800 ace->aceMask, ace->who.id));
802 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
803 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
804 ace->who.uid == ownerUID) {
805 ace->flags |= SMB_ACE4_ID_SPECIAL;
806 ace->who.special_id = SMB_ACE4_WHO_OWNER;
807 DEBUG(10,("replaced with special owner ace\n"));
810 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
811 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
812 ace->who.uid == ownerGID) {
813 ace->flags |= SMB_ACE4_ID_SPECIAL;
814 ace->who.special_id = SMB_ACE4_WHO_GROUP;
815 DEBUG(10,("replaced with special group ace\n"));
818 return true; /* OK */
821 static int smbacl4_substitute_simple(
822 struct SMB4ACL_T *acl,
827 struct SMB4ACE_T *aceint;
829 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
830 SMB_ACE4PROP_T *ace = &aceint->prop;
832 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
833 "mask: %x, who: %d\n",
834 ace->aceType, ace->flags, ace->aceFlags,
835 ace->aceMask, ace->who.id));
837 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
838 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
839 ace->who.uid == ownerUID &&
840 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
841 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
842 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
843 ace->flags |= SMB_ACE4_ID_SPECIAL;
844 ace->who.special_id = SMB_ACE4_WHO_OWNER;
845 DEBUG(10,("replaced with special owner ace\n"));
848 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
849 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
850 ace->who.uid == ownerGID &&
851 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
852 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
853 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
854 ace->flags |= SMB_ACE4_ID_SPECIAL;
855 ace->who.special_id = SMB_ACE4_WHO_GROUP;
856 DEBUG(10,("replaced with special group ace\n"));
859 return true; /* OK */
862 static struct SMB4ACL_T *smbacl4_win2nfs4(
865 const struct security_acl *dacl,
866 const struct smbacl4_vfs_params *pparams,
871 struct SMB4ACL_T *theacl;
874 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
876 theacl = smb_create_smb4acl(mem_ctx);
880 for(i=0; i<dacl->num_aces; i++) {
881 SMB_ACE4PROP_T ace_v4;
882 bool addNewACE = true;
884 if (!smbacl4_fill_ace4(is_directory, pparams,
886 dacl->aces + i, &ace_v4)) {
887 struct dom_sid_buf buf;
888 DEBUG(3, ("Could not fill ace for file, SID %s\n",
889 dom_sid_str_buf(&((dacl->aces+i)->trustee),
894 if (pparams->acedup!=e_dontcare) {
895 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
896 &ace_v4, &addNewACE, i))
901 smb_add_ace4(theacl, &ace_v4);
904 if (pparams->mode==e_simple) {
905 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
908 if (pparams->mode==e_special) {
909 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
915 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
916 const struct smbacl4_vfs_params *pparams,
917 uint32_t security_info_sent,
918 const struct security_descriptor *psd,
919 set_nfs4acl_native_fn_t set_nfs4_native)
921 struct smbacl4_vfs_params params;
922 struct SMB4ACL_T *theacl = NULL;
923 bool result, is_directory;
925 SMB_STRUCT_STAT sbuf;
926 bool set_acl_as_root = false;
927 uid_t newUID = (uid_t)-1;
928 gid_t newGID = (gid_t)-1;
930 TALLOC_CTX *frame = talloc_stackframe();
932 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
934 if ((security_info_sent & (SECINFO_DACL |
935 SECINFO_GROUP | SECINFO_OWNER)) == 0)
937 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
938 security_info_sent));
940 return NT_STATUS_OK; /* won't show error - later to be
944 if (pparams == NULL) {
945 /* Special behaviours */
946 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
948 return NT_STATUS_NO_MEMORY;
953 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
955 return map_nt_error_from_unix(errno);
958 is_directory = S_ISDIR(sbuf.st_ex_mode);
960 if (pparams->do_chown) {
961 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
962 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
963 security_info_sent, psd);
964 if (!NT_STATUS_IS_OK(status)) {
965 DEBUG(8, ("unpack_nt_owners failed"));
969 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
970 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
972 status = try_chown(fsp, newUID, newGID);
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(3,("chown %s, %u, %u failed. Error = "
975 "%s.\n", fsp_str_dbg(fsp),
976 (unsigned int)newUID,
977 (unsigned int)newGID,
983 DEBUG(10,("chown %s, %u, %u succeeded.\n",
984 fsp_str_dbg(fsp), (unsigned int)newUID,
985 (unsigned int)newGID));
986 if (smbacl4_GetFileOwner(fsp->conn,
990 return map_nt_error_from_unix(errno);
993 /* If we successfully chowned, we know we must
994 * be able to set the acl, so do it as root.
996 set_acl_as_root = true;
1000 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1001 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1002 security_info_sent));
1004 return NT_STATUS_OK;
1007 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1008 sbuf.st_ex_uid, sbuf.st_ex_gid);
1011 return map_nt_error_from_unix(errno);
1014 smbacl4_set_controlflags(theacl, psd->type);
1015 smbacl4_dump_nfs4acl(10, theacl);
1017 if (set_acl_as_root) {
1020 result = set_nfs4_native(handle, fsp, theacl);
1021 saved_errno = errno;
1022 if (set_acl_as_root) {
1029 errno = saved_errno;
1030 DEBUG(10, ("set_nfs4_native failed with %s\n",
1032 return map_nt_error_from_unix(errno);
1035 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1036 return NT_STATUS_OK;