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 bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
301 const struct smbacl4_vfs_params *params,
302 struct SMB4ACL_T *acl, /* in */
303 struct dom_sid *psid_owner, /* in */
304 struct dom_sid *psid_group, /* in */
305 bool is_directory, /* in */
306 struct security_ace **ppnt_ace_list, /* out */
307 int *pgood_aces /* out */
310 struct SMB4ACE_T *aceint;
311 struct security_ace *nt_ace_list = NULL;
314 DEBUG(10, ("%s entered\n", __func__));
316 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
318 if (nt_ace_list==NULL)
320 DEBUG(10, ("talloc error with %d aces", acl->naces));
325 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
328 struct dom_sid_buf buf;
329 SMB_ACE4PROP_T *ace = &aceint->prop;
330 uint32_t win_ace_flags;
332 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
333 "mask: %x, who: %d\n",
334 ace->aceType, ace->flags,
335 ace->aceFlags, ace->aceMask, ace->who.id));
337 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
338 switch (ace->who.special_id) {
339 case SMB_ACE4_WHO_OWNER:
340 sid_copy(&sid, psid_owner);
342 case SMB_ACE4_WHO_GROUP:
343 sid_copy(&sid, psid_group);
345 case SMB_ACE4_WHO_EVERYONE:
346 sid_copy(&sid, &global_sid_World);
349 DEBUG(8, ("invalid special who id %d "
350 "ignored\n", ace->who.special_id));
354 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
355 gid_to_sid(&sid, ace->who.gid);
357 uid_to_sid(&sid, ace->who.uid);
360 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
361 dom_sid_str_buf(&sid, &buf)));
363 if (!is_directory && params->map_full_control) {
365 * Do we have all access except DELETE_CHILD
366 * (not caring about the delete bit).
368 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
370 if (test_mask == SMB_ACE4_ALL_MASKS) {
371 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
375 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
378 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
379 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
381 * GPFS sets inherits dir_inhert and file_inherit flags
382 * to files, too, which confuses windows, and seems to
383 * be wrong anyways. ==> Map these bits away for files.
385 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
386 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT);
389 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
390 ace->aceFlags, win_ace_flags));
394 /* Mapping of owner@ and group@ to creator owner and
395 creator group. Keep old behavior in mode special. */
396 if (params->mode != e_special &&
397 ace->flags & SMB_ACE4_ID_SPECIAL &&
398 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
399 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
400 DEBUG(10, ("Map special entry\n"));
401 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
402 uint32_t win_ace_flags_current;
403 DEBUG(10, ("Map current sid\n"));
404 win_ace_flags_current = win_ace_flags &
405 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
406 SEC_ACE_FLAG_CONTAINER_INHERIT);
407 init_sec_ace(&nt_ace_list[good_aces++], &sid,
409 win_ace_flags_current);
411 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
412 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
413 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
414 uint32_t win_ace_flags_creator;
415 DEBUG(10, ("Map creator owner\n"));
416 win_ace_flags_creator = win_ace_flags |
417 SMB_ACE4_INHERIT_ONLY_ACE;
418 init_sec_ace(&nt_ace_list[good_aces++],
419 &global_sid_Creator_Owner,
421 win_ace_flags_creator);
423 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
424 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
425 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
426 uint32_t win_ace_flags_creator;
427 DEBUG(10, ("Map creator owner group\n"));
428 win_ace_flags_creator = win_ace_flags |
429 SMB_ACE4_INHERIT_ONLY_ACE;
430 init_sec_ace(&nt_ace_list[good_aces++],
431 &global_sid_Creator_Group,
433 win_ace_flags_creator);
436 DEBUG(10, ("Map normal sid\n"));
437 init_sec_ace(&nt_ace_list[good_aces++], &sid,
443 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
446 /* returns a NULL ace list when good_aces is zero. */
447 if (good_aces && nt_ace_list == NULL) {
448 DEBUG(10, ("realloc error with %d aces", good_aces));
453 *ppnt_ace_list = nt_ace_list;
454 *pgood_aces = good_aces;
459 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
460 const struct smbacl4_vfs_params *params,
461 uint32_t security_info,
463 struct security_descriptor **ppdesc,
464 struct SMB4ACL_T *theacl)
467 struct dom_sid sid_owner, sid_group;
469 struct security_ace *nt_ace_list = NULL;
470 struct security_acl *psa = NULL;
471 TALLOC_CTX *frame = talloc_stackframe();
476 return NT_STATUS_ACCESS_DENIED; /* special because we
477 * need to think through
481 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
482 gid_to_sid(&sid_group, sbuf->st_ex_gid);
484 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
485 S_ISDIR(sbuf->st_ex_mode),
486 &nt_ace_list, &good_aces);
488 DEBUG(8,("smbacl4_nfs42win failed\n"));
490 return map_nt_error_from_unix(errno);
493 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
495 DEBUG(2,("make_sec_acl failed\n"));
497 return NT_STATUS_NO_MEMORY;
500 DEBUG(10,("after make sec_acl\n"));
501 *ppdesc = make_sec_desc(
502 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
503 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
504 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
505 NULL, psa, &sd_size);
507 DEBUG(2,("make_sec_desc failed\n"));
509 return NT_STATUS_NO_MEMORY;
512 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
514 (int)ndr_size_security_descriptor(*ppdesc, 0)));
520 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
521 const struct smbacl4_vfs_params *pparams,
522 uint32_t security_info,
524 struct security_descriptor **ppdesc,
525 struct SMB4ACL_T *theacl)
527 SMB_STRUCT_STAT sbuf;
528 struct smbacl4_vfs_params params;
529 SMB_STRUCT_STAT *psbuf = NULL;
531 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
533 if (VALID_STAT(fsp->fsp_name->st)) {
534 psbuf = &fsp->fsp_name->st;
538 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
539 return map_nt_error_from_unix(errno);
544 if (pparams == NULL) {
545 /* Special behaviours */
546 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
547 return NT_STATUS_NO_MEMORY;
552 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
553 mem_ctx, ppdesc, theacl);
556 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
557 const struct smb_filename *smb_fname,
558 const struct smbacl4_vfs_params *pparams,
559 uint32_t security_info,
561 struct security_descriptor **ppdesc,
562 struct SMB4ACL_T *theacl)
564 SMB_STRUCT_STAT sbuf;
565 struct smbacl4_vfs_params params;
566 const SMB_STRUCT_STAT *psbuf = NULL;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
569 smb_fname->base_name));
571 if (VALID_STAT(smb_fname->st)) {
572 psbuf = &smb_fname->st;
576 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
577 return map_nt_error_from_unix(errno);
582 if (pparams == NULL) {
583 /* Special behaviours */
584 if (smbacl4_get_vfs_params(conn, ¶ms)) {
585 return NT_STATUS_NO_MEMORY;
590 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
591 mem_ctx, ppdesc, theacl);
594 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
596 struct SMB4ACE_T *aceint;
598 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
600 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
601 SMB_ACE4PROP_T *ace = &aceint->prop;
603 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
604 "mask=0x%x, id=%d\n",
606 ace->aceFlags, ace->flags,
613 * Find 2 NFS4 who-special ACE property (non-copy!!!)
614 * match nonzero if "special" and who is equal
615 * return ace if found matching; otherwise NULL
617 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
618 struct SMB4ACL_T *acl,
619 SMB_ACE4PROP_T *aceNew)
621 struct SMB4ACE_T *aceint;
623 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
624 SMB_ACE4PROP_T *ace = &aceint->prop;
626 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
627 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
628 ace->aceType, ace->flags, ace->aceFlags,
629 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
631 if (ace->flags == aceNew->flags &&
632 ace->aceType==aceNew->aceType &&
633 ace->aceFlags==aceNew->aceFlags)
635 /* keep type safety; e.g. gid is an u.short */
636 if (ace->flags & SMB_ACE4_ID_SPECIAL)
638 if (ace->who.special_id ==
639 aceNew->who.special_id)
642 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
644 if (ace->who.gid==aceNew->who.gid)
647 if (ace->who.uid==aceNew->who.uid)
658 static bool smbacl4_fill_ace4(
660 const struct smbacl4_vfs_params *params,
663 const struct security_ace *ace_nt, /* input */
664 SMB_ACE4PROP_T *ace_v4 /* output */
667 struct dom_sid_buf buf;
669 DEBUG(10, ("got ace for %s\n",
670 dom_sid_str_buf(&ace_nt->trustee, &buf)));
672 ZERO_STRUCTP(ace_v4);
674 /* only ACCESS|DENY supported right now */
675 ace_v4->aceType = ace_nt->type;
677 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
680 /* remove inheritance flags on files */
682 DEBUG(10, ("Removing inheritance flags from a file\n"));
683 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
684 SMB_ACE4_DIRECTORY_INHERIT_ACE|
685 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
686 SMB_ACE4_INHERIT_ONLY_ACE);
689 ace_v4->aceMask = ace_nt->access_mask &
690 (SEC_STD_ALL | SEC_FILE_ALL);
692 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
694 if (ace_v4->aceFlags!=ace_nt->flags)
695 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
696 ace_v4->aceFlags, ace_nt->flags));
698 if (ace_v4->aceMask!=ace_nt->access_mask)
699 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
700 ace_v4->aceMask, ace_nt->access_mask));
702 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
703 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
704 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
705 } else if (params->mode!=e_special &&
706 dom_sid_equal(&ace_nt->trustee,
707 &global_sid_Creator_Owner)) {
708 DEBUG(10, ("Map creator owner\n"));
709 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
710 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
711 /* A non inheriting creator owner entry has no effect. */
712 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
713 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
714 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
717 } else if (params->mode!=e_special &&
718 dom_sid_equal(&ace_nt->trustee,
719 &global_sid_Creator_Group)) {
720 DEBUG(10, ("Map creator owner group\n"));
721 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
722 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
723 /* A non inheriting creator group entry has no effect. */
724 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
725 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
726 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
730 struct unixid unixid;
733 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
735 DBG_WARNING("Could not convert %s to uid or gid.\n",
736 dom_sid_str_buf(&ace_nt->trustee, &buf));
740 if (dom_sid_compare_domain(&ace_nt->trustee,
741 &global_sid_Unix_NFS) == 0) {
745 switch (unixid.type) {
747 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
748 ace_v4->who.gid = unixid.id;
751 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
752 ace_v4->who.gid = unixid.id;
755 ace_v4->who.uid = unixid.id;
757 case ID_TYPE_NOT_SPECIFIED:
759 DBG_WARNING("Could not convert %s to uid or gid.\n",
760 dom_sid_str_buf(&ace_nt->trustee, &buf));
765 return true; /* OK */
768 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
769 struct SMB4ACL_T *theacl,
774 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
779 case e_merge: /* "merge" flags */
781 ace4found->aceFlags |= ace->aceFlags;
782 ace4found->aceMask |= ace->aceMask;
784 case e_ignore: /* leave out this record */
787 case e_reject: /* do an error */
788 DBG_INFO("ACL rejected by duplicate nt ace.\n");
789 errno = EINVAL; /* SHOULD be set on any _real_ error */
799 static int smbacl4_substitute_special(
800 struct SMB4ACL_T *acl,
805 struct SMB4ACE_T *aceint;
807 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
808 SMB_ACE4PROP_T *ace = &aceint->prop;
810 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
811 "mask: %x, who: %d\n",
812 ace->aceType, ace->flags, ace->aceFlags,
813 ace->aceMask, ace->who.id));
815 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
816 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
817 ace->who.uid == ownerUID) {
818 ace->flags |= SMB_ACE4_ID_SPECIAL;
819 ace->who.special_id = SMB_ACE4_WHO_OWNER;
820 DEBUG(10,("replaced with special owner ace\n"));
823 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
824 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
825 ace->who.uid == ownerGID) {
826 ace->flags |= SMB_ACE4_ID_SPECIAL;
827 ace->who.special_id = SMB_ACE4_WHO_GROUP;
828 DEBUG(10,("replaced with special group ace\n"));
831 return true; /* OK */
834 static int smbacl4_substitute_simple(
835 struct SMB4ACL_T *acl,
840 struct SMB4ACE_T *aceint;
842 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
843 SMB_ACE4PROP_T *ace = &aceint->prop;
845 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
846 "mask: %x, who: %d\n",
847 ace->aceType, ace->flags, ace->aceFlags,
848 ace->aceMask, ace->who.id));
850 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
851 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
852 ace->who.uid == ownerUID &&
853 !nfs_ace_is_inherit(ace)) {
854 ace->flags |= SMB_ACE4_ID_SPECIAL;
855 ace->who.special_id = SMB_ACE4_WHO_OWNER;
856 DEBUG(10,("replaced with special owner ace\n"));
859 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
860 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
861 ace->who.gid == ownerGID &&
862 !nfs_ace_is_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)) {
911 smb_add_ace4(theacl, &ace_v4);
915 if (pparams->mode==e_simple) {
916 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
919 if (pparams->mode==e_special) {
920 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
926 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
927 const struct smbacl4_vfs_params *pparams,
928 uint32_t security_info_sent,
929 const struct security_descriptor *psd,
930 set_nfs4acl_native_fn_t set_nfs4_native)
932 struct smbacl4_vfs_params params;
933 struct SMB4ACL_T *theacl = NULL;
934 bool result, is_directory;
936 SMB_STRUCT_STAT sbuf;
937 bool set_acl_as_root = false;
938 uid_t newUID = (uid_t)-1;
939 gid_t newGID = (gid_t)-1;
941 TALLOC_CTX *frame = talloc_stackframe();
943 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
945 if ((security_info_sent & (SECINFO_DACL |
946 SECINFO_GROUP | SECINFO_OWNER)) == 0)
948 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
949 security_info_sent));
951 return NT_STATUS_OK; /* won't show error - later to be
955 if (pparams == NULL) {
956 /* Special behaviours */
957 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
959 return NT_STATUS_NO_MEMORY;
964 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
966 return map_nt_error_from_unix(errno);
969 is_directory = S_ISDIR(sbuf.st_ex_mode);
971 if (pparams->do_chown) {
972 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
973 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
974 security_info_sent, psd);
975 if (!NT_STATUS_IS_OK(status)) {
976 DEBUG(8, ("unpack_nt_owners failed"));
980 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
981 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
983 status = try_chown(fsp, newUID, newGID);
984 if (!NT_STATUS_IS_OK(status)) {
985 DEBUG(3,("chown %s, %u, %u failed. Error = "
986 "%s.\n", fsp_str_dbg(fsp),
987 (unsigned int)newUID,
988 (unsigned int)newGID,
994 DEBUG(10,("chown %s, %u, %u succeeded.\n",
995 fsp_str_dbg(fsp), (unsigned int)newUID,
996 (unsigned int)newGID));
997 if (smbacl4_GetFileOwner(fsp->conn,
1001 return map_nt_error_from_unix(errno);
1004 /* If we successfully chowned, we know we must
1005 * be able to set the acl, so do it as root.
1007 set_acl_as_root = true;
1011 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1012 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1013 security_info_sent));
1015 return NT_STATUS_OK;
1018 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1019 sbuf.st_ex_uid, sbuf.st_ex_gid);
1022 return map_nt_error_from_unix(errno);
1025 smbacl4_set_controlflags(theacl, psd->type);
1026 smbacl4_dump_nfs4acl(10, theacl);
1028 if (set_acl_as_root) {
1031 result = set_nfs4_native(handle, fsp, theacl);
1032 saved_errno = errno;
1033 if (set_acl_as_root) {
1040 errno = saved_errno;
1041 DEBUG(10, ("set_nfs4_native failed with %s\n",
1043 return map_nt_error_from_unix(errno);
1046 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1047 return NT_STATUS_OK;