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));
390 /* Mapping of owner@ and group@ to creator owner and
391 creator group. Keep old behavior in mode special. */
392 if (params->mode != e_special &&
393 ace->flags & SMB_ACE4_ID_SPECIAL &&
394 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
395 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
396 DEBUG(10, ("Map special entry\n"));
397 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
398 uint32_t win_ace_flags_current;
399 DEBUG(10, ("Map current sid\n"));
400 win_ace_flags_current = win_ace_flags &
401 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
402 SEC_ACE_FLAG_CONTAINER_INHERIT);
403 init_sec_ace(&nt_ace_list[good_aces++], &sid,
405 win_ace_flags_current);
407 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
408 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
409 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
410 uint32_t win_ace_flags_creator;
411 DEBUG(10, ("Map creator owner\n"));
412 win_ace_flags_creator = win_ace_flags |
413 SMB_ACE4_INHERIT_ONLY_ACE;
414 init_sec_ace(&nt_ace_list[good_aces++],
415 &global_sid_Creator_Owner,
417 win_ace_flags_creator);
419 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
420 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
421 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
422 uint32_t win_ace_flags_creator;
423 DEBUG(10, ("Map creator owner group\n"));
424 win_ace_flags_creator = win_ace_flags |
425 SMB_ACE4_INHERIT_ONLY_ACE;
426 init_sec_ace(&nt_ace_list[good_aces++],
427 &global_sid_Creator_Group,
429 win_ace_flags_creator);
432 DEBUG(10, ("Map normal sid\n"));
433 init_sec_ace(&nt_ace_list[good_aces++], &sid,
439 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
442 /* returns a NULL ace list when good_aces is zero. */
443 if (good_aces && nt_ace_list == NULL) {
444 DEBUG(10, ("realloc error with %d aces", good_aces));
449 *ppnt_ace_list = nt_ace_list;
450 *pgood_aces = good_aces;
455 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
456 const struct smbacl4_vfs_params *params,
457 uint32_t security_info,
459 struct security_descriptor **ppdesc,
460 struct SMB4ACL_T *theacl)
463 struct dom_sid sid_owner, sid_group;
465 struct security_ace *nt_ace_list = NULL;
466 struct security_acl *psa = NULL;
467 TALLOC_CTX *frame = talloc_stackframe();
472 return NT_STATUS_ACCESS_DENIED; /* special because we
473 * need to think through
477 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
478 gid_to_sid(&sid_group, sbuf->st_ex_gid);
480 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
481 S_ISDIR(sbuf->st_ex_mode),
482 &nt_ace_list, &good_aces);
484 DEBUG(8,("smbacl4_nfs42win failed\n"));
486 return map_nt_error_from_unix(errno);
489 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
491 DEBUG(2,("make_sec_acl failed\n"));
493 return NT_STATUS_NO_MEMORY;
496 DEBUG(10,("after make sec_acl\n"));
497 *ppdesc = make_sec_desc(
498 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
499 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
500 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
501 NULL, psa, &sd_size);
503 DEBUG(2,("make_sec_desc failed\n"));
505 return NT_STATUS_NO_MEMORY;
508 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
510 (int)ndr_size_security_descriptor(*ppdesc, 0)));
516 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
517 const struct smbacl4_vfs_params *pparams,
518 uint32_t security_info,
520 struct security_descriptor **ppdesc,
521 struct SMB4ACL_T *theacl)
523 SMB_STRUCT_STAT sbuf;
524 struct smbacl4_vfs_params params;
525 SMB_STRUCT_STAT *psbuf = NULL;
527 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
529 if (VALID_STAT(fsp->fsp_name->st)) {
530 psbuf = &fsp->fsp_name->st;
534 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
535 return map_nt_error_from_unix(errno);
540 if (pparams == NULL) {
541 /* Special behaviours */
542 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
543 return NT_STATUS_NO_MEMORY;
548 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
549 mem_ctx, ppdesc, theacl);
552 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
553 const struct smb_filename *smb_fname,
554 const struct smbacl4_vfs_params *pparams,
555 uint32_t security_info,
557 struct security_descriptor **ppdesc,
558 struct SMB4ACL_T *theacl)
560 SMB_STRUCT_STAT sbuf;
561 struct smbacl4_vfs_params params;
562 const SMB_STRUCT_STAT *psbuf = NULL;
564 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
565 smb_fname->base_name));
567 if (VALID_STAT(smb_fname->st)) {
568 psbuf = &smb_fname->st;
572 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
573 return map_nt_error_from_unix(errno);
578 if (pparams == NULL) {
579 /* Special behaviours */
580 if (smbacl4_get_vfs_params(conn, ¶ms)) {
581 return NT_STATUS_NO_MEMORY;
586 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
587 mem_ctx, ppdesc, theacl);
590 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
592 struct SMB4ACE_T *aceint;
594 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
596 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
597 SMB_ACE4PROP_T *ace = &aceint->prop;
599 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
600 "mask=0x%x, id=%d\n",
602 ace->aceFlags, ace->flags,
609 * Find 2 NFS4 who-special ACE property (non-copy!!!)
610 * match nonzero if "special" and who is equal
611 * return ace if found matching; otherwise NULL
613 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
614 struct SMB4ACL_T *acl,
615 SMB_ACE4PROP_T *aceNew)
617 struct SMB4ACE_T *aceint;
619 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
620 SMB_ACE4PROP_T *ace = &aceint->prop;
622 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
623 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
624 ace->aceType, ace->flags, ace->aceFlags,
625 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
627 if (ace->flags == aceNew->flags &&
628 ace->aceType==aceNew->aceType &&
629 ace->aceFlags==aceNew->aceFlags)
631 /* keep type safety; e.g. gid is an u.short */
632 if (ace->flags & SMB_ACE4_ID_SPECIAL)
634 if (ace->who.special_id ==
635 aceNew->who.special_id)
638 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
640 if (ace->who.gid==aceNew->who.gid)
643 if (ace->who.uid==aceNew->who.uid)
654 static bool smbacl4_fill_ace4(
655 const struct smb_filename *filename,
656 const struct smbacl4_vfs_params *params,
659 const struct security_ace *ace_nt, /* input */
660 SMB_ACE4PROP_T *ace_v4 /* output */
663 DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
665 ZERO_STRUCTP(ace_v4);
667 /* only ACCESS|DENY supported right now */
668 ace_v4->aceType = ace_nt->type;
670 ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
673 /* remove inheritance flags on files */
674 if (VALID_STAT(filename->st) &&
675 !S_ISDIR(filename->st.st_ex_mode)) {
676 DEBUG(10, ("Removing inheritance flags from a file\n"));
677 ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
678 SMB_ACE4_DIRECTORY_INHERIT_ACE|
679 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
680 SMB_ACE4_INHERIT_ONLY_ACE);
683 ace_v4->aceMask = ace_nt->access_mask &
684 (SEC_STD_ALL | SEC_FILE_ALL);
686 se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
688 if (ace_v4->aceFlags!=ace_nt->flags)
689 DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
690 ace_v4->aceFlags, ace_nt->flags));
692 if (ace_v4->aceMask!=ace_nt->access_mask)
693 DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
694 ace_v4->aceMask, ace_nt->access_mask));
696 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
697 ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
698 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
699 } else if (params->mode!=e_special &&
700 dom_sid_equal(&ace_nt->trustee,
701 &global_sid_Creator_Owner)) {
702 DEBUG(10, ("Map creator owner\n"));
703 ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
704 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
705 /* A non inheriting creator owner entry has no effect. */
706 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
707 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
708 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
711 } else if (params->mode!=e_special &&
712 dom_sid_equal(&ace_nt->trustee,
713 &global_sid_Creator_Group)) {
714 DEBUG(10, ("Map creator owner group\n"));
715 ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
716 ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
717 /* A non inheriting creator group entry has no effect. */
718 ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
719 if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
720 && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
728 * ID_TYPE_BOTH returns both uid and gid. Explicitly
729 * check for ownerUID to allow the mapping of the
730 * owner to a special entry in this idmap config.
732 if (sid_to_uid(&ace_nt->trustee, &uid) && uid == ownerUID) {
733 ace_v4->who.uid = uid;
734 } else if (sid_to_gid(&ace_nt->trustee, &gid)) {
735 ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
736 ace_v4->who.gid = gid;
737 } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
738 ace_v4->who.uid = uid;
739 } else if (dom_sid_compare_domain(&ace_nt->trustee,
740 &global_sid_Unix_NFS) == 0) {
743 DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
744 "convert %s to uid or gid\n",
746 sid_string_dbg(&ace_nt->trustee)));
751 return true; /* OK */
754 static int smbacl4_MergeIgnoreReject(
755 enum smbacl4_acedup_enum acedup,
756 struct SMB4ACL_T *theacl, /* may modify it */
757 SMB_ACE4PROP_T *ace, /* the "new" ACE */
763 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
768 case e_merge: /* "merge" flags */
770 ace4found->aceFlags |= ace->aceFlags;
771 ace4found->aceMask |= ace->aceMask;
773 case e_ignore: /* leave out this record */
776 case e_reject: /* do an error */
777 DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
778 errno = EINVAL; /* SHOULD be set on any _real_ error */
788 static int smbacl4_substitute_special(
789 struct SMB4ACL_T *acl,
794 struct SMB4ACE_T *aceint;
796 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
797 SMB_ACE4PROP_T *ace = &aceint->prop;
799 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
800 "mask: %x, who: %d\n",
801 ace->aceType, ace->flags, ace->aceFlags,
802 ace->aceMask, ace->who.id));
804 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
805 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
806 ace->who.uid == ownerUID) {
807 ace->flags |= SMB_ACE4_ID_SPECIAL;
808 ace->who.special_id = SMB_ACE4_WHO_OWNER;
809 DEBUG(10,("replaced with special owner ace\n"));
812 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
813 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
814 ace->who.uid == ownerGID) {
815 ace->flags |= SMB_ACE4_ID_SPECIAL;
816 ace->who.special_id = SMB_ACE4_WHO_GROUP;
817 DEBUG(10,("replaced with special group ace\n"));
820 return true; /* OK */
823 static int smbacl4_substitute_simple(
824 struct SMB4ACL_T *acl,
829 struct SMB4ACE_T *aceint;
831 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
832 SMB_ACE4PROP_T *ace = &aceint->prop;
834 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
835 "mask: %x, who: %d\n",
836 ace->aceType, ace->flags, ace->aceFlags,
837 ace->aceMask, ace->who.id));
839 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
840 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
841 ace->who.uid == ownerUID &&
842 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
843 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
844 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
845 ace->flags |= SMB_ACE4_ID_SPECIAL;
846 ace->who.special_id = SMB_ACE4_WHO_OWNER;
847 DEBUG(10,("replaced with special owner ace\n"));
850 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
851 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
852 ace->who.uid == ownerGID &&
853 !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
854 !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
855 !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
856 ace->flags |= SMB_ACE4_ID_SPECIAL;
857 ace->who.special_id = SMB_ACE4_WHO_GROUP;
858 DEBUG(10,("replaced with special group ace\n"));
861 return true; /* OK */
864 static struct SMB4ACL_T *smbacl4_win2nfs4(
866 const files_struct *fsp,
867 const struct security_acl *dacl,
868 const struct smbacl4_vfs_params *pparams,
873 struct SMB4ACL_T *theacl;
875 const char *filename = fsp->fsp_name->base_name;
877 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
879 theacl = smb_create_smb4acl(mem_ctx);
883 for(i=0; i<dacl->num_aces; i++) {
884 SMB_ACE4PROP_T ace_v4;
885 bool addNewACE = true;
887 if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
889 dacl->aces + i, &ace_v4)) {
890 DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
892 sid_string_dbg(&((dacl->aces+i)->trustee))));
896 if (pparams->acedup!=e_dontcare) {
897 if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
898 &ace_v4, &addNewACE, i))
903 smb_add_ace4(theacl, &ace_v4);
906 if (pparams->mode==e_simple) {
907 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
910 if (pparams->mode==e_special) {
911 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
917 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
918 const struct smbacl4_vfs_params *pparams,
919 uint32_t security_info_sent,
920 const struct security_descriptor *psd,
921 set_nfs4acl_native_fn_t set_nfs4_native)
923 struct smbacl4_vfs_params params;
924 struct SMB4ACL_T *theacl = NULL;
927 SMB_STRUCT_STAT sbuf;
928 bool set_acl_as_root = false;
929 uid_t newUID = (uid_t)-1;
930 gid_t newGID = (gid_t)-1;
932 TALLOC_CTX *frame = talloc_stackframe();
934 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
936 if ((security_info_sent & (SECINFO_DACL |
937 SECINFO_GROUP | SECINFO_OWNER)) == 0)
939 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
940 security_info_sent));
942 return NT_STATUS_OK; /* won't show error - later to be
946 if (pparams == NULL) {
947 /* Special behaviours */
948 if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
950 return NT_STATUS_NO_MEMORY;
955 if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
957 return map_nt_error_from_unix(errno);
960 if (pparams->do_chown) {
961 /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
962 NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
963 security_info_sent, psd);
964 if (!NT_STATUS_IS_OK(status)) {
965 DEBUG(8, ("unpack_nt_owners failed"));
969 if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
970 ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
972 status = try_chown(fsp, newUID, newGID);
973 if (!NT_STATUS_IS_OK(status)) {
974 DEBUG(3,("chown %s, %u, %u failed. Error = "
975 "%s.\n", fsp_str_dbg(fsp),
976 (unsigned int)newUID,
977 (unsigned int)newGID,
983 DEBUG(10,("chown %s, %u, %u succeeded.\n",
984 fsp_str_dbg(fsp), (unsigned int)newUID,
985 (unsigned int)newGID));
986 if (smbacl4_GetFileOwner(fsp->conn,
990 return map_nt_error_from_unix(errno);
993 /* If we successfully chowned, we know we must
994 * be able to set the acl, so do it as root.
996 set_acl_as_root = true;
1000 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1001 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1002 security_info_sent));
1004 return NT_STATUS_OK;
1007 theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, pparams,
1008 sbuf.st_ex_uid, sbuf.st_ex_gid);
1011 return map_nt_error_from_unix(errno);
1014 smbacl4_set_controlflags(theacl, psd->type);
1015 smbacl4_dump_nfs4acl(10, theacl);
1017 if (set_acl_as_root) {
1020 result = set_nfs4_native(handle, fsp, theacl);
1021 saved_errno = errno;
1022 if (set_acl_as_root) {
1029 errno = saved_errno;
1030 DEBUG(10, ("set_nfs4_native failed with %s\n",
1032 return map_nt_error_from_unix(errno);
1035 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1036 return NT_STATUS_OK;