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 */
187 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
189 struct SMB4ACE_T *ace;
191 ace = talloc_zero(acl, struct SMB4ACE_T);
194 DEBUG(0, ("TALLOC_SIZE failed\n"));
198 /* ace->next = NULL not needed */
199 memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
201 if (acl->first==NULL)
206 acl->last->next = ace;
214 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
223 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
232 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
241 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
250 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
256 return acl->controlflags;
259 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
265 acl->controlflags = controlflags;
269 static int smbacl4_GetFileOwner(struct connection_struct *conn,
270 const char *filename,
271 SMB_STRUCT_STAT *psbuf)
275 /* Get the stat struct for the owner info. */
276 if (vfs_stat_smb_basename(conn, filename, psbuf) != 0)
278 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
286 static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
290 if (fsp->fh->fd == -1) {
291 return smbacl4_GetFileOwner(fsp->conn,
292 fsp->fsp_name->base_name, psbuf);
294 if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
296 DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
304 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
305 smbacl4_vfs_params *params,
306 struct SMB4ACL_T *acl, /* in */
307 struct dom_sid *psid_owner, /* in */
308 struct dom_sid *psid_group, /* in */
309 bool is_directory, /* in */
310 struct security_ace **ppnt_ace_list, /* out */
311 int *pgood_aces /* out */
314 struct SMB4ACE_T *aceint;
315 struct security_ace *nt_ace_list = NULL;
318 DEBUG(10, ("%s entered\n", __func__));
320 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
322 if (nt_ace_list==NULL)
324 DEBUG(10, ("talloc error with %d aces", acl->naces));
329 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
332 SMB_ACE4PROP_T *ace = &aceint->prop;
333 uint32_t win_ace_flags;
335 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
336 "mask: %x, who: %d\n",
337 ace->aceType, ace->flags,
338 ace->aceFlags, ace->aceMask, ace->who.id));
340 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
341 switch (ace->who.special_id) {
342 case SMB_ACE4_WHO_OWNER:
343 sid_copy(&sid, psid_owner);
345 case SMB_ACE4_WHO_GROUP:
346 sid_copy(&sid, psid_group);
348 case SMB_ACE4_WHO_EVERYONE:
349 sid_copy(&sid, &global_sid_World);
352 DEBUG(8, ("invalid special who id %d "
353 "ignored\n", ace->who.special_id));
357 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
358 gid_to_sid(&sid, ace->who.gid);
360 uid_to_sid(&sid, ace->who.uid);
363 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
364 sid_string_dbg(&sid)));
366 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
367 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
370 if (!is_directory && params->map_full_control) {
372 * Do we have all access except DELETE_CHILD
373 * (not caring about the delete bit).
375 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
377 if (test_mask == SMB_ACE4_ALL_MASKS) {
378 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
382 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
385 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
386 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
388 * GPFS sets inherits dir_inhert and file_inherit flags
389 * to files, too, which confuses windows, and seems to
390 * be wrong anyways. ==> Map these bits away for files.
392 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
393 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
394 SEC_ACE_FLAG_CONTAINER_INHERIT);
396 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
397 ace->aceFlags, win_ace_flags));
400 /* Windows clients expect SYNC on acls to
401 correctly allow rename. See bug #7909. */
402 /* But not on DENY ace entries. See
404 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
405 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
408 /* Mapping of owner@ and group@ to creator owner and
409 creator group. Keep old behavior in mode special. */
410 if (params->mode != e_special &&
411 ace->flags & SMB_ACE4_ID_SPECIAL &&
412 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
413 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
414 DEBUG(10, ("Map special entry\n"));
415 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
416 uint32_t win_ace_flags_current;
417 DEBUG(10, ("Map current sid\n"));
418 win_ace_flags_current = win_ace_flags &
419 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
420 SEC_ACE_FLAG_CONTAINER_INHERIT);
421 init_sec_ace(&nt_ace_list[good_aces++], &sid,
423 win_ace_flags_current);
425 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
426 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
427 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
428 uint32_t win_ace_flags_creator;
429 DEBUG(10, ("Map creator owner\n"));
430 win_ace_flags_creator = win_ace_flags |
431 SMB_ACE4_INHERIT_ONLY_ACE;
432 init_sec_ace(&nt_ace_list[good_aces++],
433 &global_sid_Creator_Owner,
435 win_ace_flags_creator);
437 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
438 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
439 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
440 uint32_t win_ace_flags_creator;
441 DEBUG(10, ("Map creator owner group\n"));
442 win_ace_flags_creator = win_ace_flags |
443 SMB_ACE4_INHERIT_ONLY_ACE;
444 init_sec_ace(&nt_ace_list[good_aces++],
445 &global_sid_Creator_Group,
447 win_ace_flags_creator);
450 DEBUG(10, ("Map normal sid\n"));
451 init_sec_ace(&nt_ace_list[good_aces++], &sid,
457 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
460 /* returns a NULL ace list when good_aces is zero. */
461 if (good_aces && nt_ace_list == NULL) {
462 DEBUG(10, ("realloc error with %d aces", good_aces));
467 *ppnt_ace_list = nt_ace_list;
468 *pgood_aces = good_aces;
473 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
474 smbacl4_vfs_params *params,
475 uint32_t security_info,
477 struct security_descriptor **ppdesc,
478 struct SMB4ACL_T *theacl)
481 struct dom_sid sid_owner, sid_group;
483 struct security_ace *nt_ace_list = NULL;
484 struct security_acl *psa = NULL;
485 TALLOC_CTX *frame = talloc_stackframe();
490 return NT_STATUS_ACCESS_DENIED; /* special because we
491 * need to think through
495 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
496 gid_to_sid(&sid_group, sbuf->st_ex_gid);
498 ok = smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
499 S_ISDIR(sbuf->st_ex_mode),
500 &nt_ace_list, &good_aces);
502 DEBUG(8,("smbacl4_nfs42win failed\n"));
504 return map_nt_error_from_unix(errno);
507 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
509 DEBUG(2,("make_sec_acl failed\n"));
511 return NT_STATUS_NO_MEMORY;
514 DEBUG(10,("after make sec_acl\n"));
515 *ppdesc = make_sec_desc(
516 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
517 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
518 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
519 NULL, psa, &sd_size);
521 DEBUG(2,("make_sec_desc failed\n"));
523 return NT_STATUS_NO_MEMORY;
526 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
528 (int)ndr_size_security_descriptor(*ppdesc, 0)));
534 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
535 uint32_t security_info,
537 struct security_descriptor **ppdesc,
538 struct SMB4ACL_T *theacl)
540 SMB_STRUCT_STAT sbuf;
541 smbacl4_vfs_params params;
543 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
545 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
546 return map_nt_error_from_unix(errno);
549 /* Special behaviours */
550 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, fsp->conn, ¶ms)) {
551 return NT_STATUS_NO_MEMORY;
554 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
555 mem_ctx, ppdesc, theacl);
558 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
560 uint32_t security_info,
562 struct security_descriptor **ppdesc,
563 struct SMB4ACL_T *theacl)
565 SMB_STRUCT_STAT sbuf;
566 smbacl4_vfs_params params;
568 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n", name));
570 if (smbacl4_GetFileOwner(conn, name, &sbuf)) {
571 return map_nt_error_from_unix(errno);
574 /* Special behaviours */
575 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME, conn, ¶ms)) {
576 return NT_STATUS_NO_MEMORY;
579 return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
580 mem_ctx, ppdesc, theacl);
583 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
585 struct SMB4ACE_T *aceint;
587 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
589 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
590 SMB_ACE4PROP_T *ace = &aceint->prop;
592 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
593 "mask=0x%x, id=%d\n",
595 ace->aceFlags, ace->flags,
602 * Find 2 NFS4 who-special ACE property (non-copy!!!)
603 * match nonzero if "special" and who is equal
604 * return ace if found matching; otherwise NULL
606 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
607 struct SMB4ACL_T *acl,
608 SMB_ACE4PROP_T *aceNew)
610 struct SMB4ACE_T *aceint;
612 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
613 SMB_ACE4PROP_T *ace = &aceint->prop;
615 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
616 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
617 ace->aceType, ace->flags, ace->aceFlags,
618 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
620 if (ace->flags == aceNew->flags &&
621 ace->aceType==aceNew->aceType &&
622 ace->aceFlags==aceNew->aceFlags)
624 /* keep type safety; e.g. gid is an u.short */
625 if (ace->flags & SMB_ACE4_ID_SPECIAL)
627 if (ace->who.special_id ==
628 aceNew->who.special_id)
631 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
633 if (ace->who.gid==aceNew->who.gid)
636 if (ace->who.uid==aceNew->who.uid)
647 static bool smbacl4_fill_ace4(
648 const struct smb_filename *filename,
649 smbacl4_vfs_params *params,
652 const struct security_ace *ace_nt, /* input */
653 SMB_ACE4PROP_T *ace_v4 /* output */
656 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
658 ZERO_STRUCTP(ace_v4);
660 /* only ACCESS|DENY supported right now */
661 ace_v4->aceType = ace_nt->type;
663 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
666 /* remove inheritance flags on files */
667 if (VALID_STAT(filename->st) &&
668 !S_ISDIR(filename->st.st_ex_mode)) {
669 DEBUG(10, ("Removing inheritance flags from a file\n"));
670 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
671 SMB_ACE4_DIRECTORY_INHERIT_ACE|
672 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
673 SMB_ACE4_INHERIT_ONLY_ACE);
676 ace_v4->aceMask = ace_nt->access_mask &
677 (SEC_STD_ALL | SEC_FILE_ALL);
679 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
681 if (ace_v4->aceFlags!=ace_nt->flags)
682 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
683 ace_v4->aceFlags, ace_nt->flags));
685 if (ace_v4->aceMask!=ace_nt->access_mask)
686 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
687 ace_v4->aceMask, ace_nt->access_mask));
689 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
690 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
691 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
692 } else if (params->mode!=e_special &&
693 dom_sid_equal(&ace_nt->trustee,
694 &global_sid_Creator_Owner)) {
695 DEBUG(10, ("Map creator owner\n"));
696 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
697 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
698 /* A non inheriting creator owner entry has no effect. */
699 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
700 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
701 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
704 } else if (params->mode!=e_special &&
705 dom_sid_equal(&ace_nt->trustee,
706 &global_sid_Creator_Group)) {
707 DEBUG(10, ("Map creator owner group\n"));
708 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
709 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
710 /* A non inheriting creator group entry has no effect. */
711 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
712 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
713 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
720 if (sid_to_gid(&ace_nt->trustee, &gid)) {
721 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
722 ace_v4->who.gid = gid;
723 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
724 ace_v4->who.uid = uid;
725 } else if (dom_sid_compare_domain(&ace_nt->trustee,
726 &global_sid_Unix_NFS) == 0) {
729 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
730 "convert %s to uid or gid\n",
732 sid_string_dbg(&ace_nt->trustee)));
737 return true; /* OK */
740 static int smbacl4_MergeIgnoreReject(
741 enum smbacl4_acedup_enum acedup,
742 struct SMB4ACL_T *theacl, /* may modify it */
743 SMB_ACE4PROP_T *ace, /* the "new" ACE */
749 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
754 case e_merge: /* "merge" flags */
756 ace4found->aceFlags |= ace->aceFlags;
757 ace4found->aceMask |= ace->aceMask;
759 case e_ignore: /* leave out this record */
762 case e_reject: /* do an error */
763 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
764 errno = EINVAL; /* SHOULD be set on any _real_ error */
774 static int smbacl4_substitute_special(
775 struct SMB4ACL_T *acl,
780 struct SMB4ACE_T *aceint;
782 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
783 SMB_ACE4PROP_T *ace = &aceint->prop;
785 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
786 "mask: %x, who: %d\n",
787 ace->aceType, ace->flags, ace->aceFlags,
788 ace->aceMask, ace->who.id));
790 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
791 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
792 ace->who.uid == ownerUID) {
793 ace->flags |= SMB_ACE4_ID_SPECIAL;
794 ace->who.special_id = SMB_ACE4_WHO_OWNER;
795 DEBUG(10,("replaced with special owner ace\n"));
798 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
799 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
800 ace->who.uid == ownerGID) {
801 ace->flags |= SMB_ACE4_ID_SPECIAL;
802 ace->who.special_id = SMB_ACE4_WHO_GROUP;
803 DEBUG(10,("replaced with special group ace\n"));
806 return true; /* OK */
809 static int smbacl4_substitute_simple(
810 struct SMB4ACL_T *acl,
815 struct SMB4ACE_T *aceint;
817 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
818 SMB_ACE4PROP_T *ace = &aceint->prop;
820 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
821 "mask: %x, who: %d\n",
822 ace->aceType, ace->flags, ace->aceFlags,
823 ace->aceMask, ace->who.id));
825 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
826 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
827 ace->who.uid == ownerUID &&
828 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
829 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
830 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
831 ace->flags |= SMB_ACE4_ID_SPECIAL;
832 ace->who.special_id = SMB_ACE4_WHO_OWNER;
833 DEBUG(10,("replaced with special owner ace\n"));
836 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
837 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
838 ace->who.uid == ownerGID &&
839 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
840 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
841 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
842 ace->flags |= SMB_ACE4_ID_SPECIAL;
843 ace->who.special_id = SMB_ACE4_WHO_GROUP;
844 DEBUG(10,("replaced with special group ace\n"));
847 return true; /* OK */
850 static struct SMB4ACL_T *smbacl4_win2nfs4(
852 const files_struct *fsp,
853 const struct security_acl *dacl,
854 smbacl4_vfs_params *pparams,
859 struct SMB4ACL_T *theacl;
861 const char *filename = fsp->fsp_name->base_name;
863 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
865 theacl = smb_create_smb4acl(mem_ctx);
869 for(i=0; i<dacl->num_aces; i++) {
870 SMB_ACE4PROP_T ace_v4;
871 bool addNewACE = true;
873 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
875 dacl->aces + i, &ace_v4)) {
876 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
878 sid_string_dbg(&((dacl->aces+i)->trustee))));
882 if (pparams->acedup!=e_dontcare) {
883 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
884 &ace_v4, &addNewACE, i))
889 smb_add_ace4(theacl, &ace_v4);
892 if (pparams->mode==e_simple) {
893 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
896 if (pparams->mode==e_special) {
897 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
903 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
904 uint32_t security_info_sent,
905 const struct security_descriptor *psd,
906 set_nfs4acl_native_fn_t set_nfs4_native)
908 smbacl4_vfs_params params;
909 struct SMB4ACL_T *theacl = NULL;
912 SMB_STRUCT_STAT sbuf;
913 bool set_acl_as_root = false;
914 uid_t newUID = (uid_t)-1;
915 gid_t newGID = (gid_t)-1;
917 TALLOC_CTX *frame = talloc_stackframe();
919 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
921 if ((security_info_sent & (SECINFO_DACL |
922 SECINFO_GROUP | SECINFO_OWNER)) == 0)
924 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
925 security_info_sent));
927 return NT_STATUS_OK; /* won't show error - later to be
931 /* Special behaviours */
932 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
933 fsp->conn, ¶ms)) {
935 return NT_STATUS_NO_MEMORY;
938 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
940 return map_nt_error_from_unix(errno);
943 if (params.do_chown) {
944 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
945 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
946 security_info_sent, psd);
947 if (!NT_STATUS_IS_OK(status)) {
948 DEBUG(8, ("unpack_nt_owners failed"));
952 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
953 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
955 status = try_chown(fsp, newUID, newGID);
956 if (!NT_STATUS_IS_OK(status)) {
957 DEBUG(3,("chown %s, %u, %u failed. Error = "
958 "%s.\n", fsp_str_dbg(fsp),
959 (unsigned int)newUID,
960 (unsigned int)newGID,
966 DEBUG(10,("chown %s, %u, %u succeeded.\n",
967 fsp_str_dbg(fsp), (unsigned int)newUID,
968 (unsigned int)newGID));
969 if (smbacl4_GetFileOwner(fsp->conn,
970 fsp->fsp_name->base_name,
973 return map_nt_error_from_unix(errno);
976 /* If we successfully chowned, we know we must
977 * be able to set the acl, so do it as root.
979 set_acl_as_root = true;
983 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
984 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
985 security_info_sent));
990 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
991 sbuf.st_ex_uid, sbuf.st_ex_gid);
994 return map_nt_error_from_unix(errno);
997 smbacl4_set_controlflags(theacl, psd->type);
998 smbacl4_dump_nfs4acl(10, theacl);
1000 if (set_acl_as_root) {
1003 result = set_nfs4_native(handle, fsp, theacl);
1004 saved_errno = errno;
1005 if (set_acl_as_root) {
1012 errno = saved_errno;
1013 DEBUG(10, ("set_nfs4_native failed with %s\n",
1015 return map_nt_error_from_unix(errno);
1018 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1019 return NT_STATUS_OK;