Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 00d3b7a4 authored by David Howells's avatar David Howells Committed by David S. Miller
Browse files

[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: default avatarDavid Howells <dhowells@redhat.com>
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parent 436058a4
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@ kafs-objs := \
	mntpt.o \
	proc.o \
	rxrpc.o \
	security.o \
	server.o \
	super.o \
	vlclient.o \
+25 −2
Original line number Diff line number Diff line
@@ -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;
@@ -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
 */
@@ -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 */
+4 −1
Original line number Diff line number Diff line
@@ -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))
+77 −21
Original line number Diff line number Diff line
@@ -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;
	}

	} while ((vllist = next));
	_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);
}

/*
 * 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]");
+3 −0
Original line number Diff line number Diff line
@@ -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,
Loading