Skip to content

Commit

Permalink
[AFS]: Add security support.
Browse files Browse the repository at this point in the history
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 <[email protected]>
Signed-off-by: David S. Miller <[email protected]>
  • Loading branch information
dhowells authored and davem330 committed Apr 26, 2007
1 parent 436058a commit 00d3b7a
Show file tree
Hide file tree
Showing 18 changed files with 945 additions and 238 deletions.
1 change: 1 addition & 0 deletions fs/afs/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ kafs-objs := \
mntpt.o \
proc.o \
rxrpc.o \
security.o \
server.o \
super.o \
vlclient.o \
Expand Down
27 changes: 25 additions & 2 deletions fs/afs/afs.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,6 +77,26 @@ struct afs_volume_info {
} servers[8];
};

/*
* 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
*/
Expand All @@ -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 */
Expand Down
5 changes: 4 additions & 1 deletion fs/afs/callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -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))
Expand Down
98 changes: 77 additions & 21 deletions fs/afs/cell.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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;

Expand All @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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]");
Expand Down
3 changes: 3 additions & 0 deletions fs/afs/cmservice.c
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
Expand All @@ -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,
Expand Down
Loading

0 comments on commit 00d3b7a

Please sign in to comment.