mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	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: David Howells <dhowells@redhat.com>
This commit is contained in:
		
							parent
							
								
									a2f611a3dc
								
							
						
					
					
						commit
						260f082bae
					
				
					 5 changed files with 184 additions and 0 deletions
				
			
		| 
						 | 
					@ -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 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -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 */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue