lkml.org 
[lkml]   [2009]   [Jun]   [16]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 15/17] AFS: Implement the PSetTokens pioctl
    Date
    Implement the PSetTokens pioctl for AFS.  This will submit a security token for
    caching.

    This can be tested with the OpenAFS userspace tools using the klog program,
    which should add a key to the session keyring with something like:

    [root@andromeda ~]# echo password | klog -pipe admin
    [root@andromeda ~]# keyctl show
    Session Keyring
    -3 --alswrv 0 0 keyring: _ses
    147139749 --alswrv 0 -1 \_ keyring: _uid.0
    457362442 --als--v 0 0 \_ rxrpc: cambridge.redhat.com

    Note that 'klog -setpag' is not supported by this patch as there's currently
    no way for a process to replace its parent process's session keyring.

    Signed-off-by: David Howells <dhowells@redhat.com>
    ---

    fs/afs/cell.c | 15 ++++
    fs/afs/internal.h | 1
    fs/afs/pioctl.c | 177 +++++++++++++++++++++++++++++++++++++++++++++++
    include/linux/afscall.h | 14 ++++
    include/linux/venus.h | 1
    5 files changed, 208 insertions(+), 0 deletions(-)


    diff --git a/fs/afs/cell.c b/fs/afs/cell.c
    index e19c13f..b900fc7 100644
    --- a/fs/afs/cell.c
    +++ b/fs/afs/cell.c
    @@ -227,6 +227,21 @@ int afs_cell_init(char *rootcell)
    }

    /*
    + * get a reference to the root cell
    + */
    +struct afs_cell *afs_get_root_cell(void)
    +{
    + struct afs_cell *cell;
    +
    + read_lock(&afs_cells_lock);
    + cell = afs_cell_root;
    + afs_get_cell(cell);
    + read_unlock(&afs_cells_lock);
    +
    + return cell;
    +}
    +
    +/*
    * lookup a cell record
    */
    struct afs_cell *afs_cell_lookup(const char *name, unsigned namesz)
    diff --git a/fs/afs/internal.h b/fs/afs/internal.h
    index 9a8e8a2..cf08782 100644
    --- a/fs/afs/internal.h
    +++ b/fs/afs/internal.h
    @@ -467,6 +467,7 @@ extern struct list_head afs_proc_cells;

    #define afs_get_cell(C) do { atomic_inc(&(C)->usage); } while(0)
    extern int afs_cell_init(char *);
    +extern struct afs_cell *afs_get_root_cell(void);
    extern struct afs_cell *afs_cell_create(const char *, char *);
    extern struct afs_cell *afs_cell_lookup(const char *, unsigned);
    extern struct afs_cell *afs_grab_cell(struct afs_cell *);
    diff --git a/fs/afs/pioctl.c b/fs/afs/pioctl.c
    index ffbec0c..e6ea69f 100644
    --- a/fs/afs/pioctl.c
    +++ b/fs/afs/pioctl.c
    @@ -2,6 +2,8 @@
    *
    * Copyright (C) 2008 Jacob Thebault-Spieker <summatusmentis@gmail.com>
    *
    + * Modified by David Howells <dhowells@redhat.com>
    + *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License
    * as published by the Free Software Foundation; either version
    @@ -12,6 +14,10 @@
    #include <linux/pioctl.h>
    #include <linux/venus.h>
    #include <linux/string.h>
    +#include <linux/ctype.h>
    +#include <linux/key.h>
    +#include <linux/keyctl.h>
    +#include <keys/rxrpc-type.h>
    #include "internal.h"

    /*
    @@ -219,6 +225,173 @@ long afs_pioctl(struct dentry *dentry, int cmd, struct vice_ioctl *arg)
    }

    /*
    + * Set a user's rxkad authentication tokens
    + */
    +static long afs_PSetTokens(struct vice_ioctl *arg)
    +{
    + struct rxrpc_key_data_v2 *payload;
    + struct clear_token details;
    + struct afs_cell *cell;
    + const char *cp;
    + key_ref_t keyring_r, key_r;
    + size_t in_size, loop;
    + void *in, *in_next, *ticket;
    + char *cellname, *keyname, *dp;
    + long ret;
    + u32 tktlen, tmp, flag;
    +
    + _enter("");
    +
    + /* decode the argument block */
    + in_next = arg->in;
    + in_size = arg->in_size;
    +
    +#define CHECK(n) \
    + do { \
    + if (in_size < (n)) \
    + goto underflow; \
    + in = in_next; \
    + in_size -= (n); \
    + in_next += (n); \
    + } while(0)
    +
    +#define DECODE(to) \
    + do { \
    + CHECK(sizeof(*(to))); \
    + memcpy(to, in, sizeof(*(to))); \
    + } while(0)
    +
    + DECODE(&tktlen);
    + _debug("tktlen: %u", tktlen);
    + if (tktlen > INT_MAX)
    + goto invalid;
    + CHECK(tktlen);
    + ticket = in;
    + DECODE(&tmp);
    + _debug("clear token %u", tmp);
    + if (tmp != sizeof(struct clear_token))
    + goto invalid;
    + DECODE(&details);
    + _debug("ah:%x vi:%x bts:%x ets:%x (e-b:%u) (CT:%lx)",
    + details.auth_handle, details.vice_id,
    + details.begin_timestamp, details.end_timestamp,
    + details.end_timestamp - details.begin_timestamp,
    + CURRENT_TIME.tv_sec);
    + if (details.vice_id == UINT_MAX)
    + goto invalid;
    + if (details.auth_handle == UINT_MAX)
    + details.auth_handle = 999;
    +
    + /* flags and cellname are optional, defaulting to the root cell */
    + _debug("in_size: %zu", in_size);
    + if (in_size != 0) {
    + DECODE(&flag);
    + _debug("flag: %x", flag);
    +
    + if (flag & 0x8000) {
    + /* the caller wants us to give our parent a new PAG
    + * - we don't support this currently
    + */
    + _leave(" = -EACCES");
    + return -EACCES;
    + }
    +
    + /* remainder is cell name */
    + CHECK(sizeof(char));
    + cellname = in;
    + for (loop = 0; loop < in_size; loop++)
    + if (!isprint(cellname[loop]))
    + goto invalid;
    +
    + if (cellname[loop] != '\0')
    + goto invalid;
    + cell = NULL;
    +
    + _debug("cellname: %s", cellname);
    + } else {
    + cell = afs_get_root_cell();
    + cellname = cell->name;
    + flag = 1;
    + }
    +
    +#undef DECODE
    +#undef CHECK
    +
    + /* construct the key name */
    + ret = -ENOMEM;
    + keyname = kmalloc(4 + strlen(cellname) + 1, GFP_KERNEL);
    + if (!keyname)
    + goto error_nokeyname;
    +
    + memcpy(keyname, "afs@", 4);
    + dp = keyname + 4;
    + cp = cellname;
    + while (*cp)
    + *dp++ = toupper(*cp++);
    + *dp = 0;
    +
    + /* we install the authentication token as a key */
    + payload = kmalloc(sizeof(*payload) + tktlen, GFP_KERNEL);
    + if (!payload)
    + goto error_nopayload;
    +
    + payload->kif_version = 2;
    + payload->security_index = RXRPC_SECURITY_RXKAD;
    + payload->ticket_length = tktlen;
    + payload->vice_id = details.vice_id;
    + payload->start = details.begin_timestamp;
    + payload->expiry = details.end_timestamp;
    + payload->kvno = details.auth_handle;
    + memcpy(payload->session_key, details.session_key, 8);
    + memcpy(payload->ticket, ticket, tktlen);
    +
    + /* add the key to the session keyring */
    + keyring_r = lookup_user_key(KEY_SPEC_SESSION_KEYRING, 1, 0,
    + WANT_KEY_WRITE);
    + if (IS_ERR(keyring_r)) {
    + _debug("keyring lookup failed");
    + ret = PTR_ERR(keyring_r);
    + goto error;
    + }
    +
    + /* create or update the requested key and add it to the target
    + * keyring */
    + key_r = key_create_or_update(keyring_r, "rxrpc", keyname,
    + payload, sizeof(*payload) + tktlen,
    + KEY_PERM_UNDEF, KEY_ALLOC_IN_QUOTA);
    + key_ref_put(keyring_r);
    +
    + if (IS_ERR(key_r)) {
    + _debug("key create failed");
    + ret = PTR_ERR(key_r);
    + goto error;
    + }
    +
    + _debug("key serial: %x", key_ref_to_ptr(key_r)->serial);
    +
    + key_ref_put(key_r);
    + arg->out_size = 0;
    + ret = 0;
    +
    +error:
    + kfree(payload);
    +error_nopayload:
    + kfree(keyname);
    +error_nokeyname:
    + afs_put_cell(cell);
    + _leave(" = %ld", ret);
    + return ret;
    +
    +underflow:
    + _leave(" = -EINVAL [short arg]");
    + return -EINVAL;
    +
    +invalid:
    + _leave(" = -EINVAL [invalid arg]");
    + return -EINVAL;
    +}
    +
    +/*
    * The AFS pathless pioctl handler
    */
    long afs_pathless_pioctl(int cmd, struct vice_ioctl *arg)
    @@ -231,6 +404,10 @@ long afs_pathless_pioctl(int cmd, struct vice_ioctl *arg)
    #define VIOC_COMMAND(nr) (_VICEIOCTL(nr) & ~IOCSIZE_MASK)

    switch (cmd & ~IOCSIZE_MASK) {
    + case VIOC_COMMAND(PSetTokens):
    + ret = afs_PSetTokens(arg);
    + break;
    +
    default:
    printk(KERN_DEBUG "AFS: Unsupported pioctl command %x\n", cmd);
    ret = -EOPNOTSUPP;
    diff --git a/include/linux/afscall.h b/include/linux/afscall.h
    index 00054f0..7635aab 100644
    --- a/include/linux/afscall.h
    +++ b/include/linux/afscall.h
    @@ -2,6 +2,8 @@
    *
    * Copyright (C) 2008 Jacob Thebault-Spieker <summatusmentis@gmail.com>
    *
    + * Modified by David Howells <dhowells@redhat.com>
    + *
    * This program is free software; you can redistribute it and/or
    * modify it under the terms of the GNU General Public License
    * as published by the Free Software Foundation; either version
    @@ -14,6 +16,7 @@
    #define AFSCALL_PIOCTL 0x14

    /* pioctl commands */
    +#define PSetTokens 3 /* get authentication tokens for user */
    #define PGetVolStat 4 /* get volume status */
    #define PWhereIs 14 /* find out where a volume is located */
    #define PGetFID 22 /* get file ID */
    @@ -40,4 +43,15 @@ struct VolumeStatus {
    int PartMaxBlocks; /* size of volume's partition */
    };

    +/*
    + * User details when getting or submitting a token
    + */
    +struct clear_token {
    + u32 auth_handle; /* key version number */
    + u8 session_key[8]; /* session encryption key */
    + u32 vice_id; /* client/user ID */
    + u32 begin_timestamp; /* time_t at which ticket starts */
    + u32 end_timestamp; /* time_t at which ticket expires */
    +};
    +
    #endif /* _LINUX_AFSCALL_H */
    diff --git a/include/linux/venus.h b/include/linux/venus.h
    index ea8e468..b90e5f2 100644
    --- a/include/linux/venus.h
    +++ b/include/linux/venus.h
    @@ -17,6 +17,7 @@
    /*
    * pioctl commands (not usable as ioctls)
    */
    +#define VIOCSETTOK _VICEIOCTL(PSetTokens)
    #define VIOCGETVOLSTAT _VICEIOCTL(PGetVolStat)
    #define VIOCWHEREIS _VICEIOCTL(PWhereIs)
    #define VIOCGETFID _VICEIOCTL(PGetFID)


    \
     
     \ /
      Last update: 2009-06-16 22:45    [W:0.039 / U:1.116 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site