diff options
author | David Howells <dhowells@redhat.com> | 2019-04-25 09:26:52 -0400 |
---|---|---|
committer | David Howells <dhowells@redhat.com> | 2019-05-07 11:48:44 -0400 |
commit | 260f082bae6dcf70aeae2cc3e24aecb55bdb1c99 (patch) | |
tree | 128a02382c0b98b01f8c1fce97347a41a2507e40 /fs/afs | |
parent | a2f611a3dc317d8ea1c98ad6c54b911cf7f93193 (diff) |
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>
Diffstat (limited to 'fs/afs')
-rw-r--r-- | fs/afs/afs_fs.h | 1 | ||||
-rw-r--r-- | fs/afs/fsclient.c | 122 | ||||
-rw-r--r-- | fs/afs/internal.h | 7 | ||||
-rw-r--r-- | fs/afs/xattr.c | 53 |
4 files changed, 183 insertions, 0 deletions
diff --git a/fs/afs/afs_fs.h b/fs/afs/afs_fs.h index ddfa88a7a9c0..4df1f1eec0ab 100644 --- a/fs/afs/afs_fs.h +++ b/fs/afs/afs_fs.h | |||
@@ -17,6 +17,7 @@ | |||
17 | 17 | ||
18 | enum AFS_FS_Operations { | 18 | enum AFS_FS_Operations { |
19 | FSFETCHDATA = 130, /* AFS Fetch file data */ | 19 | FSFETCHDATA = 130, /* AFS Fetch file data */ |
20 | FSFETCHACL = 131, /* AFS Fetch file ACL */ | ||
20 | FSFETCHSTATUS = 132, /* AFS Fetch file status */ | 21 | FSFETCHSTATUS = 132, /* AFS Fetch file status */ |
21 | FSSTOREDATA = 133, /* AFS Store file data */ | 22 | FSSTOREDATA = 133, /* AFS Store file data */ |
22 | FSSTORESTATUS = 135, /* AFS Store file status */ | 23 | FSSTORESTATUS = 135, /* AFS Store file status */ |
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c index 9b73a57aa5cb..283f486c59f4 100644 --- a/fs/afs/fsclient.c +++ b/fs/afs/fsclient.c | |||
@@ -2391,3 +2391,125 @@ int afs_fs_inline_bulk_status(struct afs_fs_cursor *fc, | |||
2391 | afs_make_call(&fc->ac, call, GFP_NOFS); | 2391 | afs_make_call(&fc->ac, call, GFP_NOFS); |
2392 | return afs_wait_for_call_to_complete(call, &fc->ac); | 2392 | return afs_wait_for_call_to_complete(call, &fc->ac); |
2393 | } | 2393 | } |
2394 | |||
2395 | /* | ||
2396 | * deliver reply data to an FS.FetchACL | ||
2397 | */ | ||
2398 | static int afs_deliver_fs_fetch_acl(struct afs_call *call) | ||
2399 | { | ||
2400 | struct afs_vnode *vnode = call->reply[1]; | ||
2401 | struct afs_acl *acl; | ||
2402 | const __be32 *bp; | ||
2403 | unsigned int size; | ||
2404 | int ret; | ||
2405 | |||
2406 | _enter("{%u}", call->unmarshall); | ||
2407 | |||
2408 | switch (call->unmarshall) { | ||
2409 | case 0: | ||
2410 | afs_extract_to_tmp(call); | ||
2411 | call->unmarshall++; | ||
2412 | |||
2413 | /* extract the returned data length */ | ||
2414 | case 1: | ||
2415 | ret = afs_extract_data(call, true); | ||
2416 | if (ret < 0) | ||
2417 | return ret; | ||
2418 | |||
2419 | size = call->count2 = ntohl(call->tmp); | ||
2420 | size = round_up(size, 4); | ||
2421 | |||
2422 | acl = kmalloc(struct_size(acl, data, size), GFP_KERNEL); | ||
2423 | if (!acl) | ||
2424 | return -ENOMEM; | ||
2425 | call->reply[0] = acl; | ||
2426 | acl->size = call->count2; | ||
2427 | afs_extract_begin(call, acl->data, size); | ||
2428 | call->unmarshall++; | ||
2429 | |||
2430 | /* extract the returned data */ | ||
2431 | case 2: | ||
2432 | ret = afs_extract_data(call, true); | ||
2433 | if (ret < 0) | ||
2434 | return ret; | ||
2435 | |||
2436 | afs_extract_to_buf(call, (21 + 6) * 4); | ||
2437 | call->unmarshall++; | ||
2438 | |||
2439 | /* extract the metadata */ | ||
2440 | case 3: | ||
2441 | ret = afs_extract_data(call, false); | ||
2442 | if (ret < 0) | ||
2443 | return ret; | ||
2444 | |||
2445 | bp = call->buffer; | ||
2446 | ret = afs_decode_status(call, &bp, &vnode->status, vnode, | ||
2447 | &vnode->status.data_version, NULL); | ||
2448 | if (ret < 0) | ||
2449 | return ret; | ||
2450 | xdr_decode_AFSVolSync(&bp, call->reply[2]); | ||
2451 | |||
2452 | call->unmarshall++; | ||
2453 | |||
2454 | case 4: | ||
2455 | break; | ||
2456 | } | ||
2457 | |||
2458 | _leave(" = 0 [done]"); | ||
2459 | return 0; | ||
2460 | } | ||
2461 | |||
2462 | static void afs_destroy_fs_fetch_acl(struct afs_call *call) | ||
2463 | { | ||
2464 | kfree(call->reply[0]); | ||
2465 | afs_flat_call_destructor(call); | ||
2466 | } | ||
2467 | |||
2468 | /* | ||
2469 | * FS.FetchACL operation type | ||
2470 | */ | ||
2471 | static const struct afs_call_type afs_RXFSFetchACL = { | ||
2472 | .name = "FS.FetchACL", | ||
2473 | .op = afs_FS_FetchACL, | ||
2474 | .deliver = afs_deliver_fs_fetch_acl, | ||
2475 | .destructor = afs_destroy_fs_fetch_acl, | ||
2476 | }; | ||
2477 | |||
2478 | /* | ||
2479 | * Fetch the ACL for a file. | ||
2480 | */ | ||
2481 | struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *fc) | ||
2482 | { | ||
2483 | struct afs_vnode *vnode = fc->vnode; | ||
2484 | struct afs_call *call; | ||
2485 | struct afs_net *net = afs_v2net(vnode); | ||
2486 | __be32 *bp; | ||
2487 | |||
2488 | _enter(",%x,{%llx:%llu},,", | ||
2489 | key_serial(fc->key), vnode->fid.vid, vnode->fid.vnode); | ||
2490 | |||
2491 | call = afs_alloc_flat_call(net, &afs_RXFSFetchACL, 16, (21 + 6) * 4); | ||
2492 | if (!call) { | ||
2493 | fc->ac.error = -ENOMEM; | ||
2494 | return ERR_PTR(-ENOMEM); | ||
2495 | } | ||
2496 | |||
2497 | call->key = fc->key; | ||
2498 | call->reply[0] = NULL; | ||
2499 | call->reply[1] = vnode; | ||
2500 | call->reply[2] = NULL; /* volsync */ | ||
2501 | call->ret_reply0 = true; | ||
2502 | |||
2503 | /* marshall the parameters */ | ||
2504 | bp = call->request; | ||
2505 | bp[0] = htonl(FSFETCHACL); | ||
2506 | bp[1] = htonl(vnode->fid.vid); | ||
2507 | bp[2] = htonl(vnode->fid.vnode); | ||
2508 | bp[3] = htonl(vnode->fid.unique); | ||
2509 | |||
2510 | call->cb_break = fc->cb_break; | ||
2511 | afs_use_fs_server(call, fc->cbi); | ||
2512 | trace_afs_make_fs_call(call, &vnode->fid); | ||
2513 | afs_make_call(&fc->ac, call, GFP_KERNEL); | ||
2514 | return (struct afs_acl *)afs_wait_for_call_to_complete(call, &fc->ac); | ||
2515 | } | ||
diff --git a/fs/afs/internal.h b/fs/afs/internal.h index 585a5952f608..683b802c20ea 100644 --- a/fs/afs/internal.h +++ b/fs/afs/internal.h | |||
@@ -977,6 +977,13 @@ extern int afs_fs_fetch_status(struct afs_fs_cursor *, struct afs_net *, | |||
977 | struct afs_fid *, struct afs_file_status *, | 977 | struct afs_fid *, struct afs_file_status *, |
978 | struct afs_callback *, struct afs_volsync *); | 978 | struct afs_callback *, struct afs_volsync *); |
979 | 979 | ||
980 | struct afs_acl { | ||
981 | u32 size; | ||
982 | u8 data[]; | ||
983 | }; | ||
984 | |||
985 | extern struct afs_acl *afs_fs_fetch_acl(struct afs_fs_cursor *); | ||
986 | |||
980 | /* | 987 | /* |
981 | * fs_probe.c | 988 | * fs_probe.c |
982 | */ | 989 | */ |
diff --git a/fs/afs/xattr.c b/fs/afs/xattr.c index e729ee3d4b02..b7d3d714d8ff 100644 --- a/fs/afs/xattr.c +++ b/fs/afs/xattr.c | |||
@@ -16,6 +16,7 @@ | |||
16 | #include "internal.h" | 16 | #include "internal.h" |
17 | 17 | ||
18 | static const char afs_xattr_list[] = | 18 | static const char afs_xattr_list[] = |
19 | "afs.acl\0" | ||
19 | "afs.cell\0" | 20 | "afs.cell\0" |
20 | "afs.fid\0" | 21 | "afs.fid\0" |
21 | "afs.volume"; | 22 | "afs.volume"; |
@@ -34,6 +35,57 @@ ssize_t afs_listxattr(struct dentry *dentry, char *buffer, size_t size) | |||
34 | } | 35 | } |
35 | 36 | ||
36 | /* | 37 | /* |
38 | * Get a file's ACL. | ||
39 | */ | ||
40 | static int afs_xattr_get_acl(const struct xattr_handler *handler, | ||
41 | struct dentry *dentry, | ||
42 | struct inode *inode, const char *name, | ||
43 | void *buffer, size_t size) | ||
44 | { | ||
45 | struct afs_fs_cursor fc; | ||
46 | struct afs_vnode *vnode = AFS_FS_I(inode); | ||
47 | struct afs_acl *acl = NULL; | ||
48 | struct key *key; | ||
49 | int ret; | ||
50 | |||
51 | key = afs_request_key(vnode->volume->cell); | ||
52 | if (IS_ERR(key)) | ||
53 | return PTR_ERR(key); | ||
54 | |||
55 | ret = -ERESTARTSYS; | ||
56 | if (afs_begin_vnode_operation(&fc, vnode, key)) { | ||
57 | while (afs_select_fileserver(&fc)) { | ||
58 | fc.cb_break = afs_calc_vnode_cb_break(vnode); | ||
59 | acl = afs_fs_fetch_acl(&fc); | ||
60 | } | ||
61 | |||
62 | afs_check_for_remote_deletion(&fc, fc.vnode); | ||
63 | afs_vnode_commit_status(&fc, vnode, fc.cb_break); | ||
64 | ret = afs_end_vnode_operation(&fc); | ||
65 | } | ||
66 | |||
67 | if (ret == 0) { | ||
68 | ret = acl->size; | ||
69 | if (size > 0) { | ||
70 | ret = -ERANGE; | ||
71 | if (acl->size > size) | ||
72 | return -ERANGE; | ||
73 | memcpy(buffer, acl->data, acl->size); | ||
74 | ret = acl->size; | ||
75 | } | ||
76 | kfree(acl); | ||
77 | } | ||
78 | |||
79 | key_put(key); | ||
80 | return ret; | ||
81 | } | ||
82 | |||
83 | static const struct xattr_handler afs_xattr_afs_acl_handler = { | ||
84 | .name = "afs.acl", | ||
85 | .get = afs_xattr_get_acl, | ||
86 | }; | ||
87 | |||
88 | /* | ||
37 | * Get the name of the cell on which a file resides. | 89 | * Get the name of the cell on which a file resides. |
38 | */ | 90 | */ |
39 | static int afs_xattr_get_cell(const struct xattr_handler *handler, | 91 | static int afs_xattr_get_cell(const struct xattr_handler *handler, |
@@ -123,6 +175,7 @@ static const struct xattr_handler afs_xattr_afs_volume_handler = { | |||
123 | }; | 175 | }; |
124 | 176 | ||
125 | const struct xattr_handler *afs_xattr_handlers[] = { | 177 | const struct xattr_handler *afs_xattr_handlers[] = { |
178 | &afs_xattr_afs_acl_handler, | ||
126 | &afs_xattr_afs_cell_handler, | 179 | &afs_xattr_afs_cell_handler, |
127 | &afs_xattr_afs_fid_handler, | 180 | &afs_xattr_afs_fid_handler, |
128 | &afs_xattr_afs_volume_handler, | 181 | &afs_xattr_afs_volume_handler, |