<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Kernel sources &#187; midcomms</title>
	<atom:link href="http://lynyrd.ru/category/midcomms/feed" rel="self" type="application/rss+xml" />
	<link>http://lynyrd.ru</link>
	<description></description>
	<lastBuildDate>Sun, 31 Jan 2010 05:51:15 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.8.4</generator>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>super.c</title>
		<link>http://lynyrd.ru/super-c-5</link>
		<comments>http://lynyrd.ru/super-c-5#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:05:45 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1102</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2003 Erez Zadok
 * Copyright (C) 2001-2003 Stony Brook University
 * Copyright (C) 2004-2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *              Michael C. Thompson 
 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1102"></span><br />
 *<br />
 * Copyright (C) 1997-2003 Erez Zadok<br />
 * Copyright (C) 2001-2003 Stony Brook University<br />
 * Copyright (C) 2004-2006 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *              Michael C. Thompson <mcthomps@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/fs.h>
#include
<linux/mount.h>
#include
<linux/key.h>
#include
<linux/seq_file.h>
#include
<linux/smp_lock.h>
#include
<linux/file.h>
#include
<linux/crypto.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>struct kmem_cache *ecryptfs_inode_info_cache;</p>
<p>/**<br />
 * ecryptfs_alloc_inode &#8211; allocate an ecryptfs inode<br />
 * @sb: Pointer to the ecryptfs super block<br />
 *<br />
 * Called to bring an inode into existence.<br />
 *<br />
 * Only handle allocation, setting up structures should be done in<br />
 * ecryptfs_read_inode. This is because the kernel, between now and<br />
 * then, will 0 out the private data pointer.<br />
 *<br />
 * Returns a pointer to a newly allocated inode, NULL otherwise<br />
 */<br />
static struct inode *ecryptfs_alloc_inode(struct super_block *sb)<br />
{<br />
	struct ecryptfs_inode_info *inode_info;<br />
	struct inode *inode = NULL;</p>
<p>	inode_info = kmem_cache_alloc(ecryptfs_inode_info_cache, GFP_KERNEL);<br />
	if (unlikely(!inode_info))<br />
		goto out;<br />
	ecryptfs_init_crypt_stat(&#038;inode_info->crypt_stat);<br />
	mutex_init(&#038;inode_info->lower_file_mutex);<br />
	inode_info->lower_file = NULL;<br />
	inode = &#038;inode_info->vfs_inode;<br />
out:<br />
	return inode;<br />
}</p>
<p>/**<br />
 * ecryptfs_destroy_inode<br />
 * @inode: The ecryptfs inode<br />
 *<br />
 * This is used during the final destruction of the inode.  All<br />
 * allocation of memory related to the inode, including allocated<br />
 * memory in the crypt_stat struct, will be released here. This<br />
 * function also fput()&#8217;s the persistent file for the lower inode.<br />
 * There should be no chance that this deallocation will be missed.<br />
 */<br />
static void ecryptfs_destroy_inode(struct inode *inode)<br />
{<br />
	struct ecryptfs_inode_info *inode_info;</p>
<p>	inode_info = ecryptfs_inode_to_private(inode);<br />
	if (inode_info->lower_file) {<br />
		struct dentry *lower_dentry =<br />
			inode_info->lower_file->f_dentry;</p>
<p>		BUG_ON(!lower_dentry);<br />
		if (lower_dentry->d_inode) {<br />
			fput(inode_info->lower_file);<br />
			inode_info->lower_file = NULL;<br />
			d_drop(lower_dentry);<br />
		}<br />
	}<br />
	ecryptfs_destroy_crypt_stat(&#038;inode_info->crypt_stat);<br />
	kmem_cache_free(ecryptfs_inode_info_cache, inode_info);<br />
}</p>
<p>/**<br />
 * ecryptfs_init_inode<br />
 * @inode: The ecryptfs inode<br />
 *<br />
 * Set up the ecryptfs inode.<br />
 */<br />
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode)<br />
{<br />
	ecryptfs_set_inode_lower(inode, lower_inode);<br />
	inode->i_ino = lower_inode->i_ino;<br />
	inode->i_version++;<br />
	inode->i_op = &#038;ecryptfs_main_iops;<br />
	inode->i_fop = &#038;ecryptfs_main_fops;<br />
	inode->i_mapping->a_ops = &#038;ecryptfs_aops;<br />
}</p>
<p>/**<br />
 * ecryptfs_put_super<br />
 * @sb: Pointer to the ecryptfs super block<br />
 *<br />
 * Final actions when unmounting a file system.<br />
 * This will handle deallocation and release of our private data.<br />
 */<br />
static void ecryptfs_put_super(struct super_block *sb)<br />
{<br />
	struct ecryptfs_sb_info *sb_info = ecryptfs_superblock_to_private(sb);</p>
<p>	lock_kernel();</p>
<p>	ecryptfs_destroy_mount_crypt_stat(&#038;sb_info->mount_crypt_stat);<br />
	kmem_cache_free(ecryptfs_sb_info_cache, sb_info);<br />
	ecryptfs_set_superblock_private(sb, NULL);</p>
<p>	unlock_kernel();<br />
}</p>
<p>/**<br />
 * ecryptfs_statfs<br />
 * @sb: The ecryptfs super block<br />
 * @buf: The struct kstatfs to fill in with stats<br />
 *<br />
 * Get the filesystem statistics. Currently, we let this pass right through<br />
 * to the lower filesystem and take no action ourselves.<br />
 */<br />
static int ecryptfs_statfs(struct dentry *dentry, struct kstatfs *buf)<br />
{<br />
	return vfs_statfs(ecryptfs_dentry_to_lower(dentry), buf);<br />
}</p>
<p>/**<br />
 * ecryptfs_clear_inode<br />
 * @inode &#8211; The ecryptfs inode<br />
 *<br />
 * Called by iput() when the inode reference count reached zero<br />
 * and the inode is not hashed anywhere.  Used to clear anything<br />
 * that needs to be, before the inode is completely destroyed and put<br />
 * on the inode free list. We use this to drop out reference to the<br />
 * lower inode.<br />
 */<br />
static void ecryptfs_clear_inode(struct inode *inode)<br />
{<br />
	iput(ecryptfs_inode_to_lower(inode));<br />
}</p>
<p>/**<br />
 * ecryptfs_show_options<br />
 *<br />
 * Prints the mount options for a given superblock.<br />
 * Returns zero; does not fail.<br />
 */<br />
static int ecryptfs_show_options(struct seq_file *m, struct vfsmount *mnt)<br />
{<br />
	struct super_block *sb = mnt->mnt_sb;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		&#038;ecryptfs_superblock_to_private(sb)->mount_crypt_stat;<br />
	struct ecryptfs_global_auth_tok *walker;</p>
<p>	mutex_lock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	list_for_each_entry(walker,<br />
			    &#038;mount_crypt_stat->global_auth_tok_list,<br />
			    mount_crypt_stat_list) {<br />
		if (walker->flags &#038; ECRYPTFS_AUTH_TOK_FNEK)<br />
			seq_printf(m, &laquo;,ecryptfs_fnek_sig=%s&raquo;, walker->sig);<br />
		else<br />
			seq_printf(m, &laquo;,ecryptfs_sig=%s&raquo;, walker->sig);<br />
	}<br />
	mutex_unlock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);</p>
<p>	seq_printf(m, &laquo;,ecryptfs_cipher=%s&raquo;,<br />
		mount_crypt_stat->global_default_cipher_name);</p>
<p>	if (mount_crypt_stat->global_default_cipher_key_size)<br />
		seq_printf(m, &laquo;,ecryptfs_key_bytes=%zd&raquo;,<br />
			   mount_crypt_stat->global_default_cipher_key_size);<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)<br />
		seq_printf(m, &laquo;,ecryptfs_passthrough&raquo;);<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_XATTR_METADATA_ENABLED)<br />
		seq_printf(m, &laquo;,ecryptfs_xattr_metadata&raquo;);<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED_VIEW_ENABLED)<br />
		seq_printf(m, &laquo;,ecryptfs_encrypted_view&raquo;);<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_UNLINK_SIGS)<br />
		seq_printf(m, &laquo;,ecryptfs_unlink_sigs&raquo;);</p>
<p>	return 0;<br />
}</p>
<p>const struct super_operations ecryptfs_sops = {<br />
	.alloc_inode = ecryptfs_alloc_inode,<br />
	.destroy_inode = ecryptfs_destroy_inode,<br />
	.drop_inode = generic_delete_inode,<br />
	.put_super = ecryptfs_put_super,<br />
	.statfs = ecryptfs_statfs,<br />
	.remount_fs = NULL,<br />
	.clear_inode = ecryptfs_clear_inode,<br />
	.show_options = ecryptfs_show_options<br />
};</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/super-c-5/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>read_write.c</title>
		<link>http://lynyrd.ru/read_write-c</link>
		<comments>http://lynyrd.ru/read_write-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:05:29 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1100</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 2007 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *
 * 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 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1100"></span><br />
 *<br />
 * Copyright (C) 2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/fs.h>
#include
<linux/pagemap.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * ecryptfs_write_lower<br />
 * @ecryptfs_inode: The eCryptfs inode<br />
 * @data: Data to write<br />
 * @offset: Byte offset in the lower file to which to write the data<br />
 * @size: Number of bytes from @data to write at @offset in the lower<br />
 *        file<br />
 *<br />
 * Write data to the lower file.<br />
 *<br />
 * Returns bytes written on success; less than zero on error<br />
 */<br />
int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,<br />
			 loff_t offset, size_t size)<br />
{<br />
	struct ecryptfs_inode_info *inode_info;<br />
	mm_segment_t fs_save;<br />
	ssize_t rc;</p>
<p>	inode_info = ecryptfs_inode_to_private(ecryptfs_inode);<br />
	mutex_lock(&#038;inode_info->lower_file_mutex);<br />
	BUG_ON(!inode_info->lower_file);<br />
	inode_info->lower_file->f_pos = offset;<br />
	fs_save = get_fs();<br />
	set_fs(get_ds());<br />
	rc = vfs_write(inode_info->lower_file, data, size,<br />
		       &#038;inode_info->lower_file->f_pos);<br />
	set_fs(fs_save);<br />
	mutex_unlock(&#038;inode_info->lower_file_mutex);<br />
	mark_inode_dirty_sync(ecryptfs_inode);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_write_lower_page_segment<br />
 * @ecryptfs_inode: The eCryptfs inode<br />
 * @page_for_lower: The page containing the data to be written to the<br />
 *                  lower file<br />
 * @offset_in_page: The offset in the @page_for_lower from which to<br />
 *                  start writing the data<br />
 * @size: The amount of data from @page_for_lower to write to the<br />
 *        lower file<br />
 *<br />
 * Determines the byte offset in the file for the given page and<br />
 * offset within the page, maps the page, and makes the call to write<br />
 * the contents of @page_for_lower to the lower inode.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,<br />
				      struct page *page_for_lower,<br />
				      size_t offset_in_page, size_t size)<br />
{<br />
	char *virt;<br />
	loff_t offset;<br />
	int rc;</p>
<p>	offset = ((((loff_t)page_for_lower->index) << PAGE_CACHE_SHIFT)<br />
		  + offset_in_page);<br />
	virt = kmap(page_for_lower);<br />
	rc = ecryptfs_write_lower(ecryptfs_inode, virt, offset, size);<br />
	if (rc > 0)<br />
		rc = 0;<br />
	kunmap(page_for_lower);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_write<br />
 * @ecryptfs_file: The eCryptfs file into which to write<br />
 * @data: Virtual address where data to write is located<br />
 * @offset: Offset in the eCryptfs file at which to begin writing the<br />
 *          data from @data<br />
 * @size: The number of bytes to write from @data<br />
 *<br />
 * Write an arbitrary amount of data to an arbitrary location in the<br />
 * eCryptfs inode page cache. This is done on a page-by-page, and then<br />
 * by an extent-by-extent, basis; individual extents are encrypted and<br />
 * written to the lower page cache (via VFS writes). This function<br />
 * takes care of all the address translation to locations in the lower<br />
 * filesystem; it also handles truncate events, writing out zeros<br />
 * where necessary.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,<br />
		   size_t size)<br />
{<br />
	struct page *ecryptfs_page;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
	struct inode *ecryptfs_inode = ecryptfs_file->f_dentry->d_inode;<br />
	char *ecryptfs_page_virt;<br />
	loff_t ecryptfs_file_size = i_size_read(ecryptfs_inode);<br />
	loff_t data_offset = 0;<br />
	loff_t pos;<br />
	int rc = 0;</p>
<p>	crypt_stat = &#038;ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;<br />
	/*<br />
	 * if we are writing beyond current size, then start pos<br />
	 * at the current size &#8211; we&#8217;ll fill in zeros from there.<br />
	 */<br />
	if (offset > ecryptfs_file_size)<br />
		pos = ecryptfs_file_size;<br />
	else<br />
		pos = offset;<br />
	while (pos < (offset + size)) {<br />
		pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);<br />
		size_t start_offset_in_page = (pos &#038; ~PAGE_CACHE_MASK);<br />
		size_t num_bytes = (PAGE_CACHE_SIZE &#8211; start_offset_in_page);<br />
		size_t total_remaining_bytes = ((offset + size) &#8211; pos);</p>
<p>		if (num_bytes > total_remaining_bytes)<br />
			num_bytes = total_remaining_bytes;<br />
		if (pos < offset) {<br />
			/* remaining zeros to write, up to destination offset */<br />
			size_t total_remaining_zeros = (offset - pos);</p>
<p>			if (num_bytes > total_remaining_zeros)<br />
				num_bytes = total_remaining_zeros;<br />
		}<br />
		ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,<br />
							 ecryptfs_page_idx);<br />
		if (IS_ERR(ecryptfs_page)) {<br />
			rc = PTR_ERR(ecryptfs_page);<br />
			printk(KERN_ERR &laquo;%s: Error getting page at &raquo;<br />
			       &laquo;index [%ld] from eCryptfs inode &raquo;<br />
			       &laquo;mapping; rc = [%d]\n&raquo;, __func__,<br />
			       ecryptfs_page_idx, rc);<br />
			goto out;<br />
		}<br />
		ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);</p>
<p>		/*<br />
		 * pos: where we&#8217;re now writing, offset: where the request was<br />
		 * If current pos is before request, we are filling zeros<br />
		 * If we are at or beyond request, we are writing the *data*<br />
		 * If we&#8217;re in a fresh page beyond eof, zero it in either case<br />
		 */<br />
		if (pos < offset || !start_offset_in_page) {<br />
			/* We are extending past the previous end of the file.<br />
			 * Fill in zero values to the end of the page */<br />
			memset(((char *)ecryptfs_page_virt<br />
				+ start_offset_in_page), 0,<br />
				PAGE_CACHE_SIZE - start_offset_in_page);<br />
		}</p>
<p>		/* pos >= offset, we are now writing the data request */<br />
		if (pos >= offset) {<br />
			memcpy(((char *)ecryptfs_page_virt<br />
				+ start_offset_in_page),<br />
			       (data + data_offset), num_bytes);<br />
			data_offset += num_bytes;<br />
		}<br />
		kunmap_atomic(ecryptfs_page_virt, KM_USER0);<br />
		flush_dcache_page(ecryptfs_page);<br />
		SetPageUptodate(ecryptfs_page);<br />
		unlock_page(ecryptfs_page);<br />
		if (crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)<br />
			rc = ecryptfs_encrypt_page(ecryptfs_page);<br />
		else<br />
			rc = ecryptfs_write_lower_page_segment(ecryptfs_inode,<br />
						ecryptfs_page,<br />
						start_offset_in_page,<br />
						data_offset);<br />
		page_cache_release(ecryptfs_page);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error encrypting &raquo;<br />
			       &laquo;page; rc = [%d]\n&raquo;, __func__, rc);<br />
			goto out;<br />
		}<br />
		pos += num_bytes;<br />
	}<br />
	if ((offset + size) > ecryptfs_file_size) {<br />
		i_size_write(ecryptfs_inode, (offset + size));<br />
		if (crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED) {<br />
			rc = ecryptfs_write_inode_size_to_metadata(<br />
								ecryptfs_inode);<br />
			if (rc) {<br />
				printk(KERN_ERR	&laquo;Problem with &raquo;<br />
				       &laquo;ecryptfs_write_inode_size_to_metadata; &raquo;<br />
				       &laquo;rc = [%d]\n&raquo;, rc);<br />
				goto out;<br />
			}<br />
		}<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_lower<br />
 * @data: The read data is stored here by this function<br />
 * @offset: Byte offset in the lower file from which to read the data<br />
 * @size: Number of bytes to read from @offset of the lower file and<br />
 *        store into @data<br />
 * @ecryptfs_inode: The eCryptfs inode<br />
 *<br />
 * Read @size bytes of data at byte offset @offset from the lower<br />
 * inode into memory location @data.<br />
 *<br />
 * Returns bytes read on success; 0 on EOF; less than zero on error<br />
 */<br />
int ecryptfs_read_lower(char *data, loff_t offset, size_t size,<br />
			struct inode *ecryptfs_inode)<br />
{<br />
	struct ecryptfs_inode_info *inode_info =<br />
		ecryptfs_inode_to_private(ecryptfs_inode);<br />
	mm_segment_t fs_save;<br />
	ssize_t rc;</p>
<p>	mutex_lock(&#038;inode_info->lower_file_mutex);<br />
	BUG_ON(!inode_info->lower_file);<br />
	inode_info->lower_file->f_pos = offset;<br />
	fs_save = get_fs();<br />
	set_fs(get_ds());<br />
	rc = vfs_read(inode_info->lower_file, data, size,<br />
		      &#038;inode_info->lower_file->f_pos);<br />
	set_fs(fs_save);<br />
	mutex_unlock(&#038;inode_info->lower_file_mutex);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_lower_page_segment<br />
 * @page_for_ecryptfs: The page into which data for eCryptfs will be<br />
 *                     written<br />
 * @offset_in_page: Offset in @page_for_ecryptfs from which to start<br />
 *                  writing<br />
 * @size: The number of bytes to write into @page_for_ecryptfs<br />
 * @ecryptfs_inode: The eCryptfs inode<br />
 *<br />
 * Determines the byte offset in the file for the given page and<br />
 * offset within the page, maps the page, and makes the call to read<br />
 * the contents of @page_for_ecryptfs from the lower inode.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,<br />
				     pgoff_t page_index,<br />
				     size_t offset_in_page, size_t size,<br />
				     struct inode *ecryptfs_inode)<br />
{<br />
	char *virt;<br />
	loff_t offset;<br />
	int rc;</p>
<p>	offset = ((((loff_t)page_index) << PAGE_CACHE_SHIFT) + offset_in_page);<br />
	virt = kmap(page_for_ecryptfs);<br />
	rc = ecryptfs_read_lower(virt, offset, size, ecryptfs_inode);<br />
	if (rc > 0)<br />
		rc = 0;<br />
	kunmap(page_for_ecryptfs);<br />
	flush_dcache_page(page_for_ecryptfs);<br />
	return rc;<br />
}</p>
<p>#if 0<br />
/**<br />
 * ecryptfs_read<br />
 * @data: The virtual address into which to write the data read (and<br />
 *        possibly decrypted) from the lower file<br />
 * @offset: The offset in the decrypted view of the file from which to<br />
 *          read into @data<br />
 * @size: The number of bytes to read into @data<br />
 * @ecryptfs_file: The eCryptfs file from which to read<br />
 *<br />
 * Read an arbitrary amount of data from an arbitrary location in the<br />
 * eCryptfs page cache. This is done on an extent-by-extent basis;<br />
 * individual extents are decrypted and read from the lower page<br />
 * cache (via VFS reads). This function takes care of all the<br />
 * address translation to locations in the lower filesystem.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_read(char *data, loff_t offset, size_t size,<br />
		  struct file *ecryptfs_file)<br />
{<br />
	struct page *ecryptfs_page;<br />
	char *ecryptfs_page_virt;<br />
	loff_t ecryptfs_file_size =<br />
		i_size_read(ecryptfs_file->f_dentry->d_inode);<br />
	loff_t data_offset = 0;<br />
	loff_t pos;<br />
	int rc = 0;</p>
<p>	if ((offset + size) > ecryptfs_file_size) {<br />
		rc = -EINVAL;<br />
		printk(KERN_ERR &laquo;%s: Attempt to read data past the end of the &raquo;<br />
			&laquo;file; offset = [%lld]; size = [%td]; &raquo;<br />
		       &laquo;ecryptfs_file_size = [%lld]\n&raquo;,<br />
		       __func__, offset, size, ecryptfs_file_size);<br />
		goto out;<br />
	}<br />
	pos = offset;<br />
	while (pos < (offset + size)) {<br />
		pgoff_t ecryptfs_page_idx = (pos >> PAGE_CACHE_SHIFT);<br />
		size_t start_offset_in_page = (pos &#038; ~PAGE_CACHE_MASK);<br />
		size_t num_bytes = (PAGE_CACHE_SIZE &#8211; start_offset_in_page);<br />
		size_t total_remaining_bytes = ((offset + size) &#8211; pos);</p>
<p>		if (num_bytes > total_remaining_bytes)<br />
			num_bytes = total_remaining_bytes;<br />
		ecryptfs_page = ecryptfs_get_locked_page(ecryptfs_file,<br />
							 ecryptfs_page_idx);<br />
		if (IS_ERR(ecryptfs_page)) {<br />
			rc = PTR_ERR(ecryptfs_page);<br />
			printk(KERN_ERR &laquo;%s: Error getting page at &raquo;<br />
			       &laquo;index [%ld] from eCryptfs inode &raquo;<br />
			       &laquo;mapping; rc = [%d]\n&raquo;, __func__,<br />
			       ecryptfs_page_idx, rc);<br />
			goto out;<br />
		}<br />
		ecryptfs_page_virt = kmap_atomic(ecryptfs_page, KM_USER0);<br />
		memcpy((data + data_offset),<br />
		       ((char *)ecryptfs_page_virt + start_offset_in_page),<br />
		       num_bytes);<br />
		kunmap_atomic(ecryptfs_page_virt, KM_USER0);<br />
		flush_dcache_page(ecryptfs_page);<br />
		SetPageUptodate(ecryptfs_page);<br />
		unlock_page(ecryptfs_page);<br />
		page_cache_release(ecryptfs_page);<br />
		pos += num_bytes;<br />
		data_offset += num_bytes;<br />
	}<br />
out:<br />
	return rc;<br />
}<br />
#endif  /*  0  */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/read_write-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>mmap.c</title>
		<link>http://lynyrd.ru/mmap-c</link>
		<comments>http://lynyrd.ru/mmap-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:05:09 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1098</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 * This is where eCryptfs coordinates the symmetric encryption and
 * decryption of the file data as it passes between the lower
 * encrypted file and the upper decrypted file.
 *
 * Copyright (C) 1997-2003 Erez Zadok
 * Copyright (C) 2001-2003 Stony Brook University
 * Copyright (C) 2004-2007 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1098"></span><br />
 * This is where eCryptfs coordinates the symmetric encryption and<br />
 * decryption of the file data as it passes between the lower<br />
 * encrypted file and the upper decrypted file.<br />
 *<br />
 * Copyright (C) 1997-2003 Erez Zadok<br />
 * Copyright (C) 2001-2003 Stony Brook University<br />
 * Copyright (C) 2004-2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/pagemap.h>
#include
<linux/writeback.h>
#include
<linux/page-flags.h>
#include
<linux/mount.h>
#include
<linux/file.h>
#include
<linux/crypto.h>
#include
<linux/scatterlist.h>
#include <asm/unaligned.h><br />
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * ecryptfs_get_locked_page<br />
 *<br />
 * Get one page from cache or lower f/s, return error otherwise.<br />
 *<br />
 * Returns locked and up-to-date page (if ok), with increased<br />
 * refcnt.<br />
 */<br />
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index)<br />
{<br />
	struct dentry *dentry;<br />
	struct inode *inode;<br />
	struct address_space *mapping;<br />
	struct page *page;</p>
<p>	dentry = file->f_path.dentry;<br />
	inode = dentry->d_inode;<br />
	mapping = inode->i_mapping;<br />
	page = read_mapping_page(mapping, index, (void *)file);<br />
	if (!IS_ERR(page))<br />
		lock_page(page);<br />
	return page;<br />
}</p>
<p>/**<br />
 * ecryptfs_writepage<br />
 * @page: Page that is locked before this call is made<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_writepage(struct page *page, struct writeback_control *wbc)<br />
{<br />
	int rc;</p>
<p>	rc = ecryptfs_encrypt_page(page);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error encrypting &raquo;<br />
				&laquo;page (upper index [0x%.16x])\n&raquo;, page->index);<br />
		ClearPageUptodate(page);<br />
		goto out;<br />
	}<br />
	SetPageUptodate(page);<br />
	unlock_page(page);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 *   Header Extent:<br />
 *     Octets 0-7:        Unencrypted file size (big-endian)<br />
 *     Octets 8-15:       eCryptfs special marker<br />
 *     Octets 16-19:      Flags<br />
 *      Octet 16:         File format version number (between 0 and 255)<br />
 *      Octets 17-18:     Reserved<br />
 *      Octet 19:         Bit 1 (lsb): Reserved<br />
 *                        Bit 2: Encrypted?<br />
 *                        Bits 3-8: Reserved<br />
 *     Octets 20-23:      Header extent size (big-endian)<br />
 *     Octets 24-25:      Number of header extents at front of file<br />
 *                        (big-endian)<br />
 *     Octet  26:         Begin RFC 2440 authentication token packet set<br />
 */<br />
static void set_header_info(char *page_virt,<br />
			    struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	size_t written;<br />
	size_t save_num_header_bytes_at_front =<br />
		crypt_stat->num_header_bytes_at_front;</p>
<p>	crypt_stat->num_header_bytes_at_front =<br />
		ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;<br />
	ecryptfs_write_header_metadata(page_virt + 20, crypt_stat, &#038;written);<br />
	crypt_stat->num_header_bytes_at_front =<br />
		save_num_header_bytes_at_front;<br />
}</p>
<p>/**<br />
 * ecryptfs_copy_up_encrypted_with_header<br />
 * @page: Sort of a &laquo;virtual&raquo; representation of the encrypted lower<br />
 *        file. The actual lower file does not have the metadata in<br />
 *        the header. This is locked.<br />
 * @crypt_stat: The eCryptfs inode&#8217;s cryptographic context<br />
 *<br />
 * The &laquo;view&raquo; is the version of the file that userspace winds up<br />
 * seeing, with the header information inserted.<br />
 */<br />
static int<br />
ecryptfs_copy_up_encrypted_with_header(struct page *page,<br />
				       struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	loff_t extent_num_in_page = 0;<br />
	loff_t num_extents_per_page = (PAGE_CACHE_SIZE<br />
				       / crypt_stat->extent_size);<br />
	int rc = 0;</p>
<p>	while (extent_num_in_page < num_extents_per_page) {<br />
		loff_t view_extent_num = ((((loff_t)page->index)<br />
					   * num_extents_per_page)<br />
					  + extent_num_in_page);<br />
		size_t num_header_extents_at_front =<br />
			(crypt_stat->num_header_bytes_at_front<br />
			 / crypt_stat->extent_size);</p>
<p>		if (view_extent_num < num_header_extents_at_front) {<br />
			/* This is a header extent */<br />
			char *page_virt;</p>
<p>			page_virt = kmap_atomic(page, KM_USER0);<br />
			memset(page_virt, 0, PAGE_CACHE_SIZE);<br />
			/* TODO: Support more than one header extent */<br />
			if (view_extent_num == 0) {<br />
				rc = ecryptfs_read_xattr_region(<br />
					page_virt, page->mapping->host);<br />
				set_header_info(page_virt, crypt_stat);<br />
			}<br />
			kunmap_atomic(page_virt, KM_USER0);<br />
			flush_dcache_page(page);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error reading xattr &raquo;<br />
				       &laquo;region; rc = [%d]\n&raquo;, __func__, rc);<br />
				goto out;<br />
			}<br />
		} else {<br />
			/* This is an encrypted data extent */<br />
			loff_t lower_offset =<br />
				((view_extent_num * crypt_stat->extent_size)<br />
				 &#8211; crypt_stat->num_header_bytes_at_front);</p>
<p>			rc = ecryptfs_read_lower_page_segment(<br />
				page, (lower_offset >> PAGE_CACHE_SHIFT),<br />
				(lower_offset &#038; ~PAGE_CACHE_MASK),<br />
				crypt_stat->extent_size, page->mapping->host);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error attempting to read &raquo;<br />
				       &laquo;extent at offset [%lld] in the lower &raquo;<br />
				       &laquo;file; rc = [%d]\n&raquo;, __func__,<br />
				       lower_offset, rc);<br />
				goto out;<br />
			}<br />
		}<br />
		extent_num_in_page++;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_readpage<br />
 * @file: An eCryptfs file<br />
 * @page: Page from eCryptfs inode mapping into which to stick the read data<br />
 *<br />
 * Read in a page, decrypting if necessary.<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int ecryptfs_readpage(struct file *file, struct page *page)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
		&#038;ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;<br />
	int rc = 0;</p>
<p>	if (!crypt_stat<br />
	    || !(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)<br />
	    || (crypt_stat->flags &#038; ECRYPTFS_NEW_FILE)) {<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&laquo;Passing through unencrypted page\n&raquo;);<br />
		rc = ecryptfs_read_lower_page_segment(page, page->index, 0,<br />
						      PAGE_CACHE_SIZE,<br />
						      page->mapping->host);<br />
	} else if (crypt_stat->flags &#038; ECRYPTFS_VIEW_AS_ENCRYPTED) {<br />
		if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR) {<br />
			rc = ecryptfs_copy_up_encrypted_with_header(page,<br />
								    crypt_stat);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error attempting to copy &raquo;<br />
				       &laquo;the encrypted content from the lower &raquo;<br />
				       &laquo;file whilst inserting the metadata &raquo;<br />
				       &laquo;from the xattr into the header; rc = &raquo;<br />
				       &laquo;[%d]\n&raquo;, __func__, rc);<br />
				goto out;<br />
			}</p>
<p>		} else {<br />
			rc = ecryptfs_read_lower_page_segment(<br />
				page, page->index, 0, PAGE_CACHE_SIZE,<br />
				page->mapping->host);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;Error reading page; rc = &raquo;<br />
				       &laquo;[%d]\n&raquo;, rc);<br />
				goto out;<br />
			}<br />
		}<br />
	} else {<br />
		rc = ecryptfs_decrypt_page(page);<br />
		if (rc) {<br />
			ecryptfs_printk(KERN_ERR, &laquo;Error decrypting page; &raquo;<br />
					&laquo;rc = [%d]\n&raquo;, rc);<br />
			goto out;<br />
		}<br />
	}<br />
out:<br />
	if (rc)<br />
		ClearPageUptodate(page);<br />
	else<br />
		SetPageUptodate(page);<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;Unlocking page with index = [0x%.16x]\n&raquo;,<br />
			page->index);<br />
	unlock_page(page);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * Called with lower inode mutex held.<br />
 */<br />
static int fill_zeros_to_end_of_page(struct page *page, unsigned int to)<br />
{<br />
	struct inode *inode = page->mapping->host;<br />
	int end_byte_in_page;</p>
<p>	if ((i_size_read(inode) / PAGE_CACHE_SIZE) != page->index)<br />
		goto out;<br />
	end_byte_in_page = i_size_read(inode) % PAGE_CACHE_SIZE;<br />
	if (to > end_byte_in_page)<br />
		end_byte_in_page = to;<br />
	zero_user_segment(page, end_byte_in_page, PAGE_CACHE_SIZE);<br />
out:<br />
	return 0;<br />
}</p>
<p>/**<br />
 * ecryptfs_write_begin<br />
 * @file: The eCryptfs file<br />
 * @mapping: The eCryptfs object<br />
 * @pos: The file offset at which to start writing<br />
 * @len: Length of the write<br />
 * @flags: Various flags<br />
 * @pagep: Pointer to return the page<br />
 * @fsdata: Pointer to return fs data (unused)<br />
 *<br />
 * This function must zero any hole we create<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_write_begin(struct file *file,<br />
			struct address_space *mapping,<br />
			loff_t pos, unsigned len, unsigned flags,<br />
			struct page **pagep, void **fsdata)<br />
{<br />
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;<br />
	struct page *page;<br />
	loff_t prev_page_end_size;<br />
	int rc = 0;</p>
<p>	page = grab_cache_page_write_begin(mapping, index, flags);<br />
	if (!page)<br />
		return -ENOMEM;<br />
	*pagep = page;</p>
<p>	if (!PageUptodate(page)) {<br />
		struct ecryptfs_crypt_stat *crypt_stat =<br />
			&#038;ecryptfs_inode_to_private(<br />
				file->f_path.dentry->d_inode)->crypt_stat;</p>
<p>		if (!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)<br />
		    || (crypt_stat->flags &#038; ECRYPTFS_NEW_FILE)) {<br />
			rc = ecryptfs_read_lower_page_segment(<br />
				page, index, 0, PAGE_CACHE_SIZE, mapping->host);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error attemping to read &raquo;<br />
				       &laquo;lower page segment; rc = [%d]\n&raquo;,<br />
				       __func__, rc);<br />
				ClearPageUptodate(page);<br />
				goto out;<br />
			} else<br />
				SetPageUptodate(page);<br />
		} else if (crypt_stat->flags &#038; ECRYPTFS_VIEW_AS_ENCRYPTED) {<br />
			if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR) {<br />
				rc = ecryptfs_copy_up_encrypted_with_header(<br />
					page, crypt_stat);<br />
				if (rc) {<br />
					printk(KERN_ERR &laquo;%s: Error attempting &raquo;<br />
					       &laquo;to copy the encrypted content &raquo;<br />
					       &laquo;from the lower file whilst &raquo;<br />
					       &laquo;inserting the metadata from &raquo;<br />
					       &laquo;the xattr into the header; rc &raquo;<br />
					       &laquo;= [%d]\n&raquo;, __func__, rc);<br />
					ClearPageUptodate(page);<br />
					goto out;<br />
				}<br />
				SetPageUptodate(page);<br />
			} else {<br />
				rc = ecryptfs_read_lower_page_segment(<br />
					page, index, 0, PAGE_CACHE_SIZE,<br />
					mapping->host);<br />
				if (rc) {<br />
					printk(KERN_ERR &laquo;%s: Error reading &raquo;<br />
					       &laquo;page; rc = [%d]\n&raquo;,<br />
					       __func__, rc);<br />
					ClearPageUptodate(page);<br />
					goto out;<br />
				}<br />
				SetPageUptodate(page);<br />
			}<br />
		} else {<br />
			rc = ecryptfs_decrypt_page(page);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error decrypting page &raquo;<br />
				       &laquo;at index [%ld]; rc = [%d]\n&raquo;,<br />
				       __func__, page->index, rc);<br />
				ClearPageUptodate(page);<br />
				goto out;<br />
			}<br />
			SetPageUptodate(page);<br />
		}<br />
	}<br />
	prev_page_end_size = ((loff_t)index << PAGE_CACHE_SHIFT);<br />
	/* If creating a page or more of holes, zero them out via truncate.<br />
	 * Note, this will increase i_size. */<br />
	if (index != 0) {<br />
		if (prev_page_end_size > i_size_read(page->mapping->host)) {<br />
			rc = ecryptfs_truncate(file->f_path.dentry,<br />
					       prev_page_end_size);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;%s: Error on attempt to &raquo;<br />
				       &laquo;truncate to (higher) offset [%lld];&raquo;<br />
				       &raquo; rc = [%d]\n&raquo;, __func__,<br />
				       prev_page_end_size, rc);<br />
				goto out;<br />
			}<br />
		}<br />
	}<br />
	/* Writing to a new page, and creating a small hole from start<br />
	 * of page?  Zero it out. */<br />
	if ((i_size_read(mapping->host) == prev_page_end_size)<br />
	    &#038;&#038; (pos != 0))<br />
		zero_user(page, 0, PAGE_CACHE_SIZE);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_write_inode_size_to_header<br />
 *<br />
 * Writes the lower file size to the first 8 bytes of the header.<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int ecryptfs_write_inode_size_to_header(struct inode *ecryptfs_inode)<br />
{<br />
	char *file_size_virt;<br />
	int rc;</p>
<p>	file_size_virt = kmalloc(sizeof(u64), GFP_KERNEL);<br />
	if (!file_size_virt) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	put_unaligned_be64(i_size_read(ecryptfs_inode), file_size_virt);<br />
	rc = ecryptfs_write_lower(ecryptfs_inode, file_size_virt, 0,<br />
				  sizeof(u64));<br />
	kfree(file_size_virt);<br />
	if (rc < 0)<br />
		printk(KERN_ERR "%s: Error writing file size to header; "<br />
		       "rc = [%d]\n", __func__, rc);<br />
	else<br />
		rc = 0;<br />
out:<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_xattr_cache;</p>
<p>static int ecryptfs_write_inode_size_to_xattr(struct inode *ecryptfs_inode)<br />
{<br />
	ssize_t size;<br />
	void *xattr_virt;<br />
	struct dentry *lower_dentry =<br />
		ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;<br />
	struct inode *lower_inode = lower_dentry->d_inode;<br />
	int rc;</p>
<p>	if (!lower_inode->i_op->getxattr || !lower_inode->i_op->setxattr) {<br />
		printk(KERN_WARNING<br />
		       &laquo;No support for setting xattr in lower filesystem\n&raquo;);<br />
		rc = -ENOSYS;<br />
		goto out;<br />
	}<br />
	xattr_virt = kmem_cache_alloc(ecryptfs_xattr_cache, GFP_KERNEL);<br />
	if (!xattr_virt) {<br />
		printk(KERN_ERR &laquo;Out of memory whilst attempting to write &raquo;<br />
		       &laquo;inode size to xattr\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;lower_inode->i_mutex);<br />
	size = lower_inode->i_op->getxattr(lower_dentry, ECRYPTFS_XATTR_NAME,<br />
					   xattr_virt, PAGE_CACHE_SIZE);<br />
	if (size < 0)<br />
		size = 8;<br />
	put_unaligned_be64(i_size_read(ecryptfs_inode), xattr_virt);<br />
	rc = lower_inode->i_op->setxattr(lower_dentry, ECRYPTFS_XATTR_NAME,<br />
					 xattr_virt, size, 0);<br />
	mutex_unlock(&#038;lower_inode->i_mutex);<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;Error whilst attempting to write inode size &raquo;<br />
		       &laquo;to lower file xattr; rc = [%d]\n&raquo;, rc);<br />
	kmem_cache_free(ecryptfs_xattr_cache, xattr_virt);<br />
out:<br />
	return rc;<br />
}</p>
<p>int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat;</p>
<p>	crypt_stat = &#038;ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;<br />
	BUG_ON(!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED));<br />
	if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR)<br />
		return ecryptfs_write_inode_size_to_xattr(ecryptfs_inode);<br />
	else<br />
		return ecryptfs_write_inode_size_to_header(ecryptfs_inode);<br />
}</p>
<p>/**<br />
 * ecryptfs_write_end<br />
 * @file: The eCryptfs file object<br />
 * @mapping: The eCryptfs object<br />
 * @pos: The file position<br />
 * @len: The length of the data (unused)<br />
 * @copied: The amount of data copied<br />
 * @page: The eCryptfs page<br />
 * @fsdata: The fsdata (unused)<br />
 *<br />
 * This is where we encrypt the data and pass the encrypted data to<br />
 * the lower filesystem.  In OpenPGP-compatible mode, we operate on<br />
 * entire underlying packets.<br />
 */<br />
static int ecryptfs_write_end(struct file *file,<br />
			struct address_space *mapping,<br />
			loff_t pos, unsigned len, unsigned copied,<br />
			struct page *page, void *fsdata)<br />
{<br />
	pgoff_t index = pos >> PAGE_CACHE_SHIFT;<br />
	unsigned from = pos &#038; (PAGE_CACHE_SIZE &#8211; 1);<br />
	unsigned to = from + copied;<br />
	struct inode *ecryptfs_inode = mapping->host;<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
		&#038;ecryptfs_inode_to_private(file->f_path.dentry->d_inode)->crypt_stat;<br />
	int rc;</p>
<p>	if (crypt_stat->flags &#038; ECRYPTFS_NEW_FILE) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;ECRYPTFS_NEW_FILE flag set in &raquo;<br />
			&laquo;crypt_stat at memory location [%p]\n&raquo;, crypt_stat);<br />
		crypt_stat->flags &#038;= ~(ECRYPTFS_NEW_FILE);<br />
	} else<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Not a new file\n&raquo;);<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;Calling fill_zeros_to_end_of_page&raquo;<br />
			&laquo;(page w/ index = [0x%.16x], to = [%d])\n&raquo;, index, to);<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)) {<br />
		rc = ecryptfs_write_lower_page_segment(ecryptfs_inode, page, 0,<br />
						       to);<br />
		if (!rc) {<br />
			rc = copied;<br />
			fsstack_copy_inode_size(ecryptfs_inode,<br />
				ecryptfs_inode_to_lower(ecryptfs_inode));<br />
		}<br />
		goto out;<br />
	}<br />
	/* Fills in zeros if &#8216;to&#8217; goes beyond inode size */<br />
	rc = fill_zeros_to_end_of_page(page, to);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error attempting to fill &raquo;<br />
			&laquo;zeros in page with index = [0x%.16x]\n&raquo;, index);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_encrypt_page(page);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error encrypting page (upper &raquo;<br />
				&laquo;index [0x%.16x])\n&raquo;, index);<br />
		goto out;<br />
	}<br />
	if (pos + copied > i_size_read(ecryptfs_inode)) {<br />
		i_size_write(ecryptfs_inode, pos + copied);<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Expanded file size to &raquo;<br />
				&laquo;[0x%.16x]\n&raquo;, i_size_read(ecryptfs_inode));<br />
	}<br />
	rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;Error writing inode size to metadata; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, rc);<br />
	else<br />
		rc = copied;<br />
out:<br />
	unlock_page(page);<br />
	page_cache_release(page);<br />
	return rc;<br />
}</p>
<p>static sector_t ecryptfs_bmap(struct address_space *mapping, sector_t block)<br />
{<br />
	int rc = 0;<br />
	struct inode *inode;<br />
	struct inode *lower_inode;</p>
<p>	inode = (struct inode *)mapping->host;<br />
	lower_inode = ecryptfs_inode_to_lower(inode);<br />
	if (lower_inode->i_mapping->a_ops->bmap)<br />
		rc = lower_inode->i_mapping->a_ops->bmap(lower_inode->i_mapping,<br />
							 block);<br />
	return rc;<br />
}</p>
<p>const struct address_space_operations ecryptfs_aops = {<br />
	.writepage = ecryptfs_writepage,<br />
	.readpage = ecryptfs_readpage,<br />
	.write_begin = ecryptfs_write_begin,<br />
	.write_end = ecryptfs_write_end,<br />
	.bmap = ecryptfs_bmap,<br />
};</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/mmap-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>micsdev.c</title>
		<link>http://lynyrd.ru/micsdev-c</link>
		<comments>http://lynyrd.ru/micsdev-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:04:52 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1096</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 2008 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1096"></span><br />
 *<br />
 * Copyright (C) 2008 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License version<br />
 * 2 as published by the Free Software Foundation.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/fs.h>
#include
<linux/hash.h>
#include
<linux/random.h>
#include
<linux/miscdevice.h>
#include
<linux/poll.h>
#include
<linux/wait.h>
#include
<linux/module.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>static atomic_t ecryptfs_num_miscdev_opens;</p>
<p>/**<br />
 * ecryptfs_miscdev_poll<br />
 * @file: dev file (ignored)<br />
 * @pt: dev poll table (ignored)<br />
 *<br />
 * Returns the poll mask<br />
 */<br />
static unsigned int<br />
ecryptfs_miscdev_poll(struct file *file, poll_table *pt)<br />
{<br />
	struct ecryptfs_daemon *daemon;<br />
	unsigned int mask = 0;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	/* TODO: Just use file->private_data? */<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, current_user_ns());<br />
	BUG_ON(rc || !daemon);<br />
	mutex_lock(&#038;daemon->mux);<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_ZOMBIE) {<br />
		printk(KERN_WARNING &laquo;%s: Attempt to poll on zombified &raquo;<br />
		       &laquo;daemon\n&raquo;, __func__);<br />
		goto out_unlock_daemon;<br />
	}<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_IN_READ)<br />
		goto out_unlock_daemon;<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_IN_POLL)<br />
		goto out_unlock_daemon;<br />
	daemon->flags |= ECRYPTFS_DAEMON_IN_POLL;<br />
	mutex_unlock(&#038;daemon->mux);<br />
	poll_wait(file, &#038;daemon->wait, pt);<br />
	mutex_lock(&#038;daemon->mux);<br />
	if (!list_empty(&#038;daemon->msg_ctx_out_queue))<br />
		mask |= POLLIN | POLLRDNORM;<br />
out_unlock_daemon:<br />
	daemon->flags &#038;= ~ECRYPTFS_DAEMON_IN_POLL;<br />
	mutex_unlock(&#038;daemon->mux);<br />
	return mask;<br />
}</p>
<p>/**<br />
 * ecryptfs_miscdev_open<br />
 * @inode: inode of miscdev handle (ignored)<br />
 * @file: file for miscdev handle (ignored)<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int<br />
ecryptfs_miscdev_open(struct inode *inode, struct file *file)<br />
{<br />
	struct ecryptfs_daemon *daemon = NULL;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	rc = try_module_get(THIS_MODULE);<br />
	if (rc == 0) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR &laquo;%s: Error attempting to increment module use &raquo;<br />
		       &laquo;count; rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_unlock_daemon_list;<br />
	}<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, current_user_ns());<br />
	if (rc || !daemon) {<br />
		rc = ecryptfs_spawn_daemon(&#038;daemon, euid, current_user_ns(),<br />
					   task_pid(current));<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to spawn daemon; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
			goto out_module_put_unlock_daemon_list;<br />
		}<br />
	}<br />
	mutex_lock(&#038;daemon->mux);<br />
	if (daemon->pid != task_pid(current)) {<br />
		rc = -EINVAL;<br />
		printk(KERN_ERR &laquo;%s: pid [0x%p] has registered with euid [%d], &raquo;<br />
		       &laquo;but pid [0x%p] has attempted to open the handle &raquo;<br />
		       &laquo;instead\n&raquo;, __func__, daemon->pid, daemon->euid,<br />
		       task_pid(current));<br />
		goto out_unlock_daemon;<br />
	}<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_MISCDEV_OPEN) {<br />
		rc = -EBUSY;<br />
		printk(KERN_ERR &laquo;%s: Miscellaneous device handle may only be &raquo;<br />
		       &laquo;opened once per daemon; pid [0x%p] already has this &raquo;<br />
		       &laquo;handle open\n&raquo;, __func__, daemon->pid);<br />
		goto out_unlock_daemon;<br />
	}<br />
	daemon->flags |= ECRYPTFS_DAEMON_MISCDEV_OPEN;<br />
	atomic_inc(&#038;ecryptfs_num_miscdev_opens);<br />
out_unlock_daemon:<br />
	mutex_unlock(&#038;daemon->mux);<br />
out_module_put_unlock_daemon_list:<br />
	if (rc)<br />
		module_put(THIS_MODULE);<br />
out_unlock_daemon_list:<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_miscdev_release<br />
 * @inode: inode of fs/ecryptfs/euid handle (ignored)<br />
 * @file: file for fs/ecryptfs/euid handle (ignored)<br />
 *<br />
 * This keeps the daemon registered until the daemon sends another<br />
 * ioctl to fs/ecryptfs/ctl or until the kernel module unregisters.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int<br />
ecryptfs_miscdev_release(struct inode *inode, struct file *file)<br />
{<br />
	struct ecryptfs_daemon *daemon = NULL;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, current_user_ns());<br />
	BUG_ON(rc || !daemon);<br />
	mutex_lock(&#038;daemon->mux);<br />
	BUG_ON(daemon->pid != task_pid(current));<br />
	BUG_ON(!(daemon->flags &#038; ECRYPTFS_DAEMON_MISCDEV_OPEN));<br />
	daemon->flags &#038;= ~ECRYPTFS_DAEMON_MISCDEV_OPEN;<br />
	atomic_dec(&#038;ecryptfs_num_miscdev_opens);<br />
	mutex_unlock(&#038;daemon->mux);<br />
	rc = ecryptfs_exorcise_daemon(daemon);<br />
	if (rc) {<br />
		printk(KERN_CRIT &laquo;%s: Fatal error whilst attempting to &raquo;<br />
		       &laquo;shut down daemon; rc = [%d]. Please report this &raquo;<br />
		       &laquo;bug.\n&raquo;, __func__, rc);<br />
		BUG();<br />
	}<br />
	module_put(THIS_MODULE);<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_send_miscdev<br />
 * @data: Data to send to daemon; may be NULL<br />
 * @data_size: Amount of data to send to daemon<br />
 * @msg_ctx: Message context, which is used to handle the reply. If<br />
 *           this is NULL, then we do not expect a reply.<br />
 * @msg_type: Type of message<br />
 * @msg_flags: Flags for message<br />
 * @daemon: eCryptfs daemon object<br />
 *<br />
 * Add msg_ctx to queue and then, if it exists, notify the blocked<br />
 * miscdevess about the data being available. Must be called with<br />
 * ecryptfs_daemon_hash_mux held.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_send_miscdev(char *data, size_t data_size,<br />
			  struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,<br />
			  u16 msg_flags, struct ecryptfs_daemon *daemon)<br />
{<br />
	int rc = 0;</p>
<p>	mutex_lock(&#038;msg_ctx->mux);<br />
	msg_ctx->msg = kmalloc((sizeof(*msg_ctx->msg) + data_size),<br />
			       GFP_KERNEL);<br />
	if (!msg_ctx->msg) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
		       &laquo;to kmalloc(%zd, GFP_KERNEL)\n&raquo;, __func__,<br />
		       (sizeof(*msg_ctx->msg) + data_size));<br />
		goto out_unlock;<br />
	}<br />
	msg_ctx->msg->index = msg_ctx->index;<br />
	msg_ctx->msg->data_len = data_size;<br />
	msg_ctx->type = msg_type;<br />
	memcpy(msg_ctx->msg->data, data, data_size);<br />
	msg_ctx->msg_size = (sizeof(*msg_ctx->msg) + data_size);<br />
	mutex_lock(&#038;daemon->mux);<br />
	list_add_tail(&#038;msg_ctx->daemon_out_list, &#038;daemon->msg_ctx_out_queue);<br />
	daemon->num_queued_msg_ctx++;<br />
	wake_up_interruptible(&#038;daemon->wait);<br />
	mutex_unlock(&#038;daemon->mux);<br />
out_unlock:<br />
	mutex_unlock(&#038;msg_ctx->mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_miscdev_read &#8211; format and send message from queue<br />
 * @file: fs/ecryptfs/euid miscdevfs handle (ignored)<br />
 * @buf: User buffer into which to copy the next message on the daemon queue<br />
 * @count: Amount of space available in @buf<br />
 * @ppos: Offset in file (ignored)<br />
 *<br />
 * Pulls the most recent message from the daemon queue, formats it for<br />
 * being sent via a miscdevfs handle, and copies it into @buf<br />
 *<br />
 * Returns the number of bytes copied into the user buffer<br />
 */<br />
static ssize_t<br />
ecryptfs_miscdev_read(struct file *file, char __user *buf, size_t count,<br />
		      loff_t *ppos)<br />
{<br />
	struct ecryptfs_daemon *daemon;<br />
	struct ecryptfs_msg_ctx *msg_ctx;<br />
	size_t packet_length_size;<br />
	char packet_length[3];<br />
	size_t i;<br />
	size_t total_length;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	/* TODO: Just use file->private_data? */<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, current_user_ns());<br />
	BUG_ON(rc || !daemon);<br />
	mutex_lock(&#038;daemon->mux);<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_ZOMBIE) {<br />
		rc = 0;<br />
		mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
		printk(KERN_WARNING &laquo;%s: Attempt to read from zombified &raquo;<br />
		       &laquo;daemon\n&raquo;, __func__);<br />
		goto out_unlock_daemon;<br />
	}<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_IN_READ) {<br />
		rc = 0;<br />
		mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
		goto out_unlock_daemon;<br />
	}<br />
	/* This daemon will not go away so long as this flag is set */<br />
	daemon->flags |= ECRYPTFS_DAEMON_IN_READ;<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
check_list:<br />
	if (list_empty(&#038;daemon->msg_ctx_out_queue)) {<br />
		mutex_unlock(&#038;daemon->mux);<br />
		rc = wait_event_interruptible(<br />
			daemon->wait, !list_empty(&#038;daemon->msg_ctx_out_queue));<br />
		mutex_lock(&#038;daemon->mux);<br />
		if (rc < 0) {<br />
			rc = 0;<br />
			goto out_unlock_daemon;<br />
		}<br />
	}<br />
	if (daemon->flags &#038; ECRYPTFS_DAEMON_ZOMBIE) {<br />
		rc = 0;<br />
		goto out_unlock_daemon;<br />
	}<br />
	if (list_empty(&#038;daemon->msg_ctx_out_queue)) {<br />
		/* Something else jumped in since the<br />
		 * wait_event_interruptable() and removed the<br />
		 * message from the queue; try again */<br />
		goto check_list;<br />
	}<br />
	BUG_ON(euid != daemon->euid);<br />
	BUG_ON(current_user_ns() != daemon->user_ns);<br />
	BUG_ON(task_pid(current) != daemon->pid);<br />
	msg_ctx = list_first_entry(&#038;daemon->msg_ctx_out_queue,<br />
				   struct ecryptfs_msg_ctx, daemon_out_list);<br />
	BUG_ON(!msg_ctx);<br />
	mutex_lock(&#038;msg_ctx->mux);<br />
	if (msg_ctx->msg) {<br />
		rc = ecryptfs_write_packet_length(packet_length,<br />
						  msg_ctx->msg_size,<br />
						  &#038;packet_length_size);<br />
		if (rc) {<br />
			rc = 0;<br />
			printk(KERN_WARNING &laquo;%s: Error writing packet length; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
			goto out_unlock_msg_ctx;<br />
		}<br />
	} else {<br />
		packet_length_size = 0;<br />
		msg_ctx->msg_size = 0;<br />
	}<br />
	/* miscdevfs packet format:<br />
	 *  Octet 0: Type<br />
	 *  Octets 1-4: network byte order msg_ctx->counter<br />
	 *  Octets 5-N0: Size of struct ecryptfs_message to follow<br />
	 *  Octets N0-N1: struct ecryptfs_message (including data)<br />
	 *<br />
	 *  Octets 5-N1 not written if the packet type does not<br />
	 *  include a message */<br />
	total_length = (1 + 4 + packet_length_size + msg_ctx->msg_size);<br />
	if (count < total_length) {<br />
		rc = 0;<br />
		printk(KERN_WARNING "%s: Only given user buffer of "<br />
		       "size [%zd], but we need [%zd] to read the "<br />
		       "pending message\n", __func__, count, total_length);<br />
		goto out_unlock_msg_ctx;<br />
	}<br />
	rc = -EFAULT;<br />
	if (put_user(msg_ctx->type, buf))<br />
		goto out_unlock_msg_ctx;<br />
	if (put_user(cpu_to_be32(msg_ctx->counter), (__be32 __user *)(buf + 1)))<br />
		goto out_unlock_msg_ctx;<br />
	i = 5;<br />
	if (msg_ctx->msg) {<br />
		if (copy_to_user(&#038;buf[i], packet_length, packet_length_size))<br />
			goto out_unlock_msg_ctx;<br />
		i += packet_length_size;<br />
		if (copy_to_user(&#038;buf[i], msg_ctx->msg, msg_ctx->msg_size))<br />
			goto out_unlock_msg_ctx;<br />
		i += msg_ctx->msg_size;<br />
	}<br />
	rc = i;<br />
	list_del(&#038;msg_ctx->daemon_out_list);<br />
	kfree(msg_ctx->msg);<br />
	msg_ctx->msg = NULL;<br />
	/* We do not expect a reply from the userspace daemon for any<br />
	 * message type other than ECRYPTFS_MSG_REQUEST */<br />
	if (msg_ctx->type != ECRYPTFS_MSG_REQUEST)<br />
		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);<br />
out_unlock_msg_ctx:<br />
	mutex_unlock(&#038;msg_ctx->mux);<br />
out_unlock_daemon:<br />
	daemon->flags &#038;= ~ECRYPTFS_DAEMON_IN_READ;<br />
	mutex_unlock(&#038;daemon->mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_miscdev_response &#8211; miscdevess response to message previously sent to daemon<br />
 * @data: Bytes comprising struct ecryptfs_message<br />
 * @data_size: sizeof(struct ecryptfs_message) + data len<br />
 * @euid: Effective user id of miscdevess sending the miscdev response<br />
 * @user_ns: The namespace in which @euid applies<br />
 * @pid: Miscdevess id of miscdevess sending the miscdev response<br />
 * @seq: Sequence number for miscdev response packet<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_miscdev_response(char *data, size_t data_size,<br />
				     uid_t euid, struct user_namespace *user_ns,<br />
				     struct pid *pid, u32 seq)<br />
{<br />
	struct ecryptfs_message *msg = (struct ecryptfs_message *)data;<br />
	int rc;</p>
<p>	if ((sizeof(*msg) + msg->data_len) != data_size) {<br />
		printk(KERN_WARNING &laquo;%s: (sizeof(*msg) + msg->data_len) = &raquo;<br />
		       &laquo;[%zd]; data_size = [%zd]. Invalid packet.\n&raquo;, __func__,<br />
		       (sizeof(*msg) + msg->data_len), data_size);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_process_response(msg, euid, user_ns, pid, seq);<br />
	if (rc)<br />
		printk(KERN_ERR<br />
		       &laquo;Error processing response message; rc = [%d]\n&raquo;, rc);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_miscdev_write &#8211; handle write to daemon miscdev handle<br />
 * @file: File for misc dev handle (ignored)<br />
 * @buf: Buffer containing user data<br />
 * @count: Amount of data in @buf<br />
 * @ppos: Pointer to offset in file (ignored)<br />
 *<br />
 * miscdevfs packet format:<br />
 *  Octet 0: Type<br />
 *  Octets 1-4: network byte order msg_ctx->counter (0&#8217;s for non-response)<br />
 *  Octets 5-N0: Size of struct ecryptfs_message to follow<br />
 *  Octets N0-N1: struct ecryptfs_message (including data)<br />
 *<br />
 * Returns the number of bytes read from @buf<br />
 */<br />
static ssize_t<br />
ecryptfs_miscdev_write(struct file *file, const char __user *buf,<br />
		       size_t count, loff_t *ppos)<br />
{<br />
	__be32 counter_nbo;<br />
	u32 seq;<br />
	size_t packet_size, packet_size_length, i;<br />
	ssize_t sz = 0;<br />
	char *data;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	if (count == 0)<br />
		goto out;</p>
<p>	data = memdup_user(buf, count);<br />
	if (IS_ERR(data)) {<br />
		printk(KERN_ERR &laquo;%s: memdup_user returned error [%ld]\n&raquo;,<br />
		       __func__, PTR_ERR(data));<br />
		goto out;<br />
	}<br />
	sz = count;<br />
	i = 0;<br />
	switch (data[i++]) {<br />
	case ECRYPTFS_MSG_RESPONSE:<br />
		if (count < (1 + 4 + 1 + sizeof(struct ecryptfs_message))) {<br />
			printk(KERN_WARNING &laquo;%s: Minimum acceptable packet &raquo;<br />
			       &laquo;size is [%zd], but amount of data written is &raquo;<br />
			       &laquo;only [%zd]. Discarding response packet.\n&raquo;,<br />
			       __func__,<br />
			       (1 + 4 + 1 + sizeof(struct ecryptfs_message)),<br />
			       count);<br />
			goto out_free;<br />
		}<br />
		memcpy(&#038;counter_nbo, &#038;data[i], 4);<br />
		seq = be32_to_cpu(counter_nbo);<br />
		i += 4;<br />
		rc = ecryptfs_parse_packet_length(&#038;data[i], &#038;packet_size,<br />
						  &#038;packet_size_length);<br />
		if (rc) {<br />
			printk(KERN_WARNING &laquo;%s: Error parsing packet length; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
			goto out_free;<br />
		}<br />
		i += packet_size_length;<br />
		if ((1 + 4 + packet_size_length + packet_size) != count) {<br />
			printk(KERN_WARNING &laquo;%s: (1 + packet_size_length([%zd])&raquo;<br />
			       &raquo; + packet_size([%zd]))([%zd]) != &raquo;<br />
			       &laquo;count([%zd]). Invalid packet format.\n&raquo;,<br />
			       __func__, packet_size_length, packet_size,<br />
			       (1 + packet_size_length + packet_size), count);<br />
			goto out_free;<br />
		}<br />
		rc = ecryptfs_miscdev_response(&#038;data[i], packet_size,<br />
					       euid, current_user_ns(),<br />
					       task_pid(current), seq);<br />
		if (rc)<br />
			printk(KERN_WARNING &laquo;%s: Failed to deliver miscdev &raquo;<br />
			       &laquo;response to requesting operation; rc = [%d]\n&raquo;,<br />
			       __func__, rc);<br />
		break;<br />
	case ECRYPTFS_MSG_HELO:<br />
	case ECRYPTFS_MSG_QUIT:<br />
		break;<br />
	default:<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Dropping miscdev &raquo;<br />
				&laquo;message of unrecognized type [%d]\n&raquo;,<br />
				data[0]);<br />
		break;<br />
	}<br />
out_free:<br />
	kfree(data);<br />
out:<br />
	return sz;<br />
}</p>
<p>static const struct file_operations ecryptfs_miscdev_fops = {<br />
	.open    = ecryptfs_miscdev_open,<br />
	.poll    = ecryptfs_miscdev_poll,<br />
	.read    = ecryptfs_miscdev_read,<br />
	.write   = ecryptfs_miscdev_write,<br />
	.release = ecryptfs_miscdev_release,<br />
};</p>
<p>static struct miscdevice ecryptfs_miscdev = {<br />
	.minor = MISC_DYNAMIC_MINOR,<br />
	.name  = &laquo;ecryptfs&raquo;,<br />
	.fops  = &#038;ecryptfs_miscdev_fops<br />
};</p>
<p>/**<br />
 * ecryptfs_init_ecryptfs_miscdev<br />
 *<br />
 * Messages sent to the userspace daemon from the kernel are placed on<br />
 * a queue associated with the daemon. The next read against the<br />
 * miscdev handle by that daemon will return the oldest message placed<br />
 * on the message queue for the daemon.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_init_ecryptfs_miscdev(void)<br />
{<br />
	int rc;</p>
<p>	atomic_set(&#038;ecryptfs_num_miscdev_opens, 0);<br />
	rc = misc_register(&#038;ecryptfs_miscdev);<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;%s: Failed to register miscellaneous device &raquo;<br />
		       &laquo;for communications with userspace daemons; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_destroy_ecryptfs_miscdev<br />
 *<br />
 * All of the daemons must be exorcised prior to calling this<br />
 * function.<br />
 */<br />
void ecryptfs_destroy_ecryptfs_miscdev(void)<br />
{<br />
	BUG_ON(atomic_read(&#038;ecryptfs_num_miscdev_opens) != 0);<br />
	misc_deregister(&#038;ecryptfs_miscdev);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/micsdev-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>messaging.c</title>
		<link>http://lynyrd.ru/messaging-c</link>
		<comments>http://lynyrd.ru/messaging-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:04:34 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1094</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 2004-2008 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *		Tyler Hicks 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1094"></span><br />
 *<br />
 * Copyright (C) 2004-2008 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com><br />
 *		Tyler Hicks <tyhicks@ou.edu><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License version<br />
 * 2 as published by the Free Software Foundation.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */<br />
#include
<linux/sched.h>
#include
<linux/user_namespace.h>
#include
<linux/nsproxy.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>static LIST_HEAD(ecryptfs_msg_ctx_free_list);<br />
static LIST_HEAD(ecryptfs_msg_ctx_alloc_list);<br />
static struct mutex ecryptfs_msg_ctx_lists_mux;</p>
<p>static struct hlist_head *ecryptfs_daemon_hash;<br />
struct mutex ecryptfs_daemon_hash_mux;<br />
static int ecryptfs_hash_buckets;<br />
#define ecryptfs_uid_hash(uid) \<br />
        hash_long((unsigned long)uid, ecryptfs_hash_buckets)</p>
<p>static u32 ecryptfs_msg_counter;<br />
static struct ecryptfs_msg_ctx *ecryptfs_msg_ctx_arr;</p>
<p>/**<br />
 * ecryptfs_acquire_free_msg_ctx<br />
 * @msg_ctx: The context that was acquired from the free list<br />
 *<br />
 * Acquires a context element from the free list and locks the mutex<br />
 * on the context.  Sets the msg_ctx task to current.  Returns zero on<br />
 * success; non-zero on error or upon failure to acquire a free<br />
 * context element.  Must be called with ecryptfs_msg_ctx_lists_mux<br />
 * held.<br />
 */<br />
static int ecryptfs_acquire_free_msg_ctx(struct ecryptfs_msg_ctx **msg_ctx)<br />
{<br />
	struct list_head *p;<br />
	int rc;</p>
<p>	if (list_empty(&#038;ecryptfs_msg_ctx_free_list)) {<br />
		printk(KERN_WARNING &laquo;%s: The eCryptfs free &raquo;<br />
		       &laquo;context list is empty.  It may be helpful to &raquo;<br />
		       &laquo;specify the ecryptfs_message_buf_len &raquo;<br />
		       &laquo;parameter to be greater than the current &raquo;<br />
		       &laquo;value of [%d]\n&raquo;, __func__, ecryptfs_message_buf_len);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	list_for_each(p, &#038;ecryptfs_msg_ctx_free_list) {<br />
		*msg_ctx = list_entry(p, struct ecryptfs_msg_ctx, node);<br />
		if (mutex_trylock(&#038;(*msg_ctx)->mux)) {<br />
			(*msg_ctx)->task = current;<br />
			rc = 0;<br />
			goto out;<br />
		}<br />
	}<br />
	rc = -ENOMEM;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_msg_ctx_free_to_alloc<br />
 * @msg_ctx: The context to move from the free list to the alloc list<br />
 *<br />
 * Must be called with ecryptfs_msg_ctx_lists_mux held.<br />
 */<br />
static void ecryptfs_msg_ctx_free_to_alloc(struct ecryptfs_msg_ctx *msg_ctx)<br />
{<br />
	list_move(&#038;msg_ctx->node, &#038;ecryptfs_msg_ctx_alloc_list);<br />
	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_PENDING;<br />
	msg_ctx->counter = ++ecryptfs_msg_counter;<br />
}</p>
<p>/**<br />
 * ecryptfs_msg_ctx_alloc_to_free<br />
 * @msg_ctx: The context to move from the alloc list to the free list<br />
 *<br />
 * Must be called with ecryptfs_msg_ctx_lists_mux held.<br />
 */<br />
void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx)<br />
{<br />
	list_move(&#038;(msg_ctx->node), &#038;ecryptfs_msg_ctx_free_list);<br />
	if (msg_ctx->msg)<br />
		kfree(msg_ctx->msg);<br />
	msg_ctx->msg = NULL;<br />
	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_FREE;<br />
}</p>
<p>/**<br />
 * ecryptfs_find_daemon_by_euid<br />
 * @euid: The effective user id which maps to the desired daemon id<br />
 * @user_ns: The namespace in which @euid applies<br />
 * @daemon: If return value is zero, points to the desired daemon pointer<br />
 *<br />
 * Must be called with ecryptfs_daemon_hash_mux held.<br />
 *<br />
 * Search the hash list for the given user id.<br />
 *<br />
 * Returns zero if the user id exists in the list; non-zero otherwise.<br />
 */<br />
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,<br />
				 struct user_namespace *user_ns)<br />
{<br />
	struct hlist_node *elem;<br />
	int rc;</p>
<p>	hlist_for_each_entry(*daemon, elem,<br />
			     &#038;ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)],<br />
			     euid_chain) {<br />
		if ((*daemon)->euid == euid &#038;&#038; (*daemon)->user_ns == user_ns) {<br />
			rc = 0;<br />
			goto out;<br />
		}<br />
	}<br />
	rc = -EINVAL;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_spawn_daemon &#8211; Create and initialize a new daemon struct<br />
 * @daemon: Pointer to set to newly allocated daemon struct<br />
 * @euid: Effective user id for the daemon<br />
 * @user_ns: The namespace in which @euid applies<br />
 * @pid: Process id for the daemon<br />
 *<br />
 * Must be called ceremoniously while in possession of<br />
 * ecryptfs_sacred_daemon_hash_mux<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int<br />
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,<br />
		      struct user_namespace *user_ns, struct pid *pid)<br />
{<br />
	int rc = 0;</p>
<p>	(*daemon) = kzalloc(sizeof(**daemon), GFP_KERNEL);<br />
	if (!(*daemon)) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Failed to allocate [%zd] bytes of &raquo;<br />
		       &laquo;GFP_KERNEL memory\n&raquo;, __func__, sizeof(**daemon));<br />
		goto out;<br />
	}<br />
	(*daemon)->euid = euid;<br />
	(*daemon)->user_ns = get_user_ns(user_ns);<br />
	(*daemon)->pid = get_pid(pid);<br />
	(*daemon)->task = current;<br />
	mutex_init(&#038;(*daemon)->mux);<br />
	INIT_LIST_HEAD(&#038;(*daemon)->msg_ctx_out_queue);<br />
	init_waitqueue_head(&#038;(*daemon)->wait);<br />
	(*daemon)->num_queued_msg_ctx = 0;<br />
	hlist_add_head(&#038;(*daemon)->euid_chain,<br />
		       &#038;ecryptfs_daemon_hash[ecryptfs_uid_hash(euid)]);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_exorcise_daemon &#8211; Destroy the daemon struct<br />
 *<br />
 * Must be called ceremoniously while in possession of<br />
 * ecryptfs_daemon_hash_mux and the daemon&#8217;s own mux.<br />
 */<br />
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon)<br />
{<br />
	struct ecryptfs_msg_ctx *msg_ctx, *msg_ctx_tmp;<br />
	int rc = 0;</p>
<p>	mutex_lock(&#038;daemon->mux);<br />
	if ((daemon->flags &#038; ECRYPTFS_DAEMON_IN_READ)<br />
	    || (daemon->flags &#038; ECRYPTFS_DAEMON_IN_POLL)) {<br />
		rc = -EBUSY;<br />
		printk(KERN_WARNING &laquo;%s: Attempt to destroy daemon with pid &raquo;<br />
		       &laquo;[0x%p], but it is in the midst of a read or a poll\n&raquo;,<br />
		       __func__, daemon->pid);<br />
		mutex_unlock(&#038;daemon->mux);<br />
		goto out;<br />
	}<br />
	list_for_each_entry_safe(msg_ctx, msg_ctx_tmp,<br />
				 &#038;daemon->msg_ctx_out_queue, daemon_out_list) {<br />
		list_del(&#038;msg_ctx->daemon_out_list);<br />
		daemon->num_queued_msg_ctx&#8211;;<br />
		printk(KERN_WARNING &laquo;%s: Warning: dropping message that is in &raquo;<br />
		       &laquo;the out queue of a dying daemon\n&raquo;, __func__);<br />
		ecryptfs_msg_ctx_alloc_to_free(msg_ctx);<br />
	}<br />
	hlist_del(&#038;daemon->euid_chain);<br />
	if (daemon->task)<br />
		wake_up_process(daemon->task);<br />
	if (daemon->pid)<br />
		put_pid(daemon->pid);<br />
	if (daemon->user_ns)<br />
		put_user_ns(daemon->user_ns);<br />
	mutex_unlock(&#038;daemon->mux);<br />
	kzfree(daemon);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_process_quit<br />
 * @euid: The user ID owner of the message<br />
 * @user_ns: The namespace in which @euid applies<br />
 * @pid: The process ID for the userspace program that sent the<br />
 *       message<br />
 *<br />
 * Deletes the corresponding daemon for the given euid and pid, if<br />
 * it is the registered that is requesting the deletion. Returns zero<br />
 * after deleting the desired daemon; non-zero otherwise.<br />
 */<br />
int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,<br />
			  struct pid *pid)<br />
{<br />
	struct ecryptfs_daemon *daemon;<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, user_ns);<br />
	if (rc || !daemon) {<br />
		rc = -EINVAL;<br />
		printk(KERN_ERR &laquo;Received request from user [%d] to &raquo;<br />
		       &laquo;unregister unrecognized daemon [0x%p]\n&raquo;, euid, pid);<br />
		goto out_unlock;<br />
	}<br />
	rc = ecryptfs_exorcise_daemon(daemon);<br />
out_unlock:<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_process_reponse<br />
 * @msg: The ecryptfs message received; the caller should sanity check<br />
 *       msg->data_len and free the memory<br />
 * @pid: The process ID of the userspace application that sent the<br />
 *       message<br />
 * @seq: The sequence number of the message; must match the sequence<br />
 *       number for the existing message context waiting for this<br />
 *       response<br />
 *<br />
 * Processes a response message after sending an operation request to<br />
 * userspace. Some other process is awaiting this response. Before<br />
 * sending out its first communications, the other process allocated a<br />
 * msg_ctx from the ecryptfs_msg_ctx_arr at a particular index. The<br />
 * response message contains this index so that we can copy over the<br />
 * response message into the msg_ctx that the process holds a<br />
 * reference to. The other process is going to wake up, check to see<br />
 * that msg_ctx->state == ECRYPTFS_MSG_CTX_STATE_DONE, and then<br />
 * proceed to read off and process the response message. Returns zero<br />
 * upon delivery to desired context element; non-zero upon delivery<br />
 * failure or error.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,<br />
			      struct user_namespace *user_ns, struct pid *pid,<br />
			      u32 seq)<br />
{<br />
	struct ecryptfs_daemon *daemon;<br />
	struct ecryptfs_msg_ctx *msg_ctx;<br />
	size_t msg_size;<br />
	struct nsproxy *nsproxy;<br />
	struct user_namespace *tsk_user_ns;<br />
	uid_t ctx_euid;<br />
	int rc;</p>
<p>	if (msg->index >= ecryptfs_message_buf_len) {<br />
		rc = -EINVAL;<br />
		printk(KERN_ERR &laquo;%s: Attempt to reference &raquo;<br />
		       &laquo;context buffer at index [%d]; maximum &raquo;<br />
		       &laquo;allowable is [%d]\n&raquo;, __func__, msg->index,<br />
		       (ecryptfs_message_buf_len &#8211; 1));<br />
		goto out;<br />
	}<br />
	msg_ctx = &#038;ecryptfs_msg_ctx_arr[msg->index];<br />
	mutex_lock(&#038;msg_ctx->mux);<br />
	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	rcu_read_lock();<br />
	nsproxy = task_nsproxy(msg_ctx->task);<br />
	if (nsproxy == NULL) {<br />
		rc = -EBADMSG;<br />
		printk(KERN_ERR &laquo;%s: Receiving process is a zombie. Dropping &raquo;<br />
		       &laquo;message.\n&raquo;, __func__);<br />
		rcu_read_unlock();<br />
		mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
		goto wake_up;<br />
	}<br />
	tsk_user_ns = __task_cred(msg_ctx->task)->user->user_ns;<br />
	ctx_euid = task_euid(msg_ctx->task);<br />
	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, ctx_euid, tsk_user_ns);<br />
	rcu_read_unlock();<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	if (rc) {<br />
		rc = -EBADMSG;<br />
		printk(KERN_WARNING &laquo;%s: User [%d] received a &raquo;<br />
		       &laquo;message response from process [0x%p] but does &raquo;<br />
		       &laquo;not have a registered daemon\n&raquo;, __func__,<br />
		       ctx_euid, pid);<br />
		goto wake_up;<br />
	}<br />
	if (ctx_euid != euid) {<br />
		rc = -EBADMSG;<br />
		printk(KERN_WARNING &laquo;%s: Received message from user &raquo;<br />
		       &laquo;[%d]; expected message from user [%d]\n&raquo;, __func__,<br />
		       euid, ctx_euid);<br />
		goto unlock;<br />
	}<br />
	if (tsk_user_ns != user_ns) {<br />
		rc = -EBADMSG;<br />
		printk(KERN_WARNING &laquo;%s: Received message from user_ns &raquo;<br />
		       &laquo;[0x%p]; expected message from user_ns [0x%p]\n&raquo;,<br />
		       __func__, user_ns, tsk_user_ns);<br />
		goto unlock;<br />
	}<br />
	if (daemon->pid != pid) {<br />
		rc = -EBADMSG;<br />
		printk(KERN_ERR &laquo;%s: User [%d] sent a message response &raquo;<br />
		       &laquo;from an unrecognized process [0x%p]\n&raquo;,<br />
		       __func__, ctx_euid, pid);<br />
		goto unlock;<br />
	}<br />
	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_PENDING) {<br />
		rc = -EINVAL;<br />
		printk(KERN_WARNING &laquo;%s: Desired context element is not &raquo;<br />
		       &laquo;pending a response\n&raquo;, __func__);<br />
		goto unlock;<br />
	} else if (msg_ctx->counter != seq) {<br />
		rc = -EINVAL;<br />
		printk(KERN_WARNING &laquo;%s: Invalid message sequence; &raquo;<br />
		       &laquo;expected [%d]; received [%d]\n&raquo;, __func__,<br />
		       msg_ctx->counter, seq);<br />
		goto unlock;<br />
	}<br />
	msg_size = (sizeof(*msg) + msg->data_len);<br />
	msg_ctx->msg = kmalloc(msg_size, GFP_KERNEL);<br />
	if (!msg_ctx->msg) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Failed to allocate [%zd] bytes of &raquo;<br />
		       &laquo;GFP_KERNEL memory\n&raquo;, __func__, msg_size);<br />
		goto unlock;<br />
	}<br />
	memcpy(msg_ctx->msg, msg, msg_size);<br />
	msg_ctx->state = ECRYPTFS_MSG_CTX_STATE_DONE;<br />
	rc = 0;<br />
wake_up:<br />
	wake_up_process(msg_ctx->task);<br />
unlock:<br />
	mutex_unlock(&#038;msg_ctx->mux);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_send_message_locked<br />
 * @data: The data to send<br />
 * @data_len: The length of data<br />
 * @msg_ctx: The message context allocated for the send<br />
 *<br />
 * Must be called with ecryptfs_daemon_hash_mux held.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int<br />
ecryptfs_send_message_locked(char *data, int data_len, u8 msg_type,<br />
			     struct ecryptfs_msg_ctx **msg_ctx)<br />
{<br />
	struct ecryptfs_daemon *daemon;<br />
	uid_t euid = current_euid();<br />
	int rc;</p>
<p>	rc = ecryptfs_find_daemon_by_euid(&#038;daemon, euid, current_user_ns());<br />
	if (rc || !daemon) {<br />
		rc = -ENOTCONN;<br />
		printk(KERN_ERR &laquo;%s: User [%d] does not have a daemon &raquo;<br />
		       &laquo;registered\n&raquo;, __func__, euid);<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	rc = ecryptfs_acquire_free_msg_ctx(msg_ctx);<br />
	if (rc) {<br />
		mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
		printk(KERN_WARNING &laquo;%s: Could not claim a free &raquo;<br />
		       &laquo;context element\n&raquo;, __func__);<br />
		goto out;<br />
	}<br />
	ecryptfs_msg_ctx_free_to_alloc(*msg_ctx);<br />
	mutex_unlock(&#038;(*msg_ctx)->mux);<br />
	mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	rc = ecryptfs_send_miscdev(data, data_len, *msg_ctx, msg_type, 0,<br />
				   daemon);<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;%s: Error attempting to send message to &raquo;<br />
		       &laquo;userspace daemon; rc = [%d]\n&raquo;, __func__, rc);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_send_message<br />
 * @data: The data to send<br />
 * @data_len: The length of data<br />
 * @msg_ctx: The message context allocated for the send<br />
 *<br />
 * Grabs ecryptfs_daemon_hash_mux.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_send_message(char *data, int data_len,<br />
			  struct ecryptfs_msg_ctx **msg_ctx)<br />
{<br />
	int rc;</p>
<p>	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	rc = ecryptfs_send_message_locked(data, data_len, ECRYPTFS_MSG_REQUEST,<br />
					  msg_ctx);<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_wait_for_response<br />
 * @msg_ctx: The context that was assigned when sending a message<br />
 * @msg: The incoming message from userspace; not set if rc != 0<br />
 *<br />
 * Sleeps until awaken by ecryptfs_receive_message or until the amount<br />
 * of time exceeds ecryptfs_message_wait_timeout.  If zero is<br />
 * returned, msg will point to a valid message from userspace; a<br />
 * non-zero value is returned upon failure to receive a message or an<br />
 * error occurs. Callee must free @msg on success.<br />
 */<br />
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,<br />
			       struct ecryptfs_message **msg)<br />
{<br />
	signed long timeout = ecryptfs_message_wait_timeout * HZ;<br />
	int rc = 0;</p>
<p>sleep:<br />
	timeout = schedule_timeout_interruptible(timeout);<br />
	mutex_lock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	mutex_lock(&#038;msg_ctx->mux);<br />
	if (msg_ctx->state != ECRYPTFS_MSG_CTX_STATE_DONE) {<br />
		if (timeout) {<br />
			mutex_unlock(&#038;msg_ctx->mux);<br />
			mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
			goto sleep;<br />
		}<br />
		rc = -ENOMSG;<br />
	} else {<br />
		*msg = msg_ctx->msg;<br />
		msg_ctx->msg = NULL;<br />
	}<br />
	ecryptfs_msg_ctx_alloc_to_free(msg_ctx);<br />
	mutex_unlock(&#038;msg_ctx->mux);<br />
	mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	return rc;<br />
}</p>
<p>int ecryptfs_init_messaging(void)<br />
{<br />
	int i;<br />
	int rc = 0;</p>
<p>	if (ecryptfs_number_of_users > ECRYPTFS_MAX_NUM_USERS) {<br />
		ecryptfs_number_of_users = ECRYPTFS_MAX_NUM_USERS;<br />
		printk(KERN_WARNING &laquo;%s: Specified number of users is &raquo;<br />
		       &laquo;too large, defaulting to [%d] users\n&raquo;, __func__,<br />
		       ecryptfs_number_of_users);<br />
	}<br />
	mutex_init(&#038;ecryptfs_daemon_hash_mux);<br />
	mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
	ecryptfs_hash_buckets = 1;<br />
	while (ecryptfs_number_of_users >> ecryptfs_hash_buckets)<br />
		ecryptfs_hash_buckets++;<br />
	ecryptfs_daemon_hash = kmalloc((sizeof(struct hlist_head)<br />
					* ecryptfs_hash_buckets), GFP_KERNEL);<br />
	if (!ecryptfs_daemon_hash) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Failed to allocate memory\n&raquo;, __func__);<br />
		mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
		goto out;<br />
	}<br />
	for (i = 0; i < ecryptfs_hash_buckets; i++)<br />
		INIT_HLIST_HEAD(&#038;ecryptfs_daemon_hash[i]);<br />
	mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	ecryptfs_msg_ctx_arr = kmalloc((sizeof(struct ecryptfs_msg_ctx)<br />
					* ecryptfs_message_buf_len),<br />
				       GFP_KERNEL);<br />
	if (!ecryptfs_msg_ctx_arr) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Failed to allocate memory\n&raquo;, __func__);<br />
		goto out;<br />
	}<br />
	mutex_init(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	mutex_lock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	ecryptfs_msg_counter = 0;<br />
	for (i = 0; i < ecryptfs_message_buf_len; i++) {<br />
		INIT_LIST_HEAD(&#038;ecryptfs_msg_ctx_arr[i].node);<br />
		INIT_LIST_HEAD(&#038;ecryptfs_msg_ctx_arr[i].daemon_out_list);<br />
		mutex_init(&#038;ecryptfs_msg_ctx_arr[i].mux);<br />
		mutex_lock(&#038;ecryptfs_msg_ctx_arr[i].mux);<br />
		ecryptfs_msg_ctx_arr[i].index = i;<br />
		ecryptfs_msg_ctx_arr[i].state = ECRYPTFS_MSG_CTX_STATE_FREE;<br />
		ecryptfs_msg_ctx_arr[i].counter = 0;<br />
		ecryptfs_msg_ctx_arr[i].task = NULL;<br />
		ecryptfs_msg_ctx_arr[i].msg = NULL;<br />
		list_add_tail(&#038;ecryptfs_msg_ctx_arr[i].node,<br />
			      &#038;ecryptfs_msg_ctx_free_list);<br />
		mutex_unlock(&#038;ecryptfs_msg_ctx_arr[i].mux);<br />
	}<br />
	mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	rc = ecryptfs_init_ecryptfs_miscdev();<br />
	if (rc)<br />
		ecryptfs_release_messaging();<br />
out:<br />
	return rc;<br />
}</p>
<p>void ecryptfs_release_messaging(void)<br />
{<br />
	if (ecryptfs_msg_ctx_arr) {<br />
		int i;</p>
<p>		mutex_lock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
		for (i = 0; i < ecryptfs_message_buf_len; i++) {<br />
			mutex_lock(&#038;ecryptfs_msg_ctx_arr[i].mux);<br />
			if (ecryptfs_msg_ctx_arr[i].msg)<br />
				kfree(ecryptfs_msg_ctx_arr[i].msg);<br />
			mutex_unlock(&#038;ecryptfs_msg_ctx_arr[i].mux);<br />
		}<br />
		kfree(ecryptfs_msg_ctx_arr);<br />
		mutex_unlock(&#038;ecryptfs_msg_ctx_lists_mux);<br />
	}<br />
	if (ecryptfs_daemon_hash) {<br />
		struct hlist_node *elem;<br />
		struct ecryptfs_daemon *daemon;<br />
		int i;</p>
<p>		mutex_lock(&#038;ecryptfs_daemon_hash_mux);<br />
		for (i = 0; i < ecryptfs_hash_buckets; i++) {<br />
			int rc;</p>
<p>			hlist_for_each_entry(daemon, elem,<br />
					     &#038;ecryptfs_daemon_hash[i],<br />
					     euid_chain) {<br />
				rc = ecryptfs_exorcise_daemon(daemon);<br />
				if (rc)<br />
					printk(KERN_ERR &laquo;%s: Error whilst &raquo;<br />
					       &laquo;attempting to destroy daemon; &raquo;<br />
					       &laquo;rc = [%d]. Dazed and confused, &raquo;<br />
					       &laquo;but trying to continue.\n&raquo;,<br />
					       __func__, rc);<br />
			}<br />
		}<br />
		kfree(ecryptfs_daemon_hash);<br />
		mutex_unlock(&#038;ecryptfs_daemon_hash_mux);<br />
	}<br />
	ecryptfs_destroy_ecryptfs_miscdev();<br />
	return;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/messaging-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>main.c</title>
		<link>http://lynyrd.ru/main-c-3</link>
		<comments>http://lynyrd.ru/main-c-3#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:04:03 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1092</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2003 Erez Zadok
 * Copyright (C) 2001-2003 Stony Brook University
 * Copyright (C) 2004-2007 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *              Michael C. Thompson 
 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1092"></span><br />
 *<br />
 * Copyright (C) 1997-2003 Erez Zadok<br />
 * Copyright (C) 2001-2003 Stony Brook University<br />
 * Copyright (C) 2004-2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *              Michael C. Thompson <mcthomps@us.ibm.com><br />
 *              Tyler Hicks <tyhicks@ou.edu><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/dcache.h>
#include
<linux/file.h>
#include
<linux/module.h>
#include
<linux/namei.h>
#include
<linux/skbuff.h>
#include
<linux/crypto.h>
#include
<linux/mount.h>
#include
<linux/pagemap.h>
#include
<linux/key.h>
#include
<linux/parser.h>
#include
<linux/fs_stack.h>
#include
<linux/ima.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * Module parameter that defines the ecryptfs_verbosity level.<br />
 */<br />
int ecryptfs_verbosity = 0;</p>
<p>module_param(ecryptfs_verbosity, int, 0);<br />
MODULE_PARM_DESC(ecryptfs_verbosity,<br />
		 &laquo;Initial verbosity level (0 or 1; defaults to &raquo;<br />
		 &laquo;0, which is Quiet)&raquo;);</p>
<p>/**<br />
 * Module parameter that defines the number of message buffer elements<br />
 */<br />
unsigned int ecryptfs_message_buf_len = ECRYPTFS_DEFAULT_MSG_CTX_ELEMS;</p>
<p>module_param(ecryptfs_message_buf_len, uint, 0);<br />
MODULE_PARM_DESC(ecryptfs_message_buf_len,<br />
		 &laquo;Number of message buffer elements&raquo;);</p>
<p>/**<br />
 * Module parameter that defines the maximum guaranteed amount of time to wait<br />
 * for a response from ecryptfsd.  The actual sleep time will be, more than<br />
 * likely, a small amount greater than this specified value, but only less if<br />
 * the message successfully arrives.<br />
 */<br />
signed long ecryptfs_message_wait_timeout = ECRYPTFS_MAX_MSG_CTX_TTL / HZ;</p>
<p>module_param(ecryptfs_message_wait_timeout, long, 0);<br />
MODULE_PARM_DESC(ecryptfs_message_wait_timeout,<br />
		 &laquo;Maximum number of seconds that an operation will &raquo;<br />
		 &laquo;sleep while waiting for a message response from &raquo;<br />
		 &laquo;userspace&raquo;);</p>
<p>/**<br />
 * Module parameter that is an estimate of the maximum number of users<br />
 * that will be concurrently using eCryptfs. Set this to the right<br />
 * value to balance performance and memory use.<br />
 */<br />
unsigned int ecryptfs_number_of_users = ECRYPTFS_DEFAULT_NUM_USERS;</p>
<p>module_param(ecryptfs_number_of_users, uint, 0);<br />
MODULE_PARM_DESC(ecryptfs_number_of_users, &laquo;An estimate of the number of &raquo;<br />
		 &laquo;concurrent users of eCryptfs&raquo;);</p>
<p>void __ecryptfs_printk(const char *fmt, &#8230;)<br />
{<br />
	va_list args;<br />
	va_start(args, fmt);<br />
	if (fmt[1] == &#8216;7&#8242;) { /* KERN_DEBUG */<br />
		if (ecryptfs_verbosity >= 1)<br />
			vprintk(fmt, args);<br />
	} else<br />
		vprintk(fmt, args);<br />
	va_end(args);<br />
}</p>
<p>/**<br />
 * ecryptfs_init_persistent_file<br />
 * @ecryptfs_dentry: Fully initialized eCryptfs dentry object, with<br />
 *                   the lower dentry and the lower mount set<br />
 *<br />
 * eCryptfs only ever keeps a single open file for every lower<br />
 * inode. All I/O operations to the lower inode occur through that<br />
 * file. When the first eCryptfs dentry that interposes with the first<br />
 * lower dentry for that inode is created, this function creates the<br />
 * persistent file struct and associates it with the eCryptfs<br />
 * inode. When the eCryptfs inode is destroyed, the file is closed.<br />
 *<br />
 * The persistent file will be opened with read/write permissions, if<br />
 * possible. Otherwise, it is opened read-only.<br />
 *<br />
 * This function does nothing if a lower persistent file is already<br />
 * associated with the eCryptfs inode.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry)<br />
{<br />
	const struct cred *cred = current_cred();<br />
	struct ecryptfs_inode_info *inode_info =<br />
		ecryptfs_inode_to_private(ecryptfs_dentry->d_inode);<br />
	int opened_lower_file = 0;<br />
	int rc = 0;</p>
<p>	mutex_lock(&#038;inode_info->lower_file_mutex);<br />
	if (!inode_info->lower_file) {<br />
		struct dentry *lower_dentry;<br />
		struct vfsmount *lower_mnt =<br />
			ecryptfs_dentry_to_lower_mnt(ecryptfs_dentry);</p>
<p>		lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);<br />
		rc = ecryptfs_privileged_open(&#038;inode_info->lower_file,<br />
					      lower_dentry, lower_mnt, cred);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error opening lower persistent file &raquo;<br />
			       &laquo;for lower_dentry [0x%p] and lower_mnt [0x%p]; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, lower_dentry, lower_mnt, rc);<br />
			inode_info->lower_file = NULL;<br />
		} else<br />
			opened_lower_file = 1;<br />
	}<br />
	mutex_unlock(&#038;inode_info->lower_file_mutex);<br />
	if (opened_lower_file)<br />
		ima_counts_get(inode_info->lower_file);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_interpose<br />
 * @lower_dentry: Existing dentry in the lower filesystem<br />
 * @dentry: ecryptfs&#8217; dentry<br />
 * @sb: ecryptfs&#8217;s super_block<br />
 * @flags: flags to govern behavior of interpose procedure<br />
 *<br />
 * Interposes upper and lower dentries.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_interpose(struct dentry *lower_dentry, struct dentry *dentry,<br />
		       struct super_block *sb, u32 flags)<br />
{<br />
	struct inode *lower_inode;<br />
	struct inode *inode;<br />
	int rc = 0;</p>
<p>	lower_inode = lower_dentry->d_inode;<br />
	if (lower_inode->i_sb != ecryptfs_superblock_to_lower(sb)) {<br />
		rc = -EXDEV;<br />
		goto out;<br />
	}<br />
	if (!igrab(lower_inode)) {<br />
		rc = -ESTALE;<br />
		goto out;<br />
	}<br />
	inode = iget5_locked(sb, (unsigned long)lower_inode,<br />
			     ecryptfs_inode_test, ecryptfs_inode_set,<br />
			     lower_inode);<br />
	if (!inode) {<br />
		rc = -EACCES;<br />
		iput(lower_inode);<br />
		goto out;<br />
	}<br />
	if (inode->i_state &#038; I_NEW)<br />
		unlock_new_inode(inode);<br />
	else<br />
		iput(lower_inode);<br />
	if (S_ISLNK(lower_inode->i_mode))<br />
		inode->i_op = &#038;ecryptfs_symlink_iops;<br />
	else if (S_ISDIR(lower_inode->i_mode))<br />
		inode->i_op = &#038;ecryptfs_dir_iops;<br />
	if (S_ISDIR(lower_inode->i_mode))<br />
		inode->i_fop = &#038;ecryptfs_dir_fops;<br />
	if (special_file(lower_inode->i_mode))<br />
		init_special_inode(inode, lower_inode->i_mode,<br />
				   lower_inode->i_rdev);<br />
	dentry->d_op = &#038;ecryptfs_dops;<br />
	fsstack_copy_attr_all(inode, lower_inode, NULL);<br />
	/* This size will be overwritten for real files w/ headers and<br />
	 * other metadata */<br />
	fsstack_copy_inode_size(inode, lower_inode);<br />
	if (flags &#038; ECRYPTFS_INTERPOSE_FLAG_D_ADD)<br />
		d_add(dentry, inode);<br />
	else<br />
		d_instantiate(dentry, inode);<br />
out:<br />
	return rc;<br />
}</p>
<p>enum { ecryptfs_opt_sig, ecryptfs_opt_ecryptfs_sig,<br />
       ecryptfs_opt_cipher, ecryptfs_opt_ecryptfs_cipher,<br />
       ecryptfs_opt_ecryptfs_key_bytes,<br />
       ecryptfs_opt_passthrough, ecryptfs_opt_xattr_metadata,<br />
       ecryptfs_opt_encrypted_view, ecryptfs_opt_fnek_sig,<br />
       ecryptfs_opt_fn_cipher, ecryptfs_opt_fn_cipher_key_bytes,<br />
       ecryptfs_opt_unlink_sigs, ecryptfs_opt_err };</p>
<p>static const match_table_t tokens = {<br />
	{ecryptfs_opt_sig, &laquo;sig=%s&raquo;},<br />
	{ecryptfs_opt_ecryptfs_sig, &laquo;ecryptfs_sig=%s&raquo;},<br />
	{ecryptfs_opt_cipher, &laquo;cipher=%s&raquo;},<br />
	{ecryptfs_opt_ecryptfs_cipher, &laquo;ecryptfs_cipher=%s&raquo;},<br />
	{ecryptfs_opt_ecryptfs_key_bytes, &laquo;ecryptfs_key_bytes=%u&raquo;},<br />
	{ecryptfs_opt_passthrough, &laquo;ecryptfs_passthrough&raquo;},<br />
	{ecryptfs_opt_xattr_metadata, &laquo;ecryptfs_xattr_metadata&raquo;},<br />
	{ecryptfs_opt_encrypted_view, &laquo;ecryptfs_encrypted_view&raquo;},<br />
	{ecryptfs_opt_fnek_sig, &laquo;ecryptfs_fnek_sig=%s&raquo;},<br />
	{ecryptfs_opt_fn_cipher, &laquo;ecryptfs_fn_cipher=%s&raquo;},<br />
	{ecryptfs_opt_fn_cipher_key_bytes, &laquo;ecryptfs_fn_key_bytes=%u&raquo;},<br />
	{ecryptfs_opt_unlink_sigs, &laquo;ecryptfs_unlink_sigs&raquo;},<br />
	{ecryptfs_opt_err, NULL}<br />
};</p>
<p>static int ecryptfs_init_global_auth_toks(<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	struct ecryptfs_global_auth_tok *global_auth_tok;<br />
	int rc = 0;</p>
<p>	list_for_each_entry(global_auth_tok,<br />
			    &#038;mount_crypt_stat->global_auth_tok_list,<br />
			    mount_crypt_stat_list) {<br />
		rc = ecryptfs_keyring_auth_tok_for_sig(<br />
			&#038;global_auth_tok->global_auth_tok_key,<br />
			&#038;global_auth_tok->global_auth_tok,<br />
			global_auth_tok->sig);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Could not find valid key in user &raquo;<br />
			       &laquo;session keyring for sig specified in mount &raquo;<br />
			       &laquo;option: [%s]\n&raquo;, global_auth_tok->sig);<br />
			global_auth_tok->flags |= ECRYPTFS_AUTH_TOK_INVALID;<br />
			goto out;<br />
		} else<br />
			global_auth_tok->flags &#038;= ~ECRYPTFS_AUTH_TOK_INVALID;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>static void ecryptfs_init_mount_crypt_stat(<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	memset((void *)mount_crypt_stat, 0,<br />
	       sizeof(struct ecryptfs_mount_crypt_stat));<br />
	INIT_LIST_HEAD(&#038;mount_crypt_stat->global_auth_tok_list);<br />
	mutex_init(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	mount_crypt_stat->flags |= ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED;<br />
}</p>
<p>/**<br />
 * ecryptfs_parse_options<br />
 * @sb: The ecryptfs super block<br />
 * @options: The options pased to the kernel<br />
 *<br />
 * Parse mount options:<br />
 * debug=N 	   &#8211; ecryptfs_verbosity level for debug output<br />
 * sig=XXX	   &#8211; description(signature) of the key to use<br />
 *<br />
 * Returns the dentry object of the lower-level (lower/interposed)<br />
 * directory; We want to mount our stackable file system on top of<br />
 * that lower directory.<br />
 *<br />
 * The signature of the key to use must be the description of a key<br />
 * already in the keyring. Mounting will fail if the key can not be<br />
 * found.<br />
 *<br />
 * Returns zero on success; non-zero on error<br />
 */<br />
static int ecryptfs_parse_options(struct super_block *sb, char *options)<br />
{<br />
	char *p;<br />
	int rc = 0;<br />
	int sig_set = 0;<br />
	int cipher_name_set = 0;<br />
	int fn_cipher_name_set = 0;<br />
	int cipher_key_bytes;<br />
	int cipher_key_bytes_set = 0;<br />
	int fn_cipher_key_bytes;<br />
	int fn_cipher_key_bytes_set = 0;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		&#038;ecryptfs_superblock_to_private(sb)->mount_crypt_stat;<br />
	substring_t args[MAX_OPT_ARGS];<br />
	int token;<br />
	char *sig_src;<br />
	char *cipher_name_dst;<br />
	char *cipher_name_src;<br />
	char *fn_cipher_name_dst;<br />
	char *fn_cipher_name_src;<br />
	char *fnek_dst;<br />
	char *fnek_src;<br />
	char *cipher_key_bytes_src;<br />
	char *fn_cipher_key_bytes_src;</p>
<p>	if (!options) {<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	ecryptfs_init_mount_crypt_stat(mount_crypt_stat);<br />
	while ((p = strsep(&#038;options, &laquo;,&raquo;)) != NULL) {<br />
		if (!*p)<br />
			continue;<br />
		token = match_token(p, tokens, args);<br />
		switch (token) {<br />
		case ecryptfs_opt_sig:<br />
		case ecryptfs_opt_ecryptfs_sig:<br />
			sig_src = args[0].from;<br />
			rc = ecryptfs_add_global_auth_tok(mount_crypt_stat,<br />
							  sig_src, 0);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;Error attempting to register &raquo;<br />
				       &laquo;global sig; rc = [%d]\n&raquo;, rc);<br />
				goto out;<br />
			}<br />
			sig_set = 1;<br />
			break;<br />
		case ecryptfs_opt_cipher:<br />
		case ecryptfs_opt_ecryptfs_cipher:<br />
			cipher_name_src = args[0].from;<br />
			cipher_name_dst =<br />
				mount_crypt_stat-><br />
				global_default_cipher_name;<br />
			strncpy(cipher_name_dst, cipher_name_src,<br />
				ECRYPTFS_MAX_CIPHER_NAME_SIZE);<br />
			cipher_name_dst[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = &#8216;\0&#8242;;<br />
			cipher_name_set = 1;<br />
			break;<br />
		case ecryptfs_opt_ecryptfs_key_bytes:<br />
			cipher_key_bytes_src = args[0].from;<br />
			cipher_key_bytes =<br />
				(int)simple_strtol(cipher_key_bytes_src,<br />
						   &#038;cipher_key_bytes_src, 0);<br />
			mount_crypt_stat->global_default_cipher_key_size =<br />
				cipher_key_bytes;<br />
			cipher_key_bytes_set = 1;<br />
			break;<br />
		case ecryptfs_opt_passthrough:<br />
			mount_crypt_stat->flags |=<br />
				ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED;<br />
			break;<br />
		case ecryptfs_opt_xattr_metadata:<br />
			mount_crypt_stat->flags |=<br />
				ECRYPTFS_XATTR_METADATA_ENABLED;<br />
			break;<br />
		case ecryptfs_opt_encrypted_view:<br />
			mount_crypt_stat->flags |=<br />
				ECRYPTFS_XATTR_METADATA_ENABLED;<br />
			mount_crypt_stat->flags |=<br />
				ECRYPTFS_ENCRYPTED_VIEW_ENABLED;<br />
			break;<br />
		case ecryptfs_opt_fnek_sig:<br />
			fnek_src = args[0].from;<br />
			fnek_dst =<br />
				mount_crypt_stat->global_default_fnek_sig;<br />
			strncpy(fnek_dst, fnek_src, ECRYPTFS_SIG_SIZE_HEX);<br />
			mount_crypt_stat->global_default_fnek_sig[<br />
				ECRYPTFS_SIG_SIZE_HEX] = &#8216;\0&#8242;;<br />
			rc = ecryptfs_add_global_auth_tok(<br />
				mount_crypt_stat,<br />
				mount_crypt_stat->global_default_fnek_sig,<br />
				ECRYPTFS_AUTH_TOK_FNEK);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;Error attempting to register &raquo;<br />
				       &laquo;global fnek sig [%s]; rc = [%d]\n&raquo;,<br />
				       mount_crypt_stat->global_default_fnek_sig,<br />
				       rc);<br />
				goto out;<br />
			}<br />
			mount_crypt_stat->flags |=<br />
				(ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES<br />
				 | ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK);<br />
			break;<br />
		case ecryptfs_opt_fn_cipher:<br />
			fn_cipher_name_src = args[0].from;<br />
			fn_cipher_name_dst =<br />
				mount_crypt_stat->global_default_fn_cipher_name;<br />
			strncpy(fn_cipher_name_dst, fn_cipher_name_src,<br />
				ECRYPTFS_MAX_CIPHER_NAME_SIZE);<br />
			mount_crypt_stat->global_default_fn_cipher_name[<br />
				ECRYPTFS_MAX_CIPHER_NAME_SIZE] = &#8216;\0&#8242;;<br />
			fn_cipher_name_set = 1;<br />
			break;<br />
		case ecryptfs_opt_fn_cipher_key_bytes:<br />
			fn_cipher_key_bytes_src = args[0].from;<br />
			fn_cipher_key_bytes =<br />
				(int)simple_strtol(fn_cipher_key_bytes_src,<br />
						   &#038;fn_cipher_key_bytes_src, 0);<br />
			mount_crypt_stat->global_default_fn_cipher_key_bytes =<br />
				fn_cipher_key_bytes;<br />
			fn_cipher_key_bytes_set = 1;<br />
			break;<br />
		case ecryptfs_opt_unlink_sigs:<br />
			mount_crypt_stat->flags |= ECRYPTFS_UNLINK_SIGS;<br />
			break;<br />
		case ecryptfs_opt_err:<br />
		default:<br />
			printk(KERN_WARNING<br />
			       &laquo;%s: eCryptfs: unrecognized option [%s]\n&raquo;,<br />
			       __func__, p);<br />
		}<br />
	}<br />
	if (!sig_set) {<br />
		rc = -EINVAL;<br />
		ecryptfs_printk(KERN_ERR, &laquo;You must supply at least one valid &raquo;<br />
				&laquo;auth tok signature as a mount &raquo;<br />
				&laquo;parameter; see the eCryptfs README\n&raquo;);<br />
		goto out;<br />
	}<br />
	if (!cipher_name_set) {<br />
		int cipher_name_len = strlen(ECRYPTFS_DEFAULT_CIPHER);</p>
<p>		BUG_ON(cipher_name_len >= ECRYPTFS_MAX_CIPHER_NAME_SIZE);<br />
		strcpy(mount_crypt_stat->global_default_cipher_name,<br />
		       ECRYPTFS_DEFAULT_CIPHER);<br />
	}<br />
	if ((mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)<br />
	    &#038;&#038; !fn_cipher_name_set)<br />
		strcpy(mount_crypt_stat->global_default_fn_cipher_name,<br />
		       mount_crypt_stat->global_default_cipher_name);<br />
	if (!cipher_key_bytes_set)<br />
		mount_crypt_stat->global_default_cipher_key_size = 0;<br />
	if ((mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)<br />
	    &#038;&#038; !fn_cipher_key_bytes_set)<br />
		mount_crypt_stat->global_default_fn_cipher_key_bytes =<br />
			mount_crypt_stat->global_default_cipher_key_size;<br />
	mutex_lock(&#038;key_tfm_list_mutex);<br />
	if (!ecryptfs_tfm_exists(mount_crypt_stat->global_default_cipher_name,<br />
				 NULL)) {<br />
		rc = ecryptfs_add_new_key_tfm(<br />
			NULL, mount_crypt_stat->global_default_cipher_name,<br />
			mount_crypt_stat->global_default_cipher_key_size);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error attempting to initialize &raquo;<br />
			       &laquo;cipher with name = [%s] and key size = [%td]; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;,<br />
			       mount_crypt_stat->global_default_cipher_name,<br />
			       mount_crypt_stat->global_default_cipher_key_size,<br />
			       rc);<br />
			rc = -EINVAL;<br />
			mutex_unlock(&#038;key_tfm_list_mutex);<br />
			goto out;<br />
		}<br />
	}<br />
	if ((mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)<br />
	    &#038;&#038; !ecryptfs_tfm_exists(<br />
		    mount_crypt_stat->global_default_fn_cipher_name, NULL)) {<br />
		rc = ecryptfs_add_new_key_tfm(<br />
			NULL, mount_crypt_stat->global_default_fn_cipher_name,<br />
			mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error attempting to initialize &raquo;<br />
			       &laquo;cipher with name = [%s] and key size = [%td]; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;,<br />
			       mount_crypt_stat->global_default_fn_cipher_name,<br />
			       mount_crypt_stat->global_default_fn_cipher_key_bytes,<br />
			       rc);<br />
			rc = -EINVAL;<br />
			mutex_unlock(&#038;key_tfm_list_mutex);<br />
			goto out;<br />
		}<br />
	}<br />
	mutex_unlock(&#038;key_tfm_list_mutex);<br />
	rc = ecryptfs_init_global_auth_toks(mount_crypt_stat);<br />
	if (rc)<br />
		printk(KERN_WARNING &laquo;One or more global auth toks could not &raquo;<br />
		       &laquo;properly register; rc = [%d]\n&raquo;, rc);<br />
out:<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_sb_info_cache;</p>
<p>/**<br />
 * ecryptfs_fill_super<br />
 * @sb: The ecryptfs super block<br />
 * @raw_data: The options passed to mount<br />
 * @silent: Not used but required by function prototype<br />
 *<br />
 * Sets up what we can of the sb, rest is done in ecryptfs_read_super<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int<br />
ecryptfs_fill_super(struct super_block *sb, void *raw_data, int silent)<br />
{<br />
	int rc = 0;</p>
<p>	/* Released in ecryptfs_put_super() */<br />
	ecryptfs_set_superblock_private(sb,<br />
					kmem_cache_zalloc(ecryptfs_sb_info_cache,<br />
							 GFP_KERNEL));<br />
	if (!ecryptfs_superblock_to_private(sb)) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Out of memory\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	sb->s_op = &#038;ecryptfs_sops;<br />
	/* Released through deactivate_super(sb) from get_sb_nodev */<br />
	sb->s_root = d_alloc(NULL, &#038;(const struct qstr) {<br />
			     .hash = 0,.name = &laquo;/&raquo;,.len = 1});<br />
	if (!sb->s_root) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;d_alloc failed\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	sb->s_root->d_op = &#038;ecryptfs_dops;<br />
	sb->s_root->d_sb = sb;<br />
	sb->s_root->d_parent = sb->s_root;<br />
	/* Released in d_release when dput(sb->s_root) is called */<br />
	/* through deactivate_super(sb) from get_sb_nodev() */<br />
	ecryptfs_set_dentry_private(sb->s_root,<br />
				    kmem_cache_zalloc(ecryptfs_dentry_info_cache,<br />
						     GFP_KERNEL));<br />
	if (!ecryptfs_dentry_to_private(sb->s_root)) {<br />
		ecryptfs_printk(KERN_ERR,<br />
				&laquo;dentry_info_cache alloc failed\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	rc = 0;<br />
out:<br />
	/* Should be able to rely on deactivate_super called from<br />
	 * get_sb_nodev */<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_super<br />
 * @sb: The ecryptfs super block<br />
 * @dev_name: The path to mount over<br />
 *<br />
 * Read the super block of the lower filesystem, and use<br />
 * ecryptfs_interpose to create our initial inode and super block<br />
 * struct.<br />
 */<br />
static int ecryptfs_read_super(struct super_block *sb, const char *dev_name)<br />
{<br />
	struct path path;<br />
	int rc;</p>
<p>	rc = kern_path(dev_name, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, &#038;path);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;path_lookup() failed\n&raquo;);<br />
		goto out;<br />
	}<br />
	ecryptfs_set_superblock_lower(sb, path.dentry->d_sb);<br />
	sb->s_maxbytes = path.dentry->d_sb->s_maxbytes;<br />
	sb->s_blocksize = path.dentry->d_sb->s_blocksize;<br />
	ecryptfs_set_dentry_lower(sb->s_root, path.dentry);<br />
	ecryptfs_set_dentry_lower_mnt(sb->s_root, path.mnt);<br />
	rc = ecryptfs_interpose(path.dentry, sb->s_root, sb, 0);<br />
	if (rc)<br />
		goto out_free;<br />
	rc = 0;<br />
	goto out;<br />
out_free:<br />
	path_put(&#038;path);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_get_sb<br />
 * @fs_type<br />
 * @flags<br />
 * @dev_name: The path to mount over<br />
 * @raw_data: The options passed into the kernel<br />
 *<br />
 * The whole ecryptfs_get_sb process is broken into 4 functions:<br />
 * ecryptfs_parse_options(): handle options passed to ecryptfs, if any<br />
 * ecryptfs_fill_super(): used by get_sb_nodev, fills out the super_block<br />
 *                        with as much information as it can before needing<br />
 *                        the lower filesystem.<br />
 * ecryptfs_read_super(): this accesses the lower filesystem and uses<br />
 *                        ecryptfs_interpolate to perform most of the linking<br />
 * ecryptfs_interpolate(): links the lower filesystem into ecryptfs<br />
 */<br />
static int ecryptfs_get_sb(struct file_system_type *fs_type, int flags,<br />
			const char *dev_name, void *raw_data,<br />
			struct vfsmount *mnt)<br />
{<br />
	int rc;<br />
	struct super_block *sb;</p>
<p>	rc = get_sb_nodev(fs_type, flags, raw_data, ecryptfs_fill_super, mnt);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "Getting sb failed; rc = [%d]\n", rc);<br />
		goto out;<br />
	}<br />
	sb = mnt->mnt_sb;<br />
	rc = ecryptfs_parse_options(sb, raw_data);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error parsing options; rc = [%d]\n&raquo;, rc);<br />
		goto out_abort;<br />
	}<br />
	rc = ecryptfs_read_super(sb, dev_name);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Reading sb failed; rc = [%d]\n&raquo;, rc);<br />
		goto out_abort;<br />
	}<br />
	goto out;<br />
out_abort:<br />
	dput(sb->s_root); /* aka mnt->mnt_root, as set by get_sb_nodev() */<br />
	deactivate_locked_super(sb);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_kill_block_super<br />
 * @sb: The ecryptfs super block<br />
 *<br />
 * Used to bring the superblock down and free the private data.<br />
 * Private data is free&#8217;d in ecryptfs_put_super()<br />
 */<br />
static void ecryptfs_kill_block_super(struct super_block *sb)<br />
{<br />
	generic_shutdown_super(sb);<br />
}</p>
<p>static struct file_system_type ecryptfs_fs_type = {<br />
	.owner = THIS_MODULE,<br />
	.name = &laquo;ecryptfs&raquo;,<br />
	.get_sb = ecryptfs_get_sb,<br />
	.kill_sb = ecryptfs_kill_block_super,<br />
	.fs_flags = 0<br />
};</p>
<p>/**<br />
 * inode_info_init_once<br />
 *<br />
 * Initializes the ecryptfs_inode_info_cache when it is created<br />
 */<br />
static void<br />
inode_info_init_once(void *vptr)<br />
{<br />
	struct ecryptfs_inode_info *ei = (struct ecryptfs_inode_info *)vptr;</p>
<p>	inode_init_once(&#038;ei->vfs_inode);<br />
}</p>
<p>static struct ecryptfs_cache_info {<br />
	struct kmem_cache **cache;<br />
	const char *name;<br />
	size_t size;<br />
	void (*ctor)(void *obj);<br />
} ecryptfs_cache_infos[] = {<br />
	{<br />
		.cache = &#038;ecryptfs_auth_tok_list_item_cache,<br />
		.name = &laquo;ecryptfs_auth_tok_list_item&raquo;,<br />
		.size = sizeof(struct ecryptfs_auth_tok_list_item),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_file_info_cache,<br />
		.name = &laquo;ecryptfs_file_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_file_info),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_dentry_info_cache,<br />
		.name = &laquo;ecryptfs_dentry_info_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_dentry_info),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_inode_info_cache,<br />
		.name = &laquo;ecryptfs_inode_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_inode_info),<br />
		.ctor = inode_info_init_once,<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_sb_info_cache,<br />
		.name = &laquo;ecryptfs_sb_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_sb_info),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_header_cache_1,<br />
		.name = &laquo;ecryptfs_headers_1&#8243;,<br />
		.size = PAGE_CACHE_SIZE,<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_header_cache_2,<br />
		.name = &laquo;ecryptfs_headers_2&#8243;,<br />
		.size = PAGE_CACHE_SIZE,<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_xattr_cache,<br />
		.name = &laquo;ecryptfs_xattr_cache&raquo;,<br />
		.size = PAGE_CACHE_SIZE,<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_key_record_cache,<br />
		.name = &laquo;ecryptfs_key_record_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_key_record),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_key_sig_cache,<br />
		.name = &laquo;ecryptfs_key_sig_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_key_sig),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_global_auth_tok_cache,<br />
		.name = &laquo;ecryptfs_global_auth_tok_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_global_auth_tok),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_key_tfm_cache,<br />
		.name = &laquo;ecryptfs_key_tfm_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_key_tfm),<br />
	},<br />
	{<br />
		.cache = &#038;ecryptfs_open_req_cache,<br />
		.name = &laquo;ecryptfs_open_req_cache&raquo;,<br />
		.size = sizeof(struct ecryptfs_open_req),<br />
	},<br />
};</p>
<p>static void ecryptfs_free_kmem_caches(void)<br />
{<br />
	int i;</p>
<p>	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {<br />
		struct ecryptfs_cache_info *info;</p>
<p>		info = &#038;ecryptfs_cache_infos[i];<br />
		if (*(info->cache))<br />
			kmem_cache_destroy(*(info->cache));<br />
	}<br />
}</p>
<p>/**<br />
 * ecryptfs_init_kmem_caches<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_init_kmem_caches(void)<br />
{<br />
	int i;</p>
<p>	for (i = 0; i < ARRAY_SIZE(ecryptfs_cache_infos); i++) {<br />
		struct ecryptfs_cache_info *info;</p>
<p>		info = &#038;ecryptfs_cache_infos[i];<br />
		*(info->cache) = kmem_cache_create(info->name, info->size,<br />
				0, SLAB_HWCACHE_ALIGN, info->ctor);<br />
		if (!*(info->cache)) {<br />
			ecryptfs_free_kmem_caches();<br />
			ecryptfs_printk(KERN_WARNING, &laquo;%s: &raquo;<br />
					&laquo;kmem_cache_create failed\n&raquo;,<br />
					info->name);<br />
			return -ENOMEM;<br />
		}<br />
	}<br />
	return 0;<br />
}</p>
<p>static struct kobject *ecryptfs_kobj;</p>
<p>static ssize_t version_show(struct kobject *kobj,<br />
			    struct kobj_attribute *attr, char *buff)<br />
{<br />
	return snprintf(buff, PAGE_SIZE, &laquo;%d\n&raquo;, ECRYPTFS_VERSIONING_MASK);<br />
}</p>
<p>static struct kobj_attribute version_attr = __ATTR_RO(version);</p>
<p>static struct attribute *attributes[] = {<br />
	&#038;version_attr.attr,<br />
	NULL,<br />
};</p>
<p>static struct attribute_group attr_group = {<br />
	.attrs = attributes,<br />
};</p>
<p>static int do_sysfs_registration(void)<br />
{<br />
	int rc;</p>
<p>	ecryptfs_kobj = kobject_create_and_add(&raquo;ecryptfs&raquo;, fs_kobj);<br />
	if (!ecryptfs_kobj) {<br />
		printk(KERN_ERR &laquo;Unable to create ecryptfs kset\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	rc = sysfs_create_group(ecryptfs_kobj, &#038;attr_group);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;Unable to create ecryptfs version attributes\n&raquo;);<br />
		kobject_put(ecryptfs_kobj);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>static void do_sysfs_unregistration(void)<br />
{<br />
	sysfs_remove_group(ecryptfs_kobj, &#038;attr_group);<br />
	kobject_put(ecryptfs_kobj);<br />
}</p>
<p>static int __init ecryptfs_init(void)<br />
{<br />
	int rc;</p>
<p>	if (ECRYPTFS_DEFAULT_EXTENT_SIZE > PAGE_CACHE_SIZE) {<br />
		rc = -EINVAL;<br />
		ecryptfs_printk(KERN_ERR, &laquo;The eCryptfs extent size is &raquo;<br />
				&laquo;larger than the host&#8217;s page size, and so &raquo;<br />
				&laquo;eCryptfs cannot run on this system. The &raquo;<br />
				&laquo;default eCryptfs extent size is [%d] bytes; &raquo;<br />
				&laquo;the page size is [%d] bytes.\n&raquo;,<br />
				ECRYPTFS_DEFAULT_EXTENT_SIZE, PAGE_CACHE_SIZE);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_init_kmem_caches();<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;Failed to allocate one or more kmem_cache objects\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = register_filesystem(&#038;ecryptfs_fs_type);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Failed to register filesystem\n&raquo;);<br />
		goto out_free_kmem_caches;<br />
	}<br />
	rc = do_sysfs_registration();<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;sysfs registration failed\n&raquo;);<br />
		goto out_unregister_filesystem;<br />
	}<br />
	rc = ecryptfs_init_kthread();<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: kthread initialization failed; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_do_sysfs_unregistration;<br />
	}<br />
	rc = ecryptfs_init_messaging();<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Failure occured while attempting to &raquo;<br />
				&laquo;initialize the communications channel to &raquo;<br />
				&laquo;ecryptfsd\n&raquo;);<br />
		goto out_destroy_kthread;<br />
	}<br />
	rc = ecryptfs_init_crypto();<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Failure whilst attempting to init crypto; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, rc);<br />
		goto out_release_messaging;<br />
	}<br />
	if (ecryptfs_verbosity > 0)<br />
		printk(KERN_CRIT &laquo;eCryptfs verbosity set to %d. Secret values &raquo;<br />
			&laquo;will be written to the syslog!\n&raquo;, ecryptfs_verbosity);</p>
<p>	goto out;<br />
out_release_messaging:<br />
	ecryptfs_release_messaging();<br />
out_destroy_kthread:<br />
	ecryptfs_destroy_kthread();<br />
out_do_sysfs_unregistration:<br />
	do_sysfs_unregistration();<br />
out_unregister_filesystem:<br />
	unregister_filesystem(&#038;ecryptfs_fs_type);<br />
out_free_kmem_caches:<br />
	ecryptfs_free_kmem_caches();<br />
out:<br />
	return rc;<br />
}</p>
<p>static void __exit ecryptfs_exit(void)<br />
{<br />
	int rc;</p>
<p>	rc = ecryptfs_destroy_crypto();<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;Failure whilst attempting to destroy crypto; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, rc);<br />
	ecryptfs_release_messaging();<br />
	ecryptfs_destroy_kthread();<br />
	do_sysfs_unregistration();<br />
	unregister_filesystem(&#038;ecryptfs_fs_type);<br />
	ecryptfs_free_kmem_caches();<br />
}</p>
<p>MODULE_AUTHOR(&raquo;Michael A. Halcrow <mhalcrow@us.ibm.com>&laquo;);<br />
MODULE_DESCRIPTION(&raquo;eCryptfs&raquo;);</p>
<p>MODULE_LICENSE(&raquo;GPL&raquo;);</p>
<p>module_init(ecryptfs_init)<br />
module_exit(ecryptfs_exit)</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/main-c-3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>kthread.c</title>
		<link>http://lynyrd.ru/kthread-c</link>
		<comments>http://lynyrd.ru/kthread-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:03:43 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1090</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 2008 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *
 * 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 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1090"></span><br />
 *<br />
 * Copyright (C) 2008 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/kthread.h>
#include
<linux/freezer.h>
#include
<linux/wait.h>
#include
<linux/mount.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>struct kmem_cache *ecryptfs_open_req_cache;</p>
<p>static struct ecryptfs_kthread_ctl {<br />
#define ECRYPTFS_KTHREAD_ZOMBIE 0&#215;00000001<br />
	u32 flags;<br />
	struct mutex mux;<br />
	struct list_head req_list;<br />
	wait_queue_head_t wait;<br />
} ecryptfs_kthread_ctl;</p>
<p>static struct task_struct *ecryptfs_kthread;</p>
<p>/**<br />
 * ecryptfs_threadfn<br />
 * @ignored: ignored<br />
 *<br />
 * The eCryptfs kernel thread that has the responsibility of getting<br />
 * the lower persistent file with RW permissions.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_threadfn(void *ignored)<br />
{<br />
	set_freezable();<br />
	while (1)  {<br />
		struct ecryptfs_open_req *req;</p>
<p>		wait_event_freezable(<br />
			ecryptfs_kthread_ctl.wait,<br />
			(!list_empty(&#038;ecryptfs_kthread_ctl.req_list)<br />
			 || kthread_should_stop()));<br />
		mutex_lock(&#038;ecryptfs_kthread_ctl.mux);<br />
		if (ecryptfs_kthread_ctl.flags &#038; ECRYPTFS_KTHREAD_ZOMBIE) {<br />
			mutex_unlock(&#038;ecryptfs_kthread_ctl.mux);<br />
			goto out;<br />
		}<br />
		while (!list_empty(&#038;ecryptfs_kthread_ctl.req_list)) {<br />
			req = list_first_entry(&#038;ecryptfs_kthread_ctl.req_list,<br />
					       struct ecryptfs_open_req,<br />
					       kthread_ctl_list);<br />
			mutex_lock(&#038;req->mux);<br />
			list_del(&#038;req->kthread_ctl_list);<br />
			if (!(req->flags &#038; ECRYPTFS_REQ_ZOMBIE)) {<br />
				dget(req->lower_dentry);<br />
				mntget(req->lower_mnt);<br />
				(*req->lower_file) = dentry_open(<br />
					req->lower_dentry, req->lower_mnt,<br />
					(O_RDWR | O_LARGEFILE), current_cred());<br />
				req->flags |= ECRYPTFS_REQ_PROCESSED;<br />
			}<br />
			wake_up(&#038;req->wait);<br />
			mutex_unlock(&#038;req->mux);<br />
		}<br />
		mutex_unlock(&#038;ecryptfs_kthread_ctl.mux);<br />
	}<br />
out:<br />
	return 0;<br />
}</p>
<p>int ecryptfs_init_kthread(void)<br />
{<br />
	int rc = 0;</p>
<p>	mutex_init(&#038;ecryptfs_kthread_ctl.mux);<br />
	init_waitqueue_head(&#038;ecryptfs_kthread_ctl.wait);<br />
	INIT_LIST_HEAD(&#038;ecryptfs_kthread_ctl.req_list);<br />
	ecryptfs_kthread = kthread_run(&#038;ecryptfs_threadfn, NULL,<br />
				       &laquo;ecryptfs-kthread&raquo;);<br />
	if (IS_ERR(ecryptfs_kthread)) {<br />
		rc = PTR_ERR(ecryptfs_kthread);<br />
		printk(KERN_ERR &laquo;%s: Failed to create kernel thread; rc = [%d]&raquo;<br />
		       &laquo;\n&raquo;, __func__, rc);<br />
	}<br />
	return rc;<br />
}</p>
<p>void ecryptfs_destroy_kthread(void)<br />
{<br />
	struct ecryptfs_open_req *req;</p>
<p>	mutex_lock(&#038;ecryptfs_kthread_ctl.mux);<br />
	ecryptfs_kthread_ctl.flags |= ECRYPTFS_KTHREAD_ZOMBIE;<br />
	list_for_each_entry(req, &#038;ecryptfs_kthread_ctl.req_list,<br />
			    kthread_ctl_list) {<br />
		mutex_lock(&#038;req->mux);<br />
		req->flags |= ECRYPTFS_REQ_ZOMBIE;<br />
		wake_up(&#038;req->wait);<br />
		mutex_unlock(&#038;req->mux);<br />
	}<br />
	mutex_unlock(&#038;ecryptfs_kthread_ctl.mux);<br />
	kthread_stop(ecryptfs_kthread);<br />
	wake_up(&#038;ecryptfs_kthread_ctl.wait);<br />
}</p>
<p>/**<br />
 * ecryptfs_privileged_open<br />
 * @lower_file: Result of dentry_open by root on lower dentry<br />
 * @lower_dentry: Lower dentry for file to open<br />
 * @lower_mnt: Lower vfsmount for file to open<br />
 *<br />
 * This function gets a r/w file opened againt the lower dentry.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_privileged_open(struct file **lower_file,<br />
			     struct dentry *lower_dentry,<br />
			     struct vfsmount *lower_mnt,<br />
			     const struct cred *cred)<br />
{<br />
	struct ecryptfs_open_req *req;<br />
	int flags = O_LARGEFILE;<br />
	int rc = 0;</p>
<p>	/* Corresponding dput() and mntput() are done when the<br />
	 * persistent file is fput() when the eCryptfs inode is<br />
	 * destroyed. */<br />
	dget(lower_dentry);<br />
	mntget(lower_mnt);<br />
	flags |= IS_RDONLY(lower_dentry->d_inode) ? O_RDONLY : O_RDWR;<br />
	(*lower_file) = dentry_open(lower_dentry, lower_mnt, flags, cred);<br />
	if (!IS_ERR(*lower_file))<br />
		goto out;<br />
	if (flags &#038; O_RDONLY) {<br />
		rc = PTR_ERR((*lower_file));<br />
		goto out;<br />
	}<br />
	req = kmem_cache_alloc(ecryptfs_open_req_cache, GFP_KERNEL);<br />
	if (!req) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	mutex_init(&#038;req->mux);<br />
	req->lower_file = lower_file;<br />
	req->lower_dentry = lower_dentry;<br />
	req->lower_mnt = lower_mnt;<br />
	init_waitqueue_head(&#038;req->wait);<br />
	req->flags = 0;<br />
	mutex_lock(&#038;ecryptfs_kthread_ctl.mux);<br />
	if (ecryptfs_kthread_ctl.flags &#038; ECRYPTFS_KTHREAD_ZOMBIE) {<br />
		rc = -EIO;<br />
		mutex_unlock(&#038;ecryptfs_kthread_ctl.mux);<br />
		printk(KERN_ERR &laquo;%s: We are in the middle of shutting down; &raquo;<br />
		       &laquo;aborting privileged request to open lower file\n&raquo;,<br />
			__func__);<br />
		goto out_free;<br />
	}<br />
	list_add_tail(&#038;req->kthread_ctl_list, &#038;ecryptfs_kthread_ctl.req_list);<br />
	mutex_unlock(&#038;ecryptfs_kthread_ctl.mux);<br />
	wake_up(&#038;ecryptfs_kthread_ctl.wait);<br />
	wait_event(req->wait, (req->flags != 0));<br />
	mutex_lock(&#038;req->mux);<br />
	BUG_ON(req->flags == 0);<br />
	if (req->flags &#038; ECRYPTFS_REQ_DROPPED<br />
	    || req->flags &#038; ECRYPTFS_REQ_ZOMBIE) {<br />
		rc = -EIO;<br />
		printk(KERN_WARNING &laquo;%s: Privileged open request dropped\n&raquo;,<br />
		       __func__);<br />
		goto out_unlock;<br />
	}<br />
	if (IS_ERR(*req->lower_file))<br />
		rc = PTR_ERR(*req->lower_file);<br />
out_unlock:<br />
	mutex_unlock(&#038;req->mux);<br />
out_free:<br />
	kmem_cache_free(ecryptfs_open_req_cache, req);<br />
out:<br />
	return rc;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/kthread-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>keystore.c</title>
		<link>http://lynyrd.ru/keystore-c</link>
		<comments>http://lynyrd.ru/keystore-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:03:21 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1088</guid>
		<description><![CDATA[/**
 * 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 
 *          ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1088"></span><br />
 * In-kernel key management code.  Includes functions to parse and<br />
 * write authentication token-related packets with the underlying<br />
 * file.<br />
 *<br />
 * Copyright (C) 2004-2006 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com><br />
 *              Michael C. Thompson <mcthomps@us.ibm.com><br />
 *              Trevor S. Highland<br />
<trevor.highland@gmail.com>
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/string.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 &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * request_key returned an error instead of a valid key address;<br />
 * determine the type of error, make appropriate log entries, and<br />
 * return an error code.<br />
 */<br />
static int process_request_key_err(long err_code)<br />
{<br />
	int rc = 0;</p>
<p>	switch (err_code) {<br />
	case -ENOKEY:<br />
		ecryptfs_printk(KERN_WARNING, &laquo;No key\n&raquo;);<br />
		rc = -ENOENT;<br />
		break;<br />
	case -EKEYEXPIRED:<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Key expired\n&raquo;);<br />
		rc = -ETIME;<br />
		break;<br />
	case -EKEYREVOKED:<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Key revoked\n&raquo;);<br />
		rc = -EINVAL;<br />
		break;<br />
	default:<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Unknown error code: &raquo;<br />
				&laquo;[0x%.16x]\n&raquo;, err_code);<br />
		rc = -EINVAL;<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_parse_packet_length<br />
 * @data: Pointer to memory containing length at offset<br />
 * @size: This function writes the decoded size to this memory<br />
 *        address; zero on error<br />
 * @length_size: The number of bytes occupied by the encoded length<br />
 *<br />
 * Returns zero on success; non-zero on error<br />
 */<br />
int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,<br />
				 size_t *length_size)<br />
{<br />
	int rc = 0;</p>
<p>	(*length_size) = 0;<br />
	(*size) = 0;<br />
	if (data[0] < 192) {<br />
		/* One-byte length */<br />
		(*size) = (unsigned char)data[0];<br />
		(*length_size) = 1;<br />
	} else if (data[0] < 224) {<br />
		/* Two-byte length */<br />
		(*size) = (((unsigned char)(data[0]) - 192) * 256);<br />
		(*size) += ((unsigned char)(data[1]) + 192);<br />
		(*length_size) = 2;<br />
	} else if (data[0] == 255) {<br />
		/* Five-byte length; we're not supposed to see this */<br />
		ecryptfs_printk(KERN_ERR, "Five-byte packet length not "<br />
				"supported\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	} else {<br />
		ecryptfs_printk(KERN_ERR, "Error parsing packet length\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_write_packet_length<br />
 * @dest: The byte array target into which to write the length. Must<br />
 *        have at least 5 bytes allocated.<br />
 * @size: The length to write.<br />
 * @packet_size_length: The number of bytes used to encode the packet<br />
 *                      length is written to this address.<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
int ecryptfs_write_packet_length(char *dest, size_t size,<br />
				 size_t *packet_size_length)<br />
{<br />
	int rc = 0;</p>
<p>	if (size < 192) {<br />
		dest[0] = size;<br />
		(*packet_size_length) = 1;<br />
	} else if (size < 65536) {<br />
		dest[0] = (((size - 192) / 256) + 192);<br />
		dest[1] = ((size - 192) % 256);<br />
		(*packet_size_length) = 2;<br />
	} else {<br />
		rc = -EINVAL;<br />
		ecryptfs_printk(KERN_WARNING,<br />
				"Unsupported packet size: [%d]\n", size);<br />
	}<br />
	return rc;<br />
}</p>
<p>static int<br />
write_tag_64_packet(char *signature, struct ecryptfs_session_key *session_key,<br />
		    char **packet, size_t *packet_len)<br />
{<br />
	size_t i = 0;<br />
	size_t data_len;<br />
	size_t packet_size_len;<br />
	char *message;<br />
	int rc;</p>
<p>	/*<br />
	 *              ***** TAG 64 Packet Format *****<br />
	 *    | Content Type                       | 1 byte       |<br />
	 *    | Key Identifier Size                | 1 or 2 bytes |<br />
	 *    | Key Identifier                     | arbitrary    |<br />
	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |<br />
	 *    | Encrypted File Encryption Key      | arbitrary    |<br />
	 */<br />
	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX<br />
		    + session_key->encrypted_key_size);<br />
	*packet = kmalloc(data_len, GFP_KERNEL);<br />
	message = *packet;<br />
	if (!message) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Unable to allocate memory\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	message[i++] = ECRYPTFS_TAG_64_PACKET_TYPE;<br />
	rc = ecryptfs_write_packet_length(&#038;message[i], ECRYPTFS_SIG_SIZE_HEX,<br />
					  &#038;packet_size_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 64 packet &raquo;<br />
				&laquo;header; cannot generate packet length\n&raquo;);<br />
		goto out;<br />
	}<br />
	i += packet_size_len;<br />
	memcpy(&#038;message[i], signature, ECRYPTFS_SIG_SIZE_HEX);<br />
	i += ECRYPTFS_SIG_SIZE_HEX;<br />
	rc = ecryptfs_write_packet_length(&#038;message[i],<br />
					  session_key->encrypted_key_size,<br />
					  &#038;packet_size_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 64 packet &raquo;<br />
				&laquo;header; cannot generate packet length\n&raquo;);<br />
		goto out;<br />
	}<br />
	i += packet_size_len;<br />
	memcpy(&#038;message[i], session_key->encrypted_key,<br />
	       session_key->encrypted_key_size);<br />
	i += session_key->encrypted_key_size;<br />
	*packet_len = i;<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
parse_tag_65_packet(struct ecryptfs_session_key *session_key, u8 *cipher_code,<br />
		    struct ecryptfs_message *msg)<br />
{<br />
	size_t i = 0;<br />
	char *data;<br />
	size_t data_len;<br />
	size_t m_size;<br />
	size_t message_len;<br />
	u16 checksum = 0;<br />
	u16 expected_checksum = 0;<br />
	int rc;</p>
<p>	/*<br />
	 *              ***** TAG 65 Packet Format *****<br />
	 *         | Content Type             | 1 byte       |<br />
	 *         | Status Indicator         | 1 byte       |<br />
	 *         | File Encryption Key Size | 1 or 2 bytes |<br />
	 *         | File Encryption Key      | arbitrary    |<br />
	 */<br />
	message_len = msg->data_len;<br />
	data = msg->data;<br />
	if (message_len < 4) {<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	if (data[i++] != ECRYPTFS_TAG_65_PACKET_TYPE) {<br />
		ecryptfs_printk(KERN_ERR, "Type should be ECRYPTFS_TAG_65\n");<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	if (data[i++]) {<br />
		ecryptfs_printk(KERN_ERR, "Status indicator has non-zero value "<br />
				"[%d]\n", data[i-1]);<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_parse_packet_length(&#038;data[i], &#038;m_size, &#038;data_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, "Error parsing packet length; "<br />
				"rc = [%d]\n", rc);<br />
		goto out;<br />
	}<br />
	i += data_len;<br />
	if (message_len < (i + m_size)) {<br />
		ecryptfs_printk(KERN_ERR, "The message received from ecryptfsd "<br />
				"is shorter than expected\n");<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	if (m_size < 3) {<br />
		ecryptfs_printk(KERN_ERR,<br />
				"The decrypted key is not long enough to "<br />
				"include a cipher code and checksum\n");<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	*cipher_code = data[i++];<br />
	/* The decrypted key includes 1 byte cipher code and 2 byte checksum */<br />
	session_key->decrypted_key_size = m_size &#8211; 3;<br />
	if (session_key->decrypted_key_size > ECRYPTFS_MAX_KEY_BYTES) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;key_size [%d] larger than &raquo;<br />
				&laquo;the maximum key size [%d]\n&raquo;,<br />
				session_key->decrypted_key_size,<br />
				ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	memcpy(session_key->decrypted_key, &#038;data[i],<br />
	       session_key->decrypted_key_size);<br />
	i += session_key->decrypted_key_size;<br />
	expected_checksum += (unsigned char)(data[i++]) << 8;<br />
	expected_checksum += (unsigned char)(data[i++]);<br />
	for (i = 0; i < session_key->decrypted_key_size; i++)<br />
		checksum += session_key->decrypted_key[i];<br />
	if (expected_checksum != checksum) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Invalid checksum for file &raquo;<br />
				&laquo;encryption  key; expected [%x]; calculated &raquo;<br />
				&laquo;[%x]\n&raquo;, expected_checksum, checksum);<br />
		rc = -EIO;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
write_tag_66_packet(char *signature, u8 cipher_code,<br />
		    struct ecryptfs_crypt_stat *crypt_stat, char **packet,<br />
		    size_t *packet_len)<br />
{<br />
	size_t i = 0;<br />
	size_t j;<br />
	size_t data_len;<br />
	size_t checksum = 0;<br />
	size_t packet_size_len;<br />
	char *message;<br />
	int rc;</p>
<p>	/*<br />
	 *              ***** TAG 66 Packet Format *****<br />
	 *         | Content Type             | 1 byte       |<br />
	 *         | Key Identifier Size      | 1 or 2 bytes |<br />
	 *         | Key Identifier           | arbitrary    |<br />
	 *         | File Encryption Key Size | 1 or 2 bytes |<br />
	 *         | File Encryption Key      | arbitrary    |<br />
	 */<br />
	data_len = (5 + ECRYPTFS_SIG_SIZE_HEX + crypt_stat->key_size);<br />
	*packet = kmalloc(data_len, GFP_KERNEL);<br />
	message = *packet;<br />
	if (!message) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Unable to allocate memory\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	message[i++] = ECRYPTFS_TAG_66_PACKET_TYPE;<br />
	rc = ecryptfs_write_packet_length(&#038;message[i], ECRYPTFS_SIG_SIZE_HEX,<br />
					  &#038;packet_size_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 66 packet &raquo;<br />
				&laquo;header; cannot generate packet length\n&raquo;);<br />
		goto out;<br />
	}<br />
	i += packet_size_len;<br />
	memcpy(&#038;message[i], signature, ECRYPTFS_SIG_SIZE_HEX);<br />
	i += ECRYPTFS_SIG_SIZE_HEX;<br />
	/* The encrypted key includes 1 byte cipher code and 2 byte checksum */<br />
	rc = ecryptfs_write_packet_length(&#038;message[i], crypt_stat->key_size + 3,<br />
					  &#038;packet_size_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 66 packet &raquo;<br />
				&laquo;header; cannot generate packet length\n&raquo;);<br />
		goto out;<br />
	}<br />
	i += packet_size_len;<br />
	message[i++] = cipher_code;<br />
	memcpy(&#038;message[i], crypt_stat->key, crypt_stat->key_size);<br />
	i += crypt_stat->key_size;<br />
	for (j = 0; j < crypt_stat->key_size; j++)<br />
		checksum += crypt_stat->key[j];<br />
	message[i++] = (checksum / 256) % 256;<br />
	message[i++] = (checksum % 256);<br />
	*packet_len = i;<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
parse_tag_67_packet(struct ecryptfs_key_record *key_rec,<br />
		    struct ecryptfs_message *msg)<br />
{<br />
	size_t i = 0;<br />
	char *data;<br />
	size_t data_len;<br />
	size_t message_len;<br />
	int rc;</p>
<p>	/*<br />
	 *              ***** TAG 65 Packet Format *****<br />
	 *    | Content Type                       | 1 byte       |<br />
	 *    | Status Indicator                   | 1 byte       |<br />
	 *    | Encrypted File Encryption Key Size | 1 or 2 bytes |<br />
	 *    | Encrypted File Encryption Key      | arbitrary    |<br />
	 */<br />
	message_len = msg->data_len;<br />
	data = msg->data;<br />
	/* verify that everything through the encrypted FEK size is present */<br />
	if (message_len < 4) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR "%s: message_len is [%zd]; minimum acceptable "<br />
		       "message length is [%d]\n", __func__, message_len, 4);<br />
		goto out;<br />
	}<br />
	if (data[i++] != ECRYPTFS_TAG_67_PACKET_TYPE) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR "%s: Type should be ECRYPTFS_TAG_67\n",<br />
		       __func__);<br />
		goto out;<br />
	}<br />
	if (data[i++]) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR "%s: Status indicator has non zero "<br />
		       "value [%d]\n", __func__, data[i-1]);</p>
<p>		goto out;<br />
	}<br />
	rc = ecryptfs_parse_packet_length(&#038;data[i], &#038;key_rec->enc_key_size,<br />
					  &#038;data_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error parsing packet length; &raquo;<br />
				&laquo;rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	i += data_len;<br />
	if (message_len < (i + key_rec->enc_key_size)) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR &laquo;%s: message_len [%zd]; max len is [%zd]\n&raquo;,<br />
		       __func__, message_len, (i + key_rec->enc_key_size));<br />
		goto out;<br />
	}<br />
	if (key_rec->enc_key_size > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {<br />
		rc = -EIO;<br />
		printk(KERN_ERR &laquo;%s: Encrypted key_size [%zd] larger than &raquo;<br />
		       &laquo;the maximum key size [%d]\n&raquo;, __func__,<br />
		       key_rec->enc_key_size,<br />
		       ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES);<br />
		goto out;<br />
	}<br />
	memcpy(key_rec->enc_key, &#038;data[i], key_rec->enc_key_size);<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_find_global_auth_tok_for_sig(<br />
	struct ecryptfs_global_auth_tok **global_auth_tok,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig)<br />
{<br />
	struct ecryptfs_global_auth_tok *walker;<br />
	int rc = 0;</p>
<p>	(*global_auth_tok) = NULL;<br />
	mutex_lock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	list_for_each_entry(walker,<br />
			    &#038;mount_crypt_stat->global_auth_tok_list,<br />
			    mount_crypt_stat_list) {<br />
		if (memcmp(walker->sig, sig, ECRYPTFS_SIG_SIZE_HEX) == 0) {<br />
			rc = key_validate(walker->global_auth_tok_key);<br />
			if (!rc)<br />
				(*global_auth_tok) = walker;<br />
			goto out;<br />
		}<br />
	}<br />
	rc = -EINVAL;<br />
out:<br />
	mutex_unlock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_find_auth_tok_for_sig<br />
 * @auth_tok: Set to the matching auth_tok; NULL if not found<br />
 * @crypt_stat: inode crypt_stat crypto context<br />
 * @sig: Sig of auth_tok to find<br />
 *<br />
 * For now, this function simply looks at the registered auth_tok&#8217;s<br />
 * linked off the mount_crypt_stat, so all the auth_toks that can be<br />
 * used must be registered at mount time. This function could<br />
 * potentially try a lot harder to find auth_tok&#8217;s (e.g., by calling<br />
 * out to ecryptfsd to dynamically retrieve an auth_tok object) so<br />
 * that static registration of auth_tok&#8217;s will no longer be necessary.<br />
 *<br />
 * Returns zero on no error; non-zero on error<br />
 */<br />
static int<br />
ecryptfs_find_auth_tok_for_sig(<br />
	struct ecryptfs_auth_tok **auth_tok,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
	char *sig)<br />
{<br />
	struct ecryptfs_global_auth_tok *global_auth_tok;<br />
	int rc = 0;</p>
<p>	(*auth_tok) = NULL;<br />
	if (ecryptfs_find_global_auth_tok_for_sig(&#038;global_auth_tok,<br />
						  mount_crypt_stat, sig)) {<br />
		struct key *auth_tok_key;</p>
<p>		rc = ecryptfs_keyring_auth_tok_for_sig(&#038;auth_tok_key, auth_tok,<br />
						       sig);<br />
	} else<br />
		(*auth_tok) = global_auth_tok->global_auth_tok;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * write_tag_70_packet can gobble a lot of stack space. We stuff most<br />
 * of the function&#8217;s parameters in a kmalloc&#8217;d struct to help reduce<br />
 * eCryptfs&#8217; overall stack usage.<br />
 */<br />
struct ecryptfs_write_tag_70_packet_silly_stack {<br />
	u8 cipher_code;<br />
	size_t max_packet_size;<br />
	size_t packet_size_len;<br />
	size_t block_aligned_filename_size;<br />
	size_t block_size;<br />
	size_t i;<br />
	size_t j;<br />
	size_t num_rand_bytes;<br />
	struct mutex *tfm_mutex;<br />
	char *block_aligned_filename;<br />
	struct ecryptfs_auth_tok *auth_tok;<br />
	struct scatterlist src_sg;<br />
	struct scatterlist dst_sg;<br />
	struct blkcipher_desc desc;<br />
	char iv[ECRYPTFS_MAX_IV_BYTES];<br />
	char hash[ECRYPTFS_TAG_70_DIGEST_SIZE];<br />
	char tmp_hash[ECRYPTFS_TAG_70_DIGEST_SIZE];<br />
	struct hash_desc hash_desc;<br />
	struct scatterlist hash_sg;<br />
};</p>
<p>/**<br />
 * write_tag_70_packet &#8211; Write encrypted filename (EFN) packet against FNEK<br />
 * @filename: NULL-terminated filename string<br />
 *<br />
 * This is the simplest mechanism for achieving filename encryption in<br />
 * eCryptfs. It encrypts the given filename with the mount-wide<br />
 * filename encryption key (FNEK) and stores it in a packet to @dest,<br />
 * which the callee will encode and write directly into the dentry<br />
 * name.<br />
 */<br />
int<br />
ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,<br />
			     size_t *packet_size,<br />
			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			     char *filename, size_t filename_size)<br />
{<br />
	struct ecryptfs_write_tag_70_packet_silly_stack *s;<br />
	int rc = 0;</p>
<p>	s = kmalloc(sizeof(*s), GFP_KERNEL);<br />
	if (!s) {<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst trying to kmalloc &raquo;<br />
		       &laquo;[%zd] bytes of kernel memory\n&raquo;, __func__, sizeof(*s));<br />
		goto out;<br />
	}<br />
	s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;<br />
	(*packet_size) = 0;<br />
	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(<br />
		&#038;s->desc.tfm,<br />
		&#038;s->tfm_mutex, mount_crypt_stat->global_default_fn_cipher_name);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to get &raquo;<br />
		       &laquo;tfm and mutex for cipher name [%s]; rc = [%d]\n&raquo;,<br />
		       mount_crypt_stat->global_default_fn_cipher_name, rc);<br />
		goto out;<br />
	}<br />
	mutex_lock(s->tfm_mutex);<br />
	s->block_size = crypto_blkcipher_blocksize(s->desc.tfm);<br />
	/* Plus one for the \0 separator between the random prefix<br />
	 * and the plaintext filename */<br />
	s->num_rand_bytes = (ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES + 1);<br />
	s->block_aligned_filename_size = (s->num_rand_bytes + filename_size);<br />
	if ((s->block_aligned_filename_size % s->block_size) != 0) {<br />
		s->num_rand_bytes += (s->block_size<br />
				      &#8211; (s->block_aligned_filename_size<br />
					 % s->block_size));<br />
		s->block_aligned_filename_size = (s->num_rand_bytes<br />
						  + filename_size);<br />
	}<br />
	/* Octet 0: Tag 70 identifier<br />
	 * Octets 1-N1: Tag 70 packet size (includes cipher identifier<br />
	 *              and block-aligned encrypted filename size)<br />
	 * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE)<br />
	 * Octet N2-N3: Cipher identifier (1 octet)<br />
	 * Octets N3-N4: Block-aligned encrypted filename<br />
	 *  &#8211; Consists of a minimum number of random characters, a \0<br />
	 *    separator, and then the filename */<br />
	s->max_packet_size = (1                   /* Tag 70 identifier */<br />
			      + 3                 /* Max Tag 70 packet size */<br />
			      + ECRYPTFS_SIG_SIZE /* FNEK sig */<br />
			      + 1                 /* Cipher identifier */<br />
			      + s->block_aligned_filename_size);<br />
	if (dest == NULL) {<br />
		(*packet_size) = s->max_packet_size;<br />
		goto out_unlock;<br />
	}<br />
	if (s->max_packet_size > (*remaining_bytes)) {<br />
		printk(KERN_WARNING &laquo;%s: Require [%zd] bytes to write; only &raquo;<br />
		       &laquo;[%zd] available\n&raquo;, __func__, s->max_packet_size,<br />
		       (*remaining_bytes));<br />
		rc = -EINVAL;<br />
		goto out_unlock;<br />
	}<br />
	s->block_aligned_filename = kzalloc(s->block_aligned_filename_size,<br />
					    GFP_KERNEL);<br />
	if (!s->block_aligned_filename) {<br />
		printk(KERN_ERR &laquo;%s: Out of kernel memory whilst attempting to &raquo;<br />
		       &laquo;kzalloc [%zd] bytes\n&raquo;, __func__,<br />
		       s->block_aligned_filename_size);<br />
		rc = -ENOMEM;<br />
		goto out_unlock;<br />
	}<br />
	s->i = 0;<br />
	dest[s->i++] = ECRYPTFS_TAG_70_PACKET_TYPE;<br />
	rc = ecryptfs_write_packet_length(&#038;dest[s->i],<br />
					  (ECRYPTFS_SIG_SIZE<br />
					   + 1 /* Cipher code */<br />
					   + s->block_aligned_filename_size),<br />
					  &#038;s->packet_size_len);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error generating tag 70 packet &raquo;<br />
		       &laquo;header; cannot generate packet length; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out_free_unlock;<br />
	}<br />
	s->i += s->packet_size_len;<br />
	ecryptfs_from_hex(&#038;dest[s->i],<br />
			  mount_crypt_stat->global_default_fnek_sig,<br />
			  ECRYPTFS_SIG_SIZE);<br />
	s->i += ECRYPTFS_SIG_SIZE;<br />
	s->cipher_code = ecryptfs_code_for_cipher_string(<br />
		mount_crypt_stat->global_default_fn_cipher_name,<br />
		mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
	if (s->cipher_code == 0) {<br />
		printk(KERN_WARNING &laquo;%s: Unable to generate code for &raquo;<br />
		       &laquo;cipher [%s] with key bytes [%zd]\n&raquo;, __func__,<br />
		       mount_crypt_stat->global_default_fn_cipher_name,<br />
		       mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
		rc = -EINVAL;<br />
		goto out_free_unlock;<br />
	}<br />
	dest[s->i++] = s->cipher_code;<br />
	rc = ecryptfs_find_auth_tok_for_sig(<br />
		&#038;s->auth_tok, mount_crypt_stat,<br />
		mount_crypt_stat->global_default_fnek_sig);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to find auth tok for &raquo;<br />
		       &laquo;fnek sig [%s]; rc = [%d]\n&raquo;, __func__,<br />
		       mount_crypt_stat->global_default_fnek_sig, rc);<br />
		goto out_free_unlock;<br />
	}<br />
	/* TODO: Support other key modules than passphrase for<br />
	 * filename encryption */<br />
	if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {<br />
		rc = -EOPNOTSUPP;<br />
		printk(KERN_INFO &laquo;%s: Filename encryption only supports &raquo;<br />
		       &laquo;password tokens\n&raquo;, __func__);<br />
		goto out_free_unlock;<br />
	}<br />
	sg_init_one(<br />
		&#038;s->hash_sg,<br />
		(u8 *)s->auth_tok->token.password.session_key_encryption_key,<br />
		s->auth_tok->token.password.session_key_encryption_key_bytes);<br />
	s->hash_desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;<br />
	s->hash_desc.tfm = crypto_alloc_hash(ECRYPTFS_TAG_70_DIGEST, 0,<br />
					     CRYPTO_ALG_ASYNC);<br />
	if (IS_ERR(s->hash_desc.tfm)) {<br />
			rc = PTR_ERR(s->hash_desc.tfm);<br />
			printk(KERN_ERR &laquo;%s: Error attempting to &raquo;<br />
			       &laquo;allocate hash crypto context; rc = [%d]\n&raquo;,<br />
			       __func__, rc);<br />
			goto out_free_unlock;<br />
	}<br />
	rc = crypto_hash_init(&#038;s->hash_desc);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error initializing crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out_release_free_unlock;<br />
	}<br />
	rc = crypto_hash_update(<br />
		&#038;s->hash_desc, &#038;s->hash_sg,<br />
		s->auth_tok->token.password.session_key_encryption_key_bytes);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error updating crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out_release_free_unlock;<br />
	}<br />
	rc = crypto_hash_final(&#038;s->hash_desc, s->hash);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error finalizing crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out_release_free_unlock;<br />
	}<br />
	for (s->j = 0; s->j < (s->num_rand_bytes &#8211; 1); s->j++) {<br />
		s->block_aligned_filename[s->j] =<br />
			s->hash[(s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)];<br />
		if ((s->j % ECRYPTFS_TAG_70_DIGEST_SIZE)<br />
		    == (ECRYPTFS_TAG_70_DIGEST_SIZE &#8211; 1)) {<br />
			sg_init_one(&#038;s->hash_sg, (u8 *)s->hash,<br />
				    ECRYPTFS_TAG_70_DIGEST_SIZE);<br />
			rc = crypto_hash_init(&#038;s->hash_desc);<br />
			if (rc) {<br />
				printk(KERN_ERR<br />
				       &laquo;%s: Error initializing crypto hash; &raquo;<br />
				       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
				goto out_release_free_unlock;<br />
			}<br />
			rc = crypto_hash_update(&#038;s->hash_desc, &#038;s->hash_sg,<br />
						ECRYPTFS_TAG_70_DIGEST_SIZE);<br />
			if (rc) {<br />
				printk(KERN_ERR<br />
				       &laquo;%s: Error updating crypto hash; &raquo;<br />
				       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
				goto out_release_free_unlock;<br />
			}<br />
			rc = crypto_hash_final(&#038;s->hash_desc, s->tmp_hash);<br />
			if (rc) {<br />
				printk(KERN_ERR<br />
				       &laquo;%s: Error finalizing crypto hash; &raquo;<br />
				       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
				goto out_release_free_unlock;<br />
			}<br />
			memcpy(s->hash, s->tmp_hash,<br />
			       ECRYPTFS_TAG_70_DIGEST_SIZE);<br />
		}<br />
		if (s->block_aligned_filename[s->j] == &#8216;\0&#8242;)<br />
			s->block_aligned_filename[s->j] = ECRYPTFS_NON_NULL;<br />
	}<br />
	memcpy(&#038;s->block_aligned_filename[s->num_rand_bytes], filename,<br />
	       filename_size);<br />
	rc = virt_to_scatterlist(s->block_aligned_filename,<br />
				 s->block_aligned_filename_size, &#038;s->src_sg, 1);<br />
	if (rc != 1) {<br />
		printk(KERN_ERR &laquo;%s: Internal error whilst attempting to &raquo;<br />
		       &laquo;convert filename memory to scatterlist; &raquo;<br />
		       &laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
		       &laquo;block_aligned_filename_size = [%zd]\n&raquo;, __func__, rc,<br />
		       s->block_aligned_filename_size);<br />
		goto out_release_free_unlock;<br />
	}<br />
	rc = virt_to_scatterlist(&#038;dest[s->i], s->block_aligned_filename_size,<br />
				 &#038;s->dst_sg, 1);<br />
	if (rc != 1) {<br />
		printk(KERN_ERR &laquo;%s: Internal error whilst attempting to &raquo;<br />
		       &laquo;convert encrypted filename memory to scatterlist; &raquo;<br />
		       &laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
		       &laquo;block_aligned_filename_size = [%zd]\n&raquo;, __func__, rc,<br />
		       s->block_aligned_filename_size);<br />
		goto out_release_free_unlock;<br />
	}<br />
	/* The characters in the first block effectively do the job<br />
	 * of the IV here, so we just use 0&#8217;s for the IV. Note the<br />
	 * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES<br />
	 * >= ECRYPTFS_MAX_IV_BYTES. */<br />
	memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES);<br />
	s->desc.info = s->iv;<br />
	rc = crypto_blkcipher_setkey(<br />
		s->desc.tfm,<br />
		s->auth_tok->token.password.session_key_encryption_key,<br />
		mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "%s: Error setting key for crypto context; "<br />
		       "rc = [%d]. s->auth_tok->token.password.session_key_&raquo;<br />
		       &laquo;encryption_key = [0x%p]; mount_crypt_stat->&raquo;<br />
		       &laquo;global_default_fn_cipher_key_bytes = [%zd]\n&raquo;, __func__,<br />
		       rc,<br />
		       s->auth_tok->token.password.session_key_encryption_key,<br />
		       mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
		goto out_release_free_unlock;<br />
	}<br />
	rc = crypto_blkcipher_encrypt_iv(&#038;s->desc, &#038;s->dst_sg, &#038;s->src_sg,<br />
					 s->block_aligned_filename_size);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to encrypt filename; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_release_free_unlock;<br />
	}<br />
	s->i += s->block_aligned_filename_size;<br />
	(*packet_size) = s->i;<br />
	(*remaining_bytes) -= (*packet_size);<br />
out_release_free_unlock:<br />
	crypto_free_hash(s->hash_desc.tfm);<br />
out_free_unlock:<br />
	kzfree(s->block_aligned_filename);<br />
out_unlock:<br />
	mutex_unlock(s->tfm_mutex);<br />
out:<br />
	kfree(s);<br />
	return rc;<br />
}</p>
<p>struct ecryptfs_parse_tag_70_packet_silly_stack {<br />
	u8 cipher_code;<br />
	size_t max_packet_size;<br />
	size_t packet_size_len;<br />
	size_t parsed_tag_70_packet_size;<br />
	size_t block_aligned_filename_size;<br />
	size_t block_size;<br />
	size_t i;<br />
	struct mutex *tfm_mutex;<br />
	char *decrypted_filename;<br />
	struct ecryptfs_auth_tok *auth_tok;<br />
	struct scatterlist src_sg;<br />
	struct scatterlist dst_sg;<br />
	struct blkcipher_desc desc;<br />
	char fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX + 1];<br />
	char iv[ECRYPTFS_MAX_IV_BYTES];<br />
	char cipher_string[ECRYPTFS_MAX_CIPHER_NAME_SIZE];<br />
};</p>
<p>/**<br />
 * parse_tag_70_packet &#8211; Parse and process FNEK-encrypted passphrase packet<br />
 * @filename: This function kmalloc&#8217;s the memory for the filename<br />
 * @filename_size: This function sets this to the amount of memory<br />
 *                 kmalloc&#8217;d for the filename<br />
 * @packet_size: This function sets this to the the number of octets<br />
 *               in the packet parsed<br />
 * @mount_crypt_stat: The mount-wide cryptographic context<br />
 * @data: The memory location containing the start of the tag 70<br />
 *        packet<br />
 * @max_packet_size: The maximum legal size of the packet to be parsed<br />
 *                   from @data<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int<br />
ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,<br />
			     size_t *packet_size,<br />
			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			     char *data, size_t max_packet_size)<br />
{<br />
	struct ecryptfs_parse_tag_70_packet_silly_stack *s;<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	(*filename_size) = 0;<br />
	(*filename) = NULL;<br />
	s = kmalloc(sizeof(*s), GFP_KERNEL);<br />
	if (!s) {<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst trying to kmalloc &raquo;<br />
		       &laquo;[%zd] bytes of kernel memory\n&raquo;, __func__, sizeof(*s));<br />
		goto out;<br />
	}<br />
	s->desc.flags = CRYPTO_TFM_REQ_MAY_SLEEP;<br />
	if (max_packet_size < (1 + 1 + ECRYPTFS_SIG_SIZE + 1 + 1)) {<br />
		printk(KERN_WARNING "%s: max_packet_size is [%zd]; it must be "<br />
		       "at least [%d]\n", __func__, max_packet_size,<br />
			(1 + 1 + ECRYPTFS_SIG_SIZE + 1 + 1));<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	/* Octet 0: Tag 70 identifier<br />
	 * Octets 1-N1: Tag 70 packet size (includes cipher identifier<br />
	 *              and block-aligned encrypted filename size)<br />
	 * Octets N1-N2: FNEK sig (ECRYPTFS_SIG_SIZE)<br />
	 * Octet N2-N3: Cipher identifier (1 octet)<br />
	 * Octets N3-N4: Block-aligned encrypted filename<br />
	 *  - Consists of a minimum number of random numbers, a \0<br />
	 *    separator, and then the filename */<br />
	if (data[(*packet_size)++] != ECRYPTFS_TAG_70_PACKET_TYPE) {<br />
		printk(KERN_WARNING "%s: Invalid packet tag [0x%.2x]; must be "<br />
		       "tag [0x%.2x]\n", __func__,<br />
		       data[((*packet_size) - 1)], ECRYPTFS_TAG_70_PACKET_TYPE);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_parse_packet_length(&#038;data[(*packet_size)],<br />
					  &#038;s->parsed_tag_70_packet_size,<br />
					  &#038;s->packet_size_len);<br />
	if (rc) {<br />
		printk(KERN_WARNING &laquo;%s: Error parsing packet length; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out;<br />
	}<br />
	s->block_aligned_filename_size = (s->parsed_tag_70_packet_size<br />
					  &#8211; ECRYPTFS_SIG_SIZE &#8211; 1);<br />
	if ((1 + s->packet_size_len + s->parsed_tag_70_packet_size)<br />
	    > max_packet_size) {<br />
		printk(KERN_WARNING &laquo;%s: max_packet_size is [%zd]; real packet &raquo;<br />
		       &laquo;size is [%zd]\n&raquo;, __func__, max_packet_size,<br />
		       (1 + s->packet_size_len + 1<br />
			+ s->block_aligned_filename_size));<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	(*packet_size) += s->packet_size_len;<br />
	ecryptfs_to_hex(s->fnek_sig_hex, &#038;data[(*packet_size)],<br />
			ECRYPTFS_SIG_SIZE);<br />
	s->fnek_sig_hex[ECRYPTFS_SIG_SIZE_HEX] = &#8216;\0&#8242;;<br />
	(*packet_size) += ECRYPTFS_SIG_SIZE;<br />
	s->cipher_code = data[(*packet_size)++];<br />
	rc = ecryptfs_cipher_code_to_string(s->cipher_string, s->cipher_code);<br />
	if (rc) {<br />
		printk(KERN_WARNING &laquo;%s: Cipher code [%d] is invalid\n&raquo;,<br />
		       __func__, s->cipher_code);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&#038;s->desc.tfm,<br />
							&#038;s->tfm_mutex,<br />
							s->cipher_string);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to get &raquo;<br />
		       &laquo;tfm and mutex for cipher name [%s]; rc = [%d]\n&raquo;,<br />
		       s->cipher_string, rc);<br />
		goto out;<br />
	}<br />
	mutex_lock(s->tfm_mutex);<br />
	rc = virt_to_scatterlist(&#038;data[(*packet_size)],<br />
				 s->block_aligned_filename_size, &#038;s->src_sg, 1);<br />
	if (rc != 1) {<br />
		printk(KERN_ERR &laquo;%s: Internal error whilst attempting to &raquo;<br />
		       &laquo;convert encrypted filename memory to scatterlist; &raquo;<br />
		       &laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
		       &laquo;block_aligned_filename_size = [%zd]\n&raquo;, __func__, rc,<br />
		       s->block_aligned_filename_size);<br />
		goto out_unlock;<br />
	}<br />
	(*packet_size) += s->block_aligned_filename_size;<br />
	s->decrypted_filename = kmalloc(s->block_aligned_filename_size,<br />
					GFP_KERNEL);<br />
	if (!s->decrypted_filename) {<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst attempting to &raquo;<br />
		       &laquo;kmalloc [%zd] bytes\n&raquo;, __func__,<br />
		       s->block_aligned_filename_size);<br />
		rc = -ENOMEM;<br />
		goto out_unlock;<br />
	}<br />
	rc = virt_to_scatterlist(s->decrypted_filename,<br />
				 s->block_aligned_filename_size, &#038;s->dst_sg, 1);<br />
	if (rc != 1) {<br />
		printk(KERN_ERR &laquo;%s: Internal error whilst attempting to &raquo;<br />
		       &laquo;convert decrypted filename memory to scatterlist; &raquo;<br />
		       &laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
		       &laquo;block_aligned_filename_size = [%zd]\n&raquo;, __func__, rc,<br />
		       s->block_aligned_filename_size);<br />
		goto out_free_unlock;<br />
	}<br />
	/* The characters in the first block effectively do the job of<br />
	 * the IV here, so we just use 0&#8217;s for the IV. Note the<br />
	 * constraint that ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES<br />
	 * >= ECRYPTFS_MAX_IV_BYTES. */<br />
	memset(s->iv, 0, ECRYPTFS_MAX_IV_BYTES);<br />
	s->desc.info = s->iv;<br />
	rc = ecryptfs_find_auth_tok_for_sig(&#038;s->auth_tok, mount_crypt_stat,<br />
					    s->fnek_sig_hex);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to find auth tok for &raquo;<br />
		       &laquo;fnek sig [%s]; rc = [%d]\n&raquo;, __func__, s->fnek_sig_hex,<br />
		       rc);<br />
		goto out_free_unlock;<br />
	}<br />
	/* TODO: Support other key modules than passphrase for<br />
	 * filename encryption */<br />
	if (s->auth_tok->token_type != ECRYPTFS_PASSWORD) {<br />
		rc = -EOPNOTSUPP;<br />
		printk(KERN_INFO &laquo;%s: Filename encryption only supports &raquo;<br />
		       &laquo;password tokens\n&raquo;, __func__);<br />
		goto out_free_unlock;<br />
	}<br />
	rc = crypto_blkcipher_setkey(<br />
		s->desc.tfm,<br />
		s->auth_tok->token.password.session_key_encryption_key,<br />
		mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "%s: Error setting key for crypto context; "<br />
		       "rc = [%d]. s->auth_tok->token.password.session_key_&raquo;<br />
		       &laquo;encryption_key = [0x%p]; mount_crypt_stat->&raquo;<br />
		       &laquo;global_default_fn_cipher_key_bytes = [%zd]\n&raquo;, __func__,<br />
		       rc,<br />
		       s->auth_tok->token.password.session_key_encryption_key,<br />
		       mount_crypt_stat->global_default_fn_cipher_key_bytes);<br />
		goto out_free_unlock;<br />
	}<br />
	rc = crypto_blkcipher_decrypt_iv(&#038;s->desc, &#038;s->dst_sg, &#038;s->src_sg,<br />
					 s->block_aligned_filename_size);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to decrypt filename; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_free_unlock;<br />
	}<br />
	s->i = 0;<br />
	while (s->decrypted_filename[s->i] != &#8216;\0&#8242;<br />
	       &#038;&#038; s->i < s->block_aligned_filename_size)<br />
		s->i++;<br />
	if (s->i == s->block_aligned_filename_size) {<br />
		printk(KERN_WARNING &laquo;%s: Invalid tag 70 packet; could not &raquo;<br />
		       &laquo;find valid separator between random characters and &raquo;<br />
		       &laquo;the filename\n&raquo;, __func__);<br />
		rc = -EINVAL;<br />
		goto out_free_unlock;<br />
	}<br />
	s->i++;<br />
	(*filename_size) = (s->block_aligned_filename_size &#8211; s->i);<br />
	if (!((*filename_size) > 0 &#038;&#038; (*filename_size < PATH_MAX))) {<br />
		printk(KERN_WARNING "%s: Filename size is [%zd], which is "<br />
		       "invalid\n", __func__, (*filename_size));<br />
		rc = -EINVAL;<br />
		goto out_free_unlock;<br />
	}<br />
	(*filename) = kmalloc(((*filename_size) + 1), GFP_KERNEL);<br />
	if (!(*filename)) {<br />
		printk(KERN_ERR "%s: Out of memory whilst attempting to "<br />
		       "kmalloc [%zd] bytes\n", __func__,<br />
		       ((*filename_size) + 1));<br />
		rc = -ENOMEM;<br />
		goto out_free_unlock;<br />
	}<br />
	memcpy((*filename), &#038;s->decrypted_filename[s->i], (*filename_size));<br />
	(*filename)[(*filename_size)] = &#8216;\0&#8242;;<br />
out_free_unlock:<br />
	kfree(s->decrypted_filename);<br />
out_unlock:<br />
	mutex_unlock(s->tfm_mutex);<br />
out:<br />
	if (rc) {<br />
		(*packet_size) = 0;<br />
		(*filename_size) = 0;<br />
		(*filename) = NULL;<br />
	}<br />
	kfree(s);<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_get_auth_tok_sig(char **sig, struct ecryptfs_auth_tok *auth_tok)<br />
{<br />
	int rc = 0;</p>
<p>	(*sig) = NULL;<br />
	switch (auth_tok->token_type) {<br />
	case ECRYPTFS_PASSWORD:<br />
		(*sig) = auth_tok->token.password.signature;<br />
		break;<br />
	case ECRYPTFS_PRIVATE_KEY:<br />
		(*sig) = auth_tok->token.private_key.signature;<br />
		break;<br />
	default:<br />
		printk(KERN_ERR &laquo;Cannot get sig for auth_tok of type [%d]\n&raquo;,<br />
		       auth_tok->token_type);<br />
		rc = -EINVAL;<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * decrypt_pki_encrypted_session_key &#8211; Decrypt the session key with the given auth_tok.<br />
 * @auth_tok: The key authentication token used to decrypt the session key<br />
 * @crypt_stat: The cryptographic context<br />
 *<br />
 * Returns zero on success; non-zero error otherwise.<br />
 */<br />
static int<br />
decrypt_pki_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,<br />
				  struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	u8 cipher_code = 0;<br />
	struct ecryptfs_msg_ctx *msg_ctx;<br />
	struct ecryptfs_message *msg = NULL;<br />
	char *auth_tok_sig;<br />
	char *payload;<br />
	size_t payload_len;<br />
	int rc;</p>
<p>	rc = ecryptfs_get_auth_tok_sig(&#038;auth_tok_sig, auth_tok);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Unrecognized auth tok type: [%d]\n&raquo;,<br />
		       auth_tok->token_type);<br />
		goto out;<br />
	}<br />
	rc = write_tag_64_packet(auth_tok_sig, &#038;(auth_tok->session_key),<br />
				 &#038;payload, &#038;payload_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Failed to write tag 64 packet\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_send_message(payload, payload_len, &#038;msg_ctx);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error sending message to &raquo;<br />
				&laquo;ecryptfsd\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_wait_for_response(msg_ctx, &#038;msg);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Failed to receive tag 65 packet &raquo;<br />
				&laquo;from the user space daemon\n&raquo;);<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	rc = parse_tag_65_packet(&#038;(auth_tok->session_key),<br />
				 &#038;cipher_code, msg);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Failed to parse tag 65 packet; rc = [%d]\n&raquo;,<br />
		       rc);<br />
		goto out;<br />
	}<br />
	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;<br />
	memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,<br />
	       auth_tok->session_key.decrypted_key_size);<br />
	crypt_stat->key_size = auth_tok->session_key.decrypted_key_size;<br />
	rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher, cipher_code);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Cipher code [%d] is invalid\n&raquo;,<br />
				cipher_code)<br />
		goto out;<br />
	}<br />
	crypt_stat->flags |= ECRYPTFS_KEY_VALID;<br />
	if (ecryptfs_verbosity > 0) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Decrypted session key:\n&raquo;);<br />
		ecryptfs_dump_hex(crypt_stat->key,<br />
				  crypt_stat->key_size);<br />
	}<br />
out:<br />
	if (msg)<br />
		kfree(msg);<br />
	return rc;<br />
}</p>
<p>static void wipe_auth_tok_list(struct list_head *auth_tok_list_head)<br />
{<br />
	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;<br />
	struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;</p>
<p>	list_for_each_entry_safe(auth_tok_list_item, auth_tok_list_item_tmp,<br />
				 auth_tok_list_head, list) {<br />
		list_del(&#038;auth_tok_list_item->list);<br />
		kmem_cache_free(ecryptfs_auth_tok_list_item_cache,<br />
				auth_tok_list_item);<br />
	}<br />
}</p>
<p>struct kmem_cache *ecryptfs_auth_tok_list_item_cache;</p>
<p>/**<br />
 * parse_tag_1_packet<br />
 * @crypt_stat: The cryptographic context to modify based on packet contents<br />
 * @data: The raw bytes of the packet.<br />
 * @auth_tok_list: eCryptfs parses packets into authentication tokens;<br />
 *                 a new authentication token will be placed at the<br />
 *                 end of this list for this packet.<br />
 * @new_auth_tok: Pointer to a pointer to memory that this function<br />
 *                allocates; sets the memory address of the pointer to<br />
 *                NULL on error. This object is added to the<br />
 *                auth_tok_list.<br />
 * @packet_size: This function writes the size of the parsed packet<br />
 *               into this memory location; zero on error.<br />
 * @max_packet_size: The maximum allowable packet size<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
parse_tag_1_packet(struct ecryptfs_crypt_stat *crypt_stat,<br />
		   unsigned char *data, struct list_head *auth_tok_list,<br />
		   struct ecryptfs_auth_tok **new_auth_tok,<br />
		   size_t *packet_size, size_t max_packet_size)<br />
{<br />
	size_t body_size;<br />
	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;<br />
	size_t length_size;<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	(*new_auth_tok) = NULL;<br />
	/**<br />
	 * This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 1<br />
	 *<br />
	 * Tag 1 identifier (1 byte)<br />
	 * Max Tag 1 packet size (max 3 bytes)<br />
	 * Version (1 byte)<br />
	 * Key identifier (8 bytes; ECRYPTFS_SIG_SIZE)<br />
	 * Cipher identifier (1 byte)<br />
	 * Encrypted key size (arbitrary)<br />
	 *<br />
	 * 12 bytes minimum packet size<br />
	 */<br />
	if (unlikely(max_packet_size < 12)) {<br />
		printk(KERN_ERR "Invalid max packet size; must be >=12\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (data[(*packet_size)++] != ECRYPTFS_TAG_1_PACKET_TYPE) {<br />
		printk(KERN_ERR &laquo;Enter w/ first byte != 0x%.2x\n&raquo;,<br />
		       ECRYPTFS_TAG_1_PACKET_TYPE);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or<br />
	 * at end of function upon failure */<br />
	auth_tok_list_item =<br />
		kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache,<br />
				  GFP_KERNEL);<br />
	if (!auth_tok_list_item) {<br />
		printk(KERN_ERR &laquo;Unable to allocate memory\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	(*new_auth_tok) = &#038;auth_tok_list_item->auth_tok;<br />
	rc = ecryptfs_parse_packet_length(&#038;data[(*packet_size)], &#038;body_size,<br />
					  &#038;length_size);<br />
	if (rc) {<br />
		printk(KERN_WARNING &laquo;Error parsing packet length; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, rc);<br />
		goto out_free;<br />
	}<br />
	if (unlikely(body_size < (ECRYPTFS_SIG_SIZE + 2))) {<br />
		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	(*packet_size) += length_size;<br />
	if (unlikely((*packet_size) + body_size > max_packet_size)) {<br />
		printk(KERN_WARNING &laquo;Packet size exceeds max\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	if (unlikely(data[(*packet_size)++] != 0&#215;03)) {<br />
		printk(KERN_WARNING &laquo;Unknown version number [%d]\n&raquo;,<br />
		       data[(*packet_size) - 1]);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	ecryptfs_to_hex((*new_auth_tok)->token.private_key.signature,<br />
			&#038;data[(*packet_size)], ECRYPTFS_SIG_SIZE);<br />
	*packet_size += ECRYPTFS_SIG_SIZE;<br />
	/* This byte is skipped because the kernel does not need to<br />
	 * know which public key encryption algorithm was used */<br />
	(*packet_size)++;<br />
	(*new_auth_tok)->session_key.encrypted_key_size =<br />
		body_size &#8211; (ECRYPTFS_SIG_SIZE + 2);<br />
	if ((*new_auth_tok)->session_key.encrypted_key_size<br />
	    > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {<br />
		printk(KERN_WARNING &laquo;Tag 1 packet contains key larger &raquo;<br />
		       &laquo;than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	memcpy((*new_auth_tok)->session_key.encrypted_key,<br />
	       &#038;data[(*packet_size)], (body_size &#8211; (ECRYPTFS_SIG_SIZE + 2)));<br />
	(*packet_size) += (*new_auth_tok)->session_key.encrypted_key_size;<br />
	(*new_auth_tok)->session_key.flags &#038;=<br />
		~ECRYPTFS_CONTAINS_DECRYPTED_KEY;<br />
	(*new_auth_tok)->session_key.flags |=<br />
		ECRYPTFS_CONTAINS_ENCRYPTED_KEY;<br />
	(*new_auth_tok)->token_type = ECRYPTFS_PRIVATE_KEY;<br />
	(*new_auth_tok)->flags = 0;<br />
	(*new_auth_tok)->session_key.flags &#038;=<br />
		~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);<br />
	(*new_auth_tok)->session_key.flags &#038;=<br />
		~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);<br />
	list_add(&#038;auth_tok_list_item->list, auth_tok_list);<br />
	goto out;<br />
out_free:<br />
	(*new_auth_tok) = NULL;<br />
	memset(auth_tok_list_item, 0,<br />
	       sizeof(struct ecryptfs_auth_tok_list_item));<br />
	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,<br />
			auth_tok_list_item);<br />
out:<br />
	if (rc)<br />
		(*packet_size) = 0;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * parse_tag_3_packet<br />
 * @crypt_stat: The cryptographic context to modify based on packet<br />
 *              contents.<br />
 * @data: The raw bytes of the packet.<br />
 * @auth_tok_list: eCryptfs parses packets into authentication tokens;<br />
 *                 a new authentication token will be placed at the end<br />
 *                 of this list for this packet.<br />
 * @new_auth_tok: Pointer to a pointer to memory that this function<br />
 *                allocates; sets the memory address of the pointer to<br />
 *                NULL on error. This object is added to the<br />
 *                auth_tok_list.<br />
 * @packet_size: This function writes the size of the parsed packet<br />
 *               into this memory location; zero on error.<br />
 * @max_packet_size: maximum number of bytes to parse<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
parse_tag_3_packet(struct ecryptfs_crypt_stat *crypt_stat,<br />
		   unsigned char *data, struct list_head *auth_tok_list,<br />
		   struct ecryptfs_auth_tok **new_auth_tok,<br />
		   size_t *packet_size, size_t max_packet_size)<br />
{<br />
	size_t body_size;<br />
	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;<br />
	size_t length_size;<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	(*new_auth_tok) = NULL;<br />
	/**<br />
	 *This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 3<br />
	 *<br />
	 * Tag 3 identifier (1 byte)<br />
	 * Max Tag 3 packet size (max 3 bytes)<br />
	 * Version (1 byte)<br />
	 * Cipher code (1 byte)<br />
	 * S2K specifier (1 byte)<br />
	 * Hash identifier (1 byte)<br />
	 * Salt (ECRYPTFS_SALT_SIZE)<br />
	 * Hash iterations (1 byte)<br />
	 * Encrypted key (arbitrary)<br />
	 *<br />
	 * (ECRYPTFS_SALT_SIZE + 7) minimum packet size<br />
	 */<br />
	if (max_packet_size < (ECRYPTFS_SALT_SIZE + 7)) {<br />
		printk(KERN_ERR "Max packet size too large\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (data[(*packet_size)++] != ECRYPTFS_TAG_3_PACKET_TYPE) {<br />
		printk(KERN_ERR "First byte != 0x%.2x; invalid packet\n",<br />
		       ECRYPTFS_TAG_3_PACKET_TYPE);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	/* Released: wipe_auth_tok_list called in ecryptfs_parse_packet_set or<br />
	 * at end of function upon failure */<br />
	auth_tok_list_item =<br />
	    kmem_cache_zalloc(ecryptfs_auth_tok_list_item_cache, GFP_KERNEL);<br />
	if (!auth_tok_list_item) {<br />
		printk(KERN_ERR "Unable to allocate memory\n");<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	(*new_auth_tok) = &#038;auth_tok_list_item->auth_tok;<br />
	rc = ecryptfs_parse_packet_length(&#038;data[(*packet_size)], &#038;body_size,<br />
					  &#038;length_size);<br />
	if (rc) {<br />
		printk(KERN_WARNING &laquo;Error parsing packet length; rc = [%d]\n&raquo;,<br />
		       rc);<br />
		goto out_free;<br />
	}<br />
	if (unlikely(body_size < (ECRYPTFS_SALT_SIZE + 5))) {<br />
		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	(*packet_size) += length_size;<br />
	if (unlikely((*packet_size) + body_size > max_packet_size)) {<br />
		printk(KERN_ERR &laquo;Packet size exceeds max\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	(*new_auth_tok)->session_key.encrypted_key_size =<br />
		(body_size &#8211; (ECRYPTFS_SALT_SIZE + 5));<br />
	if ((*new_auth_tok)->session_key.encrypted_key_size<br />
	    > ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES) {<br />
		printk(KERN_WARNING &laquo;Tag 3 packet contains key larger &raquo;<br />
		       &laquo;than ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	if (unlikely(data[(*packet_size)++] != 0&#215;04)) {<br />
		printk(KERN_WARNING &laquo;Unknown version number [%d]\n&raquo;,<br />
		       data[(*packet_size) - 1]);<br />
		rc = -EINVAL;<br />
		goto out_free;<br />
	}<br />
	rc = ecryptfs_cipher_code_to_string(crypt_stat->cipher,<br />
					    (u16)data[(*packet_size)]);<br />
	if (rc)<br />
		goto out_free;<br />
	/* A little extra work to differentiate among the AES key<br />
	 * sizes; see RFC2440 */<br />
	switch(data[(*packet_size)++]) {<br />
	case RFC2440_CIPHER_AES_192:<br />
		crypt_stat->key_size = 24;<br />
		break;<br />
	default:<br />
		crypt_stat->key_size =<br />
			(*new_auth_tok)->session_key.encrypted_key_size;<br />
	}<br />
	rc = ecryptfs_init_crypt_ctx(crypt_stat);<br />
	if (rc)<br />
		goto out_free;<br />
	if (unlikely(data[(*packet_size)++] != 0&#215;03)) {<br />
		printk(KERN_WARNING &laquo;Only S2K ID 3 is currently supported\n&raquo;);<br />
		rc = -ENOSYS;<br />
		goto out_free;<br />
	}<br />
	/* TODO: finish the hash mapping */<br />
	switch (data[(*packet_size)++]) {<br />
	case 0&#215;01: /* See RFC2440 for these numbers and their mappings */<br />
		/* Choose MD5 */<br />
		memcpy((*new_auth_tok)->token.password.salt,<br />
		       &#038;data[(*packet_size)], ECRYPTFS_SALT_SIZE);<br />
		(*packet_size) += ECRYPTFS_SALT_SIZE;<br />
		/* This conversion was taken straight from RFC2440 */<br />
		(*new_auth_tok)->token.password.hash_iterations =<br />
			((u32) 16 + (data[(*packet_size)] &#038; 15))<br />
				<< ((data[(*packet_size)] >> 4) + 6);<br />
		(*packet_size)++;<br />
		/* Friendly reminder:<br />
		 * (*new_auth_tok)->session_key.encrypted_key_size =<br />
		 *         (body_size &#8211; (ECRYPTFS_SALT_SIZE + 5)); */<br />
		memcpy((*new_auth_tok)->session_key.encrypted_key,<br />
		       &#038;data[(*packet_size)],<br />
		       (*new_auth_tok)->session_key.encrypted_key_size);<br />
		(*packet_size) +=<br />
			(*new_auth_tok)->session_key.encrypted_key_size;<br />
		(*new_auth_tok)->session_key.flags &#038;=<br />
			~ECRYPTFS_CONTAINS_DECRYPTED_KEY;<br />
		(*new_auth_tok)->session_key.flags |=<br />
			ECRYPTFS_CONTAINS_ENCRYPTED_KEY;<br />
		(*new_auth_tok)->token.password.hash_algo = 0&#215;01; /* MD5 */<br />
		break;<br />
	default:<br />
		ecryptfs_printk(KERN_ERR, &laquo;Unsupported hash algorithm: &raquo;<br />
				&laquo;[%d]\n&raquo;, data[(*packet_size) - 1]);<br />
		rc = -ENOSYS;<br />
		goto out_free;<br />
	}<br />
	(*new_auth_tok)->token_type = ECRYPTFS_PASSWORD;<br />
	/* TODO: Parametarize; we might actually want userspace to<br />
	 * decrypt the session key. */<br />
	(*new_auth_tok)->session_key.flags &#038;=<br />
			    ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT);<br />
	(*new_auth_tok)->session_key.flags &#038;=<br />
			    ~(ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT);<br />
	list_add(&#038;auth_tok_list_item->list, auth_tok_list);<br />
	goto out;<br />
out_free:<br />
	(*new_auth_tok) = NULL;<br />
	memset(auth_tok_list_item, 0,<br />
	       sizeof(struct ecryptfs_auth_tok_list_item));<br />
	kmem_cache_free(ecryptfs_auth_tok_list_item_cache,<br />
			auth_tok_list_item);<br />
out:<br />
	if (rc)<br />
		(*packet_size) = 0;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * parse_tag_11_packet<br />
 * @data: The raw bytes of the packet<br />
 * @contents: This function writes the data contents of the literal<br />
 *            packet into this memory location<br />
 * @max_contents_bytes: The maximum number of bytes that this function<br />
 *                      is allowed to write into contents<br />
 * @tag_11_contents_size: This function writes the size of the parsed<br />
 *                        contents into this memory location; zero on<br />
 *                        error<br />
 * @packet_size: This function writes the size of the parsed packet<br />
 *               into this memory location; zero on error<br />
 * @max_packet_size: maximum number of bytes to parse<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
parse_tag_11_packet(unsigned char *data, unsigned char *contents,<br />
		    size_t max_contents_bytes, size_t *tag_11_contents_size,<br />
		    size_t *packet_size, size_t max_packet_size)<br />
{<br />
	size_t body_size;<br />
	size_t length_size;<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	(*tag_11_contents_size) = 0;<br />
	/* This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 11<br />
	 *<br />
	 * Tag 11 identifier (1 byte)<br />
	 * Max Tag 11 packet size (max 3 bytes)<br />
	 * Binary format specifier (1 byte)<br />
	 * Filename length (1 byte)<br />
	 * Filename (&raquo;_CONSOLE&raquo;) (8 bytes)<br />
	 * Modification date (4 bytes)<br />
	 * Literal data (arbitrary)<br />
	 *<br />
	 * We need at least 16 bytes of data for the packet to even be<br />
	 * valid.<br />
	 */<br />
	if (max_packet_size < 16) {<br />
		printk(KERN_ERR "Maximum packet size too small\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (data[(*packet_size)++] != ECRYPTFS_TAG_11_PACKET_TYPE) {<br />
		printk(KERN_WARNING "Invalid tag 11 packet format\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_parse_packet_length(&#038;data[(*packet_size)], &#038;body_size,<br />
					  &#038;length_size);<br />
	if (rc) {<br />
		printk(KERN_WARNING "Invalid tag 11 packet format\n");<br />
		goto out;<br />
	}<br />
	if (body_size < 14) {<br />
		printk(KERN_WARNING "Invalid body size ([%td])\n", body_size);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	(*packet_size) += length_size;<br />
	(*tag_11_contents_size) = (body_size - 14);<br />
	if (unlikely((*packet_size) + body_size + 1 > max_packet_size)) {<br />
		printk(KERN_ERR &laquo;Packet size exceeds max\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (unlikely((*tag_11_contents_size) > max_contents_bytes)) {<br />
		printk(KERN_ERR &laquo;Literal data section in tag 11 packet exceeds &raquo;<br />
		       &laquo;expected size\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (data[(*packet_size)++] != 0&#215;62) {<br />
		printk(KERN_WARNING &laquo;Unrecognizable packet\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (data[(*packet_size)++] != 0&#215;08) {<br />
		printk(KERN_WARNING &laquo;Unrecognizable packet\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	(*packet_size) += 12; /* Ignore filename and modification date */<br />
	memcpy(contents, &#038;data[(*packet_size)], (*tag_11_contents_size));<br />
	(*packet_size) += (*tag_11_contents_size);<br />
out:<br />
	if (rc) {<br />
		(*packet_size) = 0;<br />
		(*tag_11_contents_size) = 0;<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_verify_version<br />
 * @version: The version number to confirm<br />
 *<br />
 * Returns zero on good version; non-zero otherwise<br />
 */<br />
static int ecryptfs_verify_version(u16 version)<br />
{<br />
	int rc = 0;<br />
	unsigned char major;<br />
	unsigned char minor;</p>
<p>	major = ((version >> <img src='http://lynyrd.ru/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> &#038; 0xFF);<br />
	minor = (version &#038; 0xFF);<br />
	if (major != ECRYPTFS_VERSION_MAJOR) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Major version number mismatch. &raquo;<br />
				&laquo;Expected [%d]; got [%d]\n&raquo;,<br />
				ECRYPTFS_VERSION_MAJOR, major);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if (minor != ECRYPTFS_VERSION_MINOR) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Minor version number mismatch. &raquo;<br />
				&laquo;Expected [%d]; got [%d]\n&raquo;,<br />
				ECRYPTFS_VERSION_MINOR, minor);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,<br />
				      struct ecryptfs_auth_tok **auth_tok,<br />
				      char *sig)<br />
{<br />
	int rc = 0;</p>
<p>	(*auth_tok_key) = request_key(&#038;key_type_user, sig, NULL);<br />
	if (!(*auth_tok_key) || IS_ERR(*auth_tok_key)) {<br />
		printk(KERN_ERR &laquo;Could not find key with description: [%s]\n&raquo;,<br />
		       sig);<br />
		rc = process_request_key_err(PTR_ERR(*auth_tok_key));<br />
		goto out;<br />
	}<br />
	(*auth_tok) = ecryptfs_get_key_payload_data(*auth_tok_key);<br />
	if (ecryptfs_verify_version((*auth_tok)->version)) {<br />
		printk(KERN_ERR<br />
		       &laquo;Data structure version mismatch. &raquo;<br />
		       &laquo;Userspace tools must match eCryptfs &raquo;<br />
		       &laquo;kernel module with major version [%d] &raquo;<br />
		       &laquo;and minor version [%d]\n&raquo;,<br />
		       ECRYPTFS_VERSION_MAJOR,<br />
		       ECRYPTFS_VERSION_MINOR);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	if ((*auth_tok)->token_type != ECRYPTFS_PASSWORD<br />
	    &#038;&#038; (*auth_tok)->token_type != ECRYPTFS_PRIVATE_KEY) {<br />
		printk(KERN_ERR &laquo;Invalid auth_tok structure &raquo;<br />
		       &laquo;returned from key query\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * decrypt_passphrase_encrypted_session_key &#8211; Decrypt the session key with the given auth_tok.<br />
 * @auth_tok: The passphrase authentication token to use to encrypt the FEK<br />
 * @crypt_stat: The cryptographic context<br />
 *<br />
 * Returns zero on success; non-zero error otherwise<br />
 */<br />
static int<br />
decrypt_passphrase_encrypted_session_key(struct ecryptfs_auth_tok *auth_tok,<br />
					 struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	struct scatterlist dst_sg[2];<br />
	struct scatterlist src_sg[2];<br />
	struct mutex *tfm_mutex;<br />
	struct blkcipher_desc desc = {<br />
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP<br />
	};<br />
	int rc = 0;</p>
<p>	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(<br />
			KERN_DEBUG, &laquo;Session key encryption key (size [%d]):\n&raquo;,<br />
			auth_tok->token.password.session_key_encryption_key_bytes);<br />
		ecryptfs_dump_hex(<br />
			auth_tok->token.password.session_key_encryption_key,<br />
			auth_tok->token.password.session_key_encryption_key_bytes);<br />
	}<br />
	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&#038;desc.tfm, &#038;tfm_mutex,<br />
							crypt_stat->cipher);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to get &raquo;<br />
		       &laquo;tfm and mutex for cipher name [%s]; rc = [%d]\n&raquo;,<br />
		       crypt_stat->cipher, rc);<br />
		goto out;<br />
	}<br />
	rc = virt_to_scatterlist(auth_tok->session_key.encrypted_key,<br />
				 auth_tok->session_key.encrypted_key_size,<br />
				 src_sg, 2);<br />
	if (rc < 1 || rc > 2) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to convert &raquo;<br />
			&laquo;auth_tok->session_key.encrypted_key to scatterlist; &raquo;<br />
			&laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
		       &laquo;auth_tok->session_key.encrypted_key_size = [%d]\n&raquo;, rc,<br />
			auth_tok->session_key.encrypted_key_size);<br />
		goto out;<br />
	}<br />
	auth_tok->session_key.decrypted_key_size =<br />
		auth_tok->session_key.encrypted_key_size;<br />
	rc = virt_to_scatterlist(auth_tok->session_key.decrypted_key,<br />
				 auth_tok->session_key.decrypted_key_size,<br />
				 dst_sg, 2);<br />
	if (rc < 1 || rc > 2) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to convert &raquo;<br />
			&laquo;auth_tok->session_key.decrypted_key to scatterlist; &raquo;<br />
			&laquo;expected rc = 1; got rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	mutex_lock(tfm_mutex);<br />
	rc = crypto_blkcipher_setkey(<br />
		desc.tfm, auth_tok->token.password.session_key_encryption_key,<br />
		crypt_stat->key_size);<br />
	if (unlikely(rc < 0)) {<br />
		mutex_unlock(tfm_mutex);<br />
		printk(KERN_ERR "Error setting key for crypto context\n");<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	rc = crypto_blkcipher_decrypt(&#038;desc, dst_sg, src_sg,<br />
				      auth_tok->session_key.encrypted_key_size);<br />
	mutex_unlock(tfm_mutex);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;Error decrypting; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	auth_tok->session_key.flags |= ECRYPTFS_CONTAINS_DECRYPTED_KEY;<br />
	memcpy(crypt_stat->key, auth_tok->session_key.decrypted_key,<br />
	       auth_tok->session_key.decrypted_key_size);<br />
	crypt_stat->flags |= ECRYPTFS_KEY_VALID;<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;FEK of size [%d]:\n&raquo;,<br />
				crypt_stat->key_size);<br />
		ecryptfs_dump_hex(crypt_stat->key,<br />
				  crypt_stat->key_size);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_parse_packet_set<br />
 * @crypt_stat: The cryptographic context<br />
 * @src: Virtual address of region of memory containing the packets<br />
 * @ecryptfs_dentry: The eCryptfs dentry associated with the packet set<br />
 *<br />
 * Get crypt_stat to have the file&#8217;s session key if the requisite key<br />
 * is available to decrypt the session key.<br />
 *<br />
 * Returns Zero if a valid authentication token was retrieved and<br />
 * processed; negative value for file not encrypted or for error<br />
 * conditions.<br />
 */<br />
int ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,<br />
			      unsigned char *src,<br />
			      struct dentry *ecryptfs_dentry)<br />
{<br />
	size_t i = 0;<br />
	size_t found_auth_tok;<br />
	size_t next_packet_is_auth_tok_packet;<br />
	struct list_head auth_tok_list;<br />
	struct ecryptfs_auth_tok *matching_auth_tok;<br />
	struct ecryptfs_auth_tok *candidate_auth_tok;<br />
	char *candidate_auth_tok_sig;<br />
	size_t packet_size;<br />
	struct ecryptfs_auth_tok *new_auth_tok;<br />
	unsigned char sig_tmp_space[ECRYPTFS_SIG_SIZE];<br />
	struct ecryptfs_auth_tok_list_item *auth_tok_list_item;<br />
	size_t tag_11_contents_size;<br />
	size_t tag_11_packet_size;<br />
	int rc = 0;</p>
<p>	INIT_LIST_HEAD(&#038;auth_tok_list);<br />
	/* Parse the header to find as many packets as we can; these will be<br />
	 * added the our &#038;auth_tok_list */<br />
	next_packet_is_auth_tok_packet = 1;<br />
	while (next_packet_is_auth_tok_packet) {<br />
		size_t max_packet_size = ((PAGE_CACHE_SIZE &#8211; <img src='http://lynyrd.ru/wp-includes/images/smilies/icon_cool.gif' alt='8)' class='wp-smiley' /> &#8211; i);</p>
<p>		switch (src[i]) {<br />
		case ECRYPTFS_TAG_3_PACKET_TYPE:<br />
			rc = parse_tag_3_packet(crypt_stat,<br />
						(unsigned char *)&#038;src[i],<br />
						&#038;auth_tok_list, &#038;new_auth_tok,<br />
						&#038;packet_size, max_packet_size);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_ERR, &laquo;Error parsing &raquo;<br />
						&laquo;tag 3 packet\n&raquo;);<br />
				rc = -EIO;<br />
				goto out_wipe_list;<br />
			}<br />
			i += packet_size;<br />
			rc = parse_tag_11_packet((unsigned char *)&#038;src[i],<br />
						 sig_tmp_space,<br />
						 ECRYPTFS_SIG_SIZE,<br />
						 &#038;tag_11_contents_size,<br />
						 &#038;tag_11_packet_size,<br />
						 max_packet_size);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_ERR, &laquo;No valid &raquo;<br />
						&laquo;(ecryptfs-specific) literal &raquo;<br />
						&laquo;packet containing &raquo;<br />
						&laquo;authentication token &raquo;<br />
						&laquo;signature found after &raquo;<br />
						&laquo;tag 3 packet\n&raquo;);<br />
				rc = -EIO;<br />
				goto out_wipe_list;<br />
			}<br />
			i += tag_11_packet_size;<br />
			if (ECRYPTFS_SIG_SIZE != tag_11_contents_size) {<br />
				ecryptfs_printk(KERN_ERR, &laquo;Expected &raquo;<br />
						&laquo;signature of size [%d]; &raquo;<br />
						&laquo;read size [%d]\n&raquo;,<br />
						ECRYPTFS_SIG_SIZE,<br />
						tag_11_contents_size);<br />
				rc = -EIO;<br />
				goto out_wipe_list;<br />
			}<br />
			ecryptfs_to_hex(new_auth_tok->token.password.signature,<br />
					sig_tmp_space, tag_11_contents_size);<br />
			new_auth_tok->token.password.signature[<br />
				ECRYPTFS_PASSWORD_SIG_SIZE] = &#8216;\0&#8242;;<br />
			crypt_stat->flags |= ECRYPTFS_ENCRYPTED;<br />
			break;<br />
		case ECRYPTFS_TAG_1_PACKET_TYPE:<br />
			rc = parse_tag_1_packet(crypt_stat,<br />
						(unsigned char *)&#038;src[i],<br />
						&#038;auth_tok_list, &#038;new_auth_tok,<br />
						&#038;packet_size, max_packet_size);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_ERR, &laquo;Error parsing &raquo;<br />
						&laquo;tag 1 packet\n&raquo;);<br />
				rc = -EIO;<br />
				goto out_wipe_list;<br />
			}<br />
			i += packet_size;<br />
			crypt_stat->flags |= ECRYPTFS_ENCRYPTED;<br />
			break;<br />
		case ECRYPTFS_TAG_11_PACKET_TYPE:<br />
			ecryptfs_printk(KERN_WARNING, &laquo;Invalid packet set &raquo;<br />
					&laquo;(Tag 11 not allowed by itself)\n&raquo;);<br />
			rc = -EIO;<br />
			goto out_wipe_list;<br />
			break;<br />
		default:<br />
			ecryptfs_printk(KERN_DEBUG, &laquo;No packet at offset &raquo;<br />
					&laquo;[%d] of the file header; hex value of &raquo;<br />
					&laquo;character is [0x%.2x]\n&raquo;, i, src[i]);<br />
			next_packet_is_auth_tok_packet = 0;<br />
		}<br />
	}<br />
	if (list_empty(&#038;auth_tok_list)) {<br />
		printk(KERN_ERR &laquo;The lower file appears to be a non-encrypted &raquo;<br />
		       &laquo;eCryptfs file; this is not supported in this version &raquo;<br />
		       &laquo;of the eCryptfs kernel module\n&raquo;);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	/* auth_tok_list contains the set of authentication tokens<br />
	 * parsed from the metadata. We need to find a matching<br />
	 * authentication token that has the secret component(s)<br />
	 * necessary to decrypt the EFEK in the auth_tok parsed from<br />
	 * the metadata. There may be several potential matches, but<br />
	 * just one will be sufficient to decrypt to get the FEK. */<br />
find_next_matching_auth_tok:<br />
	found_auth_tok = 0;<br />
	list_for_each_entry(auth_tok_list_item, &#038;auth_tok_list, list) {<br />
		candidate_auth_tok = &#038;auth_tok_list_item->auth_tok;<br />
		if (unlikely(ecryptfs_verbosity > 0)) {<br />
			ecryptfs_printk(KERN_DEBUG,<br />
					&laquo;Considering cadidate auth tok:\n&raquo;);<br />
			ecryptfs_dump_auth_tok(candidate_auth_tok);<br />
		}<br />
		rc = ecryptfs_get_auth_tok_sig(&#038;candidate_auth_tok_sig,<br />
					       candidate_auth_tok);<br />
		if (rc) {<br />
			printk(KERN_ERR<br />
			       &laquo;Unrecognized candidate auth tok type: [%d]\n&raquo;,<br />
			       candidate_auth_tok->token_type);<br />
			rc = -EINVAL;<br />
			goto out_wipe_list;<br />
		}<br />
		ecryptfs_find_auth_tok_for_sig(&#038;matching_auth_tok,<br />
					       crypt_stat->mount_crypt_stat,<br />
					       candidate_auth_tok_sig);<br />
		if (matching_auth_tok) {<br />
			found_auth_tok = 1;<br />
			goto found_matching_auth_tok;<br />
		}<br />
	}<br />
	if (!found_auth_tok) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Could not find a usable &raquo;<br />
				&laquo;authentication token\n&raquo;);<br />
		rc = -EIO;<br />
		goto out_wipe_list;<br />
	}<br />
found_matching_auth_tok:<br />
	if (candidate_auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {<br />
		memcpy(&#038;(candidate_auth_tok->token.private_key),<br />
		       &#038;(matching_auth_tok->token.private_key),<br />
		       sizeof(struct ecryptfs_private_key));<br />
		rc = decrypt_pki_encrypted_session_key(candidate_auth_tok,<br />
						       crypt_stat);<br />
	} else if (candidate_auth_tok->token_type == ECRYPTFS_PASSWORD) {<br />
		memcpy(&#038;(candidate_auth_tok->token.password),<br />
		       &#038;(matching_auth_tok->token.password),<br />
		       sizeof(struct ecryptfs_password));<br />
		rc = decrypt_passphrase_encrypted_session_key(<br />
			candidate_auth_tok, crypt_stat);<br />
	}<br />
	if (rc) {<br />
		struct ecryptfs_auth_tok_list_item *auth_tok_list_item_tmp;</p>
<p>		ecryptfs_printk(KERN_WARNING, &laquo;Error decrypting the &raquo;<br />
				&laquo;session key for authentication token with sig &raquo;<br />
				&laquo;[%.*s]; rc = [%d]. Removing auth tok &raquo;<br />
				&laquo;candidate from the list and searching for &raquo;<br />
				&laquo;the next match.\n&raquo;, candidate_auth_tok_sig,<br />
				ECRYPTFS_SIG_SIZE_HEX, rc);<br />
		list_for_each_entry_safe(auth_tok_list_item,<br />
					 auth_tok_list_item_tmp,<br />
					 &#038;auth_tok_list, list) {<br />
			if (candidate_auth_tok<br />
			    == &#038;auth_tok_list_item->auth_tok) {<br />
				list_del(&#038;auth_tok_list_item->list);<br />
				kmem_cache_free(<br />
					ecryptfs_auth_tok_list_item_cache,<br />
					auth_tok_list_item);<br />
				goto find_next_matching_auth_tok;<br />
			}<br />
		}<br />
		BUG();<br />
	}<br />
	rc = ecryptfs_compute_root_iv(crypt_stat);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error computing &raquo;<br />
				&laquo;the root IV\n&raquo;);<br />
		goto out_wipe_list;<br />
	}<br />
	rc = ecryptfs_init_crypt_ctx(crypt_stat);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error initializing crypto &raquo;<br />
				&laquo;context for cipher [%s]; rc = [%d]\n&raquo;,<br />
				crypt_stat->cipher, rc);<br />
	}<br />
out_wipe_list:<br />
	wipe_auth_tok_list(&#038;auth_tok_list);<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
pki_encrypt_session_key(struct ecryptfs_auth_tok *auth_tok,<br />
			struct ecryptfs_crypt_stat *crypt_stat,<br />
			struct ecryptfs_key_record *key_rec)<br />
{<br />
	struct ecryptfs_msg_ctx *msg_ctx = NULL;<br />
	char *payload = NULL;<br />
	size_t payload_len;<br />
	struct ecryptfs_message *msg;<br />
	int rc;</p>
<p>	rc = write_tag_66_packet(auth_tok->token.private_key.signature,<br />
				 ecryptfs_code_for_cipher_string(<br />
					 crypt_stat->cipher,<br />
					 crypt_stat->key_size),<br />
				 crypt_stat, &#038;payload, &#038;payload_len);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 66 packet\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_send_message(payload, payload_len, &#038;msg_ctx);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error sending message to &raquo;<br />
				&laquo;ecryptfsd\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_wait_for_response(msg_ctx, &#038;msg);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Failed to receive tag 67 packet &raquo;<br />
				&laquo;from the user space daemon\n&raquo;);<br />
		rc = -EIO;<br />
		goto out;<br />
	}<br />
	rc = parse_tag_67_packet(key_rec, msg);<br />
	if (rc)<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error parsing tag 67 packet\n&raquo;);<br />
	kfree(msg);<br />
out:<br />
	kfree(payload);<br />
	return rc;<br />
}<br />
/**<br />
 * write_tag_1_packet &#8211; Write an RFC2440-compatible tag 1 (public key) packet<br />
 * @dest: Buffer into which to write the packet<br />
 * @remaining_bytes: Maximum number of bytes that can be writtn<br />
 * @auth_tok: The authentication token used for generating the tag 1 packet<br />
 * @crypt_stat: The cryptographic context<br />
 * @key_rec: The key record struct for the tag 1 packet<br />
 * @packet_size: This function will write the number of bytes that end<br />
 *               up constituting the packet; set to zero on error<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
write_tag_1_packet(char *dest, size_t *remaining_bytes,<br />
		   struct ecryptfs_auth_tok *auth_tok,<br />
		   struct ecryptfs_crypt_stat *crypt_stat,<br />
		   struct ecryptfs_key_record *key_rec, size_t *packet_size)<br />
{<br />
	size_t i;<br />
	size_t encrypted_session_key_valid = 0;<br />
	size_t packet_size_length;<br />
	size_t max_packet_size;<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	ecryptfs_from_hex(key_rec->sig, auth_tok->token.private_key.signature,<br />
			  ECRYPTFS_SIG_SIZE);<br />
	encrypted_session_key_valid = 0;<br />
	for (i = 0; i < crypt_stat->key_size; i++)<br />
		encrypted_session_key_valid |=<br />
			auth_tok->session_key.encrypted_key[i];<br />
	if (encrypted_session_key_valid) {<br />
		memcpy(key_rec->enc_key,<br />
		       auth_tok->session_key.encrypted_key,<br />
		       auth_tok->session_key.encrypted_key_size);<br />
		goto encrypted_session_key_set;<br />
	}<br />
	if (auth_tok->session_key.encrypted_key_size == 0)<br />
		auth_tok->session_key.encrypted_key_size =<br />
			auth_tok->token.private_key.key_size;<br />
	rc = pki_encrypt_session_key(auth_tok, crypt_stat, key_rec);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Failed to encrypt session key via a key &raquo;<br />
		       &laquo;module; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	if (ecryptfs_verbosity > 0) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Encrypted key:\n&raquo;);<br />
		ecryptfs_dump_hex(key_rec->enc_key, key_rec->enc_key_size);<br />
	}<br />
encrypted_session_key_set:<br />
	/* This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 1 */<br />
	max_packet_size = (1                         /* Tag 1 identifier */<br />
			   + 3                       /* Max Tag 1 packet size */<br />
			   + 1                       /* Version */<br />
			   + ECRYPTFS_SIG_SIZE       /* Key identifier */<br />
			   + 1                       /* Cipher identifier */<br />
			   + key_rec->enc_key_size); /* Encrypted key size */<br />
	if (max_packet_size > (*remaining_bytes)) {<br />
		printk(KERN_ERR &laquo;Packet length larger than maximum allowable; &raquo;<br />
		       &laquo;need up to [%td] bytes, but there are only [%td] &raquo;<br />
		       &laquo;available\n&raquo;, max_packet_size, (*remaining_bytes));<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	dest[(*packet_size)++] = ECRYPTFS_TAG_1_PACKET_TYPE;<br />
	rc = ecryptfs_write_packet_length(&#038;dest[(*packet_size)],<br />
					  (max_packet_size &#8211; 4),<br />
					  &#038;packet_size_length);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating tag 1 packet &raquo;<br />
				&laquo;header; cannot generate packet length\n&raquo;);<br />
		goto out;<br />
	}<br />
	(*packet_size) += packet_size_length;<br />
	dest[(*packet_size)++] = 0&#215;03; /* version 3 */<br />
	memcpy(&#038;dest[(*packet_size)], key_rec->sig, ECRYPTFS_SIG_SIZE);<br />
	(*packet_size) += ECRYPTFS_SIG_SIZE;<br />
	dest[(*packet_size)++] = RFC2440_CIPHER_RSA;<br />
	memcpy(&#038;dest[(*packet_size)], key_rec->enc_key,<br />
	       key_rec->enc_key_size);<br />
	(*packet_size) += key_rec->enc_key_size;<br />
out:<br />
	if (rc)<br />
		(*packet_size) = 0;<br />
	else<br />
		(*remaining_bytes) -= (*packet_size);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * write_tag_11_packet<br />
 * @dest: Target into which Tag 11 packet is to be written<br />
 * @remaining_bytes: Maximum packet length<br />
 * @contents: Byte array of contents to copy in<br />
 * @contents_length: Number of bytes in contents<br />
 * @packet_length: Length of the Tag 11 packet written; zero on error<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
write_tag_11_packet(char *dest, size_t *remaining_bytes, char *contents,<br />
		    size_t contents_length, size_t *packet_length)<br />
{<br />
	size_t packet_size_length;<br />
	size_t max_packet_size;<br />
	int rc = 0;</p>
<p>	(*packet_length) = 0;<br />
	/* This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 11 */<br />
	max_packet_size = (1                   /* Tag 11 identifier */<br />
			   + 3                 /* Max Tag 11 packet size */<br />
			   + 1                 /* Binary format specifier */<br />
			   + 1                 /* Filename length */<br />
			   + 8                 /* Filename (&raquo;_CONSOLE&raquo;) */<br />
			   + 4                 /* Modification date */<br />
			   + contents_length); /* Literal data */<br />
	if (max_packet_size > (*remaining_bytes)) {<br />
		printk(KERN_ERR &laquo;Packet length larger than maximum allowable; &raquo;<br />
		       &laquo;need up to [%td] bytes, but there are only [%td] &raquo;<br />
		       &laquo;available\n&raquo;, max_packet_size, (*remaining_bytes));<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	dest[(*packet_length)++] = ECRYPTFS_TAG_11_PACKET_TYPE;<br />
	rc = ecryptfs_write_packet_length(&#038;dest[(*packet_length)],<br />
					  (max_packet_size &#8211; 4),<br />
					  &#038;packet_size_length);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error generating tag 11 packet header; cannot &raquo;<br />
		       &laquo;generate packet length. rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	(*packet_length) += packet_size_length;<br />
	dest[(*packet_length)++] = 0&#215;62; /* binary data format specifier */<br />
	dest[(*packet_length)++] = 8;<br />
	memcpy(&#038;dest[(*packet_length)], &laquo;_CONSOLE&raquo;, 8);<br />
	(*packet_length) += 8;<br />
	memset(&#038;dest[(*packet_length)], 0&#215;00, 4);<br />
	(*packet_length) += 4;<br />
	memcpy(&#038;dest[(*packet_length)], contents, contents_length);<br />
	(*packet_length) += contents_length;<br />
 out:<br />
	if (rc)<br />
		(*packet_length) = 0;<br />
	else<br />
		(*remaining_bytes) -= (*packet_length);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * write_tag_3_packet<br />
 * @dest: Buffer into which to write the packet<br />
 * @remaining_bytes: Maximum number of bytes that can be written<br />
 * @auth_tok: Authentication token<br />
 * @crypt_stat: The cryptographic context<br />
 * @key_rec: encrypted key<br />
 * @packet_size: This function will write the number of bytes that end<br />
 *               up constituting the packet; set to zero on error<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
static int<br />
write_tag_3_packet(char *dest, size_t *remaining_bytes,<br />
		   struct ecryptfs_auth_tok *auth_tok,<br />
		   struct ecryptfs_crypt_stat *crypt_stat,<br />
		   struct ecryptfs_key_record *key_rec, size_t *packet_size)<br />
{<br />
	size_t i;<br />
	size_t encrypted_session_key_valid = 0;<br />
	char session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];<br />
	struct scatterlist dst_sg[2];<br />
	struct scatterlist src_sg[2];<br />
	struct mutex *tfm_mutex = NULL;<br />
	u8 cipher_code;<br />
	size_t packet_size_length;<br />
	size_t max_packet_size;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		crypt_stat->mount_crypt_stat;<br />
	struct blkcipher_desc desc = {<br />
		.tfm = NULL,<br />
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP<br />
	};<br />
	int rc = 0;</p>
<p>	(*packet_size) = 0;<br />
	ecryptfs_from_hex(key_rec->sig, auth_tok->token.password.signature,<br />
			  ECRYPTFS_SIG_SIZE);<br />
	rc = ecryptfs_get_tfm_and_mutex_for_cipher_name(&#038;desc.tfm, &#038;tfm_mutex,<br />
							crypt_stat->cipher);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;Internal error whilst attempting to get &raquo;<br />
		       &laquo;tfm and mutex for cipher name [%s]; rc = [%d]\n&raquo;,<br />
		       crypt_stat->cipher, rc);<br />
		goto out;<br />
	}<br />
	if (mount_crypt_stat->global_default_cipher_key_size == 0) {<br />
		struct blkcipher_alg *alg = crypto_blkcipher_alg(desc.tfm);</p>
<p>		printk(KERN_WARNING &laquo;No key size specified at mount; &raquo;<br />
		       &laquo;defaulting to [%d]\n&raquo;, alg->max_keysize);<br />
		mount_crypt_stat->global_default_cipher_key_size =<br />
			alg->max_keysize;<br />
	}<br />
	if (crypt_stat->key_size == 0)<br />
		crypt_stat->key_size =<br />
			mount_crypt_stat->global_default_cipher_key_size;<br />
	if (auth_tok->session_key.encrypted_key_size == 0)<br />
		auth_tok->session_key.encrypted_key_size =<br />
			crypt_stat->key_size;<br />
	if (crypt_stat->key_size == 24<br />
	    &#038;&#038; strcmp(&raquo;aes&raquo;, crypt_stat->cipher) == 0) {<br />
		memset((crypt_stat->key + 24), 0, 8);<br />
		auth_tok->session_key.encrypted_key_size = 32;<br />
	} else<br />
		auth_tok->session_key.encrypted_key_size = crypt_stat->key_size;<br />
	key_rec->enc_key_size =<br />
		auth_tok->session_key.encrypted_key_size;<br />
	encrypted_session_key_valid = 0;<br />
	for (i = 0; i < auth_tok->session_key.encrypted_key_size; i++)<br />
		encrypted_session_key_valid |=<br />
			auth_tok->session_key.encrypted_key[i];<br />
	if (encrypted_session_key_valid) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;encrypted_session_key_valid != 0; &raquo;<br />
				&laquo;using auth_tok->session_key.encrypted_key, &raquo;<br />
				&laquo;where key_rec->enc_key_size = [%d]\n&raquo;,<br />
				key_rec->enc_key_size);<br />
		memcpy(key_rec->enc_key,<br />
		       auth_tok->session_key.encrypted_key,<br />
		       key_rec->enc_key_size);<br />
		goto encrypted_session_key_set;<br />
	}<br />
	if (auth_tok->token.password.flags &#038;<br />
	    ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Using previously generated &raquo;<br />
				&laquo;session key encryption key of size [%d]\n&raquo;,<br />
				auth_tok->token.password.<br />
				session_key_encryption_key_bytes);<br />
		memcpy(session_key_encryption_key,<br />
		       auth_tok->token.password.session_key_encryption_key,<br />
		       crypt_stat->key_size);<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&laquo;Cached session key &raquo; &laquo;encryption key: \n&raquo;);<br />
		if (ecryptfs_verbosity > 0)<br />
			ecryptfs_dump_hex(session_key_encryption_key, 16);<br />
	}<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Session key encryption key:\n&raquo;);<br />
		ecryptfs_dump_hex(session_key_encryption_key, 16);<br />
	}<br />
	rc = virt_to_scatterlist(crypt_stat->key, key_rec->enc_key_size,<br />
				 src_sg, 2);<br />
	if (rc < 1 || rc > 2) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating scatterlist &raquo;<br />
				&laquo;for crypt_stat session key; expected rc = 1; &raquo;<br />
				&laquo;got rc = [%d]. key_rec->enc_key_size = [%d]\n&raquo;,<br />
				rc, key_rec->enc_key_size);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	rc = virt_to_scatterlist(key_rec->enc_key, key_rec->enc_key_size,<br />
				 dst_sg, 2);<br />
	if (rc < 1 || rc > 2) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error generating scatterlist &raquo;<br />
				&laquo;for crypt_stat encrypted session key; &raquo;<br />
				&laquo;expected rc = 1; got rc = [%d]. &raquo;<br />
				&laquo;key_rec->enc_key_size = [%d]\n&raquo;, rc,<br />
				key_rec->enc_key_size);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	mutex_lock(tfm_mutex);<br />
	rc = crypto_blkcipher_setkey(desc.tfm, session_key_encryption_key,<br />
				     crypt_stat->key_size);<br />
	if (rc < 0) {<br />
		mutex_unlock(tfm_mutex);<br />
		ecryptfs_printk(KERN_ERR, "Error setting key for crypto "<br />
				"context; rc = [%d]\n", rc);<br />
		goto out;<br />
	}<br />
	rc = 0;<br />
	ecryptfs_printk(KERN_DEBUG, "Encrypting [%d] bytes of the key\n",<br />
			crypt_stat->key_size);<br />
	rc = crypto_blkcipher_encrypt(&#038;desc, dst_sg, src_sg,<br />
				      (*key_rec).enc_key_size);<br />
	mutex_unlock(tfm_mutex);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error encrypting; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;This should be the encrypted key:\n&raquo;);<br />
	if (ecryptfs_verbosity > 0) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;EFEK of size [%d]:\n&raquo;,<br />
				key_rec->enc_key_size);<br />
		ecryptfs_dump_hex(key_rec->enc_key,<br />
				  key_rec->enc_key_size);<br />
	}<br />
encrypted_session_key_set:<br />
	/* This format is inspired by OpenPGP; see RFC 2440<br />
	 * packet tag 3 */<br />
	max_packet_size = (1                         /* Tag 3 identifier */<br />
			   + 3                       /* Max Tag 3 packet size */<br />
			   + 1                       /* Version */<br />
			   + 1                       /* Cipher code */<br />
			   + 1                       /* S2K specifier */<br />
			   + 1                       /* Hash identifier */<br />
			   + ECRYPTFS_SALT_SIZE      /* Salt */<br />
			   + 1                       /* Hash iterations */<br />
			   + key_rec->enc_key_size); /* Encrypted key size */<br />
	if (max_packet_size > (*remaining_bytes)) {<br />
		printk(KERN_ERR &laquo;Packet too large; need up to [%td] bytes, but &raquo;<br />
		       &laquo;there are only [%td] available\n&raquo;, max_packet_size,<br />
		       (*remaining_bytes));<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	dest[(*packet_size)++] = ECRYPTFS_TAG_3_PACKET_TYPE;<br />
	/* Chop off the Tag 3 identifier(1) and Tag 3 packet size(3)<br />
	 * to get the number of octets in the actual Tag 3 packet */<br />
	rc = ecryptfs_write_packet_length(&#038;dest[(*packet_size)],<br />
					  (max_packet_size &#8211; 4),<br />
					  &#038;packet_size_length);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error generating tag 3 packet header; cannot &raquo;<br />
		       &laquo;generate packet length. rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	(*packet_size) += packet_size_length;<br />
	dest[(*packet_size)++] = 0&#215;04; /* version 4 */<br />
	/* TODO: Break from RFC2440 so that arbitrary ciphers can be<br />
	 * specified with strings */<br />
	cipher_code = ecryptfs_code_for_cipher_string(crypt_stat->cipher,<br />
						      crypt_stat->key_size);<br />
	if (cipher_code == 0) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Unable to generate code for &raquo;<br />
				&laquo;cipher [%s]\n&raquo;, crypt_stat->cipher);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	dest[(*packet_size)++] = cipher_code;<br />
	dest[(*packet_size)++] = 0&#215;03;	/* S2K */<br />
	dest[(*packet_size)++] = 0&#215;01;	/* MD5 (TODO: parameterize) */<br />
	memcpy(&#038;dest[(*packet_size)], auth_tok->token.password.salt,<br />
	       ECRYPTFS_SALT_SIZE);<br />
	(*packet_size) += ECRYPTFS_SALT_SIZE;	/* salt */<br />
	dest[(*packet_size)++] = 0&#215;60;	/* hash iterations (65536) */<br />
	memcpy(&#038;dest[(*packet_size)], key_rec->enc_key,<br />
	       key_rec->enc_key_size);<br />
	(*packet_size) += key_rec->enc_key_size;<br />
out:<br />
	if (rc)<br />
		(*packet_size) = 0;<br />
	else<br />
		(*remaining_bytes) -= (*packet_size);<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_key_record_cache;</p>
<p>/**<br />
 * ecryptfs_generate_key_packet_set<br />
 * @dest_base: Virtual address from which to write the key record set<br />
 * @crypt_stat: The cryptographic context from which the<br />
 *              authentication tokens will be retrieved<br />
 * @ecryptfs_dentry: The dentry, used to retrieve the mount crypt stat<br />
 *                   for the global parameters<br />
 * @len: The amount written<br />
 * @max: The maximum amount of data allowed to be written<br />
 *<br />
 * Generates a key packet set and writes it to the virtual address<br />
 * passed in.<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
int<br />
ecryptfs_generate_key_packet_set(char *dest_base,<br />
				 struct ecryptfs_crypt_stat *crypt_stat,<br />
				 struct dentry *ecryptfs_dentry, size_t *len,<br />
				 size_t max)<br />
{<br />
	struct ecryptfs_auth_tok *auth_tok;<br />
	struct ecryptfs_global_auth_tok *global_auth_tok;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		&#038;ecryptfs_superblock_to_private(<br />
			ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	size_t written;<br />
	struct ecryptfs_key_record *key_rec;<br />
	struct ecryptfs_key_sig *key_sig;<br />
	int rc = 0;</p>
<p>	(*len) = 0;<br />
	mutex_lock(&#038;crypt_stat->keysig_list_mutex);<br />
	key_rec = kmem_cache_alloc(ecryptfs_key_record_cache, GFP_KERNEL);<br />
	if (!key_rec) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	list_for_each_entry(key_sig, &#038;crypt_stat->keysig_list,<br />
			    crypt_stat_list) {<br />
		memset(key_rec, 0, sizeof(*key_rec));<br />
		rc = ecryptfs_find_global_auth_tok_for_sig(&#038;global_auth_tok,<br />
							   mount_crypt_stat,<br />
							   key_sig->keysig);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error attempting to get the global &raquo;<br />
			       &laquo;auth_tok; rc = [%d]\n&raquo;, rc);<br />
			goto out_free;<br />
		}<br />
		if (global_auth_tok->flags &#038; ECRYPTFS_AUTH_TOK_INVALID) {<br />
			printk(KERN_WARNING<br />
			       &laquo;Skipping invalid auth tok with sig = [%s]\n&raquo;,<br />
			       global_auth_tok->sig);<br />
			continue;<br />
		}<br />
		auth_tok = global_auth_tok->global_auth_tok;<br />
		if (auth_tok->token_type == ECRYPTFS_PASSWORD) {<br />
			rc = write_tag_3_packet((dest_base + (*len)),<br />
						&#038;max, auth_tok,<br />
						crypt_stat, key_rec,<br />
						&#038;written);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_WARNING, &laquo;Error &raquo;<br />
						&laquo;writing tag 3 packet\n&raquo;);<br />
				goto out_free;<br />
			}<br />
			(*len) += written;<br />
			/* Write auth tok signature packet */<br />
			rc = write_tag_11_packet((dest_base + (*len)), &#038;max,<br />
						 key_rec->sig,<br />
						 ECRYPTFS_SIG_SIZE, &#038;written);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_ERR, &laquo;Error writing &raquo;<br />
						&laquo;auth tok signature packet\n&raquo;);<br />
				goto out_free;<br />
			}<br />
			(*len) += written;<br />
		} else if (auth_tok->token_type == ECRYPTFS_PRIVATE_KEY) {<br />
			rc = write_tag_1_packet(dest_base + (*len),<br />
						&#038;max, auth_tok,<br />
						crypt_stat, key_rec, &#038;written);<br />
			if (rc) {<br />
				ecryptfs_printk(KERN_WARNING, &laquo;Error &raquo;<br />
						&laquo;writing tag 1 packet\n&raquo;);<br />
				goto out_free;<br />
			}<br />
			(*len) += written;<br />
		} else {<br />
			ecryptfs_printk(KERN_WARNING, &laquo;Unsupported &raquo;<br />
					&laquo;authentication token type\n&raquo;);<br />
			rc = -EINVAL;<br />
			goto out_free;<br />
		}<br />
	}<br />
	if (likely(max > 0)) {<br />
		dest_base[(*len)] = 0&#215;00;<br />
	} else {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error writing boundary byte\n&raquo;);<br />
		rc = -EIO;<br />
	}<br />
out_free:<br />
	kmem_cache_free(ecryptfs_key_record_cache, key_rec);<br />
out:<br />
	if (rc)<br />
		(*len) = 0;<br />
	mutex_unlock(&#038;crypt_stat->keysig_list_mutex);<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_key_sig_cache;</p>
<p>int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig)<br />
{<br />
	struct ecryptfs_key_sig *new_key_sig;</p>
<p>	new_key_sig = kmem_cache_alloc(ecryptfs_key_sig_cache, GFP_KERNEL);<br />
	if (!new_key_sig) {<br />
		printk(KERN_ERR<br />
		       &laquo;Error allocating from ecryptfs_key_sig_cache\n&raquo;);<br />
		return -ENOMEM;<br />
	}<br />
	memcpy(new_key_sig->keysig, sig, ECRYPTFS_SIG_SIZE_HEX);<br />
	/* Caller must hold keysig_list_mutex */<br />
	list_add(&#038;new_key_sig->crypt_stat_list, &#038;crypt_stat->keysig_list);</p>
<p>	return 0;<br />
}</p>
<p>struct kmem_cache *ecryptfs_global_auth_tok_cache;</p>
<p>int<br />
ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			     char *sig, u32 global_auth_tok_flags)<br />
{<br />
	struct ecryptfs_global_auth_tok *new_auth_tok;<br />
	int rc = 0;</p>
<p>	new_auth_tok = kmem_cache_zalloc(ecryptfs_global_auth_tok_cache,<br />
					GFP_KERNEL);<br />
	if (!new_auth_tok) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;Error allocating from &raquo;<br />
		       &laquo;ecryptfs_global_auth_tok_cache\n&raquo;);<br />
		goto out;<br />
	}<br />
	memcpy(new_auth_tok->sig, sig, ECRYPTFS_SIG_SIZE_HEX);<br />
	new_auth_tok->flags = global_auth_tok_flags;<br />
	new_auth_tok->sig[ECRYPTFS_SIG_SIZE_HEX] = &#8216;\0&#8242;;<br />
	mutex_lock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	list_add(&#038;new_auth_tok->mount_crypt_stat_list,<br />
		 &#038;mount_crypt_stat->global_auth_tok_list);<br />
	mount_crypt_stat->num_global_auth_toks++;<br />
	mutex_unlock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
out:<br />
	return rc;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/keystore-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>inode.c</title>
		<link>http://lynyrd.ru/inode-c-15</link>
		<comments>http://lynyrd.ru/inode-c-15#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:02:52 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1086</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2004 Erez Zadok
 * Copyright (C) 2001-2004 Stony Brook University
 * Copyright (C) 2004-2007 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *              Michael C. Thompsion 
 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1086"></span><br />
 *<br />
 * Copyright (C) 1997-2004 Erez Zadok<br />
 * Copyright (C) 2001-2004 Stony Brook University<br />
 * Copyright (C) 2004-2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *              Michael C. Thompsion <mcthomps@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/file.h>
#include
<linux/vmalloc.h>
#include
<linux/pagemap.h>
#include
<linux/dcache.h>
#include
<linux/namei.h>
#include
<linux/mount.h>
#include
<linux/crypto.h>
#include
<linux/fs_stack.h>
#include <asm/unaligned.h><br />
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>static struct dentry *lock_parent(struct dentry *dentry)<br />
{<br />
	struct dentry *dir;</p>
<p>	dir = dget_parent(dentry);<br />
	mutex_lock_nested(&#038;(dir->d_inode->i_mutex), I_MUTEX_PARENT);<br />
	return dir;<br />
}</p>
<p>static void unlock_dir(struct dentry *dir)<br />
{<br />
	mutex_unlock(&#038;dir->d_inode->i_mutex);<br />
	dput(dir);<br />
}</p>
<p>/**<br />
 * ecryptfs_create_underlying_file<br />
 * @lower_dir_inode: inode of the parent in the lower fs of the new file<br />
 * @dentry: New file&#8217;s dentry<br />
 * @mode: The mode of the new file<br />
 * @nd: nameidata of ecryptfs&#8217; parent&#8217;s dentry &#038; vfsmount<br />
 *<br />
 * Creates the file in the lower file system.<br />
 *<br />
 * Returns zero on success; non-zero on error condition<br />
 */<br />
static int<br />
ecryptfs_create_underlying_file(struct inode *lower_dir_inode,<br />
				struct dentry *dentry, int mode,<br />
				struct nameidata *nd)<br />
{<br />
	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);<br />
	struct dentry *dentry_save;<br />
	struct vfsmount *vfsmount_save;<br />
	int rc;</p>
<p>	dentry_save = nd->path.dentry;<br />
	vfsmount_save = nd->path.mnt;<br />
	nd->path.dentry = lower_dentry;<br />
	nd->path.mnt = lower_mnt;<br />
	rc = vfs_create(lower_dir_inode, lower_dentry, mode, nd);<br />
	nd->path.dentry = dentry_save;<br />
	nd->path.mnt = vfsmount_save;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_do_create<br />
 * @directory_inode: inode of the new file&#8217;s dentry&#8217;s parent in ecryptfs<br />
 * @ecryptfs_dentry: New file&#8217;s dentry in ecryptfs<br />
 * @mode: The mode of the new file<br />
 * @nd: nameidata of ecryptfs&#8217; parent&#8217;s dentry &#038; vfsmount<br />
 *<br />
 * Creates the underlying file and the eCryptfs inode which will link to<br />
 * it. It will also update the eCryptfs directory inode to mimic the<br />
 * stat of the lower directory inode.<br />
 *<br />
 * Returns zero on success; non-zero on error condition<br />
 */<br />
static int<br />
ecryptfs_do_create(struct inode *directory_inode,<br />
		   struct dentry *ecryptfs_dentry, int mode,<br />
		   struct nameidata *nd)<br />
{<br />
	int rc;<br />
	struct dentry *lower_dentry;<br />
	struct dentry *lower_dir_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	if (IS_ERR(lower_dir_dentry)) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error locking directory of &raquo;<br />
				&laquo;dentry\n&raquo;);<br />
		rc = PTR_ERR(lower_dir_dentry);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_create_underlying_file(lower_dir_dentry->d_inode,<br />
					     ecryptfs_dentry, mode, nd);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Failure to create dentry in lower fs; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_lock;<br />
	}<br />
	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,<br />
				directory_inode->i_sb, 0);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Failure in ecryptfs_interpose\n&raquo;);<br />
		goto out_lock;<br />
	}<br />
	fsstack_copy_attr_times(directory_inode, lower_dir_dentry->d_inode);<br />
	fsstack_copy_inode_size(directory_inode, lower_dir_dentry->d_inode);<br />
out_lock:<br />
	unlock_dir(lower_dir_dentry);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * grow_file<br />
 * @ecryptfs_dentry: the eCryptfs dentry<br />
 *<br />
 * This is the code which will grow the file to its correct size.<br />
 */<br />
static int grow_file(struct dentry *ecryptfs_dentry)<br />
{<br />
	struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;<br />
	struct file fake_file;<br />
	struct ecryptfs_file_info tmp_file_info;<br />
	char zero_virt[] = { 0&#215;00 };<br />
	int rc = 0;</p>
<p>	memset(&#038;fake_file, 0, sizeof(fake_file));<br />
	fake_file.f_path.dentry = ecryptfs_dentry;<br />
	memset(&#038;tmp_file_info, 0, sizeof(tmp_file_info));<br />
	ecryptfs_set_file_private(&#038;fake_file, &#038;tmp_file_info);<br />
	ecryptfs_set_file_lower(<br />
		&#038;fake_file,<br />
		ecryptfs_inode_to_private(ecryptfs_inode)->lower_file);<br />
	rc = ecryptfs_write(&#038;fake_file, zero_virt, 0, 1);<br />
	i_size_write(ecryptfs_inode, 0);<br />
	rc = ecryptfs_write_inode_size_to_metadata(ecryptfs_inode);<br />
	ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat.flags |=<br />
		ECRYPTFS_NEW_FILE;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_initialize_file<br />
 *<br />
 * Cause the file to be changed from a basic empty file to an ecryptfs<br />
 * file with a header and first data page.<br />
 *<br />
 * Returns zero on success<br />
 */<br />
static int ecryptfs_initialize_file(struct dentry *ecryptfs_dentry)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
		&#038;ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;<br />
	int rc = 0;</p>
<p>	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;This is a directory\n&raquo;);<br />
		crypt_stat->flags &#038;= ~(ECRYPTFS_ENCRYPTED);<br />
		goto out;<br />
	}<br />
	crypt_stat->flags |= ECRYPTFS_NEW_FILE;<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;Initializing crypto context\n&raquo;);<br />
	rc = ecryptfs_new_file_context(ecryptfs_dentry);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error creating new file &raquo;<br />
				&laquo;context; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {<br />
		rc = ecryptfs_init_persistent_file(ecryptfs_dentry);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to initialize &raquo;<br />
			       &laquo;the persistent file for the dentry with name &raquo;<br />
			       &laquo;[%s]; rc = [%d]\n&raquo;, __func__,<br />
			       ecryptfs_dentry->d_name.name, rc);<br />
			goto out;<br />
		}<br />
	}<br />
	rc = ecryptfs_write_metadata(ecryptfs_dentry);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error writing headers; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	rc = grow_file(ecryptfs_dentry);<br />
	if (rc)<br />
		printk(KERN_ERR &laquo;Error growing file; rc = [%d]\n&raquo;, rc);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_create<br />
 * @dir: The inode of the directory in which to create the file.<br />
 * @dentry: The eCryptfs dentry<br />
 * @mode: The mode of the new file.<br />
 * @nd: nameidata<br />
 *<br />
 * Creates a new file.<br />
 *<br />
 * Returns zero on success; non-zero on error condition<br />
 */<br />
static int<br />
ecryptfs_create(struct inode *directory_inode, struct dentry *ecryptfs_dentry,<br />
		int mode, struct nameidata *nd)<br />
{<br />
	int rc;</p>
<p>	/* ecryptfs_do_create() calls ecryptfs_interpose() */<br />
	rc = ecryptfs_do_create(directory_inode, ecryptfs_dentry, mode, nd);<br />
	if (unlikely(rc)) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Failed to create file in&raquo;<br />
				&laquo;lower filesystem\n&raquo;);<br />
		goto out;<br />
	}<br />
	/* At this point, a file exists on &laquo;disk&raquo;; we need to make sure<br />
	 * that this on disk file is prepared to be an ecryptfs file */<br />
	rc = ecryptfs_initialize_file(ecryptfs_dentry);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_lookup_and_interpose_lower &#8211; Perform a lookup<br />
 */<br />
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,<br />
					struct dentry *lower_dentry,<br />
					struct inode *ecryptfs_dir_inode,<br />
					struct nameidata *ecryptfs_nd)<br />
{<br />
	struct dentry *lower_dir_dentry;<br />
	struct vfsmount *lower_mnt;<br />
	struct inode *lower_inode;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
	char *page_virt = NULL;<br />
	u64 file_size;<br />
	int rc = 0;</p>
<p>	lower_dir_dentry = lower_dentry->d_parent;<br />
	lower_mnt = mntget(ecryptfs_dentry_to_lower_mnt(<br />
				   ecryptfs_dentry->d_parent));<br />
	lower_inode = lower_dentry->d_inode;<br />
	fsstack_copy_attr_atime(ecryptfs_dir_inode, lower_dir_dentry->d_inode);<br />
	BUG_ON(!atomic_read(&#038;lower_dentry->d_count));<br />
	ecryptfs_set_dentry_private(ecryptfs_dentry,<br />
				    kmem_cache_alloc(ecryptfs_dentry_info_cache,<br />
						     GFP_KERNEL));<br />
	if (!ecryptfs_dentry_to_private(ecryptfs_dentry)) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
		       &laquo;to allocate ecryptfs_dentry_info struct\n&raquo;,<br />
			__func__);<br />
		goto out_dput;<br />
	}<br />
	ecryptfs_set_dentry_lower(ecryptfs_dentry, lower_dentry);<br />
	ecryptfs_set_dentry_lower_mnt(ecryptfs_dentry, lower_mnt);<br />
	if (!lower_dentry->d_inode) {<br />
		/* We want to add because we couldn&#8217;t find in lower */<br />
		d_add(ecryptfs_dentry, NULL);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_interpose(lower_dentry, ecryptfs_dentry,<br />
				ecryptfs_dir_inode->i_sb, 1);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error interposing; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out;<br />
	}<br />
	if (S_ISDIR(lower_inode->i_mode))<br />
		goto out;<br />
	if (S_ISLNK(lower_inode->i_mode))<br />
		goto out;<br />
	if (special_file(lower_inode->i_mode))<br />
		goto out;<br />
	if (!ecryptfs_nd)<br />
		goto out;<br />
	/* Released in this function */<br />
	page_virt = kmem_cache_zalloc(ecryptfs_header_cache_2, GFP_USER);<br />
	if (!page_virt) {<br />
		printk(KERN_ERR &laquo;%s: Cannot kmem_cache_zalloc() a page\n&raquo;,<br />
		       __func__);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	if (!ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->lower_file) {<br />
		rc = ecryptfs_init_persistent_file(ecryptfs_dentry);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to initialize &raquo;<br />
			       &laquo;the persistent file for the dentry with name &raquo;<br />
			       &laquo;[%s]; rc = [%d]\n&raquo;, __func__,<br />
			       ecryptfs_dentry->d_name.name, rc);<br />
			goto out_free_kmem;<br />
		}<br />
	}<br />
	crypt_stat = &#038;ecryptfs_inode_to_private(<br />
					ecryptfs_dentry->d_inode)->crypt_stat;<br />
	/* TODO: lock for crypt_stat comparison */<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_POLICY_APPLIED))<br />
			ecryptfs_set_default_sizes(crypt_stat);<br />
	rc = ecryptfs_read_and_validate_header_region(page_virt,<br />
						      ecryptfs_dentry->d_inode);<br />
	if (rc) {<br />
		rc = ecryptfs_read_and_validate_xattr_region(page_virt,<br />
							     ecryptfs_dentry);<br />
		if (rc) {<br />
			rc = 0;<br />
			goto out_free_kmem;<br />
		}<br />
		crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;<br />
	}<br />
	mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
		ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED_VIEW_ENABLED) {<br />
		if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR)<br />
			file_size = (crypt_stat->num_header_bytes_at_front<br />
				     + i_size_read(lower_dentry->d_inode));<br />
		else<br />
			file_size = i_size_read(lower_dentry->d_inode);<br />
	} else {<br />
		file_size = get_unaligned_be64(page_virt);<br />
	}<br />
	i_size_write(ecryptfs_dentry->d_inode, (loff_t)file_size);<br />
out_free_kmem:<br />
	kmem_cache_free(ecryptfs_header_cache_2, page_virt);<br />
	goto out;<br />
out_dput:<br />
	dput(lower_dentry);<br />
	d_drop(ecryptfs_dentry);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_lookup<br />
 * @ecryptfs_dir_inode: The eCryptfs directory inode<br />
 * @ecryptfs_dentry: The eCryptfs dentry that we are looking up<br />
 * @ecryptfs_nd: nameidata; may be NULL<br />
 *<br />
 * Find a file on disk. If the file does not exist, then we&#8217;ll add it to the<br />
 * dentry cache and continue on to read it from the disk.<br />
 */<br />
static struct dentry *ecryptfs_lookup(struct inode *ecryptfs_dir_inode,<br />
				      struct dentry *ecryptfs_dentry,<br />
				      struct nameidata *ecryptfs_nd)<br />
{<br />
	char *encrypted_and_encoded_name = NULL;<br />
	size_t encrypted_and_encoded_name_size;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;<br />
	struct dentry *lower_dir_dentry, *lower_dentry;<br />
	int rc = 0;</p>
<p>	ecryptfs_dentry->d_op = &#038;ecryptfs_dops;<br />
	if ((ecryptfs_dentry->d_name.len == 1<br />
	     &#038;&#038; !strcmp(ecryptfs_dentry->d_name.name, &laquo;.&raquo;))<br />
	    || (ecryptfs_dentry->d_name.len == 2<br />
		&#038;&#038; !strcmp(ecryptfs_dentry->d_name.name, &laquo;..&raquo;))) {<br />
		goto out_d_drop;<br />
	}<br />
	lower_dir_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry->d_parent);<br />
	mutex_lock(&#038;lower_dir_dentry->d_inode->i_mutex);<br />
	lower_dentry = lookup_one_len(ecryptfs_dentry->d_name.name,<br />
				      lower_dir_dentry,<br />
				      ecryptfs_dentry->d_name.len);<br />
	mutex_unlock(&#038;lower_dir_dentry->d_inode->i_mutex);<br />
	if (IS_ERR(lower_dentry)) {<br />
		rc = PTR_ERR(lower_dentry);<br />
		printk(KERN_ERR &laquo;%s: lookup_one_len() returned [%d] on &raquo;<br />
		       &laquo;lower_dentry = [%s]\n&raquo;, __func__, rc,<br />
		       ecryptfs_dentry->d_name.name);<br />
		goto out_d_drop;<br />
	}<br />
	if (lower_dentry->d_inode)<br />
		goto lookup_and_interpose;<br />
	mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
				ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	if (!(mount_crypt_stat<br />
	    &#038;&#038; (mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)))<br />
		goto lookup_and_interpose;<br />
	dput(lower_dentry);<br />
	rc = ecryptfs_encrypt_and_encode_filename(<br />
		&#038;encrypted_and_encoded_name, &#038;encrypted_and_encoded_name_size,<br />
		NULL, mount_crypt_stat, ecryptfs_dentry->d_name.name,<br />
		ecryptfs_dentry->d_name.len);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to encrypt and encode &raquo;<br />
		       &laquo;filename; rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_d_drop;<br />
	}<br />
	mutex_lock(&#038;lower_dir_dentry->d_inode->i_mutex);<br />
	lower_dentry = lookup_one_len(encrypted_and_encoded_name,<br />
				      lower_dir_dentry,<br />
				      encrypted_and_encoded_name_size &#8211; 1);<br />
	mutex_unlock(&#038;lower_dir_dentry->d_inode->i_mutex);<br />
	if (IS_ERR(lower_dentry)) {<br />
		rc = PTR_ERR(lower_dentry);<br />
		printk(KERN_ERR &laquo;%s: lookup_one_len() returned [%d] on &raquo;<br />
		       &laquo;lower_dentry = [%s]\n&raquo;, __func__, rc,<br />
		       encrypted_and_encoded_name);<br />
		goto out_d_drop;<br />
	}<br />
lookup_and_interpose:<br />
	rc = ecryptfs_lookup_and_interpose_lower(ecryptfs_dentry, lower_dentry,<br />
						 ecryptfs_dir_inode,<br />
						 ecryptfs_nd);<br />
	goto out;<br />
out_d_drop:<br />
	d_drop(ecryptfs_dentry);<br />
out:<br />
	kfree(encrypted_and_encoded_name);<br />
	return ERR_PTR(rc);<br />
}</p>
<p>static int ecryptfs_link(struct dentry *old_dentry, struct inode *dir,<br />
			 struct dentry *new_dentry)<br />
{<br />
	struct dentry *lower_old_dentry;<br />
	struct dentry *lower_new_dentry;<br />
	struct dentry *lower_dir_dentry;<br />
	u64 file_size_save;<br />
	int rc;</p>
<p>	file_size_save = i_size_read(old_dentry->d_inode);<br />
	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);<br />
	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);<br />
	dget(lower_old_dentry);<br />
	dget(lower_new_dentry);<br />
	lower_dir_dentry = lock_parent(lower_new_dentry);<br />
	rc = vfs_link(lower_old_dentry, lower_dir_dentry->d_inode,<br />
		      lower_new_dentry);<br />
	if (rc || !lower_new_dentry->d_inode)<br />
		goto out_lock;<br />
	rc = ecryptfs_interpose(lower_new_dentry, new_dentry, dir->i_sb, 0);<br />
	if (rc)<br />
		goto out_lock;<br />
	fsstack_copy_attr_times(dir, lower_new_dentry->d_inode);<br />
	fsstack_copy_inode_size(dir, lower_new_dentry->d_inode);<br />
	old_dentry->d_inode->i_nlink =<br />
		ecryptfs_inode_to_lower(old_dentry->d_inode)->i_nlink;<br />
	i_size_write(new_dentry->d_inode, file_size_save);<br />
out_lock:<br />
	unlock_dir(lower_dir_dentry);<br />
	dput(lower_new_dentry);<br />
	dput(lower_old_dentry);<br />
	d_drop(lower_old_dentry);<br />
	d_drop(new_dentry);<br />
	d_drop(old_dentry);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_unlink(struct inode *dir, struct dentry *dentry)<br />
{<br />
	int rc = 0;<br />
	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	struct inode *lower_dir_inode = ecryptfs_inode_to_lower(dir);<br />
	struct dentry *lower_dir_dentry;</p>
<p>	dget(lower_dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	rc = vfs_unlink(lower_dir_inode, lower_dentry);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error in vfs_unlink; rc = [%d]\n&raquo;, rc);<br />
		goto out_unlock;<br />
	}<br />
	fsstack_copy_attr_times(dir, lower_dir_inode);<br />
	dentry->d_inode->i_nlink =<br />
		ecryptfs_inode_to_lower(dentry->d_inode)->i_nlink;<br />
	dentry->d_inode->i_ctime = dir->i_ctime;<br />
	d_drop(dentry);<br />
out_unlock:<br />
	unlock_dir(lower_dir_dentry);<br />
	dput(lower_dentry);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_symlink(struct inode *dir, struct dentry *dentry,<br />
			    const char *symname)<br />
{<br />
	int rc;<br />
	struct dentry *lower_dentry;<br />
	struct dentry *lower_dir_dentry;<br />
	char *encoded_symname;<br />
	size_t encoded_symlen;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat = NULL;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	dget(lower_dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
		dir->i_sb)->mount_crypt_stat;<br />
	rc = ecryptfs_encrypt_and_encode_filename(&#038;encoded_symname,<br />
						  &#038;encoded_symlen,<br />
						  NULL,<br />
						  mount_crypt_stat, symname,<br />
						  strlen(symname));<br />
	if (rc)<br />
		goto out_lock;<br />
	rc = vfs_symlink(lower_dir_dentry->d_inode, lower_dentry,<br />
			 encoded_symname);<br />
	kfree(encoded_symname);<br />
	if (rc || !lower_dentry->d_inode)<br />
		goto out_lock;<br />
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);<br />
	if (rc)<br />
		goto out_lock;<br />
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);<br />
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);<br />
out_lock:<br />
	unlock_dir(lower_dir_dentry);<br />
	dput(lower_dentry);<br />
	if (!dentry->d_inode)<br />
		d_drop(dentry);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)<br />
{<br />
	int rc;<br />
	struct dentry *lower_dentry;<br />
	struct dentry *lower_dir_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	rc = vfs_mkdir(lower_dir_dentry->d_inode, lower_dentry, mode);<br />
	if (rc || !lower_dentry->d_inode)<br />
		goto out;<br />
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);<br />
	if (rc)<br />
		goto out;<br />
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);<br />
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);<br />
	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;<br />
out:<br />
	unlock_dir(lower_dir_dentry);<br />
	if (!dentry->d_inode)<br />
		d_drop(dentry);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_rmdir(struct inode *dir, struct dentry *dentry)<br />
{<br />
	struct dentry *lower_dentry;<br />
	struct dentry *lower_dir_dentry;<br />
	int rc;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	dget(dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	dget(lower_dentry);<br />
	rc = vfs_rmdir(lower_dir_dentry->d_inode, lower_dentry);<br />
	dput(lower_dentry);<br />
	if (!rc)<br />
		d_delete(lower_dentry);<br />
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);<br />
	dir->i_nlink = lower_dir_dentry->d_inode->i_nlink;<br />
	unlock_dir(lower_dir_dentry);<br />
	if (!rc)<br />
		d_drop(dentry);<br />
	dput(dentry);<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)<br />
{<br />
	int rc;<br />
	struct dentry *lower_dentry;<br />
	struct dentry *lower_dir_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	lower_dir_dentry = lock_parent(lower_dentry);<br />
	rc = vfs_mknod(lower_dir_dentry->d_inode, lower_dentry, mode, dev);<br />
	if (rc || !lower_dentry->d_inode)<br />
		goto out;<br />
	rc = ecryptfs_interpose(lower_dentry, dentry, dir->i_sb, 0);<br />
	if (rc)<br />
		goto out;<br />
	fsstack_copy_attr_times(dir, lower_dir_dentry->d_inode);<br />
	fsstack_copy_inode_size(dir, lower_dir_dentry->d_inode);<br />
out:<br />
	unlock_dir(lower_dir_dentry);<br />
	if (!dentry->d_inode)<br />
		d_drop(dentry);<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_rename(struct inode *old_dir, struct dentry *old_dentry,<br />
		struct inode *new_dir, struct dentry *new_dentry)<br />
{<br />
	int rc;<br />
	struct dentry *lower_old_dentry;<br />
	struct dentry *lower_new_dentry;<br />
	struct dentry *lower_old_dir_dentry;<br />
	struct dentry *lower_new_dir_dentry;</p>
<p>	lower_old_dentry = ecryptfs_dentry_to_lower(old_dentry);<br />
	lower_new_dentry = ecryptfs_dentry_to_lower(new_dentry);<br />
	dget(lower_old_dentry);<br />
	dget(lower_new_dentry);<br />
	lower_old_dir_dentry = dget_parent(lower_old_dentry);<br />
	lower_new_dir_dentry = dget_parent(lower_new_dentry);<br />
	lock_rename(lower_old_dir_dentry, lower_new_dir_dentry);<br />
	rc = vfs_rename(lower_old_dir_dentry->d_inode, lower_old_dentry,<br />
			lower_new_dir_dentry->d_inode, lower_new_dentry);<br />
	if (rc)<br />
		goto out_lock;<br />
	fsstack_copy_attr_all(new_dir, lower_new_dir_dentry->d_inode, NULL);<br />
	if (new_dir != old_dir)<br />
		fsstack_copy_attr_all(old_dir, lower_old_dir_dentry->d_inode, NULL);<br />
out_lock:<br />
	unlock_rename(lower_old_dir_dentry, lower_new_dir_dentry);<br />
	dput(lower_new_dentry->d_parent);<br />
	dput(lower_old_dentry->d_parent);<br />
	dput(lower_new_dentry);<br />
	dput(lower_old_dentry);<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_readlink(struct dentry *dentry, char __user *buf, int bufsiz)<br />
{<br />
	char *lower_buf;<br />
	size_t lower_bufsiz;<br />
	struct dentry *lower_dentry;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;<br />
	char *plaintext_name;<br />
	size_t plaintext_name_size;<br />
	mm_segment_t old_fs;<br />
	int rc;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	if (!lower_dentry->d_inode->i_op->readlink) {<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
						dentry->d_sb)->mount_crypt_stat;<br />
	/*<br />
	 * If the lower filename is encrypted, it will result in a significantly<br />
	 * longer name.  If needed, truncate the name after decode and decrypt.<br />
	 */<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)<br />
		lower_bufsiz = PATH_MAX;<br />
	else<br />
		lower_bufsiz = bufsiz;<br />
	/* Released in this function */<br />
	lower_buf = kmalloc(lower_bufsiz, GFP_KERNEL);<br />
	if (lower_buf == NULL) {<br />
		printk(KERN_ERR &laquo;%s: Out of memory whilst attempting to &raquo;<br />
		       &laquo;kmalloc [%zd] bytes\n&raquo;, __func__, lower_bufsiz);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	old_fs = get_fs();<br />
	set_fs(get_ds());<br />
	rc = lower_dentry->d_inode->i_op->readlink(lower_dentry,<br />
						   (char __user *)lower_buf,<br />
						   lower_bufsiz);<br />
	set_fs(old_fs);<br />
	if (rc >= 0) {<br />
		rc = ecryptfs_decode_and_decrypt_filename(&#038;plaintext_name,<br />
							  &#038;plaintext_name_size,<br />
							  dentry, lower_buf,<br />
							  rc);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to decode and &raquo;<br />
			       &laquo;decrypt filename; rc = [%d]\n&raquo;, __func__,<br />
				rc);<br />
			goto out_free_lower_buf;<br />
		}<br />
		/* Check for bufsiz <= 0 done in sys_readlinkat() */<br />
		rc = copy_to_user(buf, plaintext_name,<br />
				  min((size_t) bufsiz, plaintext_name_size));<br />
		if (rc)<br />
			rc = -EFAULT;<br />
		else<br />
			rc = plaintext_name_size;<br />
		kfree(plaintext_name);<br />
		fsstack_copy_attr_atime(dentry->d_inode, lower_dentry->d_inode);<br />
	}<br />
out_free_lower_buf:<br />
	kfree(lower_buf);<br />
out:<br />
	return rc;<br />
}</p>
<p>static void *ecryptfs_follow_link(struct dentry *dentry, struct nameidata *nd)<br />
{<br />
	char *buf;<br />
	int len = PAGE_SIZE, rc;<br />
	mm_segment_t old_fs;</p>
<p>	/* Released in ecryptfs_put_link(); only release here on error */<br />
	buf = kmalloc(len, GFP_KERNEL);<br />
	if (!buf) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	old_fs = get_fs();<br />
	set_fs(get_ds());<br />
	rc = dentry->d_inode->i_op->readlink(dentry, (char __user *)buf, len);<br />
	set_fs(old_fs);<br />
	if (rc < 0)<br />
		goto out_free;<br />
	else<br />
		buf[rc] = '\0';<br />
	rc = 0;<br />
	nd_set_link(nd, buf);<br />
	goto out;<br />
out_free:<br />
	kfree(buf);<br />
out:<br />
	return ERR_PTR(rc);<br />
}</p>
<p>static void<br />
ecryptfs_put_link(struct dentry *dentry, struct nameidata *nd, void *ptr)<br />
{<br />
	/* Free the char* */<br />
	kfree(nd_get_link(nd));<br />
}</p>
<p>/**<br />
 * upper_size_to_lower_size<br />
 * @crypt_stat: Crypt_stat associated with file<br />
 * @upper_size: Size of the upper file<br />
 *<br />
 * Calculate the required size of the lower file based on the<br />
 * specified size of the upper file. This calculation is based on the<br />
 * number of headers in the underlying file and the extent size.<br />
 *<br />
 * Returns Calculated size of the lower file.<br />
 */<br />
static loff_t<br />
upper_size_to_lower_size(struct ecryptfs_crypt_stat *crypt_stat,<br />
			 loff_t upper_size)<br />
{<br />
	loff_t lower_size;</p>
<p>	lower_size = crypt_stat->num_header_bytes_at_front;<br />
	if (upper_size != 0) {<br />
		loff_t num_extents;</p>
<p>		num_extents = upper_size >> crypt_stat->extent_shift;<br />
		if (upper_size &#038; ~crypt_stat->extent_mask)<br />
			num_extents++;<br />
		lower_size += (num_extents * crypt_stat->extent_size);<br />
	}<br />
	return lower_size;<br />
}</p>
<p>/**<br />
 * ecryptfs_truncate<br />
 * @dentry: The ecryptfs layer dentry<br />
 * @new_length: The length to expand the file to<br />
 *<br />
 * Function to handle truncations modifying the size of the file. Note<br />
 * that the file sizes are interpolated. When expanding, we are simply<br />
 * writing strings of 0&#8217;s out. When truncating, we need to modify the<br />
 * underlying file size according to the page index interpolations.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length)<br />
{<br />
	int rc = 0;<br />
	struct inode *inode = dentry->d_inode;<br />
	struct dentry *lower_dentry;<br />
	struct file fake_ecryptfs_file;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
	loff_t i_size = i_size_read(inode);<br />
	loff_t lower_size_before_truncate;<br />
	loff_t lower_size_after_truncate;</p>
<p>	if (unlikely((new_length == i_size)))<br />
		goto out;<br />
	crypt_stat = &#038;ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;<br />
	/* Set up a fake ecryptfs file, this is used to interface with<br />
	 * the file in the underlying filesystem so that the<br />
	 * truncation has an effect there as well. */<br />
	memset(&#038;fake_ecryptfs_file, 0, sizeof(fake_ecryptfs_file));<br />
	fake_ecryptfs_file.f_path.dentry = dentry;<br />
	/* Released at out_free: label */<br />
	ecryptfs_set_file_private(&#038;fake_ecryptfs_file,<br />
				  kmem_cache_alloc(ecryptfs_file_info_cache,<br />
						   GFP_KERNEL));<br />
	if (unlikely(!ecryptfs_file_to_private(&#038;fake_ecryptfs_file))) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	ecryptfs_set_file_lower(<br />
		&#038;fake_ecryptfs_file,<br />
		ecryptfs_inode_to_private(dentry->d_inode)->lower_file);<br />
	/* Switch on growing or shrinking file */<br />
	if (new_length > i_size) {<br />
		char zero[] = { 0&#215;00 };</p>
<p>		/* Write a single 0 at the last position of the file;<br />
		 * this triggers code that will fill in 0&#8217;s throughout<br />
		 * the intermediate portion of the previous end of the<br />
		 * file and the new and of the file */<br />
		rc = ecryptfs_write(&#038;fake_ecryptfs_file, zero,<br />
				    (new_length &#8211; 1), 1);<br />
	} else { /* new_length < i_size_read(inode) */<br />
		/* We're chopping off all the pages down do the page<br />
		 * in which new_length is located. Fill in the end of<br />
		 * that page from (new_length &#038; ~PAGE_CACHE_MASK) to<br />
		 * PAGE_CACHE_SIZE with zeros. */<br />
		size_t num_zeros = (PAGE_CACHE_SIZE<br />
				    - (new_length &#038; ~PAGE_CACHE_MASK));</p>
<p>		if (!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)) {<br />
			rc = vmtruncate(inode, new_length);<br />
			if (rc)<br />
				goto out_free;<br />
			rc = vmtruncate(lower_dentry->d_inode, new_length);<br />
			goto out_free;<br />
		}<br />
		if (num_zeros) {<br />
			char *zeros_virt;</p>
<p>			zeros_virt = kzalloc(num_zeros, GFP_KERNEL);<br />
			if (!zeros_virt) {<br />
				rc = -ENOMEM;<br />
				goto out_free;<br />
			}<br />
			rc = ecryptfs_write(&#038;fake_ecryptfs_file, zeros_virt,<br />
					    new_length, num_zeros);<br />
			kfree(zeros_virt);<br />
			if (rc) {<br />
				printk(KERN_ERR &laquo;Error attempting to zero out &raquo;<br />
				       &laquo;the remainder of the end page on &raquo;<br />
				       &laquo;reducing truncate; rc = [%d]\n&raquo;, rc);<br />
				goto out_free;<br />
			}<br />
		}<br />
		vmtruncate(inode, new_length);<br />
		rc = ecryptfs_write_inode_size_to_metadata(inode);<br />
		if (rc) {<br />
			printk(KERN_ERR	&laquo;Problem with &raquo;<br />
			       &laquo;ecryptfs_write_inode_size_to_metadata; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, rc);<br />
			goto out_free;<br />
		}<br />
		/* We are reducing the size of the ecryptfs file, and need to<br />
		 * know if we need to reduce the size of the lower file. */<br />
		lower_size_before_truncate =<br />
		    upper_size_to_lower_size(crypt_stat, i_size);<br />
		lower_size_after_truncate =<br />
		    upper_size_to_lower_size(crypt_stat, new_length);<br />
		if (lower_size_after_truncate < lower_size_before_truncate)<br />
			vmtruncate(lower_dentry->d_inode,<br />
				   lower_size_after_truncate);<br />
	}<br />
out_free:<br />
	if (ecryptfs_file_to_private(&#038;fake_ecryptfs_file))<br />
		kmem_cache_free(ecryptfs_file_info_cache,<br />
				ecryptfs_file_to_private(&#038;fake_ecryptfs_file));<br />
out:<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_permission(struct inode *inode, int mask)<br />
{<br />
	return inode_permission(ecryptfs_inode_to_lower(inode), mask);<br />
}</p>
<p>/**<br />
 * ecryptfs_setattr<br />
 * @dentry: dentry handle to the inode to modify<br />
 * @ia: Structure with flags of what to change and values<br />
 *<br />
 * Updates the metadata of an inode. If the update is to the size<br />
 * i.e. truncation, then ecryptfs_truncate will handle the size modification<br />
 * of both the ecryptfs inode and the lower inode.<br />
 *<br />
 * All other metadata changes will be passed right to the lower filesystem,<br />
 * and we will just update our inode to look like the lower.<br />
 */<br />
static int ecryptfs_setattr(struct dentry *dentry, struct iattr *ia)<br />
{<br />
	int rc = 0;<br />
	struct dentry *lower_dentry;<br />
	struct inode *inode;<br />
	struct inode *lower_inode;<br />
	struct ecryptfs_crypt_stat *crypt_stat;</p>
<p>	crypt_stat = &#038;ecryptfs_inode_to_private(dentry->d_inode)->crypt_stat;<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_STRUCT_INITIALIZED))<br />
		ecryptfs_init_crypt_stat(crypt_stat);<br />
	inode = dentry->d_inode;<br />
	lower_inode = ecryptfs_inode_to_lower(inode);<br />
	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	mutex_lock(&#038;crypt_stat->cs_mutex);<br />
	if (S_ISDIR(dentry->d_inode->i_mode))<br />
		crypt_stat->flags &#038;= ~(ECRYPTFS_ENCRYPTED);<br />
	else if (S_ISREG(dentry->d_inode->i_mode)<br />
		 &#038;&#038; (!(crypt_stat->flags &#038; ECRYPTFS_POLICY_APPLIED)<br />
		     || !(crypt_stat->flags &#038; ECRYPTFS_KEY_VALID))) {<br />
		struct ecryptfs_mount_crypt_stat *mount_crypt_stat;</p>
<p>		mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
			dentry->d_sb)->mount_crypt_stat;<br />
		rc = ecryptfs_read_metadata(dentry);<br />
		if (rc) {<br />
			if (!(mount_crypt_stat->flags<br />
			      &#038; ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {<br />
				rc = -EIO;<br />
				printk(KERN_WARNING &laquo;Either the lower file &raquo;<br />
				       &laquo;is not in a valid eCryptfs format, &raquo;<br />
				       &laquo;or the key could not be retrieved. &raquo;<br />
				       &laquo;Plaintext passthrough mode is not &raquo;<br />
				       &laquo;enabled; returning -EIO\n&raquo;);<br />
				mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
				goto out;<br />
			}<br />
			rc = 0;<br />
			crypt_stat->flags &#038;= ~(ECRYPTFS_ENCRYPTED);<br />
		}<br />
	}<br />
	mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
	if (ia->ia_valid &#038; ATTR_SIZE) {<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&laquo;ia->ia_valid = [0x%x] ATTR_SIZE&raquo; &raquo; = [0x%x]\n&raquo;,<br />
				ia->ia_valid, ATTR_SIZE);<br />
		rc = ecryptfs_truncate(dentry, ia->ia_size);<br />
		/* ecryptfs_truncate handles resizing of the lower file */<br />
		ia->ia_valid &#038;= ~ATTR_SIZE;<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;ia->ia_valid = [%x]\n&raquo;,<br />
				ia->ia_valid);<br />
		if (rc < 0)<br />
			goto out;<br />
	}</p>
<p>	/*<br />
	 * mode change is for clearing setuid/setgid bits. Allow lower fs<br />
	 * to interpret this in its own way.<br />
	 */<br />
	if (ia->ia_valid &#038; (ATTR_KILL_SUID | ATTR_KILL_SGID))<br />
		ia->ia_valid &#038;= ~ATTR_MODE;</p>
<p>	mutex_lock(&#038;lower_dentry->d_inode->i_mutex);<br />
	rc = notify_change(lower_dentry, ia);<br />
	mutex_unlock(&#038;lower_dentry->d_inode->i_mutex);<br />
out:<br />
	fsstack_copy_attr_all(inode, lower_inode, NULL);<br />
	return rc;<br />
}</p>
<p>int<br />
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,<br />
		  size_t size, int flags)<br />
{<br />
	int rc = 0;<br />
	struct dentry *lower_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	if (!lower_dentry->d_inode->i_op->setxattr) {<br />
		rc = -ENOSYS;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;lower_dentry->d_inode->i_mutex);<br />
	rc = lower_dentry->d_inode->i_op->setxattr(lower_dentry, name, value,<br />
						   size, flags);<br />
	mutex_unlock(&#038;lower_dentry->d_inode->i_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>ssize_t<br />
ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,<br />
			void *value, size_t size)<br />
{<br />
	int rc = 0;</p>
<p>	if (!lower_dentry->d_inode->i_op->getxattr) {<br />
		rc = -ENOSYS;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;lower_dentry->d_inode->i_mutex);<br />
	rc = lower_dentry->d_inode->i_op->getxattr(lower_dentry, name, value,<br />
						   size);<br />
	mutex_unlock(&#038;lower_dentry->d_inode->i_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>static ssize_t<br />
ecryptfs_getxattr(struct dentry *dentry, const char *name, void *value,<br />
		  size_t size)<br />
{<br />
	return ecryptfs_getxattr_lower(ecryptfs_dentry_to_lower(dentry), name,<br />
				       value, size);<br />
}</p>
<p>static ssize_t<br />
ecryptfs_listxattr(struct dentry *dentry, char *list, size_t size)<br />
{<br />
	int rc = 0;<br />
	struct dentry *lower_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	if (!lower_dentry->d_inode->i_op->listxattr) {<br />
		rc = -ENOSYS;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;lower_dentry->d_inode->i_mutex);<br />
	rc = lower_dentry->d_inode->i_op->listxattr(lower_dentry, list, size);<br />
	mutex_unlock(&#038;lower_dentry->d_inode->i_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_removexattr(struct dentry *dentry, const char *name)<br />
{<br />
	int rc = 0;<br />
	struct dentry *lower_dentry;</p>
<p>	lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	if (!lower_dentry->d_inode->i_op->removexattr) {<br />
		rc = -ENOSYS;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;lower_dentry->d_inode->i_mutex);<br />
	rc = lower_dentry->d_inode->i_op->removexattr(lower_dentry, name);<br />
	mutex_unlock(&#038;lower_dentry->d_inode->i_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode)<br />
{<br />
	if ((ecryptfs_inode_to_lower(inode)<br />
	     == (struct inode *)candidate_lower_inode))<br />
		return 1;<br />
	else<br />
		return 0;<br />
}</p>
<p>int ecryptfs_inode_set(struct inode *inode, void *lower_inode)<br />
{<br />
	ecryptfs_init_inode(inode, (struct inode *)lower_inode);<br />
	return 0;<br />
}</p>
<p>const struct inode_operations ecryptfs_symlink_iops = {<br />
	.readlink = ecryptfs_readlink,<br />
	.follow_link = ecryptfs_follow_link,<br />
	.put_link = ecryptfs_put_link,<br />
	.permission = ecryptfs_permission,<br />
	.setattr = ecryptfs_setattr,<br />
	.setxattr = ecryptfs_setxattr,<br />
	.getxattr = ecryptfs_getxattr,<br />
	.listxattr = ecryptfs_listxattr,<br />
	.removexattr = ecryptfs_removexattr<br />
};</p>
<p>const struct inode_operations ecryptfs_dir_iops = {<br />
	.create = ecryptfs_create,<br />
	.lookup = ecryptfs_lookup,<br />
	.link = ecryptfs_link,<br />
	.unlink = ecryptfs_unlink,<br />
	.symlink = ecryptfs_symlink,<br />
	.mkdir = ecryptfs_mkdir,<br />
	.rmdir = ecryptfs_rmdir,<br />
	.mknod = ecryptfs_mknod,<br />
	.rename = ecryptfs_rename,<br />
	.permission = ecryptfs_permission,<br />
	.setattr = ecryptfs_setattr,<br />
	.setxattr = ecryptfs_setxattr,<br />
	.getxattr = ecryptfs_getxattr,<br />
	.listxattr = ecryptfs_listxattr,<br />
	.removexattr = ecryptfs_removexattr<br />
};</p>
<p>const struct inode_operations ecryptfs_main_iops = {<br />
	.permission = ecryptfs_permission,<br />
	.setattr = ecryptfs_setattr,<br />
	.setxattr = ecryptfs_setxattr,<br />
	.getxattr = ecryptfs_getxattr,<br />
	.listxattr = ecryptfs_listxattr,<br />
	.removexattr = ecryptfs_removexattr<br />
};</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/inode-c-15/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>file.c</title>
		<link>http://lynyrd.ru/file-c-11</link>
		<comments>http://lynyrd.ru/file-c-11#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:02:34 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1084</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2004 Erez Zadok
 * Copyright (C) 2001-2004 Stony Brook University
 * Copyright (C) 2004-2007 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *   		Michael C. Thompson 
 *
 * This program is free software; you can redistribute it ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1084"></span><br />
 *<br />
 * Copyright (C) 1997-2004 Erez Zadok<br />
 * Copyright (C) 2001-2004 Stony Brook University<br />
 * Copyright (C) 2004-2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mhalcrow@us.ibm.com><br />
 *   		Michael C. Thompson <mcthomps@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/file.h>
#include
<linux/poll.h>
#include
<linux/mount.h>
#include
<linux/pagemap.h>
#include
<linux/security.h>
#include
<linux/compat.h>
#include
<linux/fs_stack.h>
#include
<linux/smp_lock.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * ecryptfs_read_update_atime<br />
 *<br />
 * generic_file_read updates the atime of upper layer inode.  But, it<br />
 * doesn&#8217;t give us a chance to update the atime of the lower layer<br />
 * inode.  This function is a wrapper to generic_file_read.  It<br />
 * updates the atime of the lower level inode if generic_file_read<br />
 * returns without any errors. This is to be used only for file reads.<br />
 * The function to be used for directory reads is ecryptfs_read.<br />
 */<br />
static ssize_t ecryptfs_read_update_atime(struct kiocb *iocb,<br />
				const struct iovec *iov,<br />
				unsigned long nr_segs, loff_t pos)<br />
{<br />
	int rc;<br />
	struct dentry *lower_dentry;<br />
	struct vfsmount *lower_vfsmount;<br />
	struct file *file = iocb->ki_filp;</p>
<p>	rc = generic_file_aio_read(iocb, iov, nr_segs, pos);<br />
	/*<br />
	 * Even though this is a async interface, we need to wait<br />
	 * for IO to finish to update atime<br />
	 */<br />
	if (-EIOCBQUEUED == rc)<br />
		rc = wait_on_sync_kiocb(iocb);<br />
	if (rc >= 0) {<br />
		lower_dentry = ecryptfs_dentry_to_lower(file->f_path.dentry);<br />
		lower_vfsmount = ecryptfs_dentry_to_lower_mnt(file->f_path.dentry);<br />
		touch_atime(lower_vfsmount, lower_dentry);<br />
	}<br />
	return rc;<br />
}</p>
<p>struct ecryptfs_getdents_callback {<br />
	void *dirent;<br />
	struct dentry *dentry;<br />
	filldir_t filldir;<br />
	int filldir_called;<br />
	int entries_written;<br />
};</p>
<p>/* Inspired by generic filldir in fs/readdir.c */<br />
static int<br />
ecryptfs_filldir(void *dirent, const char *lower_name, int lower_namelen,<br />
		 loff_t offset, u64 ino, unsigned int d_type)<br />
{<br />
	struct ecryptfs_getdents_callback *buf =<br />
	    (struct ecryptfs_getdents_callback *)dirent;<br />
	size_t name_size;<br />
	char *name;<br />
	int rc;</p>
<p>	buf->filldir_called++;<br />
	rc = ecryptfs_decode_and_decrypt_filename(&#038;name, &#038;name_size,<br />
						  buf->dentry, lower_name,<br />
						  lower_namelen);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error attempting to decode and decrypt &raquo;<br />
		       &laquo;filename [%s]; rc = [%d]\n&raquo;, __func__, lower_name,<br />
		       rc);<br />
		goto out;<br />
	}<br />
	rc = buf->filldir(buf->dirent, name, name_size, offset, ino, d_type);<br />
	kfree(name);<br />
	if (rc >= 0)<br />
		buf->entries_written++;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_readdir<br />
 * @file: The eCryptfs directory file<br />
 * @dirent: Directory entry handle<br />
 * @filldir: The filldir callback function<br />
 */<br />
static int ecryptfs_readdir(struct file *file, void *dirent, filldir_t filldir)<br />
{<br />
	int rc;<br />
	struct file *lower_file;<br />
	struct inode *inode;<br />
	struct ecryptfs_getdents_callback buf;</p>
<p>	lower_file = ecryptfs_file_to_lower(file);<br />
	lower_file->f_pos = file->f_pos;<br />
	inode = file->f_path.dentry->d_inode;<br />
	memset(&#038;buf, 0, sizeof(buf));<br />
	buf.dirent = dirent;<br />
	buf.dentry = file->f_path.dentry;<br />
	buf.filldir = filldir;<br />
	buf.filldir_called = 0;<br />
	buf.entries_written = 0;<br />
	rc = vfs_readdir(lower_file, ecryptfs_filldir, (void *)&#038;buf);<br />
	file->f_pos = lower_file->f_pos;<br />
	if (rc < 0)<br />
		goto out;<br />
	if (buf.filldir_called &#038;&#038; !buf.entries_written)<br />
		goto out;<br />
	if (rc >= 0)<br />
		fsstack_copy_attr_atime(inode,<br />
					lower_file->f_path.dentry->d_inode);<br />
out:<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_file_info_cache;</p>
<p>/**<br />
 * ecryptfs_open<br />
 * @inode: inode speciying file to open<br />
 * @file: Structure to return filled in<br />
 *<br />
 * Opens the file specified by inode.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_open(struct inode *inode, struct file *file)<br />
{<br />
	int rc = 0;<br />
	struct ecryptfs_crypt_stat *crypt_stat = NULL;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;<br />
	struct dentry *ecryptfs_dentry = file->f_path.dentry;<br />
	/* Private value of ecryptfs_dentry allocated in<br />
	 * ecryptfs_lookup() */<br />
	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);<br />
	struct ecryptfs_file_info *file_info;</p>
<p>	mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
		ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	if ((mount_crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED_VIEW_ENABLED)<br />
	    &#038;&#038; ((file->f_flags &#038; O_WRONLY) || (file->f_flags &#038; O_RDWR)<br />
		|| (file->f_flags &#038; O_CREAT) || (file->f_flags &#038; O_TRUNC)<br />
		|| (file->f_flags &#038; O_APPEND))) {<br />
		printk(KERN_WARNING &laquo;Mount has encrypted view enabled; &raquo;<br />
		       &laquo;files may only be read\n&raquo;);<br />
		rc = -EPERM;<br />
		goto out;<br />
	}<br />
	/* Released in ecryptfs_release or end of function if failure */<br />
	file_info = kmem_cache_zalloc(ecryptfs_file_info_cache, GFP_KERNEL);<br />
	ecryptfs_set_file_private(file, file_info);<br />
	if (!file_info) {<br />
		ecryptfs_printk(KERN_ERR,<br />
				&laquo;Error attempting to allocate memory\n&raquo;);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	lower_dentry = ecryptfs_dentry_to_lower(ecryptfs_dentry);<br />
	crypt_stat = &#038;ecryptfs_inode_to_private(inode)->crypt_stat;<br />
	mutex_lock(&#038;crypt_stat->cs_mutex);<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_POLICY_APPLIED)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Setting flags for stat&#8230;\n&raquo;);<br />
		/* Policy code enabled in future release */<br />
		crypt_stat->flags |= (ECRYPTFS_POLICY_APPLIED<br />
				      | ECRYPTFS_ENCRYPTED);<br />
	}<br />
	mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
	if ((ecryptfs_inode_to_private(inode)->lower_file->f_flags &#038; O_RDONLY)<br />
	    &#038;&#038; !(file->f_flags &#038; O_RDONLY)) {<br />
		rc = -EPERM;<br />
		printk(KERN_WARNING &laquo;%s: Lower persistent file is RO; eCryptfs &raquo;<br />
		       &laquo;file must hence be opened RO\n&raquo;, __func__);<br />
		goto out;<br />
	}<br />
	if (!ecryptfs_inode_to_private(inode)->lower_file) {<br />
		rc = ecryptfs_init_persistent_file(ecryptfs_dentry);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to initialize &raquo;<br />
			       &laquo;the persistent file for the dentry with name &raquo;<br />
			       &laquo;[%s]; rc = [%d]\n&raquo;, __func__,<br />
			       ecryptfs_dentry->d_name.name, rc);<br />
			goto out;<br />
		}<br />
	}<br />
	ecryptfs_set_file_lower(<br />
		file, ecryptfs_inode_to_private(inode)->lower_file);<br />
	if (S_ISDIR(ecryptfs_dentry->d_inode->i_mode)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;This is a directory\n&raquo;);<br />
		mutex_lock(&#038;crypt_stat->cs_mutex);<br />
		crypt_stat->flags &#038;= ~(ECRYPTFS_ENCRYPTED);<br />
		mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
		rc = 0;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;crypt_stat->cs_mutex);<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_POLICY_APPLIED)<br />
	    || !(crypt_stat->flags &#038; ECRYPTFS_KEY_VALID)) {<br />
		rc = ecryptfs_read_metadata(ecryptfs_dentry);<br />
		if (rc) {<br />
			ecryptfs_printk(KERN_DEBUG,<br />
					&laquo;Valid headers not found\n&raquo;);<br />
			if (!(mount_crypt_stat->flags<br />
			      &#038; ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED)) {<br />
				rc = -EIO;<br />
				printk(KERN_WARNING &laquo;Either the lower file &raquo;<br />
				       &laquo;is not in a valid eCryptfs format, &raquo;<br />
				       &laquo;or the key could not be retrieved. &raquo;<br />
				       &laquo;Plaintext passthrough mode is not &raquo;<br />
				       &laquo;enabled; returning -EIO\n&raquo;);<br />
				mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
				goto out_free;<br />
			}<br />
			rc = 0;<br />
			crypt_stat->flags &#038;= ~(ECRYPTFS_ENCRYPTED);<br />
			mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
			goto out;<br />
		}<br />
	}<br />
	mutex_unlock(&#038;crypt_stat->cs_mutex);<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;inode w/ addr = [0x%p], i_ino = [0x%.16x] &raquo;<br />
			&laquo;size: [0x%.16x]\n&raquo;, inode, inode->i_ino,<br />
			i_size_read(inode));<br />
	goto out;<br />
out_free:<br />
	kmem_cache_free(ecryptfs_file_info_cache,<br />
			ecryptfs_file_to_private(file));<br />
out:<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_flush(struct file *file, fl_owner_t td)<br />
{<br />
	int rc = 0;<br />
	struct file *lower_file = NULL;</p>
<p>	lower_file = ecryptfs_file_to_lower(file);<br />
	if (lower_file->f_op &#038;&#038; lower_file->f_op->flush)<br />
		rc = lower_file->f_op->flush(lower_file, td);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_release(struct inode *inode, struct file *file)<br />
{<br />
	kmem_cache_free(ecryptfs_file_info_cache,<br />
			ecryptfs_file_to_private(file));<br />
	return 0;<br />
}</p>
<p>static int<br />
ecryptfs_fsync(struct file *file, struct dentry *dentry, int datasync)<br />
{<br />
	return vfs_fsync(ecryptfs_file_to_lower(file),<br />
			 ecryptfs_dentry_to_lower(dentry),<br />
			 datasync);<br />
}</p>
<p>static int ecryptfs_fasync(int fd, struct file *file, int flag)<br />
{<br />
	int rc = 0;<br />
	struct file *lower_file = NULL;</p>
<p>	lock_kernel();<br />
	lower_file = ecryptfs_file_to_lower(file);<br />
	if (lower_file->f_op &#038;&#038; lower_file->f_op->fasync)<br />
		rc = lower_file->f_op->fasync(fd, lower_file, flag);<br />
	unlock_kernel();<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_ioctl(struct inode *inode, struct file *file,<br />
			  unsigned int cmd, unsigned long arg);</p>
<p>const struct file_operations ecryptfs_dir_fops = {<br />
	.readdir = ecryptfs_readdir,<br />
	.ioctl = ecryptfs_ioctl,<br />
	.mmap = generic_file_mmap,<br />
	.open = ecryptfs_open,<br />
	.flush = ecryptfs_flush,<br />
	.release = ecryptfs_release,<br />
	.fsync = ecryptfs_fsync,<br />
	.fasync = ecryptfs_fasync,<br />
	.splice_read = generic_file_splice_read,<br />
};</p>
<p>const struct file_operations ecryptfs_main_fops = {<br />
	.llseek = generic_file_llseek,<br />
	.read = do_sync_read,<br />
	.aio_read = ecryptfs_read_update_atime,<br />
	.write = do_sync_write,<br />
	.aio_write = generic_file_aio_write,<br />
	.readdir = ecryptfs_readdir,<br />
	.ioctl = ecryptfs_ioctl,<br />
	.mmap = generic_file_mmap,<br />
	.open = ecryptfs_open,<br />
	.flush = ecryptfs_flush,<br />
	.release = ecryptfs_release,<br />
	.fsync = ecryptfs_fsync,<br />
	.fasync = ecryptfs_fasync,<br />
	.splice_read = generic_file_splice_read,<br />
};</p>
<p>static int<br />
ecryptfs_ioctl(struct inode *inode, struct file *file, unsigned int cmd,<br />
	       unsigned long arg)<br />
{<br />
	int rc = 0;<br />
	struct file *lower_file = NULL;</p>
<p>	if (ecryptfs_file_to_private(file))<br />
		lower_file = ecryptfs_file_to_lower(file);<br />
	if (lower_file &#038;&#038; lower_file->f_op &#038;&#038; lower_file->f_op->ioctl)<br />
		rc = lower_file->f_op->ioctl(ecryptfs_inode_to_lower(inode),<br />
					     lower_file, cmd, arg);<br />
	else<br />
		rc = -ENOTTY;<br />
	return rc;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/file-c-11/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>ecryptfs_kernel.h</title>
		<link>http://lynyrd.ru/ecryptfs_kernel-h</link>
		<comments>http://lynyrd.ru/ecryptfs_kernel-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:02:15 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1082</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 * Kernel declarations.
 *
 * Copyright (C) 1997-2003 Erez Zadok
 * Copyright (C) 2001-2003 Stony Brook University
 * Copyright (C) 2004-2008 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *              Trevor ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1082"></span><br />
 * Kernel declarations.<br />
 *<br />
 * Copyright (C) 1997-2003 Erez Zadok<br />
 * Copyright (C) 2001-2003 Stony Brook University<br />
 * Copyright (C) 2004-2008 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *              Trevor S. Highland<br />
<trevor.highland@gmail.com>
 *              Tyler Hicks <tyhicks@ou.edu><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#ifndef ECRYPTFS_KERNEL_H<br />
#define ECRYPTFS_KERNEL_H</p>
<p>#include <keys/user-type.h><br />
#include
<linux/fs.h>
#include
<linux/fs_stack.h>
#include
<linux/namei.h>
#include
<linux/scatterlist.h>
#include
<linux/hash.h>
#include
<linux/nsproxy.h>
<p>/* Version verification for shared data structures w/ userspace */<br />
#define ECRYPTFS_VERSION_MAJOR 0&#215;00<br />
#define ECRYPTFS_VERSION_MINOR 0&#215;04<br />
#define ECRYPTFS_SUPPORTED_FILE_VERSION 0&#215;03<br />
/* These flags indicate which features are supported by the kernel<br />
 * module; userspace tools such as the mount helper read<br />
 * ECRYPTFS_VERSIONING_MASK from a sysfs handle in order to determine<br />
 * how to behave. */<br />
#define ECRYPTFS_VERSIONING_PASSPHRASE            0&#215;00000001<br />
#define ECRYPTFS_VERSIONING_PUBKEY                0&#215;00000002<br />
#define ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH 0&#215;00000004<br />
#define ECRYPTFS_VERSIONING_POLICY                0&#215;00000008<br />
#define ECRYPTFS_VERSIONING_XATTR                 0&#215;00000010<br />
#define ECRYPTFS_VERSIONING_MULTKEY               0&#215;00000020<br />
#define ECRYPTFS_VERSIONING_DEVMISC               0&#215;00000040<br />
#define ECRYPTFS_VERSIONING_HMAC                  0&#215;00000080<br />
#define ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION   0&#215;00000100<br />
#define ECRYPTFS_VERSIONING_GCM                   0&#215;00000200<br />
#define ECRYPTFS_VERSIONING_MASK (ECRYPTFS_VERSIONING_PASSPHRASE \<br />
				  | ECRYPTFS_VERSIONING_PLAINTEXT_PASSTHROUGH \<br />
				  | ECRYPTFS_VERSIONING_PUBKEY \<br />
				  | ECRYPTFS_VERSIONING_XATTR \<br />
				  | ECRYPTFS_VERSIONING_MULTKEY \<br />
				  | ECRYPTFS_VERSIONING_DEVMISC \<br />
				  | ECRYPTFS_VERSIONING_FILENAME_ENCRYPTION)<br />
#define ECRYPTFS_MAX_PASSWORD_LENGTH 64<br />
#define ECRYPTFS_MAX_PASSPHRASE_BYTES ECRYPTFS_MAX_PASSWORD_LENGTH<br />
#define ECRYPTFS_SALT_SIZE 8<br />
#define ECRYPTFS_SALT_SIZE_HEX (ECRYPTFS_SALT_SIZE*2)<br />
/* The original signature size is only for what is stored on disk; all<br />
 * in-memory representations are expanded hex, so it better adapted to<br />
 * be passed around or referenced on the command line */<br />
#define ECRYPTFS_SIG_SIZE 8<br />
#define ECRYPTFS_SIG_SIZE_HEX (ECRYPTFS_SIG_SIZE*2)<br />
#define ECRYPTFS_PASSWORD_SIG_SIZE ECRYPTFS_SIG_SIZE_HEX<br />
#define ECRYPTFS_MAX_KEY_BYTES 64<br />
#define ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES 512<br />
#define ECRYPTFS_DEFAULT_IV_BYTES 16<br />
#define ECRYPTFS_FILE_VERSION 0&#215;03<br />
#define ECRYPTFS_DEFAULT_EXTENT_SIZE 4096<br />
#define ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE 8192<br />
#define ECRYPTFS_DEFAULT_MSG_CTX_ELEMS 32<br />
#define ECRYPTFS_DEFAULT_SEND_TIMEOUT HZ<br />
#define ECRYPTFS_MAX_MSG_CTX_TTL (HZ*3)<br />
#define ECRYPTFS_MAX_PKI_NAME_BYTES 16<br />
#define ECRYPTFS_DEFAULT_NUM_USERS 4<br />
#define ECRYPTFS_MAX_NUM_USERS 32768<br />
#define ECRYPTFS_XATTR_NAME &laquo;user.ecryptfs&raquo;</p>
<p>#define RFC2440_CIPHER_DES3_EDE 0&#215;02<br />
#define RFC2440_CIPHER_CAST_5 0&#215;03<br />
#define RFC2440_CIPHER_BLOWFISH 0&#215;04<br />
#define RFC2440_CIPHER_AES_128 0&#215;07<br />
#define RFC2440_CIPHER_AES_192 0&#215;08<br />
#define RFC2440_CIPHER_AES_256 0&#215;09<br />
#define RFC2440_CIPHER_TWOFISH 0&#215;0a<br />
#define RFC2440_CIPHER_CAST_6 0&#215;0b</p>
<p>#define RFC2440_CIPHER_RSA 0&#215;01</p>
<p>/**<br />
 * For convenience, we may need to pass around the encrypted session<br />
 * key between kernel and userspace because the authentication token<br />
 * may not be extractable.  For example, the TPM may not release the<br />
 * private key, instead requiring the encrypted data and returning the<br />
 * decrypted data.<br />
 */<br />
struct ecryptfs_session_key {<br />
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT 0&#215;00000001<br />
#define ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT 0&#215;00000002<br />
#define ECRYPTFS_CONTAINS_DECRYPTED_KEY 0&#215;00000004<br />
#define ECRYPTFS_CONTAINS_ENCRYPTED_KEY 0&#215;00000008<br />
	u32 flags;<br />
	u32 encrypted_key_size;<br />
	u32 decrypted_key_size;<br />
	u8 encrypted_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];<br />
	u8 decrypted_key[ECRYPTFS_MAX_KEY_BYTES];<br />
};</p>
<p>struct ecryptfs_password {<br />
	u32 password_bytes;<br />
	s32 hash_algo;<br />
	u32 hash_iterations;<br />
	u32 session_key_encryption_key_bytes;<br />
#define ECRYPTFS_PERSISTENT_PASSWORD 0&#215;01<br />
#define ECRYPTFS_SESSION_KEY_ENCRYPTION_KEY_SET 0&#215;02<br />
	u32 flags;<br />
	/* Iterated-hash concatenation of salt and passphrase */<br />
	u8 session_key_encryption_key[ECRYPTFS_MAX_KEY_BYTES];<br />
	u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];<br />
	/* Always in expanded hex */<br />
	u8 salt[ECRYPTFS_SALT_SIZE];<br />
};</p>
<p>enum ecryptfs_token_types {ECRYPTFS_PASSWORD, ECRYPTFS_PRIVATE_KEY};</p>
<p>struct ecryptfs_private_key {<br />
	u32 key_size;<br />
	u32 data_len;<br />
	u8 signature[ECRYPTFS_PASSWORD_SIG_SIZE + 1];<br />
	char pki_type[ECRYPTFS_MAX_PKI_NAME_BYTES + 1];<br />
	u8 data[];<br />
};</p>
<p>/* May be a password or a private key */<br />
struct ecryptfs_auth_tok {<br />
	u16 version; /* 8-bit major and 8-bit minor */<br />
	u16 token_type;<br />
#define ECRYPTFS_ENCRYPT_ONLY 0&#215;00000001<br />
	u32 flags;<br />
	struct ecryptfs_session_key session_key;<br />
	u8 reserved[32];<br />
	union {<br />
		struct ecryptfs_password password;<br />
		struct ecryptfs_private_key private_key;<br />
	} token;<br />
} __attribute__ ((packed));</p>
<p>void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok);<br />
extern void ecryptfs_to_hex(char *dst, char *src, size_t src_size);<br />
extern void ecryptfs_from_hex(char *dst, char *src, int dst_size);</p>
<p>struct ecryptfs_key_record {<br />
	unsigned char type;<br />
	size_t enc_key_size;<br />
	unsigned char sig[ECRYPTFS_SIG_SIZE];<br />
	unsigned char enc_key[ECRYPTFS_MAX_ENCRYPTED_KEY_BYTES];<br />
};</p>
<p>struct ecryptfs_auth_tok_list {<br />
	struct ecryptfs_auth_tok *auth_tok;<br />
	struct list_head list;<br />
};</p>
<p>struct ecryptfs_crypt_stat;<br />
struct ecryptfs_mount_crypt_stat;</p>
<p>struct ecryptfs_page_crypt_context {<br />
	struct page *page;<br />
#define ECRYPTFS_PREPARE_COMMIT_MODE 0<br />
#define ECRYPTFS_WRITEPAGE_MODE      1<br />
	unsigned int mode;<br />
	union {<br />
		struct file *lower_file;<br />
		struct writeback_control *wbc;<br />
	} param;<br />
};</p>
<p>static inline struct ecryptfs_auth_tok *<br />
ecryptfs_get_key_payload_data(struct key *key)<br />
{<br />
	return (struct ecryptfs_auth_tok *)<br />
		(((struct user_key_payload*)key->payload.data)->data);<br />
}</p>
<p>#define ECRYPTFS_SUPER_MAGIC 0xf15f<br />
#define ECRYPTFS_MAX_KEYSET_SIZE 1024<br />
#define ECRYPTFS_MAX_CIPHER_NAME_SIZE 32<br />
#define ECRYPTFS_MAX_NUM_ENC_KEYS 64<br />
#define ECRYPTFS_MAX_IV_BYTES 16	/* 128 bits */<br />
#define ECRYPTFS_SALT_BYTES 2<br />
#define MAGIC_ECRYPTFS_MARKER 0&#215;3c81b7f5<br />
#define MAGIC_ECRYPTFS_MARKER_SIZE_BYTES 8	/* 4*2 */<br />
#define ECRYPTFS_FILE_SIZE_BYTES (sizeof(u64))<br />
#define ECRYPTFS_DEFAULT_CIPHER &laquo;aes&raquo;<br />
#define ECRYPTFS_DEFAULT_KEY_BYTES 16<br />
#define ECRYPTFS_DEFAULT_HASH &laquo;md5&#8243;<br />
#define ECRYPTFS_TAG_70_DIGEST ECRYPTFS_DEFAULT_HASH<br />
#define ECRYPTFS_TAG_1_PACKET_TYPE 0&#215;01<br />
#define ECRYPTFS_TAG_3_PACKET_TYPE 0&#215;8C<br />
#define ECRYPTFS_TAG_11_PACKET_TYPE 0xED<br />
#define ECRYPTFS_TAG_64_PACKET_TYPE 0&#215;40<br />
#define ECRYPTFS_TAG_65_PACKET_TYPE 0&#215;41<br />
#define ECRYPTFS_TAG_66_PACKET_TYPE 0&#215;42<br />
#define ECRYPTFS_TAG_67_PACKET_TYPE 0&#215;43<br />
#define ECRYPTFS_TAG_70_PACKET_TYPE 0&#215;46 /* FNEK-encrypted filename<br />
					  * as dentry name */<br />
#define ECRYPTFS_TAG_71_PACKET_TYPE 0&#215;47 /* FNEK-encrypted filename in<br />
					  * metadata */<br />
#define ECRYPTFS_TAG_72_PACKET_TYPE 0&#215;48 /* FEK-encrypted filename as<br />
					  * dentry name */<br />
#define ECRYPTFS_TAG_73_PACKET_TYPE 0&#215;49 /* FEK-encrypted filename as<br />
					  * metadata */<br />
/* Constraint: ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES >=<br />
 * ECRYPTFS_MAX_IV_BYTES */<br />
#define ECRYPTFS_FILENAME_MIN_RANDOM_PREPEND_BYTES 16<br />
#define ECRYPTFS_NON_NULL 0&#215;42 /* A reasonable substitute for NULL */<br />
#define MD5_DIGEST_SIZE 16<br />
#define ECRYPTFS_TAG_70_DIGEST_SIZE MD5_DIGEST_SIZE<br />
#define ECRYPTFS_FEK_ENCRYPTED_FILENAME_PREFIX &laquo;ECRYPTFS_FEK_ENCRYPTED.&raquo;<br />
#define ECRYPTFS_FEK_ENCRYPTED_FILENAME_PREFIX_SIZE 23<br />
#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX &laquo;ECRYPTFS_FNEK_ENCRYPTED.&raquo;<br />
#define ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE 24<br />
#define ECRYPTFS_ENCRYPTED_DENTRY_NAME_LEN (18 + 1 + 4 + 1 + 32)</p>
<p>struct ecryptfs_key_sig {<br />
	struct list_head crypt_stat_list;<br />
	char keysig[ECRYPTFS_SIG_SIZE_HEX];<br />
};</p>
<p>struct ecryptfs_filename {<br />
	struct list_head crypt_stat_list;<br />
#define ECRYPTFS_FILENAME_CONTAINS_DECRYPTED 0&#215;00000001<br />
	u32 flags;<br />
	u32 seq_no;<br />
	char *filename;<br />
	char *encrypted_filename;<br />
	size_t filename_size;<br />
	size_t encrypted_filename_size;<br />
	char fnek_sig[ECRYPTFS_SIG_SIZE_HEX];<br />
	char dentry_name[ECRYPTFS_ENCRYPTED_DENTRY_NAME_LEN + 1];<br />
};</p>
<p>/**<br />
 * This is the primary struct associated with each encrypted file.<br />
 *<br />
 * TODO: cache align/pack?<br />
 */<br />
struct ecryptfs_crypt_stat {<br />
#define ECRYPTFS_STRUCT_INITIALIZED   0&#215;00000001<br />
#define ECRYPTFS_POLICY_APPLIED       0&#215;00000002<br />
#define ECRYPTFS_NEW_FILE             0&#215;00000004<br />
#define ECRYPTFS_ENCRYPTED            0&#215;00000008<br />
#define ECRYPTFS_SECURITY_WARNING     0&#215;00000010<br />
#define ECRYPTFS_ENABLE_HMAC          0&#215;00000020<br />
#define ECRYPTFS_ENCRYPT_IV_PAGES     0&#215;00000040<br />
#define ECRYPTFS_KEY_VALID            0&#215;00000080<br />
#define ECRYPTFS_METADATA_IN_XATTR    0&#215;00000100<br />
#define ECRYPTFS_VIEW_AS_ENCRYPTED    0&#215;00000200<br />
#define ECRYPTFS_KEY_SET              0&#215;00000400<br />
#define ECRYPTFS_ENCRYPT_FILENAMES    0&#215;00000800<br />
#define ECRYPTFS_ENCFN_USE_MOUNT_FNEK 0&#215;00001000<br />
#define ECRYPTFS_ENCFN_USE_FEK        0&#215;00002000<br />
#define ECRYPTFS_UNLINK_SIGS	      0&#215;00004000<br />
	u32 flags;<br />
	unsigned int file_version;<br />
	size_t iv_bytes;<br />
	size_t num_header_bytes_at_front;<br />
	size_t extent_size; /* Data extent size; default is 4096 */<br />
	size_t key_size;<br />
	size_t extent_shift;<br />
	unsigned int extent_mask;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat;<br />
	struct crypto_blkcipher *tfm;<br />
	struct crypto_hash *hash_tfm; /* Crypto context for generating<br />
				       * the initialization vectors */<br />
	unsigned char cipher[ECRYPTFS_MAX_CIPHER_NAME_SIZE];<br />
	unsigned char key[ECRYPTFS_MAX_KEY_BYTES];<br />
	unsigned char root_iv[ECRYPTFS_MAX_IV_BYTES];<br />
	struct list_head keysig_list;<br />
	struct mutex keysig_list_mutex;<br />
	struct mutex cs_tfm_mutex;<br />
	struct mutex cs_hash_tfm_mutex;<br />
	struct mutex cs_mutex;<br />
};</p>
<p>/* inode private data. */<br />
struct ecryptfs_inode_info {<br />
	struct inode vfs_inode;<br />
	struct inode *wii_inode;<br />
	struct file *lower_file;<br />
	struct mutex lower_file_mutex;<br />
	struct ecryptfs_crypt_stat crypt_stat;<br />
};</p>
<p>/* dentry private data. Each dentry must keep track of a lower<br />
 * vfsmount too. */<br />
struct ecryptfs_dentry_info {<br />
	struct path lower_path;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
};</p>
<p>/**<br />
 * ecryptfs_global_auth_tok &#8211; A key used to encrypt all new files under the mountpoint<br />
 * @flags: Status flags<br />
 * @mount_crypt_stat_list: These auth_toks hang off the mount-wide<br />
 *                         cryptographic context. Every time a new<br />
 *                         inode comes into existence, eCryptfs copies<br />
 *                         the auth_toks on that list to the set of<br />
 *                         auth_toks on the inode&#8217;s crypt_stat<br />
 * @global_auth_tok_key: The key from the user&#8217;s keyring for the sig<br />
 * @global_auth_tok: The key contents<br />
 * @sig: The key identifier<br />
 *<br />
 * ecryptfs_global_auth_tok structs refer to authentication token keys<br />
 * in the user keyring that apply to newly created files. A list of<br />
 * these objects hangs off of the mount_crypt_stat struct for any<br />
 * given eCryptfs mount. This struct maintains a reference to both the<br />
 * key contents and the key itself so that the key can be put on<br />
 * unmount.<br />
 */<br />
struct ecryptfs_global_auth_tok {<br />
#define ECRYPTFS_AUTH_TOK_INVALID 0&#215;00000001<br />
#define ECRYPTFS_AUTH_TOK_FNEK    0&#215;00000002<br />
	u32 flags;<br />
	struct list_head mount_crypt_stat_list;<br />
	struct key *global_auth_tok_key;<br />
	struct ecryptfs_auth_tok *global_auth_tok;<br />
	unsigned char sig[ECRYPTFS_SIG_SIZE_HEX + 1];<br />
};</p>
<p>/**<br />
 * ecryptfs_key_tfm &#8211; Persistent key tfm<br />
 * @key_tfm: crypto API handle to the key<br />
 * @key_size: Key size in bytes<br />
 * @key_tfm_mutex: Mutex to ensure only one operation in eCryptfs is<br />
 *                 using the persistent TFM at any point in time<br />
 * @key_tfm_list: Handle to hang this off the module-wide TFM list<br />
 * @cipher_name: String name for the cipher for this TFM<br />
 *<br />
 * Typically, eCryptfs will use the same ciphers repeatedly throughout<br />
 * the course of its operations. In order to avoid unnecessarily<br />
 * destroying and initializing the same cipher repeatedly, eCryptfs<br />
 * keeps a list of crypto API contexts around to use when needed.<br />
 */<br />
struct ecryptfs_key_tfm {<br />
	struct crypto_blkcipher *key_tfm;<br />
	size_t key_size;<br />
	struct mutex key_tfm_mutex;<br />
	struct list_head key_tfm_list;<br />
	unsigned char cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];<br />
};</p>
<p>extern struct mutex key_tfm_list_mutex;</p>
<p>/**<br />
 * This struct is to enable a mount-wide passphrase/salt combo. This<br />
 * is more or less a stopgap to provide similar functionality to other<br />
 * crypto filesystems like EncFS or CFS until full policy support is<br />
 * implemented in eCryptfs.<br />
 */<br />
struct ecryptfs_mount_crypt_stat {<br />
	/* Pointers to memory we do not own, do not free these */<br />
#define ECRYPTFS_PLAINTEXT_PASSTHROUGH_ENABLED 0&#215;00000001<br />
#define ECRYPTFS_XATTR_METADATA_ENABLED        0&#215;00000002<br />
#define ECRYPTFS_ENCRYPTED_VIEW_ENABLED        0&#215;00000004<br />
#define ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED  0&#215;00000008<br />
#define ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES      0&#215;00000010<br />
#define ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK   0&#215;00000020<br />
#define ECRYPTFS_GLOBAL_ENCFN_USE_FEK          0&#215;00000040<br />
	u32 flags;<br />
	struct list_head global_auth_tok_list;<br />
	struct mutex global_auth_tok_list_mutex;<br />
	size_t num_global_auth_toks;<br />
	size_t global_default_cipher_key_size;<br />
	size_t global_default_fn_cipher_key_bytes;<br />
	unsigned char global_default_cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE<br />
						 + 1];<br />
	unsigned char global_default_fn_cipher_name[<br />
		ECRYPTFS_MAX_CIPHER_NAME_SIZE + 1];<br />
	char global_default_fnek_sig[ECRYPTFS_SIG_SIZE_HEX + 1];<br />
};</p>
<p>/* superblock private data. */<br />
struct ecryptfs_sb_info {<br />
	struct super_block *wsi_sb;<br />
	struct ecryptfs_mount_crypt_stat mount_crypt_stat;<br />
};</p>
<p>/* file private data. */<br />
struct ecryptfs_file_info {<br />
	struct file *wfi_file;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
};</p>
<p>/* auth_tok <=> encrypted_session_key mappings */<br />
struct ecryptfs_auth_tok_list_item {<br />
	unsigned char encrypted_session_key[ECRYPTFS_MAX_KEY_BYTES];<br />
	struct list_head list;<br />
	struct ecryptfs_auth_tok auth_tok;<br />
};</p>
<p>struct ecryptfs_message {<br />
	/* Can never be greater than ecryptfs_message_buf_len */<br />
	/* Used to find the parent msg_ctx */<br />
	/* Inherits from msg_ctx->index */<br />
	u32 index;<br />
	u32 data_len;<br />
	u8 data[];<br />
};</p>
<p>struct ecryptfs_msg_ctx {<br />
#define ECRYPTFS_MSG_CTX_STATE_FREE     0&#215;01<br />
#define ECRYPTFS_MSG_CTX_STATE_PENDING  0&#215;02<br />
#define ECRYPTFS_MSG_CTX_STATE_DONE     0&#215;03<br />
#define ECRYPTFS_MSG_CTX_STATE_NO_REPLY 0&#215;04<br />
	u8 state;<br />
#define ECRYPTFS_MSG_HELO 100<br />
#define ECRYPTFS_MSG_QUIT 101<br />
#define ECRYPTFS_MSG_REQUEST 102<br />
#define ECRYPTFS_MSG_RESPONSE 103<br />
	u8 type;<br />
	u32 index;<br />
	/* Counter converts to a sequence number. Each message sent<br />
	 * out for which we expect a response has an associated<br />
	 * sequence number. The response must have the same sequence<br />
	 * number as the counter for the msg_stc for the message to be<br />
	 * valid. */<br />
	u32 counter;<br />
	size_t msg_size;<br />
	struct ecryptfs_message *msg;<br />
	struct task_struct *task;<br />
	struct list_head node;<br />
	struct list_head daemon_out_list;<br />
	struct mutex mux;<br />
};</p>
<p>struct ecryptfs_daemon;</p>
<p>struct ecryptfs_daemon {<br />
#define ECRYPTFS_DAEMON_IN_READ      0&#215;00000001<br />
#define ECRYPTFS_DAEMON_IN_POLL      0&#215;00000002<br />
#define ECRYPTFS_DAEMON_ZOMBIE       0&#215;00000004<br />
#define ECRYPTFS_DAEMON_MISCDEV_OPEN 0&#215;00000008<br />
	u32 flags;<br />
	u32 num_queued_msg_ctx;<br />
	struct pid *pid;<br />
	uid_t euid;<br />
	struct user_namespace *user_ns;<br />
	struct task_struct *task;<br />
	struct mutex mux;<br />
	struct list_head msg_ctx_out_queue;<br />
	wait_queue_head_t wait;<br />
	struct hlist_node euid_chain;<br />
};</p>
<p>extern struct mutex ecryptfs_daemon_hash_mux;</p>
<p>static inline struct ecryptfs_file_info *<br />
ecryptfs_file_to_private(struct file *file)<br />
{<br />
	return (struct ecryptfs_file_info *)file->private_data;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_file_private(struct file *file,<br />
			  struct ecryptfs_file_info *file_info)<br />
{<br />
	file->private_data = file_info;<br />
}</p>
<p>static inline struct file *ecryptfs_file_to_lower(struct file *file)<br />
{<br />
	return ((struct ecryptfs_file_info *)file->private_data)->wfi_file;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_file_lower(struct file *file, struct file *lower_file)<br />
{<br />
	((struct ecryptfs_file_info *)file->private_data)->wfi_file =<br />
		lower_file;<br />
}</p>
<p>static inline struct ecryptfs_inode_info *<br />
ecryptfs_inode_to_private(struct inode *inode)<br />
{<br />
	return container_of(inode, struct ecryptfs_inode_info, vfs_inode);<br />
}</p>
<p>static inline struct inode *ecryptfs_inode_to_lower(struct inode *inode)<br />
{<br />
	return ecryptfs_inode_to_private(inode)->wii_inode;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_inode_lower(struct inode *inode, struct inode *lower_inode)<br />
{<br />
	ecryptfs_inode_to_private(inode)->wii_inode = lower_inode;<br />
}</p>
<p>static inline struct ecryptfs_sb_info *<br />
ecryptfs_superblock_to_private(struct super_block *sb)<br />
{<br />
	return (struct ecryptfs_sb_info *)sb->s_fs_info;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_superblock_private(struct super_block *sb,<br />
				struct ecryptfs_sb_info *sb_info)<br />
{<br />
	sb->s_fs_info = sb_info;<br />
}</p>
<p>static inline struct super_block *<br />
ecryptfs_superblock_to_lower(struct super_block *sb)<br />
{<br />
	return ((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_superblock_lower(struct super_block *sb,<br />
			      struct super_block *lower_sb)<br />
{<br />
	((struct ecryptfs_sb_info *)sb->s_fs_info)->wsi_sb = lower_sb;<br />
}</p>
<p>static inline struct ecryptfs_dentry_info *<br />
ecryptfs_dentry_to_private(struct dentry *dentry)<br />
{<br />
	return (struct ecryptfs_dentry_info *)dentry->d_fsdata;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_dentry_private(struct dentry *dentry,<br />
			    struct ecryptfs_dentry_info *dentry_info)<br />
{<br />
	dentry->d_fsdata = dentry_info;<br />
}</p>
<p>static inline struct dentry *<br />
ecryptfs_dentry_to_lower(struct dentry *dentry)<br />
{<br />
	return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_dentry_lower(struct dentry *dentry, struct dentry *lower_dentry)<br />
{<br />
	((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.dentry =<br />
		lower_dentry;<br />
}</p>
<p>static inline struct vfsmount *<br />
ecryptfs_dentry_to_lower_mnt(struct dentry *dentry)<br />
{<br />
	return ((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt;<br />
}</p>
<p>static inline void<br />
ecryptfs_set_dentry_lower_mnt(struct dentry *dentry, struct vfsmount *lower_mnt)<br />
{<br />
	((struct ecryptfs_dentry_info *)dentry->d_fsdata)->lower_path.mnt =<br />
		lower_mnt;<br />
}</p>
<p>#define ecryptfs_printk(type, fmt, arg&#8230;) \<br />
        __ecryptfs_printk(type &laquo;%s: &raquo; fmt, __func__, ## arg);<br />
void __ecryptfs_printk(const char *fmt, &#8230;);</p>
<p>extern const struct file_operations ecryptfs_main_fops;<br />
extern const struct file_operations ecryptfs_dir_fops;<br />
extern const struct inode_operations ecryptfs_main_iops;<br />
extern const struct inode_operations ecryptfs_dir_iops;<br />
extern const struct inode_operations ecryptfs_symlink_iops;<br />
extern const struct super_operations ecryptfs_sops;<br />
extern const struct dentry_operations ecryptfs_dops;<br />
extern const struct address_space_operations ecryptfs_aops;<br />
extern int ecryptfs_verbosity;<br />
extern unsigned int ecryptfs_message_buf_len;<br />
extern signed long ecryptfs_message_wait_timeout;<br />
extern unsigned int ecryptfs_number_of_users;</p>
<p>extern struct kmem_cache *ecryptfs_auth_tok_list_item_cache;<br />
extern struct kmem_cache *ecryptfs_file_info_cache;<br />
extern struct kmem_cache *ecryptfs_dentry_info_cache;<br />
extern struct kmem_cache *ecryptfs_inode_info_cache;<br />
extern struct kmem_cache *ecryptfs_sb_info_cache;<br />
extern struct kmem_cache *ecryptfs_header_cache_1;<br />
extern struct kmem_cache *ecryptfs_header_cache_2;<br />
extern struct kmem_cache *ecryptfs_xattr_cache;<br />
extern struct kmem_cache *ecryptfs_key_record_cache;<br />
extern struct kmem_cache *ecryptfs_key_sig_cache;<br />
extern struct kmem_cache *ecryptfs_global_auth_tok_cache;<br />
extern struct kmem_cache *ecryptfs_key_tfm_cache;<br />
extern struct kmem_cache *ecryptfs_open_req_cache;</p>
<p>struct ecryptfs_open_req {<br />
#define ECRYPTFS_REQ_PROCESSED 0&#215;00000001<br />
#define ECRYPTFS_REQ_DROPPED   0&#215;00000002<br />
#define ECRYPTFS_REQ_ZOMBIE    0&#215;00000004<br />
	u32 flags;<br />
	struct file **lower_file;<br />
	struct dentry *lower_dentry;<br />
	struct vfsmount *lower_mnt;<br />
	wait_queue_head_t wait;<br />
	struct mutex mux;<br />
	struct list_head kthread_ctl_list;<br />
};</p>
<p>#define ECRYPTFS_INTERPOSE_FLAG_D_ADD                 0&#215;00000001<br />
int ecryptfs_interpose(struct dentry *hidden_dentry,<br />
		       struct dentry *this_dentry, struct super_block *sb,<br />
		       u32 flags);<br />
int ecryptfs_lookup_and_interpose_lower(struct dentry *ecryptfs_dentry,<br />
					struct dentry *lower_dentry,<br />
					struct inode *ecryptfs_dir_inode,<br />
					struct nameidata *ecryptfs_nd);<br />
int ecryptfs_decode_and_decrypt_filename(char **decrypted_name,<br />
					 size_t *decrypted_name_size,<br />
					 struct dentry *ecryptfs_dentry,<br />
					 const char *name, size_t name_size);<br />
int ecryptfs_fill_zeros(struct file *file, loff_t new_length);<br />
int ecryptfs_encrypt_and_encode_filename(<br />
	char **encoded_name,<br />
	size_t *encoded_name_size,<br />
	struct ecryptfs_crypt_stat *crypt_stat,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
	const char *name, size_t name_size);<br />
struct dentry *ecryptfs_lower_dentry(struct dentry *this_dentry);<br />
void ecryptfs_dump_hex(char *data, int bytes);<br />
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,<br />
			int sg_size);<br />
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat);<br />
void ecryptfs_rotate_iv(unsigned char *iv);<br />
void ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);<br />
void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat);<br />
void ecryptfs_destroy_mount_crypt_stat(<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat);<br />
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat);<br />
int ecryptfs_write_inode_size_to_metadata(struct inode *ecryptfs_inode);<br />
int ecryptfs_encrypt_page(struct page *page);<br />
int ecryptfs_decrypt_page(struct page *page);<br />
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry);<br />
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry);<br />
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry);<br />
int ecryptfs_read_and_validate_header_region(char *data,<br />
					     struct inode *ecryptfs_inode);<br />
int ecryptfs_read_and_validate_xattr_region(char *page_virt,<br />
					    struct dentry *ecryptfs_dentry);<br />
u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes);<br />
int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code);<br />
void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat);<br />
int ecryptfs_generate_key_packet_set(char *dest_base,<br />
				     struct ecryptfs_crypt_stat *crypt_stat,<br />
				     struct dentry *ecryptfs_dentry,<br />
				     size_t *len, size_t max);<br />
int<br />
ecryptfs_parse_packet_set(struct ecryptfs_crypt_stat *crypt_stat,<br />
			  unsigned char *src, struct dentry *ecryptfs_dentry);<br />
int ecryptfs_truncate(struct dentry *dentry, loff_t new_length);<br />
int ecryptfs_inode_test(struct inode *inode, void *candidate_lower_inode);<br />
int ecryptfs_inode_set(struct inode *inode, void *lower_inode);<br />
void ecryptfs_init_inode(struct inode *inode, struct inode *lower_inode);<br />
ssize_t<br />
ecryptfs_getxattr_lower(struct dentry *lower_dentry, const char *name,<br />
			void *value, size_t size);<br />
int<br />
ecryptfs_setxattr(struct dentry *dentry, const char *name, const void *value,<br />
		  size_t size, int flags);<br />
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode);<br />
int ecryptfs_process_helo(uid_t euid, struct user_namespace *user_ns,<br />
			  struct pid *pid);<br />
int ecryptfs_process_quit(uid_t euid, struct user_namespace *user_ns,<br />
			  struct pid *pid);<br />
int ecryptfs_process_response(struct ecryptfs_message *msg, uid_t euid,<br />
			      struct user_namespace *user_ns, struct pid *pid,<br />
			      u32 seq);<br />
int ecryptfs_send_message(char *data, int data_len,<br />
			  struct ecryptfs_msg_ctx **msg_ctx);<br />
int ecryptfs_wait_for_response(struct ecryptfs_msg_ctx *msg_ctx,<br />
			       struct ecryptfs_message **emsg);<br />
int ecryptfs_init_messaging(void);<br />
void ecryptfs_release_messaging(void);</p>
<p>void<br />
ecryptfs_write_header_metadata(char *virt,<br />
			       struct ecryptfs_crypt_stat *crypt_stat,<br />
			       size_t *written);<br />
int ecryptfs_add_keysig(struct ecryptfs_crypt_stat *crypt_stat, char *sig);<br />
int<br />
ecryptfs_add_global_auth_tok(struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			   char *sig, u32 global_auth_tok_flags);<br />
int ecryptfs_get_global_auth_tok_for_sig(<br />
	struct ecryptfs_global_auth_tok **global_auth_tok,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat, char *sig);<br />
int<br />
ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,<br />
			 size_t key_size);<br />
int ecryptfs_init_crypto(void);<br />
int ecryptfs_destroy_crypto(void);<br />
int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm);<br />
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,<br />
					       struct mutex **tfm_mutex,<br />
					       char *cipher_name);<br />
int ecryptfs_keyring_auth_tok_for_sig(struct key **auth_tok_key,<br />
				      struct ecryptfs_auth_tok **auth_tok,<br />
				      char *sig);<br />
int ecryptfs_write_lower(struct inode *ecryptfs_inode, char *data,<br />
			 loff_t offset, size_t size);<br />
int ecryptfs_write_lower_page_segment(struct inode *ecryptfs_inode,<br />
				      struct page *page_for_lower,<br />
				      size_t offset_in_page, size_t size);<br />
int ecryptfs_write(struct file *ecryptfs_file, char *data, loff_t offset,<br />
		   size_t size);<br />
int ecryptfs_read_lower(char *data, loff_t offset, size_t size,<br />
			struct inode *ecryptfs_inode);<br />
int ecryptfs_read_lower_page_segment(struct page *page_for_ecryptfs,<br />
				     pgoff_t page_index,<br />
				     size_t offset_in_page, size_t size,<br />
				     struct inode *ecryptfs_inode);<br />
struct page *ecryptfs_get_locked_page(struct file *file, loff_t index);<br />
int ecryptfs_exorcise_daemon(struct ecryptfs_daemon *daemon);<br />
int ecryptfs_find_daemon_by_euid(struct ecryptfs_daemon **daemon, uid_t euid,<br />
				 struct user_namespace *user_ns);<br />
int ecryptfs_parse_packet_length(unsigned char *data, size_t *size,<br />
				 size_t *length_size);<br />
int ecryptfs_write_packet_length(char *dest, size_t size,<br />
				 size_t *packet_size_length);<br />
int ecryptfs_init_ecryptfs_miscdev(void);<br />
void ecryptfs_destroy_ecryptfs_miscdev(void);<br />
int ecryptfs_send_miscdev(char *data, size_t data_size,<br />
			  struct ecryptfs_msg_ctx *msg_ctx, u8 msg_type,<br />
			  u16 msg_flags, struct ecryptfs_daemon *daemon);<br />
void ecryptfs_msg_ctx_alloc_to_free(struct ecryptfs_msg_ctx *msg_ctx);<br />
int<br />
ecryptfs_spawn_daemon(struct ecryptfs_daemon **daemon, uid_t euid,<br />
		      struct user_namespace *user_ns, struct pid *pid);<br />
int ecryptfs_init_kthread(void);<br />
void ecryptfs_destroy_kthread(void);<br />
int ecryptfs_privileged_open(struct file **lower_file,<br />
			     struct dentry *lower_dentry,<br />
			     struct vfsmount *lower_mnt,<br />
			     const struct cred *cred);<br />
int ecryptfs_init_persistent_file(struct dentry *ecryptfs_dentry);<br />
int<br />
ecryptfs_write_tag_70_packet(char *dest, size_t *remaining_bytes,<br />
			     size_t *packet_size,<br />
			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			     char *filename, size_t filename_size);<br />
int<br />
ecryptfs_parse_tag_70_packet(char **filename, size_t *filename_size,<br />
			     size_t *packet_size,<br />
			     struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
			     char *data, size_t max_packet_size);<br />
int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,<br />
		       loff_t offset);</p>
<p>#endif /* #ifndef ECRYPTFS_KERNEL_H */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/ecryptfs_kernel-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>dentry.c</title>
		<link>http://lynyrd.ru/dentry-c</link>
		<comments>http://lynyrd.ru/dentry-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:01:50 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1080</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2003 Erez Zadok
 * Copyright (C) 2001-2003 Stony Brook University
 * Copyright (C) 2004-2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1080"></span><br />
 *<br />
 * Copyright (C) 1997-2003 Erez Zadok<br />
 * Copyright (C) 2001-2003 Stony Brook University<br />
 * Copyright (C) 2004-2006 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/dcache.h>
#include
<linux/namei.h>
#include
<linux/mount.h>
#include
<linux/fs_stack.h>
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * ecryptfs_d_revalidate &#8211; revalidate an ecryptfs dentry<br />
 * @dentry: The ecryptfs dentry<br />
 * @nd: The associated nameidata<br />
 *<br />
 * Called when the VFS needs to revalidate a dentry. This<br />
 * is called whenever a name lookup finds a dentry in the<br />
 * dcache. Most filesystems leave this as NULL, because all their<br />
 * dentries in the dcache are valid.<br />
 *<br />
 * Returns 1 if valid, 0 otherwise.<br />
 *<br />
 */<br />
static int ecryptfs_d_revalidate(struct dentry *dentry, struct nameidata *nd)<br />
{<br />
	struct dentry *lower_dentry = ecryptfs_dentry_to_lower(dentry);<br />
	struct vfsmount *lower_mnt = ecryptfs_dentry_to_lower_mnt(dentry);<br />
	struct dentry *dentry_save;<br />
	struct vfsmount *vfsmount_save;<br />
	int rc = 1;</p>
<p>	if (!lower_dentry->d_op || !lower_dentry->d_op->d_revalidate)<br />
		goto out;<br />
	dentry_save = nd->path.dentry;<br />
	vfsmount_save = nd->path.mnt;<br />
	nd->path.dentry = lower_dentry;<br />
	nd->path.mnt = lower_mnt;<br />
	rc = lower_dentry->d_op->d_revalidate(lower_dentry, nd);<br />
	nd->path.dentry = dentry_save;<br />
	nd->path.mnt = vfsmount_save;<br />
	if (dentry->d_inode) {<br />
		struct inode *lower_inode =<br />
			ecryptfs_inode_to_lower(dentry->d_inode);</p>
<p>		fsstack_copy_attr_all(dentry->d_inode, lower_inode, NULL);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_dentry_info_cache;</p>
<p>/**<br />
 * ecryptfs_d_release<br />
 * @dentry: The ecryptfs dentry<br />
 *<br />
 * Called when a dentry is really deallocated.<br />
 */<br />
static void ecryptfs_d_release(struct dentry *dentry)<br />
{<br />
	if (ecryptfs_dentry_to_private(dentry)) {<br />
		if (ecryptfs_dentry_to_lower(dentry)) {<br />
			dput(ecryptfs_dentry_to_lower(dentry));<br />
			mntput(ecryptfs_dentry_to_lower_mnt(dentry));<br />
		}<br />
		kmem_cache_free(ecryptfs_dentry_info_cache,<br />
				ecryptfs_dentry_to_private(dentry));<br />
	}<br />
	return;<br />
}</p>
<p>const struct dentry_operations ecryptfs_dops = {<br />
	.d_revalidate = ecryptfs_d_revalidate,<br />
	.d_release = ecryptfs_d_release,<br />
};</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/dentry-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>debug.c</title>
		<link>http://lynyrd.ru/debug-c-3</link>
		<comments>http://lynyrd.ru/debug-c-3#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:01:33 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/debug-c-3</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 * Functions only useful for debugging.
 *
 * Copyright (C) 2006 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1079"></span><br />
 * Functions only useful for debugging.<br />
 *<br />
 * Copyright (C) 2006 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>/**<br />
 * ecryptfs_dump_auth_tok &#8211; debug function to print auth toks<br />
 *<br />
 * This function will print the contents of an ecryptfs authentication<br />
 * token.<br />
 */<br />
void ecryptfs_dump_auth_tok(struct ecryptfs_auth_tok *auth_tok)<br />
{<br />
	char salt[ECRYPTFS_SALT_SIZE * 2 + 1];<br />
	char sig[ECRYPTFS_SIG_SIZE_HEX + 1];</p>
<p>	ecryptfs_printk(KERN_DEBUG, &laquo;Auth tok at mem loc [%p]:\n&raquo;,<br />
			auth_tok);<br />
	if (auth_tok->flags &#038; ECRYPTFS_PRIVATE_KEY) {<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * private key type\n&raquo;);<br />
	} else {<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * passphrase type\n&raquo;);<br />
		ecryptfs_to_hex(salt, auth_tok->token.password.salt,<br />
				ECRYPTFS_SALT_SIZE);<br />
		salt[ECRYPTFS_SALT_SIZE * 2] = &#8216;\0&#8242;;<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * salt = [%s]\n&raquo;, salt);<br />
		if (auth_tok->token.password.flags &#038;<br />
		    ECRYPTFS_PERSISTENT_PASSWORD) {<br />
			ecryptfs_printk(KERN_DEBUG, &raquo; * persistent\n&raquo;);<br />
		}<br />
		memcpy(sig, auth_tok->token.password.signature,<br />
		       ECRYPTFS_SIG_SIZE_HEX);<br />
		sig[ECRYPTFS_SIG_SIZE_HEX] = &#8216;\0&#8242;;<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * signature = [%s]\n&raquo;, sig);<br />
	}<br />
	ecryptfs_printk(KERN_DEBUG, &raquo; * session_key.flags = [0x%x]\n&raquo;,<br />
			auth_tok->session_key.flags);<br />
	if (auth_tok->session_key.flags<br />
	    &#038; ECRYPTFS_USERSPACE_SHOULD_TRY_TO_DECRYPT)<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&raquo; * Userspace decrypt request set\n&raquo;);<br />
	if (auth_tok->session_key.flags<br />
	    &#038; ECRYPTFS_USERSPACE_SHOULD_TRY_TO_ENCRYPT)<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&raquo; * Userspace encrypt request set\n&raquo;);<br />
	if (auth_tok->session_key.flags &#038; ECRYPTFS_CONTAINS_DECRYPTED_KEY) {<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * Contains decrypted key\n&raquo;);<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&raquo; * session_key.decrypted_key_size = [0x%x]\n&raquo;,<br />
				auth_tok->session_key.decrypted_key_size);<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * Decrypted session key &raquo;<br />
				&laquo;dump:\n&raquo;);<br />
		if (ecryptfs_verbosity > 0)<br />
			ecryptfs_dump_hex(auth_tok->session_key.decrypted_key,<br />
					  ECRYPTFS_DEFAULT_KEY_BYTES);<br />
	}<br />
	if (auth_tok->session_key.flags &#038; ECRYPTFS_CONTAINS_ENCRYPTED_KEY) {<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * Contains encrypted key\n&raquo;);<br />
		ecryptfs_printk(KERN_DEBUG,<br />
				&raquo; * session_key.encrypted_key_size = [0x%x]\n&raquo;,<br />
				auth_tok->session_key.encrypted_key_size);<br />
		ecryptfs_printk(KERN_DEBUG, &raquo; * Encrypted session key &raquo;<br />
				&laquo;dump:\n&raquo;);<br />
		if (ecryptfs_verbosity > 0)<br />
			ecryptfs_dump_hex(auth_tok->session_key.encrypted_key,<br />
					  auth_tok->session_key.<br />
					  encrypted_key_size);<br />
	}<br />
}</p>
<p>/**<br />
 * ecryptfs_dump_hex &#8211; debug hex printer<br />
 * @data: string of bytes to be printed<br />
 * @bytes: number of bytes to print<br />
 *<br />
 * Dump hexadecimal representation of char array<br />
 */<br />
void ecryptfs_dump_hex(char *data, int bytes)<br />
{<br />
	int i = 0;<br />
	int add_newline = 1;</p>
<p>	if (ecryptfs_verbosity < 1)<br />
		return;<br />
	if (bytes != 0) {<br />
		printk(KERN_DEBUG &laquo;0x%.2x.&raquo;, (unsigned char)data[i]);<br />
		i++;<br />
	}<br />
	while (i < bytes) {<br />
		printk(&raquo;0x%.2x.&raquo;, (unsigned char)data[i]);<br />
		i++;<br />
		if (i % 16 == 0) {<br />
			printk(&raquo;\n&raquo;);<br />
			add_newline = 0;<br />
		} else<br />
			add_newline = 1;<br />
	}<br />
	if (add_newline)<br />
		printk(&raquo;\n&raquo;);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/debug-c-3/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>crypto.c</title>
		<link>http://lynyrd.ru/crypto-c</link>
		<comments>http://lynyrd.ru/crypto-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:01:17 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1077</guid>
		<description><![CDATA[/**
 * eCryptfs: Linux filesystem encryption layer
 *
 * Copyright (C) 1997-2004 Erez Zadok
 * Copyright (C) 2001-2004 Stony Brook University
 * Copyright (C) 2004-2007 International Business Machines Corp.
 *   Author(s): Michael A. Halcrow 
 *   		Michael C. Thompson 
 *
 * This program is free software; you can redistribute it ]]></description>
			<content:encoded><![CDATA[<p>/**<br />
 * eCryptfs: Linux filesystem encryption layer<span id="more-1077"></span><br />
 *<br />
 * Copyright (C) 1997-2004 Erez Zadok<br />
 * Copyright (C) 2001-2004 Stony Brook University<br />
 * Copyright (C) 2004-2007 International Business Machines Corp.<br />
 *   Author(s): Michael A. Halcrow <mahalcro@us.ibm.com><br />
 *   		Michael C. Thompson <mcthomps@us.ibm.com><br />
 *<br />
 * This program is free software; you can redistribute it and/or<br />
 * modify it under the terms of the GNU General Public License as<br />
 * published by the Free Software Foundation; either version 2 of the<br />
 * License, or (at your option) any later version.<br />
 *<br />
 * This program is distributed in the hope that it will be useful, but<br />
 * WITHOUT ANY WARRANTY; without even the implied warranty of<br />
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU<br />
 * General Public License for more details.<br />
 *<br />
 * You should have received a copy of the GNU General Public License<br />
 * along with this program; if not, write to the Free Software<br />
 * Foundation, Inc., 59 Temple Place &#8211; Suite 330, Boston, MA<br />
 * 02111-1307, USA.<br />
 */</p>
<p>#include
<linux/fs.h>
#include
<linux/mount.h>
#include
<linux/pagemap.h>
#include
<linux/random.h>
#include
<linux/compiler.h>
#include
<linux/key.h>
#include
<linux/namei.h>
#include
<linux/crypto.h>
#include
<linux/file.h>
#include
<linux/scatterlist.h>
#include <asm/unaligned.h><br />
#include &laquo;ecryptfs_kernel.h&raquo;</p>
<p>static int<br />
ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,<br />
			     struct page *dst_page, int dst_offset,<br />
			     struct page *src_page, int src_offset, int size,<br />
			     unsigned char *iv);<br />
static int<br />
ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,<br />
			     struct page *dst_page, int dst_offset,<br />
			     struct page *src_page, int src_offset, int size,<br />
			     unsigned char *iv);</p>
<p>/**<br />
 * ecryptfs_to_hex<br />
 * @dst: Buffer to take hex character representation of contents of<br />
 *       src; must be at least of size (src_size * 2)<br />
 * @src: Buffer to be converted to a hex string respresentation<br />
 * @src_size: number of bytes to convert<br />
 */<br />
void ecryptfs_to_hex(char *dst, char *src, size_t src_size)<br />
{<br />
	int x;</p>
<p>	for (x = 0; x < src_size; x++)<br />
		sprintf(&#038;dst[x * 2], "%.2x", (unsigned char)src[x]);<br />
}</p>
<p>/**<br />
 * ecryptfs_from_hex<br />
 * @dst: Buffer to take the bytes from src hex; must be at least of<br />
 *       size (src_size / 2)<br />
 * @src: Buffer to be converted from a hex string respresentation to raw value<br />
 * @dst_size: size of dst buffer, or number of hex characters pairs to convert<br />
 */<br />
void ecryptfs_from_hex(char *dst, char *src, int dst_size)<br />
{<br />
	int x;<br />
	char tmp[3] = { 0, };</p>
<p>	for (x = 0; x < dst_size; x++) {<br />
		tmp[0] = src[x * 2];<br />
		tmp[1] = src[x * 2 + 1];<br />
		dst[x] = (unsigned char)simple_strtol(tmp, NULL, 16);<br />
	}<br />
}</p>
<p>/**<br />
 * ecryptfs_calculate_md5 - calculates the md5 of @src<br />
 * @dst: Pointer to 16 bytes of allocated memory<br />
 * @crypt_stat: Pointer to crypt_stat struct for the current inode<br />
 * @src: Data to be md5'd<br />
 * @len: Length of @src<br />
 *<br />
 * Uses the allocated crypto context that crypt_stat references to<br />
 * generate the MD5 sum of the contents of src.<br />
 */<br />
static int ecryptfs_calculate_md5(char *dst,<br />
				  struct ecryptfs_crypt_stat *crypt_stat,<br />
				  char *src, int len)<br />
{<br />
	struct scatterlist sg;<br />
	struct hash_desc desc = {<br />
		.tfm = crypt_stat->hash_tfm,<br />
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP<br />
	};<br />
	int rc = 0;</p>
<p>	mutex_lock(&#038;crypt_stat->cs_hash_tfm_mutex);<br />
	sg_init_one(&#038;sg, (u8 *)src, len);<br />
	if (!desc.tfm) {<br />
		desc.tfm = crypto_alloc_hash(ECRYPTFS_DEFAULT_HASH, 0,<br />
					     CRYPTO_ALG_ASYNC);<br />
		if (IS_ERR(desc.tfm)) {<br />
			rc = PTR_ERR(desc.tfm);<br />
			ecryptfs_printk(KERN_ERR, &laquo;Error attempting to &raquo;<br />
					&laquo;allocate crypto context; rc = [%d]\n&raquo;,<br />
					rc);<br />
			goto out;<br />
		}<br />
		crypt_stat->hash_tfm = desc.tfm;<br />
	}<br />
	rc = crypto_hash_init(&#038;desc);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error initializing crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out;<br />
	}<br />
	rc = crypto_hash_update(&#038;desc, &#038;sg, len);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error updating crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out;<br />
	}<br />
	rc = crypto_hash_final(&#038;desc, dst);<br />
	if (rc) {<br />
		printk(KERN_ERR<br />
		       &laquo;%s: Error finalizing crypto hash; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out;<br />
	}<br />
out:<br />
	mutex_unlock(&#038;crypt_stat->cs_hash_tfm_mutex);<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_crypto_api_algify_cipher_name(char **algified_name,<br />
						  char *cipher_name,<br />
						  char *chaining_modifier)<br />
{<br />
	int cipher_name_len = strlen(cipher_name);<br />
	int chaining_modifier_len = strlen(chaining_modifier);<br />
	int algified_name_len;<br />
	int rc;</p>
<p>	algified_name_len = (chaining_modifier_len + cipher_name_len + 3);<br />
	(*algified_name) = kmalloc(algified_name_len, GFP_KERNEL);<br />
	if (!(*algified_name)) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	snprintf((*algified_name), algified_name_len, &laquo;%s(%s)&raquo;,<br />
		 chaining_modifier, cipher_name);<br />
	rc = 0;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_derive_iv<br />
 * @iv: destination for the derived iv vale<br />
 * @crypt_stat: Pointer to crypt_stat struct for the current inode<br />
 * @offset: Offset of the extent whose IV we are to derive<br />
 *<br />
 * Generate the initialization vector from the given root IV and page<br />
 * offset.<br />
 *<br />
 * Returns zero on success; non-zero on error.<br />
 */<br />
int ecryptfs_derive_iv(char *iv, struct ecryptfs_crypt_stat *crypt_stat,<br />
		       loff_t offset)<br />
{<br />
	int rc = 0;<br />
	char dst[MD5_DIGEST_SIZE];<br />
	char src[ECRYPTFS_MAX_IV_BYTES + 16];</p>
<p>	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;root iv:\n&raquo;);<br />
		ecryptfs_dump_hex(crypt_stat->root_iv, crypt_stat->iv_bytes);<br />
	}<br />
	/* TODO: It is probably secure to just cast the least<br />
	 * significant bits of the root IV into an unsigned long and<br />
	 * add the offset to that rather than go through all this<br />
	 * hashing business. -Halcrow */<br />
	memcpy(src, crypt_stat->root_iv, crypt_stat->iv_bytes);<br />
	memset((src + crypt_stat->iv_bytes), 0, 16);<br />
	snprintf((src + crypt_stat->iv_bytes), 16, &laquo;%lld&raquo;, offset);<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;source:\n&raquo;);<br />
		ecryptfs_dump_hex(src, (crypt_stat->iv_bytes + 16));<br />
	}<br />
	rc = ecryptfs_calculate_md5(dst, crypt_stat, src,<br />
				    (crypt_stat->iv_bytes + 16));<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error attempting to compute &raquo;<br />
				&laquo;MD5 while generating IV for a page\n&raquo;);<br />
		goto out;<br />
	}<br />
	memcpy(iv, dst, crypt_stat->iv_bytes);<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;derived iv:\n&raquo;);<br />
		ecryptfs_dump_hex(iv, crypt_stat->iv_bytes);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_init_crypt_stat<br />
 * @crypt_stat: Pointer to the crypt_stat struct to initialize.<br />
 *<br />
 * Initialize the crypt_stat structure.<br />
 */<br />
void<br />
ecryptfs_init_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	memset((void *)crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));<br />
	INIT_LIST_HEAD(&#038;crypt_stat->keysig_list);<br />
	mutex_init(&#038;crypt_stat->keysig_list_mutex);<br />
	mutex_init(&#038;crypt_stat->cs_mutex);<br />
	mutex_init(&#038;crypt_stat->cs_tfm_mutex);<br />
	mutex_init(&#038;crypt_stat->cs_hash_tfm_mutex);<br />
	crypt_stat->flags |= ECRYPTFS_STRUCT_INITIALIZED;<br />
}</p>
<p>/**<br />
 * ecryptfs_destroy_crypt_stat<br />
 * @crypt_stat: Pointer to the crypt_stat struct to initialize.<br />
 *<br />
 * Releases all memory associated with a crypt_stat struct.<br />
 */<br />
void ecryptfs_destroy_crypt_stat(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	struct ecryptfs_key_sig *key_sig, *key_sig_tmp;</p>
<p>	if (crypt_stat->tfm)<br />
		crypto_free_blkcipher(crypt_stat->tfm);<br />
	if (crypt_stat->hash_tfm)<br />
		crypto_free_hash(crypt_stat->hash_tfm);<br />
	list_for_each_entry_safe(key_sig, key_sig_tmp,<br />
				 &#038;crypt_stat->keysig_list, crypt_stat_list) {<br />
		list_del(&#038;key_sig->crypt_stat_list);<br />
		kmem_cache_free(ecryptfs_key_sig_cache, key_sig);<br />
	}<br />
	memset(crypt_stat, 0, sizeof(struct ecryptfs_crypt_stat));<br />
}</p>
<p>void ecryptfs_destroy_mount_crypt_stat(<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	struct ecryptfs_global_auth_tok *auth_tok, *auth_tok_tmp;</p>
<p>	if (!(mount_crypt_stat->flags &#038; ECRYPTFS_MOUNT_CRYPT_STAT_INITIALIZED))<br />
		return;<br />
	mutex_lock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	list_for_each_entry_safe(auth_tok, auth_tok_tmp,<br />
				 &#038;mount_crypt_stat->global_auth_tok_list,<br />
				 mount_crypt_stat_list) {<br />
		list_del(&#038;auth_tok->mount_crypt_stat_list);<br />
		mount_crypt_stat->num_global_auth_toks&#8211;;<br />
		if (auth_tok->global_auth_tok_key<br />
		    &#038;&#038; !(auth_tok->flags &#038; ECRYPTFS_AUTH_TOK_INVALID))<br />
			key_put(auth_tok->global_auth_tok_key);<br />
		kmem_cache_free(ecryptfs_global_auth_tok_cache, auth_tok);<br />
	}<br />
	mutex_unlock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	memset(mount_crypt_stat, 0, sizeof(struct ecryptfs_mount_crypt_stat));<br />
}</p>
<p>/**<br />
 * virt_to_scatterlist<br />
 * @addr: Virtual address<br />
 * @size: Size of data; should be an even multiple of the block size<br />
 * @sg: Pointer to scatterlist array; set to NULL to obtain only<br />
 *      the number of scatterlist structs required in array<br />
 * @sg_size: Max array size<br />
 *<br />
 * Fills in a scatterlist array with page references for a passed<br />
 * virtual address.<br />
 *<br />
 * Returns the number of scatterlist structs in array used<br />
 */<br />
int virt_to_scatterlist(const void *addr, int size, struct scatterlist *sg,<br />
			int sg_size)<br />
{<br />
	int i = 0;<br />
	struct page *pg;<br />
	int offset;<br />
	int remainder_of_page;</p>
<p>	sg_init_table(sg, sg_size);</p>
<p>	while (size > 0 &#038;&#038; i < sg_size) {<br />
		pg = virt_to_page(addr);<br />
		offset = offset_in_page(addr);<br />
		if (sg)<br />
			sg_set_page(&#038;sg[i], pg, 0, offset);<br />
		remainder_of_page = PAGE_CACHE_SIZE - offset;<br />
		if (size >= remainder_of_page) {<br />
			if (sg)<br />
				sg[i].length = remainder_of_page;<br />
			addr += remainder_of_page;<br />
			size -= remainder_of_page;<br />
		} else {<br />
			if (sg)<br />
				sg[i].length = size;<br />
			addr += size;<br />
			size = 0;<br />
		}<br />
		i++;<br />
	}<br />
	if (size > 0)<br />
		return -ENOMEM;<br />
	return i;<br />
}</p>
<p>/**<br />
 * encrypt_scatterlist<br />
 * @crypt_stat: Pointer to the crypt_stat struct to initialize.<br />
 * @dest_sg: Destination of encrypted data<br />
 * @src_sg: Data to be encrypted<br />
 * @size: Length of data to be encrypted<br />
 * @iv: iv to use during encryption<br />
 *<br />
 * Returns the number of bytes encrypted; negative value on error<br />
 */<br />
static int encrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,<br />
			       struct scatterlist *dest_sg,<br />
			       struct scatterlist *src_sg, int size,<br />
			       unsigned char *iv)<br />
{<br />
	struct blkcipher_desc desc = {<br />
		.tfm = crypt_stat->tfm,<br />
		.info = iv,<br />
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP<br />
	};<br />
	int rc = 0;</p>
<p>	BUG_ON(!crypt_stat || !crypt_stat->tfm<br />
	       || !(crypt_stat->flags &#038; ECRYPTFS_STRUCT_INITIALIZED));<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Key size [%d]; key:\n&raquo;,<br />
				crypt_stat->key_size);<br />
		ecryptfs_dump_hex(crypt_stat->key,<br />
				  crypt_stat->key_size);<br />
	}<br />
	/* Consider doing this once, when the file is opened */<br />
	mutex_lock(&#038;crypt_stat->cs_tfm_mutex);<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_KEY_SET)) {<br />
		rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,<br />
					     crypt_stat->key_size);<br />
		crypt_stat->flags |= ECRYPTFS_KEY_SET;<br />
	}<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error setting key; rc = [%d]\n&raquo;,<br />
				rc);<br />
		mutex_unlock(&#038;crypt_stat->cs_tfm_mutex);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;Encrypting [%d] bytes.\n&raquo;, size);<br />
	crypto_blkcipher_encrypt_iv(&#038;desc, dest_sg, src_sg, size);<br />
	mutex_unlock(&#038;crypt_stat->cs_tfm_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_lower_offset_for_extent<br />
 *<br />
 * Convert an eCryptfs page index into a lower byte offset<br />
 */<br />
static void ecryptfs_lower_offset_for_extent(loff_t *offset, loff_t extent_num,<br />
					     struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	(*offset) = (crypt_stat->num_header_bytes_at_front<br />
		     + (crypt_stat->extent_size * extent_num));<br />
}</p>
<p>/**<br />
 * ecryptfs_encrypt_extent<br />
 * @enc_extent_page: Allocated page into which to encrypt the data in<br />
 *                   @page<br />
 * @crypt_stat: crypt_stat containing cryptographic context for the<br />
 *              encryption operation<br />
 * @page: Page containing plaintext data extent to encrypt<br />
 * @extent_offset: Page extent offset for use in generating IV<br />
 *<br />
 * Encrypts one extent of data.<br />
 *<br />
 * Return zero on success; non-zero otherwise<br />
 */<br />
static int ecryptfs_encrypt_extent(struct page *enc_extent_page,<br />
				   struct ecryptfs_crypt_stat *crypt_stat,<br />
				   struct page *page,<br />
				   unsigned long extent_offset)<br />
{<br />
	loff_t extent_base;<br />
	char extent_iv[ECRYPTFS_MAX_IV_BYTES];<br />
	int rc;</p>
<p>	extent_base = (((loff_t)page->index)<br />
		       * (PAGE_CACHE_SIZE / crypt_stat->extent_size));<br />
	rc = ecryptfs_derive_iv(extent_iv, crypt_stat,<br />
				(extent_base + extent_offset));<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error attempting to &raquo;<br />
				&laquo;derive IV for extent [0x%.16x]; &raquo;<br />
				&laquo;rc = [%d]\n&raquo;, (extent_base + extent_offset),<br />
				rc);<br />
		goto out;<br />
	}<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Encrypting extent &raquo;<br />
				&laquo;with iv:\n&raquo;);<br />
		ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;First 8 bytes before &raquo;<br />
				&laquo;encryption:\n&raquo;);<br />
		ecryptfs_dump_hex((char *)<br />
				  (page_address(page)<br />
				   + (extent_offset * crypt_stat->extent_size)),<br />
				  8);<br />
	}<br />
	rc = ecryptfs_encrypt_page_offset(crypt_stat, enc_extent_page, 0,<br />
					  page, (extent_offset<br />
						 * crypt_stat->extent_size),<br />
					  crypt_stat->extent_size, extent_iv);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "%s: Error attempting to encrypt page with "<br />
		       "page->index = [%ld], extent_offset = [%ld]; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, page->index, extent_offset,<br />
		       rc);<br />
		goto out;<br />
	}<br />
	rc = 0;<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Encrypt extent [0x%.16x]; &raquo;<br />
				&laquo;rc = [%d]\n&raquo;, (extent_base + extent_offset),<br />
				rc);<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;First 8 bytes after &raquo;<br />
				&laquo;encryption:\n&raquo;);<br />
		ecryptfs_dump_hex((char *)(page_address(enc_extent_page)), 8);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_encrypt_page<br />
 * @page: Page mapped from the eCryptfs inode for the file; contains<br />
 *        decrypted content that needs to be encrypted (to a temporary<br />
 *        page; not in place) and written out to the lower file<br />
 *<br />
 * Encrypt an eCryptfs page. This is done on a per-extent basis. Note<br />
 * that eCryptfs pages may straddle the lower pages &#8212; for instance,<br />
 * if the file was created on a machine with an 8K page size<br />
 * (resulting in an 8K header), and then the file is copied onto a<br />
 * host with a 32K page size, then when reading page 0 of the eCryptfs<br />
 * file, 24K of page 0 of the lower file will be read and decrypted,<br />
 * and then 8K of page 1 of the lower file will be read and decrypted.<br />
 *<br />
 * Returns zero on success; negative on error<br />
 */<br />
int ecryptfs_encrypt_page(struct page *page)<br />
{<br />
	struct inode *ecryptfs_inode;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
	char *enc_extent_virt;<br />
	struct page *enc_extent_page = NULL;<br />
	loff_t extent_offset;<br />
	int rc = 0;</p>
<p>	ecryptfs_inode = page->mapping->host;<br />
	crypt_stat =<br />
		&#038;(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);<br />
	BUG_ON(!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED));<br />
	enc_extent_page = alloc_page(GFP_USER);<br />
	if (!enc_extent_page) {<br />
		rc = -ENOMEM;<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error allocating memory for &raquo;<br />
				&laquo;encrypted extent\n&raquo;);<br />
		goto out;<br />
	}<br />
	enc_extent_virt = kmap(enc_extent_page);<br />
	for (extent_offset = 0;<br />
	     extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);<br />
	     extent_offset++) {<br />
		loff_t offset;</p>
<p>		rc = ecryptfs_encrypt_extent(enc_extent_page, crypt_stat, page,<br />
					     extent_offset);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error encrypting extent; &raquo;<br />
			       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
			goto out;<br />
		}<br />
		ecryptfs_lower_offset_for_extent(<br />
			&#038;offset, ((((loff_t)page->index)<br />
				   * (PAGE_CACHE_SIZE<br />
				      / crypt_stat->extent_size))<br />
				  + extent_offset), crypt_stat);<br />
		rc = ecryptfs_write_lower(ecryptfs_inode, enc_extent_virt,<br />
					  offset, crypt_stat->extent_size);<br />
		if (rc < 0) {<br />
			ecryptfs_printk(KERN_ERR, "Error attempting "<br />
					"to write lower page; rc = [%d]"<br />
					"\n", rc);<br />
			goto out;<br />
		}<br />
	}<br />
	rc = 0;<br />
out:<br />
	if (enc_extent_page) {<br />
		kunmap(enc_extent_page);<br />
		__free_page(enc_extent_page);<br />
	}<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_decrypt_extent(struct page *page,<br />
				   struct ecryptfs_crypt_stat *crypt_stat,<br />
				   struct page *enc_extent_page,<br />
				   unsigned long extent_offset)<br />
{<br />
	loff_t extent_base;<br />
	char extent_iv[ECRYPTFS_MAX_IV_BYTES];<br />
	int rc;</p>
<p>	extent_base = (((loff_t)page->index)<br />
		       * (PAGE_CACHE_SIZE / crypt_stat->extent_size));<br />
	rc = ecryptfs_derive_iv(extent_iv, crypt_stat,<br />
				(extent_base + extent_offset));<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error attempting to &raquo;<br />
				&laquo;derive IV for extent [0x%.16x]; &raquo;<br />
				&laquo;rc = [%d]\n&raquo;, (extent_base + extent_offset),<br />
				rc);<br />
		goto out;<br />
	}<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Decrypting extent &raquo;<br />
				&laquo;with iv:\n&raquo;);<br />
		ecryptfs_dump_hex(extent_iv, crypt_stat->iv_bytes);<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;First 8 bytes before &raquo;<br />
				&laquo;decryption:\n&raquo;);<br />
		ecryptfs_dump_hex((char *)<br />
				  (page_address(enc_extent_page)<br />
				   + (extent_offset * crypt_stat->extent_size)),<br />
				  8);<br />
	}<br />
	rc = ecryptfs_decrypt_page_offset(crypt_stat, page,<br />
					  (extent_offset<br />
					   * crypt_stat->extent_size),<br />
					  enc_extent_page, 0,<br />
					  crypt_stat->extent_size, extent_iv);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "%s: Error attempting to decrypt to page with "<br />
		       "page->index = [%ld], extent_offset = [%ld]; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, page->index, extent_offset,<br />
		       rc);<br />
		goto out;<br />
	}<br />
	rc = 0;<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Decrypt extent [0x%.16x]; &raquo;<br />
				&laquo;rc = [%d]\n&raquo;, (extent_base + extent_offset),<br />
				rc);<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;First 8 bytes after &raquo;<br />
				&laquo;decryption:\n&raquo;);<br />
		ecryptfs_dump_hex((char *)(page_address(page)<br />
					   + (extent_offset<br />
					      * crypt_stat->extent_size)), 8);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_decrypt_page<br />
 * @page: Page mapped from the eCryptfs inode for the file; data read<br />
 *        and decrypted from the lower file will be written into this<br />
 *        page<br />
 *<br />
 * Decrypt an eCryptfs page. This is done on a per-extent basis. Note<br />
 * that eCryptfs pages may straddle the lower pages &#8212; for instance,<br />
 * if the file was created on a machine with an 8K page size<br />
 * (resulting in an 8K header), and then the file is copied onto a<br />
 * host with a 32K page size, then when reading page 0 of the eCryptfs<br />
 * file, 24K of page 0 of the lower file will be read and decrypted,<br />
 * and then 8K of page 1 of the lower file will be read and decrypted.<br />
 *<br />
 * Returns zero on success; negative on error<br />
 */<br />
int ecryptfs_decrypt_page(struct page *page)<br />
{<br />
	struct inode *ecryptfs_inode;<br />
	struct ecryptfs_crypt_stat *crypt_stat;<br />
	char *enc_extent_virt;<br />
	struct page *enc_extent_page = NULL;<br />
	unsigned long extent_offset;<br />
	int rc = 0;</p>
<p>	ecryptfs_inode = page->mapping->host;<br />
	crypt_stat =<br />
		&#038;(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);<br />
	BUG_ON(!(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED));<br />
	enc_extent_page = alloc_page(GFP_USER);<br />
	if (!enc_extent_page) {<br />
		rc = -ENOMEM;<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error allocating memory for &raquo;<br />
				&laquo;encrypted extent\n&raquo;);<br />
		goto out;<br />
	}<br />
	enc_extent_virt = kmap(enc_extent_page);<br />
	for (extent_offset = 0;<br />
	     extent_offset < (PAGE_CACHE_SIZE / crypt_stat->extent_size);<br />
	     extent_offset++) {<br />
		loff_t offset;</p>
<p>		ecryptfs_lower_offset_for_extent(<br />
			&#038;offset, ((page->index * (PAGE_CACHE_SIZE<br />
						  / crypt_stat->extent_size))<br />
				  + extent_offset), crypt_stat);<br />
		rc = ecryptfs_read_lower(enc_extent_virt, offset,<br />
					 crypt_stat->extent_size,<br />
					 ecryptfs_inode);<br />
		if (rc < 0) {<br />
			ecryptfs_printk(KERN_ERR, "Error attempting "<br />
					"to read lower page; rc = [%d]"<br />
					"\n", rc);<br />
			goto out;<br />
		}<br />
		rc = ecryptfs_decrypt_extent(page, crypt_stat, enc_extent_page,<br />
					     extent_offset);<br />
		if (rc) {<br />
			printk(KERN_ERR "%s: Error encrypting extent; "<br />
			       "rc = [%d]\n", __func__, rc);<br />
			goto out;<br />
		}<br />
	}<br />
out:<br />
	if (enc_extent_page) {<br />
		kunmap(enc_extent_page);<br />
		__free_page(enc_extent_page);<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * decrypt_scatterlist<br />
 * @crypt_stat: Cryptographic context<br />
 * @dest_sg: The destination scatterlist to decrypt into<br />
 * @src_sg: The source scatterlist to decrypt from<br />
 * @size: The number of bytes to decrypt<br />
 * @iv: The initialization vector to use for the decryption<br />
 *<br />
 * Returns the number of bytes decrypted; negative value on error<br />
 */<br />
static int decrypt_scatterlist(struct ecryptfs_crypt_stat *crypt_stat,<br />
			       struct scatterlist *dest_sg,<br />
			       struct scatterlist *src_sg, int size,<br />
			       unsigned char *iv)<br />
{<br />
	struct blkcipher_desc desc = {<br />
		.tfm = crypt_stat->tfm,<br />
		.info = iv,<br />
		.flags = CRYPTO_TFM_REQ_MAY_SLEEP<br />
	};<br />
	int rc = 0;</p>
<p>	/* Consider doing this once, when the file is opened */<br />
	mutex_lock(&#038;crypt_stat->cs_tfm_mutex);<br />
	rc = crypto_blkcipher_setkey(crypt_stat->tfm, crypt_stat->key,<br />
				     crypt_stat->key_size);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error setting key; rc = [%d]\n&raquo;,<br />
				rc);<br />
		mutex_unlock(&#038;crypt_stat->cs_tfm_mutex);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;Decrypting [%d] bytes.\n&raquo;, size);<br />
	rc = crypto_blkcipher_decrypt_iv(&#038;desc, dest_sg, src_sg, size);<br />
	mutex_unlock(&#038;crypt_stat->cs_tfm_mutex);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error decrypting; rc = [%d]\n&raquo;,<br />
				rc);<br />
		goto out;<br />
	}<br />
	rc = size;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_encrypt_page_offset<br />
 * @crypt_stat: The cryptographic context<br />
 * @dst_page: The page to encrypt into<br />
 * @dst_offset: The offset in the page to encrypt into<br />
 * @src_page: The page to encrypt from<br />
 * @src_offset: The offset in the page to encrypt from<br />
 * @size: The number of bytes to encrypt<br />
 * @iv: The initialization vector to use for the encryption<br />
 *<br />
 * Returns the number of bytes encrypted<br />
 */<br />
static int<br />
ecryptfs_encrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,<br />
			     struct page *dst_page, int dst_offset,<br />
			     struct page *src_page, int src_offset, int size,<br />
			     unsigned char *iv)<br />
{<br />
	struct scatterlist src_sg, dst_sg;</p>
<p>	sg_init_table(&#038;src_sg, 1);<br />
	sg_init_table(&#038;dst_sg, 1);</p>
<p>	sg_set_page(&#038;src_sg, src_page, size, src_offset);<br />
	sg_set_page(&#038;dst_sg, dst_page, size, dst_offset);<br />
	return encrypt_scatterlist(crypt_stat, &#038;dst_sg, &#038;src_sg, size, iv);<br />
}</p>
<p>/**<br />
 * ecryptfs_decrypt_page_offset<br />
 * @crypt_stat: The cryptographic context<br />
 * @dst_page: The page to decrypt into<br />
 * @dst_offset: The offset in the page to decrypt into<br />
 * @src_page: The page to decrypt from<br />
 * @src_offset: The offset in the page to decrypt from<br />
 * @size: The number of bytes to decrypt<br />
 * @iv: The initialization vector to use for the decryption<br />
 *<br />
 * Returns the number of bytes decrypted<br />
 */<br />
static int<br />
ecryptfs_decrypt_page_offset(struct ecryptfs_crypt_stat *crypt_stat,<br />
			     struct page *dst_page, int dst_offset,<br />
			     struct page *src_page, int src_offset, int size,<br />
			     unsigned char *iv)<br />
{<br />
	struct scatterlist src_sg, dst_sg;</p>
<p>	sg_init_table(&#038;src_sg, 1);<br />
	sg_set_page(&#038;src_sg, src_page, size, src_offset);</p>
<p>	sg_init_table(&#038;dst_sg, 1);<br />
	sg_set_page(&#038;dst_sg, dst_page, size, dst_offset);</p>
<p>	return decrypt_scatterlist(crypt_stat, &#038;dst_sg, &#038;src_sg, size, iv);<br />
}</p>
<p>#define ECRYPTFS_MAX_SCATTERLIST_LEN 4</p>
<p>/**<br />
 * ecryptfs_init_crypt_ctx<br />
 * @crypt_stat: Uninitilized crypt stats structure<br />
 *<br />
 * Initialize the crypto context.<br />
 *<br />
 * TODO: Performance: Keep a cache of initialized cipher contexts;<br />
 * only init if needed<br />
 */<br />
int ecryptfs_init_crypt_ctx(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	char *full_alg_name;<br />
	int rc = -EINVAL;</p>
<p>	if (!crypt_stat->cipher) {<br />
		ecryptfs_printk(KERN_ERR, &laquo;No cipher specified\n&raquo;);<br />
		goto out;<br />
	}<br />
	ecryptfs_printk(KERN_DEBUG,<br />
			&laquo;Initializing cipher [%s]; strlen = [%d]; &raquo;<br />
			&laquo;key_size_bits = [%d]\n&raquo;,<br />
			crypt_stat->cipher, (int)strlen(crypt_stat->cipher),<br />
			crypt_stat->key_size << 3);<br />
	if (crypt_stat->tfm) {<br />
		rc = 0;<br />
		goto out;<br />
	}<br />
	mutex_lock(&#038;crypt_stat->cs_tfm_mutex);<br />
	rc = ecryptfs_crypto_api_algify_cipher_name(&#038;full_alg_name,<br />
						    crypt_stat->cipher, &laquo;cbc&raquo;);<br />
	if (rc)<br />
		goto out_unlock;<br />
	crypt_stat->tfm = crypto_alloc_blkcipher(full_alg_name, 0,<br />
						 CRYPTO_ALG_ASYNC);<br />
	kfree(full_alg_name);<br />
	if (IS_ERR(crypt_stat->tfm)) {<br />
		rc = PTR_ERR(crypt_stat->tfm);<br />
		crypt_stat->tfm = NULL;<br />
		ecryptfs_printk(KERN_ERR, &laquo;cryptfs: init_crypt_ctx(): &raquo;<br />
				&laquo;Error initializing cipher [%s]\n&raquo;,<br />
				crypt_stat->cipher);<br />
		goto out_unlock;<br />
	}<br />
	crypto_blkcipher_set_flags(crypt_stat->tfm, CRYPTO_TFM_REQ_WEAK_KEY);<br />
	rc = 0;<br />
out_unlock:<br />
	mutex_unlock(&#038;crypt_stat->cs_tfm_mutex);<br />
out:<br />
	return rc;<br />
}</p>
<p>static void set_extent_mask_and_shift(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	int extent_size_tmp;</p>
<p>	crypt_stat->extent_mask = 0xFFFFFFFF;<br />
	crypt_stat->extent_shift = 0;<br />
	if (crypt_stat->extent_size == 0)<br />
		return;<br />
	extent_size_tmp = crypt_stat->extent_size;<br />
	while ((extent_size_tmp &#038; 0&#215;01) == 0) {<br />
		extent_size_tmp >>= 1;<br />
		crypt_stat->extent_mask <<= 1;<br />
		crypt_stat->extent_shift++;<br />
	}<br />
}</p>
<p>void ecryptfs_set_default_sizes(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	/* Default values; may be overwritten as we are parsing the<br />
	 * packets. */<br />
	crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;<br />
	set_extent_mask_and_shift(crypt_stat);<br />
	crypt_stat->iv_bytes = ECRYPTFS_DEFAULT_IV_BYTES;<br />
	if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR)<br />
		crypt_stat->num_header_bytes_at_front = 0;<br />
	else {<br />
		if (PAGE_CACHE_SIZE <= ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)<br />
			crypt_stat->num_header_bytes_at_front =<br />
				ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;<br />
		else<br />
			crypt_stat->num_header_bytes_at_front =	PAGE_CACHE_SIZE;<br />
	}<br />
}</p>
<p>/**<br />
 * ecryptfs_compute_root_iv<br />
 * @crypt_stats<br />
 *<br />
 * On error, sets the root IV to all 0&#8217;s.<br />
 */<br />
int ecryptfs_compute_root_iv(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	int rc = 0;<br />
	char dst[MD5_DIGEST_SIZE];</p>
<p>	BUG_ON(crypt_stat->iv_bytes > MD5_DIGEST_SIZE);<br />
	BUG_ON(crypt_stat->iv_bytes <= 0);<br />
	if (!(crypt_stat->flags &#038; ECRYPTFS_KEY_VALID)) {<br />
		rc = -EINVAL;<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Session key not valid; &raquo;<br />
				&laquo;cannot generate root IV\n&raquo;);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_calculate_md5(dst, crypt_stat, crypt_stat->key,<br />
				    crypt_stat->key_size);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error attempting to compute &raquo;<br />
				&laquo;MD5 while generating root IV\n&raquo;);<br />
		goto out;<br />
	}<br />
	memcpy(crypt_stat->root_iv, dst, crypt_stat->iv_bytes);<br />
out:<br />
	if (rc) {<br />
		memset(crypt_stat->root_iv, 0, crypt_stat->iv_bytes);<br />
		crypt_stat->flags |= ECRYPTFS_SECURITY_WARNING;<br />
	}<br />
	return rc;<br />
}</p>
<p>static void ecryptfs_generate_new_key(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	get_random_bytes(crypt_stat->key, crypt_stat->key_size);<br />
	crypt_stat->flags |= ECRYPTFS_KEY_VALID;<br />
	ecryptfs_compute_root_iv(crypt_stat);<br />
	if (unlikely(ecryptfs_verbosity > 0)) {<br />
		ecryptfs_printk(KERN_DEBUG, &laquo;Generated new session key:\n&raquo;);<br />
		ecryptfs_dump_hex(crypt_stat->key,<br />
				  crypt_stat->key_size);<br />
	}<br />
}</p>
<p>/**<br />
 * ecryptfs_copy_mount_wide_flags_to_inode_flags<br />
 * @crypt_stat: The inode&#8217;s cryptographic context<br />
 * @mount_crypt_stat: The mount point&#8217;s cryptographic context<br />
 *<br />
 * This function propagates the mount-wide flags to individual inode<br />
 * flags.<br />
 */<br />
static void ecryptfs_copy_mount_wide_flags_to_inode_flags(<br />
	struct ecryptfs_crypt_stat *crypt_stat,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_XATTR_METADATA_ENABLED)<br />
		crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED_VIEW_ENABLED)<br />
		crypt_stat->flags |= ECRYPTFS_VIEW_AS_ENCRYPTED;<br />
	if (mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES) {<br />
		crypt_stat->flags |= ECRYPTFS_ENCRYPT_FILENAMES;<br />
		if (mount_crypt_stat->flags<br />
		    &#038; ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK)<br />
			crypt_stat->flags |= ECRYPTFS_ENCFN_USE_MOUNT_FNEK;<br />
		else if (mount_crypt_stat->flags<br />
			 &#038; ECRYPTFS_GLOBAL_ENCFN_USE_FEK)<br />
			crypt_stat->flags |= ECRYPTFS_ENCFN_USE_FEK;<br />
	}<br />
}</p>
<p>static int ecryptfs_copy_mount_wide_sigs_to_inode_sigs(<br />
	struct ecryptfs_crypt_stat *crypt_stat,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	struct ecryptfs_global_auth_tok *global_auth_tok;<br />
	int rc = 0;</p>
<p>	mutex_lock(&#038;crypt_stat->keysig_list_mutex);<br />
	mutex_lock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);</p>
<p>	list_for_each_entry(global_auth_tok,<br />
			    &#038;mount_crypt_stat->global_auth_tok_list,<br />
			    mount_crypt_stat_list) {<br />
		if (global_auth_tok->flags &#038; ECRYPTFS_AUTH_TOK_FNEK)<br />
			continue;<br />
		rc = ecryptfs_add_keysig(crypt_stat, global_auth_tok->sig);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error adding keysig; rc = [%d]\n&raquo;, rc);<br />
			goto out;<br />
		}<br />
	}</p>
<p>out:<br />
	mutex_unlock(&#038;mount_crypt_stat->global_auth_tok_list_mutex);<br />
	mutex_unlock(&#038;crypt_stat->keysig_list_mutex);<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_set_default_crypt_stat_vals<br />
 * @crypt_stat: The inode&#8217;s cryptographic context<br />
 * @mount_crypt_stat: The mount point&#8217;s cryptographic context<br />
 *<br />
 * Default values in the event that policy does not override them.<br />
 */<br />
static void ecryptfs_set_default_crypt_stat_vals(<br />
	struct ecryptfs_crypt_stat *crypt_stat,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,<br />
						      mount_crypt_stat);<br />
	ecryptfs_set_default_sizes(crypt_stat);<br />
	strcpy(crypt_stat->cipher, ECRYPTFS_DEFAULT_CIPHER);<br />
	crypt_stat->key_size = ECRYPTFS_DEFAULT_KEY_BYTES;<br />
	crypt_stat->flags &#038;= ~(ECRYPTFS_KEY_VALID);<br />
	crypt_stat->file_version = ECRYPTFS_FILE_VERSION;<br />
	crypt_stat->mount_crypt_stat = mount_crypt_stat;<br />
}</p>
<p>/**<br />
 * ecryptfs_new_file_context<br />
 * @ecryptfs_dentry: The eCryptfs dentry<br />
 *<br />
 * If the crypto context for the file has not yet been established,<br />
 * this is where we do that.  Establishing a new crypto context<br />
 * involves the following decisions:<br />
 *  &#8211; What cipher to use?<br />
 *  &#8211; What set of authentication tokens to use?<br />
 * Here we just worry about getting enough information into the<br />
 * authentication tokens so that we know that they are available.<br />
 * We associate the available authentication tokens with the new file<br />
 * via the set of signatures in the crypt_stat struct.  Later, when<br />
 * the headers are actually written out, we may again defer to<br />
 * userspace to perform the encryption of the session key; for the<br />
 * foreseeable future, this will be the case with public key packets.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
int ecryptfs_new_file_context(struct dentry *ecryptfs_dentry)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
	    &#038;ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
	    &#038;ecryptfs_superblock_to_private(<br />
		    ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	int cipher_name_len;<br />
	int rc = 0;</p>
<p>	ecryptfs_set_default_crypt_stat_vals(crypt_stat, mount_crypt_stat);<br />
	crypt_stat->flags |= (ECRYPTFS_ENCRYPTED | ECRYPTFS_KEY_VALID);<br />
	ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,<br />
						      mount_crypt_stat);<br />
	rc = ecryptfs_copy_mount_wide_sigs_to_inode_sigs(crypt_stat,<br />
							 mount_crypt_stat);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error attempting to copy mount-wide key sigs &raquo;<br />
		       &laquo;to the inode key sigs; rc = [%d]\n&raquo;, rc);<br />
		goto out;<br />
	}<br />
	cipher_name_len =<br />
		strlen(mount_crypt_stat->global_default_cipher_name);<br />
	memcpy(crypt_stat->cipher,<br />
	       mount_crypt_stat->global_default_cipher_name,<br />
	       cipher_name_len);<br />
	crypt_stat->cipher[cipher_name_len] = &#8216;\0&#8242;;<br />
	crypt_stat->key_size =<br />
		mount_crypt_stat->global_default_cipher_key_size;<br />
	ecryptfs_generate_new_key(crypt_stat);<br />
	rc = ecryptfs_init_crypt_ctx(crypt_stat);<br />
	if (rc)<br />
		ecryptfs_printk(KERN_ERR, &laquo;Error initializing cryptographic &raquo;<br />
				&laquo;context for cipher [%s]: rc = [%d]\n&raquo;,<br />
				crypt_stat->cipher, rc);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * contains_ecryptfs_marker &#8211; check for the ecryptfs marker<br />
 * @data: The data block in which to check<br />
 *<br />
 * Returns one if marker found; zero if not found<br />
 */<br />
static int contains_ecryptfs_marker(char *data)<br />
{<br />
	u32 m_1, m_2;</p>
<p>	m_1 = get_unaligned_be32(data);<br />
	m_2 = get_unaligned_be32(data + 4);<br />
	if ((m_1 ^ MAGIC_ECRYPTFS_MARKER) == m_2)<br />
		return 1;<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;m_1 = [0x%.8x]; m_2 = [0x%.8x]; &raquo;<br />
			&laquo;MAGIC_ECRYPTFS_MARKER = [0x%.8x]\n&raquo;, m_1, m_2,<br />
			MAGIC_ECRYPTFS_MARKER);<br />
	ecryptfs_printk(KERN_DEBUG, &laquo;(m_1 ^ MAGIC_ECRYPTFS_MARKER) = &raquo;<br />
			&laquo;[0x%.8x]\n&raquo;, (m_1 ^ MAGIC_ECRYPTFS_MARKER));<br />
	return 0;<br />
}</p>
<p>struct ecryptfs_flag_map_elem {<br />
	u32 file_flag;<br />
	u32 local_flag;<br />
};</p>
<p>/* Add support for additional flags by adding elements here. */<br />
static struct ecryptfs_flag_map_elem ecryptfs_flag_map[] = {<br />
	{0&#215;00000001, ECRYPTFS_ENABLE_HMAC},<br />
	{0&#215;00000002, ECRYPTFS_ENCRYPTED},<br />
	{0&#215;00000004, ECRYPTFS_METADATA_IN_XATTR},<br />
	{0&#215;00000008, ECRYPTFS_ENCRYPT_FILENAMES}<br />
};</p>
<p>/**<br />
 * ecryptfs_process_flags<br />
 * @crypt_stat: The cryptographic context<br />
 * @page_virt: Source data to be parsed<br />
 * @bytes_read: Updated with the number of bytes read<br />
 *<br />
 * Returns zero on success; non-zero if the flag set is invalid<br />
 */<br />
static int ecryptfs_process_flags(struct ecryptfs_crypt_stat *crypt_stat,<br />
				  char *page_virt, int *bytes_read)<br />
{<br />
	int rc = 0;<br />
	int i;<br />
	u32 flags;</p>
<p>	flags = get_unaligned_be32(page_virt);<br />
	for (i = 0; i < ((sizeof(ecryptfs_flag_map)<br />
			  / sizeof(struct ecryptfs_flag_map_elem))); i++)<br />
		if (flags &#038; ecryptfs_flag_map[i].file_flag) {<br />
			crypt_stat->flags |= ecryptfs_flag_map[i].local_flag;<br />
		} else<br />
			crypt_stat->flags &#038;= ~(ecryptfs_flag_map[i].local_flag);<br />
	/* Version is in top 8 bits of the 32-bit flag vector */<br />
	crypt_stat->file_version = ((flags >> 24) &#038; 0xFF);<br />
	(*bytes_read) = 4;<br />
	return rc;<br />
}</p>
<p>/**<br />
 * write_ecryptfs_marker<br />
 * @page_virt: The pointer to in a page to begin writing the marker<br />
 * @written: Number of bytes written<br />
 *<br />
 * Marker = 0&#215;3c81b7f5<br />
 */<br />
static void write_ecryptfs_marker(char *page_virt, size_t *written)<br />
{<br />
	u32 m_1, m_2;</p>
<p>	get_random_bytes(&#038;m_1, (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2));<br />
	m_2 = (m_1 ^ MAGIC_ECRYPTFS_MARKER);<br />
	put_unaligned_be32(m_1, page_virt);<br />
	page_virt += (MAGIC_ECRYPTFS_MARKER_SIZE_BYTES / 2);<br />
	put_unaligned_be32(m_2, page_virt);<br />
	(*written) = MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;<br />
}</p>
<p>static void<br />
write_ecryptfs_flags(char *page_virt, struct ecryptfs_crypt_stat *crypt_stat,<br />
		     size_t *written)<br />
{<br />
	u32 flags = 0;<br />
	int i;</p>
<p>	for (i = 0; i < ((sizeof(ecryptfs_flag_map)<br />
			  / sizeof(struct ecryptfs_flag_map_elem))); i++)<br />
		if (crypt_stat->flags &#038; ecryptfs_flag_map[i].local_flag)<br />
			flags |= ecryptfs_flag_map[i].file_flag;<br />
	/* Version is in top 8 bits of the 32-bit flag vector */<br />
	flags |= ((((u8)crypt_stat->file_version) << 24) &#038; 0xFF000000);<br />
	put_unaligned_be32(flags, page_virt);<br />
	(*written) = 4;<br />
}</p>
<p>struct ecryptfs_cipher_code_str_map_elem {<br />
	char cipher_str[16];<br />
	u8 cipher_code;<br />
};</p>
<p>/* Add support for additional ciphers by adding elements here. The<br />
 * cipher_code is whatever OpenPGP applicatoins use to identify the<br />
 * ciphers. List in order of probability. */<br />
static struct ecryptfs_cipher_code_str_map_elem<br />
ecryptfs_cipher_code_str_map[] = {<br />
	{"aes",RFC2440_CIPHER_AES_128 },<br />
	{"blowfish", RFC2440_CIPHER_BLOWFISH},<br />
	{"des3_ede", RFC2440_CIPHER_DES3_EDE},<br />
	{"cast5", RFC2440_CIPHER_CAST_5},<br />
	{"twofish", RFC2440_CIPHER_TWOFISH},<br />
	{"cast6", RFC2440_CIPHER_CAST_6},<br />
	{"aes", RFC2440_CIPHER_AES_192},<br />
	{"aes", RFC2440_CIPHER_AES_256}<br />
};</p>
<p>/**<br />
 * ecryptfs_code_for_cipher_string<br />
 * @cipher_name: The string alias for the cipher<br />
 * @key_bytes: Length of key in bytes; used for AES code selection<br />
 *<br />
 * Returns zero on no match, or the cipher code on match<br />
 */<br />
u8 ecryptfs_code_for_cipher_string(char *cipher_name, size_t key_bytes)<br />
{<br />
	int i;<br />
	u8 code = 0;<br />
	struct ecryptfs_cipher_code_str_map_elem *map =<br />
		ecryptfs_cipher_code_str_map;</p>
<p>	if (strcmp(cipher_name, "aes") == 0) {<br />
		switch (key_bytes) {<br />
		case 16:<br />
			code = RFC2440_CIPHER_AES_128;<br />
			break;<br />
		case 24:<br />
			code = RFC2440_CIPHER_AES_192;<br />
			break;<br />
		case 32:<br />
			code = RFC2440_CIPHER_AES_256;<br />
		}<br />
	} else {<br />
		for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)<br />
			if (strcmp(cipher_name, map[i].cipher_str) == 0) {<br />
				code = map[i].cipher_code;<br />
				break;<br />
			}<br />
	}<br />
	return code;<br />
}</p>
<p>/**<br />
 * ecryptfs_cipher_code_to_string<br />
 * @str: Destination to write out the cipher name<br />
 * @cipher_code: The code to convert to cipher name string<br />
 *<br />
 * Returns zero on success<br />
 */<br />
int ecryptfs_cipher_code_to_string(char *str, u8 cipher_code)<br />
{<br />
	int rc = 0;<br />
	int i;</p>
<p>	str[0] = '\0';<br />
	for (i = 0; i < ARRAY_SIZE(ecryptfs_cipher_code_str_map); i++)<br />
		if (cipher_code == ecryptfs_cipher_code_str_map[i].cipher_code)<br />
			strcpy(str, ecryptfs_cipher_code_str_map[i].cipher_str);<br />
	if (str[0] == '\0') {<br />
		ecryptfs_printk(KERN_WARNING, "Cipher code not recognized: "<br />
				"[%d]\n", cipher_code);<br />
		rc = -EINVAL;<br />
	}<br />
	return rc;<br />
}</p>
<p>int ecryptfs_read_and_validate_header_region(char *data,<br />
					     struct inode *ecryptfs_inode)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
		&#038;(ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat);<br />
	int rc;</p>
<p>	if (crypt_stat->extent_size == 0)<br />
		crypt_stat->extent_size = ECRYPTFS_DEFAULT_EXTENT_SIZE;<br />
	rc = ecryptfs_read_lower(data, 0, crypt_stat->extent_size,<br />
				 ecryptfs_inode);<br />
	if (rc < 0) {<br />
		printk(KERN_ERR "%s: Error reading header region; rc = [%d]\n",<br />
		       __func__, rc);<br />
		goto out;<br />
	}<br />
	if (!contains_ecryptfs_marker(data + ECRYPTFS_FILE_SIZE_BYTES)) {<br />
		rc = -EINVAL;<br />
	} else<br />
		rc = 0;<br />
out:<br />
	return rc;<br />
}</p>
<p>void<br />
ecryptfs_write_header_metadata(char *virt,<br />
			       struct ecryptfs_crypt_stat *crypt_stat,<br />
			       size_t *written)<br />
{<br />
	u32 header_extent_size;<br />
	u16 num_header_extents_at_front;</p>
<p>	header_extent_size = (u32)crypt_stat->extent_size;<br />
	num_header_extents_at_front =<br />
		(u16)(crypt_stat->num_header_bytes_at_front<br />
		      / crypt_stat->extent_size);<br />
	put_unaligned_be32(header_extent_size, virt);<br />
	virt += 4;<br />
	put_unaligned_be16(num_header_extents_at_front, virt);<br />
	(*written) = 6;<br />
}</p>
<p>struct kmem_cache *ecryptfs_header_cache_1;<br />
struct kmem_cache *ecryptfs_header_cache_2;</p>
<p>/**<br />
 * ecryptfs_write_headers_virt<br />
 * @page_virt: The virtual address to write the headers to<br />
 * @max: The size of memory allocated at page_virt<br />
 * @size: Set to the number of bytes written by this function<br />
 * @crypt_stat: The cryptographic context<br />
 * @ecryptfs_dentry: The eCryptfs dentry<br />
 *<br />
 * Format version: 1<br />
 *<br />
 *   Header Extent:<br />
 *     Octets 0-7:        Unencrypted file size (big-endian)<br />
 *     Octets 8-15:       eCryptfs special marker<br />
 *     Octets 16-19:      Flags<br />
 *      Octet 16:         File format version number (between 0 and 255)<br />
 *      Octets 17-18:     Reserved<br />
 *      Octet 19:         Bit 1 (lsb): Reserved<br />
 *                        Bit 2: Encrypted?<br />
 *                        Bits 3-8: Reserved<br />
 *     Octets 20-23:      Header extent size (big-endian)<br />
 *     Octets 24-25:      Number of header extents at front of file<br />
 *                        (big-endian)<br />
 *     Octet  26:         Begin RFC 2440 authentication token packet set<br />
 *   Data Extent 0:<br />
 *     Lower data (CBC encrypted)<br />
 *   Data Extent 1:<br />
 *     Lower data (CBC encrypted)<br />
 *   &#8230;<br />
 *<br />
 * Returns zero on success<br />
 */<br />
static int ecryptfs_write_headers_virt(char *page_virt, size_t max,<br />
				       size_t *size,<br />
				       struct ecryptfs_crypt_stat *crypt_stat,<br />
				       struct dentry *ecryptfs_dentry)<br />
{<br />
	int rc;<br />
	size_t written;<br />
	size_t offset;</p>
<p>	offset = ECRYPTFS_FILE_SIZE_BYTES;<br />
	write_ecryptfs_marker((page_virt + offset), &#038;written);<br />
	offset += written;<br />
	write_ecryptfs_flags((page_virt + offset), crypt_stat, &#038;written);<br />
	offset += written;<br />
	ecryptfs_write_header_metadata((page_virt + offset), crypt_stat,<br />
				       &#038;written);<br />
	offset += written;<br />
	rc = ecryptfs_generate_key_packet_set((page_virt + offset), crypt_stat,<br />
					      ecryptfs_dentry, &#038;written,<br />
					      max &#8211; offset);<br />
	if (rc)<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error generating key packet &raquo;<br />
				&laquo;set; rc = [%d]\n&raquo;, rc);<br />
	if (size) {<br />
		offset += written;<br />
		*size = offset;<br />
	}<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_write_metadata_to_contents(struct dentry *ecryptfs_dentry,<br />
				    char *virt, size_t virt_len)<br />
{<br />
	int rc;</p>
<p>	rc = ecryptfs_write_lower(ecryptfs_dentry->d_inode, virt,<br />
				  0, virt_len);<br />
	if (rc < 0)<br />
		printk(KERN_ERR "%s: Error attempting to write header "<br />
		       "information to lower file; rc = [%d]\n", __func__, rc);<br />
	else<br />
		rc = 0;<br />
	return rc;<br />
}</p>
<p>static int<br />
ecryptfs_write_metadata_to_xattr(struct dentry *ecryptfs_dentry,<br />
				 char *page_virt, size_t size)<br />
{<br />
	int rc;</p>
<p>	rc = ecryptfs_setxattr(ecryptfs_dentry, ECRYPTFS_XATTR_NAME, page_virt,<br />
			       size, 0);<br />
	return rc;<br />
}</p>
<p>static unsigned long ecryptfs_get_zeroed_pages(gfp_t gfp_mask,<br />
					       unsigned int order)<br />
{<br />
	struct page *page;</p>
<p>	page = alloc_pages(gfp_mask | __GFP_ZERO, order);<br />
	if (page)<br />
		return (unsigned long) page_address(page);<br />
	return 0;<br />
}</p>
<p>/**<br />
 * ecryptfs_write_metadata<br />
 * @ecryptfs_dentry: The eCryptfs dentry<br />
 *<br />
 * Write the file headers out.  This will likely involve a userspace<br />
 * callout, in which the session key is encrypted with one or more<br />
 * public keys and/or the passphrase necessary to do the encryption is<br />
 * retrieved via a prompt.  Exactly what happens at this point should<br />
 * be policy-dependent.<br />
 *<br />
 * Returns zero on success; non-zero on error<br />
 */<br />
int ecryptfs_write_metadata(struct dentry *ecryptfs_dentry)<br />
{<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
		&#038;ecryptfs_inode_to_private(ecryptfs_dentry->d_inode)->crypt_stat;<br />
	unsigned int order;<br />
	char *virt;<br />
	size_t virt_len;<br />
	size_t size = 0;<br />
	int rc = 0;</p>
<p>	if (likely(crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED)) {<br />
		if (!(crypt_stat->flags &#038; ECRYPTFS_KEY_VALID)) {<br />
			printk(KERN_ERR &laquo;Key is invalid; bailing out\n&raquo;);<br />
			rc = -EINVAL;<br />
			goto out;<br />
		}<br />
	} else {<br />
		printk(KERN_WARNING &laquo;%s: Encrypted flag not set\n&raquo;,<br />
		       __func__);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	virt_len = crypt_stat->num_header_bytes_at_front;<br />
	order = get_order(virt_len);<br />
	/* Released in this function */<br />
	virt = (char *)ecryptfs_get_zeroed_pages(GFP_KERNEL, order);<br />
	if (!virt) {<br />
		printk(KERN_ERR &laquo;%s: Out of memory\n&raquo;, __func__);<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_write_headers_virt(virt, virt_len, &#038;size, crypt_stat,<br />
					 ecryptfs_dentry);<br />
	if (unlikely(rc)) {<br />
		printk(KERN_ERR &laquo;%s: Error whilst writing headers; rc = [%d]\n&raquo;,<br />
		       __func__, rc);<br />
		goto out_free;<br />
	}<br />
	if (crypt_stat->flags &#038; ECRYPTFS_METADATA_IN_XATTR)<br />
		rc = ecryptfs_write_metadata_to_xattr(ecryptfs_dentry, virt,<br />
						      size);<br />
	else<br />
		rc = ecryptfs_write_metadata_to_contents(ecryptfs_dentry, virt,<br />
							 virt_len);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;%s: Error writing metadata out to lower file; &raquo;<br />
		       &laquo;rc = [%d]\n&raquo;, __func__, rc);<br />
		goto out_free;<br />
	}<br />
out_free:<br />
	free_pages((unsigned long)virt, order);<br />
out:<br />
	return rc;<br />
}</p>
<p>#define ECRYPTFS_DONT_VALIDATE_HEADER_SIZE 0<br />
#define ECRYPTFS_VALIDATE_HEADER_SIZE 1<br />
static int parse_header_metadata(struct ecryptfs_crypt_stat *crypt_stat,<br />
				 char *virt, int *bytes_read,<br />
				 int validate_header_size)<br />
{<br />
	int rc = 0;<br />
	u32 header_extent_size;<br />
	u16 num_header_extents_at_front;</p>
<p>	header_extent_size = get_unaligned_be32(virt);<br />
	virt += sizeof(__be32);<br />
	num_header_extents_at_front = get_unaligned_be16(virt);<br />
	crypt_stat->num_header_bytes_at_front =<br />
		(((size_t)num_header_extents_at_front<br />
		  * (size_t)header_extent_size));<br />
	(*bytes_read) = (sizeof(__be32) + sizeof(__be16));<br />
	if ((validate_header_size == ECRYPTFS_VALIDATE_HEADER_SIZE)<br />
	    &#038;&#038; (crypt_stat->num_header_bytes_at_front<br />
		< ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE)) {<br />
		rc = -EINVAL;<br />
		printk(KERN_WARNING "Invalid header size: [%zd]\n",<br />
		       crypt_stat->num_header_bytes_at_front);<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * set_default_header_data<br />
 * @crypt_stat: The cryptographic context<br />
 *<br />
 * For version 0 file format; this function is only for backwards<br />
 * compatibility for files created with the prior versions of<br />
 * eCryptfs.<br />
 */<br />
static void set_default_header_data(struct ecryptfs_crypt_stat *crypt_stat)<br />
{<br />
	crypt_stat->num_header_bytes_at_front =<br />
		ECRYPTFS_MINIMUM_HEADER_EXTENT_SIZE;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_headers_virt<br />
 * @page_virt: The virtual address into which to read the headers<br />
 * @crypt_stat: The cryptographic context<br />
 * @ecryptfs_dentry: The eCryptfs dentry<br />
 * @validate_header_size: Whether to validate the header size while reading<br />
 *<br />
 * Read/parse the header data. The header format is detailed in the<br />
 * comment block for the ecryptfs_write_headers_virt() function.<br />
 *<br />
 * Returns zero on success<br />
 */<br />
static int ecryptfs_read_headers_virt(char *page_virt,<br />
				      struct ecryptfs_crypt_stat *crypt_stat,<br />
				      struct dentry *ecryptfs_dentry,<br />
				      int validate_header_size)<br />
{<br />
	int rc = 0;<br />
	int offset;<br />
	int bytes_read;</p>
<p>	ecryptfs_set_default_sizes(crypt_stat);<br />
	crypt_stat->mount_crypt_stat = &#038;ecryptfs_superblock_to_private(<br />
		ecryptfs_dentry->d_sb)->mount_crypt_stat;<br />
	offset = ECRYPTFS_FILE_SIZE_BYTES;<br />
	rc = contains_ecryptfs_marker(page_virt + offset);<br />
	if (rc == 0) {<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	offset += MAGIC_ECRYPTFS_MARKER_SIZE_BYTES;<br />
	rc = ecryptfs_process_flags(crypt_stat, (page_virt + offset),<br />
				    &#038;bytes_read);<br />
	if (rc) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;Error processing flags\n&raquo;);<br />
		goto out;<br />
	}<br />
	if (crypt_stat->file_version > ECRYPTFS_SUPPORTED_FILE_VERSION) {<br />
		ecryptfs_printk(KERN_WARNING, &laquo;File version is [%d]; only &raquo;<br />
				&laquo;file version [%d] is supported by this &raquo;<br />
				&laquo;version of eCryptfs\n&raquo;,<br />
				crypt_stat->file_version,<br />
				ECRYPTFS_SUPPORTED_FILE_VERSION);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
	offset += bytes_read;<br />
	if (crypt_stat->file_version >= 1) {<br />
		rc = parse_header_metadata(crypt_stat, (page_virt + offset),<br />
					   &#038;bytes_read, validate_header_size);<br />
		if (rc) {<br />
			ecryptfs_printk(KERN_WARNING, &laquo;Error reading header &raquo;<br />
					&laquo;metadata; rc = [%d]\n&raquo;, rc);<br />
		}<br />
		offset += bytes_read;<br />
	} else<br />
		set_default_header_data(crypt_stat);<br />
	rc = ecryptfs_parse_packet_set(crypt_stat, (page_virt + offset),<br />
				       ecryptfs_dentry);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_xattr_region<br />
 * @page_virt: The vitual address into which to read the xattr data<br />
 * @ecryptfs_inode: The eCryptfs inode<br />
 *<br />
 * Attempts to read the crypto metadata from the extended attribute<br />
 * region of the lower file.<br />
 *<br />
 * Returns zero on success; non-zero on error<br />
 */<br />
int ecryptfs_read_xattr_region(char *page_virt, struct inode *ecryptfs_inode)<br />
{<br />
	struct dentry *lower_dentry =<br />
		ecryptfs_inode_to_private(ecryptfs_inode)->lower_file->f_dentry;<br />
	ssize_t size;<br />
	int rc = 0;</p>
<p>	size = ecryptfs_getxattr_lower(lower_dentry, ECRYPTFS_XATTR_NAME,<br />
				       page_virt, ECRYPTFS_DEFAULT_EXTENT_SIZE);<br />
	if (size < 0) {<br />
		if (unlikely(ecryptfs_verbosity > 0))<br />
			printk(KERN_INFO &laquo;Error attempting to read the [%s] &raquo;<br />
			       &laquo;xattr from the lower file; return value = &raquo;<br />
			       &laquo;[%zd]\n&raquo;, ECRYPTFS_XATTR_NAME, size);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>int ecryptfs_read_and_validate_xattr_region(char *page_virt,<br />
					    struct dentry *ecryptfs_dentry)<br />
{<br />
	int rc;</p>
<p>	rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_dentry->d_inode);<br />
	if (rc)<br />
		goto out;<br />
	if (!contains_ecryptfs_marker(page_virt	+ ECRYPTFS_FILE_SIZE_BYTES)) {<br />
		printk(KERN_WARNING &laquo;Valid data found in [%s] xattr, but &raquo;<br />
			&laquo;the marker is invalid\n&raquo;, ECRYPTFS_XATTR_NAME);<br />
		rc = -EINVAL;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_read_metadata<br />
 *<br />
 * Common entry point for reading file metadata. From here, we could<br />
 * retrieve the header information from the header region of the file,<br />
 * the xattr region of the file, or some other repostory that is<br />
 * stored separately from the file itself. The current implementation<br />
 * supports retrieving the metadata information from the file contents<br />
 * and from the xattr region.<br />
 *<br />
 * Returns zero if valid headers found and parsed; non-zero otherwise<br />
 */<br />
int ecryptfs_read_metadata(struct dentry *ecryptfs_dentry)<br />
{<br />
	int rc = 0;<br />
	char *page_virt = NULL;<br />
	struct inode *ecryptfs_inode = ecryptfs_dentry->d_inode;<br />
	struct ecryptfs_crypt_stat *crypt_stat =<br />
	    &#038;ecryptfs_inode_to_private(ecryptfs_inode)->crypt_stat;<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		&#038;ecryptfs_superblock_to_private(<br />
			ecryptfs_dentry->d_sb)->mount_crypt_stat;</p>
<p>	ecryptfs_copy_mount_wide_flags_to_inode_flags(crypt_stat,<br />
						      mount_crypt_stat);<br />
	/* Read the first page from the underlying file */<br />
	page_virt = kmem_cache_alloc(ecryptfs_header_cache_1, GFP_USER);<br />
	if (!page_virt) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;%s: Unable to allocate page_virt\n&raquo;,<br />
		       __func__);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_read_lower(page_virt, 0, crypt_stat->extent_size,<br />
				 ecryptfs_inode);<br />
	if (rc >= 0)<br />
		rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,<br />
						ecryptfs_dentry,<br />
						ECRYPTFS_VALIDATE_HEADER_SIZE);<br />
	if (rc) {<br />
		rc = ecryptfs_read_xattr_region(page_virt, ecryptfs_inode);<br />
		if (rc) {<br />
			printk(KERN_DEBUG &laquo;Valid eCryptfs headers not found in &raquo;<br />
			       &laquo;file header region or xattr region\n&raquo;);<br />
			rc = -EINVAL;<br />
			goto out;<br />
		}<br />
		rc = ecryptfs_read_headers_virt(page_virt, crypt_stat,<br />
						ecryptfs_dentry,<br />
						ECRYPTFS_DONT_VALIDATE_HEADER_SIZE);<br />
		if (rc) {<br />
			printk(KERN_DEBUG &laquo;Valid eCryptfs headers not found in &raquo;<br />
			       &laquo;file xattr region either\n&raquo;);<br />
			rc = -EINVAL;<br />
		}<br />
		if (crypt_stat->mount_crypt_stat->flags<br />
		    &#038; ECRYPTFS_XATTR_METADATA_ENABLED) {<br />
			crypt_stat->flags |= ECRYPTFS_METADATA_IN_XATTR;<br />
		} else {<br />
			printk(KERN_WARNING &laquo;Attempt to access file with &raquo;<br />
			       &laquo;crypto metadata only in the extended attribute &raquo;<br />
			       &laquo;region, but eCryptfs was mounted without &raquo;<br />
			       &laquo;xattr support enabled. eCryptfs will not treat &raquo;<br />
			       &laquo;this like an encrypted file.\n&raquo;);<br />
			rc = -EINVAL;<br />
		}<br />
	}<br />
out:<br />
	if (page_virt) {<br />
		memset(page_virt, 0, PAGE_CACHE_SIZE);<br />
		kmem_cache_free(ecryptfs_header_cache_1, page_virt);<br />
	}<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_encrypt_filename &#8211; encrypt filename<br />
 *<br />
 * CBC-encrypts the filename. We do not want to encrypt the same<br />
 * filename with the same key and IV, which may happen with hard<br />
 * links, so we prepend random bits to each filename.<br />
 *<br />
 * Returns zero on success; non-zero otherwise<br />
 */<br />
static int<br />
ecryptfs_encrypt_filename(struct ecryptfs_filename *filename,<br />
			  struct ecryptfs_crypt_stat *crypt_stat,<br />
			  struct ecryptfs_mount_crypt_stat *mount_crypt_stat)<br />
{<br />
	int rc = 0;</p>
<p>	filename->encrypted_filename = NULL;<br />
	filename->encrypted_filename_size = 0;<br />
	if ((crypt_stat &#038;&#038; (crypt_stat->flags &#038; ECRYPTFS_ENCFN_USE_MOUNT_FNEK))<br />
	    || (mount_crypt_stat &#038;&#038; (mount_crypt_stat->flags<br />
				     &#038; ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK))) {<br />
		size_t packet_size;<br />
		size_t remaining_bytes;</p>
<p>		rc = ecryptfs_write_tag_70_packet(<br />
			NULL, NULL,<br />
			&#038;filename->encrypted_filename_size,<br />
			mount_crypt_stat, NULL,<br />
			filename->filename_size);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to get packet &raquo;<br />
			       &laquo;size for tag 72; rc = [%d]\n&raquo;, __func__,<br />
			       rc);<br />
			filename->encrypted_filename_size = 0;<br />
			goto out;<br />
		}<br />
		filename->encrypted_filename =<br />
			kmalloc(filename->encrypted_filename_size, GFP_KERNEL);<br />
		if (!filename->encrypted_filename) {<br />
			printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
			       &laquo;to kmalloc [%zd] bytes\n&raquo;, __func__,<br />
			       filename->encrypted_filename_size);<br />
			rc = -ENOMEM;<br />
			goto out;<br />
		}<br />
		remaining_bytes = filename->encrypted_filename_size;<br />
		rc = ecryptfs_write_tag_70_packet(filename->encrypted_filename,<br />
						  &#038;remaining_bytes,<br />
						  &#038;packet_size,<br />
						  mount_crypt_stat,<br />
						  filename->filename,<br />
						  filename->filename_size);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to generate &raquo;<br />
			       &laquo;tag 70 packet; rc = [%d]\n&raquo;, __func__,<br />
			       rc);<br />
			kfree(filename->encrypted_filename);<br />
			filename->encrypted_filename = NULL;<br />
			filename->encrypted_filename_size = 0;<br />
			goto out;<br />
		}<br />
		filename->encrypted_filename_size = packet_size;<br />
	} else {<br />
		printk(KERN_ERR &laquo;%s: No support for requested filename &raquo;<br />
		       &laquo;encryption method in this release\n&raquo;, __func__);<br />
		rc = -EOPNOTSUPP;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>static int ecryptfs_copy_filename(char **copied_name, size_t *copied_name_size,<br />
				  const char *name, size_t name_size)<br />
{<br />
	int rc = 0;</p>
<p>	(*copied_name) = kmalloc((name_size + 1), GFP_KERNEL);<br />
	if (!(*copied_name)) {<br />
		rc = -ENOMEM;<br />
		goto out;<br />
	}<br />
	memcpy((void *)(*copied_name), (void *)name, name_size);<br />
	(*copied_name)[(name_size)] = &#8216;\0&#8242;;	/* Only for convenience<br />
						 * in printing out the<br />
						 * string in debug<br />
						 * messages */<br />
	(*copied_name_size) = name_size;<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_process_key_cipher &#8211; Perform key cipher initialization.<br />
 * @key_tfm: Crypto context for key material, set by this function<br />
 * @cipher_name: Name of the cipher<br />
 * @key_size: Size of the key in bytes<br />
 *<br />
 * Returns zero on success. Any crypto_tfm structs allocated here<br />
 * should be released by other functions, such as on a superblock put<br />
 * event, regardless of whether this function succeeds for fails.<br />
 */<br />
static int<br />
ecryptfs_process_key_cipher(struct crypto_blkcipher **key_tfm,<br />
			    char *cipher_name, size_t *key_size)<br />
{<br />
	char dummy_key[ECRYPTFS_MAX_KEY_BYTES];<br />
	char *full_alg_name;<br />
	int rc;</p>
<p>	*key_tfm = NULL;<br />
	if (*key_size > ECRYPTFS_MAX_KEY_BYTES) {<br />
		rc = -EINVAL;<br />
		printk(KERN_ERR &laquo;Requested key size is [%zd] bytes; maximum &raquo;<br />
		      &laquo;allowable is [%d]\n&raquo;, *key_size, ECRYPTFS_MAX_KEY_BYTES);<br />
		goto out;<br />
	}<br />
	rc = ecryptfs_crypto_api_algify_cipher_name(&#038;full_alg_name, cipher_name,<br />
						    &laquo;ecb&raquo;);<br />
	if (rc)<br />
		goto out;<br />
	*key_tfm = crypto_alloc_blkcipher(full_alg_name, 0, CRYPTO_ALG_ASYNC);<br />
	kfree(full_alg_name);<br />
	if (IS_ERR(*key_tfm)) {<br />
		rc = PTR_ERR(*key_tfm);<br />
		printk(KERN_ERR &laquo;Unable to allocate crypto cipher with name &raquo;<br />
		       &laquo;[%s]; rc = [%d]\n&raquo;, full_alg_name, rc);<br />
		goto out;<br />
	}<br />
	crypto_blkcipher_set_flags(*key_tfm, CRYPTO_TFM_REQ_WEAK_KEY);<br />
	if (*key_size == 0) {<br />
		struct blkcipher_alg *alg = crypto_blkcipher_alg(*key_tfm);</p>
<p>		*key_size = alg->max_keysize;<br />
	}<br />
	get_random_bytes(dummy_key, *key_size);<br />
	rc = crypto_blkcipher_setkey(*key_tfm, dummy_key, *key_size);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error attempting to set key of size [%zd] for &raquo;<br />
		       &laquo;cipher [%s]; rc = [%d]\n&raquo;, *key_size, full_alg_name,<br />
		       rc);<br />
		rc = -EINVAL;<br />
		goto out;<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>struct kmem_cache *ecryptfs_key_tfm_cache;<br />
static struct list_head key_tfm_list;<br />
struct mutex key_tfm_list_mutex;</p>
<p>int ecryptfs_init_crypto(void)<br />
{<br />
	mutex_init(&#038;key_tfm_list_mutex);<br />
	INIT_LIST_HEAD(&#038;key_tfm_list);<br />
	return 0;<br />
}</p>
<p>/**<br />
 * ecryptfs_destroy_crypto &#8211; free all cached key_tfms on key_tfm_list<br />
 *<br />
 * Called only at module unload time<br />
 */<br />
int ecryptfs_destroy_crypto(void)<br />
{<br />
	struct ecryptfs_key_tfm *key_tfm, *key_tfm_tmp;</p>
<p>	mutex_lock(&#038;key_tfm_list_mutex);<br />
	list_for_each_entry_safe(key_tfm, key_tfm_tmp, &#038;key_tfm_list,<br />
				 key_tfm_list) {<br />
		list_del(&#038;key_tfm->key_tfm_list);<br />
		if (key_tfm->key_tfm)<br />
			crypto_free_blkcipher(key_tfm->key_tfm);<br />
		kmem_cache_free(ecryptfs_key_tfm_cache, key_tfm);<br />
	}<br />
	mutex_unlock(&#038;key_tfm_list_mutex);<br />
	return 0;<br />
}</p>
<p>int<br />
ecryptfs_add_new_key_tfm(struct ecryptfs_key_tfm **key_tfm, char *cipher_name,<br />
			 size_t key_size)<br />
{<br />
	struct ecryptfs_key_tfm *tmp_tfm;<br />
	int rc = 0;</p>
<p>	BUG_ON(!mutex_is_locked(&#038;key_tfm_list_mutex));</p>
<p>	tmp_tfm = kmem_cache_alloc(ecryptfs_key_tfm_cache, GFP_KERNEL);<br />
	if (key_tfm != NULL)<br />
		(*key_tfm) = tmp_tfm;<br />
	if (!tmp_tfm) {<br />
		rc = -ENOMEM;<br />
		printk(KERN_ERR &laquo;Error attempting to allocate from &raquo;<br />
		       &laquo;ecryptfs_key_tfm_cache\n&raquo;);<br />
		goto out;<br />
	}<br />
	mutex_init(&#038;tmp_tfm->key_tfm_mutex);<br />
	strncpy(tmp_tfm->cipher_name, cipher_name,<br />
		ECRYPTFS_MAX_CIPHER_NAME_SIZE);<br />
	tmp_tfm->cipher_name[ECRYPTFS_MAX_CIPHER_NAME_SIZE] = &#8216;\0&#8242;;<br />
	tmp_tfm->key_size = key_size;<br />
	rc = ecryptfs_process_key_cipher(&#038;tmp_tfm->key_tfm,<br />
					 tmp_tfm->cipher_name,<br />
					 &#038;tmp_tfm->key_size);<br />
	if (rc) {<br />
		printk(KERN_ERR &laquo;Error attempting to initialize key TFM &raquo;<br />
		       &laquo;cipher with name = [%s]; rc = [%d]\n&raquo;,<br />
		       tmp_tfm->cipher_name, rc);<br />
		kmem_cache_free(ecryptfs_key_tfm_cache, tmp_tfm);<br />
		if (key_tfm != NULL)<br />
			(*key_tfm) = NULL;<br />
		goto out;<br />
	}<br />
	list_add(&#038;tmp_tfm->key_tfm_list, &#038;key_tfm_list);<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_tfm_exists &#8211; Search for existing tfm for cipher_name.<br />
 * @cipher_name: the name of the cipher to search for<br />
 * @key_tfm: set to corresponding tfm if found<br />
 *<br />
 * Searches for cached key_tfm matching @cipher_name<br />
 * Must be called with &#038;key_tfm_list_mutex held<br />
 * Returns 1 if found, with @key_tfm set<br />
 * Returns 0 if not found, with @key_tfm set to NULL<br />
 */<br />
int ecryptfs_tfm_exists(char *cipher_name, struct ecryptfs_key_tfm **key_tfm)<br />
{<br />
	struct ecryptfs_key_tfm *tmp_key_tfm;</p>
<p>	BUG_ON(!mutex_is_locked(&#038;key_tfm_list_mutex));</p>
<p>	list_for_each_entry(tmp_key_tfm, &#038;key_tfm_list, key_tfm_list) {<br />
		if (strcmp(tmp_key_tfm->cipher_name, cipher_name) == 0) {<br />
			if (key_tfm)<br />
				(*key_tfm) = tmp_key_tfm;<br />
			return 1;<br />
		}<br />
	}<br />
	if (key_tfm)<br />
		(*key_tfm) = NULL;<br />
	return 0;<br />
}</p>
<p>/**<br />
 * ecryptfs_get_tfm_and_mutex_for_cipher_name<br />
 *<br />
 * @tfm: set to cached tfm found, or new tfm created<br />
 * @tfm_mutex: set to mutex for cached tfm found, or new tfm created<br />
 * @cipher_name: the name of the cipher to search for and/or add<br />
 *<br />
 * Sets pointers to @tfm &#038; @tfm_mutex matching @cipher_name.<br />
 * Searches for cached item first, and creates new if not found.<br />
 * Returns 0 on success, non-zero if adding new cipher failed<br />
 */<br />
int ecryptfs_get_tfm_and_mutex_for_cipher_name(struct crypto_blkcipher **tfm,<br />
					       struct mutex **tfm_mutex,<br />
					       char *cipher_name)<br />
{<br />
	struct ecryptfs_key_tfm *key_tfm;<br />
	int rc = 0;</p>
<p>	(*tfm) = NULL;<br />
	(*tfm_mutex) = NULL;</p>
<p>	mutex_lock(&#038;key_tfm_list_mutex);<br />
	if (!ecryptfs_tfm_exists(cipher_name, &#038;key_tfm)) {<br />
		rc = ecryptfs_add_new_key_tfm(&#038;key_tfm, cipher_name, 0);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;Error adding new key_tfm to list; &raquo;<br />
					&laquo;rc = [%d]\n&raquo;, rc);<br />
			goto out;<br />
		}<br />
	}<br />
	(*tfm) = key_tfm->key_tfm;<br />
	(*tfm_mutex) = &#038;key_tfm->key_tfm_mutex;<br />
out:<br />
	mutex_unlock(&#038;key_tfm_list_mutex);<br />
	return rc;<br />
}</p>
<p>/* 64 characters forming a 6-bit target field */<br />
static unsigned char *portable_filename_chars = (&raquo;-.0123456789ABCD&raquo;<br />
						 &laquo;EFGHIJKLMNOPQRST&raquo;<br />
						 &laquo;UVWXYZabcdefghij&raquo;<br />
						 &laquo;klmnopqrstuvwxyz&raquo;);</p>
<p>/* We could either offset on every reverse map or just pad some 0&#215;00&#8217;s<br />
 * at the front here */<br />
static const unsigned char filename_rev_map[] = {<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 7 */<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 15 */<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 23 */<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 31 */<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 39 */<br />
	0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;01, 0&#215;00, /* 47 */<br />
	0&#215;02, 0&#215;03, 0&#215;04, 0&#215;05, 0&#215;06, 0&#215;07, 0&#215;08, 0&#215;09, /* 55 */<br />
	0&#215;0A, 0&#215;0B, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 63 */<br />
	0&#215;00, 0&#215;0C, 0&#215;0D, 0&#215;0E, 0&#215;0F, 0&#215;10, 0&#215;11, 0&#215;12, /* 71 */<br />
	0&#215;13, 0&#215;14, 0&#215;15, 0&#215;16, 0&#215;17, 0&#215;18, 0&#215;19, 0&#215;1A, /* 79 */<br />
	0&#215;1B, 0&#215;1C, 0&#215;1D, 0&#215;1E, 0&#215;1F, 0&#215;20, 0&#215;21, 0&#215;22, /* 87 */<br />
	0&#215;23, 0&#215;24, 0&#215;25, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, 0&#215;00, /* 95 */<br />
	0&#215;00, 0&#215;26, 0&#215;27, 0&#215;28, 0&#215;29, 0&#215;2A, 0&#215;2B, 0&#215;2C, /* 103 */<br />
	0&#215;2D, 0&#215;2E, 0&#215;2F, 0&#215;30, 0&#215;31, 0&#215;32, 0&#215;33, 0&#215;34, /* 111 */<br />
	0&#215;35, 0&#215;36, 0&#215;37, 0&#215;38, 0&#215;39, 0&#215;3A, 0&#215;3B, 0&#215;3C, /* 119 */<br />
	0&#215;3D, 0&#215;3E, 0&#215;3F<br />
};</p>
<p>/**<br />
 * ecryptfs_encode_for_filename<br />
 * @dst: Destination location for encoded filename<br />
 * @dst_size: Size of the encoded filename in bytes<br />
 * @src: Source location for the filename to encode<br />
 * @src_size: Size of the source in bytes<br />
 */<br />
void ecryptfs_encode_for_filename(unsigned char *dst, size_t *dst_size,<br />
				  unsigned char *src, size_t src_size)<br />
{<br />
	size_t num_blocks;<br />
	size_t block_num = 0;<br />
	size_t dst_offset = 0;<br />
	unsigned char last_block[3];</p>
<p>	if (src_size == 0) {<br />
		(*dst_size) = 0;<br />
		goto out;<br />
	}<br />
	num_blocks = (src_size / 3);<br />
	if ((src_size % 3) == 0) {<br />
		memcpy(last_block, (&#038;src[src_size - 3]), 3);<br />
	} else {<br />
		num_blocks++;<br />
		last_block[2] = 0&#215;00;<br />
		switch (src_size % 3) {<br />
		case 1:<br />
			last_block[0] = src[src_size - 1];<br />
			last_block[1] = 0&#215;00;<br />
			break;<br />
		case 2:<br />
			last_block[0] = src[src_size - 2];<br />
			last_block[1] = src[src_size - 1];<br />
		}<br />
	}<br />
	(*dst_size) = (num_blocks * 4);<br />
	if (!dst)<br />
		goto out;<br />
	while (block_num < num_blocks) {<br />
		unsigned char *src_block;<br />
		unsigned char dst_block[4];</p>
<p>		if (block_num == (num_blocks - 1))<br />
			src_block = last_block;<br />
		else<br />
			src_block = &#038;src[block_num * 3];<br />
		dst_block[0] = ((src_block[0] >> 2) &#038; 0&#215;3F);<br />
		dst_block[1] = (((src_block[0] << 4) &#038; 0x30)<br />
				| ((src_block[1] >> 4) &#038; 0&#215;0F));<br />
		dst_block[2] = (((src_block[1] << 2) &#038; 0x3C)<br />
				| ((src_block[2] >> 6) &#038; 0&#215;03));<br />
		dst_block[3] = (src_block[2] &#038; 0&#215;3F);<br />
		dst[dst_offset++] = portable_filename_chars[dst_block[0]];<br />
		dst[dst_offset++] = portable_filename_chars[dst_block[1]];<br />
		dst[dst_offset++] = portable_filename_chars[dst_block[2]];<br />
		dst[dst_offset++] = portable_filename_chars[dst_block[3]];<br />
		block_num++;<br />
	}<br />
out:<br />
	return;<br />
}</p>
<p>/**<br />
 * ecryptfs_decode_from_filename<br />
 * @dst: If NULL, this function only sets @dst_size and returns. If<br />
 *       non-NULL, this function decodes the encoded octets in @src<br />
 *       into the memory that @dst points to.<br />
 * @dst_size: Set to the size of the decoded string.<br />
 * @src: The encoded set of octets to decode.<br />
 * @src_size: The size of the encoded set of octets to decode.<br />
 */<br />
static void<br />
ecryptfs_decode_from_filename(unsigned char *dst, size_t *dst_size,<br />
			      const unsigned char *src, size_t src_size)<br />
{<br />
	u8 current_bit_offset = 0;<br />
	size_t src_byte_offset = 0;<br />
	size_t dst_byte_offset = 0;</p>
<p>	if (dst == NULL) {<br />
		/* Not exact; conservatively long. Every block of 4<br />
		 * encoded characters decodes into a block of 3<br />
		 * decoded characters. This segment of code provides<br />
		 * the caller with the maximum amount of allocated<br />
		 * space that @dst will need to point to in a<br />
		 * subsequent call. */<br />
		(*dst_size) = (((src_size + 1) * 3) / 4);<br />
		goto out;<br />
	}<br />
	while (src_byte_offset < src_size) {<br />
		unsigned char src_byte =<br />
				filename_rev_map[(int)src[src_byte_offset]];</p>
<p>		switch (current_bit_offset) {<br />
		case 0:<br />
			dst[dst_byte_offset] = (src_byte << 2);<br />
			current_bit_offset = 6;<br />
			break;<br />
		case 6:<br />
			dst[dst_byte_offset++] |= (src_byte >> 4);<br />
			dst[dst_byte_offset] = ((src_byte &#038; 0xF)<br />
						 << 4);<br />
			current_bit_offset = 4;<br />
			break;<br />
		case 4:<br />
			dst[dst_byte_offset++] |= (src_byte >> 2);<br />
			dst[dst_byte_offset] = (src_byte << 6);<br />
			current_bit_offset = 2;<br />
			break;<br />
		case 2:<br />
			dst[dst_byte_offset++] |= (src_byte);<br />
			dst[dst_byte_offset] = 0;<br />
			current_bit_offset = 0;<br />
			break;<br />
		}<br />
		src_byte_offset++;<br />
	}<br />
	(*dst_size) = dst_byte_offset;<br />
out:<br />
	return;<br />
}</p>
<p>/**<br />
 * ecryptfs_encrypt_and_encode_filename - converts a plaintext file name to cipher text<br />
 * @crypt_stat: The crypt_stat struct associated with the file anem to encode<br />
 * @name: The plaintext name<br />
 * @length: The length of the plaintext<br />
 * @encoded_name: The encypted name<br />
 *<br />
 * Encrypts and encodes a filename into something that constitutes a<br />
 * valid filename for a filesystem, with printable characters.<br />
 *<br />
 * We assume that we have a properly initialized crypto context,<br />
 * pointed to by crypt_stat->tfm.<br />
 *<br />
 * Returns zero on success; non-zero on otherwise<br />
 */<br />
int ecryptfs_encrypt_and_encode_filename(<br />
	char **encoded_name,<br />
	size_t *encoded_name_size,<br />
	struct ecryptfs_crypt_stat *crypt_stat,<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat,<br />
	const char *name, size_t name_size)<br />
{<br />
	size_t encoded_name_no_prefix_size;<br />
	int rc = 0;</p>
<p>	(*encoded_name) = NULL;<br />
	(*encoded_name_size) = 0;<br />
	if ((crypt_stat &#038;&#038; (crypt_stat->flags &#038; ECRYPTFS_ENCRYPT_FILENAMES))<br />
	    || (mount_crypt_stat &#038;&#038; (mount_crypt_stat->flags<br />
				     &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES))) {<br />
		struct ecryptfs_filename *filename;</p>
<p>		filename = kzalloc(sizeof(*filename), GFP_KERNEL);<br />
		if (!filename) {<br />
			printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
			       &laquo;to kzalloc [%zd] bytes\n&raquo;, __func__,<br />
			       sizeof(*filename));<br />
			rc = -ENOMEM;<br />
			goto out;<br />
		}<br />
		filename->filename = (char *)name;<br />
		filename->filename_size = name_size;<br />
		rc = ecryptfs_encrypt_filename(filename, crypt_stat,<br />
					       mount_crypt_stat);<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to encrypt &raquo;<br />
			       &laquo;filename; rc = [%d]\n&raquo;, __func__, rc);<br />
			kfree(filename);<br />
			goto out;<br />
		}<br />
		ecryptfs_encode_for_filename(<br />
			NULL, &#038;encoded_name_no_prefix_size,<br />
			filename->encrypted_filename,<br />
			filename->encrypted_filename_size);<br />
		if ((crypt_stat &#038;&#038; (crypt_stat->flags<br />
				    &#038; ECRYPTFS_ENCFN_USE_MOUNT_FNEK))<br />
		    || (mount_crypt_stat<br />
			&#038;&#038; (mount_crypt_stat->flags<br />
			    &#038; ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK)))<br />
			(*encoded_name_size) =<br />
				(ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE<br />
				 + encoded_name_no_prefix_size);<br />
		else<br />
			(*encoded_name_size) =<br />
				(ECRYPTFS_FEK_ENCRYPTED_FILENAME_PREFIX_SIZE<br />
				 + encoded_name_no_prefix_size);<br />
		(*encoded_name) = kmalloc((*encoded_name_size) + 1, GFP_KERNEL);<br />
		if (!(*encoded_name)) {<br />
			printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
			       &laquo;to kzalloc [%zd] bytes\n&raquo;, __func__,<br />
			       (*encoded_name_size));<br />
			rc = -ENOMEM;<br />
			kfree(filename->encrypted_filename);<br />
			kfree(filename);<br />
			goto out;<br />
		}<br />
		if ((crypt_stat &#038;&#038; (crypt_stat->flags<br />
				    &#038; ECRYPTFS_ENCFN_USE_MOUNT_FNEK))<br />
		    || (mount_crypt_stat<br />
			&#038;&#038; (mount_crypt_stat->flags<br />
			    &#038; ECRYPTFS_GLOBAL_ENCFN_USE_MOUNT_FNEK))) {<br />
			memcpy((*encoded_name),<br />
			       ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX,<br />
			       ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE);<br />
			ecryptfs_encode_for_filename(<br />
			    ((*encoded_name)<br />
			     + ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE),<br />
			    &#038;encoded_name_no_prefix_size,<br />
			    filename->encrypted_filename,<br />
			    filename->encrypted_filename_size);<br />
			(*encoded_name_size) =<br />
				(ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE<br />
				 + encoded_name_no_prefix_size);<br />
			(*encoded_name)[(*encoded_name_size)] = &#8216;\0&#8242;;<br />
			(*encoded_name_size)++;<br />
		} else {<br />
			rc = -EOPNOTSUPP;<br />
		}<br />
		if (rc) {<br />
			printk(KERN_ERR &laquo;%s: Error attempting to encode &raquo;<br />
			       &laquo;encrypted filename; rc = [%d]\n&raquo;, __func__,<br />
			       rc);<br />
			kfree((*encoded_name));<br />
			(*encoded_name) = NULL;<br />
			(*encoded_name_size) = 0;<br />
		}<br />
		kfree(filename->encrypted_filename);<br />
		kfree(filename);<br />
	} else {<br />
		rc = ecryptfs_copy_filename(encoded_name,<br />
					    encoded_name_size,<br />
					    name, name_size);<br />
	}<br />
out:<br />
	return rc;<br />
}</p>
<p>/**<br />
 * ecryptfs_decode_and_decrypt_filename &#8211; converts the encoded cipher text name to decoded plaintext<br />
 * @plaintext_name: The plaintext name<br />
 * @plaintext_name_size: The plaintext name size<br />
 * @ecryptfs_dir_dentry: eCryptfs directory dentry<br />
 * @name: The filename in cipher text<br />
 * @name_size: The cipher text name size<br />
 *<br />
 * Decrypts and decodes the filename.<br />
 *<br />
 * Returns zero on error; non-zero otherwise<br />
 */<br />
int ecryptfs_decode_and_decrypt_filename(char **plaintext_name,<br />
					 size_t *plaintext_name_size,<br />
					 struct dentry *ecryptfs_dir_dentry,<br />
					 const char *name, size_t name_size)<br />
{<br />
	struct ecryptfs_mount_crypt_stat *mount_crypt_stat =<br />
		&#038;ecryptfs_superblock_to_private(<br />
			ecryptfs_dir_dentry->d_sb)->mount_crypt_stat;<br />
	char *decoded_name;<br />
	size_t decoded_name_size;<br />
	size_t packet_size;<br />
	int rc = 0;</p>
<p>	if ((mount_crypt_stat->flags &#038; ECRYPTFS_GLOBAL_ENCRYPT_FILENAMES)<br />
	    &#038;&#038; !(mount_crypt_stat->flags &#038; ECRYPTFS_ENCRYPTED_VIEW_ENABLED)<br />
	    &#038;&#038; (name_size > ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE)<br />
	    &#038;&#038; (strncmp(name, ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX,<br />
			ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE) == 0)) {<br />
		const char *orig_name = name;<br />
		size_t orig_name_size = name_size;</p>
<p>		name += ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE;<br />
		name_size -= ECRYPTFS_FNEK_ENCRYPTED_FILENAME_PREFIX_SIZE;<br />
		ecryptfs_decode_from_filename(NULL, &#038;decoded_name_size,<br />
					      name, name_size);<br />
		decoded_name = kmalloc(decoded_name_size, GFP_KERNEL);<br />
		if (!decoded_name) {<br />
			printk(KERN_ERR &laquo;%s: Out of memory whilst attempting &raquo;<br />
			       &laquo;to kmalloc [%zd] bytes\n&raquo;, __func__,<br />
			       decoded_name_size);<br />
			rc = -ENOMEM;<br />
			goto out;<br />
		}<br />
		ecryptfs_decode_from_filename(decoded_name, &#038;decoded_name_size,<br />
					      name, name_size);<br />
		rc = ecryptfs_parse_tag_70_packet(plaintext_name,<br />
						  plaintext_name_size,<br />
						  &#038;packet_size,<br />
						  mount_crypt_stat,<br />
						  decoded_name,<br />
						  decoded_name_size);<br />
		if (rc) {<br />
			printk(KERN_INFO &laquo;%s: Could not parse tag 70 packet &raquo;<br />
			       &laquo;from filename; copying through filename &raquo;<br />
			       &laquo;as-is\n&raquo;, __func__);<br />
			rc = ecryptfs_copy_filename(plaintext_name,<br />
						    plaintext_name_size,<br />
						    orig_name, orig_name_size);<br />
			goto out_free;<br />
		}<br />
	} else {<br />
		rc = ecryptfs_copy_filename(plaintext_name,<br />
					    plaintext_name_size,<br />
					    name, name_size);<br />
		goto out;<br />
	}<br />
out_free:<br />
	kfree(decoded_name);<br />
out:<br />
	return rc;<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/crypto-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>user.h</title>
		<link>http://lynyrd.ru/user-h-2</link>
		<comments>http://lynyrd.ru/user-h-2#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:00:41 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/user-h-2</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#ifndef __UTIL_DOT_H__
#define __UTIL_DOT_H__
void dlm_message_out(struct dlm_message *ms);
void dlm_message_in(struct dlm_message *ms);
void dlm_rcom_out(struct dlm_rcom *rc);
void ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005 Red Hat, Inc.  All rights reserved.<span id="more-1076"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __UTIL_DOT_H__<br />
#define __UTIL_DOT_H__</p>
<p>void dlm_message_out(struct dlm_message *ms);<br />
void dlm_message_in(struct dlm_message *ms);<br />
void dlm_rcom_out(struct dlm_rcom *rc);<br />
void dlm_rcom_in(struct dlm_rcom *rc);</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/user-h-2/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>util.c</title>
		<link>http://lynyrd.ru/util-c</link>
		<comments>http://lynyrd.ru/util-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:00:26 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1074</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#include &#171;dlm_internal.h&#187;
#include &#171;rcom.h&#187;
#include &#171;util.h&#187;
#define DLM_ERRNO_EDEADLK		35
#define DLM_ERRNO_EBADR			53
#define DLM_ERRNO_EBADSLT		57
#define DLM_ERRNO_EPROTO		71
#define DLM_ERRNO_EOPNOTSUPP		95
#define DLM_ERRNO_ETIMEDOUT	   ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2008 Red Hat, Inc.  All rights reserved.<span id="more-1074"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;rcom.h&raquo;<br />
#include &laquo;util.h&raquo;</p>
<p>#define DLM_ERRNO_EDEADLK		35<br />
#define DLM_ERRNO_EBADR			53<br />
#define DLM_ERRNO_EBADSLT		57<br />
#define DLM_ERRNO_EPROTO		71<br />
#define DLM_ERRNO_EOPNOTSUPP		95<br />
#define DLM_ERRNO_ETIMEDOUT	       110<br />
#define DLM_ERRNO_EINPROGRESS	       115</p>
<p>static void header_out(struct dlm_header *hd)<br />
{<br />
	hd->h_version		= cpu_to_le32(hd->h_version);<br />
	hd->h_lockspace		= cpu_to_le32(hd->h_lockspace);<br />
	hd->h_nodeid		= cpu_to_le32(hd->h_nodeid);<br />
	hd->h_length		= cpu_to_le16(hd->h_length);<br />
}</p>
<p>static void header_in(struct dlm_header *hd)<br />
{<br />
	hd->h_version		= le32_to_cpu(hd->h_version);<br />
	hd->h_lockspace		= le32_to_cpu(hd->h_lockspace);<br />
	hd->h_nodeid		= le32_to_cpu(hd->h_nodeid);<br />
	hd->h_length		= le16_to_cpu(hd->h_length);<br />
}</p>
<p>/* higher errno values are inconsistent across architectures, so select<br />
   one set of values for on the wire */</p>
<p>static int to_dlm_errno(int err)<br />
{<br />
	switch (err) {<br />
	case -EDEADLK:<br />
		return -DLM_ERRNO_EDEADLK;<br />
	case -EBADR:<br />
		return -DLM_ERRNO_EBADR;<br />
	case -EBADSLT:<br />
		return -DLM_ERRNO_EBADSLT;<br />
	case -EPROTO:<br />
		return -DLM_ERRNO_EPROTO;<br />
	case -EOPNOTSUPP:<br />
		return -DLM_ERRNO_EOPNOTSUPP;<br />
	case -ETIMEDOUT:<br />
		return -DLM_ERRNO_ETIMEDOUT;<br />
	case -EINPROGRESS:<br />
		return -DLM_ERRNO_EINPROGRESS;<br />
	}<br />
	return err;<br />
}</p>
<p>static int from_dlm_errno(int err)<br />
{<br />
	switch (err) {<br />
	case -DLM_ERRNO_EDEADLK:<br />
		return -EDEADLK;<br />
	case -DLM_ERRNO_EBADR:<br />
		return -EBADR;<br />
	case -DLM_ERRNO_EBADSLT:<br />
		return -EBADSLT;<br />
	case -DLM_ERRNO_EPROTO:<br />
		return -EPROTO;<br />
	case -DLM_ERRNO_EOPNOTSUPP:<br />
		return -EOPNOTSUPP;<br />
	case -DLM_ERRNO_ETIMEDOUT:<br />
		return -ETIMEDOUT;<br />
	case -DLM_ERRNO_EINPROGRESS:<br />
		return -EINPROGRESS;<br />
	}<br />
	return err;<br />
}</p>
<p>void dlm_message_out(struct dlm_message *ms)<br />
{<br />
	header_out(&#038;ms->m_header);</p>
<p>	ms->m_type		= cpu_to_le32(ms->m_type);<br />
	ms->m_nodeid		= cpu_to_le32(ms->m_nodeid);<br />
	ms->m_pid		= cpu_to_le32(ms->m_pid);<br />
	ms->m_lkid		= cpu_to_le32(ms->m_lkid);<br />
	ms->m_remid		= cpu_to_le32(ms->m_remid);<br />
	ms->m_parent_lkid	= cpu_to_le32(ms->m_parent_lkid);<br />
	ms->m_parent_remid	= cpu_to_le32(ms->m_parent_remid);<br />
	ms->m_exflags		= cpu_to_le32(ms->m_exflags);<br />
	ms->m_sbflags		= cpu_to_le32(ms->m_sbflags);<br />
	ms->m_flags		= cpu_to_le32(ms->m_flags);<br />
	ms->m_lvbseq		= cpu_to_le32(ms->m_lvbseq);<br />
	ms->m_hash		= cpu_to_le32(ms->m_hash);<br />
	ms->m_status		= cpu_to_le32(ms->m_status);<br />
	ms->m_grmode		= cpu_to_le32(ms->m_grmode);<br />
	ms->m_rqmode		= cpu_to_le32(ms->m_rqmode);<br />
	ms->m_bastmode		= cpu_to_le32(ms->m_bastmode);<br />
	ms->m_asts		= cpu_to_le32(ms->m_asts);<br />
	ms->m_result		= cpu_to_le32(to_dlm_errno(ms->m_result));<br />
}</p>
<p>void dlm_message_in(struct dlm_message *ms)<br />
{<br />
	header_in(&#038;ms->m_header);</p>
<p>	ms->m_type		= le32_to_cpu(ms->m_type);<br />
	ms->m_nodeid		= le32_to_cpu(ms->m_nodeid);<br />
	ms->m_pid		= le32_to_cpu(ms->m_pid);<br />
	ms->m_lkid		= le32_to_cpu(ms->m_lkid);<br />
	ms->m_remid		= le32_to_cpu(ms->m_remid);<br />
	ms->m_parent_lkid	= le32_to_cpu(ms->m_parent_lkid);<br />
	ms->m_parent_remid	= le32_to_cpu(ms->m_parent_remid);<br />
	ms->m_exflags		= le32_to_cpu(ms->m_exflags);<br />
	ms->m_sbflags		= le32_to_cpu(ms->m_sbflags);<br />
	ms->m_flags		= le32_to_cpu(ms->m_flags);<br />
	ms->m_lvbseq		= le32_to_cpu(ms->m_lvbseq);<br />
	ms->m_hash		= le32_to_cpu(ms->m_hash);<br />
	ms->m_status		= le32_to_cpu(ms->m_status);<br />
	ms->m_grmode		= le32_to_cpu(ms->m_grmode);<br />
	ms->m_rqmode		= le32_to_cpu(ms->m_rqmode);<br />
	ms->m_bastmode		= le32_to_cpu(ms->m_bastmode);<br />
	ms->m_asts		= le32_to_cpu(ms->m_asts);<br />
	ms->m_result		= from_dlm_errno(le32_to_cpu(ms->m_result));<br />
}</p>
<p>void dlm_rcom_out(struct dlm_rcom *rc)<br />
{<br />
	header_out(&#038;rc->rc_header);</p>
<p>	rc->rc_type		= cpu_to_le32(rc->rc_type);<br />
	rc->rc_result		= cpu_to_le32(rc->rc_result);<br />
	rc->rc_id		= cpu_to_le64(rc->rc_id);<br />
	rc->rc_seq		= cpu_to_le64(rc->rc_seq);<br />
	rc->rc_seq_reply	= cpu_to_le64(rc->rc_seq_reply);<br />
}</p>
<p>void dlm_rcom_in(struct dlm_rcom *rc)<br />
{<br />
	header_in(&#038;rc->rc_header);</p>
<p>	rc->rc_type		= le32_to_cpu(rc->rc_type);<br />
	rc->rc_result		= le32_to_cpu(rc->rc_result);<br />
	rc->rc_id		= le64_to_cpu(rc->rc_id);<br />
	rc->rc_seq		= le64_to_cpu(rc->rc_seq);<br />
	rc->rc_seq_reply	= le64_to_cpu(rc->rc_seq_reply);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/util-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>user.h</title>
		<link>http://lynyrd.ru/user-h</link>
		<comments>http://lynyrd.ru/user-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 04:00:07 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/user-h</guid>
		<description><![CDATA[/*
 * Copyright (C) 2006-2008 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License v.2.
 */
#ifndef __USER_DOT_H__
#define __USER_DOT_H__
void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode);
int ]]></description>
			<content:encoded><![CDATA[<p>/*<br />
 * Copyright (C) 2006-2008 Red Hat, Inc.  All rights reserved.<span id="more-1073"></span><br />
 *<br />
 * This copyrighted material is made available to anyone wishing to use,<br />
 * modify, copy, or redistribute it subject to the terms and conditions<br />
 * of the GNU General Public License v.2.<br />
 */</p>
<p>#ifndef __USER_DOT_H__<br />
#define __USER_DOT_H__</p>
<p>void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode);<br />
int dlm_user_init(void);<br />
void dlm_user_exit(void);<br />
int dlm_device_deregister(struct dlm_ls *ls);<br />
int dlm_user_daemon_available(void);</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/user-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>user.c</title>
		<link>http://lynyrd.ru/user-c</link>
		<comments>http://lynyrd.ru/user-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:59:49 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/user-c</guid>
		<description><![CDATA[/*
 * Copyright (C) 2006-2009 Red Hat, Inc.  All rights reserved.
 *
 * This copyrighted material is made available to anyone wishing to use,
 * modify, copy, or redistribute it subject to the terms and conditions
 * of the GNU General Public License v.2.
 */
#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include &#171;dlm_internal.h&#187;
#include &#171;lockspace.h&#187;
#include &#171;lock.h&#187;
#include &#171;lvb_table.h&#187;
#include &#171;user.h&#187;
static const char name_prefix[] = ]]></description>
			<content:encoded><![CDATA[<p>/*<br />
 * Copyright (C) 2006-2009 Red Hat, Inc.  All rights reserved.<span id="more-1072"></span><br />
 *<br />
 * This copyrighted material is made available to anyone wishing to use,<br />
 * modify, copy, or redistribute it subject to the terms and conditions<br />
 * of the GNU General Public License v.2.<br />
 */</p>
<p>#include
<linux/miscdevice.h>
#include
<linux/init.h>
#include
<linux/wait.h>
#include
<linux/module.h>
#include
<linux/file.h>
#include
<linux/fs.h>
#include
<linux/poll.h>
#include
<linux/signal.h>
#include
<linux/spinlock.h>
#include
<linux/dlm.h>
#include
<linux/dlm_device.h>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;lvb_table.h&raquo;<br />
#include &laquo;user.h&raquo;</p>
<p>static const char name_prefix[] = &laquo;dlm&raquo;;<br />
static const struct file_operations device_fops;<br />
static atomic_t dlm_monitor_opened;<br />
static int dlm_monitor_unused = 1;</p>
<p>#ifdef CONFIG_COMPAT</p>
<p>struct dlm_lock_params32 {<br />
	__u8 mode;<br />
	__u8 namelen;<br />
	__u16 unused;<br />
	__u32 flags;<br />
	__u32 lkid;<br />
	__u32 parent;<br />
	__u64 xid;<br />
	__u64 timeout;<br />
	__u32 castparam;<br />
	__u32 castaddr;<br />
	__u32 bastparam;<br />
	__u32 bastaddr;<br />
	__u32 lksb;<br />
	char lvb[DLM_USER_LVB_LEN];<br />
	char name[0];<br />
};</p>
<p>struct dlm_write_request32 {<br />
	__u32 version[3];<br />
	__u8 cmd;<br />
	__u8 is64bit;<br />
	__u8 unused[2];</p>
<p>	union  {<br />
		struct dlm_lock_params32 lock;<br />
		struct dlm_lspace_params lspace;<br />
		struct dlm_purge_params purge;<br />
	} i;<br />
};</p>
<p>struct dlm_lksb32 {<br />
	__u32 sb_status;<br />
	__u32 sb_lkid;<br />
	__u8 sb_flags;<br />
	__u32 sb_lvbptr;<br />
};</p>
<p>struct dlm_lock_result32 {<br />
	__u32 version[3];<br />
	__u32 length;<br />
	__u32 user_astaddr;<br />
	__u32 user_astparam;<br />
	__u32 user_lksb;<br />
	struct dlm_lksb32 lksb;<br />
	__u8 bast_mode;<br />
	__u8 unused[3];<br />
	/* Offsets may be zero if no data is present */<br />
	__u32 lvb_offset;<br />
};</p>
<p>static void compat_input(struct dlm_write_request *kb,<br />
			 struct dlm_write_request32 *kb32,<br />
			 int namelen)<br />
{<br />
	kb->version[0] = kb32->version[0];<br />
	kb->version[1] = kb32->version[1];<br />
	kb->version[2] = kb32->version[2];</p>
<p>	kb->cmd = kb32->cmd;<br />
	kb->is64bit = kb32->is64bit;<br />
	if (kb->cmd == DLM_USER_CREATE_LOCKSPACE ||<br />
	    kb->cmd == DLM_USER_REMOVE_LOCKSPACE) {<br />
		kb->i.lspace.flags = kb32->i.lspace.flags;<br />
		kb->i.lspace.minor = kb32->i.lspace.minor;<br />
		memcpy(kb->i.lspace.name, kb32->i.lspace.name, namelen);<br />
	} else if (kb->cmd == DLM_USER_PURGE) {<br />
		kb->i.purge.nodeid = kb32->i.purge.nodeid;<br />
		kb->i.purge.pid = kb32->i.purge.pid;<br />
	} else {<br />
		kb->i.lock.mode = kb32->i.lock.mode;<br />
		kb->i.lock.namelen = kb32->i.lock.namelen;<br />
		kb->i.lock.flags = kb32->i.lock.flags;<br />
		kb->i.lock.lkid = kb32->i.lock.lkid;<br />
		kb->i.lock.parent = kb32->i.lock.parent;<br />
		kb->i.lock.xid = kb32->i.lock.xid;<br />
		kb->i.lock.timeout = kb32->i.lock.timeout;<br />
		kb->i.lock.castparam = (void *)(long)kb32->i.lock.castparam;<br />
		kb->i.lock.castaddr = (void *)(long)kb32->i.lock.castaddr;<br />
		kb->i.lock.bastparam = (void *)(long)kb32->i.lock.bastparam;<br />
		kb->i.lock.bastaddr = (void *)(long)kb32->i.lock.bastaddr;<br />
		kb->i.lock.lksb = (void *)(long)kb32->i.lock.lksb;<br />
		memcpy(kb->i.lock.lvb, kb32->i.lock.lvb, DLM_USER_LVB_LEN);<br />
		memcpy(kb->i.lock.name, kb32->i.lock.name, namelen);<br />
	}<br />
}</p>
<p>static void compat_output(struct dlm_lock_result *res,<br />
			  struct dlm_lock_result32 *res32)<br />
{<br />
	res32->version[0] = res->version[0];<br />
	res32->version[1] = res->version[1];<br />
	res32->version[2] = res->version[2];</p>
<p>	res32->user_astaddr = (__u32)(long)res->user_astaddr;<br />
	res32->user_astparam = (__u32)(long)res->user_astparam;<br />
	res32->user_lksb = (__u32)(long)res->user_lksb;<br />
	res32->bast_mode = res->bast_mode;</p>
<p>	res32->lvb_offset = res->lvb_offset;<br />
	res32->length = res->length;</p>
<p>	res32->lksb.sb_status = res->lksb.sb_status;<br />
	res32->lksb.sb_flags = res->lksb.sb_flags;<br />
	res32->lksb.sb_lkid = res->lksb.sb_lkid;<br />
	res32->lksb.sb_lvbptr = (__u32)(long)res->lksb.sb_lvbptr;<br />
}<br />
#endif</p>
<p>/* Figure out if this lock is at the end of its life and no longer<br />
   available for the application to use.  The lkb still exists until<br />
   the final ast is read.  A lock becomes EOL in three situations:<br />
     1. a noqueue request fails with EAGAIN<br />
     2. an unlock completes with EUNLOCK<br />
     3. a cancel of a waiting request completes with ECANCEL/EDEADLK<br />
   An EOL lock needs to be removed from the process&#8217;s list of locks.<br />
   And we can&#8217;t allow any new operation on an EOL lock.  This is<br />
   not related to the lifetime of the lkb struct which is managed<br />
   entirely by refcount. */</p>
<p>static int lkb_is_endoflife(struct dlm_lkb *lkb, int sb_status, int type)<br />
{<br />
	switch (sb_status) {<br />
	case -DLM_EUNLOCK:<br />
		return 1;<br />
	case -DLM_ECANCEL:<br />
	case -ETIMEDOUT:<br />
	case -EDEADLK:<br />
		if (lkb->lkb_grmode == DLM_LOCK_IV)<br />
			return 1;<br />
		break;<br />
	case -EAGAIN:<br />
		if (type == AST_COMP &#038;&#038; lkb->lkb_grmode == DLM_LOCK_IV)<br />
			return 1;<br />
		break;<br />
	}<br />
	return 0;<br />
}</p>
<p>/* we could possibly check if the cancel of an orphan has resulted in the lkb<br />
   being removed and then remove that lkb from the orphans list and free it */</p>
<p>void dlm_user_add_ast(struct dlm_lkb *lkb, int type, int bastmode)<br />
{<br />
	struct dlm_ls *ls;<br />
	struct dlm_user_args *ua;<br />
	struct dlm_user_proc *proc;<br />
	int eol = 0, ast_type;</p>
<p>	if (lkb->lkb_flags &#038; (DLM_IFL_ORPHAN | DLM_IFL_DEAD))<br />
		return;</p>
<p>	ls = lkb->lkb_resource->res_ls;<br />
	mutex_lock(&#038;ls->ls_clear_proc_locks);</p>
<p>	/* If ORPHAN/DEAD flag is set, it means the process is dead so an ast<br />
	   can&#8217;t be delivered.  For ORPHAN&#8217;s, dlm_clear_proc_locks() freed<br />
	   lkb->ua so we can&#8217;t try to use it.  This second check is necessary<br />
	   for cases where a completion ast is received for an operation that<br />
	   began before clear_proc_locks did its cancel/unlock. */</p>
<p>	if (lkb->lkb_flags &#038; (DLM_IFL_ORPHAN | DLM_IFL_DEAD))<br />
		goto out;</p>
<p>	DLM_ASSERT(lkb->lkb_ua, dlm_print_lkb(lkb););<br />
	ua = lkb->lkb_ua;<br />
	proc = ua->proc;</p>
<p>	if (type == AST_BAST &#038;&#038; ua->bastaddr == NULL)<br />
		goto out;</p>
<p>	spin_lock(&#038;proc->asts_spin);</p>
<p>	ast_type = lkb->lkb_ast_type;<br />
	lkb->lkb_ast_type |= type;<br />
	if (bastmode)<br />
		lkb->lkb_bastmode = bastmode;</p>
<p>	if (!ast_type) {<br />
		kref_get(&#038;lkb->lkb_ref);<br />
		list_add_tail(&#038;lkb->lkb_astqueue, &#038;proc->asts);<br />
		wake_up_interruptible(&#038;proc->wait);<br />
	}<br />
	if (type == AST_COMP &#038;&#038; (ast_type &#038; AST_COMP))<br />
		log_debug(ls, &laquo;ast overlap %x status %x %x&raquo;,<br />
			  lkb->lkb_id, ua->lksb.sb_status, lkb->lkb_flags);</p>
<p>	eol = lkb_is_endoflife(lkb, ua->lksb.sb_status, type);<br />
	if (eol) {<br />
		lkb->lkb_ast_type &#038;= ~AST_BAST;<br />
		lkb->lkb_flags |= DLM_IFL_ENDOFLIFE;<br />
	}</p>
<p>	/* We want to copy the lvb to userspace when the completion<br />
	   ast is read if the status is 0, the lock has an lvb and<br />
	   lvb_ops says we should.  We could probably have set_lvb_lock()<br />
	   set update_user_lvb instead and not need old_mode */</p>
<p>	if ((lkb->lkb_ast_type &#038; AST_COMP) &#038;&#038;<br />
	    (lkb->lkb_lksb->sb_status == 0) &#038;&#038;<br />
	    lkb->lkb_lksb->sb_lvbptr &#038;&#038;<br />
	    dlm_lvb_operations[ua->old_mode + 1][lkb->lkb_grmode + 1])<br />
		ua->update_user_lvb = 1;<br />
	else<br />
		ua->update_user_lvb = 0;</p>
<p>	spin_unlock(&#038;proc->asts_spin);</p>
<p>	if (eol) {<br />
		spin_lock(&#038;proc->locks_spin);<br />
		if (!list_empty(&#038;lkb->lkb_ownqueue)) {<br />
			list_del_init(&#038;lkb->lkb_ownqueue);<br />
			dlm_put_lkb(lkb);<br />
		}<br />
		spin_unlock(&#038;proc->locks_spin);<br />
	}<br />
 out:<br />
	mutex_unlock(&#038;ls->ls_clear_proc_locks);<br />
}</p>
<p>static int device_user_lock(struct dlm_user_proc *proc,<br />
			    struct dlm_lock_params *params)<br />
{<br />
	struct dlm_ls *ls;<br />
	struct dlm_user_args *ua;<br />
	int error = -ENOMEM;</p>
<p>	ls = dlm_find_lockspace_local(proc->lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	if (!params->castaddr || !params->lksb) {<br />
		error = -EINVAL;<br />
		goto out;<br />
	}</p>
<p>	ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);<br />
	if (!ua)<br />
		goto out;<br />
	ua->proc = proc;<br />
	ua->user_lksb = params->lksb;<br />
	ua->castparam = params->castparam;<br />
	ua->castaddr = params->castaddr;<br />
	ua->bastparam = params->bastparam;<br />
	ua->bastaddr = params->bastaddr;<br />
	ua->xid = params->xid;</p>
<p>	if (params->flags &#038; DLM_LKF_CONVERT)<br />
		error = dlm_user_convert(ls, ua,<br />
				         params->mode, params->flags,<br />
				         params->lkid, params->lvb,<br />
					 (unsigned long) params->timeout);<br />
	else {<br />
		error = dlm_user_request(ls, ua,<br />
					 params->mode, params->flags,<br />
					 params->name, params->namelen,<br />
					 (unsigned long) params->timeout);<br />
		if (!error)<br />
			error = ua->lksb.sb_lkid;<br />
	}<br />
 out:<br />
	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>static int device_user_unlock(struct dlm_user_proc *proc,<br />
			      struct dlm_lock_params *params)<br />
{<br />
	struct dlm_ls *ls;<br />
	struct dlm_user_args *ua;<br />
	int error = -ENOMEM;</p>
<p>	ls = dlm_find_lockspace_local(proc->lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	ua = kzalloc(sizeof(struct dlm_user_args), GFP_KERNEL);<br />
	if (!ua)<br />
		goto out;<br />
	ua->proc = proc;<br />
	ua->user_lksb = params->lksb;<br />
	ua->castparam = params->castparam;<br />
	ua->castaddr = params->castaddr;</p>
<p>	if (params->flags &#038; DLM_LKF_CANCEL)<br />
		error = dlm_user_cancel(ls, ua, params->flags, params->lkid);<br />
	else<br />
		error = dlm_user_unlock(ls, ua, params->flags, params->lkid,<br />
					params->lvb);<br />
 out:<br />
	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>static int device_user_deadlock(struct dlm_user_proc *proc,<br />
				struct dlm_lock_params *params)<br />
{<br />
	struct dlm_ls *ls;<br />
	int error;</p>
<p>	ls = dlm_find_lockspace_local(proc->lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	error = dlm_user_deadlock(ls, params->flags, params->lkid);</p>
<p>	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>static int dlm_device_register(struct dlm_ls *ls, char *name)<br />
{<br />
	int error, len;</p>
<p>	/* The device is already registered.  This happens when the<br />
	   lockspace is created multiple times from userspace. */<br />
	if (ls->ls_device.name)<br />
		return 0;</p>
<p>	error = -ENOMEM;<br />
	len = strlen(name) + strlen(name_prefix) + 2;<br />
	ls->ls_device.name = kzalloc(len, GFP_KERNEL);<br />
	if (!ls->ls_device.name)<br />
		goto fail;</p>
<p>	snprintf((char *)ls->ls_device.name, len, &laquo;%s_%s&raquo;, name_prefix,<br />
		 name);<br />
	ls->ls_device.fops = &#038;device_fops;<br />
	ls->ls_device.minor = MISC_DYNAMIC_MINOR;</p>
<p>	error = misc_register(&#038;ls->ls_device);<br />
	if (error) {<br />
		kfree(ls->ls_device.name);<br />
	}<br />
fail:<br />
	return error;<br />
}</p>
<p>int dlm_device_deregister(struct dlm_ls *ls)<br />
{<br />
	int error;</p>
<p>	/* The device is not registered.  This happens when the lockspace<br />
	   was never used from userspace, or when device_create_lockspace()<br />
	   calls dlm_release_lockspace() after the register fails. */<br />
	if (!ls->ls_device.name)<br />
		return 0;</p>
<p>	error = misc_deregister(&#038;ls->ls_device);<br />
	if (!error)<br />
		kfree(ls->ls_device.name);<br />
	return error;<br />
}</p>
<p>static int device_user_purge(struct dlm_user_proc *proc,<br />
			     struct dlm_purge_params *params)<br />
{<br />
	struct dlm_ls *ls;<br />
	int error;</p>
<p>	ls = dlm_find_lockspace_local(proc->lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	error = dlm_user_purge(ls, proc, params->nodeid, params->pid);</p>
<p>	dlm_put_lockspace(ls);<br />
	return error;<br />
}</p>
<p>static int device_create_lockspace(struct dlm_lspace_params *params)<br />
{<br />
	dlm_lockspace_t *lockspace;<br />
	struct dlm_ls *ls;<br />
	int error;</p>
<p>	if (!capable(CAP_SYS_ADMIN))<br />
		return -EPERM;</p>
<p>	error = dlm_new_lockspace(params->name, strlen(params->name),<br />
				  &#038;lockspace, params->flags, DLM_USER_LVB_LEN);<br />
	if (error)<br />
		return error;</p>
<p>	ls = dlm_find_lockspace_local(lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	error = dlm_device_register(ls, params->name);<br />
	dlm_put_lockspace(ls);</p>
<p>	if (error)<br />
		dlm_release_lockspace(lockspace, 0);<br />
	else<br />
		error = ls->ls_device.minor;</p>
<p>	return error;<br />
}</p>
<p>static int device_remove_lockspace(struct dlm_lspace_params *params)<br />
{<br />
	dlm_lockspace_t *lockspace;<br />
	struct dlm_ls *ls;<br />
	int error, force = 0;</p>
<p>	if (!capable(CAP_SYS_ADMIN))<br />
		return -EPERM;</p>
<p>	ls = dlm_find_lockspace_device(params->minor);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	if (params->flags &#038; DLM_USER_LSFLG_FORCEFREE)<br />
		force = 2;</p>
<p>	lockspace = ls->ls_local_handle;<br />
	dlm_put_lockspace(ls);</p>
<p>	/* The final dlm_release_lockspace waits for references to go to<br />
	   zero, so all processes will need to close their device for the<br />
	   ls before the release will proceed.  release also calls the<br />
	   device_deregister above.  Converting a positive return value<br />
	   from release to zero means that userspace won&#8217;t know when its<br />
	   release was the final one, but it shouldn&#8217;t need to know. */</p>
<p>	error = dlm_release_lockspace(lockspace, force);<br />
	if (error > 0)<br />
		error = 0;<br />
	return error;<br />
}</p>
<p>/* Check the user&#8217;s version matches ours */<br />
static int check_version(struct dlm_write_request *req)<br />
{<br />
	if (req->version[0] != DLM_DEVICE_VERSION_MAJOR ||<br />
	    (req->version[0] == DLM_DEVICE_VERSION_MAJOR &#038;&#038;<br />
	     req->version[1] > DLM_DEVICE_VERSION_MINOR)) {</p>
<p>		printk(KERN_DEBUG &laquo;dlm: process %s (%d) version mismatch &raquo;<br />
		       &laquo;user (%d.%d.%d) kernel (%d.%d.%d)\n&raquo;,<br />
		       current->comm,<br />
		       task_pid_nr(current),<br />
		       req->version[0],<br />
		       req->version[1],<br />
		       req->version[2],<br />
		       DLM_DEVICE_VERSION_MAJOR,<br />
		       DLM_DEVICE_VERSION_MINOR,<br />
		       DLM_DEVICE_VERSION_PATCH);<br />
		return -EINVAL;<br />
	}<br />
	return 0;<br />
}</p>
<p>/*<br />
 * device_write<br />
 *<br />
 *   device_user_lock<br />
 *     dlm_user_request -> request_lock<br />
 *     dlm_user_convert -> convert_lock<br />
 *<br />
 *   device_user_unlock<br />
 *     dlm_user_unlock -> unlock_lock<br />
 *     dlm_user_cancel -> cancel_lock<br />
 *<br />
 *   device_create_lockspace<br />
 *     dlm_new_lockspace<br />
 *<br />
 *   device_remove_lockspace<br />
 *     dlm_release_lockspace<br />
 */</p>
<p>/* a write to a lockspace device is a lock or unlock request, a write<br />
   to the control device is to create/remove a lockspace */</p>
<p>static ssize_t device_write(struct file *file, const char __user *buf,<br />
			    size_t count, loff_t *ppos)<br />
{<br />
	struct dlm_user_proc *proc = file->private_data;<br />
	struct dlm_write_request *kbuf;<br />
	sigset_t tmpsig, allsigs;<br />
	int error;</p>
<p>#ifdef CONFIG_COMPAT<br />
	if (count < sizeof(struct dlm_write_request32))<br />
#else<br />
	if (count < sizeof(struct dlm_write_request))<br />
#endif<br />
		return -EINVAL;</p>
<p>	kbuf = kzalloc(count + 1, GFP_KERNEL);<br />
	if (!kbuf)<br />
		return -ENOMEM;</p>
<p>	if (copy_from_user(kbuf, buf, count)) {<br />
		error = -EFAULT;<br />
		goto out_free;<br />
	}</p>
<p>	if (check_version(kbuf)) {<br />
		error = -EBADE;<br />
		goto out_free;<br />
	}</p>
<p>#ifdef CONFIG_COMPAT<br />
	if (!kbuf->is64bit) {<br />
		struct dlm_write_request32 *k32buf;<br />
		int namelen = 0;</p>
<p>		if (count > sizeof(struct dlm_write_request32))<br />
			namelen = count &#8211; sizeof(struct dlm_write_request32);</p>
<p>		k32buf = (struct dlm_write_request32 *)kbuf;</p>
<p>		/* add 1 after namelen so that the name string is terminated */<br />
		kbuf = kzalloc(sizeof(struct dlm_write_request) + namelen + 1,<br />
			       GFP_KERNEL);<br />
		if (!kbuf) {<br />
			kfree(k32buf);<br />
			return -ENOMEM;<br />
		}</p>
<p>		if (proc)<br />
			set_bit(DLM_PROC_FLAGS_COMPAT, &#038;proc->flags);</p>
<p>		compat_input(kbuf, k32buf, namelen);<br />
		kfree(k32buf);<br />
	}<br />
#endif</p>
<p>	/* do we really need this? can a write happen after a close? */<br />
	if ((kbuf->cmd == DLM_USER_LOCK || kbuf->cmd == DLM_USER_UNLOCK) &#038;&#038;<br />
	    (proc &#038;&#038; test_bit(DLM_PROC_FLAGS_CLOSING, &#038;proc->flags))) {<br />
		error = -EINVAL;<br />
		goto out_free;<br />
	}</p>
<p>	sigfillset(&#038;allsigs);<br />
	sigprocmask(SIG_BLOCK, &#038;allsigs, &#038;tmpsig);</p>
<p>	error = -EINVAL;</p>
<p>	switch (kbuf->cmd)<br />
	{<br />
	case DLM_USER_LOCK:<br />
		if (!proc) {<br />
			log_print(&raquo;no locking on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_user_lock(proc, &#038;kbuf->i.lock);<br />
		break;</p>
<p>	case DLM_USER_UNLOCK:<br />
		if (!proc) {<br />
			log_print(&raquo;no locking on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_user_unlock(proc, &#038;kbuf->i.lock);<br />
		break;</p>
<p>	case DLM_USER_DEADLOCK:<br />
		if (!proc) {<br />
			log_print(&raquo;no locking on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_user_deadlock(proc, &#038;kbuf->i.lock);<br />
		break;</p>
<p>	case DLM_USER_CREATE_LOCKSPACE:<br />
		if (proc) {<br />
			log_print(&raquo;create/remove only on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_create_lockspace(&#038;kbuf->i.lspace);<br />
		break;</p>
<p>	case DLM_USER_REMOVE_LOCKSPACE:<br />
		if (proc) {<br />
			log_print(&raquo;create/remove only on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_remove_lockspace(&#038;kbuf->i.lspace);<br />
		break;</p>
<p>	case DLM_USER_PURGE:<br />
		if (!proc) {<br />
			log_print(&raquo;no locking on control device&raquo;);<br />
			goto out_sig;<br />
		}<br />
		error = device_user_purge(proc, &#038;kbuf->i.purge);<br />
		break;</p>
<p>	default:<br />
		log_print(&raquo;Unknown command passed to DLM device : %d\n&raquo;,<br />
			  kbuf->cmd);<br />
	}</p>
<p> out_sig:<br />
	sigprocmask(SIG_SETMASK, &#038;tmpsig, NULL);<br />
	recalc_sigpending();<br />
 out_free:<br />
	kfree(kbuf);<br />
	return error;<br />
}</p>
<p>/* Every process that opens the lockspace device has its own &laquo;proc&raquo; structure<br />
   hanging off the open file that&#8217;s used to keep track of locks owned by the<br />
   process and asts that need to be delivered to the process. */</p>
<p>static int device_open(struct inode *inode, struct file *file)<br />
{<br />
	struct dlm_user_proc *proc;<br />
	struct dlm_ls *ls;</p>
<p>	ls = dlm_find_lockspace_device(iminor(inode));<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	proc = kzalloc(sizeof(struct dlm_user_proc), GFP_KERNEL);<br />
	if (!proc) {<br />
		dlm_put_lockspace(ls);<br />
		return -ENOMEM;<br />
	}</p>
<p>	proc->lockspace = ls->ls_local_handle;<br />
	INIT_LIST_HEAD(&#038;proc->asts);<br />
	INIT_LIST_HEAD(&#038;proc->locks);<br />
	INIT_LIST_HEAD(&#038;proc->unlocking);<br />
	spin_lock_init(&#038;proc->asts_spin);<br />
	spin_lock_init(&#038;proc->locks_spin);<br />
	init_waitqueue_head(&#038;proc->wait);<br />
	file->private_data = proc;</p>
<p>	return 0;<br />
}</p>
<p>static int device_close(struct inode *inode, struct file *file)<br />
{<br />
	struct dlm_user_proc *proc = file->private_data;<br />
	struct dlm_ls *ls;<br />
	sigset_t tmpsig, allsigs;</p>
<p>	ls = dlm_find_lockspace_local(proc->lockspace);<br />
	if (!ls)<br />
		return -ENOENT;</p>
<p>	sigfillset(&#038;allsigs);<br />
	sigprocmask(SIG_BLOCK, &#038;allsigs, &#038;tmpsig);</p>
<p>	set_bit(DLM_PROC_FLAGS_CLOSING, &#038;proc->flags);</p>
<p>	dlm_clear_proc_locks(ls, proc);</p>
<p>	/* at this point no more lkb&#8217;s should exist for this lockspace,<br />
	   so there&#8217;s no chance of dlm_user_add_ast() being called and<br />
	   looking for lkb->ua->proc */</p>
<p>	kfree(proc);<br />
	file->private_data = NULL;</p>
<p>	dlm_put_lockspace(ls);<br />
	dlm_put_lockspace(ls);  /* for the find in device_open() */</p>
<p>	/* FIXME: AUTOFREE: if this ls is no longer used do<br />
	   device_remove_lockspace() */</p>
<p>	sigprocmask(SIG_SETMASK, &#038;tmpsig, NULL);<br />
	recalc_sigpending();</p>
<p>	return 0;<br />
}</p>
<p>static int copy_result_to_user(struct dlm_user_args *ua, int compat, int type,<br />
			       int bmode, char __user *buf, size_t count)<br />
{<br />
#ifdef CONFIG_COMPAT<br />
	struct dlm_lock_result32 result32;<br />
#endif<br />
	struct dlm_lock_result result;<br />
	void *resultptr;<br />
	int error=0;<br />
	int len;<br />
	int struct_len;</p>
<p>	memset(&#038;result, 0, sizeof(struct dlm_lock_result));<br />
	result.version[0] = DLM_DEVICE_VERSION_MAJOR;<br />
	result.version[1] = DLM_DEVICE_VERSION_MINOR;<br />
	result.version[2] = DLM_DEVICE_VERSION_PATCH;<br />
	memcpy(&#038;result.lksb, &#038;ua->lksb, sizeof(struct dlm_lksb));<br />
	result.user_lksb = ua->user_lksb;</p>
<p>	/* FIXME: dlm1 provides for the user&#8217;s bastparam/addr to not be updated<br />
	   in a conversion unless the conversion is successful.  See code<br />
	   in dlm_user_convert() for updating ua from ua_tmp.  OpenVMS, though,<br />
	   notes that a new blocking AST address and parameter are set even if<br />
	   the conversion fails, so maybe we should just do that. */</p>
<p>	if (type == AST_BAST) {<br />
		result.user_astaddr = ua->bastaddr;<br />
		result.user_astparam = ua->bastparam;<br />
		result.bast_mode = bmode;<br />
	} else {<br />
		result.user_astaddr = ua->castaddr;<br />
		result.user_astparam = ua->castparam;<br />
	}</p>
<p>#ifdef CONFIG_COMPAT<br />
	if (compat)<br />
		len = sizeof(struct dlm_lock_result32);<br />
	else<br />
#endif<br />
		len = sizeof(struct dlm_lock_result);<br />
	struct_len = len;</p>
<p>	/* copy lvb to userspace if there is one, it&#8217;s been updated, and<br />
	   the user buffer has space for it */</p>
<p>	if (ua->update_user_lvb &#038;&#038; ua->lksb.sb_lvbptr &#038;&#038;<br />
	    count >= len + DLM_USER_LVB_LEN) {<br />
		if (copy_to_user(buf+len, ua->lksb.sb_lvbptr,<br />
				 DLM_USER_LVB_LEN)) {<br />
			error = -EFAULT;<br />
			goto out;<br />
		}</p>
<p>		result.lvb_offset = len;<br />
		len += DLM_USER_LVB_LEN;<br />
	}</p>
<p>	result.length = len;<br />
	resultptr = &result;<br />
#ifdef CONFIG_COMPAT<br />
	if (compat) {<br />
		compat_output(&#038;result, &#038;result32);<br />
		resultptr = &result32;<br />
	}<br />
#endif</p>
<p>	if (copy_to_user(buf, resultptr, struct_len))<br />
		error = -EFAULT;<br />
	else<br />
		error = len;<br />
 out:<br />
	return error;<br />
}</p>
<p>static int copy_version_to_user(char __user *buf, size_t count)<br />
{<br />
	struct dlm_device_version ver;</p>
<p>	memset(&#038;ver, 0, sizeof(struct dlm_device_version));<br />
	ver.version[0] = DLM_DEVICE_VERSION_MAJOR;<br />
	ver.version[1] = DLM_DEVICE_VERSION_MINOR;<br />
	ver.version[2] = DLM_DEVICE_VERSION_PATCH;</p>
<p>	if (copy_to_user(buf, &#038;ver, sizeof(struct dlm_device_version)))<br />
		return -EFAULT;<br />
	return sizeof(struct dlm_device_version);<br />
}</p>
<p>/* a read returns a single ast described in a struct dlm_lock_result */</p>
<p>static ssize_t device_read(struct file *file, char __user *buf, size_t count,<br />
			   loff_t *ppos)<br />
{<br />
	struct dlm_user_proc *proc = file->private_data;<br />
	struct dlm_lkb *lkb;<br />
	DECLARE_WAITQUEUE(wait, current);<br />
	int error, type=0, bmode=0, removed = 0;</p>
<p>	if (count == sizeof(struct dlm_device_version)) {<br />
		error = copy_version_to_user(buf, count);<br />
		return error;<br />
	}</p>
<p>	if (!proc) {<br />
		log_print(&raquo;non-version read from control device %zu&raquo;, count);<br />
		return -EINVAL;<br />
	}</p>
<p>#ifdef CONFIG_COMPAT<br />
	if (count < sizeof(struct dlm_lock_result32))<br />
#else<br />
	if (count < sizeof(struct dlm_lock_result))<br />
#endif<br />
		return -EINVAL;</p>
<p>	/* do we really need this? can a read happen after a close? */<br />
	if (test_bit(DLM_PROC_FLAGS_CLOSING, &#038;proc->flags))<br />
		return -EINVAL;</p>
<p>	spin_lock(&#038;proc->asts_spin);<br />
	if (list_empty(&#038;proc->asts)) {<br />
		if (file->f_flags &#038; O_NONBLOCK) {<br />
			spin_unlock(&#038;proc->asts_spin);<br />
			return -EAGAIN;<br />
		}</p>
<p>		add_wait_queue(&#038;proc->wait, &#038;wait);</p>
<p>	repeat:<br />
		set_current_state(TASK_INTERRUPTIBLE);<br />
		if (list_empty(&#038;proc->asts) &#038;&#038; !signal_pending(current)) {<br />
			spin_unlock(&#038;proc->asts_spin);<br />
			schedule();<br />
			spin_lock(&#038;proc->asts_spin);<br />
			goto repeat;<br />
		}<br />
		set_current_state(TASK_RUNNING);<br />
		remove_wait_queue(&#038;proc->wait, &#038;wait);</p>
<p>		if (signal_pending(current)) {<br />
			spin_unlock(&#038;proc->asts_spin);<br />
			return -ERESTARTSYS;<br />
		}<br />
	}</p>
<p>	/* there may be both completion and blocking asts to return for<br />
	   the lkb, don&#8217;t remove lkb from asts list unless no asts remain */</p>
<p>	lkb = list_entry(proc->asts.next, struct dlm_lkb, lkb_astqueue);</p>
<p>	if (lkb->lkb_ast_type &#038; AST_COMP) {<br />
		lkb->lkb_ast_type &#038;= ~AST_COMP;<br />
		type = AST_COMP;<br />
	} else if (lkb->lkb_ast_type &#038; AST_BAST) {<br />
		lkb->lkb_ast_type &#038;= ~AST_BAST;<br />
		type = AST_BAST;<br />
		bmode = lkb->lkb_bastmode;<br />
	}</p>
<p>	if (!lkb->lkb_ast_type) {<br />
		list_del(&#038;lkb->lkb_astqueue);<br />
		removed = 1;<br />
	}<br />
	spin_unlock(&#038;proc->asts_spin);</p>
<p>	error = copy_result_to_user(lkb->lkb_ua,<br />
			 	test_bit(DLM_PROC_FLAGS_COMPAT, &#038;proc->flags),<br />
				type, bmode, buf, count);</p>
<p>	/* removes reference for the proc->asts lists added by<br />
	   dlm_user_add_ast() and may result in the lkb being freed */<br />
	if (removed)<br />
		dlm_put_lkb(lkb);</p>
<p>	return error;<br />
}</p>
<p>static unsigned int device_poll(struct file *file, poll_table *wait)<br />
{<br />
	struct dlm_user_proc *proc = file->private_data;</p>
<p>	poll_wait(file, &#038;proc->wait, wait);</p>
<p>	spin_lock(&#038;proc->asts_spin);<br />
	if (!list_empty(&#038;proc->asts)) {<br />
		spin_unlock(&#038;proc->asts_spin);<br />
		return POLLIN | POLLRDNORM;<br />
	}<br />
	spin_unlock(&#038;proc->asts_spin);<br />
	return 0;<br />
}</p>
<p>int dlm_user_daemon_available(void)<br />
{<br />
	/* dlm_controld hasn&#8217;t started (or, has started, but not<br />
	   properly populated configfs) */</p>
<p>	if (!dlm_our_nodeid())<br />
		return 0;</p>
<p>	/* This is to deal with versions of dlm_controld that don&#8217;t<br />
	   know about the monitor device.  We assume that if the<br />
	   dlm_controld was started (above), but the monitor device<br />
	   was never opened, that it&#8217;s an old version.  dlm_controld<br />
	   should open the monitor device before populating configfs. */</p>
<p>	if (dlm_monitor_unused)<br />
		return 1;</p>
<p>	return atomic_read(&#038;dlm_monitor_opened) ? 1 : 0;<br />
}</p>
<p>static int ctl_device_open(struct inode *inode, struct file *file)<br />
{<br />
	file->private_data = NULL;<br />
	return 0;<br />
}</p>
<p>static int ctl_device_close(struct inode *inode, struct file *file)<br />
{<br />
	return 0;<br />
}</p>
<p>static int monitor_device_open(struct inode *inode, struct file *file)<br />
{<br />
	atomic_inc(&#038;dlm_monitor_opened);<br />
	dlm_monitor_unused = 0;<br />
	return 0;<br />
}</p>
<p>static int monitor_device_close(struct inode *inode, struct file *file)<br />
{<br />
	if (atomic_dec_and_test(&#038;dlm_monitor_opened))<br />
		dlm_stop_lockspaces();<br />
	return 0;<br />
}</p>
<p>static const struct file_operations device_fops = {<br />
	.open    = device_open,<br />
	.release = device_close,<br />
	.read    = device_read,<br />
	.write   = device_write,<br />
	.poll    = device_poll,<br />
	.owner   = THIS_MODULE,<br />
};</p>
<p>static const struct file_operations ctl_device_fops = {<br />
	.open    = ctl_device_open,<br />
	.release = ctl_device_close,<br />
	.read    = device_read,<br />
	.write   = device_write,<br />
	.owner   = THIS_MODULE,<br />
};</p>
<p>static struct miscdevice ctl_device = {<br />
	.name  = &laquo;dlm-control&raquo;,<br />
	.fops  = &#038;ctl_device_fops,<br />
	.minor = MISC_DYNAMIC_MINOR,<br />
};</p>
<p>static const struct file_operations monitor_device_fops = {<br />
	.open    = monitor_device_open,<br />
	.release = monitor_device_close,<br />
	.owner   = THIS_MODULE,<br />
};</p>
<p>static struct miscdevice monitor_device = {<br />
	.name  = &laquo;dlm-monitor&raquo;,<br />
	.fops  = &#038;monitor_device_fops,<br />
	.minor = MISC_DYNAMIC_MINOR,<br />
};</p>
<p>int __init dlm_user_init(void)<br />
{<br />
	int error;</p>
<p>	atomic_set(&#038;dlm_monitor_opened, 0);</p>
<p>	error = misc_register(&#038;ctl_device);<br />
	if (error) {<br />
		log_print(&raquo;misc_register failed for control device&raquo;);<br />
		goto out;<br />
	}</p>
<p>	error = misc_register(&#038;monitor_device);<br />
	if (error) {<br />
		log_print(&raquo;misc_register failed for monitor device&raquo;);<br />
		misc_deregister(&#038;ctl_device);<br />
	}<br />
 out:<br />
	return error;<br />
}</p>
<p>void dlm_user_exit(void)<br />
{<br />
	misc_deregister(&#038;ctl_device);<br />
	misc_deregister(&#038;monitor_device);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/user-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>requestqueue.h</title>
		<link>http://lynyrd.ru/requestqueue-h</link>
		<comments>http://lynyrd.ru/requestqueue-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:59:29 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/requestqueue-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#ifndef __REQUESTQUEUE_DOT_H__
#define __REQUESTQUEUE_DOT_H__
void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms);
int dlm_process_requestqueue(struct ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.<span id="more-1071"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __REQUESTQUEUE_DOT_H__<br />
#define __REQUESTQUEUE_DOT_H__</p>
<p>void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms);<br />
int dlm_process_requestqueue(struct dlm_ls *ls);<br />
void dlm_wait_requestqueue(struct dlm_ls *ls);<br />
void dlm_purge_requestqueue(struct dlm_ls *ls);</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/requestqueue-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>requestqueue.c</title>
		<link>http://lynyrd.ru/requestqueue-c</link>
		<comments>http://lynyrd.ru/requestqueue-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:59:11 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/requestqueue-c</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License v.2.
**
*******************************************************************************
******************************************************************************/
#include &#171;dlm_internal.h&#187;
#include &#171;member.h&#187;
#include &#171;lock.h&#187;
#include &#171;dir.h&#187;
#include &#171;config.h&#187;
#include &#171;requestqueue.h&#187;
struct rq_entry {
	struct list_head list;
	int nodeid;
	struct ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.<span id="more-1070"></span><br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;dir.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;requestqueue.h&raquo;</p>
<p>struct rq_entry {<br />
	struct list_head list;<br />
	int nodeid;<br />
	struct dlm_message request;<br />
};</p>
<p>/*<br />
 * Requests received while the lockspace is in recovery get added to the<br />
 * request queue and processed when recovery is complete.  This happens when<br />
 * the lockspace is suspended on some nodes before it is on others, or the<br />
 * lockspace is enabled on some while still suspended on others.<br />
 */</p>
<p>void dlm_add_requestqueue(struct dlm_ls *ls, int nodeid, struct dlm_message *ms)<br />
{<br />
	struct rq_entry *e;<br />
	int length = ms->m_header.h_length &#8211; sizeof(struct dlm_message);</p>
<p>	e = kmalloc(sizeof(struct rq_entry) + length, ls->ls_allocation);<br />
	if (!e) {<br />
		log_print(&raquo;dlm_add_requestqueue: out of memory len %d&raquo;, length);<br />
		return;<br />
	}</p>
<p>	e->nodeid = nodeid;<br />
	memcpy(&#038;e->request, ms, ms->m_header.h_length);</p>
<p>	mutex_lock(&#038;ls->ls_requestqueue_mutex);<br />
	list_add_tail(&#038;e->list, &#038;ls->ls_requestqueue);<br />
	mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
}</p>
<p>/*<br />
 * Called by dlm_recoverd to process normal messages saved while recovery was<br />
 * happening.  Normal locking has been enabled before this is called.  dlm_recv<br />
 * upon receiving a message, will wait for all saved messages to be drained<br />
 * here before processing the message it got.  If a new dlm_ls_stop() arrives<br />
 * while we&#8217;re processing these saved messages, it may block trying to suspend<br />
 * dlm_recv if dlm_recv is waiting for us in dlm_wait_requestqueue.  In that<br />
 * case, we don&#8217;t abort since locking_stopped is still 0.  If dlm_recv is not<br />
 * waiting for us, then this processing may be aborted due to locking_stopped.<br />
 */</p>
<p>int dlm_process_requestqueue(struct dlm_ls *ls)<br />
{<br />
	struct rq_entry *e;<br />
	int error = 0;</p>
<p>	mutex_lock(&#038;ls->ls_requestqueue_mutex);</p>
<p>	for (;;) {<br />
		if (list_empty(&#038;ls->ls_requestqueue)) {<br />
			mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
			error = 0;<br />
			break;<br />
		}<br />
		e = list_entry(ls->ls_requestqueue.next, struct rq_entry, list);<br />
		mutex_unlock(&#038;ls->ls_requestqueue_mutex);</p>
<p>		dlm_receive_message_saved(ls, &#038;e->request);</p>
<p>		mutex_lock(&#038;ls->ls_requestqueue_mutex);<br />
		list_del(&#038;e->list);<br />
		kfree(e);</p>
<p>		if (dlm_locking_stopped(ls)) {<br />
			log_debug(ls, &laquo;process_requestqueue abort running&raquo;);<br />
			mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
			error = -EINTR;<br />
			break;<br />
		}<br />
		schedule();<br />
	}</p>
<p>	return error;<br />
}</p>
<p>/*<br />
 * After recovery is done, locking is resumed and dlm_recoverd takes all the<br />
 * saved requests and processes them as they would have been by dlm_recv.  At<br />
 * the same time, dlm_recv will start receiving new requests from remote nodes.<br />
 * We want to delay dlm_recv processing new requests until dlm_recoverd has<br />
 * finished processing the old saved requests.  We don&#8217;t check for locking<br />
 * stopped here because dlm_ls_stop won&#8217;t stop locking until it&#8217;s suspended us<br />
 * (dlm_recv).<br />
 */</p>
<p>void dlm_wait_requestqueue(struct dlm_ls *ls)<br />
{<br />
	for (;;) {<br />
		mutex_lock(&#038;ls->ls_requestqueue_mutex);<br />
		if (list_empty(&#038;ls->ls_requestqueue))<br />
			break;<br />
		mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
		schedule();<br />
	}<br />
	mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
}</p>
<p>static int purge_request(struct dlm_ls *ls, struct dlm_message *ms, int nodeid)<br />
{<br />
	uint32_t type = ms->m_type;</p>
<p>	/* the ls is being cleaned up and freed by release_lockspace */<br />
	if (!ls->ls_count)<br />
		return 1;</p>
<p>	if (dlm_is_removed(ls, nodeid))<br />
		return 1;</p>
<p>	/* directory operations are always purged because the directory is<br />
	   always rebuilt during recovery and the lookups resent */</p>
<p>	if (type == DLM_MSG_REMOVE ||<br />
	    type == DLM_MSG_LOOKUP ||<br />
	    type == DLM_MSG_LOOKUP_REPLY)<br />
		return 1;</p>
<p>	if (!dlm_no_directory(ls))<br />
		return 0;</p>
<p>	/* with no directory, the master is likely to change as a part of<br />
	   recovery; requests to/from the defunct master need to be purged */</p>
<p>	switch (type) {<br />
	case DLM_MSG_REQUEST:<br />
	case DLM_MSG_CONVERT:<br />
	case DLM_MSG_UNLOCK:<br />
	case DLM_MSG_CANCEL:<br />
		/* we&#8217;re no longer the master of this resource, the sender<br />
		   will resend to the new master (see waiter_needs_recovery) */</p>
<p>		if (dlm_hash2nodeid(ls, ms->m_hash) != dlm_our_nodeid())<br />
			return 1;<br />
		break;</p>
<p>	case DLM_MSG_REQUEST_REPLY:<br />
	case DLM_MSG_CONVERT_REPLY:<br />
	case DLM_MSG_UNLOCK_REPLY:<br />
	case DLM_MSG_CANCEL_REPLY:<br />
	case DLM_MSG_GRANT:<br />
		/* this reply is from the former master of the resource,<br />
		   we&#8217;ll resend to the new master if needed */</p>
<p>		if (dlm_hash2nodeid(ls, ms->m_hash) != nodeid)<br />
			return 1;<br />
		break;<br />
	}</p>
<p>	return 0;<br />
}</p>
<p>void dlm_purge_requestqueue(struct dlm_ls *ls)<br />
{<br />
	struct dlm_message *ms;<br />
	struct rq_entry *e, *safe;</p>
<p>	mutex_lock(&#038;ls->ls_requestqueue_mutex);<br />
	list_for_each_entry_safe(e, safe, &#038;ls->ls_requestqueue, list) {<br />
		ms =  &#038;e->request;</p>
<p>		if (purge_request(ls, ms, e->nodeid)) {<br />
			list_del(&#038;e->list);<br />
			kfree(e);<br />
		}<br />
	}<br />
	mutex_unlock(&#038;ls->ls_requestqueue_mutex);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/requestqueue-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>recoverd.h</title>
		<link>http://lynyrd.ru/recoverd-h</link>
		<comments>http://lynyrd.ru/recoverd-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:58:54 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/recoverd-h</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1069"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __RECOVERD_DOT_H__<br />
#define __RECOVERD_DOT_H__</p>
<p>void dlm_recoverd_kick(struct dlm_ls *ls);<br />
void dlm_recoverd_stop(struct dlm_ls *ls);<br />
int dlm_recoverd_start(struct dlm_ls *ls);<br />
void dlm_recoverd_suspend(struct dlm_ls *ls);<br />
void dlm_recoverd_resume(struct dlm_ls *ls);</p>
<p>#endif				/* __RECOVERD_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/recoverd-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>recoverd.c</title>
		<link>http://lynyrd.ru/recoverd-c</link>
		<comments>http://lynyrd.ru/recoverd-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:58:36 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1067</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1067"></span><br />
**  Copyright (C) 2004-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;dir.h&raquo;<br />
#include &laquo;ast.h&raquo;<br />
#include &laquo;recover.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;requestqueue.h&raquo;<br />
#include &laquo;recoverd.h&raquo;</p>
<p>/* If the start for which we&#8217;re re-enabling locking (seq) has been superseded<br />
   by a newer stop (ls_recover_seq), we need to leave locking disabled.</p>
<p>   We suspend dlm_recv threads here to avoid the race where dlm_recv a) sees<br />
   locking stopped and b) adds a message to the requestqueue, but dlm_recoverd<br />
   enables locking and clears the requestqueue between a and b. */</p>
<p>static int enable_locking(struct dlm_ls *ls, uint64_t seq)<br />
{<br />
	int error = -EINTR;</p>
<p>	down_write(&#038;ls->ls_recv_active);</p>
<p>	spin_lock(&#038;ls->ls_recover_lock);<br />
	if (ls->ls_recover_seq == seq) {<br />
		set_bit(LSFL_RUNNING, &#038;ls->ls_flags);<br />
		/* unblocks processes waiting to enter the dlm */<br />
		up_write(&#038;ls->ls_in_recovery);<br />
		error = 0;<br />
	}<br />
	spin_unlock(&#038;ls->ls_recover_lock);</p>
<p>	up_write(&#038;ls->ls_recv_active);<br />
	return error;<br />
}</p>
<p>static int ls_recover(struct dlm_ls *ls, struct dlm_recover *rv)<br />
{<br />
	unsigned long start;<br />
	int error, neg = 0;</p>
<p>	log_debug(ls, &laquo;recover %llx&raquo;, (unsigned long long)rv->seq);</p>
<p>	mutex_lock(&#038;ls->ls_recoverd_active);</p>
<p>	/*<br />
	 * Suspending and resuming dlm_astd ensures that no lkb&#8217;s from this ls<br />
	 * will be processed by dlm_astd during recovery.<br />
	 */</p>
<p>	dlm_astd_suspend();<br />
	dlm_astd_resume();</p>
<p>	/*<br />
	 * Free non-master tossed rsb&#8217;s.  Master rsb&#8217;s are kept on toss<br />
	 * list and put on root list to be included in resdir recovery.<br />
	 */</p>
<p>	dlm_clear_toss_list(ls);</p>
<p>	/*<br />
	 * This list of root rsb&#8217;s will be the basis of most of the recovery<br />
	 * routines.<br />
	 */</p>
<p>	dlm_create_root_list(ls);</p>
<p>	/*<br />
	 * Add or remove nodes from the lockspace&#8217;s ls_nodes list.<br />
	 * Also waits for all nodes to complete dlm_recover_members.<br />
	 */</p>
<p>	error = dlm_recover_members(ls, rv, &#038;neg);<br />
	if (error) {<br />
		log_debug(ls, &laquo;recover_members failed %d&raquo;, error);<br />
		goto fail;<br />
	}<br />
	start = jiffies;</p>
<p>	/*<br />
	 * Rebuild our own share of the directory by collecting from all other<br />
	 * nodes their master rsb names that hash to us.<br />
	 */</p>
<p>	error = dlm_recover_directory(ls);<br />
	if (error) {<br />
		log_debug(ls, &laquo;recover_directory failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	/*<br />
	 * Wait for all nodes to complete directory rebuild.<br />
	 */</p>
<p>	error = dlm_recover_directory_wait(ls);<br />
	if (error) {<br />
		log_debug(ls, &laquo;recover_directory_wait failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	/*<br />
	 * We may have outstanding operations that are waiting for a reply from<br />
	 * a failed node.  Mark these to be resent after recovery.  Unlock and<br />
	 * cancel ops can just be completed.<br />
	 */</p>
<p>	dlm_recover_waiters_pre(ls);</p>
<p>	error = dlm_recovery_stopped(ls);<br />
	if (error)<br />
		goto fail;</p>
<p>	if (neg || dlm_no_directory(ls)) {<br />
		/*<br />
		 * Clear lkb&#8217;s for departed nodes.<br />
		 */</p>
<p>		dlm_purge_locks(ls);</p>
<p>		/*<br />
		 * Get new master nodeid&#8217;s for rsb&#8217;s that were mastered on<br />
		 * departed nodes.<br />
		 */</p>
<p>		error = dlm_recover_masters(ls);<br />
		if (error) {<br />
			log_debug(ls, &laquo;recover_masters failed %d&raquo;, error);<br />
			goto fail;<br />
		}</p>
<p>		/*<br />
		 * Send our locks on remastered rsb&#8217;s to the new masters.<br />
		 */</p>
<p>		error = dlm_recover_locks(ls);<br />
		if (error) {<br />
			log_debug(ls, &laquo;recover_locks failed %d&raquo;, error);<br />
			goto fail;<br />
		}</p>
<p>		error = dlm_recover_locks_wait(ls);<br />
		if (error) {<br />
			log_debug(ls, &laquo;recover_locks_wait failed %d&raquo;, error);<br />
			goto fail;<br />
		}</p>
<p>		/*<br />
		 * Finalize state in master rsb&#8217;s now that all locks can be<br />
		 * checked.  This includes conversion resolution and lvb<br />
		 * settings.<br />
		 */</p>
<p>		dlm_recover_rsbs(ls);<br />
	} else {<br />
		/*<br />
		 * Other lockspace members may be going through the &laquo;neg&raquo; steps<br />
		 * while also adding us to the lockspace, in which case they&#8217;ll<br />
		 * be doing the recover_locks (RS_LOCKS) barrier.<br />
		 */<br />
		dlm_set_recover_status(ls, DLM_RS_LOCKS);</p>
<p>		error = dlm_recover_locks_wait(ls);<br />
		if (error) {<br />
			log_debug(ls, &laquo;recover_locks_wait failed %d&raquo;, error);<br />
			goto fail;<br />
		}<br />
	}</p>
<p>	dlm_release_root_list(ls);</p>
<p>	/*<br />
	 * Purge directory-related requests that are saved in requestqueue.<br />
	 * All dir requests from before recovery are invalid now due to the dir<br />
	 * rebuild and will be resent by the requesting nodes.<br />
	 */</p>
<p>	dlm_purge_requestqueue(ls);</p>
<p>	dlm_set_recover_status(ls, DLM_RS_DONE);<br />
	error = dlm_recover_done_wait(ls);<br />
	if (error) {<br />
		log_debug(ls, &laquo;recover_done_wait failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	dlm_clear_members_gone(ls);</p>
<p>	dlm_adjust_timeouts(ls);</p>
<p>	error = enable_locking(ls, rv->seq);<br />
	if (error) {<br />
		log_debug(ls, &laquo;enable_locking failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	error = dlm_process_requestqueue(ls);<br />
	if (error) {<br />
		log_debug(ls, &laquo;process_requestqueue failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	error = dlm_recover_waiters_post(ls);<br />
	if (error) {<br />
		log_debug(ls, &laquo;recover_waiters_post failed %d&raquo;, error);<br />
		goto fail;<br />
	}</p>
<p>	dlm_grant_after_purge(ls);</p>
<p>	dlm_astd_wake();</p>
<p>	log_debug(ls, &laquo;recover %llx done: %u ms&raquo;,<br />
		  (unsigned long long)rv->seq,<br />
		  jiffies_to_msecs(jiffies &#8211; start));<br />
	mutex_unlock(&#038;ls->ls_recoverd_active);</p>
<p>	return 0;</p>
<p> fail:<br />
	dlm_release_root_list(ls);<br />
	log_debug(ls, &laquo;recover %llx error %d&raquo;,<br />
		  (unsigned long long)rv->seq, error);<br />
	mutex_unlock(&#038;ls->ls_recoverd_active);<br />
	return error;<br />
}</p>
<p>/* The dlm_ls_start() that created the rv we take here may already have been<br />
   stopped via dlm_ls_stop(); in that case we need to leave the RECOVERY_STOP<br />
   flag set. */</p>
<p>static void do_ls_recovery(struct dlm_ls *ls)<br />
{<br />
	struct dlm_recover *rv = NULL;</p>
<p>	spin_lock(&#038;ls->ls_recover_lock);<br />
	rv = ls->ls_recover_args;<br />
	ls->ls_recover_args = NULL;<br />
	if (rv &#038;&#038; ls->ls_recover_seq == rv->seq)<br />
		clear_bit(LSFL_RECOVERY_STOP, &#038;ls->ls_flags);<br />
	spin_unlock(&#038;ls->ls_recover_lock);</p>
<p>	if (rv) {<br />
		ls_recover(ls, rv);<br />
		kfree(rv->nodeids);<br />
		kfree(rv->new);<br />
		kfree(rv);<br />
	}<br />
}</p>
<p>static int dlm_recoverd(void *arg)<br />
{<br />
	struct dlm_ls *ls;</p>
<p>	ls = dlm_find_lockspace_local(arg);<br />
	if (!ls) {<br />
		log_print(&raquo;dlm_recoverd: no lockspace %p&raquo;, arg);<br />
		return -1;<br />
	}</p>
<p>	while (!kthread_should_stop()) {<br />
		set_current_state(TASK_INTERRUPTIBLE);<br />
		if (!test_bit(LSFL_WORK, &#038;ls->ls_flags))<br />
			schedule();<br />
		set_current_state(TASK_RUNNING);</p>
<p>		if (test_and_clear_bit(LSFL_WORK, &#038;ls->ls_flags))<br />
			do_ls_recovery(ls);<br />
	}</p>
<p>	dlm_put_lockspace(ls);<br />
	return 0;<br />
}</p>
<p>void dlm_recoverd_kick(struct dlm_ls *ls)<br />
{<br />
	set_bit(LSFL_WORK, &#038;ls->ls_flags);<br />
	wake_up_process(ls->ls_recoverd_task);<br />
}</p>
<p>int dlm_recoverd_start(struct dlm_ls *ls)<br />
{<br />
	struct task_struct *p;<br />
	int error = 0;</p>
<p>	p = kthread_run(dlm_recoverd, ls, &laquo;dlm_recoverd&raquo;);<br />
	if (IS_ERR(p))<br />
		error = PTR_ERR(p);<br />
	else<br />
                ls->ls_recoverd_task = p;<br />
	return error;<br />
}</p>
<p>void dlm_recoverd_stop(struct dlm_ls *ls)<br />
{<br />
	kthread_stop(ls->ls_recoverd_task);<br />
}</p>
<p>void dlm_recoverd_suspend(struct dlm_ls *ls)<br />
{<br />
	wake_up(&#038;ls->ls_wait_general);<br />
	mutex_lock(&#038;ls->ls_recoverd_active);<br />
}</p>
<p>void dlm_recoverd_resume(struct dlm_ls *ls)<br />
{<br />
	mutex_unlock(&#038;ls->ls_recoverd_active);<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/recoverd-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>recover.h</title>
		<link>http://lynyrd.ru/recover-h</link>
		<comments>http://lynyrd.ru/recover-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:57:59 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1065</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1065"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __RECOVER_DOT_H__<br />
#define __RECOVER_DOT_H__</p>
<p>int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls));<br />
uint32_t dlm_recover_status(struct dlm_ls *ls);<br />
void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status);<br />
int dlm_recover_members_wait(struct dlm_ls *ls);<br />
int dlm_recover_directory_wait(struct dlm_ls *ls);<br />
int dlm_recover_locks_wait(struct dlm_ls *ls);<br />
int dlm_recover_done_wait(struct dlm_ls *ls);<br />
int dlm_recover_masters(struct dlm_ls *ls);<br />
int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc);<br />
int dlm_recover_locks(struct dlm_ls *ls);<br />
void dlm_recovered_lock(struct dlm_rsb *r);<br />
int dlm_create_root_list(struct dlm_ls *ls);<br />
void dlm_release_root_list(struct dlm_ls *ls);<br />
void dlm_clear_toss_list(struct dlm_ls *ls);<br />
void dlm_recover_rsbs(struct dlm_ls *ls);</p>
<p>#endif				/* __RECOVER_DOT_H__ */</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/recover-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>recover.c</title>
		<link>http://lynyrd.ru/recover-c</link>
		<comments>http://lynyrd.ru/recover-c#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:57:39 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/recover-c</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1064"></span><br />
**  Copyright (C) 2004-2005 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#include &laquo;dlm_internal.h&raquo;<br />
#include &laquo;lockspace.h&raquo;<br />
#include &laquo;dir.h&raquo;<br />
#include &laquo;config.h&raquo;<br />
#include &laquo;ast.h&raquo;<br />
#include &laquo;memory.h&raquo;<br />
#include &laquo;rcom.h&raquo;<br />
#include &laquo;lock.h&raquo;<br />
#include &laquo;lowcomms.h&raquo;<br />
#include &laquo;member.h&raquo;<br />
#include &laquo;recover.h&raquo;</p>
<p>/*<br />
 * Recovery waiting routines: these functions wait for a particular reply from<br />
 * a remote node, or for the remote node to report a certain status.  They need<br />
 * to abort if the lockspace is stopped indicating a node has failed (perhaps<br />
 * the one being waited for).<br />
 */</p>
<p>/*<br />
 * Wait until given function returns non-zero or lockspace is stopped<br />
 * (LS_RECOVERY_STOP set due to failure of a node in ls_nodes).  When another<br />
 * function thinks it could have completed the waited-on task, they should wake<br />
 * up ls_wait_general to get an immediate response rather than waiting for the<br />
 * timer to detect the result.  A timer wakes us up periodically while waiting<br />
 * to see if we should abort due to a node failure.  This should only be called<br />
 * by the dlm_recoverd thread.<br />
 */</p>
<p>static void dlm_wait_timer_fn(unsigned long data)<br />
{<br />
	struct dlm_ls *ls = (struct dlm_ls *) data;<br />
	mod_timer(&#038;ls->ls_timer, jiffies + (dlm_config.ci_recover_timer * HZ));<br />
	wake_up(&#038;ls->ls_wait_general);<br />
}</p>
<p>int dlm_wait_function(struct dlm_ls *ls, int (*testfn) (struct dlm_ls *ls))<br />
{<br />
	int error = 0;</p>
<p>	init_timer(&#038;ls->ls_timer);<br />
	ls->ls_timer.function = dlm_wait_timer_fn;<br />
	ls->ls_timer.data = (long) ls;<br />
	ls->ls_timer.expires = jiffies + (dlm_config.ci_recover_timer * HZ);<br />
	add_timer(&#038;ls->ls_timer);</p>
<p>	wait_event(ls->ls_wait_general, testfn(ls) || dlm_recovery_stopped(ls));<br />
	del_timer_sync(&#038;ls->ls_timer);</p>
<p>	if (dlm_recovery_stopped(ls)) {<br />
		log_debug(ls, &laquo;dlm_wait_function aborted&raquo;);<br />
		error = -EINTR;<br />
	}<br />
	return error;<br />
}</p>
<p>/*<br />
 * An efficient way for all nodes to wait for all others to have a certain<br />
 * status.  The node with the lowest nodeid polls all the others for their<br />
 * status (wait_status_all) and all the others poll the node with the low id<br />
 * for its accumulated result (wait_status_low).  When all nodes have set<br />
 * status flag X, then status flag X_ALL will be set on the low nodeid.<br />
 */</p>
<p>uint32_t dlm_recover_status(struct dlm_ls *ls)<br />
{<br />
	uint32_t status;<br />
	spin_lock(&#038;ls->ls_recover_lock);<br />
	status = ls->ls_recover_status;<br />
	spin_unlock(&#038;ls->ls_recover_lock);<br />
	return status;<br />
}</p>
<p>void dlm_set_recover_status(struct dlm_ls *ls, uint32_t status)<br />
{<br />
	spin_lock(&#038;ls->ls_recover_lock);<br />
	ls->ls_recover_status |= status;<br />
	spin_unlock(&#038;ls->ls_recover_lock);<br />
}</p>
<p>static int wait_status_all(struct dlm_ls *ls, uint32_t wait_status)<br />
{<br />
	struct dlm_rcom *rc = ls->ls_recover_buf;<br />
	struct dlm_member *memb;<br />
	int error = 0, delay;</p>
<p>	list_for_each_entry(memb, &#038;ls->ls_nodes, list) {<br />
		delay = 0;<br />
		for (;;) {<br />
			if (dlm_recovery_stopped(ls)) {<br />
				error = -EINTR;<br />
				goto out;<br />
			}</p>
<p>			error = dlm_rcom_status(ls, memb->nodeid);<br />
			if (error)<br />
				goto out;</p>
<p>			if (rc->rc_result &#038; wait_status)<br />
				break;<br />
			if (delay < 1000)<br />
				delay += 20;<br />
			msleep(delay);<br />
		}<br />
	}<br />
 out:<br />
	return error;<br />
}</p>
<p>static int wait_status_low(struct dlm_ls *ls, uint32_t wait_status)<br />
{<br />
	struct dlm_rcom *rc = ls->ls_recover_buf;<br />
	int error = 0, delay = 0, nodeid = ls->ls_low_nodeid;</p>
<p>	for (;;) {<br />
		if (dlm_recovery_stopped(ls)) {<br />
			error = -EINTR;<br />
			goto out;<br />
		}</p>
<p>		error = dlm_rcom_status(ls, nodeid);<br />
		if (error)<br />
			break;</p>
<p>		if (rc->rc_result &#038; wait_status)<br />
			break;<br />
		if (delay < 1000)<br />
			delay += 20;<br />
		msleep(delay);<br />
	}<br />
 out:<br />
	return error;<br />
}</p>
<p>static int wait_status(struct dlm_ls *ls, uint32_t status)<br />
{<br />
	uint32_t status_all = status << 1;<br />
	int error;</p>
<p>	if (ls->ls_low_nodeid == dlm_our_nodeid()) {<br />
		error = wait_status_all(ls, status);<br />
		if (!error)<br />
			dlm_set_recover_status(ls, status_all);<br />
	} else<br />
		error = wait_status_low(ls, status_all);</p>
<p>	return error;<br />
}</p>
<p>int dlm_recover_members_wait(struct dlm_ls *ls)<br />
{<br />
	return wait_status(ls, DLM_RS_NODES);<br />
}</p>
<p>int dlm_recover_directory_wait(struct dlm_ls *ls)<br />
{<br />
	return wait_status(ls, DLM_RS_DIR);<br />
}</p>
<p>int dlm_recover_locks_wait(struct dlm_ls *ls)<br />
{<br />
	return wait_status(ls, DLM_RS_LOCKS);<br />
}</p>
<p>int dlm_recover_done_wait(struct dlm_ls *ls)<br />
{<br />
	return wait_status(ls, DLM_RS_DONE);<br />
}</p>
<p>/*<br />
 * The recover_list contains all the rsb&#8217;s for which we&#8217;ve requested the new<br />
 * master nodeid.  As replies are returned from the resource directories the<br />
 * rsb&#8217;s are removed from the list.  When the list is empty we&#8217;re done.<br />
 *<br />
 * The recover_list is later similarly used for all rsb&#8217;s for which we&#8217;ve sent<br />
 * new lkb&#8217;s and need to receive new corresponding lkid&#8217;s.<br />
 *<br />
 * We use the address of the rsb struct as a simple local identifier for the<br />
 * rsb so we can match an rcom reply with the rsb it was sent for.<br />
 */</p>
<p>static int recover_list_empty(struct dlm_ls *ls)<br />
{<br />
	int empty;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	empty = list_empty(&#038;ls->ls_recover_list);<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);</p>
<p>	return empty;<br />
}</p>
<p>static void recover_list_add(struct dlm_rsb *r)<br />
{<br />
	struct dlm_ls *ls = r->res_ls;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	if (list_empty(&#038;r->res_recover_list)) {<br />
		list_add_tail(&#038;r->res_recover_list, &#038;ls->ls_recover_list);<br />
		ls->ls_recover_list_count++;<br />
		dlm_hold_rsb(r);<br />
	}<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);<br />
}</p>
<p>static void recover_list_del(struct dlm_rsb *r)<br />
{<br />
	struct dlm_ls *ls = r->res_ls;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	list_del_init(&#038;r->res_recover_list);<br />
	ls->ls_recover_list_count&#8211;;<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);</p>
<p>	dlm_put_rsb(r);<br />
}</p>
<p>static struct dlm_rsb *recover_list_find(struct dlm_ls *ls, uint64_t id)<br />
{<br />
	struct dlm_rsb *r = NULL;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);</p>
<p>	list_for_each_entry(r, &#038;ls->ls_recover_list, res_recover_list) {<br />
		if (id == (unsigned long) r)<br />
			goto out;<br />
	}<br />
	r = NULL;<br />
 out:<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);<br />
	return r;<br />
}</p>
<p>static void recover_list_clear(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r, *s;</p>
<p>	spin_lock(&#038;ls->ls_recover_list_lock);<br />
	list_for_each_entry_safe(r, s, &#038;ls->ls_recover_list, res_recover_list) {<br />
		list_del_init(&#038;r->res_recover_list);<br />
		r->res_recover_locks_count = 0;<br />
		dlm_put_rsb(r);<br />
		ls->ls_recover_list_count&#8211;;<br />
	}</p>
<p>	if (ls->ls_recover_list_count != 0) {<br />
		log_error(ls, &laquo;warning: recover_list_count %d&raquo;,<br />
			  ls->ls_recover_list_count);<br />
		ls->ls_recover_list_count = 0;<br />
	}<br />
	spin_unlock(&#038;ls->ls_recover_list_lock);<br />
}</p>
<p>/* Master recovery: find new master node for rsb&#8217;s that were<br />
   mastered on nodes that have been removed.</p>
<p>   dlm_recover_masters<br />
   recover_master<br />
   dlm_send_rcom_lookup            ->  receive_rcom_lookup<br />
                                       dlm_dir_lookup<br />
   receive_rcom_lookup_reply       <-<br />
   dlm_recover_master_reply<br />
   set_new_master<br />
   set_master_lkbs<br />
   set_lock_master<br />
*/</p>
<p>/*<br />
 * Set the lock master for all LKBs in a lock queue<br />
 * If we are the new master of the rsb, we may have received new<br />
 * MSTCPY locks from other nodes already which we need to ignore<br />
 * when setting the new nodeid.<br />
 */</p>
<p>static void set_lock_master(struct list_head *queue, int nodeid)<br />
{<br />
	struct dlm_lkb *lkb;</p>
<p>	list_for_each_entry(lkb, queue, lkb_statequeue)<br />
		if (!(lkb->lkb_flags &#038; DLM_IFL_MSTCPY))<br />
			lkb->lkb_nodeid = nodeid;<br />
}</p>
<p>static void set_master_lkbs(struct dlm_rsb *r)<br />
{<br />
	set_lock_master(&#038;r->res_grantqueue, r->res_nodeid);<br />
	set_lock_master(&#038;r->res_convertqueue, r->res_nodeid);<br />
	set_lock_master(&#038;r->res_waitqueue, r->res_nodeid);<br />
}</p>
<p>/*<br />
 * Propogate the new master nodeid to locks<br />
 * The NEW_MASTER flag tells dlm_recover_locks() which rsb&#8217;s to consider.<br />
 * The NEW_MASTER2 flag tells recover_lvb() and set_locks_purged() which<br />
 * rsb&#8217;s to consider.<br />
 */</p>
<p>static void set_new_master(struct dlm_rsb *r, int nodeid)<br />
{<br />
	lock_rsb(r);<br />
	r->res_nodeid = nodeid;<br />
	set_master_lkbs(r);<br />
	rsb_set_flag(r, RSB_NEW_MASTER);<br />
	rsb_set_flag(r, RSB_NEW_MASTER2);<br />
	unlock_rsb(r);<br />
}</p>
<p>/*<br />
 * We do async lookups on rsb&#8217;s that need new masters.  The rsb&#8217;s<br />
 * waiting for a lookup reply are kept on the recover_list.<br />
 */</p>
<p>static int recover_master(struct dlm_rsb *r)<br />
{<br />
	struct dlm_ls *ls = r->res_ls;<br />
	int error, dir_nodeid, ret_nodeid, our_nodeid = dlm_our_nodeid();</p>
<p>	dir_nodeid = dlm_dir_nodeid(r);</p>
<p>	if (dir_nodeid == our_nodeid) {<br />
		error = dlm_dir_lookup(ls, our_nodeid, r->res_name,<br />
				       r->res_length, &#038;ret_nodeid);<br />
		if (error)<br />
			log_error(ls, &laquo;recover dir lookup error %d&raquo;, error);</p>
<p>		if (ret_nodeid == our_nodeid)<br />
			ret_nodeid = 0;<br />
		set_new_master(r, ret_nodeid);<br />
	} else {<br />
		recover_list_add(r);<br />
		error = dlm_send_rcom_lookup(r, dir_nodeid);<br />
	}</p>
<p>	return error;<br />
}</p>
<p>/*<br />
 * When not using a directory, most resource names will hash to a new static<br />
 * master nodeid and the resource will need to be remastered.<br />
 */</p>
<p>static int recover_master_static(struct dlm_rsb *r)<br />
{<br />
	int master = dlm_dir_nodeid(r);</p>
<p>	if (master == dlm_our_nodeid())<br />
		master = 0;</p>
<p>	if (r->res_nodeid != master) {<br />
		if (is_master(r))<br />
			dlm_purge_mstcpy_locks(r);<br />
		set_new_master(r, master);<br />
		return 1;<br />
	}<br />
	return 0;<br />
}</p>
<p>/*<br />
 * Go through local root resources and for each rsb which has a master which<br />
 * has departed, get the new master nodeid from the directory.  The dir will<br />
 * assign mastery to the first node to look up the new master.  That means<br />
 * we&#8217;ll discover in this lookup if we&#8217;re the new master of any rsb&#8217;s.<br />
 *<br />
 * We fire off all the dir lookup requests individually and asynchronously to<br />
 * the correct dir node.<br />
 */</p>
<p>int dlm_recover_masters(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error = 0, count = 0;</p>
<p>	log_debug(ls, &laquo;dlm_recover_masters&raquo;);</p>
<p>	down_read(&#038;ls->ls_root_sem);<br />
	list_for_each_entry(r, &#038;ls->ls_root_list, res_root_list) {<br />
		if (dlm_recovery_stopped(ls)) {<br />
			up_read(&#038;ls->ls_root_sem);<br />
			error = -EINTR;<br />
			goto out;<br />
		}</p>
<p>		if (dlm_no_directory(ls))<br />
			count += recover_master_static(r);<br />
		else if (!is_master(r) &#038;&#038;<br />
			 (dlm_is_removed(ls, r->res_nodeid) ||<br />
			  rsb_flag(r, RSB_NEW_MASTER))) {<br />
			recover_master(r);<br />
			count++;<br />
		}</p>
<p>		schedule();<br />
	}<br />
	up_read(&#038;ls->ls_root_sem);</p>
<p>	log_debug(ls, &laquo;dlm_recover_masters %d resources&raquo;, count);</p>
<p>	error = dlm_wait_function(ls, &#038;recover_list_empty);<br />
 out:<br />
	if (error)<br />
		recover_list_clear(ls);<br />
	return error;<br />
}</p>
<p>int dlm_recover_master_reply(struct dlm_ls *ls, struct dlm_rcom *rc)<br />
{<br />
	struct dlm_rsb *r;<br />
	int nodeid;</p>
<p>	r = recover_list_find(ls, rc->rc_id);<br />
	if (!r) {<br />
		log_error(ls, &laquo;dlm_recover_master_reply no id %llx&raquo;,<br />
			  (unsigned long long)rc->rc_id);<br />
		goto out;<br />
	}</p>
<p>	nodeid = rc->rc_result;<br />
	if (nodeid == dlm_our_nodeid())<br />
		nodeid = 0;</p>
<p>	set_new_master(r, nodeid);<br />
	recover_list_del(r);</p>
<p>	if (recover_list_empty(ls))<br />
		wake_up(&#038;ls->ls_wait_general);<br />
 out:<br />
	return 0;<br />
}</p>
<p>/* Lock recovery: rebuild the process-copy locks we hold on a<br />
   remastered rsb on the new rsb master.</p>
<p>   dlm_recover_locks<br />
   recover_locks<br />
   recover_locks_queue<br />
   dlm_send_rcom_lock              ->  receive_rcom_lock<br />
                                       dlm_recover_master_copy<br />
   receive_rcom_lock_reply         <-<br />
   dlm_recover_process_copy<br />
*/</p>
<p>/*<br />
 * keep a count of the number of lkb's we send to the new master; when we get<br />
 * an equal number of replies then recovery for the rsb is done<br />
 */</p>
<p>static int recover_locks_queue(struct dlm_rsb *r, struct list_head *head)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int error = 0;</p>
<p>	list_for_each_entry(lkb, head, lkb_statequeue) {<br />
	   	error = dlm_send_rcom_lock(r, lkb);<br />
		if (error)<br />
			break;<br />
		r->res_recover_locks_count++;<br />
	}</p>
<p>	return error;<br />
}</p>
<p>static int recover_locks(struct dlm_rsb *r)<br />
{<br />
	int error = 0;</p>
<p>	lock_rsb(r);</p>
<p>	DLM_ASSERT(!r->res_recover_locks_count, dlm_dump_rsb(r););</p>
<p>	error = recover_locks_queue(r, &#038;r->res_grantqueue);<br />
	if (error)<br />
		goto out;<br />
	error = recover_locks_queue(r, &#038;r->res_convertqueue);<br />
	if (error)<br />
		goto out;<br />
	error = recover_locks_queue(r, &#038;r->res_waitqueue);<br />
	if (error)<br />
		goto out;</p>
<p>	if (r->res_recover_locks_count)<br />
		recover_list_add(r);<br />
	else<br />
		rsb_clear_flag(r, RSB_NEW_MASTER);<br />
 out:<br />
	unlock_rsb(r);<br />
	return error;<br />
}</p>
<p>int dlm_recover_locks(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	int error, count = 0;</p>
<p>	log_debug(ls, &laquo;dlm_recover_locks&raquo;);</p>
<p>	down_read(&#038;ls->ls_root_sem);<br />
	list_for_each_entry(r, &#038;ls->ls_root_list, res_root_list) {<br />
		if (is_master(r)) {<br />
			rsb_clear_flag(r, RSB_NEW_MASTER);<br />
			continue;<br />
		}</p>
<p>		if (!rsb_flag(r, RSB_NEW_MASTER))<br />
			continue;</p>
<p>		if (dlm_recovery_stopped(ls)) {<br />
			error = -EINTR;<br />
			up_read(&#038;ls->ls_root_sem);<br />
			goto out;<br />
		}</p>
<p>		error = recover_locks(r);<br />
		if (error) {<br />
			up_read(&#038;ls->ls_root_sem);<br />
			goto out;<br />
		}</p>
<p>		count += r->res_recover_locks_count;<br />
	}<br />
	up_read(&#038;ls->ls_root_sem);</p>
<p>	log_debug(ls, &laquo;dlm_recover_locks %d locks&raquo;, count);</p>
<p>	error = dlm_wait_function(ls, &#038;recover_list_empty);<br />
 out:<br />
	if (error)<br />
		recover_list_clear(ls);<br />
	else<br />
		dlm_set_recover_status(ls, DLM_RS_LOCKS);<br />
	return error;<br />
}</p>
<p>void dlm_recovered_lock(struct dlm_rsb *r)<br />
{<br />
	DLM_ASSERT(rsb_flag(r, RSB_NEW_MASTER), dlm_dump_rsb(r););</p>
<p>	r->res_recover_locks_count&#8211;;<br />
	if (!r->res_recover_locks_count) {<br />
		rsb_clear_flag(r, RSB_NEW_MASTER);<br />
		recover_list_del(r);<br />
	}</p>
<p>	if (recover_list_empty(r->res_ls))<br />
		wake_up(&#038;r->res_ls->ls_wait_general);<br />
}</p>
<p>/*<br />
 * The lvb needs to be recovered on all master rsb&#8217;s.  This includes setting<br />
 * the VALNOTVALID flag if necessary, and determining the correct lvb contents<br />
 * based on the lvb&#8217;s of the locks held on the rsb.<br />
 *<br />
 * RSB_VALNOTVALID is set if there are only NL/CR locks on the rsb.  If it<br />
 * was already set prior to recovery, it&#8217;s not cleared, regardless of locks.<br />
 *<br />
 * The LVB contents are only considered for changing when this is a new master<br />
 * of the rsb (NEW_MASTER2).  Then, the rsb&#8217;s lvb is taken from any lkb with<br />
 * mode > CR.  If no lkb&#8217;s exist with mode above CR, the lvb contents are taken<br />
 * from the lkb with the largest lvb sequence number.<br />
 */</p>
<p>static void recover_lvb(struct dlm_rsb *r)<br />
{<br />
	struct dlm_lkb *lkb, *high_lkb = NULL;<br />
	uint32_t high_seq = 0;<br />
	int lock_lvb_exists = 0;<br />
	int big_lock_exists = 0;<br />
	int lvblen = r->res_ls->ls_lvblen;</p>
<p>	list_for_each_entry(lkb, &#038;r->res_grantqueue, lkb_statequeue) {<br />
		if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
			continue;</p>
<p>		lock_lvb_exists = 1;</p>
<p>		if (lkb->lkb_grmode > DLM_LOCK_CR) {<br />
			big_lock_exists = 1;<br />
			goto setflag;<br />
		}</p>
<p>		if (((int)lkb->lkb_lvbseq &#8211; (int)high_seq) >= 0) {<br />
			high_lkb = lkb;<br />
			high_seq = lkb->lkb_lvbseq;<br />
		}<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		if (!(lkb->lkb_exflags &#038; DLM_LKF_VALBLK))<br />
			continue;</p>
<p>		lock_lvb_exists = 1;</p>
<p>		if (lkb->lkb_grmode > DLM_LOCK_CR) {<br />
			big_lock_exists = 1;<br />
			goto setflag;<br />
		}</p>
<p>		if (((int)lkb->lkb_lvbseq &#8211; (int)high_seq) >= 0) {<br />
			high_lkb = lkb;<br />
			high_seq = lkb->lkb_lvbseq;<br />
		}<br />
	}</p>
<p> setflag:<br />
	if (!lock_lvb_exists)<br />
		goto out;</p>
<p>	if (!big_lock_exists)<br />
		rsb_set_flag(r, RSB_VALNOTVALID);</p>
<p>	/* don&#8217;t mess with the lvb unless we&#8217;re the new master */<br />
	if (!rsb_flag(r, RSB_NEW_MASTER2))<br />
		goto out;</p>
<p>	if (!r->res_lvbptr) {<br />
		r->res_lvbptr = dlm_allocate_lvb(r->res_ls);<br />
		if (!r->res_lvbptr)<br />
			goto out;<br />
	}</p>
<p>	if (big_lock_exists) {<br />
		r->res_lvbseq = lkb->lkb_lvbseq;<br />
		memcpy(r->res_lvbptr, lkb->lkb_lvbptr, lvblen);<br />
	} else if (high_lkb) {<br />
		r->res_lvbseq = high_lkb->lkb_lvbseq;<br />
		memcpy(r->res_lvbptr, high_lkb->lkb_lvbptr, lvblen);<br />
	} else {<br />
		r->res_lvbseq = 0;<br />
		memset(r->res_lvbptr, 0, lvblen);<br />
	}<br />
 out:<br />
	return;<br />
}</p>
<p>/* All master rsb&#8217;s flagged RECOVER_CONVERT need to be looked at.  The locks<br />
   converting PR->CW or CW->PR need to have their lkb_grmode set. */</p>
<p>static void recover_conversion(struct dlm_rsb *r)<br />
{<br />
	struct dlm_lkb *lkb;<br />
	int grmode = -1;</p>
<p>	list_for_each_entry(lkb, &#038;r->res_grantqueue, lkb_statequeue) {<br />
		if (lkb->lkb_grmode == DLM_LOCK_PR ||<br />
		    lkb->lkb_grmode == DLM_LOCK_CW) {<br />
			grmode = lkb->lkb_grmode;<br />
			break;<br />
		}<br />
	}</p>
<p>	list_for_each_entry(lkb, &#038;r->res_convertqueue, lkb_statequeue) {<br />
		if (lkb->lkb_grmode != DLM_LOCK_IV)<br />
			continue;<br />
		if (grmode == -1)<br />
			lkb->lkb_grmode = lkb->lkb_rqmode;<br />
		else<br />
			lkb->lkb_grmode = grmode;<br />
	}<br />
}</p>
<p>/* We&#8217;ve become the new master for this rsb and waiting/converting locks may<br />
   need to be granted in dlm_grant_after_purge() due to locks that may have<br />
   existed from a removed node. */</p>
<p>static void set_locks_purged(struct dlm_rsb *r)<br />
{<br />
	if (!list_empty(&#038;r->res_waitqueue) || !list_empty(&#038;r->res_convertqueue))<br />
		rsb_set_flag(r, RSB_LOCKS_PURGED);<br />
}</p>
<p>void dlm_recover_rsbs(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	int count = 0;</p>
<p>	log_debug(ls, &laquo;dlm_recover_rsbs&raquo;);</p>
<p>	down_read(&#038;ls->ls_root_sem);<br />
	list_for_each_entry(r, &#038;ls->ls_root_list, res_root_list) {<br />
		lock_rsb(r);<br />
		if (is_master(r)) {<br />
			if (rsb_flag(r, RSB_RECOVER_CONVERT))<br />
				recover_conversion(r);<br />
			if (rsb_flag(r, RSB_NEW_MASTER2))<br />
				set_locks_purged(r);<br />
			recover_lvb(r);<br />
			count++;<br />
		}<br />
		rsb_clear_flag(r, RSB_RECOVER_CONVERT);<br />
		rsb_clear_flag(r, RSB_NEW_MASTER2);<br />
		unlock_rsb(r);<br />
	}<br />
	up_read(&#038;ls->ls_root_sem);</p>
<p>	log_debug(ls, &laquo;dlm_recover_rsbs %d rsbs&raquo;, count);<br />
}</p>
<p>/* Create a single list of all root rsb&#8217;s to be used during recovery */</p>
<p>int dlm_create_root_list(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r;<br />
	int i, error = 0;</p>
<p>	down_write(&#038;ls->ls_root_sem);<br />
	if (!list_empty(&#038;ls->ls_root_list)) {<br />
		log_error(ls, &laquo;root list not empty&raquo;);<br />
		error = -EINVAL;<br />
		goto out;<br />
	}</p>
<p>	for (i = 0; i < ls->ls_rsbtbl_size; i++) {<br />
		spin_lock(&#038;ls->ls_rsbtbl[i].lock);<br />
		list_for_each_entry(r, &#038;ls->ls_rsbtbl[i].list, res_hashchain) {<br />
			list_add(&#038;r->res_root_list, &#038;ls->ls_root_list);<br />
			dlm_hold_rsb(r);<br />
		}</p>
<p>		/* If we&#8217;re using a directory, add tossed rsbs to the root<br />
		   list; they&#8217;ll have entries created in the new directory,<br />
		   but no other recovery steps should do anything with them. */</p>
<p>		if (dlm_no_directory(ls)) {<br />
			spin_unlock(&#038;ls->ls_rsbtbl[i].lock);<br />
			continue;<br />
		}</p>
<p>		list_for_each_entry(r, &#038;ls->ls_rsbtbl[i].toss, res_hashchain) {<br />
			list_add(&#038;r->res_root_list, &#038;ls->ls_root_list);<br />
			dlm_hold_rsb(r);<br />
		}<br />
		spin_unlock(&#038;ls->ls_rsbtbl[i].lock);<br />
	}<br />
 out:<br />
	up_write(&#038;ls->ls_root_sem);<br />
	return error;<br />
}</p>
<p>void dlm_release_root_list(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r, *safe;</p>
<p>	down_write(&#038;ls->ls_root_sem);<br />
	list_for_each_entry_safe(r, safe, &#038;ls->ls_root_list, res_root_list) {<br />
		list_del_init(&#038;r->res_root_list);<br />
		dlm_put_rsb(r);<br />
	}<br />
	up_write(&#038;ls->ls_root_sem);<br />
}</p>
<p>/* If not using a directory, clear the entire toss list, there&#8217;s no benefit to<br />
   caching the master value since it&#8217;s fixed.  If we are using a dir, keep the<br />
   rsb&#8217;s we&#8217;re the master of.  Recovery will add them to the root list and from<br />
   there they&#8217;ll be entered in the rebuilt directory. */</p>
<p>void dlm_clear_toss_list(struct dlm_ls *ls)<br />
{<br />
	struct dlm_rsb *r, *safe;<br />
	int i;</p>
<p>	for (i = 0; i < ls->ls_rsbtbl_size; i++) {<br />
		spin_lock(&#038;ls->ls_rsbtbl[i].lock);<br />
		list_for_each_entry_safe(r, safe, &#038;ls->ls_rsbtbl[i].toss,<br />
					 res_hashchain) {<br />
			if (dlm_no_directory(ls) || !is_master(r)) {<br />
				list_del(&#038;r->res_hashchain);<br />
				dlm_free_rsb(r);<br />
			}<br />
		}<br />
		spin_unlock(&#038;ls->ls_rsbtbl[i].lock);<br />
	}<br />
}</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/recover-c/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>rcom.h</title>
		<link>http://lynyrd.ru/rcom-h</link>
		<comments>http://lynyrd.ru/rcom-h#comments</comments>
		<pubDate>Sun, 31 Jan 2010 03:57:18 +0000</pubDate>
		<dc:creator>lynyrd</dc:creator>
				<category><![CDATA[midcomms]]></category>

		<guid isPermaLink="false">http://lynyrd.ru/?p=1062</guid>
		<description><![CDATA[/******************************************************************************
*******************************************************************************
**
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.
**
**  This copyrighted material is made available to anyone wishing to use,
**  modify, copy, or redistribute it subject to the terms and conditions
**  of the GNU General Public License ]]></description>
			<content:encoded><![CDATA[<p>/******************************************************************************<br />
*******************************************************************************<br />
**<br />
**  Copyright (C) Sistina Software, Inc.  1997-2003  All rights reserved.<span id="more-1062"></span><br />
**  Copyright (C) 2005-2007 Red Hat, Inc.  All rights reserved.<br />
**<br />
**  This copyrighted material is made available to anyone wishing to use,<br />
**  modify, copy, or redistribute it subject to the terms and conditions<br />
**  of the GNU General Public License v.2.<br />
**<br />
*******************************************************************************<br />
******************************************************************************/</p>
<p>#ifndef __RCOM_DOT_H__<br />
#define __RCOM_DOT_H__</p>
<p>int dlm_rcom_status(struct dlm_ls *ls, int nodeid);<br />
int dlm_rcom_names(struct dlm_ls *ls, int nodeid, char *last_name,int last_len);<br />
int dlm_send_rcom_lookup(struct dlm_rsb *r, int dir_nodeid);<br />
int dlm_send_rcom_lock(struct dlm_rsb *r, struct dlm_lkb *lkb);<br />
void dlm_receive_rcom(struct dlm_ls *ls, struct dlm_rcom *rc, int nodeid);<br />
int dlm_send_ls_not_ready(int nodeid, struct dlm_rcom *rc_in);</p>
<p>#endif</p>
]]></content:encoded>
			<wfw:commentRss>http://lynyrd.ru/rcom-h/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
