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 "../libcli/security/dom_sid.h"
25 #include "../libcli/security/security.h"
26 #include "dbwrap/dbwrap.h"
27 #include "dbwrap/dbwrap_open.h"
28 #include "system/filesys.h"
29 #include "passdb/lookup_sid.h"
31 #include "lib/param/loadparm.h"
34 #define DBGC_CLASS DBGC_ACLS
36 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
38 extern const struct generic_mapping file_generic_mapping;
43 struct SMB4ACE_T *next;
48 uint16_t controlflags;
50 struct SMB4ACE_T *first;
51 struct SMB4ACE_T *last;
54 enum smbacl4_mode_enum {e_simple=0, e_special=1};
55 enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
57 struct smbacl4_vfs_params {
58 enum smbacl4_mode_enum mode;
60 enum smbacl4_acedup_enum acedup;
61 bool map_full_control;
65 * Gather special parameters for NFS4 ACL handling
67 static int smbacl4_get_vfs_params(
68 struct connection_struct *conn,
69 struct smbacl4_vfs_params *params
72 static const struct enum_list enum_smbacl4_modes[] = {
73 { e_simple, "simple" },
74 { e_special, "special" },
77 static const struct enum_list enum_smbacl4_acedups[] = {
78 { e_dontcare, "dontcare" },
79 { e_reject, "reject" },
80 { e_ignore, "ignore" },
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
89 enum_smbacl4_modes, e_simple);
91 DEBUG(10, ("value for %s:mode unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
95 params->mode = (enum smbacl4_mode_enum)enumval;
97 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
100 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
101 enum_smbacl4_acedups, e_dontcare);
103 DEBUG(10, ("value for %s:acedup unknown\n",
104 SMBACL4_PARAM_TYPE_NAME));
107 params->acedup = (enum smbacl4_acedup_enum)enumval;
109 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
111 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
112 enum_smbacl4_modes[params->mode].name,
113 params->do_chown ? "true" : "false",
114 enum_smbacl4_acedups[params->acedup].name,
115 params->map_full_control ? "true" : "false"));
120 /************************************************
121 Split the ACE flag mapping between nfs4 and Windows
122 into two separate functions rather than trying to do
123 it inline. Allows us to carefully control what flags
124 are mapped to what in one place.
125 ************************************************/
127 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
128 uint32_t nfs4_ace_flags)
130 uint32_t win_ace_flags = 0;
132 /* The nfs4 flags <= 0xf map perfectly. */
133 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
134 SEC_ACE_FLAG_CONTAINER_INHERIT|
135 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
136 SEC_ACE_FLAG_INHERIT_ONLY);
138 /* flags greater than 0xf have diverged :-(. */
139 /* See the nfs4 ace flag definitions here:
140 http://www.ietf.org/rfc/rfc3530.txt.
141 And the Windows ace flag definitions here:
142 librpc/idl/security.idl. */
143 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
144 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
147 return win_ace_flags;
150 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
152 uint32_t nfs4_ace_flags = 0;
154 /* The windows flags <= 0xf map perfectly. */
155 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
156 SMB_ACE4_DIRECTORY_INHERIT_ACE|
157 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
158 SMB_ACE4_INHERIT_ONLY_ACE);
160 /* flags greater than 0xf have diverged :-(. */
161 /* See the nfs4 ace flag definitions here:
162 http://www.ietf.org/rfc/rfc3530.txt.
163 And the Windows ace flag definitions here:
164 librpc/idl/security.idl. */
165 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
166 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
169 return nfs4_ace_flags;
172 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
174 struct SMB4ACL_T *theacl;
176 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
179 DEBUG(0, ("TALLOC_SIZE failed\n"));
183 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
184 /* theacl->first, last = NULL not needed */
188 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
190 struct SMB4ACE_T *ace;
192 ace = talloc_zero(acl, struct SMB4ACE_T);
195 DEBUG(0, ("TALLOC_SIZE failed\n"));
199 /* ace->next = NULL not needed */
200 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
202 if (acl->first==NULL)
207 acl->last->next = ace;
215 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
224 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
233 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
242 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
251 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
257 return acl->controlflags;
260 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
266 acl->controlflags = controlflags;
270 static int smbacl4_GetFileOwner(struct connection_struct *conn,
271 const struct smb_filename *smb_fname,
272 SMB_STRUCT_STAT *psbuf)
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
279 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
287 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
291 if (fsp->fh->fd == -1) {
292 return smbacl4_GetFileOwner(fsp->conn,
293 fsp->fsp_name, psbuf);
295 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
297 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
305 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
306 const struct smbacl4_vfs_params *params,
307 struct SMB4ACL_T *acl, /* in */
308 struct dom_sid *psid_owner, /* in */
309 struct dom_sid *psid_group, /* in */
310 bool is_directory, /* in */
311 struct security_ace **ppnt_ace_list, /* out */
312 int *pgood_aces /* out */
315 struct SMB4ACE_T *aceint;
316 struct security_ace *nt_ace_list = NULL;
319 DEBUG(10, ("%s entered\n", __func__));
321 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
323 if (nt_ace_list==NULL)
325 DEBUG(10, ("talloc error with %d aces", acl->naces));
330 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
333 SMB_ACE4PROP_T *ace = &aceint->prop;
334 uint32_t win_ace_flags;
336 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
337 "mask: %x, who: %d\n",
338 ace->aceType, ace->flags,
339 ace->aceFlags, ace->aceMask, ace->who.id));
341 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
342 switch (ace->who.special_id) {
343 case SMB_ACE4_WHO_OWNER:
344 sid_copy(&sid, psid_owner);
346 case SMB_ACE4_WHO_GROUP:
347 sid_copy(&sid, psid_group);
349 case SMB_ACE4_WHO_EVERYONE:
350 sid_copy(&sid, &global_sid_World);
353 DEBUG(8, ("invalid special who id %d "
354 "ignored\n", ace->who.special_id));
358 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
359 gid_to_sid(&sid, ace->who.gid);
361 uid_to_sid(&sid, ace->who.uid);
364 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
365 sid_string_dbg(&sid)));
367 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
368 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
371 if (!is_directory && params->map_full_control) {
373 * Do we have all access except DELETE_CHILD
374 * (not caring about the delete bit).
376 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
378 if (test_mask == SMB_ACE4_ALL_MASKS) {
379 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
383 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
386 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
387 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
389 * GPFS sets inherits dir_inhert and file_inherit flags
390 * to files, too, which confuses windows, and seems to
391 * be wrong anyways. ==> Map these bits away for files.
393 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
394 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
395 SEC_ACE_FLAG_CONTAINER_INHERIT);
397 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
398 ace->aceFlags, win_ace_flags));
401 /* Windows clients expect SYNC on acls to
402 correctly allow rename. See bug #7909. */
403 /* But not on DENY ace entries. See
405 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
406 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
409 /* Mapping of owner@ and group@ to creator owner and
410 creator group. Keep old behavior in mode special. */
411 if (params->mode != e_special &&
412 ace->flags & SMB_ACE4_ID_SPECIAL &&
413 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
414 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
415 DEBUG(10, ("Map special entry\n"));
416 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
417 uint32_t win_ace_flags_current;
418 DEBUG(10, ("Map current sid\n"));
419 win_ace_flags_current = win_ace_flags &
420 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
421 SEC_ACE_FLAG_CONTAINER_INHERIT);
422 init_sec_ace(&nt_ace_list[good_aces++], &sid,
424 win_ace_flags_current);
426 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
427 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
428 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
429 uint32_t win_ace_flags_creator;
430 DEBUG(10, ("Map creator owner\n"));
431 win_ace_flags_creator = win_ace_flags |
432 SMB_ACE4_INHERIT_ONLY_ACE;
433 init_sec_ace(&nt_ace_list[good_aces++],
434 &global_sid_Creator_Owner,
436 win_ace_flags_creator);
438 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
439 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
440 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
441 uint32_t win_ace_flags_creator;
442 DEBUG(10, ("Map creator owner group\n"));
443 win_ace_flags_creator = win_ace_flags |
444 SMB_ACE4_INHERIT_ONLY_ACE;
445 init_sec_ace(&nt_ace_list[good_aces++],
446 &global_sid_Creator_Group,
448 win_ace_flags_creator);
451 DEBUG(10, ("Map normal sid\n"));
452 init_sec_ace(&nt_ace_list[good_aces++], &sid,
458 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
461 /* returns a NULL ace list when good_aces is zero. */
462 if (good_aces && nt_ace_list == NULL) {
463 DEBUG(10, ("realloc error with %d aces", good_aces));
468 *ppnt_ace_list = nt_ace_list;
469 *pgood_aces = good_aces;
474 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
475 const struct smbacl4_vfs_params *params,
476 uint32_t security_info,
478 struct security_descriptor **ppdesc,
479 struct SMB4ACL_T *theacl)
482 struct dom_sid sid_owner, sid_group;
484 struct security_ace *nt_ace_list = NULL;
485 struct security_acl *psa = NULL;
486 TALLOC_CTX *frame = talloc_stackframe();
491 return NT_STATUS_ACCESS_DENIED; /* special because we
492 * need to think through
496 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
497 gid_to_sid(&sid_group, sbuf->st_ex_gid);
499 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
500 S_ISDIR(sbuf->st_ex_mode),
501 &nt_ace_list, &good_aces);
503 DEBUG(8,("smbacl4_nfs42win failed\n"));
505 return map_nt_error_from_unix(errno);
508 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
510 DEBUG(2,("make_sec_acl failed\n"));
512 return NT_STATUS_NO_MEMORY;
515 DEBUG(10,("after make sec_acl\n"));
516 *ppdesc = make_sec_desc(
517 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
518 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
519 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
520 NULL, psa, &sd_size);
522 DEBUG(2,("make_sec_desc failed\n"));
524 return NT_STATUS_NO_MEMORY;
527 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
529 (int)ndr_size_security_descriptor(*ppdesc, 0)));
535 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
536 const struct smbacl4_vfs_params *pparams,
537 uint32_t security_info,
539 struct security_descriptor **ppdesc,
540 struct SMB4ACL_T *theacl)
542 SMB_STRUCT_STAT sbuf;
543 struct smbacl4_vfs_params params;
545 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
547 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
548 return map_nt_error_from_unix(errno);
551 /* Special behaviours */
552 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
553 return NT_STATUS_NO_MEMORY;
556 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
557 mem_ctx, ppdesc, theacl);
560 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
561 const struct smb_filename *smb_fname,
562 uint32_t security_info,
564 struct security_descriptor **ppdesc,
565 struct SMB4ACL_T *theacl)
567 SMB_STRUCT_STAT sbuf;
568 struct smbacl4_vfs_params params;
570 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
571 smb_fname->base_name));
573 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
574 return map_nt_error_from_unix(errno);
577 /* Special behaviours */
578 if (smbacl4_get_vfs_params(conn, ¶ms)) {
579 return NT_STATUS_NO_MEMORY;
582 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
583 mem_ctx, ppdesc, theacl);
586 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
588 struct SMB4ACE_T *aceint;
590 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
592 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
593 SMB_ACE4PROP_T *ace = &aceint->prop;
595 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
596 "mask=0x%x, id=%d\n",
598 ace->aceFlags, ace->flags,
605 * Find 2 NFS4 who-special ACE property (non-copy!!!)
606 * match nonzero if "special" and who is equal
607 * return ace if found matching; otherwise NULL
609 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
610 struct SMB4ACL_T *acl,
611 SMB_ACE4PROP_T *aceNew)
613 struct SMB4ACE_T *aceint;
615 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
616 SMB_ACE4PROP_T *ace = &aceint->prop;
618 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
619 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
620 ace->aceType, ace->flags, ace->aceFlags,
621 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
623 if (ace->flags == aceNew->flags &&
624 ace->aceType==aceNew->aceType &&
625 ace->aceFlags==aceNew->aceFlags)
627 /* keep type safety; e.g. gid is an u.short */
628 if (ace->flags & SMB_ACE4_ID_SPECIAL)
630 if (ace->who.special_id ==
631 aceNew->who.special_id)
634 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
636 if (ace->who.gid==aceNew->who.gid)
639 if (ace->who.uid==aceNew->who.uid)
650 static bool smbacl4_fill_ace4(
651 const struct smb_filename *filename,
652 const struct smbacl4_vfs_params *params,
655 const struct security_ace *ace_nt, /* input */
656 SMB_ACE4PROP_T *ace_v4 /* output */
659 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
661 ZERO_STRUCTP(ace_v4);
663 /* only ACCESS|DENY supported right now */
664 ace_v4->aceType = ace_nt->type;
666 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
669 /* remove inheritance flags on files */
670 if (VALID_STAT(filename->st) &&
671 !S_ISDIR(filename->st.st_ex_mode)) {
672 DEBUG(10, ("Removing inheritance flags from a file\n"));
673 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
674 SMB_ACE4_DIRECTORY_INHERIT_ACE|
675 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
676 SMB_ACE4_INHERIT_ONLY_ACE);
679 ace_v4->aceMask = ace_nt->access_mask &
680 (SEC_STD_ALL | SEC_FILE_ALL);
682 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
684 if (ace_v4->aceFlags!=ace_nt->flags)
685 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
686 ace_v4->aceFlags, ace_nt->flags));
688 if (ace_v4->aceMask!=ace_nt->access_mask)
689 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
690 ace_v4->aceMask, ace_nt->access_mask));
692 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
693 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
694 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
695 } else if (params->mode!=e_special &&
696 dom_sid_equal(&ace_nt->trustee,
697 &global_sid_Creator_Owner)) {
698 DEBUG(10, ("Map creator owner\n"));
699 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
700 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
701 /* A non inheriting creator owner entry has no effect. */
702 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
703 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
704 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
707 } else if (params->mode!=e_special &&
708 dom_sid_equal(&ace_nt->trustee,
709 &global_sid_Creator_Group)) {
710 DEBUG(10, ("Map creator owner group\n"));
711 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
712 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
713 /* A non inheriting creator group entry has no effect. */
714 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
715 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
716 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
723 if (sid_to_gid(&ace_nt->trustee, &gid)) {
724 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
725 ace_v4->who.gid = gid;
726 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
727 ace_v4->who.uid = uid;
728 } else if (dom_sid_compare_domain(&ace_nt->trustee,
729 &global_sid_Unix_NFS) == 0) {
732 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
733 "convert %s to uid or gid\n",
735 sid_string_dbg(&ace_nt->trustee)));
740 return true; /* OK */
743 static int smbacl4_MergeIgnoreReject(
744 enum smbacl4_acedup_enum acedup,
745 struct SMB4ACL_T *theacl, /* may modify it */
746 SMB_ACE4PROP_T *ace, /* the "new" ACE */
752 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
757 case e_merge: /* "merge" flags */
759 ace4found->aceFlags |= ace->aceFlags;
760 ace4found->aceMask |= ace->aceMask;
762 case e_ignore: /* leave out this record */
765 case e_reject: /* do an error */
766 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
767 errno = EINVAL; /* SHOULD be set on any _real_ error */
777 static int smbacl4_substitute_special(
778 struct SMB4ACL_T *acl,
783 struct SMB4ACE_T *aceint;
785 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
786 SMB_ACE4PROP_T *ace = &aceint->prop;
788 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
789 "mask: %x, who: %d\n",
790 ace->aceType, ace->flags, ace->aceFlags,
791 ace->aceMask, ace->who.id));
793 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
794 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
795 ace->who.uid == ownerUID) {
796 ace->flags |= SMB_ACE4_ID_SPECIAL;
797 ace->who.special_id = SMB_ACE4_WHO_OWNER;
798 DEBUG(10,("replaced with special owner ace\n"));
801 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
802 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
803 ace->who.uid == ownerGID) {
804 ace->flags |= SMB_ACE4_ID_SPECIAL;
805 ace->who.special_id = SMB_ACE4_WHO_GROUP;
806 DEBUG(10,("replaced with special group ace\n"));
809 return true; /* OK */
812 static int smbacl4_substitute_simple(
813 struct SMB4ACL_T *acl,
818 struct SMB4ACE_T *aceint;
820 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
821 SMB_ACE4PROP_T *ace = &aceint->prop;
823 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
824 "mask: %x, who: %d\n",
825 ace->aceType, ace->flags, ace->aceFlags,
826 ace->aceMask, ace->who.id));
828 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
829 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
830 ace->who.uid == ownerUID &&
831 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
832 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
833 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
834 ace->flags |= SMB_ACE4_ID_SPECIAL;
835 ace->who.special_id = SMB_ACE4_WHO_OWNER;
836 DEBUG(10,("replaced with special owner ace\n"));
839 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
840 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
841 ace->who.uid == ownerGID &&
842 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
843 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
844 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
845 ace->flags |= SMB_ACE4_ID_SPECIAL;
846 ace->who.special_id = SMB_ACE4_WHO_GROUP;
847 DEBUG(10,("replaced with special group ace\n"));
850 return true; /* OK */
853 static struct SMB4ACL_T *smbacl4_win2nfs4(
855 const files_struct *fsp,
856 const struct security_acl *dacl,
857 const struct smbacl4_vfs_params *pparams,
862 struct SMB4ACL_T *theacl;
864 const char *filename = fsp->fsp_name->base_name;
866 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
868 theacl = smb_create_smb4acl(mem_ctx);
872 for(i=0; i<dacl->num_aces; i++) {
873 SMB_ACE4PROP_T ace_v4;
874 bool addNewACE = true;
876 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
878 dacl->aces + i, &ace_v4)) {
879 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
881 sid_string_dbg(&((dacl->aces+i)->trustee))));
885 if (pparams->acedup!=e_dontcare) {
886 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
887 &ace_v4, &addNewACE, i))
892 smb_add_ace4(theacl, &ace_v4);
895 if (pparams->mode==e_simple) {
896 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
899 if (pparams->mode==e_special) {
900 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
906 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
907 uint32_t security_info_sent,
908 const struct security_descriptor *psd,
909 set_nfs4acl_native_fn_t set_nfs4_native)
911 struct smbacl4_vfs_params params;
912 struct SMB4ACL_T *theacl = NULL;
915 SMB_STRUCT_STAT sbuf;
916 bool set_acl_as_root = false;
917 uid_t newUID = (uid_t)-1;
918 gid_t newGID = (gid_t)-1;
920 TALLOC_CTX *frame = talloc_stackframe();
922 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
924 if ((security_info_sent & (SECINFO_DACL |
925 SECINFO_GROUP | SECINFO_OWNER)) == 0)
927 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
928 security_info_sent));
930 return NT_STATUS_OK; /* won't show error - later to be
934 /* Special behaviours */
935 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
937 return NT_STATUS_NO_MEMORY;
940 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
942 return map_nt_error_from_unix(errno);
945 if (params.do_chown) {
946 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
947 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
948 security_info_sent, psd);
949 if (!NT_STATUS_IS_OK(status)) {
950 DEBUG(8, ("unpack_nt_owners failed"));
954 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
955 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
957 status = try_chown(fsp, newUID, newGID);
958 if (!NT_STATUS_IS_OK(status)) {
959 DEBUG(3,("chown %s, %u, %u failed. Error = "
960 "%s.\n", fsp_str_dbg(fsp),
961 (unsigned int)newUID,
962 (unsigned int)newGID,
968 DEBUG(10,("chown %s, %u, %u succeeded.\n",
969 fsp_str_dbg(fsp), (unsigned int)newUID,
970 (unsigned int)newGID));
971 if (smbacl4_GetFileOwner(fsp->conn,
975 return map_nt_error_from_unix(errno);
978 /* If we successfully chowned, we know we must
979 * be able to set the acl, so do it as root.
981 set_acl_as_root = true;
985 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
986 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
987 security_info_sent));
992 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
993 sbuf.st_ex_uid, sbuf.st_ex_gid);
996 return map_nt_error_from_unix(errno);
999 smbacl4_set_controlflags(theacl, psd->type);
1000 smbacl4_dump_nfs4acl(10, theacl);
1002 if (set_acl_as_root) {
1005 result = set_nfs4_native(handle, fsp, theacl);
1006 saved_errno = errno;
1007 if (set_acl_as_root) {
1014 errno = saved_errno;
1015 DEBUG(10, ("set_nfs4_native failed with %s\n",
1017 return map_nt_error_from_unix(errno);
1020 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1021 return NT_STATUS_OK;