Skip to content

Commit

Permalink
Ensure that commonly requested xattrs are in SA
Browse files Browse the repository at this point in the history
Now that we have SA-based xattrs on FreeBSD we should
ensure that certain important samba-related xattrs are
written to this area rather than in the xattr dir. This
avoids having to perform more expensive permissions check,
lookup, and read.

Since we can't always know what the contents of these xattrs
will be beforehand, store empty xattrs and have Samba internally
assign special meaning to the ones with no value (e.g. fail
read with ENOATTR). This is sufficient to mask the attributes
from SMB clients since vfs_streams_xattr will attempt to
FGETXATTR prior to appending the xattr to STREAM_INFO response.

Three attributes to be stored in this way are:
- user.DOSATTRIB (always requested for files)
- stream (AFP_AfpInfo) which is used by VFS fruit to generate
  response to SMB2 FIND_INFO requests when AAPL context negotiated.
- stream (AFP_Resource) which is requested by Finder to check for
  metadata related to icons or other usage of resource forks.
  • Loading branch information
anodos325 committed Feb 16, 2023
1 parent 48cc0ef commit 77a83a3
Showing 1 changed file with 122 additions and 2 deletions.
124 changes: 122 additions & 2 deletions source3/modules/vfs_streams_xattr.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,10 @@ struct streams_xattr_config {
const char *prefix;
size_t prefix_len;
bool store_stream_type;
bool seed_builtin_attrs;
int xattr_compat_bytes;
char *afpinfo_name;
char *afpresource_name;
};

struct stream_io {
Expand All @@ -46,6 +49,20 @@ struct stream_io {
vfs_handle_struct *handle;
};

const char EMPTY_XATTR[64] = {0};

static bool is_builtin_attr_name(const char *name,
struct streams_xattr_config *config)
{
if ((strcmp(name, SAMBA_XATTR_DOS_ATTRIB) == 0) ||
(strcmp(name, config->afpinfo_name) == 0) ||
(strcmp(name, config->afpresource_name) == 0)) {
return true;
}

return false;
}

static ssize_t get_xattr_size_fsp(vfs_handle_struct *handle,
struct files_struct *fsp,
const char *xattr_name)
Expand Down Expand Up @@ -957,6 +974,28 @@ static int streams_xattr_connect(vfs_handle_struct *handle,

config->xattr_compat_bytes = xattr_compat ? 0 : 1;

config->afpinfo_name = talloc_asprintf(config, "%s%s%s",
prefix, "AFP_AfpInfo", config->store_stream_type ? ":$DATA" : ""
);
if (config->afpinfo_name == NULL) {
DBG_ERR("talloc_asprintf() failed\n");
return -1;
}

config->afpresource_name = talloc_asprintf(config, "%s%s%s",
prefix, "AFP_Resource", config->store_stream_type ? ":$DATA" : ""
);

if (config->afpresource_name == NULL) {
DBG_ERR("talloc_asprintf() failed\n");
return -1;
}

config->seed_builtin_attrs = lp_parm_bool(SNUM(handle->conn),
"streams_xattr",
"seed_builtin_attrs",
false);

SMB_VFS_HANDLE_SET_DATA(handle, config,
NULL, struct stream_xattr_config,
return -1);
Expand Down Expand Up @@ -1387,6 +1426,73 @@ static int streams_xattr_fchmod(vfs_handle_struct *handle,
return 0;
}

static int seed_builtin_attr(struct vfs_handle_struct *handle,
struct files_struct *fsp,
const char *name,
bool as_root)
{
int rv;

if (!CAN_WRITE(handle->conn)) {
errno = EPERM;
return -1;
}

rv = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, EMPTY_XATTR,
sizeof(EMPTY_XATTR), XATTR_CREATE);

if ((rv == -1) && as_root && ((errno == EPERM) || (errno == EACCES))) {
become_root();
rv = SMB_VFS_NEXT_FSETXATTR(handle, fsp, name, EMPTY_XATTR,
sizeof(EMPTY_XATTR), XATTR_CREATE);
unbecome_root();
}

if (rv == -1) {
DBG_INFO("%s: failed to seed builtin xattr on [%s]: %s\n",
name, fsp_str_dbg(fsp), strerror(errno));
}

return rv;
}

static ssize_t parse_retrieved_xattr(struct vfs_handle_struct *handle,
struct files_struct *fsp,
const char *name,
char *value,
ssize_t xattr_get_rv,
struct streams_xattr_config *config)
{
ssize_t rv = xattr_get_rv;

if (!is_builtin_attr_name(name, config)) {
return rv;
}

if (xattr_get_rv == -1) {
if ((errno == ENOATTR) && (config->seed_builtin_attrs)) {
seed_builtin_attr(handle, fsp, name, true);
}
} else if (xattr_get_rv == sizeof(EMPTY_XATTR)) {
size_t off;
bool has_data = false;

for (off=0; off < rv; off++) {
if (value[off] != '\0') {
has_data = true;
break;
}
}

if (!has_data) {
errno = ENOATTR;
rv = -1;
}
}

return rv;
}

static ssize_t streams_xattr_fgetxattr(struct vfs_handle_struct *handle,
struct files_struct *fsp,
const char *name,
Expand All @@ -1395,13 +1501,19 @@ static ssize_t streams_xattr_fgetxattr(struct vfs_handle_struct *handle,
{
struct stream_io *sio =
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
struct streams_xattr_config *config = NULL;
SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
return -1);

ssize_t rv = -1;

if (sio == NULL) {
return SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
rv = SMB_VFS_NEXT_FGETXATTR(handle, fsp, name, value, size);
return parse_retrieved_xattr(handle, fsp, name, value, rv, config);
}

errno = ENOTSUP;
return -1;
return rv;
}

static ssize_t streams_xattr_flistxattr(struct vfs_handle_struct *handle,
Expand All @@ -1426,8 +1538,16 @@ static int streams_xattr_fremovexattr(struct vfs_handle_struct *handle,
{
struct stream_io *sio =
(struct stream_io *)VFS_FETCH_FSP_EXTENSION(handle, fsp);
struct streams_xattr_config *config = NULL;

SMB_VFS_HANDLE_GET_DATA(handle, config, struct streams_xattr_config,
return -1);

if (sio == NULL) {
if (config->seed_builtin_attrs &&
is_builtin_attr_name(sio->xattr_name, config)) {
return seed_builtin_attr(handle, fsp, sio->xattr_name, false);
}
return SMB_VFS_NEXT_FREMOVEXATTR(handle, fsp, name);
}

Expand Down

0 comments on commit 77a83a3

Please sign in to comment.