summaryrefslogtreecommitdiffstats
path: root/fs/afs/super.c
diff options
context:
space:
mode:
authorDavid Howells <dhowells@redhat.com>2007-04-27 00:57:07 +0200
committerDavid S. Miller <davem@davemloft.net>2007-04-27 00:57:07 +0200
commit00d3b7a4533e367b0dc2812a706db8f9f071c27f (patch)
treef0b1ae0266267cb2c54cb11aa61ad0758ce9c0f5 /fs/afs/super.c
parent[AFS]: Handle multiple mounts of an AFS superblock correctly. (diff)
downloadlinux-00d3b7a4533e367b0dc2812a706db8f9f071c27f.tar.xz
linux-00d3b7a4533e367b0dc2812a706db8f9f071c27f.zip
[AFS]: Add security support.
Add security support to the AFS filesystem. Kerberos IV tickets are added as RxRPC keys are added to the session keyring with the klog program. open() and other VFS operations then find this ticket with request_key() and either use it immediately (eg: mkdir, unlink) or attach it to a file descriptor (open). Signed-off-by: David Howells <dhowells@redhat.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'fs/afs/super.c')
-rw-r--r--fs/afs/super.c142
1 files changed, 120 insertions, 22 deletions
diff --git a/fs/afs/super.c b/fs/afs/super.c
index 77e68759788f..497350a5463b 100644
--- a/fs/afs/super.c
+++ b/fs/afs/super.c
@@ -24,12 +24,6 @@
#define AFS_FS_MAGIC 0x6B414653 /* 'kAFS' */
-struct afs_mount_params {
- int rwpath;
- struct afs_cell *default_cell;
- struct afs_volume *volume;
-};
-
static void afs_i_init_once(void *foo, struct kmem_cache *cachep,
unsigned long flags);
@@ -150,8 +144,8 @@ static int want_no_value(char *const *_value, const char *option)
* - this function has been shamelessly adapted from the ext3 fs which
* shamelessly adapted it from the msdos fs
*/
-static int afs_super_parse_options(struct afs_mount_params *params,
- char *options, const char **devname)
+static int afs_parse_options(struct afs_mount_params *params,
+ char *options, const char **devname)
{
struct afs_cell *cell;
char *key, *value;
@@ -183,8 +177,8 @@ static int afs_super_parse_options(struct afs_mount_params *params,
cell = afs_cell_lookup(value, strlen(value));
if (IS_ERR(cell))
return PTR_ERR(cell);
- afs_put_cell(params->default_cell);
- params->default_cell = cell;
+ afs_put_cell(params->cell);
+ params->cell = cell;
} else {
printk("kAFS: Unknown mount option: '%s'\n", key);
ret = -EINVAL;
@@ -199,6 +193,99 @@ error:
}
/*
+ * parse a device name to get cell name, volume name, volume type and R/W
+ * selector
+ * - this can be one of the following:
+ * "%[cell:]volume[.]" R/W volume
+ * "#[cell:]volume[.]" R/O or R/W volume (rwpath=0),
+ * or R/W (rwpath=1) volume
+ * "%[cell:]volume.readonly" R/O volume
+ * "#[cell:]volume.readonly" R/O volume
+ * "%[cell:]volume.backup" Backup volume
+ * "#[cell:]volume.backup" Backup volume
+ */
+static int afs_parse_device_name(struct afs_mount_params *params,
+ const char *name)
+{
+ struct afs_cell *cell;
+ const char *cellname, *suffix;
+ int cellnamesz;
+
+ _enter(",%s", name);
+
+ if (!name) {
+ printk(KERN_ERR "kAFS: no volume name specified\n");
+ return -EINVAL;
+ }
+
+ if ((name[0] != '%' && name[0] != '#') || !name[1]) {
+ printk(KERN_ERR "kAFS: unparsable volume name\n");
+ return -EINVAL;
+ }
+
+ /* determine the type of volume we're looking for */
+ params->type = AFSVL_ROVOL;
+ params->force = false;
+ if (params->rwpath || name[0] == '%') {
+ params->type = AFSVL_RWVOL;
+ params->force = true;
+ }
+ name++;
+
+ /* split the cell name out if there is one */
+ params->volname = strchr(name, ':');
+ if (params->volname) {
+ cellname = name;
+ cellnamesz = params->volname - name;
+ params->volname++;
+ } else {
+ params->volname = name;
+ cellname = NULL;
+ cellnamesz = 0;
+ }
+
+ /* the volume type is further affected by a possible suffix */
+ suffix = strrchr(params->volname, '.');
+ if (suffix) {
+ if (strcmp(suffix, ".readonly") == 0) {
+ params->type = AFSVL_ROVOL;
+ params->force = true;
+ } else if (strcmp(suffix, ".backup") == 0) {
+ params->type = AFSVL_BACKVOL;
+ params->force = true;
+ } else if (suffix[1] == 0) {
+ } else {
+ suffix = NULL;
+ }
+ }
+
+ params->volnamesz = suffix ?
+ suffix - params->volname : strlen(params->volname);
+
+ _debug("cell %*.*s [%p]",
+ cellnamesz, cellnamesz, cellname ?: "", params->cell);
+
+ /* lookup the cell record */
+ if (cellname || !params->cell) {
+ cell = afs_cell_lookup(cellname, cellnamesz);
+ if (IS_ERR(cell)) {
+ printk(KERN_ERR "kAFS: unable to lookup cell '%s'\n",
+ cellname ?: "");
+ return PTR_ERR(cell);
+ }
+ afs_put_cell(params->cell);
+ params->cell = cell;
+ }
+
+ _debug("CELL:%s [%p] VOLUME:%*.*s SUFFIX:%s TYPE:%d%s",
+ params->cell->name, params->cell,
+ params->volnamesz, params->volnamesz, params->volname,
+ suffix ?: "-", params->type, params->force ? " FORCE" : "");
+
+ return 0;
+}
+
+/*
* check a superblock to see if it's the one we're looking for
*/
static int afs_test_super(struct super_block *sb, void *data)
@@ -244,7 +331,7 @@ static int afs_fill_super(struct super_block *sb, void *data)
fid.vid = as->volume->vid;
fid.vnode = 1;
fid.unique = 1;
- inode = afs_iget(sb, &fid);
+ inode = afs_iget(sb, params->key, &fid);
if (IS_ERR(inode))
goto error_inode;
@@ -285,31 +372,40 @@ static int afs_get_sb(struct file_system_type *fs_type,
struct afs_mount_params params;
struct super_block *sb;
struct afs_volume *vol;
+ struct key *key;
int ret;
_enter(",,%s,%p", dev_name, options);
memset(&params, 0, sizeof(params));
- /* parse the options */
+ /* parse the options and device name */
if (options) {
- ret = afs_super_parse_options(&params, options, &dev_name);
+ ret = afs_parse_options(&params, options, &dev_name);
if (ret < 0)
goto error;
- if (!dev_name) {
- printk("kAFS: no volume name specified\n");
- ret = -EINVAL;
- goto error;
- }
}
+
+ ret = afs_parse_device_name(&params, dev_name);
+ if (ret < 0)
+ goto error;
+
+ /* try and do the mount securely */
+ key = afs_request_key(params.cell);
+ if (IS_ERR(key)) {
+ _leave(" = %ld [key]", PTR_ERR(key));
+ ret = PTR_ERR(key);
+ goto error;
+ }
+ params.key = key;
+
/* parse the device name */
- vol = afs_volume_lookup(dev_name, params.default_cell, params.rwpath);
+ vol = afs_volume_lookup(&params);
if (IS_ERR(vol)) {
ret = PTR_ERR(vol);
goto error;
}
-
params.volume = vol;
/* allocate a deviceless superblock */
@@ -337,13 +433,14 @@ static int afs_get_sb(struct file_system_type *fs_type,
simple_set_mnt(mnt, sb);
afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
+ afs_put_cell(params.cell);
_leave(" = 0 [%p]", sb);
return 0;
error:
afs_put_volume(params.volume);
- afs_put_cell(params.default_cell);
+ afs_put_cell(params.cell);
+ key_put(params.key);
_leave(" = %d", ret);
return ret;
}
@@ -375,6 +472,7 @@ static void afs_i_init_once(void *_vnode, struct kmem_cache *cachep,
memset(vnode, 0, sizeof(*vnode));
inode_init_once(&vnode->vfs_inode);
init_waitqueue_head(&vnode->update_waitq);
+ mutex_init(&vnode->permits_lock);
spin_lock_init(&vnode->lock);
INIT_WORK(&vnode->cb_broken_work, afs_broken_callback_work);
mutex_init(&vnode->cb_broken_lock);