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 typedef 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 const char *type_name,
69 struct connection_struct *conn,
70 smbacl4_vfs_params *params
73 static const struct enum_list enum_smbacl4_modes[] = {
74 { e_simple, "simple" },
75 { e_special, "special" },
78 static const struct enum_list enum_smbacl4_acedups[] = {
79 { e_dontcare, "dontcare" },
80 { e_reject, "reject" },
81 { e_ignore, "ignore" },
89 enumval = lp_parm_enum(SNUM(conn), type_name, "mode",
90 enum_smbacl4_modes, e_simple);
92 DEBUG(10, ("value for %s:mode unknown\n", type_name));
95 params->mode = (enum smbacl4_mode_enum)enumval;
97 params->do_chown = lp_parm_bool(SNUM(conn), type_name,
100 enumval = lp_parm_enum(SNUM(conn), type_name, "acedup",
101 enum_smbacl4_acedups, e_dontcare);
103 DEBUG(10, ("value for %s:acedup unknown\n", type_name));
106 params->acedup = (enum smbacl4_acedup_enum)enumval;
108 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
110 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
111 enum_smbacl4_modes[params->mode].name,
112 params->do_chown ? "true" : "false",
113 enum_smbacl4_acedups[params->acedup].name,
114 params->map_full_control ? "true" : "false"));
119 /************************************************
120 Split the ACE flag mapping between nfs4 and Windows
121 into two separate functions rather than trying to do
122 it inline. Allows us to carefully control what flags
123 are mapped to what in one place.
124 ************************************************/
126 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
127 uint32_t nfs4_ace_flags)
129 uint32_t win_ace_flags = 0;
131 /* The nfs4 flags <= 0xf map perfectly. */
132 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
133 SEC_ACE_FLAG_CONTAINER_INHERIT|
134 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
135 SEC_ACE_FLAG_INHERIT_ONLY);
137 /* flags greater than 0xf have diverged :-(. */
138 /* See the nfs4 ace flag definitions here:
139 http://www.ietf.org/rfc/rfc3530.txt.
140 And the Windows ace flag definitions here:
141 librpc/idl/security.idl. */
142 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
143 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
146 return win_ace_flags;
149 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
151 uint32_t nfs4_ace_flags = 0;
153 /* The windows flags <= 0xf map perfectly. */
154 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
155 SMB_ACE4_DIRECTORY_INHERIT_ACE|
156 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
157 SMB_ACE4_INHERIT_ONLY_ACE);
159 /* flags greater than 0xf have diverged :-(. */
160 /* See the nfs4 ace flag definitions here:
161 http://www.ietf.org/rfc/rfc3530.txt.
162 And the Windows ace flag definitions here:
163 librpc/idl/security.idl. */
164 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
165 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
168 return nfs4_ace_flags;
171 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
173 struct SMB4ACL_T *theacl;
175 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
178 DEBUG(0, ("TALLOC_SIZE failed\n"));
182 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
183 /* theacl->first, last = NULL not needed */
184 return (struct SMB4ACL_T *)theacl;
187 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 struct SMB4ACE_T *ace;
191 ace = (struct SMB4ACE_T *)TALLOC_ZERO_SIZE(
192 acl, sizeof(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 = (void *)ace;
212 return (struct SMB4ACE_T *)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 char *filename,
272 SMB_STRUCT_STAT *psbuf)
276 /* Get the stat struct for the owner info. */
277 if (vfs_stat_smb_basename(conn, filename, 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->base_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 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 = (struct security_ace *)TALLOC_ZERO_SIZE(
322 mem_ctx, 2 * acl->naces * sizeof(struct security_ace));
323 if (nt_ace_list==NULL)
325 DEBUG(10, ("talloc error with %d aces", acl->naces));
330 for (aceint=acl->first;
332 aceint=(struct SMB4ACE_T *)aceint->next) {
335 SMB_ACE4PROP_T *ace = &aceint->prop;
336 uint32_t win_ace_flags;
338 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
339 "mask: %x, who: %d\n",
340 ace->aceType, ace->flags,
341 ace->aceFlags, ace->aceMask, ace->who.id));
343 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
344 switch (ace->who.special_id) {
345 case SMB_ACE4_WHO_OWNER:
346 sid_copy(&sid, psid_owner);
348 case SMB_ACE4_WHO_GROUP:
349 sid_copy(&sid, psid_group);
351 case SMB_ACE4_WHO_EVERYONE:
352 sid_copy(&sid, &global_sid_World);
355 DEBUG(8, ("invalid special who id %d "
356 "ignored\n", ace->who.special_id));
360 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
361 gid_to_sid(&sid, ace->who.gid);
363 uid_to_sid(&sid, ace->who.uid);
366 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
367 sid_string_dbg(&sid)));
369 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
370 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
373 if (!is_directory && params->map_full_control) {
375 * Do we have all access except DELETE_CHILD
376 * (not caring about the delete bit).
378 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
380 if (test_mask == SMB_ACE4_ALL_MASKS) {
381 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
385 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
388 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
389 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
391 * GPFS sets inherits dir_inhert and file_inherit flags
392 * to files, too, which confuses windows, and seems to
393 * be wrong anyways. ==> Map these bits away for files.
395 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
396 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
397 SEC_ACE_FLAG_CONTAINER_INHERIT);
399 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
400 ace->aceFlags, win_ace_flags));
403 /* Windows clients expect SYNC on acls to
404 correctly allow rename. See bug #7909. */
405 /* But not on DENY ace entries. See
407 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
408 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
411 /* Mapping of owner@ and group@ to creator owner and
412 creator group. Keep old behavior in mode special. */
413 if (params->mode != e_special &&
414 ace->flags & SMB_ACE4_ID_SPECIAL &&
415 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
416 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
417 DEBUG(10, ("Map special entry\n"));
418 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
419 uint32_t win_ace_flags_current;
420 DEBUG(10, ("Map current sid\n"));
421 win_ace_flags_current = win_ace_flags &
422 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
423 SEC_ACE_FLAG_CONTAINER_INHERIT);
424 init_sec_ace(&nt_ace_list[good_aces++], &sid,
426 win_ace_flags_current);
428 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
429 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
430 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
431 uint32_t win_ace_flags_creator;
432 DEBUG(10, ("Map creator owner\n"));
433 win_ace_flags_creator = win_ace_flags |
434 SMB_ACE4_INHERIT_ONLY_ACE;
435 init_sec_ace(&nt_ace_list[good_aces++],
436 &global_sid_Creator_Owner,
438 win_ace_flags_creator);
440 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
441 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
442 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
443 uint32_t win_ace_flags_creator;
444 DEBUG(10, ("Map creator owner group\n"));
445 win_ace_flags_creator = win_ace_flags |
446 SMB_ACE4_INHERIT_ONLY_ACE;
447 init_sec_ace(&nt_ace_list[good_aces++],
448 &global_sid_Creator_Group,
450 win_ace_flags_creator);
453 DEBUG(10, ("Map normal sid\n"));
454 init_sec_ace(&nt_ace_list[good_aces++], &sid,
460 nt_ace_list = (struct security_ace *)
461 TALLOC_REALLOC(mem_ctx, nt_ace_list,
462 good_aces * sizeof(struct security_ace));
463 /* returns a NULL ace list when good_aces is zero. */
464 if (good_aces && nt_ace_list == NULL) {
465 DEBUG(10, ("realloc error with %d aces", good_aces));
470 *ppnt_ace_list = nt_ace_list;
471 *pgood_aces = good_aces;
476 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
477 smbacl4_vfs_params *params,
478 uint32_t security_info,
480 struct security_descriptor **ppdesc,
481 struct SMB4ACL_T *theacl)
484 struct dom_sid sid_owner, sid_group;
486 struct security_ace *nt_ace_list = NULL;
487 struct security_acl *psa = NULL;
488 TALLOC_CTX *frame = talloc_stackframe();
492 return NT_STATUS_ACCESS_DENIED; /* special because we
493 * need to think through
497 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
498 gid_to_sid(&sid_group, sbuf->st_ex_gid);
500 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
501 S_ISDIR(sbuf->st_ex_mode),
502 &nt_ace_list, &good_aces)==false) {
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 uint32_t security_info,
538 struct security_descriptor **ppdesc,
539 struct SMB4ACL_T *theacl)
541 SMB_STRUCT_STAT sbuf;
542 smbacl4_vfs_params params;
544 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
546 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
547 return map_nt_error_from_unix(errno);
550 /* Special behaviours */
551 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, ¶ms)) {
552 return NT_STATUS_NO_MEMORY;
555 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
556 mem_ctx, ppdesc, theacl);
559 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
561 uint32_t security_info,
563 struct security_descriptor **ppdesc,
564 struct SMB4ACL_T *theacl)
566 SMB_STRUCT_STAT sbuf;
567 smbacl4_vfs_params params;
569 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
571 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
572 return map_nt_error_from_unix(errno);
575 /* Special behaviours */
576 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, ¶ms)) {
577 return NT_STATUS_NO_MEMORY;
580 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
581 mem_ctx, ppdesc, theacl);
584 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
586 struct SMB4ACE_T *aceint;
588 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
590 for (aceint = acl->first;
592 aceint=(struct SMB4ACE_T *)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;
616 aceint=(struct SMB4ACE_T *)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(
652 const struct smb_filename *filename,
653 smbacl4_vfs_params *params,
656 const struct security_ace *ace_nt, /* input */
657 SMB_ACE4PROP_T *ace_v4 /* output */
660 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
662 ZERO_STRUCTP(ace_v4);
664 /* only ACCESS|DENY supported right now */
665 ace_v4->aceType = ace_nt->type;
667 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
670 /* remove inheritance flags on files */
671 if (VALID_STAT(filename->st) &&
672 !S_ISDIR(filename->st.st_ex_mode)) {
673 DEBUG(10, ("Removing inheritance flags from a file\n"));
674 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
675 SMB_ACE4_DIRECTORY_INHERIT_ACE|
676 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
677 SMB_ACE4_INHERIT_ONLY_ACE);
680 ace_v4->aceMask = ace_nt->access_mask &
681 (SEC_STD_ALL | SEC_FILE_ALL);
683 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
685 if (ace_v4->aceFlags!=ace_nt->flags)
686 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
687 ace_v4->aceFlags, ace_nt->flags));
689 if (ace_v4->aceMask!=ace_nt->access_mask)
690 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
691 ace_v4->aceMask, ace_nt->access_mask));
693 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
694 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
695 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
696 } else if (params->mode!=e_special &&
697 dom_sid_equal(&ace_nt->trustee,
698 &global_sid_Creator_Owner)) {
699 DEBUG(10, ("Map creator owner\n"));
700 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
701 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
702 /* A non inheriting creator owner entry has no effect. */
703 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
704 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
705 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
708 } else if (params->mode!=e_special &&
709 dom_sid_equal(&ace_nt->trustee,
710 &global_sid_Creator_Group)) {
711 DEBUG(10, ("Map creator owner group\n"));
712 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
713 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
714 /* A non inheriting creator group entry has no effect. */
715 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
716 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
717 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
724 if (sid_to_gid(&ace_nt->trustee, &gid)) {
725 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
726 ace_v4->who.gid = gid;
727 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
728 ace_v4->who.uid = uid;
729 } else if (dom_sid_compare_domain(&ace_nt->trustee,
730 &global_sid_Unix_NFS) == 0) {
733 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
734 "convert %s to uid or gid\n",
736 sid_string_dbg(&ace_nt->trustee)));
741 return true; /* OK */
744 static int smbacl4_MergeIgnoreReject(
745 enum smbacl4_acedup_enum acedup,
746 struct SMB4ACL_T *theacl, /* may modify it */
747 SMB_ACE4PROP_T *ace, /* the "new" ACE */
753 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
758 case e_merge: /* "merge" flags */
760 ace4found->aceFlags |= ace->aceFlags;
761 ace4found->aceMask |= ace->aceMask;
763 case e_ignore: /* leave out this record */
766 case e_reject: /* do an error */
767 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
768 errno = EINVAL; /* SHOULD be set on any _real_ error */
778 static int smbacl4_substitute_special(
779 struct SMB4ACL_T *acl,
784 struct SMB4ACE_T *aceint;
786 for(aceint = acl->first; aceint!=NULL;
787 aceint=(struct SMB4ACE_T *)aceint->next) {
788 SMB_ACE4PROP_T *ace = &aceint->prop;
790 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
791 "mask: %x, who: %d\n",
792 ace->aceType, ace->flags, ace->aceFlags,
793 ace->aceMask, ace->who.id));
795 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
796 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
797 ace->who.uid == ownerUID) {
798 ace->flags |= SMB_ACE4_ID_SPECIAL;
799 ace->who.special_id = SMB_ACE4_WHO_OWNER;
800 DEBUG(10,("replaced with special owner ace\n"));
803 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
804 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
805 ace->who.uid == ownerGID) {
806 ace->flags |= SMB_ACE4_ID_SPECIAL;
807 ace->who.special_id = SMB_ACE4_WHO_GROUP;
808 DEBUG(10,("replaced with special group ace\n"));
811 return true; /* OK */
814 static int smbacl4_substitute_simple(
815 struct SMB4ACL_T *acl,
820 struct SMB4ACE_T *aceint;
822 for(aceint = acl->first; aceint!=NULL;
823 aceint=(struct SMB4ACE_T *)aceint->next) {
824 SMB_ACE4PROP_T *ace = &aceint->prop;
826 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
827 "mask: %x, who: %d\n",
828 ace->aceType, ace->flags, ace->aceFlags,
829 ace->aceMask, ace->who.id));
831 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
832 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
833 ace->who.uid == ownerUID &&
834 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
835 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
836 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
837 ace->flags |= SMB_ACE4_ID_SPECIAL;
838 ace->who.special_id = SMB_ACE4_WHO_OWNER;
839 DEBUG(10,("replaced with special owner ace\n"));
842 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
843 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
844 ace->who.uid == ownerGID &&
845 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
846 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
847 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
848 ace->flags |= SMB_ACE4_ID_SPECIAL;
849 ace->who.special_id = SMB_ACE4_WHO_GROUP;
850 DEBUG(10,("replaced with special group ace\n"));
853 return true; /* OK */
856 static struct SMB4ACL_T *smbacl4_win2nfs4(
858 const files_struct *fsp,
859 const struct security_acl *dacl,
860 smbacl4_vfs_params *pparams,
865 struct SMB4ACL_T *theacl;
867 const char *filename = fsp->fsp_name->base_name;
869 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
871 theacl = smb_create_smb4acl(mem_ctx);
875 for(i=0; i<dacl->num_aces; i++) {
876 SMB_ACE4PROP_T ace_v4;
877 bool addNewACE = true;
879 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
881 dacl->aces + i, &ace_v4)) {
882 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
884 sid_string_dbg(&((dacl->aces+i)->trustee))));
888 if (pparams->acedup!=e_dontcare) {
889 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
890 &ace_v4, &addNewACE, i))
895 smb_add_ace4(theacl, &ace_v4);
898 if (pparams->mode==e_simple) {
899 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
902 if (pparams->mode==e_special) {
903 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
909 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
910 uint32_t security_info_sent,
911 const struct security_descriptor *psd,
912 set_nfs4acl_native_fn_t set_nfs4_native)
914 smbacl4_vfs_params params;
915 struct SMB4ACL_T *theacl = NULL;
918 SMB_STRUCT_STAT sbuf;
919 bool set_acl_as_root = false;
920 uid_t newUID = (uid_t)-1;
921 gid_t newGID = (gid_t)-1;
923 TALLOC_CTX *frame = talloc_stackframe();
925 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
927 if ((security_info_sent & (SECINFO_DACL |
928 SECINFO_GROUP | SECINFO_OWNER)) == 0)
930 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
931 security_info_sent));
933 return NT_STATUS_OK; /* won't show error - later to be
937 /* Special behaviours */
938 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
939 fsp->conn, ¶ms)) {
941 return NT_STATUS_NO_MEMORY;
944 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
946 return map_nt_error_from_unix(errno);
949 if (params.do_chown) {
950 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
951 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
952 security_info_sent, psd);
953 if (!NT_STATUS_IS_OK(status)) {
954 DEBUG(8, ("unpack_nt_owners failed"));
958 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
959 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
961 status = try_chown(fsp, newUID, newGID);
962 if (!NT_STATUS_IS_OK(status)) {
963 DEBUG(3,("chown %s, %u, %u failed. Error = "
964 "%s.\n", fsp_str_dbg(fsp),
965 (unsigned int)newUID,
966 (unsigned int)newGID,
972 DEBUG(10,("chown %s, %u, %u succeeded.\n",
973 fsp_str_dbg(fsp), (unsigned int)newUID,
974 (unsigned int)newGID));
975 if (smbacl4_GetFileOwner(fsp->conn,
976 fsp->fsp_name->base_name,
979 return map_nt_error_from_unix(errno);
982 /* If we successfully chowned, we know we must
983 * be able to set the acl, so do it as root.
985 set_acl_as_root = true;
989 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
990 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
991 security_info_sent));
996 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
997 sbuf.st_ex_uid, sbuf.st_ex_gid);
1000 return map_nt_error_from_unix(errno);
1003 smbacl4_set_controlflags(theacl, psd->type);
1004 smbacl4_dump_nfs4acl(10, theacl);
1006 if (set_acl_as_root) {
1009 result = set_nfs4_native(handle, fsp, theacl);
1010 saved_errno = errno;
1011 if (set_acl_as_root) {
1018 errno = saved_errno;
1019 DEBUG(10, ("set_nfs4_native failed with %s\n",
1021 return map_nt_error_from_unix(errno);
1024 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1025 return NT_STATUS_OK;