diff options
author | David Howells <dhowells@redhat.com> | 2007-04-26 15:57:07 -0700 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2007-04-26 15:57:07 -0700 |
commit | 00d3b7a4533e367b0dc2812a706db8f9f071c27f (patch) | |
tree | f0b1ae0266267cb2c54cb11aa61ad0758ce9c0f5 /fs/afs/cell.c | |
parent | 436058a49e0fb91c74454dbee9cfee6fb53b4336 (diff) |
[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/cell.c')
-rw-r--r-- | fs/afs/cell.c | 98 |
1 files changed, 77 insertions, 21 deletions
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]"); |