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 = 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 = (void *)ace;
211 return (struct SMB4ACE_T *)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;
331 aceint=(struct SMB4ACE_T *)aceint->next) {
334 SMB_ACE4PROP_T *ace = &aceint->prop;
335 uint32_t win_ace_flags;
337 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
338 "mask: %x, who: %d\n",
339 ace->aceType, ace->flags,
340 ace->aceFlags, ace->aceMask, ace->who.id));
342 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
343 switch (ace->who.special_id) {
344 case SMB_ACE4_WHO_OWNER:
345 sid_copy(&sid, psid_owner);
347 case SMB_ACE4_WHO_GROUP:
348 sid_copy(&sid, psid_group);
350 case SMB_ACE4_WHO_EVERYONE:
351 sid_copy(&sid, &global_sid_World);
354 DEBUG(8, ("invalid special who id %d "
355 "ignored\n", ace->who.special_id));
359 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
360 gid_to_sid(&sid, ace->who.gid);
362 uid_to_sid(&sid, ace->who.uid);
365 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
366 sid_string_dbg(&sid)));
368 if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
369 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
372 if (!is_directory && params->map_full_control) {
374 * Do we have all access except DELETE_CHILD
375 * (not caring about the delete bit).
377 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
379 if (test_mask == SMB_ACE4_ALL_MASKS) {
380 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
384 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
387 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
388 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
390 * GPFS sets inherits dir_inhert and file_inherit flags
391 * to files, too, which confuses windows, and seems to
392 * be wrong anyways. ==> Map these bits away for files.
394 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
395 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
396 SEC_ACE_FLAG_CONTAINER_INHERIT);
398 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
399 ace->aceFlags, win_ace_flags));
402 /* Windows clients expect SYNC on acls to
403 correctly allow rename. See bug #7909. */
404 /* But not on DENY ace entries. See
406 if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
407 mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
410 /* Mapping of owner@ and group@ to creator owner and
411 creator group. Keep old behavior in mode special. */
412 if (params->mode != e_special &&
413 ace->flags & SMB_ACE4_ID_SPECIAL &&
414 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
415 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
416 DEBUG(10, ("Map special entry\n"));
417 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
418 uint32_t win_ace_flags_current;
419 DEBUG(10, ("Map current sid\n"));
420 win_ace_flags_current = win_ace_flags &
421 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
422 SEC_ACE_FLAG_CONTAINER_INHERIT);
423 init_sec_ace(&nt_ace_list[good_aces++], &sid,
425 win_ace_flags_current);
427 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
428 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
429 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
430 uint32_t win_ace_flags_creator;
431 DEBUG(10, ("Map creator owner\n"));
432 win_ace_flags_creator = win_ace_flags |
433 SMB_ACE4_INHERIT_ONLY_ACE;
434 init_sec_ace(&nt_ace_list[good_aces++],
435 &global_sid_Creator_Owner,
437 win_ace_flags_creator);
439 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
440 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
441 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
442 uint32_t win_ace_flags_creator;
443 DEBUG(10, ("Map creator owner group\n"));
444 win_ace_flags_creator = win_ace_flags |
445 SMB_ACE4_INHERIT_ONLY_ACE;
446 init_sec_ace(&nt_ace_list[good_aces++],
447 &global_sid_Creator_Group,
449 win_ace_flags_creator);
452 DEBUG(10, ("Map normal sid\n"));
453 init_sec_ace(&nt_ace_list[good_aces++], &sid,
459 nt_ace_list = (struct security_ace *)
460 TALLOC_REALLOC(mem_ctx, nt_ace_list,
461 good_aces * sizeof(struct security_ace));
462 /* returns a NULL ace list when good_aces is zero. */
463 if (good_aces && nt_ace_list == NULL) {
464 DEBUG(10, ("realloc error with %d aces", good_aces));
469 *ppnt_ace_list = nt_ace_list;
470 *pgood_aces = good_aces;
475 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
476 smbacl4_vfs_params *params,
477 uint32_t security_info,
479 struct security_descriptor **ppdesc,
480 struct SMB4ACL_T *theacl)
483 struct dom_sid sid_owner, sid_group;
485 struct security_ace *nt_ace_list = NULL;
486 struct security_acl *psa = NULL;
487 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 if (smbacl4_nfs42win(mem_ctx, params, theacl, &sid_owner, &sid_group,
500 S_ISDIR(sbuf->st_ex_mode),
501 &nt_ace_list, &good_aces)==false) {
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;
591 aceint=(struct SMB4ACE_T *)aceint->next) {
592 SMB_ACE4PROP_T *ace = &aceint->prop;
594 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
595 "mask=0x%x, id=%d\n",
597 ace->aceFlags, ace->flags,
604 * Find 2 NFS4 who-special ACE property (non-copy!!!)
605 * match nonzero if "special" and who is equal
606 * return ace if found matching; otherwise NULL
608 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
609 struct SMB4ACL_T *acl,
610 SMB_ACE4PROP_T *aceNew)
612 struct SMB4ACE_T *aceint;
614 for (aceint = acl->first; aceint != NULL;
615 aceint=(struct SMB4ACE_T *)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 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;
786 aceint=(struct SMB4ACE_T *)aceint->next) {
787 SMB_ACE4PROP_T *ace = &aceint->prop;
789 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
790 "mask: %x, who: %d\n",
791 ace->aceType, ace->flags, ace->aceFlags,
792 ace->aceMask, ace->who.id));
794 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
795 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
796 ace->who.uid == ownerUID) {
797 ace->flags |= SMB_ACE4_ID_SPECIAL;
798 ace->who.special_id = SMB_ACE4_WHO_OWNER;
799 DEBUG(10,("replaced with special owner ace\n"));
802 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
803 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
804 ace->who.uid == ownerGID) {
805 ace->flags |= SMB_ACE4_ID_SPECIAL;
806 ace->who.special_id = SMB_ACE4_WHO_GROUP;
807 DEBUG(10,("replaced with special group ace\n"));
810 return true; /* OK */
813 static int smbacl4_substitute_simple(
814 struct SMB4ACL_T *acl,
819 struct SMB4ACE_T *aceint;
821 for(aceint = acl->first; aceint!=NULL;
822 aceint=(struct SMB4ACE_T *)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 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 uint32_t security_info_sent,
910 const struct security_descriptor *psd,
911 set_nfs4acl_native_fn_t set_nfs4_native)
913 smbacl4_vfs_params params;
914 struct SMB4ACL_T *theacl = NULL;
917 SMB_STRUCT_STAT sbuf;
918 bool set_acl_as_root = false;
919 uid_t newUID = (uid_t)-1;
920 gid_t newGID = (gid_t)-1;
922 TALLOC_CTX *frame = talloc_stackframe();
924 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
926 if ((security_info_sent & (SECINFO_DACL |
927 SECINFO_GROUP | SECINFO_OWNER)) == 0)
929 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
930 security_info_sent));
932 return NT_STATUS_OK; /* won't show error - later to be
936 /* Special behaviours */
937 if (smbacl4_get_vfs_params(SMBACL4_PARAM_TYPE_NAME,
938 fsp->conn, ¶ms)) {
940 return NT_STATUS_NO_MEMORY;
943 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
945 return map_nt_error_from_unix(errno);
948 if (params.do_chown) {
949 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
950 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
951 security_info_sent, psd);
952 if (!NT_STATUS_IS_OK(status)) {
953 DEBUG(8, ("unpack_nt_owners failed"));
957 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
958 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
960 status = try_chown(fsp, newUID, newGID);
961 if (!NT_STATUS_IS_OK(status)) {
962 DEBUG(3,("chown %s, %u, %u failed. Error = "
963 "%s.\n", fsp_str_dbg(fsp),
964 (unsigned int)newUID,
965 (unsigned int)newGID,
971 DEBUG(10,("chown %s, %u, %u succeeded.\n",
972 fsp_str_dbg(fsp), (unsigned int)newUID,
973 (unsigned int)newGID));
974 if (smbacl4_GetFileOwner(fsp->conn,
975 fsp->fsp_name->base_name,
978 return map_nt_error_from_unix(errno);
981 /* If we successfully chowned, we know we must
982 * be able to set the acl, so do it as root.
984 set_acl_as_root = true;
988 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
989 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
990 security_info_sent));
995 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
996 sbuf.st_ex_uid, sbuf.st_ex_gid);
999 return map_nt_error_from_unix(errno);
1002 smbacl4_set_controlflags(theacl, psd->type);
1003 smbacl4_dump_nfs4acl(10, theacl);
1005 if (set_acl_as_root) {
1008 result = set_nfs4_native(handle, fsp, theacl);
1009 saved_errno = errno;
1010 if (set_acl_as_root) {
1017 errno = saved_errno;
1018 DEBUG(10, ("set_nfs4_native failed with %s\n",
1020 return map_nt_error_from_unix(errno);
1023 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1024 return NT_STATUS_OK;