s3:printing: Allow to run samba-bgqd as a standalone systemd service
[Samba.git] / source3 / modules / nfs4_acls.c
blobc80f8390170b92a3e87e76571f833e2a4a86b229
1 /*
2 * NFS4 ACL handling
4 * Copyright (C) Jim McDonough, 2006
5 * Copyright (C) Christof Schmitt 2019
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "includes.h"
22 #include "smbd/smbd.h"
23 #include "nfs4_acls.h"
24 #include "librpc/gen_ndr/ndr_security.h"
25 #include "librpc/gen_ndr/idmap.h"
26 #include "../libcli/security/dom_sid.h"
27 #include "../libcli/security/security.h"
28 #include "dbwrap/dbwrap.h"
29 #include "dbwrap/dbwrap_open.h"
30 #include "system/filesys.h"
31 #include "passdb/lookup_sid.h"
32 #include "util_tdb.h"
33 #include "lib/param/loadparm.h"
35 #undef DBGC_CLASS
36 #define DBGC_CLASS DBGC_ACLS
38 #define SMBACL4_PARAM_TYPE_NAME "nfs4"
40 extern const struct generic_mapping file_generic_mapping;
42 struct SMB4ACE_T
44 SMB_ACE4PROP_T prop;
45 struct SMB4ACE_T *next;
48 struct SMB4ACL_T
50 uint16_t controlflags;
51 uint32_t naces;
52 struct SMB4ACE_T *first;
53 struct SMB4ACE_T *last;
57 * Gather special parameters for NFS4 ACL handling
59 int smbacl4_get_vfs_params(struct connection_struct *conn,
60 struct smbacl4_vfs_params *params)
62 static const struct enum_list enum_smbacl4_modes[] = {
63 { e_simple, "simple" },
64 { e_special, "special" },
65 { -1 , NULL }
67 static const struct enum_list enum_smbacl4_acedups[] = {
68 { e_dontcare, "dontcare" },
69 { e_reject, "reject" },
70 { e_ignore, "ignore" },
71 { e_merge, "merge" },
72 { -1 , NULL }
74 int enumval;
76 *params = (struct smbacl4_vfs_params) { 0 };
78 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
79 enum_smbacl4_modes, e_simple);
80 if (enumval == -1) {
81 DEBUG(10, ("value for %s:mode unknown\n",
82 SMBACL4_PARAM_TYPE_NAME));
83 return -1;
85 params->mode = (enum smbacl4_mode_enum)enumval;
86 if (params->mode == e_special) {
87 DBG_WARNING("nfs4:mode special is deprecated.\n");
90 params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
91 "chown", true);
93 enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
94 enum_smbacl4_acedups, e_merge);
95 if (enumval == -1) {
96 DEBUG(10, ("value for %s:acedup unknown\n",
97 SMBACL4_PARAM_TYPE_NAME));
98 return -1;
100 params->acedup = (enum smbacl4_acedup_enum)enumval;
101 if (params->acedup == e_ignore) {
102 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
104 if (params->acedup == e_reject) {
105 DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
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"));
116 return 0;
119 static int fstatat_with_cap_dac_override(int fd,
120 const char *pathname,
121 SMB_STRUCT_STAT *sbuf,
122 int flags,
123 bool fake_dir_create_times)
125 int ret;
127 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
128 ret = sys_fstatat(fd,
129 pathname,
130 sbuf,
131 flags,
132 fake_dir_create_times);
133 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
135 return ret;
138 static int stat_with_cap_dac_override(struct vfs_handle_struct *handle,
139 struct smb_filename *smb_fname, int flag)
141 bool fake_dctime = lp_fake_directory_create_times(SNUM(handle->conn));
142 int fd = -1;
143 NTSTATUS status;
144 struct smb_filename *dir_name = NULL;
145 struct smb_filename *rel_name = NULL;
146 int ret = -1;
147 #ifdef O_PATH
148 int open_flags = O_PATH;
149 #else
150 int open_flags = O_RDONLY;
151 #endif
153 status = SMB_VFS_PARENT_PATHNAME(handle->conn,
154 talloc_tos(),
155 smb_fname,
156 &dir_name,
157 &rel_name);
158 if (!NT_STATUS_IS_OK(status)) {
159 errno = map_errno_from_nt_status(status);
160 return -1;
163 fd = open(dir_name->base_name, open_flags, 0);
164 if (fd == -1) {
165 TALLOC_FREE(dir_name);
166 return -1;
169 ret = fstatat_with_cap_dac_override(fd,
170 rel_name->base_name,
171 &smb_fname->st,
172 flag,
173 fake_dctime);
175 TALLOC_FREE(dir_name);
176 close(fd);
178 return ret;
181 int nfs4_acl_stat(struct vfs_handle_struct *handle,
182 struct smb_filename *smb_fname)
184 int ret;
186 ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
187 if (ret == -1 && errno == EACCES) {
188 DEBUG(10, ("Trying stat with capability for %s\n",
189 smb_fname->base_name));
190 ret = stat_with_cap_dac_override(handle, smb_fname, 0);
192 return ret;
195 static int fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
196 bool fake_dir_create_times)
198 int ret;
200 set_effective_capability(DAC_OVERRIDE_CAPABILITY);
201 ret = sys_fstat(fd, sbuf, fake_dir_create_times);
202 drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
204 return ret;
207 int nfs4_acl_fstat(struct vfs_handle_struct *handle,
208 struct files_struct *fsp,
209 SMB_STRUCT_STAT *sbuf)
211 int ret;
213 ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
214 if (ret == -1 && errno == EACCES) {
215 bool fake_dctime =
216 lp_fake_directory_create_times(SNUM(handle->conn));
218 DBG_DEBUG("fstat for %s failed with EACCES. Trying with "
219 "CAP_DAC_OVERRIDE.\n", fsp->fsp_name->base_name);
220 ret = fstat_with_cap_dac_override(fsp_get_pathref_fd(fsp),
221 sbuf,
222 fake_dctime);
225 return ret;
228 int nfs4_acl_lstat(struct vfs_handle_struct *handle,
229 struct smb_filename *smb_fname)
231 int ret;
233 ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
234 if (ret == -1 && errno == EACCES) {
235 DEBUG(10, ("Trying lstat with capability for %s\n",
236 smb_fname->base_name));
237 ret = stat_with_cap_dac_override(handle, smb_fname,
238 AT_SYMLINK_NOFOLLOW);
240 return ret;
243 int nfs4_acl_fstatat(struct vfs_handle_struct *handle,
244 const struct files_struct *dirfsp,
245 const struct smb_filename *smb_fname,
246 SMB_STRUCT_STAT *sbuf,
247 int flags)
249 int ret;
251 ret = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
252 if (ret == -1 && errno == EACCES) {
253 bool fake_dctime =
254 lp_fake_directory_create_times(SNUM(handle->conn));
256 DBG_DEBUG("fstatat for %s failed with EACCES. Trying with "
257 "CAP_DAC_OVERRIDE.\n", dirfsp->fsp_name->base_name);
258 ret = fstatat_with_cap_dac_override(fsp_get_pathref_fd(dirfsp),
259 smb_fname->base_name,
260 sbuf,
261 flags,
262 fake_dctime);
265 return ret;
268 /************************************************
269 Split the ACE flag mapping between nfs4 and Windows
270 into two separate functions rather than trying to do
271 it inline. Allows us to carefully control what flags
272 are mapped to what in one place.
273 ************************************************/
275 static uint32_t map_nfs4_ace_flags_to_windows_ace_flags(
276 uint32_t nfs4_ace_flags)
278 uint32_t win_ace_flags = 0;
280 /* The nfs4 flags <= 0xf map perfectly. */
281 win_ace_flags = nfs4_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
282 SEC_ACE_FLAG_CONTAINER_INHERIT|
283 SEC_ACE_FLAG_NO_PROPAGATE_INHERIT|
284 SEC_ACE_FLAG_INHERIT_ONLY);
286 /* flags greater than 0xf have diverged :-(. */
287 /* See the nfs4 ace flag definitions here:
288 http://www.ietf.org/rfc/rfc3530.txt.
289 And the Windows ace flag definitions here:
290 librpc/idl/security.idl. */
291 if (nfs4_ace_flags & SMB_ACE4_INHERITED_ACE) {
292 win_ace_flags |= SEC_ACE_FLAG_INHERITED_ACE;
295 return win_ace_flags;
298 static uint32_t map_windows_ace_flags_to_nfs4_ace_flags(uint32_t win_ace_flags)
300 uint32_t nfs4_ace_flags = 0;
302 /* The windows flags <= 0xf map perfectly. */
303 nfs4_ace_flags = win_ace_flags & (SMB_ACE4_FILE_INHERIT_ACE|
304 SMB_ACE4_DIRECTORY_INHERIT_ACE|
305 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
306 SMB_ACE4_INHERIT_ONLY_ACE);
308 /* flags greater than 0xf have diverged :-(. */
309 /* See the nfs4 ace flag definitions here:
310 http://www.ietf.org/rfc/rfc3530.txt.
311 And the Windows ace flag definitions here:
312 librpc/idl/security.idl. */
313 if (win_ace_flags & SEC_ACE_FLAG_INHERITED_ACE) {
314 nfs4_ace_flags |= SMB_ACE4_INHERITED_ACE;
317 return nfs4_ace_flags;
320 struct SMB4ACL_T *smb_create_smb4acl(TALLOC_CTX *mem_ctx)
322 struct SMB4ACL_T *theacl;
324 theacl = talloc_zero(mem_ctx, struct SMB4ACL_T);
325 if (theacl==NULL)
327 DEBUG(0, ("TALLOC_SIZE failed\n"));
328 errno = ENOMEM;
329 return NULL;
331 theacl->controlflags = SEC_DESC_SELF_RELATIVE;
332 /* theacl->first, last = NULL not needed */
333 return theacl;
336 struct SMB4ACE_T *smb_add_ace4(struct SMB4ACL_T *acl, SMB_ACE4PROP_T *prop)
338 struct SMB4ACE_T *ace;
340 ace = talloc_zero(acl, struct SMB4ACE_T);
341 if (ace==NULL)
343 DBG_ERR("talloc_zero failed\n");
344 errno = ENOMEM;
345 return NULL;
347 ace->prop = *prop;
349 if (acl->first==NULL)
351 acl->first = ace;
352 acl->last = ace;
353 } else {
354 acl->last->next = ace;
355 acl->last = ace;
357 acl->naces++;
359 return ace;
362 SMB_ACE4PROP_T *smb_get_ace4(struct SMB4ACE_T *ace)
364 if (ace == NULL) {
365 return NULL;
368 return &ace->prop;
371 struct SMB4ACE_T *smb_next_ace4(struct SMB4ACE_T *ace)
373 if (ace == NULL) {
374 return NULL;
377 return ace->next;
380 struct SMB4ACE_T *smb_first_ace4(struct SMB4ACL_T *acl)
382 if (acl == NULL) {
383 return NULL;
386 return acl->first;
389 uint32_t smb_get_naces(struct SMB4ACL_T *acl)
391 if (acl == NULL) {
392 return 0;
395 return acl->naces;
398 uint16_t smbacl4_get_controlflags(struct SMB4ACL_T *acl)
400 if (acl == NULL) {
401 return 0;
404 return acl->controlflags;
407 bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
409 if (acl == NULL) {
410 return false;
413 acl->controlflags = controlflags;
414 return true;
417 bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
419 return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
420 SMB_ACE4_FILE_INHERIT_ACE|
421 SMB_ACE4_DIRECTORY_INHERIT_ACE);
424 static int smbacl4_GetFileOwner(struct connection_struct *conn,
425 const struct smb_filename *smb_fname,
426 SMB_STRUCT_STAT *psbuf)
428 ZERO_STRUCTP(psbuf);
430 /* Get the stat struct for the owner info. */
431 if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
433 DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
434 strerror(errno)));
435 return -1;
438 return 0;
441 static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
442 int *good_aces)
444 struct security_ace *last = NULL;
445 int i;
447 if (*good_aces < 2) {
448 return;
451 last = &nt_ace_list[(*good_aces) - 1];
453 for (i = 0; i < (*good_aces) - 1; i++) {
454 struct security_ace *cur = &nt_ace_list[i];
456 if (cur->type == last->type &&
457 cur->flags == last->flags &&
458 cur->access_mask == last->access_mask &&
459 dom_sid_equal(&cur->trustee, &last->trustee))
461 struct dom_sid_buf sid_buf;
463 DBG_INFO("Removing duplicate entry for SID %s.\n",
464 dom_sid_str_buf(&last->trustee, &sid_buf));
465 (*good_aces)--;
470 static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
471 const struct smbacl4_vfs_params *params,
472 struct SMB4ACL_T *acl, /* in */
473 struct dom_sid *psid_owner, /* in */
474 struct dom_sid *psid_group, /* in */
475 bool is_directory, /* in */
476 struct security_ace **ppnt_ace_list, /* out */
477 int *pgood_aces /* out */
480 struct SMB4ACE_T *aceint;
481 struct security_ace *nt_ace_list = NULL;
482 int good_aces = 0;
484 DEBUG(10, ("%s entered\n", __func__));
486 nt_ace_list = talloc_zero_array(mem_ctx, struct security_ace,
487 2 * acl->naces);
488 if (nt_ace_list==NULL)
490 DEBUG(10, ("talloc error with %d aces\n", acl->naces));
491 errno = ENOMEM;
492 return false;
495 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
496 uint32_t mask;
497 struct dom_sid sid;
498 struct dom_sid_buf buf;
499 SMB_ACE4PROP_T *ace = &aceint->prop;
500 uint32_t win_ace_flags;
502 DEBUG(10, ("type: %d, iflags: %x, flags: %x, "
503 "mask: %x, who: %d\n",
504 ace->aceType, ace->flags,
505 ace->aceFlags, ace->aceMask, ace->who.id));
507 if (ace->flags & SMB_ACE4_ID_SPECIAL) {
508 switch (ace->who.special_id) {
509 case SMB_ACE4_WHO_OWNER:
510 sid_copy(&sid, psid_owner);
511 break;
512 case SMB_ACE4_WHO_GROUP:
513 sid_copy(&sid, psid_group);
514 break;
515 case SMB_ACE4_WHO_EVERYONE:
516 sid_copy(&sid, &global_sid_World);
517 break;
518 default:
519 DEBUG(8, ("invalid special who id %d "
520 "ignored\n", ace->who.special_id));
521 continue;
523 } else {
524 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) {
525 gid_to_sid(&sid, ace->who.gid);
526 } else {
527 uid_to_sid(&sid, ace->who.uid);
530 DEBUG(10, ("mapped %d to %s\n", ace->who.id,
531 dom_sid_str_buf(&sid, &buf)));
533 if (!is_directory && params->map_full_control) {
535 * Do we have all access except DELETE_CHILD
536 * (not caring about the delete bit).
538 uint32_t test_mask = ((ace->aceMask|SMB_ACE4_DELETE|SMB_ACE4_DELETE_CHILD) &
539 SMB_ACE4_ALL_MASKS);
540 if (test_mask == SMB_ACE4_ALL_MASKS) {
541 ace->aceMask |= SMB_ACE4_DELETE_CHILD;
545 win_ace_flags = map_nfs4_ace_flags_to_windows_ace_flags(
546 ace->aceFlags);
547 if (!is_directory &&
548 (win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
549 SEC_ACE_FLAG_CONTAINER_INHERIT))) {
551 * GPFS sets inherits dir_inherit and file_inherit flags
552 * to files, too, which confuses windows, and seems to
553 * be wrong anyways. ==> Map these bits away for files.
555 DEBUG(10, ("removing inherit flags from nfs4 ace\n"));
556 win_ace_flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|
557 SEC_ACE_FLAG_CONTAINER_INHERIT);
559 DEBUG(10, ("Windows mapped ace flags: 0x%x => 0x%x\n",
560 ace->aceFlags, win_ace_flags));
562 mask = ace->aceMask;
564 /* Mapping of owner@ and group@ to creator owner and
565 creator group. Keep old behavior in mode special. */
566 if (params->mode != e_special &&
567 ace->flags & SMB_ACE4_ID_SPECIAL &&
568 (ace->who.special_id == SMB_ACE4_WHO_OWNER ||
569 ace->who.special_id == SMB_ACE4_WHO_GROUP)) {
570 DEBUG(10, ("Map special entry\n"));
571 if (!(win_ace_flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
572 uint32_t win_ace_flags_current;
573 DEBUG(10, ("Map current sid\n"));
574 win_ace_flags_current = win_ace_flags &
575 ~(SEC_ACE_FLAG_OBJECT_INHERIT |
576 SEC_ACE_FLAG_CONTAINER_INHERIT);
577 init_sec_ace(&nt_ace_list[good_aces++], &sid,
578 ace->aceType, mask,
579 win_ace_flags_current);
581 if (ace->who.special_id == SMB_ACE4_WHO_OWNER &&
582 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
583 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
584 uint32_t win_ace_flags_creator;
585 DEBUG(10, ("Map creator owner\n"));
586 win_ace_flags_creator = win_ace_flags |
587 SMB_ACE4_INHERIT_ONLY_ACE;
588 init_sec_ace(&nt_ace_list[good_aces++],
589 &global_sid_Creator_Owner,
590 ace->aceType, mask,
591 win_ace_flags_creator);
593 if (ace->who.special_id == SMB_ACE4_WHO_GROUP &&
594 win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT |
595 SEC_ACE_FLAG_CONTAINER_INHERIT)) {
596 uint32_t win_ace_flags_creator;
597 DEBUG(10, ("Map creator owner group\n"));
598 win_ace_flags_creator = win_ace_flags |
599 SMB_ACE4_INHERIT_ONLY_ACE;
600 init_sec_ace(&nt_ace_list[good_aces++],
601 &global_sid_Creator_Group,
602 ace->aceType, mask,
603 win_ace_flags_creator);
605 } else {
606 DEBUG(10, ("Map normal sid\n"));
607 init_sec_ace(&nt_ace_list[good_aces++], &sid,
608 ace->aceType, mask,
609 win_ace_flags);
612 check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
615 nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
616 good_aces);
618 /* returns a NULL ace list when good_aces is zero. */
619 if (good_aces && nt_ace_list == NULL) {
620 DEBUG(10, ("realloc error with %d aces\n", good_aces));
621 errno = ENOMEM;
622 return false;
625 *ppnt_ace_list = nt_ace_list;
626 *pgood_aces = good_aces;
628 return true;
631 static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
632 const struct smbacl4_vfs_params *params,
633 uint32_t security_info,
634 TALLOC_CTX *mem_ctx,
635 struct security_descriptor **ppdesc,
636 struct SMB4ACL_T *theacl)
638 int good_aces = 0;
639 struct dom_sid sid_owner, sid_group;
640 size_t sd_size = 0;
641 struct security_ace *nt_ace_list = NULL;
642 struct security_acl *psa = NULL;
643 TALLOC_CTX *frame = talloc_stackframe();
644 bool ok;
646 if (theacl==NULL) {
647 TALLOC_FREE(frame);
648 return NT_STATUS_ACCESS_DENIED; /* special because we
649 * need to think through
650 * the null case.*/
653 uid_to_sid(&sid_owner, sbuf->st_ex_uid);
654 gid_to_sid(&sid_group, sbuf->st_ex_gid);
656 ok = smbacl4_nfs42win(frame, params, theacl, &sid_owner, &sid_group,
657 S_ISDIR(sbuf->st_ex_mode),
658 &nt_ace_list, &good_aces);
659 if (!ok) {
660 DEBUG(8,("smbacl4_nfs42win failed\n"));
661 TALLOC_FREE(frame);
662 return map_nt_error_from_unix(errno);
665 psa = make_sec_acl(frame, NT4_ACL_REVISION, good_aces, nt_ace_list);
666 if (psa == NULL) {
667 DEBUG(2,("make_sec_acl failed\n"));
668 TALLOC_FREE(frame);
669 return NT_STATUS_NO_MEMORY;
672 DEBUG(10,("after make sec_acl\n"));
673 *ppdesc = make_sec_desc(
674 mem_ctx, SD_REVISION, smbacl4_get_controlflags(theacl),
675 (security_info & SECINFO_OWNER) ? &sid_owner : NULL,
676 (security_info & SECINFO_GROUP) ? &sid_group : NULL,
677 NULL, psa, &sd_size);
678 if (*ppdesc==NULL) {
679 DEBUG(2,("make_sec_desc failed\n"));
680 TALLOC_FREE(frame);
681 return NT_STATUS_NO_MEMORY;
684 DEBUG(10, ("smb_get_nt_acl_nfs4_common successfully exited with "
685 "sd_size %d\n",
686 (int)ndr_size_security_descriptor(*ppdesc, 0)));
688 TALLOC_FREE(frame);
689 return NT_STATUS_OK;
692 NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
693 const struct smbacl4_vfs_params *pparams,
694 uint32_t security_info,
695 TALLOC_CTX *mem_ctx,
696 struct security_descriptor **ppdesc,
697 struct SMB4ACL_T *theacl)
699 struct smbacl4_vfs_params params;
701 DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
703 if (!VALID_STAT(fsp->fsp_name->st)) {
704 NTSTATUS status;
706 status = vfs_stat_fsp(fsp);
707 if (!NT_STATUS_IS_OK(status)) {
708 return status;
712 if (pparams == NULL) {
713 /* Special behaviours */
714 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
715 return NT_STATUS_NO_MEMORY;
717 pparams = &params;
720 return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
721 security_info,
722 mem_ctx, ppdesc, theacl);
725 NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
726 const struct smb_filename *smb_fname,
727 const struct smbacl4_vfs_params *pparams,
728 uint32_t security_info,
729 TALLOC_CTX *mem_ctx,
730 struct security_descriptor **ppdesc,
731 struct SMB4ACL_T *theacl)
733 SMB_STRUCT_STAT sbuf;
734 struct smbacl4_vfs_params params;
735 const SMB_STRUCT_STAT *psbuf = NULL;
737 DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
738 smb_fname->base_name));
740 if (VALID_STAT(smb_fname->st)) {
741 psbuf = &smb_fname->st;
744 if (psbuf == NULL) {
745 if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
746 return map_nt_error_from_unix(errno);
748 psbuf = &sbuf;
751 if (pparams == NULL) {
752 /* Special behaviours */
753 if (smbacl4_get_vfs_params(conn, &params)) {
754 return NT_STATUS_NO_MEMORY;
756 pparams = &params;
759 return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
760 mem_ctx, ppdesc, theacl);
763 static void smbacl4_dump_nfs4acl(int level, struct SMB4ACL_T *acl)
765 struct SMB4ACE_T *aceint;
767 DEBUG(level, ("NFS4ACL: size=%d\n", acl->naces));
769 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
770 SMB_ACE4PROP_T *ace = &aceint->prop;
772 DEBUG(level, ("\tACE: type=%d, flags=0x%x, fflags=0x%x, "
773 "mask=0x%x, id=%d\n",
774 ace->aceType,
775 ace->aceFlags, ace->flags,
776 ace->aceMask,
777 ace->who.id));
782 * Find 2 NFS4 who-special ACE property (non-copy!!!)
783 * match nonzero if "special" and who is equal
784 * return ace if found matching; otherwise NULL
786 static SMB_ACE4PROP_T *smbacl4_find_equal_special(
787 struct SMB4ACL_T *acl,
788 SMB_ACE4PROP_T *aceNew)
790 struct SMB4ACE_T *aceint;
792 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
793 SMB_ACE4PROP_T *ace = &aceint->prop;
795 DEBUG(10,("ace type:0x%x flags:0x%x aceFlags:0x%x "
796 "new type:0x%x flags:0x%x aceFlags:0x%x\n",
797 ace->aceType, ace->flags, ace->aceFlags,
798 aceNew->aceType, aceNew->flags,aceNew->aceFlags));
800 if (ace->flags == aceNew->flags &&
801 ace->aceType==aceNew->aceType &&
802 ace->aceFlags==aceNew->aceFlags)
804 /* keep type safety; e.g. gid is an u.short */
805 if (ace->flags & SMB_ACE4_ID_SPECIAL)
807 if (ace->who.special_id ==
808 aceNew->who.special_id)
809 return ace;
810 } else {
811 if (ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP)
813 if (ace->who.gid==aceNew->who.gid)
814 return ace;
815 } else {
816 if (ace->who.uid==aceNew->who.uid)
817 return ace;
823 return NULL;
826 static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
827 struct SMB4ACL_T *theacl,
828 SMB_ACE4PROP_T *ace,
829 bool *paddNewACE)
831 int result = 0;
832 SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
833 if (ace4found)
835 switch(acedup)
837 case e_merge: /* "merge" flags */
838 *paddNewACE = false;
839 ace4found->aceFlags |= ace->aceFlags;
840 ace4found->aceMask |= ace->aceMask;
841 break;
842 case e_ignore: /* leave out this record */
843 *paddNewACE = false;
844 break;
845 case e_reject: /* do an error */
846 DBG_INFO("ACL rejected by duplicate nt ace.\n");
847 errno = EINVAL; /* SHOULD be set on any _real_ error */
848 result = -1;
849 break;
850 default:
851 break;
854 return result;
857 static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
858 struct SMB4ACL_T *nfs4_acl,
859 SMB_ACE4PROP_T *nfs4_ace)
861 bool add_ace = true;
863 if (acedup != e_dontcare) {
864 int ret;
866 ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
867 nfs4_ace, &add_ace);
868 if (ret == -1) {
869 return -1;
873 if (add_ace) {
874 smb_add_ace4(nfs4_acl, nfs4_ace);
877 return 0;
880 static int nfs4_acl_add_sec_ace(bool is_directory,
881 const struct smbacl4_vfs_params *params,
882 uid_t ownerUID,
883 gid_t ownerGID,
884 const struct security_ace *ace_nt,
885 struct SMB4ACL_T *nfs4_acl)
887 struct dom_sid_buf buf;
888 SMB_ACE4PROP_T nfs4_ace = { 0 };
889 SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
890 bool add_ace2 = false;
891 int ret;
893 DEBUG(10, ("got ace for %s\n",
894 dom_sid_str_buf(&ace_nt->trustee, &buf)));
896 /* only ACCESS|DENY supported right now */
897 nfs4_ace.aceType = ace_nt->type;
899 nfs4_ace.aceFlags =
900 map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
902 /* remove inheritance flags on files */
903 if (!is_directory) {
904 DEBUG(10, ("Removing inheritance flags from a file\n"));
905 nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
906 SMB_ACE4_DIRECTORY_INHERIT_ACE|
907 SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
908 SMB_ACE4_INHERIT_ONLY_ACE);
911 nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
913 se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
915 if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
916 nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
917 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
918 } else if (params->mode!=e_special &&
919 dom_sid_equal(&ace_nt->trustee,
920 &global_sid_Creator_Owner)) {
921 DEBUG(10, ("Map creator owner\n"));
922 nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
923 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
924 /* A non inheriting creator owner entry has no effect. */
925 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
926 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
927 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
928 return 0;
930 } else if (params->mode!=e_special &&
931 dom_sid_equal(&ace_nt->trustee,
932 &global_sid_Creator_Group)) {
933 DEBUG(10, ("Map creator owner group\n"));
934 nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
935 nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
936 /* A non inheriting creator group entry has no effect. */
937 nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
938 if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
939 && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
940 return 0;
942 } else {
943 struct unixid unixid;
944 bool ok;
946 ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
947 if (!ok) {
948 DBG_WARNING("Could not convert %s to uid or gid.\n",
949 dom_sid_str_buf(&ace_nt->trustee, &buf));
950 return 0;
953 if (dom_sid_compare_domain(&ace_nt->trustee,
954 &global_sid_Unix_NFS) == 0) {
955 return 0;
958 switch (unixid.type) {
959 case ID_TYPE_BOTH:
960 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
961 nfs4_ace.who.gid = unixid.id;
963 if (ownerUID == unixid.id &&
964 !nfs_ace_is_inherit(&nfs4_ace))
967 * IDMAP_TYPE_BOTH for owner. Add
968 * additional user entry, which can be
969 * mapped to special:owner to reflect
970 * the permissions in the modebits.
972 * This only applies to non-inheriting
973 * entries as only these are replaced
974 * with SPECIAL_OWNER in nfs4:mode=simple.
976 nfs4_ace_2 = (SMB_ACE4PROP_T) {
977 .who.uid = unixid.id,
978 .aceFlags = (nfs4_ace.aceFlags &
979 ~SMB_ACE4_IDENTIFIER_GROUP),
980 .aceMask = nfs4_ace.aceMask,
981 .aceType = nfs4_ace.aceType,
983 add_ace2 = true;
985 break;
986 case ID_TYPE_GID:
987 nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
988 nfs4_ace.who.gid = unixid.id;
989 break;
990 case ID_TYPE_UID:
991 nfs4_ace.who.uid = unixid.id;
992 break;
993 case ID_TYPE_NOT_SPECIFIED:
994 default:
995 DBG_WARNING("Could not convert %s to uid or gid.\n",
996 dom_sid_str_buf(&ace_nt->trustee, &buf));
997 return 0;
1001 ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
1002 if (ret != 0) {
1003 return -1;
1006 if (!add_ace2) {
1007 return 0;
1010 return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
1013 static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
1014 uid_t ownerUID,
1015 gid_t ownerGID)
1017 struct SMB4ACE_T *aceint;
1019 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
1020 SMB_ACE4PROP_T *ace = &aceint->prop;
1022 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1023 "mask: %x, who: %d\n",
1024 ace->aceType, ace->flags, ace->aceFlags,
1025 ace->aceMask, ace->who.id));
1027 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1028 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1029 ace->who.uid == ownerUID) {
1030 ace->flags |= SMB_ACE4_ID_SPECIAL;
1031 ace->who.special_id = SMB_ACE4_WHO_OWNER;
1032 DEBUG(10,("replaced with special owner ace\n"));
1035 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1036 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1037 ace->who.uid == ownerGID) {
1038 ace->flags |= SMB_ACE4_ID_SPECIAL;
1039 ace->who.special_id = SMB_ACE4_WHO_GROUP;
1040 DEBUG(10,("replaced with special group ace\n"));
1045 static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
1046 uid_t ownerUID,
1047 gid_t ownerGID)
1049 struct SMB4ACE_T *aceint;
1051 for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
1052 SMB_ACE4PROP_T *ace = &aceint->prop;
1054 DEBUG(10,("ace type: %d, iflags: %x, flags: %x, "
1055 "mask: %x, who: %d\n",
1056 ace->aceType, ace->flags, ace->aceFlags,
1057 ace->aceMask, ace->who.id));
1059 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1060 !(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
1061 ace->who.uid == ownerUID &&
1062 !nfs_ace_is_inherit(ace)) {
1063 ace->flags |= SMB_ACE4_ID_SPECIAL;
1064 ace->who.special_id = SMB_ACE4_WHO_OWNER;
1065 DEBUG(10,("replaced with special owner ace\n"));
1068 if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
1069 ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
1070 ace->who.gid == ownerGID &&
1071 !nfs_ace_is_inherit(ace)) {
1072 ace->flags |= SMB_ACE4_ID_SPECIAL;
1073 ace->who.special_id = SMB_ACE4_WHO_GROUP;
1074 DEBUG(10,("replaced with special group ace\n"));
1079 static struct SMB4ACL_T *smbacl4_win2nfs4(
1080 TALLOC_CTX *mem_ctx,
1081 bool is_directory,
1082 const struct security_acl *dacl,
1083 const struct smbacl4_vfs_params *pparams,
1084 uid_t ownerUID,
1085 gid_t ownerGID
1088 struct SMB4ACL_T *theacl;
1089 uint32_t i;
1091 DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
1093 theacl = smb_create_smb4acl(mem_ctx);
1094 if (theacl==NULL)
1095 return NULL;
1097 for(i=0; i<dacl->num_aces; i++) {
1098 int ret;
1100 ret = nfs4_acl_add_sec_ace(is_directory, pparams,
1101 ownerUID, ownerGID,
1102 dacl->aces + i, theacl);
1103 if (ret == -1) {
1104 return NULL;
1108 if (pparams->mode==e_simple) {
1109 smbacl4_substitute_simple(theacl, ownerUID, ownerGID);
1112 if (pparams->mode==e_special) {
1113 smbacl4_substitute_special(theacl, ownerUID, ownerGID);
1116 return theacl;
1119 NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
1120 const struct smbacl4_vfs_params *pparams,
1121 uint32_t security_info_sent,
1122 const struct security_descriptor *psd,
1123 set_nfs4acl_native_fn_t set_nfs4_native)
1125 struct smbacl4_vfs_params params;
1126 struct SMB4ACL_T *theacl = NULL;
1127 bool result, is_directory;
1129 bool set_acl_as_root = false;
1130 int saved_errno;
1131 NTSTATUS status;
1132 TALLOC_CTX *frame = talloc_stackframe();
1134 DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
1136 if ((security_info_sent & (SECINFO_DACL |
1137 SECINFO_GROUP | SECINFO_OWNER)) == 0)
1139 DEBUG(9, ("security_info_sent (0x%x) ignored\n",
1140 security_info_sent));
1141 TALLOC_FREE(frame);
1142 return NT_STATUS_OK; /* won't show error - later to be
1143 * refined... */
1146 if (security_descriptor_with_ms_nfs(psd)) {
1147 TALLOC_FREE(frame);
1148 return NT_STATUS_OK;
1151 if (pparams == NULL) {
1152 /* Special behaviours */
1153 if (smbacl4_get_vfs_params(fsp->conn, &params)) {
1154 TALLOC_FREE(frame);
1155 return NT_STATUS_NO_MEMORY;
1157 pparams = &params;
1160 status = vfs_stat_fsp(fsp);
1161 if (!NT_STATUS_IS_OK(status)) {
1162 TALLOC_FREE(frame);
1163 return status;
1166 is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
1168 if (pparams->do_chown) {
1170 * When the chown succeeds, the special entries in the
1171 * file system ACL refer to the new owner. In order to
1172 * apply the complete information from the DACL,
1173 * setting the ACL then has to succeed. Track this
1174 * case with set_acl_as_root and set the ACL as root
1175 * accordingly.
1177 status = chown_if_needed(fsp, security_info_sent, psd,
1178 &set_acl_as_root);
1179 if (!NT_STATUS_IS_OK(status)) {
1180 TALLOC_FREE(frame);
1181 return status;
1185 if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
1186 DEBUG(10, ("no dacl found; security_info_sent = 0x%x\n",
1187 security_info_sent));
1188 TALLOC_FREE(frame);
1189 return NT_STATUS_OK;
1192 theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
1193 fsp->fsp_name->st.st_ex_uid,
1194 fsp->fsp_name->st.st_ex_gid);
1195 if (!theacl) {
1196 TALLOC_FREE(frame);
1197 return map_nt_error_from_unix(errno);
1200 smbacl4_set_controlflags(theacl, psd->type);
1201 smbacl4_dump_nfs4acl(10, theacl);
1203 if (set_acl_as_root) {
1204 become_root();
1206 result = set_nfs4_native(handle, fsp, theacl);
1207 saved_errno = errno;
1208 if (set_acl_as_root) {
1209 unbecome_root();
1212 TALLOC_FREE(frame);
1214 if (result!=true) {
1215 errno = saved_errno;
1216 DEBUG(10, ("set_nfs4_native failed with %s\n",
1217 strerror(errno)));
1218 return map_nt_error_from_unix(errno);
1221 DEBUG(10, ("smb_set_nt_acl_nfs4 succeeded\n"));
1222 return NT_STATUS_OK;