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;
55 * Gather special parameters for NFS4 ACL handling
57 int smbacl4_get_vfs_params(struct connection_struct *conn,
58 struct smbacl4_vfs_params *params)
60 static const struct enum_list enum_smbacl4_modes[] = {
61 { e_simple, "simple" },
62 { e_special, "special" },
65 static const struct enum_list enum_smbacl4_acedups[] = {
66 { e_dontcare, "dontcare" },
67 { e_reject, "reject" },
68 { e_ignore, "ignore" },
76 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
77 enum_smbacl4_modes, e_simple);
79 DEBUG(10, ("value for %s:mode unknown\n",
80 SMBACL4_PARAM_TYPE_NAME));
83 params->mode = (enum smbacl4_mode_enum)enumval;
85 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
88 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
89 enum_smbacl4_acedups, e_dontcare);
91 DEBUG(10, ("value for %s:acedup unknown\n",
92 SMBACL4_PARAM_TYPE_NAME));
95 params->acedup = (enum smbacl4_acedup_enum)enumval;
97 params->map_full_control = lp_acl_map_full_control(SNUM(conn));
99 DEBUG(10, ("mode:%s, do_chown:%s, acedup: %s map full control:%s\n",
100 enum_smbacl4_modes[params->mode].name,
101 params->do_chown ? "true" : "false",
102 enum_smbacl4_acedups[params->acedup].name,
103 params->map_full_control ? "true" : "false"));
108 /************************************************
109 Split the ACE flag mapping between nfs4 and Windows
110 into two separate functions rather than trying to do
111 it inline. Allows us to carefully control what flags
112 are mapped to what in one place.
113 ************************************************/
115 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
116 uint32_t nfs4_ace_flags)
118 uint32_t win_ace_flags = 0;
120 /* The nfs4 flags <= 0xf map perfectly. */
121 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
122 SEC_ACE_FLAG_CONTAINER_INHERIT|
123 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
124 SEC_ACE_FLAG_INHERIT_ONLY);
126 /* flags greater than 0xf have diverged :-(. */
127 /* See the nfs4 ace flag definitions here:
128 http://www.ietf.org/rfc/rfc3530.txt.
129 And the Windows ace flag definitions here:
130 librpc/idl/security.idl. */
131 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
132 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
135 return win_ace_flags;
138 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
140 uint32_t nfs4_ace_flags = 0;
142 /* The windows flags <= 0xf map perfectly. */
143 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
144 SMB_ACE4_DIRECTORY_INHERIT_ACE|
145 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
146 SMB_ACE4_INHERIT_ONLY_ACE);
148 /* flags greater than 0xf have diverged :-(. */
149 /* See the nfs4 ace flag definitions here:
150 http://www.ietf.org/rfc/rfc3530.txt.
151 And the Windows ace flag definitions here:
152 librpc/idl/security.idl. */
153 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
154 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
157 return nfs4_ace_flags;
160 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
162 struct SMB4ACL_T *theacl;
164 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
167 DEBUG(0, ("TALLOC_SIZE failed\n"));
171 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
172 /* theacl->first, last = NULL not needed */
176 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
178 struct SMB4ACE_T *ace;
180 ace = talloc_zero(acl, struct SMB4ACE_T);
183 DEBUG(0, ("TALLOC_SIZE failed\n"));
187 /* ace->next = NULL not needed */
188 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
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 SMB_ACE4PROP_T *ace = &aceint->prop;
322 uint32_t win_ace_flags;
324 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
325 "mask: %x, who: %d\n",
326 ace->aceType, ace->flags,
327 ace->aceFlags, ace->aceMask, ace->who.id));
329 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
330 switch (ace->who.special_id) {
331 case SMB_ACE4_WHO_OWNER:
332 sid_copy(&sid, psid_owner);
334 case SMB_ACE4_WHO_GROUP:
335 sid_copy(&sid, psid_group);
337 case SMB_ACE4_WHO_EVERYONE:
338 sid_copy(&sid, &global_sid_World);
341 DEBUG(8, ("invalid special who id %d "
342 "ignored\n", ace->who.special_id));
346 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
347 gid_to_sid(&sid, ace->who.gid);
349 uid_to_sid(&sid, ace->who.uid);
352 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
353 sid_string_dbg(&sid)));
355 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
356 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
359 if (!is_directory && params->map_full_control) {
361 * Do we have all access except DELETE_CHILD
362 * (not caring about the delete bit).
364 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
366 if (test_mask == SMB_ACE4_ALL_MASKS) {
367 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
371 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
374 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
375 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
377 * GPFS sets inherits dir_inhert and file_inherit flags
378 * to files, too, which confuses windows, and seems to
379 * be wrong anyways. ==> Map these bits away for files.
381 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
382 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
383 SEC_ACE_FLAG_CONTAINER_INHERIT);
385 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
386 ace->aceFlags, win_ace_flags));
389 /* Windows clients expect SYNC on acls to
390 correctly allow rename. See bug #7909. */
391 /* But not on DENY ace entries. See
393 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
394 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
397 /* Mapping of owner@ and group@ to creator owner and
398 creator group. Keep old behavior in mode special. */
399 if (params->mode != e_special &&
400 ace->flags & SMB_ACE4_ID_SPECIAL &&
401 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
402 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
403 DEBUG(10, ("Map special entry\n"));
404 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
405 uint32_t win_ace_flags_current;
406 DEBUG(10, ("Map current sid\n"));
407 win_ace_flags_current = win_ace_flags &
408 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
409 SEC_ACE_FLAG_CONTAINER_INHERIT);
410 init_sec_ace(&nt_ace_list[good_aces++], &sid,
412 win_ace_flags_current);
414 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
415 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
416 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
417 uint32_t win_ace_flags_creator;
418 DEBUG(10, ("Map creator owner\n"));
419 win_ace_flags_creator = win_ace_flags |
420 SMB_ACE4_INHERIT_ONLY_ACE;
421 init_sec_ace(&nt_ace_list[good_aces++],
422 &global_sid_Creator_Owner,
424 win_ace_flags_creator);
426 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
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 group\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_Group,
436 win_ace_flags_creator);
439 DEBUG(10, ("Map normal sid\n"));
440 init_sec_ace(&nt_ace_list[good_aces++], &sid,
446 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
449 /* returns a NULL ace list when good_aces is zero. */
450 if (good_aces && nt_ace_list == NULL) {
451 DEBUG(10, ("realloc error with %d aces", good_aces));
456 *ppnt_ace_list = nt_ace_list;
457 *pgood_aces = good_aces;
462 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
463 const struct smbacl4_vfs_params *params,
464 uint32_t security_info,
466 struct security_descriptor **ppdesc,
467 struct SMB4ACL_T *theacl)
470 struct dom_sid sid_owner, sid_group;
472 struct security_ace *nt_ace_list = NULL;
473 struct security_acl *psa = NULL;
474 TALLOC_CTX *frame = talloc_stackframe();
479 return NT_STATUS_ACCESS_DENIED; /* special because we
480 * need to think through
484 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
485 gid_to_sid(&sid_group, sbuf->st_ex_gid);
487 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
488 S_ISDIR(sbuf->st_ex_mode),
489 &nt_ace_list, &good_aces);
491 DEBUG(8,("smbacl4_nfs42win failed\n"));
493 return map_nt_error_from_unix(errno);
496 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
498 DEBUG(2,("make_sec_acl failed\n"));
500 return NT_STATUS_NO_MEMORY;
503 DEBUG(10,("after make sec_acl\n"));
504 *ppdesc = make_sec_desc(
505 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
506 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
507 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
508 NULL, psa, &sd_size);
510 DEBUG(2,("make_sec_desc failed\n"));
512 return NT_STATUS_NO_MEMORY;
515 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
517 (int)ndr_size_security_descriptor(*ppdesc, 0)));
523 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
524 const struct smbacl4_vfs_params *pparams,
525 uint32_t security_info,
527 struct security_descriptor **ppdesc,
528 struct SMB4ACL_T *theacl)
530 SMB_STRUCT_STAT sbuf;
531 struct smbacl4_vfs_params params;
533 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
535 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
536 return map_nt_error_from_unix(errno);
539 if (pparams == NULL) {
540 /* Special behaviours */
541 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
542 return NT_STATUS_NO_MEMORY;
547 return smb_get_nt_acl_nfs4_common(&sbuf, pparams, security_info,
548 mem_ctx, ppdesc, theacl);
551 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
552 const struct smb_filename *smb_fname,
553 const struct smbacl4_vfs_params *pparams,
554 uint32_t security_info,
556 struct security_descriptor **ppdesc,
557 struct SMB4ACL_T *theacl)
559 SMB_STRUCT_STAT sbuf;
560 struct smbacl4_vfs_params params;
562 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
563 smb_fname->base_name));
565 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
566 return map_nt_error_from_unix(errno);
569 if (pparams == NULL) {
570 /* Special behaviours */
571 if (smbacl4_get_vfs_params(conn, ¶ms)) {
572 return NT_STATUS_NO_MEMORY;
577 return smb_get_nt_acl_nfs4_common(&sbuf, pparams, security_info,
578 mem_ctx, ppdesc, theacl);
581 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
583 struct SMB4ACE_T *aceint;
585 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
587 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
588 SMB_ACE4PROP_T *ace = &aceint->prop;
590 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
591 "mask=0x%x, id=%d\n",
593 ace->aceFlags, ace->flags,
600 * Find 2 NFS4 who-special ACE property (non-copy!!!)
601 * match nonzero if "special" and who is equal
602 * return ace if found matching; otherwise NULL
604 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
605 struct SMB4ACL_T *acl,
606 SMB_ACE4PROP_T *aceNew)
608 struct SMB4ACE_T *aceint;
610 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
611 SMB_ACE4PROP_T *ace = &aceint->prop;
613 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
614 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
615 ace->aceType, ace->flags, ace->aceFlags,
616 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
618 if (ace->flags == aceNew->flags &&
619 ace->aceType==aceNew->aceType &&
620 ace->aceFlags==aceNew->aceFlags)
622 /* keep type safety; e.g. gid is an u.short */
623 if (ace->flags & SMB_ACE4_ID_SPECIAL)
625 if (ace->who.special_id ==
626 aceNew->who.special_id)
629 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
631 if (ace->who.gid==aceNew->who.gid)
634 if (ace->who.uid==aceNew->who.uid)
645 static bool smbacl4_fill_ace4(
646 const struct smb_filename *filename,
647 const struct smbacl4_vfs_params *params,
650 const struct security_ace *ace_nt, /* input */
651 SMB_ACE4PROP_T *ace_v4 /* output */
654 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
656 ZERO_STRUCTP(ace_v4);
658 /* only ACCESS|DENY supported right now */
659 ace_v4->aceType = ace_nt->type;
661 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
664 /* remove inheritance flags on files */
665 if (VALID_STAT(filename->st) &&
666 !S_ISDIR(filename->st.st_ex_mode)) {
667 DEBUG(10, ("Removing inheritance flags from a file\n"));
668 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
669 SMB_ACE4_DIRECTORY_INHERIT_ACE|
670 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
671 SMB_ACE4_INHERIT_ONLY_ACE);
674 ace_v4->aceMask = ace_nt->access_mask &
675 (SEC_STD_ALL | SEC_FILE_ALL);
677 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
679 if (ace_v4->aceFlags!=ace_nt->flags)
680 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
681 ace_v4->aceFlags, ace_nt->flags));
683 if (ace_v4->aceMask!=ace_nt->access_mask)
684 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
685 ace_v4->aceMask, ace_nt->access_mask));
687 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
688 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
689 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
690 } else if (params->mode!=e_special &&
691 dom_sid_equal(&ace_nt->trustee,
692 &global_sid_Creator_Owner)) {
693 DEBUG(10, ("Map creator owner\n"));
694 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
695 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
696 /* A non inheriting creator owner entry has no effect. */
697 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
698 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
699 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
702 } else if (params->mode!=e_special &&
703 dom_sid_equal(&ace_nt->trustee,
704 &global_sid_Creator_Group)) {
705 DEBUG(10, ("Map creator owner group\n"));
706 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
707 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
708 /* A non inheriting creator group entry has no effect. */
709 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
710 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
711 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
719 * ID_TYPE_BOTH returns both uid and gid. Explicitly
720 * check for ownerUID to allow the mapping of the
721 * owner to a special entry in this idmap config.
723 if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) {
724 ace_v4->who.uid = uid;
725 } else if (sid_to_gid(&ace_nt->trustee, &gid)) {
726 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
727 ace_v4->who.gid = gid;
728 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
729 ace_v4->who.uid = uid;
730 } else if (dom_sid_compare_domain(&ace_nt->trustee,
731 &global_sid_Unix_NFS) == 0) {
734 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
735 "convert %s to uid or gid\n",
737 sid_string_dbg(&ace_nt->trustee)));
742 return true; /* OK */
745 static int smbacl4_MergeIgnoreReject(
746 enum smbacl4_acedup_enum acedup,
747 struct SMB4ACL_T *theacl, /* may modify it */
748 SMB_ACE4PROP_T *ace, /* the "new" ACE */
754 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
759 case e_merge: /* "merge" flags */
761 ace4found->aceFlags |= ace->aceFlags;
762 ace4found->aceMask |= ace->aceMask;
764 case e_ignore: /* leave out this record */
767 case e_reject: /* do an error */
768 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
769 errno = EINVAL; /* SHOULD be set on any _real_ error */
779 static int smbacl4_substitute_special(
780 struct SMB4ACL_T *acl,
785 struct SMB4ACE_T *aceint;
787 for (aceint = acl->first; aceint != NULL; aceint = 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; aceint = aceint->next) {
823 SMB_ACE4PROP_T *ace = &aceint->prop;
825 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
826 "mask: %x, who: %d\n",
827 ace->aceType, ace->flags, ace->aceFlags,
828 ace->aceMask, ace->who.id));
830 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
831 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
832 ace->who.uid == ownerUID &&
833 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
834 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
835 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
836 ace->flags |= SMB_ACE4_ID_SPECIAL;
837 ace->who.special_id = SMB_ACE4_WHO_OWNER;
838 DEBUG(10,("replaced with special owner ace\n"));
841 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
842 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
843 ace->who.uid == ownerGID &&
844 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
845 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
846 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
847 ace->flags |= SMB_ACE4_ID_SPECIAL;
848 ace->who.special_id = SMB_ACE4_WHO_GROUP;
849 DEBUG(10,("replaced with special group ace\n"));
852 return true; /* OK */
855 static struct SMB4ACL_T *smbacl4_win2nfs4(
857 const files_struct *fsp,
858 const struct security_acl *dacl,
859 const struct smbacl4_vfs_params *pparams,
864 struct SMB4ACL_T *theacl;
866 const char *filename = fsp->fsp_name->base_name;
868 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
870 theacl = smb_create_smb4acl(mem_ctx);
874 for(i=0; i<dacl->num_aces; i++) {
875 SMB_ACE4PROP_T ace_v4;
876 bool addNewACE = true;
878 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
880 dacl->aces + i, &ace_v4)) {
881 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
883 sid_string_dbg(&((dacl->aces+i)->trustee))));
887 if (pparams->acedup!=e_dontcare) {
888 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
889 &ace_v4, &addNewACE, i))
894 smb_add_ace4(theacl, &ace_v4);
897 if (pparams->mode==e_simple) {
898 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
901 if (pparams->mode==e_special) {
902 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
908 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
909 const struct smbacl4_vfs_params *pparams,
910 uint32_t security_info_sent,
911 const struct security_descriptor *psd,
912 set_nfs4acl_native_fn_t set_nfs4_native)
914 struct 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 if (pparams == NULL) {
938 /* Special behaviours */
939 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
941 return NT_STATUS_NO_MEMORY;
946 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
948 return map_nt_error_from_unix(errno);
951 if (pparams->do_chown) {
952 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
953 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
954 security_info_sent, psd);
955 if (!NT_STATUS_IS_OK(status)) {
956 DEBUG(8, ("unpack_nt_owners failed"));
960 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
961 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
963 status = try_chown(fsp, newUID, newGID);
964 if (!NT_STATUS_IS_OK(status)) {
965 DEBUG(3,("chown %s, %u, %u failed. Error = "
966 "%s.\n", fsp_str_dbg(fsp),
967 (unsigned int)newUID,
968 (unsigned int)newGID,
974 DEBUG(10,("chown %s, %u, %u succeeded.\n",
975 fsp_str_dbg(fsp), (unsigned int)newUID,
976 (unsigned int)newGID));
977 if (smbacl4_GetFileOwner(fsp->conn,
981 return map_nt_error_from_unix(errno);
984 /* If we successfully chowned, we know we must
985 * be able to set the acl, so do it as root.
987 set_acl_as_root = true;
991 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
992 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
993 security_info_sent));
998 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams,
999 sbuf.st_ex_uid, sbuf.st_ex_gid);
1002 return map_nt_error_from_unix(errno);
1005 smbacl4_set_controlflags(theacl, psd->type);
1006 smbacl4_dump_nfs4acl(10, theacl);
1008 if (set_acl_as_root) {
1011 result = set_nfs4_native(handle, fsp, theacl);
1012 saved_errno = errno;
1013 if (set_acl_as_root) {
1020 errno = saved_errno;
1021 DEBUG(10, ("set_nfs4_native failed with %s\n",
1023 return map_nt_error_from_unix(errno);
1026 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1027 return NT_STATUS_OK;