Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make samba aware of ACL brand and trivial ACEs #79

Open
wants to merge 1 commit into
base: SCALE-v4-15-stable
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions source3/include/vfs.h
Original file line number Diff line number Diff line change
Expand Up @@ -440,6 +440,7 @@ typedef struct files_struct {
bool closing : 1;
bool lock_failure_seen : 1;
bool encryption_required : 1;
bool acl_is_trivial : 1;
} fsp_flags;

struct tevent_timer *update_write_time_event;
Expand Down
2 changes: 2 additions & 0 deletions source3/modules/nfs41acl.x
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,8 @@ const ACL4_XATTR_VERSION_DEFAULT = ACL4_XATTR_VERSION_40;
const ACL4_AUTO_INHERIT = 0x00000001;
const ACL4_PROTECTED = 0x00000002;
const ACL4_DEFAULTED = 0x00000004;
const ACL4_IS_TRIVIAL = 0x00010000;
const ACL4_IS_DIR = 0x00020000;

typedef u_int aclflag4;

Expand Down
20 changes: 20 additions & 0 deletions source3/modules/nfs4_acls.c
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct SMB4ACL_T
{
uint16_t controlflags;
uint32_t naces;
bool is_trivial;
struct SMB4ACE_T *first;
struct SMB4ACE_T *last;
};
Expand Down Expand Up @@ -265,6 +266,25 @@ bool smbacl4_set_controlflags(struct SMB4ACL_T *acl, uint16_t controlflags)
return true;
}

bool smbacl4_get_trivial(const struct SMB4ACL_T *acl, bool *trivialp)
{
if (acl == NULL) {
return false;
}
*trivialp = acl->is_trivial;
return true;
}

bool smbacl4_set_trivial(struct SMB4ACL_T *acl, bool trivial)
{
if (acl == NULL) {
return false;
}
acl->is_trivial = trivial;
return true;
}


bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace)
{
return ace->aceFlags & (SMB_ACE4_INHERIT_ONLY_ACE|
Expand Down
4 changes: 4 additions & 0 deletions source3/modules/nfs4_acls.h
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,10 @@ bool smbacl4_set_controlflags(struct SMB4ACL_T *theacl, uint16_t controlflags);

bool nfs_ace_is_inherit(SMB_ACE4PROP_T *ace);

bool smbacl4_get_trivial(const struct SMB4ACL_T *acl, bool *trivialp);

bool smbacl4_set_trivial(struct SMB4ACL_T *acl, bool trivial);

NTSTATUS smb_fget_nt_acl_nfs4(files_struct *fsp,
const struct smbacl4_vfs_params *pparams,
uint32_t security_info,
Expand Down
5 changes: 4 additions & 1 deletion source3/modules/nfs4acl_xattr_xdr.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ static NTSTATUS nfs4acl_xdr_blob_to_nfs4acli(struct vfs_handle_struct *handle,
return NT_STATUS_OK;
}

#define ACL4_ALL_FLAGS (ACL4_AUTO_INHERIT | ACL4_PROTECTED | ACL4_DEFAULTED)

static NTSTATUS nfs4acli_to_smb4acl(struct vfs_handle_struct *handle,
TALLOC_CTX *mem_ctx,
nfsacl41i *nacl,
Expand All @@ -300,7 +302,8 @@ static NTSTATUS nfs4acli_to_smb4acl(struct vfs_handle_struct *handle,
if (config->nfs_version > ACL4_XATTR_VERSION_40) {
nfsacl41_flag = nfs4acli_get_flags(nacl);
smb4acl_flags = nfs4acl_to_smb4acl_flags(nfsacl41_flag);
smbacl4_set_controlflags(smb4acl, smb4acl_flags);
smbacl4_set_controlflags(smb4acl, smb4acl_flags & ACL4_ALL_FLAGS);
smbacl4_set_trivial(smb4acl, smb4acl_flags & ACL4_IS_TRIVIAL);
}

DBG_DEBUG("flags [%x] nace [%u]\n", smb4acl_flags, naces);
Expand Down
18 changes: 15 additions & 3 deletions source3/modules/vfs_nfs4acl_xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -232,6 +232,14 @@ static NTSTATUS nfs4acl_xattr_fget_nt_acl(struct vfs_handle_struct *handle,

status = smb_fget_nt_acl_nfs4(fsp, NULL, security_info, mem_ctx,
sd, smb4acl);

if (NT_STATUS_IS_OK(status)) {
bool ok, is_trivial;
ok = smbacl4_get_trivial(smb4acl, &is_trivial);
if (ok) {
fsp->fsp_flags.acl_is_trivial = is_trivial;
}
}
TALLOC_FREE(frame);
return status;
}
Expand Down Expand Up @@ -465,9 +473,11 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
switch (nfs_version) {
case 40:
config->nfs_version = ACL4_XATTR_VERSION_40;
handle->conn->aclbrand = SMB_ACL_BRAND_NFS40;
break;
case 41:
config->nfs_version = ACL4_XATTR_VERSION_41;
handle->conn->aclbrand = SMB_ACL_BRAND_NFS41;
break;
default:
config->nfs_version = ACL4_XATTR_VERSION_DEFAULT;
Expand Down Expand Up @@ -516,11 +526,13 @@ static int nfs4acl_connect(struct vfs_handle_struct *handle,
"'store dos attributes = yes' "
"for service [%s]\n", service);

lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
if (handle->conn->aclbrand != SMB_ACL_BRAND_NFS41) {
lp_do_parameter(SNUM(handle->conn), "inherit acls", "true");
lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
}
lp_do_parameter(SNUM(handle->conn), "dos filemode", "true");
lp_do_parameter(SNUM(handle->conn), "force unknown acl user", "true");
lp_do_parameter(SNUM(handle->conn), "create mask", "0666");
lp_do_parameter(SNUM(handle->conn), "directory mask", "0777");
lp_do_parameter(SNUM(handle->conn), "store dos attributes", "yes");

return 0;
Expand Down
155 changes: 151 additions & 4 deletions source3/modules/vfs_recycle.c
Original file line number Diff line number Diff line change
Expand Up @@ -436,13 +436,143 @@ static bool recycle_file_exist(vfs_handle_struct *handle,
return false;
}

#ifdef FREEBSD
static bool acl_strip(files_struct *dirfsp,
struct smb_filename *smb_fname,
mode_t mode)
{
bool ok;
int dirfd, fd, err;
acl_t old, new;

dirfd = fsp_get_pathref_fd(dirfsp);
SMB_ASSERT(dirfd != -1);

fd = openat(dirfd, smb_fname->base_name, O_DIRECTORY);
if (fd == -1) {
DBG_ERR("%s: failed to open directory: %s\n",
smb_fname->base_name, strerror(errno));
return false;
}

old = acl_get_fd_np(fd, ACL_TYPE_NFS4);
if (old == NULL) {
DBG_ERR("%s: acl_get_fd_np() failed: %s\n",
smb_fname->base_name, strerror(errno));
ok = false;
goto done;
}

new = acl_strip_np(old, 0);
if (new == NULL) {
DBG_ERR("%s: acl_get_strip_np() failed: %s\n",
smb_fname->base_name, strerror(errno));
acl_free(old);
goto done;
}
acl_free(old);

err = acl_set_fd_np(fd, new, ACL_TYPE_NFS4);
if (err) {
DBG_ERR("%s: acl_set_fd_np() failed: %s\n",
smb_fname->base_name, strerror(errno));
acl_free(new);
goto done;
}

acl_free(new);

err = fchmod(fd, mode);
if (err) {
DBG_ERR("%s: chmod() failed: %s\n",
smb_fname->base_name, strerror(errno));
}
done:
close(fd);
return ok;
}

static bool acl_is_trivial(files_strut *dirfsp,
bool *trivialp)
{
int dirfd, fd, err;
acl_t theacl;
bool is_trivial;

dirfd = fsp_get_pathref_fd(dirfsp);
SMB_ASSERT(dirfd != -1);

fd = openat(dirfd, "", O_DIRECTORY, AT_EMPTY_PATH);
if (fd == -1) {
DBG_ERR("%s: failed to open directory: %s\n",
fsp_str_dbg(dirfsp), strerror(errno));
return false;
}
theacl = acl_get_fd_np(fd, ACL_TYPE_NFS4);
if (theacl == NULL) {
DBG_ERR("%s: acl_get_fd_np() failed: %s\n",
fsp_str_dbg(dirfsp), strerror(errno));
close(fd);
return false;
}

err = acl_is_trivial_np(theacl, &is_trivial);
if (err) {
DBG_ERR("%s: acl_is_trivial_np() failed: %s\n",
fsp_str_dbg(dirfsp), strerror(errno));
}
return err ? false : true;
}

#else
static bool acl_strip(files_struct *dirfsp,
struct smb_filename *smb_fname,
mode_t mode)
{
/*
* Still need to implement functionality to strip ACL in Linux
* Current plan is to do through rmxattr on the NFS ACL xattr.
*/

return false;
}

static bool acl_is_trivial(files_strut *dirfsp,
bool *trivialp)
{
NTSTATUS status;
struct security_descriptor *sd = NULL;

status = SMB_VFS_FGET_NT_ACL(dirfsp,
(SECINFO_OWNER |
SECINFO_GROUP |
SECINFO_DACL),
talloc_tos(),
&sd);
if (!NT_STATUS_IS_OK(status)) {
DBG_ERR("%s: failed to get NT ACL: %s\n",
fsp_str_dbg(dirfsp), nt_errstr(status));
return false;
}

TALLOC_FREE(sd);
*trivialp = dirfsp->fsp_flags.acl_is_trivial;
return true;
}

#endif

/**
* Create directory tree
* @param conn connection
* @param dname Directory tree to be created
* @param check_acl whether to check if ACL is trivial
* @return Returns True for success
**/
static bool recycle_create_dir(vfs_handle_struct *handle, const files_struct *dirfsp, const char *dname)
static bool recycle_create_dir(vfs_handle_struct *handle,
const files_struct *dirfsp,
const char *dname,
bool check_acl)
{
size_t len;
mode_t mode;
Expand All @@ -451,9 +581,18 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const files_struct *di
char *token;
char *tok_str;
bool ret = False;
bool is_trivial = true;
char *saveptr;
int depth;

mode = recycle_directory_mode(handle);
if (check_acl && handle->conn->aclbrand == SMB_ACL_BRAND_NFS41) {
bool ok;
ok = acl_is_trivial(handle, dirfsp, &is_trivial);
if (!ok) {
return ok;
}
}

tmp_str = SMB_STRDUP(dname);
ALLOC_CHECK(tmp_str, done);
Expand All @@ -471,8 +610,8 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const files_struct *di
}

/* Create directory tree if necessary */
for(token = strtok_r(tok_str, "/", &saveptr); token;
token = strtok_r(NULL, "/", &saveptr)) {
for(token = strtok_r(tok_str, "/", &saveptr), depth = 0; token;
token = strtok_r(NULL, "/", &saveptr), depth++) {
if (strlcat(new_dir, token, len+1) >= len+1) {
goto done;
}
Expand All @@ -490,7 +629,15 @@ static bool recycle_create_dir(vfs_handle_struct *handle, const files_struct *di
dirfsp,
&smb_fname,
mode);
if (retval != 0) {
if (retval != 0 && errno == EPERM && !is_trivial) {
ret = acl_strip(handle, dirfsp, &smb_fname, mode);
if (!ret) {
DBG_ERR("%s: failed to strip ACL: %s\n",
new_dir, strerror(errno));
goto done;
}
}
else if (retval != 0) {
DBG_WARNING("recycle: mkdirat failed "
"for %s with error: %s\n",
new_dir,
Expand Down