aboutsummaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
Diffstat (limited to 'fs')
-rw-r--r--fs/afs/Makefile1
-rw-r--r--fs/afs/afs.h27
-rw-r--r--fs/afs/callback.c5
-rw-r--r--fs/afs/cell.c98
-rw-r--r--fs/afs/cmservice.c3
-rw-r--r--fs/afs/dir.c51
-rw-r--r--fs/afs/file.c60
-rw-r--r--fs/afs/fsclient.c9
-rw-r--r--fs/afs/inode.c21
-rw-r--r--fs/afs/internal.h106
-rw-r--r--fs/afs/mntpt.c12
-rw-r--r--fs/afs/rxrpc.c137
-rw-r--r--fs/afs/security.c345
-rw-r--r--fs/afs/super.c142
-rw-r--r--fs/afs/vlclient.c6
-rw-r--r--fs/afs/vlocation.c26
-rw-r--r--fs/afs/vnode.c25
-rw-r--r--fs/afs/volume.c109
18 files changed, 945 insertions, 238 deletions
diff --git a/fs/afs/Makefile b/fs/afs/Makefile
index 66bdc219ccd..cca198b2cae 100644
--- a/fs/afs/Makefile
+++ b/fs/afs/Makefile
@@ -15,6 +15,7 @@ kafs-objs := \
mntpt.o \
proc.o \
rxrpc.o \
+ security.o \
server.o \
super.o \
vlclient.o \
diff --git a/fs/afs/afs.h b/fs/afs/afs.h
index b9d2d2ceaf4..d959092aaf4 100644
--- a/fs/afs/afs.h
+++ b/fs/afs/afs.h
@@ -14,6 +14,9 @@
#include <linux/in.h>
+#define AFS_MAXCELLNAME 64 /* maximum length of a cell name */
+#define AFS_MAXVOLNAME 64 /* maximum length of a volume name */
+
typedef unsigned afs_volid_t;
typedef unsigned afs_vnodeid_t;
typedef unsigned long long afs_dataversion_t;
@@ -75,6 +78,26 @@ struct afs_volume_info {
};
/*
+ * AFS security ACE access mask
+ */
+typedef u32 afs_access_t;
+#define AFS_ACE_READ 0x00000001U /* - permission to read a file/dir */
+#define AFS_ACE_WRITE 0x00000002U /* - permission to write/chmod a file */
+#define AFS_ACE_INSERT 0x00000004U /* - permission to create dirent in a dir */
+#define AFS_ACE_LOOKUP 0x00000008U /* - permission to lookup a file/dir in a dir */
+#define AFS_ACE_DELETE 0x00000010U /* - permission to delete a dirent from a dir */
+#define AFS_ACE_LOCK 0x00000020U /* - permission to lock a file */
+#define AFS_ACE_ADMINISTER 0x00000040U /* - permission to change ACL */
+#define AFS_ACE_USER_A 0x01000000U /* - 'A' user-defined permission */
+#define AFS_ACE_USER_B 0x02000000U /* - 'B' user-defined permission */
+#define AFS_ACE_USER_C 0x04000000U /* - 'C' user-defined permission */
+#define AFS_ACE_USER_D 0x08000000U /* - 'D' user-defined permission */
+#define AFS_ACE_USER_E 0x10000000U /* - 'E' user-defined permission */
+#define AFS_ACE_USER_F 0x20000000U /* - 'F' user-defined permission */
+#define AFS_ACE_USER_G 0x40000000U /* - 'G' user-defined permission */
+#define AFS_ACE_USER_H 0x80000000U /* - 'H' user-defined permission */
+
+/*
* AFS file status information
*/
struct afs_file_status {
@@ -87,8 +110,8 @@ struct afs_file_status {
afs_dataversion_t data_version; /* current data version */
unsigned author; /* author ID */
unsigned owner; /* owner ID */
- unsigned caller_access; /* access rights for authenticated caller */
- unsigned anon_access; /* access rights for unauthenticated caller */
+ afs_access_t caller_access; /* access rights for authenticated caller */
+ afs_access_t anon_access; /* access rights for unauthenticated caller */
umode_t mode; /* UNIX mode */
struct afs_fid parent; /* parent file ID */
time_t mtime_client; /* last time client changed data */
diff --git a/fs/afs/callback.c b/fs/afs/callback.c
index 61121554714..e674bebbb8b 100644
--- a/fs/afs/callback.c
+++ b/fs/afs/callback.c
@@ -72,7 +72,10 @@ void afs_broken_callback_work(struct work_struct *work)
return; /* someone else is dealing with it */
if (test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
- if (afs_vnode_fetch_status(vnode) < 0)
+ if (S_ISDIR(vnode->vfs_inode.i_mode))
+ afs_clear_permits(vnode);
+
+ if (afs_vnode_fetch_status(vnode, NULL, NULL) < 0)
goto out;
if (test_bit(AFS_VNODE_DELETED, &vnode->flags))
diff --git a/fs/afs/cell.c b/fs/afs/cell.c
index 733c60246ab..9b1311a1df5 100644
--- a/fs/afs/cell.c
+++ b/fs/afs/cell.c
@@ -11,6 +11,9 @@
#include <linux/module.h>
#include <linux/slab.h>
+#include <linux/key.h>
+#include <linux/ctype.h>
+#include <keys/rxrpc-type.h>
#include "internal.h"
DECLARE_RWSEM(afs_proc_cells_sem);
@@ -23,45 +26,43 @@ static DECLARE_WAIT_QUEUE_HEAD(afs_cells_freeable_wq);
static struct afs_cell *afs_cell_root;
/*
- * create a cell record
- * - "name" is the name of the cell
- * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ * allocate a cell record and fill in its name, VL server address list and
+ * allocate an anonymous key
*/
-struct afs_cell *afs_cell_create(const char *name, char *vllist)
+static struct afs_cell *afs_cell_alloc(const char *name, char *vllist)
{
struct afs_cell *cell;
- char *next;
+ size_t namelen;
+ char keyname[4 + AFS_MAXCELLNAME + 1], *cp, *dp, *next;
int ret;
_enter("%s,%s", name, vllist);
BUG_ON(!name); /* TODO: want to look up "this cell" in the cache */
+ namelen = strlen(name);
+ if (namelen > AFS_MAXCELLNAME)
+ return ERR_PTR(-ENAMETOOLONG);
+
/* allocate and initialise a cell record */
- cell = kmalloc(sizeof(struct afs_cell) + strlen(name) + 1, GFP_KERNEL);
+ cell = kzalloc(sizeof(struct afs_cell) + namelen + 1, GFP_KERNEL);
if (!cell) {
_leave(" = -ENOMEM");
return ERR_PTR(-ENOMEM);
}
- down_write(&afs_cells_sem);
+ memcpy(cell->name, name, namelen);
+ cell->name[namelen] = 0;
- memset(cell, 0, sizeof(struct afs_cell));
atomic_set(&cell->usage, 1);
-
INIT_LIST_HEAD(&cell->link);
-
rwlock_init(&cell->servers_lock);
INIT_LIST_HEAD(&cell->servers);
-
init_rwsem(&cell->vl_sem);
INIT_LIST_HEAD(&cell->vl_list);
spin_lock_init(&cell->vl_lock);
- strcpy(cell->name, name);
-
/* fill in the VL server list from the rest of the string */
- ret = -EINVAL;
do {
unsigned a, b, c, d;
@@ -70,18 +71,73 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
*next++ = 0;
if (sscanf(vllist, "%u.%u.%u.%u", &a, &b, &c, &d) != 4)
- goto badaddr;
+ goto bad_address;
if (a > 255 || b > 255 || c > 255 || d > 255)
- goto badaddr;
+ goto bad_address;
cell->vl_addrs[cell->vl_naddrs++].s_addr =
htonl((a << 24) | (b << 16) | (c << 8) | d);
- if (cell->vl_naddrs >= AFS_CELL_MAX_ADDRS)
- break;
+ } while (cell->vl_naddrs < AFS_CELL_MAX_ADDRS && (vllist = next));
+
+ /* create a key to represent an anonymous user */
+ memcpy(keyname, "afs@", 4);
+ dp = keyname + 4;
+ cp = cell->name;
+ do {
+ *dp++ = toupper(*cp);
+ } while (*cp++);
+ cell->anonymous_key = key_alloc(&key_type_rxrpc, keyname, 0, 0, current,
+ KEY_POS_SEARCH, KEY_ALLOC_NOT_IN_QUOTA);
+ if (IS_ERR(cell->anonymous_key)) {
+ _debug("no key");
+ ret = PTR_ERR(cell->anonymous_key);
+ goto error;
+ }
+
+ ret = key_instantiate_and_link(cell->anonymous_key, NULL, 0,
+ NULL, NULL);
+ if (ret < 0) {
+ _debug("instantiate failed");
+ goto error;
+ }
+
+ _debug("anon key %p{%x}",
+ cell->anonymous_key, key_serial(cell->anonymous_key));
+
+ _leave(" = %p", cell);
+ return cell;
+
+bad_address:
+ printk(KERN_ERR "kAFS: bad VL server IP address\n");
+ ret = -EINVAL;
+error:
+ key_put(cell->anonymous_key);
+ kfree(cell);
+ _leave(" = %d", ret);
+ return ERR_PTR(ret);
+}
- } while ((vllist = next));
+/*
+ * create a cell record
+ * - "name" is the name of the cell
+ * - "vllist" is a colon separated list of IP addresses in "a.b.c.d" format
+ */
+struct afs_cell *afs_cell_create(const char *name, char *vllist)
+{
+ struct afs_cell *cell;
+ int ret;
+
+ _enter("%s,%s", name, vllist);
+
+ cell = afs_cell_alloc(name, vllist);
+ if (IS_ERR(cell)) {
+ _leave(" = %ld", PTR_ERR(cell));
+ return cell;
+ }
+
+ down_write(&afs_cells_sem);
/* add a proc directory for this cell */
ret = afs_proc_cell_setup(cell);
@@ -109,10 +165,9 @@ struct afs_cell *afs_cell_create(const char *name, char *vllist)
_leave(" = %p", cell);
return cell;
-badaddr:
- printk(KERN_ERR "kAFS: bad VL server IP address\n");
error:
up_write(&afs_cells_sem);
+ key_put(cell->anonymous_key);
kfree(cell);
_leave(" = %d", ret);
return ERR_PTR(ret);
@@ -301,6 +356,7 @@ static void afs_cell_destroy(struct afs_cell *cell)
cachefs_relinquish_cookie(cell->cache, 0);
#endif
+ key_put(cell->anonymous_key);
kfree(cell);
_leave(" [destroyed]");
diff --git a/fs/afs/cmservice.c b/fs/afs/cmservice.c
index c7141175391..c3ec57a237b 100644
--- a/fs/afs/cmservice.c
+++ b/fs/afs/cmservice.c
@@ -28,6 +28,7 @@ static void afs_cm_destructor(struct afs_call *);
* CB.CallBack operation type
*/
static const struct afs_call_type afs_SRXCBCallBack = {
+ .name = "CB.CallBack",
.deliver = afs_deliver_cb_callback,
.abort_to_error = afs_abort_to_error,
.destructor = afs_cm_destructor,
@@ -37,6 +38,7 @@ static const struct afs_call_type afs_SRXCBCallBack = {
* CB.InitCallBackState operation type
*/
static const struct afs_call_type afs_SRXCBInitCallBackState = {
+ .name = "CB.InitCallBackState",
.deliver = afs_deliver_cb_init_call_back_state,
.abort_to_error = afs_abort_to_error,
.destructor = afs_cm_destructor,
@@ -46,6 +48,7 @@ static const struct afs_call_type afs_SRXCBInitCallBackState = {
* CB.Probe operation type
*/
static const struct afs_call_type afs_SRXCBProbe = {
+ .name = "CB.Probe",
.deliver = afs_deliver_cb_probe,
.abort_to_error = afs_abort_to_error,
.destructor = afs_cm_destructor,
diff --git a/fs/afs/dir.c b/fs/afs/dir.c
index d7697f6f3b7..87368417e4d 100644
--- a/fs/afs/dir.c
+++ b/fs/afs/dir.c
@@ -15,6 +15,7 @@
#include <linux/slab.h>
#include <linux/fs.h>
#include <linux/pagemap.h>
+#include <linux/ctype.h>
#include "internal.h"
static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
@@ -28,11 +29,13 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
const struct file_operations afs_dir_file_operations = {
.open = afs_dir_open,
+ .release = afs_release,
.readdir = afs_dir_readdir,
};
const struct inode_operations afs_dir_inode_operations = {
.lookup = afs_dir_lookup,
+ .permission = afs_permission,
.getattr = afs_inode_getattr,
#if 0 /* TODO */
.create = afs_dir_create,
@@ -169,13 +172,17 @@ static inline void afs_dir_put_page(struct page *page)
/*
* get a page into the pagecache
*/
-static struct page *afs_dir_get_page(struct inode *dir, unsigned long index)
+static struct page *afs_dir_get_page(struct inode *dir, unsigned long index,
+ struct key *key)
{
struct page *page;
+ struct file file = {
+ .private_data = key,
+ };
_enter("{%lu},%lu", dir->i_ino, index);
- page = read_mapping_page(dir->i_mapping, index, NULL);
+ page = read_mapping_page(dir->i_mapping, index, &file);
if (!IS_ERR(page)) {
wait_on_page_locked(page);
kmap(page);
@@ -207,8 +214,7 @@ static int afs_dir_open(struct inode *inode, struct file *file)
if (test_bit(AFS_VNODE_DELETED, &AFS_FS_I(inode)->flags))
return -ENOENT;
- _leave(" = 0");
- return 0;
+ return afs_open(inode, file);
}
/*
@@ -311,7 +317,7 @@ static int afs_dir_iterate_block(unsigned *fpos,
* iterate through the data blob that lists the contents of an AFS directory
*/
static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
- filldir_t filldir)
+ filldir_t filldir, struct key *key)
{
union afs_dir_block *dblock;
struct afs_dir_page *dbuf;
@@ -336,7 +342,7 @@ static int afs_dir_iterate(struct inode *dir, unsigned *fpos, void *cookie,
blkoff = *fpos & ~(sizeof(union afs_dir_block) - 1);
/* fetch the appropriate page from the directory */
- page = afs_dir_get_page(dir, blkoff / PAGE_SIZE);
+ page = afs_dir_get_page(dir, blkoff / PAGE_SIZE, key);
if (IS_ERR(page)) {
ret = PTR_ERR(page);
break;
@@ -381,9 +387,11 @@ static int afs_dir_readdir(struct file *file, void *cookie, filldir_t filldir)
_enter("{%Ld,{%lu}}",
file->f_pos, file->f_path.dentry->d_inode->i_ino);
+ ASSERT(file->private_data != NULL);
+
fpos = file->f_pos;
ret = afs_dir_iterate(file->f_path.dentry->d_inode, &fpos,
- cookie, filldir);
+ cookie, filldir, file->private_data);
file->f_pos = fpos;
_leave(" = %d", ret);
@@ -424,7 +432,7 @@ static int afs_dir_lookup_filldir(void *_cookie, const char *name, int nlen,
* do a lookup in a directory
*/
static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
- struct afs_fid *fid)
+ struct afs_fid *fid, struct key *key)
{
struct afs_dir_lookup_cookie cookie;
struct afs_super_info *as;
@@ -442,7 +450,8 @@ static int afs_do_lookup(struct inode *dir, struct dentry *dentry,
cookie.found = 0;
fpos = 0;
- ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir);
+ ret = afs_dir_iterate(dir, &fpos, &cookie, afs_dir_lookup_filldir,
+ key);
if (ret < 0) {
_leave(" = %d [iter]", ret);
return ret;
@@ -468,6 +477,7 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
struct afs_vnode *vnode;
struct afs_fid fid;
struct inode *inode;
+ struct key *key;
int ret;
_enter("{%lu},%p{%s}", dir->i_ino, dentry, dentry->d_name.name);
@@ -483,14 +493,22 @@ static struct dentry *afs_dir_lookup(struct inode *dir, struct dentry *dentry,
return ERR_PTR(-ESTALE);
}
- ret = afs_do_lookup(dir, dentry, &fid);
+ key = afs_request_key(vnode->volume->cell);
+ if (IS_ERR(key)) {
+ _leave(" = %ld [key]", PTR_ERR(key));
+ return ERR_PTR(PTR_ERR(key));
+ }
+
+ ret = afs_do_lookup(dir, dentry, &fid, key);
if (ret < 0) {
+ key_put(key);
_leave(" = %d [do]", ret);
return ERR_PTR(ret);
}
/* instantiate the dentry */
- inode = afs_iget(dir->i_sb, &fid);
+ inode = afs_iget(dir->i_sb, key, &fid);
+ key_put(key);
if (IS_ERR(inode)) {
_leave(" = %ld", PTR_ERR(inode));
return ERR_PTR(PTR_ERR(inode));
@@ -559,6 +577,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
struct afs_fid fid;
struct dentry *parent;
struct inode *inode, *dir;
+ struct key *key;
int ret;
vnode = AFS_FS_I(dentry->d_inode);
@@ -566,6 +585,10 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
_enter("{sb=%p n=%s fl=%lx},",
dentry->d_sb, dentry->d_name.name, vnode->flags);
+ key = afs_request_key(vnode->volume->cell);
+ if (IS_ERR(key))
+ key = NULL;
+
/* lock down the parent dentry so we can peer at it */
parent = dget_parent(dentry);
@@ -595,7 +618,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
_debug("dir modified");
/* search the directory for this vnode */
- ret = afs_do_lookup(dir, dentry, &fid);
+ ret = afs_do_lookup(dir, dentry, &fid, key);
if (ret == -ENOENT) {
_debug("%s: dirent not found", dentry->d_name.name);
goto not_found;
@@ -637,7 +660,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
test_bit(AFS_VNODE_CB_BROKEN, &vnode->flags)) {
_debug("%s: changed", dentry->d_name.name);
set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
- if (afs_vnode_fetch_status(vnode) < 0) {
+ if (afs_vnode_fetch_status(vnode, NULL, key) < 0) {
mutex_unlock(&vnode->cb_broken_lock);
goto out_bad;
}
@@ -667,6 +690,7 @@ static int afs_d_revalidate(struct dentry *dentry, struct nameidata *nd)
out_valid:
dput(parent);
+ key_put(key);
_leave(" = 1 [valid]");
return 1;
@@ -688,6 +712,7 @@ out_bad:
shrink_dcache_parent(dentry);
d_drop(dentry);
dput(parent);
+ key_put(key);
_leave(" = 0 [bad]");
return 0;
diff --git a/fs/afs/file.c b/fs/afs/file.c
index 6990327e75d..101bbb8c0d8 100644
--- a/fs/afs/file.c
+++ b/fs/afs/file.c
@@ -17,17 +17,23 @@
#include <linux/pagemap.h>
#include "internal.h"
-#if 0
-static int afs_file_open(struct inode *inode, struct file *file);
-static int afs_file_release(struct inode *inode, struct file *file);
-#endif
-
static int afs_file_readpage(struct file *file, struct page *page);
static void afs_file_invalidatepage(struct page *page, unsigned long offset);
static int afs_file_releasepage(struct page *page, gfp_t gfp_flags);
+const struct file_operations afs_file_operations = {
+ .open = afs_open,
+ .release = afs_release,
+ .llseek = generic_file_llseek,
+ .read = do_sync_read,
+ .aio_read = generic_file_aio_read,
+ .mmap = generic_file_readonly_mmap,
+ .sendfile = generic_file_sendfile,
+};
+
const struct inode_operations afs_file_inode_operations = {
.getattr = afs_inode_getattr,
+ .permission = afs_permission,
};
const struct address_space_operations afs_fs_aops = {
@@ -38,6 +44,41 @@ const struct address_space_operations afs_fs_aops = {
};
/*
+ * open an AFS file or directory and attach a key to it
+ */
+int afs_open(struct inode *inode, struct file *file)
+{
+ struct afs_vnode *vnode = AFS_FS_I(inode);
+ struct key *key;
+
+ _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+
+ key = afs_request_key(vnode->volume->cell);
+ if (IS_ERR(key)) {
+ _leave(" = %ld [key]", PTR_ERR(key));
+ return PTR_ERR(key);
+ }
+
+ file->private_data = key;
+ _leave(" = 0");
+ return 0;
+}
+
+/*
+ * release an AFS file or directory and discard its key
+ */
+int afs_release(struct inode *inode, struct file *file)
+{
+ struct afs_vnode *vnode = AFS_FS_I(inode);
+
+ _enter("{%x:%x},", vnode->fid.vid, vnode->fid.vnode);
+
+ key_put(file->private_data);
+ _leave(" = 0");
+ return 0;
+}
+
+/*
* deal with notification that a page was read from the cache
*/
#ifdef AFS_CACHING_SUPPORT
@@ -79,13 +120,18 @@ static int afs_file_readpage(struct file *file, struct page *page)
{
struct afs_vnode *vnode;
struct inode *inode;
+ struct key *key;
size_t len;
off_t offset;
int ret;
inode = page->mapping->host;
- _enter("{%lu},{%lu}", inode->i_ino, page->index);
+ ASSERT(file != NULL);
+ key = file->private_data;
+ ASSERT(key != NULL);
+
+ _enter("{%x},{%lu},{%lu}", key_serial(key), inode->i_ino, page->index);
vnode = AFS_FS_I(inode);
@@ -124,7 +170,7 @@ static int afs_file_readpage(struct file *file, struct page *page)
/* read the contents of the file from the server into the
* page */
- ret = afs_vnode_fetch_data(vnode, offset, len, page);
+ ret = afs_vnode_fetch_data(vnode, key, offset, len, page);
if (ret < 0) {
if (ret == -ENOENT) {
_debug("got NOENT from server"
diff --git a/fs/afs/fsclient.c b/fs/afs/fsclient.c
index 167ca615c2e..321b489aa90 100644
--- a/fs/afs/fsclient.c
+++ b/fs/afs/fsclient.c
@@ -148,6 +148,7 @@ static int afs_deliver_fs_fetch_status(struct afs_call *call,
* FS.FetchStatus operation type
*/
static const struct afs_call_type afs_RXFSFetchStatus = {
+ .name = "FS.FetchStatus",
.deliver = afs_deliver_fs_fetch_status,
.abort_to_error = afs_abort_to_error,
.destructor = afs_flat_call_destructor,
@@ -157,6 +158,7 @@ static const struct afs_call_type afs_RXFSFetchStatus = {
* fetch the status information for a file
*/
int afs_fs_fetch_file_status(struct afs_server *server,
+ struct key *key,
struct afs_vnode *vnode,
struct afs_volsync *volsync,
const struct afs_wait_mode *wait_mode)
@@ -164,12 +166,13 @@ int afs_fs_fetch_file_status(struct afs_server *server,
struct afs_call *call;
__be32 *bp;
- _enter("");
+ _enter(",%x,,,", key_serial(key));
call = afs_alloc_flat_call(&afs_RXFSFetchStatus, 16, 120);
if (!call)
return -ENOMEM;
+ call->key = key;
call->reply = vnode;
call->reply2 = volsync;
call->service_id = FS_SERVICE;
@@ -279,6 +282,7 @@ static int afs_deliver_fs_fetch_data(struct afs_call *call,
* FS.FetchData operation type
*/
static const struct afs_call_type afs_RXFSFetchData = {
+ .name = "FS.FetchData",
.deliver = afs_deliver_fs_fetch_data,
.abort_to_error = afs_abort_to_error,
.destructor = afs_flat_call_destructor,
@@ -288,6 +292,7 @@ static const struct afs_call_type afs_RXFSFetchData = {
* fetch data from a file
*/
int afs_fs_fetch_data(struct afs_server *server,
+ struct key *key,
struct afs_vnode *vnode,
off_t offset, size_t length,
struct page *buffer,
@@ -303,6 +308,7 @@ int afs_fs_fetch_data(struct afs_server *server,
if (!call)
return -ENOMEM;
+ call->key = key;
call->reply = vnode;
call->reply2 = volsync;
call->reply3 = buffer;
@@ -338,6 +344,7 @@ static int afs_deliver_fs_give_up_callbacks(struct afs_call *call,
* FS.GiveUpCallBacks operation type
*/
static const struct afs_call_type afs_RXFSGiveUpCallBacks = {
+ .name = "FS.GiveUpCallBacks",
.deliver = afs_deliver_fs_give_up_callbacks,
.abort_to_error = afs_abort_to_error,
.destructor = afs_flat_call_destructor,
diff --git a/fs/afs/inode.c b/fs/afs/inode.c
index 18863315211..22733622829 100644
--- a/fs/afs/inode.c
+++ b/fs/afs/inode.c
@@ -29,7 +29,7 @@ struct afs_iget_data {
/*
* map the AFS file status to the inode member variables
*/
-static int afs_inode_map_status(struct afs_vnode *vnode)
+static int afs_inode_map_status(struct afs_vnode *vnode, struct key *key)
{
struct inode *inode = AFS_VNODE_TO_I(vnode);
@@ -44,7 +44,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
case AFS_FTYPE_FILE:
inode->i_mode = S_IFREG | vnode->status.mode;
inode->i_op = &afs_file_inode_operations;
- inode->i_fop = &generic_ro_fops;
+ inode->i_fop = &afs_file_operations;
break;
case AFS_FTYPE_DIR:
inode->i_mode = S_IFDIR | vnode->status.mode;
@@ -73,7 +73,7 @@ static int afs_inode_map_status(struct afs_vnode *vnode)
/* check to see whether a symbolic link is really a mountpoint */
if (vnode->status.type == AFS_FTYPE_SYMLINK) {
- afs_mntpt_check_symlink(vnode);
+ afs_mntpt_check_symlink(vnode, key);
if (test_bit(AFS_VNODE_MOUNTPOINT, &vnode->flags)) {
inode->i_mode = S_IFDIR | vnode->status.mode;
@@ -115,7 +115,8 @@ static int afs_iget5_set(struct inode *inode, void *opaque)
/*
* inode retrieval
*/
-inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid)
+inline struct inode *afs_iget(struct super_block *sb, struct key *key,
+ struct afs_fid *fid)
{
struct afs_iget_data data = { .fid = *fid };
struct afs_super_info *as;
@@ -157,10 +158,10 @@ inline struct inode *afs_iget(struct super_block *sb, struct afs_fid *fid)
/* okay... it's a new inode */
set_bit(AFS_VNODE_CB_BROKEN, &vnode->flags);
- ret = afs_vnode_fetch_status(vnode);
+ ret = afs_vnode_fetch_status(vnode, NULL, key);
if (ret < 0)
goto bad_inode;
- ret = afs_inode_map_status(vnode);
+ ret = afs_inode_map_status(vnode, key);
if (ret < 0)
goto bad_inode;
@@ -201,6 +202,7 @@ int afs_inode_getattr(struct vfsmount *mnt, struct dentry *dentry,
*/
void afs_clear_inode(struct inode *inode)
{
+ struct afs_permits *permits;
struct afs_vnode *vnode;
vnode = AFS_FS_I(inode);
@@ -233,5 +235,12 @@ void afs_clear_inode(struct inode *inode)
vnode->cache = NULL;
#endif
+ mutex_lock(&vnode->permits_lock);
+ permits = vnode->permits;
+ rcu_assign_pointer(vnode->permits, NULL);
+ mutex_unlock(&vnode->permits_lock);
+ if (permits)
+ call_rcu(&permits->rcu, afs_zap_permits);
+
_leave("");
}
diff --git a/fs/afs/internal.h b/fs/afs/internal.h
index afc6f0f3025..8bed2429d01 100644
--- a/fs/afs/internal.h
+++ b/fs/afs/internal.h
@@ -15,6 +15,7 @@
#include <linux/pagemap.h>
#include <linux/skbuff.h>
#include <linux/rxrpc.h>
+#include <linux/key.h>
#include "afs.h"
#include "afs_vl.h"
@@ -32,6 +33,17 @@ typedef enum {
AFS_VL_UNCERTAIN, /* uncertain state (update failed) */
} __attribute__((packed)) afs_vlocation_state_t;
+struct afs_mount_params {
+ bool rwpath; /* T if the parent should be considered R/W */
+ bool force; /* T to force cell type */
+ afs_voltype_t type; /* type of volume requested */
+ int volnamesz; /* size of volume name */
+ const char *volname; /* name of volume to mount */
+ struct afs_cell *cell; /* cell in which to find volume */
+ struct afs_volume *volume; /* volume record */
+ struct key *key; /* key to use for secure mounting */
+};
+
/*
* definition of how to wait for the completion of an operation
*/
@@ -95,6 +107,8 @@ struct afs_call {
};
struct afs_call_type {
+ const char *name;
+
/* deliver request or reply data to an call
* - returning an error will cause the call to be aborted
*/
@@ -128,8 +142,8 @@ extern struct file_system_type afs_fs_type;
* entry in the cached cell catalogue
*/
struct afs_cache_cell {
- char name[64]; /* cell name (padded with NULs) */
- struct in_addr vl_servers[15]; /* cached cell VL servers */
+ char name[AFS_MAXCELLNAME]; /* cell name (padded with NULs) */
+ struct in_addr vl_servers[15]; /* cached cell VL servers */
};
/*
@@ -138,6 +152,7 @@ struct afs_cache_cell {
struct afs_cell {
atomic_t usage;
struct list_head link; /* main cell list link */
+ struct key *anonymous_key; /* anonymous user key for this cell */
struct list_head proc_link; /* /proc cell list link */
struct proc_dir_entry *proc_dir; /* /proc dir for this cell */
#ifdef AFS_CACHING_SUPPORT
@@ -163,7 +178,9 @@ struct afs_cell {
* entry in the cached volume location catalogue
*/
struct afs_cache_vlocation {
- uint8_t name[64 + 1]; /* volume name (lowercase, padded with NULs) */
+ /* volume name (lowercase, padded with NULs) */
+ uint8_t name[AFS_MAXVOLNAME + 1];
+
uint8_t nservers; /* number of entries used in servers[] */
uint8_t vidmask; /* voltype mask for vid[] */
uint8_t srvtmask[8]; /* voltype masks for servers[] */
@@ -281,7 +298,8 @@ struct afs_vnode {
#ifdef AFS_CACHING_SUPPORT
struct cachefs_cookie *cache; /* caching cookie */
#endif
-
+ struct afs_permits *permits; /* cache of permits so far obtained */
+ struct mutex permits_lock; /* lock for altering permits list */
wait_queue_head_t update_waitq; /* status fetch waitqueue */
unsigned update_cnt; /* number of outstanding ops that will update the
* status */
@@ -296,12 +314,13 @@ struct afs_vnode {
#define AFS_VNODE_DIR_CHANGED 6 /* set if vnode's parent dir metadata changed */
#define AFS_VNODE_DIR_MODIFIED 7 /* set if vnode's parent dir data modified */
+ long acl_order; /* ACL check count (callback break count) */
+
/* outstanding callback notification on this file */
struct rb_node server_rb; /* link in server->fs_vnodes */
struct rb_node cb_promise; /* link in server->cb_promises */
struct work_struct cb_broken_work; /* work to be done on callback break */
struct mutex cb_broken_lock; /* lock against multiple attempts to fix break */
-// struct list_head cb_hash_link; /* link in master callback hash */
time_t cb_expires; /* time at which callback expires */
time_t cb_expires_at; /* time used to order cb_promise */
unsigned cb_version; /* callback version */
@@ -310,6 +329,23 @@ struct afs_vnode {
bool cb_promised; /* true if promise still holds */
};
+/*
+ * cached security record for one user's attempt to access a vnode
+ */
+struct afs_permit {
+ struct key *key; /* RxRPC ticket holding a security context */
+ afs_access_t access_mask; /* access mask for this key */
+};
+
+/*
+ * cache of security records from attempts to access a vnode
+ */
+struct afs_permits {
+ struct rcu_head rcu; /* disposal procedure */
+ int count; /* number of records */
+ struct afs_permit permits[0]; /* the permits so far examined */
+};
+
/*****************************************************************************/
/*
* callback.c
@@ -352,11 +388,17 @@ extern bool afs_cm_incoming_call(struct afs_call *);
extern const struct inode_operations afs_dir_inode_operations;
extern const struct file_operations afs_dir_file_operations;
+extern int afs_permission(struct inode *, int, struct nameidata *);
+
/*
* file.c
*/
extern const struct address_space_operations afs_fs_aops;
extern const struct inode_operations afs_file_inode_operations;
+extern const struct file_operations afs_file_operations;
+
+extern int afs_open(struct inode *, struct file *);
+extern int afs_release(struct inode *, struct file *);
#ifdef AFS_CACHING_SUPPORT
extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
@@ -365,22 +407,24 @@ extern int afs_cache_get_page_cookie(struct page *, struct cachefs_page **);
/*
* fsclient.c
*/
-extern int afs_fs_fetch_file_status(struct afs_server *,
- struct afs_vnode *,
- struct afs_volsync *,
+extern int afs_fs_fetch_file_status(struct afs_server *, struct key *,
+ struct afs_vnode *, struct afs_volsync *,
const struct afs_wait_mode *);
extern int afs_fs_give_up_callbacks(struct afs_server *,
const struct afs_wait_mode *);
-extern int afs_fs_fetch_data(struct afs_server *, struct afs_vnode *, off_t,
- size_t, struct page *, struct afs_volsync *,
+extern int afs_fs_fetch_data(struct afs_server *, struct key *,
+ struct afs_vnode *, off_t, size_t, struct page *,
+ struct afs_volsync *,
const struct afs_wait_mode *);
/*
* inode.c
*/
-extern struct inode *afs_iget(struct super_block *, struct afs_fid *);
+extern struct inode *afs_iget(struct super_block *, struct key *,
+ struct afs_fid *);
extern int afs_inode_getattr(struct vfsmount *, struct dentry *,
struct kstat *);
+extern void afs_zap_permits(struct rcu_head *);
extern void afs_clear_inode(struct inode *);
/*
@@ -402,17 +446,11 @@ extern const struct inode_operations afs_mntpt_inode_operations;
extern const struct file_operations afs_mntpt_file_operations;
extern unsigned long afs_mntpt_expiry_timeout;
-extern int afs_mntpt_check_symlink(struct afs_vnode *);
+extern int afs_mntpt_check_symlink(struct afs_vnode *, struct key *);
extern void afs_mntpt_kill_timer(void);
extern void afs_umount_begin(struct vfsmount *, int);
/*
- * super.c
- */
-extern int afs_fs_init(void);
-extern void afs_fs_exit(void);
-
-/*
* proc.c
*/
extern int afs_proc_init(void);
@@ -436,6 +474,14 @@ extern int afs_extract_data(struct afs_call *, struct sk_buff *, bool, void *,
size_t);
/*
+ * security.c
+ */
+extern void afs_clear_permits(struct afs_vnode *);
+extern void afs_cache_permit(struct afs_vnode *, struct key *, long);
+extern struct key *afs_request_key(struct afs_cell *);
+extern int afs_permission(struct inode *, int, struct nameidata *);
+
+/*
* server.c
*/
extern spinlock_t afs_server_peer_lock;
@@ -449,16 +495,23 @@ extern void afs_put_server(struct afs_server *);
extern void __exit afs_purge_servers(void);
/*
+ * super.c
+ */
+extern int afs_fs_init(void);
+extern void afs_fs_exit(void);
+
+/*
* vlclient.c
*/
#ifdef AFS_CACHING_SUPPORT
extern struct cachefs_index_def afs_vlocation_cache_index_def;
#endif
-extern int afs_vl_get_entry_by_name(struct in_addr *, const char *,
- struct afs_cache_vlocation *,
+extern int afs_vl_get_entry_by_name(struct in_addr *, struct key *,
+ const char *, struct afs_cache_vlocation *,
const struct afs_wait_mode *);
-extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t,
+extern int afs_vl_get_entry_by_id(struct in_addr *, struct key *,
+ afs_volid_t, afs_voltype_t,
struct afs_cache_vlocation *,
const struct afs_wait_mode *);
@@ -469,6 +522,7 @@ extern int afs_vl_get_entry_by_id(struct in_addr *, afs_volid_t, afs_voltype_t,
extern int __init afs_vlocation_update_init(void);
extern struct afs_vlocation *afs_vlocatio