/**
* eCryptfs: Linux filesystem encryption layer
* In-kernel key management code. Includes functions to parse and
* write authentication token-related packets with the underlying
* file.
*
* Copyright (C) 2004-2006 International Business Machines Corp.
* Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com>
* Michael C. Thompson <mcthomps@us.ibm.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 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
* 02111-1307, USA.
*/
#include <linux/string.h>
#include <linux/sched.h>
#include <linux/syscalls.h>
#include <linux/pagemap.h>
#include <linux/key.h>
#include <linux/random.h>
#include <linux/crypto.h>
#include <linux/scatterlist.h>
#include "ecryptfs_kernel.h"
/**
* request_key returned an error instead of a valid key address;
* determine the type of error, make appropriate log entries, and
* return an error code.
*/
int process_request_key_err(long err_code)
{
int rc = 0;
switch (err_code) {
case ENOKEY:
ecryptfs_printk(KERN_WARNING, "No key\n");
rc = -ENOENT;
break;
case EKEYEXPIRED:
ecryptfs_printk(KERN_WARNING, "Key expired\n");
rc = -ETIME;
break;
case EKEYREVOKED:
ecryptfs_printk(KERN_WARNING, "Key revoked\n");
rc = -EINVAL;
break;
default:
ecryptfs_printk(KERN_WARNING, "Unknown error code: "
"[0x%.16x]\n", err_code);
rc = -EINVAL;
}
return rc;
}
static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)
{
struct list_head *walker;
struct ecryptfs_auth_tok_list_item *auth_tok_list_item;
walker = auth_tok_list_head->next;
while (walker != auth_tok_list_head) {
auth_tok_list_item =
list_entry(walker, struct ecryptfs_auth_tok_list_item,
list);
walker = auth_tok_list_item->list.next;
memset(auth_tok_list_item, 0,
sizeof(struct ecryptfs_auth_tok_list_item));
kmem_cache_free(ecryptfs_auth_tok_list_item_cache,
auth_tok_list_item);
}
}
struct kmem_cache *ecryptfs_auth_tok_list_item_cache;
/**
* parse_packet_length
* @data: Pointer to memory containing length at offset
* @size: This function writes the decoded size to this memory
* address; zero on error
* @length_size: The number of bytes occupied by the encoded length
*
* Returns Zero on success
*/
static int parse_packet_length(unsigned char *data, size_t *size,
size_t *length_size)
{
int rc = 0;
(*length_size) = 0;
(*size) = 0;
if (data[0] < 192) {
/* One-byte length */
(*size) = data[0];
(*length_size) = 1;
} else if (data[0] < 224) {
/* Two-byte length */
(*size) = ((data[0] - 192) * 256);
(*size) += (data[1] + 192);
(*length_size) = 2;
} else if (data[0] == 255) {
/* Five-byte length; we're not supposed to see this */
ecryptfs_printk(KERN_ERR, "Five-byte packet length not "
"supported\n");
rc = -EINVAL;
goto out;
} else {
ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");
rc = -EINVAL;
goto out;
}
out:
return rc;
}
/**
* write_packet_length
* @dest: The byte array target into which to write the
* length. Must have at least 5 bytes allocated.
* @size: The length to write.
* @packet_size_length: The number of bytes used to encode the
* packet length is written to this address.
*
* Returns zero on success; non-zero on error.
*/
static int write_packet_length(char *dest, size_t size,
size_t *packet_size_length)
{
int rc = 0;
if (size < 192) {
dest[0] = size;
(*packet_size_length) = 1;
} else if (size < 65536) {
dest[0] = (((size -