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 (dom_sid_compare_domain(&ace_nt->trustee,
734 &global_sid_Unix_NFS) == 0) {
738 switch (unixid.type) {
740 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
741 ace_v4->who.gid = unixid.id;
744 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
745 ace_v4->who.gid = unixid.id;
748 ace_v4->who.uid = unixid.id;
750 case ID_TYPE_NOT_SPECIFIED:
752 DBG_WARNING("Could not convert %s to uid or gid.\n",
753 dom_sid_str_buf(&ace_nt->trustee, &buf));
758 return true; /* OK */
761 static int smbacl4_MergeIgnoreReject(
762 enum smbacl4_acedup_enum acedup,
763 struct SMB4ACL_T *theacl, /* may modify it */
764 SMB_ACE4PROP_T *ace, /* the "new" ACE */
770 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
775 case e_merge: /* "merge" flags */
777 ace4found->aceFlags |= ace->aceFlags;
778 ace4found->aceMask |= ace->aceMask;
780 case e_ignore: /* leave out this record */
783 case e_reject: /* do an error */
784 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
785 errno = EINVAL; /* SHOULD be set on any _real_ error */
795 static int smbacl4_substitute_special(
796 struct SMB4ACL_T *acl,
801 struct SMB4ACE_T *aceint;
803 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
804 SMB_ACE4PROP_T *ace = &aceint->prop;
806 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
807 "mask: %x, who: %d\n",
808 ace->aceType, ace->flags, ace->aceFlags,
809 ace->aceMask, ace->who.id));
811 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
812 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
813 ace->who.uid == ownerUID) {
814 ace->flags |= SMB_ACE4_ID_SPECIAL;
815 ace->who.special_id = SMB_ACE4_WHO_OWNER;
816 DEBUG(10,("replaced with special owner ace\n"));
819 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
820 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
821 ace->who.uid == ownerGID) {
822 ace->flags |= SMB_ACE4_ID_SPECIAL;
823 ace->who.special_id = SMB_ACE4_WHO_GROUP;
824 DEBUG(10,("replaced with special group ace\n"));
827 return true; /* OK */
830 static int smbacl4_substitute_simple(
831 struct SMB4ACL_T *acl,
836 struct SMB4ACE_T *aceint;
838 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
839 SMB_ACE4PROP_T *ace = &aceint->prop;
841 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
842 "mask: %x, who: %d\n",
843 ace->aceType, ace->flags, ace->aceFlags,
844 ace->aceMask, ace->who.id));
846 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
847 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
848 ace->who.uid == ownerUID &&
849 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
850 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
851 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
852 ace->flags |= SMB_ACE4_ID_SPECIAL;
853 ace->who.special_id = SMB_ACE4_WHO_OWNER;
854 DEBUG(10,("replaced with special owner ace\n"));
857 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
858 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
859 ace->who.gid == ownerGID &&
860 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
861 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
862 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
863 ace->flags |= SMB_ACE4_ID_SPECIAL;
864 ace->who.special_id = SMB_ACE4_WHO_GROUP;
865 DEBUG(10,("replaced with special group ace\n"));
868 return true; /* OK */
871 static struct SMB4ACL_T *smbacl4_win2nfs4(
874 const struct security_acl *dacl,
875 const struct smbacl4_vfs_params *pparams,
880 struct SMB4ACL_T *theacl;
883 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
885 theacl = smb_create_smb4acl(mem_ctx);
889 for(i=0; i<dacl->num_aces; i++) {
890 SMB_ACE4PROP_T ace_v4;
891 bool addNewACE = true;
893 if (!smbacl4_fill_ace4(is_directory, pparams,
895 dacl->aces + i, &ace_v4)) {
896 struct dom_sid_buf buf;
897 DEBUG(3, ("Could not fill ace for file, SID %s\n",
898 dom_sid_str_buf(&((dacl->aces+i)->trustee),
903 if (pparams->acedup!=e_dontcare) {
904 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
905 &ace_v4, &addNewACE, i))
910 smb_add_ace4(theacl, &ace_v4);
913 if (pparams->mode==e_simple) {
914 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
917 if (pparams->mode==e_special) {
918 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
924 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
925 const struct smbacl4_vfs_params *pparams,
926 uint32_t security_info_sent,
927 const struct security_descriptor *psd,
928 set_nfs4acl_native_fn_t set_nfs4_native)
930 struct smbacl4_vfs_params params;
931 struct SMB4ACL_T *theacl = NULL;
932 bool result, is_directory;
934 SMB_STRUCT_STAT sbuf;
935 bool set_acl_as_root = false;
936 uid_t newUID = (uid_t)-1;
937 gid_t newGID = (gid_t)-1;
939 TALLOC_CTX *frame = talloc_stackframe();
941 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
943 if ((security_info_sent & (SECINFO_DACL |
944 SECINFO_GROUP | SECINFO_OWNER)) == 0)
946 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
947 security_info_sent));
949 return NT_STATUS_OK; /* won't show error - later to be
953 if (pparams == NULL) {
954 /* Special behaviours */
955 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
957 return NT_STATUS_NO_MEMORY;
962 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
964 return map_nt_error_from_unix(errno);
967 is_directory = S_ISDIR(sbuf.st_ex_mode);
969 if (pparams->do_chown) {
970 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
971 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
972 security_info_sent, psd);
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(8, ("unpack_nt_owners failed"));
978 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
979 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
981 status = try_chown(fsp, newUID, newGID);
982 if (!NT_STATUS_IS_OK(status)) {
983 DEBUG(3,("chown %s, %u, %u failed. Error = "
984 "%s.\n", fsp_str_dbg(fsp),
985 (unsigned int)newUID,
986 (unsigned int)newGID,
992 DEBUG(10,("chown %s, %u, %u succeeded.\n",
993 fsp_str_dbg(fsp), (unsigned int)newUID,
994 (unsigned int)newGID));
995 if (smbacl4_GetFileOwner(fsp->conn,
999 return map_nt_error_from_unix(errno);
1002 /* If we successfully chowned, we know we must
1003 * be able to set the acl, so do it as root.
1005 set_acl_as_root = true;
1009 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1010 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1011 security_info_sent));
1013 return NT_STATUS_OK;
1016 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1017 sbuf.st_ex_uid, sbuf.st_ex_gid);
1020 return map_nt_error_from_unix(errno);
1023 smbacl4_set_controlflags(theacl, psd->type);
1024 smbacl4_dump_nfs4acl(10, theacl);
1026 if (set_acl_as_root) {
1029 result = set_nfs4_native(handle, fsp, theacl);
1030 saved_errno = errno;
1031 if (set_acl_as_root) {
1038 errno = saved_errno;
1039 DEBUG(10, ("set_nfs4_native failed with %s\n",
1041 return map_nt_error_from_unix(errno);
1044 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1045 return NT_STATUS_OK;