* NFS4 ACL handling
*
* Copyright (C) Jim McDonough, 2006
+ * Copyright (C) Christof Schmitt 2019
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
#include "smbd/smbd.h"
#include "nfs4_acls.h"
#include "librpc/gen_ndr/ndr_security.h"
+#include "librpc/gen_ndr/idmap.h"
#include "../libcli/security/dom_sid.h"
#include "../libcli/security/security.h"
#include "dbwrap/dbwrap.h"
struct SMB4ACE_T *last;
};
-enum smbacl4_mode_enum {e_simple=0, e_special=1};
-enum smbacl4_acedup_enum {e_dontcare=0, e_reject=1, e_ignore=2, e_merge=3};
-
-typedef struct _smbacl4_vfs_params {
- enum smbacl4_mode_enum mode;
- bool do_chown;
- enum smbacl4_acedup_enum acedup;
- bool map_full_control;
-} smbacl4_vfs_params;
-
/*
* Gather special parameters for NFS4 ACL handling
*/
-static int smbacl4_get_vfs_params(
- struct connection_struct *conn,
- smbacl4_vfs_params *params
-)
+int smbacl4_get_vfs_params(struct connection_struct *conn,
+ struct smbacl4_vfs_params *params)
{
static const struct enum_list enum_smbacl4_modes[] = {
{ e_simple, "simple" },
};
int enumval;
- ZERO_STRUCTP(params);
+ *params = (struct smbacl4_vfs_params) { 0 };
enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "mode",
enum_smbacl4_modes, e_simple);
return -1;
}
params->mode = (enum smbacl4_mode_enum)enumval;
+ if (params->mode == e_special) {
+ DBG_WARNING("nfs4:mode special is deprecated.\n");
+ }
params->do_chown = lp_parm_bool(SNUM(conn), SMBACL4_PARAM_TYPE_NAME,
"chown", true);
enumval = lp_parm_enum(SNUM(conn), SMBACL4_PARAM_TYPE_NAME, "acedup",
- enum_smbacl4_acedups, e_dontcare);
+ enum_smbacl4_acedups, e_merge);
if (enumval == -1) {
DEBUG(10, ("value for %s:acedup unknown\n",
SMBACL4_PARAM_TYPE_NAME));
return -1;
}
params->acedup = (enum smbacl4_acedup_enum)enumval;
+ if (params->acedup == e_ignore) {
+ DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
+ }
+ if (params->acedup == e_reject) {
+ DBG_WARNING("nfs4:acedup ignore is deprecated.\n");
+ }
params->map_full_control = lp_acl_map_full_control(SNUM(conn));
return 0;
}
+static int fstatat_with_cap_dac_override(int fd,
+ const char *pathname,
+ SMB_STRUCT_STAT *sbuf,
+ int flags,
+ bool fake_dir_create_times)
+{
+ int ret;
+
+ set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+ ret = sys_fstatat(fd,
+ pathname,
+ sbuf,
+ flags,
+ fake_dir_create_times);
+ drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+ return ret;
+}
+
+static int stat_with_cap_dac_override(struct vfs_handle_struct *handle,
+ struct smb_filename *smb_fname, int flag)
+{
+ bool fake_dctime = lp_fake_directory_create_times(SNUM(handle->conn));
+ int fd = -1;
+ NTSTATUS status;
+ struct smb_filename *dir_name = NULL;
+ struct smb_filename *rel_name = NULL;
+ int ret = -1;
+#ifdef O_PATH
+ int open_flags = O_PATH;
+#else
+ int open_flags = O_RDONLY;
+#endif
+
+ status = SMB_VFS_PARENT_PATHNAME(handle->conn,
+ talloc_tos(),
+ smb_fname,
+ &dir_name,
+ &rel_name);
+ if (!NT_STATUS_IS_OK(status)) {
+ errno = map_errno_from_nt_status(status);
+ return -1;
+ }
+
+ fd = open(dir_name->base_name, open_flags, 0);
+ if (fd == -1) {
+ TALLOC_FREE(dir_name);
+ return -1;
+ }
+
+ ret = fstatat_with_cap_dac_override(fd,
+ rel_name->base_name,
+ &smb_fname->st,
+ flag,
+ fake_dctime);
+
+ TALLOC_FREE(dir_name);
+ close(fd);
+
+ return ret;
+}
+
+int nfs4_acl_stat(struct vfs_handle_struct *handle,
+ struct smb_filename *smb_fname)
+{
+ int ret;
+
+ ret = SMB_VFS_NEXT_STAT(handle, smb_fname);
+ if (ret == -1 && errno == EACCES) {
+ DEBUG(10, ("Trying stat with capability for %s\n",
+ smb_fname->base_name));
+ ret = stat_with_cap_dac_override(handle, smb_fname, 0);
+ }
+ return ret;
+}
+
+static int fstat_with_cap_dac_override(int fd, SMB_STRUCT_STAT *sbuf,
+ bool fake_dir_create_times)
+{
+ int ret;
+
+ set_effective_capability(DAC_OVERRIDE_CAPABILITY);
+ ret = sys_fstat(fd, sbuf, fake_dir_create_times);
+ drop_effective_capability(DAC_OVERRIDE_CAPABILITY);
+
+ return ret;
+}
+
+int nfs4_acl_fstat(struct vfs_handle_struct *handle,
+ struct files_struct *fsp,
+ SMB_STRUCT_STAT *sbuf)
+{
+ int ret;
+
+ ret = SMB_VFS_NEXT_FSTAT(handle, fsp, sbuf);
+ if (ret == -1 && errno == EACCES) {
+ bool fake_dctime =
+ lp_fake_directory_create_times(SNUM(handle->conn));
+
+ DBG_DEBUG("fstat for %s failed with EACCES. Trying with "
+ "CAP_DAC_OVERRIDE.\n", fsp->fsp_name->base_name);
+ ret = fstat_with_cap_dac_override(fsp_get_pathref_fd(fsp),
+ sbuf,
+ fake_dctime);
+ }
+
+ return ret;
+}
+
+int nfs4_acl_lstat(struct vfs_handle_struct *handle,
+ struct smb_filename *smb_fname)
+{
+ int ret;
+
+ ret = SMB_VFS_NEXT_LSTAT(handle, smb_fname);
+ if (ret == -1 && errno == EACCES) {
+ DEBUG(10, ("Trying lstat with capability for %s\n",
+ smb_fname->base_name));
+ ret = stat_with_cap_dac_override(handle, smb_fname,
+ AT_SYMLINK_NOFOLLOW);
+ }
+ return ret;
+}
+
+int nfs4_acl_fstatat(struct vfs_handle_struct *handle,
+ const struct files_struct *dirfsp,
+ const struct smb_filename *smb_fname,
+ SMB_STRUCT_STAT *sbuf,
+ int flags)
+{
+ int ret;
+
+ ret = SMB_VFS_NEXT_FSTATAT(handle, dirfsp, smb_fname, sbuf, flags);
+ if (ret == -1 && errno == EACCES) {
+ bool fake_dctime =
+ lp_fake_directory_create_times(SNUM(handle->conn));
+
+ DBG_DEBUG("fstatat for %s failed with EACCES. Trying with "
+ "CAP_DAC_OVERRIDE.\n", dirfsp->fsp_name->base_name);
+ ret = fstatat_with_cap_dac_override(fsp_get_pathref_fd(dirfsp),
+ smb_fname->base_name,
+ sbuf,
+ flags,
+ fake_dctime);
+ }
+
+ return ret;
+}
+
/************************************************
Split the ACE flag mapping between nfs4 and Windows
into two separate functions rather than trying to do
ace = talloc_zero(acl, struct SMB4ACE_T);
if (ace==NULL)
{
- DEBUG(0, ("TALLOC_SIZE failed\n"));
+ DBG_ERR("talloc_zero failed\n");
errno = ENOMEM;
return NULL;
}
- /* ace->next = NULL not needed */
- memcpy(&ace->prop, prop, sizeof(SMB_ACE4PROP_T));
+ ace->prop = *prop;
if (acl->first==NULL)
{
return true;
}
+bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
+{
+ return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
+ SMB_ACE4_FILE_INHERIT_ACE|
+ SMB_ACE4_DIRECTORY_INHERIT_ACE);
+}
+
static int smbacl4_GetFileOwner(struct connection_struct *conn,
const struct smb_filename *smb_fname,
SMB_STRUCT_STAT *psbuf)
ZERO_STRUCTP(psbuf);
/* Get the stat struct for the owner info. */
- if (vfs_stat_smb_basename(conn, smb_fname->base_name, psbuf) != 0)
+ if (vfs_stat_smb_basename(conn, smb_fname, psbuf) != 0)
{
DEBUG(8, ("vfs_stat_smb_basename failed with error %s\n",
strerror(errno)));
return 0;
}
-static int smbacl4_fGetFileOwner(files_struct *fsp, SMB_STRUCT_STAT *psbuf)
+static void check_for_duplicate_sec_ace(struct security_ace *nt_ace_list,
+ int *good_aces)
{
- ZERO_STRUCTP(psbuf);
+ struct security_ace *last = NULL;
+ int i;
- if (fsp->fh->fd == -1) {
- return smbacl4_GetFileOwner(fsp->conn,
- fsp->fsp_name, psbuf);
- }
- if (SMB_VFS_FSTAT(fsp, psbuf) != 0)
- {
- DEBUG(8, ("SMB_VFS_FSTAT failed with error %s\n",
- strerror(errno)));
- return -1;
+ if (*good_aces < 2) {
+ return;
}
- return 0;
+ last = &nt_ace_list[(*good_aces) - 1];
+
+ for (i = 0; i < (*good_aces) - 1; i++) {
+ struct security_ace *cur = &nt_ace_list[i];
+
+ if (cur->type == last->type &&
+ cur->flags == last->flags &&
+ cur->access_mask == last->access_mask &&
+ dom_sid_equal(&cur->trustee, &last->trustee))
+ {
+ struct dom_sid_buf sid_buf;
+
+ DBG_INFO("Removing duplicate entry for SID %s.\n",
+ dom_sid_str_buf(&last->trustee, &sid_buf));
+ (*good_aces)--;
+ }
+ }
}
static bool smbacl4_nfs42win(TALLOC_CTX *mem_ctx,
- smbacl4_vfs_params *params,
+ const struct smbacl4_vfs_params *params,
struct SMB4ACL_T *acl, /* in */
struct dom_sid *psid_owner, /* in */
struct dom_sid *psid_group, /* in */
2 * acl->naces);
if (nt_ace_list==NULL)
{
- DEBUG(10, ("talloc error with %d aces", acl->naces));
+ DEBUG(10, ("talloc error with %d aces\n", acl->naces));
errno = ENOMEM;
return false;
}
for (aceint = acl->first; aceint != NULL; aceint = aceint->next) {
uint32_t mask;
struct dom_sid sid;
+ struct dom_sid_buf buf;
SMB_ACE4PROP_T *ace = &aceint->prop;
uint32_t win_ace_flags;
}
}
DEBUG(10, ("mapped %d to %s\n", ace->who.id,
- sid_string_dbg(&sid)));
-
- if (is_directory && (ace->aceMask & SMB_ACE4_ADD_FILE)) {
- ace->aceMask |= SMB_ACE4_DELETE_CHILD;
- }
+ dom_sid_str_buf(&sid, &buf)));
if (!is_directory && params->map_full_control) {
/*
(win_ace_flags & (SEC_ACE_FLAG_OBJECT_INHERIT|
SEC_ACE_FLAG_CONTAINER_INHERIT))) {
/*
- * GPFS sets inherits dir_inhert and file_inherit flags
+ * GPFS sets inherits dir_inherit and file_inherit flags
* to files, too, which confuses windows, and seems to
* be wrong anyways. ==> Map these bits away for files.
*/
ace->aceFlags, win_ace_flags));
mask = ace->aceMask;
- /* Windows clients expect SYNC on acls to
- correctly allow rename. See bug #7909. */
- /* But not on DENY ace entries. See
- bug #8442. */
- if(ace->aceType == SMB_ACE4_ACCESS_ALLOWED_ACE_TYPE) {
- mask = ace->aceMask | SMB_ACE4_SYNCHRONIZE;
- }
/* Mapping of owner@ and group@ to creator owner and
creator group. Keep old behavior in mode special. */
ace->aceType, mask,
win_ace_flags);
}
+
+ check_for_duplicate_sec_ace(nt_ace_list, &good_aces);
}
nt_ace_list = talloc_realloc(mem_ctx, nt_ace_list, struct security_ace,
/* returns a NULL ace list when good_aces is zero. */
if (good_aces && nt_ace_list == NULL) {
- DEBUG(10, ("realloc error with %d aces", good_aces));
+ DEBUG(10, ("realloc error with %d aces\n", good_aces));
errno = ENOMEM;
return false;
}
}
static NTSTATUS smb_get_nt_acl_nfs4_common(const SMB_STRUCT_STAT *sbuf,
- smbacl4_vfs_params *params,
+ const struct smbacl4_vfs_params *params,
uint32_t security_info,
TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc,
}
NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
+ const struct smbacl4_vfs_params *pparams,
uint32_t security_info,
TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc,
struct SMB4ACL_T *theacl)
{
- SMB_STRUCT_STAT sbuf;
- smbacl4_vfs_params params;
+ struct smbacl4_vfs_params params;
DEBUG(10, ("smb_fget_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
- if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
- return map_nt_error_from_unix(errno);
+ if (!VALID_STAT(fsp->fsp_name->st)) {
+ NTSTATUS status;
+
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
+ return status;
+ }
}
- /* Special behaviours */
- if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
- return NT_STATUS_NO_MEMORY;
+ if (pparams == NULL) {
+ /* Special behaviours */
+ if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pparams = ¶ms;
}
- return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
+ return smb_get_nt_acl_nfs4_common(&fsp->fsp_name->st, pparams,
+ security_info,
mem_ctx, ppdesc, theacl);
}
NTSTATUS smb_get_nt_acl_nfs4(struct connection_struct *conn,
const struct smb_filename *smb_fname,
+ const struct smbacl4_vfs_params *pparams,
uint32_t security_info,
TALLOC_CTX *mem_ctx,
struct security_descriptor **ppdesc,
struct SMB4ACL_T *theacl)
{
SMB_STRUCT_STAT sbuf;
- smbacl4_vfs_params params;
+ struct smbacl4_vfs_params params;
+ const SMB_STRUCT_STAT *psbuf = NULL;
DEBUG(10, ("smb_get_nt_acl_nfs4 invoked for %s\n",
smb_fname->base_name));
- if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
- return map_nt_error_from_unix(errno);
+ if (VALID_STAT(smb_fname->st)) {
+ psbuf = &smb_fname->st;
}
- /* Special behaviours */
- if (smbacl4_get_vfs_params(conn, ¶ms)) {
- return NT_STATUS_NO_MEMORY;
+ if (psbuf == NULL) {
+ if (smbacl4_GetFileOwner(conn, smb_fname, &sbuf)) {
+ return map_nt_error_from_unix(errno);
+ }
+ psbuf = &sbuf;
+ }
+
+ if (pparams == NULL) {
+ /* Special behaviours */
+ if (smbacl4_get_vfs_params(conn, ¶ms)) {
+ return NT_STATUS_NO_MEMORY;
+ }
+ pparams = ¶ms;
}
- return smb_get_nt_acl_nfs4_common(&sbuf, ¶ms, security_info,
+ return smb_get_nt_acl_nfs4_common(psbuf, pparams, security_info,
mem_ctx, ppdesc, theacl);
}
return NULL;
}
+static int smbacl4_MergeIgnoreReject(enum smbacl4_acedup_enum acedup,
+ struct SMB4ACL_T *theacl,
+ SMB_ACE4PROP_T *ace,
+ bool *paddNewACE)
+{
+ int result = 0;
+ SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
+ if (ace4found)
+ {
+ switch(acedup)
+ {
+ case e_merge: /* "merge" flags */
+ *paddNewACE = false;
+ ace4found->aceFlags |= ace->aceFlags;
+ ace4found->aceMask |= ace->aceMask;
+ break;
+ case e_ignore: /* leave out this record */
+ *paddNewACE = false;
+ break;
+ case e_reject: /* do an error */
+ DBG_INFO("ACL rejected by duplicate nt ace.\n");
+ errno = EINVAL; /* SHOULD be set on any _real_ error */
+ result = -1;
+ break;
+ default:
+ break;
+ }
+ }
+ return result;
+}
+
+static int nfs4_acl_add_ace(enum smbacl4_acedup_enum acedup,
+ struct SMB4ACL_T *nfs4_acl,
+ SMB_ACE4PROP_T *nfs4_ace)
+{
+ bool add_ace = true;
-static bool smbacl4_fill_ace4(
- const struct smb_filename *filename,
- smbacl4_vfs_params *params,
- uid_t ownerUID,
- gid_t ownerGID,
- const struct security_ace *ace_nt, /* input */
- SMB_ACE4PROP_T *ace_v4 /* output */
-)
+ if (acedup != e_dontcare) {
+ int ret;
+
+ ret = smbacl4_MergeIgnoreReject(acedup, nfs4_acl,
+ nfs4_ace, &add_ace);
+ if (ret == -1) {
+ return -1;
+ }
+ }
+
+ if (add_ace) {
+ smb_add_ace4(nfs4_acl, nfs4_ace);
+ }
+
+ return 0;
+}
+
+static int nfs4_acl_add_sec_ace(bool is_directory,
+ const struct smbacl4_vfs_params *params,
+ uid_t ownerUID,
+ gid_t ownerGID,
+ const struct security_ace *ace_nt,
+ struct SMB4ACL_T *nfs4_acl)
{
- DEBUG(10, ("got ace for %s\n", sid_string_dbg(&ace_nt->trustee)));
+ struct dom_sid_buf buf;
+ SMB_ACE4PROP_T nfs4_ace = { 0 };
+ SMB_ACE4PROP_T nfs4_ace_2 = { 0 };
+ bool add_ace2 = false;
+ int ret;
- ZERO_STRUCTP(ace_v4);
+ DEBUG(10, ("got ace for %s\n",
+ dom_sid_str_buf(&ace_nt->trustee, &buf)));
/* only ACCESS|DENY supported right now */
- ace_v4->aceType = ace_nt->type;
+ nfs4_ace.aceType = ace_nt->type;
- ace_v4->aceFlags = map_windows_ace_flags_to_nfs4_ace_flags(
- ace_nt->flags);
+ nfs4_ace.aceFlags =
+ map_windows_ace_flags_to_nfs4_ace_flags(ace_nt->flags);
/* remove inheritance flags on files */
- if (VALID_STAT(filename->st) &&
- !S_ISDIR(filename->st.st_ex_mode)) {
+ if (!is_directory) {
DEBUG(10, ("Removing inheritance flags from a file\n"));
- ace_v4->aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
- SMB_ACE4_DIRECTORY_INHERIT_ACE|
- SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
- SMB_ACE4_INHERIT_ONLY_ACE);
+ nfs4_ace.aceFlags &= ~(SMB_ACE4_FILE_INHERIT_ACE|
+ SMB_ACE4_DIRECTORY_INHERIT_ACE|
+ SMB_ACE4_NO_PROPAGATE_INHERIT_ACE|
+ SMB_ACE4_INHERIT_ONLY_ACE);
}
- ace_v4->aceMask = ace_nt->access_mask &
- (SEC_STD_ALL | SEC_FILE_ALL);
-
- se_map_generic(&ace_v4->aceMask, &file_generic_mapping);
+ nfs4_ace.aceMask = ace_nt->access_mask & (SEC_STD_ALL | SEC_FILE_ALL);
- if (ace_v4->aceFlags!=ace_nt->flags)
- DEBUG(9, ("ace_v4->aceFlags(0x%x)!=ace_nt->flags(0x%x)\n",
- ace_v4->aceFlags, ace_nt->flags));
-
- if (ace_v4->aceMask!=ace_nt->access_mask)
- DEBUG(9, ("ace_v4->aceMask(0x%x)!=ace_nt->access_mask(0x%x)\n",
- ace_v4->aceMask, ace_nt->access_mask));
+ se_map_generic(&nfs4_ace.aceMask, &file_generic_mapping);
if (dom_sid_equal(&ace_nt->trustee, &global_sid_World)) {
- ace_v4->who.special_id = SMB_ACE4_WHO_EVERYONE;
- ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ nfs4_ace.who.special_id = SMB_ACE4_WHO_EVERYONE;
+ nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
} else if (params->mode!=e_special &&
dom_sid_equal(&ace_nt->trustee,
&global_sid_Creator_Owner)) {
DEBUG(10, ("Map creator owner\n"));
- ace_v4->who.special_id = SMB_ACE4_WHO_OWNER;
- ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ nfs4_ace.who.special_id = SMB_ACE4_WHO_OWNER;
+ nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
/* A non inheriting creator owner entry has no effect. */
- ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
- if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
- && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
- return false;
+ nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
+ if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
+ && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
+ return 0;
}
} else if (params->mode!=e_special &&
dom_sid_equal(&ace_nt->trustee,
&global_sid_Creator_Group)) {
DEBUG(10, ("Map creator owner group\n"));
- ace_v4->who.special_id = SMB_ACE4_WHO_GROUP;
- ace_v4->flags |= SMB_ACE4_ID_SPECIAL;
+ nfs4_ace.who.special_id = SMB_ACE4_WHO_GROUP;
+ nfs4_ace.flags |= SMB_ACE4_ID_SPECIAL;
/* A non inheriting creator group entry has no effect. */
- ace_v4->aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
- if (!(ace_v4->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
- && !(ace_v4->aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
- return false;
+ nfs4_ace.aceFlags |= SMB_ACE4_INHERIT_ONLY_ACE;
+ if (!(nfs4_ace.aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)
+ && !(nfs4_ace.aceFlags & SMB_ACE4_FILE_INHERIT_ACE)) {
+ return 0;
}
} else {
- uid_t uid;
- gid_t gid;
-
- if (sid_to_gid(&ace_nt->trustee, &gid)) {
- ace_v4->aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
- ace_v4->who.gid = gid;
- } else if (sid_to_uid(&ace_nt->trustee, &uid)) {
- ace_v4->who.uid = uid;
- } else if (dom_sid_compare_domain(&ace_nt->trustee,
- &global_sid_Unix_NFS) == 0) {
- return false;
- } else {
- DEBUG(1, ("nfs4_acls.c: file [%s]: could not "
- "convert %s to uid or gid\n",
- filename->base_name,
- sid_string_dbg(&ace_nt->trustee)));
- return false;
+ struct unixid unixid;
+ bool ok;
+
+ ok = sids_to_unixids(&ace_nt->trustee, 1, &unixid);
+ if (!ok) {
+ DBG_WARNING("Could not convert %s to uid or gid.\n",
+ dom_sid_str_buf(&ace_nt->trustee, &buf));
+ return 0;
}
- }
- return true; /* OK */
-}
+ if (dom_sid_compare_domain(&ace_nt->trustee,
+ &global_sid_Unix_NFS) == 0) {
+ return 0;
+ }
-static int smbacl4_MergeIgnoreReject(
- enum smbacl4_acedup_enum acedup,
- struct SMB4ACL_T *theacl, /* may modify it */
- SMB_ACE4PROP_T *ace, /* the "new" ACE */
- bool *paddNewACE,
- int i
-)
-{
- int result = 0;
- SMB_ACE4PROP_T *ace4found = smbacl4_find_equal_special(theacl, ace);
- if (ace4found)
- {
- switch(acedup)
- {
- case e_merge: /* "merge" flags */
- *paddNewACE = false;
- ace4found->aceFlags |= ace->aceFlags;
- ace4found->aceMask |= ace->aceMask;
+ switch (unixid.type) {
+ case ID_TYPE_BOTH:
+ nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+ nfs4_ace.who.gid = unixid.id;
+
+ if (ownerUID == unixid.id &&
+ !nfs_ace_is_inherit(&nfs4_ace))
+ {
+ /*
+ * IDMAP_TYPE_BOTH for owner. Add
+ * additional user entry, which can be
+ * mapped to special:owner to reflect
+ * the permissions in the modebits.
+ *
+ * This only applies to non-inheriting
+ * entries as only these are replaced
+ * with SPECIAL_OWNER in nfs4:mode=simple.
+ */
+ nfs4_ace_2 = (SMB_ACE4PROP_T) {
+ .who.uid = unixid.id,
+ .aceFlags = (nfs4_ace.aceFlags &
+ ~SMB_ACE4_IDENTIFIER_GROUP),
+ .aceMask = nfs4_ace.aceMask,
+ .aceType = nfs4_ace.aceType,
+ };
+ add_ace2 = true;
+ }
break;
- case e_ignore: /* leave out this record */
- *paddNewACE = false;
+ case ID_TYPE_GID:
+ nfs4_ace.aceFlags |= SMB_ACE4_IDENTIFIER_GROUP;
+ nfs4_ace.who.gid = unixid.id;
break;
- case e_reject: /* do an error */
- DEBUG(8, ("ACL rejected by duplicate nt ace#%d\n", i));
- errno = EINVAL; /* SHOULD be set on any _real_ error */
- result = -1;
+ case ID_TYPE_UID:
+ nfs4_ace.who.uid = unixid.id;
break;
+ case ID_TYPE_NOT_SPECIFIED:
default:
- break;
+ DBG_WARNING("Could not convert %s to uid or gid.\n",
+ dom_sid_str_buf(&ace_nt->trustee, &buf));
+ return 0;
}
}
- return result;
+
+ ret = nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace);
+ if (ret != 0) {
+ return -1;
+ }
+
+ if (!add_ace2) {
+ return 0;
+ }
+
+ return nfs4_acl_add_ace(params->acedup, nfs4_acl, &nfs4_ace_2);
}
-static int smbacl4_substitute_special(
- struct SMB4ACL_T *acl,
- uid_t ownerUID,
- gid_t ownerGID
-)
+static void smbacl4_substitute_special(struct SMB4ACL_T *acl,
+ uid_t ownerUID,
+ gid_t ownerGID)
{
struct SMB4ACE_T *aceint;
DEBUG(10,("replaced with special group ace\n"));
}
}
- return true; /* OK */
}
-static int smbacl4_substitute_simple(
- struct SMB4ACL_T *acl,
- uid_t ownerUID,
- gid_t ownerGID
-)
+static void smbacl4_substitute_simple(struct SMB4ACL_T *acl,
+ uid_t ownerUID,
+ gid_t ownerGID)
{
struct SMB4ACE_T *aceint;
if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
!(ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP) &&
ace->who.uid == ownerUID &&
- !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
- !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
- !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
+ !nfs_ace_is_inherit(ace)) {
ace->flags |= SMB_ACE4_ID_SPECIAL;
ace->who.special_id = SMB_ACE4_WHO_OWNER;
DEBUG(10,("replaced with special owner ace\n"));
if (!(ace->flags & SMB_ACE4_ID_SPECIAL) &&
ace->aceFlags & SMB_ACE4_IDENTIFIER_GROUP &&
- ace->who.uid == ownerGID &&
- !(ace->aceFlags & SMB_ACE4_INHERIT_ONLY_ACE) &&
- !(ace->aceFlags & SMB_ACE4_FILE_INHERIT_ACE) &&
- !(ace->aceFlags & SMB_ACE4_DIRECTORY_INHERIT_ACE)) {
+ ace->who.gid == ownerGID &&
+ !nfs_ace_is_inherit(ace)) {
ace->flags |= SMB_ACE4_ID_SPECIAL;
ace->who.special_id = SMB_ACE4_WHO_GROUP;
DEBUG(10,("replaced with special group ace\n"));
}
}
- return true; /* OK */
}
static struct SMB4ACL_T *smbacl4_win2nfs4(
TALLOC_CTX *mem_ctx,
- const files_struct *fsp,
+ bool is_directory,
const struct security_acl *dacl,
- smbacl4_vfs_params *pparams,
+ const struct smbacl4_vfs_params *pparams,
uid_t ownerUID,
gid_t ownerGID
)
{
struct SMB4ACL_T *theacl;
uint32_t i;
- const char *filename = fsp->fsp_name->base_name;
DEBUG(10, ("smbacl4_win2nfs4 invoked\n"));
return NULL;
for(i=0; i<dacl->num_aces; i++) {
- SMB_ACE4PROP_T ace_v4;
- bool addNewACE = true;
-
- if (!smbacl4_fill_ace4(fsp->fsp_name, pparams,
- ownerUID, ownerGID,
- dacl->aces + i, &ace_v4)) {
- DEBUG(3, ("Could not fill ace for file %s, SID %s\n",
- filename,
- sid_string_dbg(&((dacl->aces+i)->trustee))));
- continue;
- }
+ int ret;
- if (pparams->acedup!=e_dontcare) {
- if (smbacl4_MergeIgnoreReject(pparams->acedup, theacl,
- &ace_v4, &addNewACE, i))
- return NULL;
+ ret = nfs4_acl_add_sec_ace(is_directory, pparams,
+ ownerUID, ownerGID,
+ dacl->aces + i, theacl);
+ if (ret == -1) {
+ return NULL;
}
-
- if (addNewACE)
- smb_add_ace4(theacl, &ace_v4);
}
if (pparams->mode==e_simple) {
}
NTSTATUS smb_set_nt_acl_nfs4(vfs_handle_struct *handle, files_struct *fsp,
+ const struct smbacl4_vfs_params *pparams,
uint32_t security_info_sent,
const struct security_descriptor *psd,
set_nfs4acl_native_fn_t set_nfs4_native)
{
- smbacl4_vfs_params params;
+ struct smbacl4_vfs_params params;
struct SMB4ACL_T *theacl = NULL;
- bool result;
+ bool result, is_directory;
- SMB_STRUCT_STAT sbuf;
bool set_acl_as_root = false;
- uid_t newUID = (uid_t)-1;
- gid_t newGID = (gid_t)-1;
int saved_errno;
+ NTSTATUS status;
TALLOC_CTX *frame = talloc_stackframe();
DEBUG(10, ("smb_set_nt_acl_nfs4 invoked for %s\n", fsp_str_dbg(fsp)));
* refined... */
}
- /* Special behaviours */
- if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
+ if (security_descriptor_with_ms_nfs(psd)) {
TALLOC_FREE(frame);
- return NT_STATUS_NO_MEMORY;
+ return NT_STATUS_OK;
}
- if (smbacl4_fGetFileOwner(fsp, &sbuf)) {
+ if (pparams == NULL) {
+ /* Special behaviours */
+ if (smbacl4_get_vfs_params(fsp->conn, ¶ms)) {
+ TALLOC_FREE(frame);
+ return NT_STATUS_NO_MEMORY;
+ }
+ pparams = ¶ms;
+ }
+
+ status = vfs_stat_fsp(fsp);
+ if (!NT_STATUS_IS_OK(status)) {
TALLOC_FREE(frame);
- return map_nt_error_from_unix(errno);
+ return status;
}
- if (params.do_chown) {
- /* chown logic is a copy/paste from posix_acl.c:set_nt_acl */
- NTSTATUS status = unpack_nt_owners(fsp->conn, &newUID, &newGID,
- security_info_sent, psd);
+ is_directory = S_ISDIR(fsp->fsp_name->st.st_ex_mode);
+
+ if (pparams->do_chown) {
+ /*
+ * When the chown succeeds, the special entries in the
+ * file system ACL refer to the new owner. In order to
+ * apply the complete information from the DACL,
+ * setting the ACL then has to succeed. Track this
+ * case with set_acl_as_root and set the ACL as root
+ * accordingly.
+ */
+ status = chown_if_needed(fsp, security_info_sent, psd,
+ &set_acl_as_root);
if (!NT_STATUS_IS_OK(status)) {
- DEBUG(8, ("unpack_nt_owners failed"));
TALLOC_FREE(frame);
return status;
}
- if (((newUID != (uid_t)-1) && (sbuf.st_ex_uid != newUID)) ||
- ((newGID != (gid_t)-1) && (sbuf.st_ex_gid != newGID))) {
-
- status = try_chown(fsp, newUID, newGID);
- if (!NT_STATUS_IS_OK(status)) {
- DEBUG(3,("chown %s, %u, %u failed. Error = "
- "%s.\n", fsp_str_dbg(fsp),
- (unsigned int)newUID,
- (unsigned int)newGID,
- nt_errstr(status)));
- TALLOC_FREE(frame);
- return status;
- }
-
- DEBUG(10,("chown %s, %u, %u succeeded.\n",
- fsp_str_dbg(fsp), (unsigned int)newUID,
- (unsigned int)newGID));
- if (smbacl4_GetFileOwner(fsp->conn,
- fsp->fsp_name,
- &sbuf)){
- TALLOC_FREE(frame);
- return map_nt_error_from_unix(errno);
- }
-
- /* If we successfully chowned, we know we must
- * be able to set the acl, so do it as root.
- */
- set_acl_as_root = true;
- }
}
if (!(security_info_sent & SECINFO_DACL) || psd->dacl ==NULL) {
return NT_STATUS_OK;
}
- theacl = smbacl4_win2nfs4(frame, fsp, psd->dacl, ¶ms,
- sbuf.st_ex_uid, sbuf.st_ex_gid);
+ theacl = smbacl4_win2nfs4(frame, is_directory, psd->dacl, pparams,
+ fsp->fsp_name->st.st_ex_uid,
+ fsp->fsp_name->st.st_ex_gid);
if (!theacl) {
TALLOC_FREE(frame);
return map_nt_error_from_unix(errno);