Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 260f082b authored by David Howells's avatar David Howells
Browse files

afs: Get an AFS3 ACL as an xattr



Implement an xattr on AFS files called "afs.acl" that retrieves a file's
ACL.  It returns the raw AFS3 ACL from the result of calling FS.FetchACL,
leaving any interpretation to userspace.

Note that whilst YFS servers will respond to FS.FetchACL, this will render
a more-advanced YFS ACL down.  Use "afs.yfs.acl" instead for that.

Signed-off-by: default avatarDavid Howells <dhowells@redhat.com>
parent a2f611a3
Loading
Loading
Loading
Loading
+1 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@


enum AFS_FS_Operations {
enum AFS_FS_Operations {
	FSFETCHDATA		= 130,	/* AFS Fetch file data */
	FSFETCHDATA		= 130,	/* AFS Fetch file data */
	FSFETCHACL		= 131,	/* AFS Fetch file ACL */
	FSFETCHSTATUS		= 132,	/* AFS Fetch file status */
	FSFETCHSTATUS		= 132,	/* AFS Fetch file status */
	FSSTOREDATA		= 133,	/* AFS Store file data */
	FSSTOREDATA		= 133,	/* AFS Store file data */
	FSSTORESTATUS		= 135,	/* AFS Store file status */
	FSSTORESTATUS		= 135,	/* AFS Store file status */
+122 −0
Original line number Original line Diff line number Diff line
@@ -2391,3 +2391,125 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc,
	afs_make_call(&fc->ac, call, GFP_NOFS);
	afs_make_call(&fc->ac, call, GFP_NOFS);
	return afs_wait_for_call_to_complete(call, &fc->ac);
	return afs_wait_for_call_to_complete(call, &fc->ac);
}
}

/*
 * deliver reply data to an FS.FetchACL
 */
static int afs_deliver_fs_fetch_acl(struct afs_call *call)
{
	struct afs_vnode *vnode = call->reply[1];
	struct afs_acl *acl;
	const __be32 *bp;
	unsigned int size;
	int ret;

	_enter("{%u}", call->unmarshall);

	switch (call->unmarshall) {
	case 0:
		afs_extract_to_tmp(call);
		call->unmarshall++;

		/* extract the returned data length */
	case 1:
		ret = afs_extract_data(call, true);
		if (ret < 0)
			return ret;

		size = call->count2 = ntohl(call->tmp);
		size = round_up(size, 4);

		acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL);
		if (!acl)
			return -ENOMEM;
		call->reply[0] = acl;
		acl->size = call->count2;
		afs_extract_begin(call, acl->data, size);
		call->unmarshall++;

		/* extract the returned data */
	case 2:
		ret = afs_extract_data(call, true);
		if (ret < 0)
			return ret;

		afs_extract_to_buf(call, (21 + 6) * 4);
		call->unmarshall++;

		/* extract the metadata */
	case 3:
		ret = afs_extract_data(call, false);
		if (ret < 0)
			return ret;

		bp = call->buffer;
		ret = afs_decode_status(call, &bp, &vnode->status, vnode,
					&vnode->status.data_version, NULL);
		if (ret < 0)
			return ret;
		xdr_decode_AFSVolSync(&bp, call->reply[2]);

		call->unmarshall++;

	case 4:
		break;
	}

	_leave(" = 0 [done]");
	return 0;
}

static void afs_destroy_fs_fetch_acl(struct afs_call *call)
{
	kfree(call->reply[0]);
	afs_flat_call_destructor(call);
}

/*
 * FS.FetchACL operation type
 */
static const struct afs_call_type afs_RXFSFetchACL = {
	.name		= "FS.FetchACL",
	.op		= afs_FS_FetchACL,
	.deliver	= afs_deliver_fs_fetch_acl,
	.destructor	= afs_destroy_fs_fetch_acl,
};

/*
 * Fetch the ACL for a file.
 */
struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc)
{
	struct afs_vnode *vnode = fc->vnode;
	struct afs_call *call;
	struct afs_net *net = afs_v2net(vnode);
	__be32 *bp;

	_enter(",%x,{%llx:%llu},,",
	       key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode);

	call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4);
	if (!call) {
		fc->ac.error = -ENOMEM;
		return ERR_PTR(-ENOMEM);
	}

	call->key = fc->key;
	call->reply[0] = NULL;
	call->reply[1] = vnode;
	call->reply[2] = NULL; /* volsync */
	call->ret_reply0 = true;

	/* marshall the parameters */
	bp = call->request;
	bp[0] = htonl(FSFETCHACL);
	bp[1] = htonl(vnode->fid.vid);
	bp[2] = htonl(vnode->fid.vnode);
	bp[3] = htonl(vnode->fid.unique);

	call->cb_break = fc->cb_break;
	afs_use_fs_server(call, fc->cbi);
	trace_afs_make_fs_call(call, &vnode->fid);
	afs_make_call(&fc->ac, call, GFP_KERNEL);
	return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac);
}
+7 −0
Original line number Original line Diff line number Diff line
@@ -977,6 +977,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *,
			       struct afs_fid *, struct afs_file_status *,
			       struct afs_fid *, struct afs_file_status *,
			       struct afs_callback *, struct afs_volsync *);
			       struct afs_callback *, struct afs_volsync *);


struct afs_acl {
	u32	size;
	u8	data[];
};

extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *);

/*
/*
 * fs_probe.c
 * fs_probe.c
 */
 */
+53 −0
Original line number Original line Diff line number Diff line
@@ -16,6 +16,7 @@
#include "internal.h"
#include "internal.h"


static const char afs_xattr_list[] =
static const char afs_xattr_list[] =
	"afs.acl\0"
	"afs.cell\0"
	"afs.cell\0"
	"afs.fid\0"
	"afs.fid\0"
	"afs.volume";
	"afs.volume";
@@ -33,6 +34,57 @@ ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size)
	return sizeof(afs_xattr_list);
	return sizeof(afs_xattr_list);
}
}


/*
 * Get a file's ACL.
 */
static int afs_xattr_get_acl(const struct xattr_handler *handler,
			     struct dentry *dentry,
			     struct inode *inode, const char *name,
			     void *buffer, size_t size)
{
	struct afs_fs_cursor fc;
	struct afs_vnode *vnode = AFS_FS_I(inode);
	struct afs_acl *acl = NULL;
	struct key *key;
	int ret;

	key = afs_request_key(vnode->volume->cell);
	if (IS_ERR(key))
		return PTR_ERR(key);

	ret = -ERESTARTSYS;
	if (afs_begin_vnode_operation(&fc, vnode, key)) {
		while (afs_select_fileserver(&fc)) {
			fc.cb_break = afs_calc_vnode_cb_break(vnode);
			acl = afs_fs_fetch_acl(&fc);
		}

		afs_check_for_remote_deletion(&fc, fc.vnode);
		afs_vnode_commit_status(&fc, vnode, fc.cb_break);
		ret = afs_end_vnode_operation(&fc);
	}

	if (ret == 0) {
		ret = acl->size;
		if (size > 0) {
			ret = -ERANGE;
			if (acl->size > size)
				return -ERANGE;
			memcpy(buffer, acl->data, acl->size);
			ret = acl->size;
		}
		kfree(acl);
	}

	key_put(key);
	return ret;
}

static const struct xattr_handler afs_xattr_afs_acl_handler = {
	.name	= "afs.acl",
	.get	= afs_xattr_get_acl,
};

/*
/*
 * Get the name of the cell on which a file resides.
 * Get the name of the cell on which a file resides.
 */
 */
@@ -123,6 +175,7 @@ static const struct xattr_handler afs_xattr_afs_volume_handler = {
};
};


const struct xattr_handler *afs_xattr_handlers[] = {
const struct xattr_handler *afs_xattr_handlers[] = {
	&afs_xattr_afs_acl_handler,
	&afs_xattr_afs_cell_handler,
	&afs_xattr_afs_cell_handler,
	&afs_xattr_afs_fid_handler,
	&afs_xattr_afs_fid_handler,
	&afs_xattr_afs_volume_handler,
	&afs_xattr_afs_volume_handler,
+1 −0
Original line number Original line Diff line number Diff line
@@ -33,6 +33,7 @@ enum afs_call_trace {


enum afs_fs_operation {
enum afs_fs_operation {
	afs_FS_FetchData		= 130,	/* AFS Fetch file data */
	afs_FS_FetchData		= 130,	/* AFS Fetch file data */
	afs_FS_FetchACL			= 131,	/* AFS Fetch file ACL */
	afs_FS_FetchStatus		= 132,	/* AFS Fetch file status */
	afs_FS_FetchStatus		= 132,	/* AFS Fetch file status */
	afs_FS_StoreData		= 133,	/* AFS Store file data */
	afs_FS_StoreData		= 133,	/* AFS Store file data */
	afs_FS_StoreStatus		= 135,	/* AFS Store file status */
	afs_FS_StoreStatus		= 135,	/* AFS Store file status */