/*
 * security/caitsith/internal.h
 *
 * Copyright (C) 2005-2012  NTT DATA CORPORATION
 *
 * Version: 0.1.2   2012/07/12
 */

#ifndef _SECURITY_CAITSITH_INTERNAL_H
#define _SECURITY_CAITSITH_INTERNAL_H

#include <linux/version.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 27)
#error This module supports only 2.6.27 and later kernels.
#endif
#include <linux/types.h>
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/mm.h>
#include <linux/utime.h>
#include <linux/file.h>
#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 38)
#include <linux/smp_lock.h>
#endif
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
#include <linux/highmem.h>
#include <linux/poll.h>
#include <linux/binfmts.h>
#include <linux/delay.h>
#include <linux/sched.h>
#include <linux/dcache.h>
#include <linux/mount.h>
#include <linux/net.h>
#include <linux/inet.h>
#include <linux/in.h>
#include <linux/in6.h>
#include <linux/un.h>
#include <linux/ptrace.h>
#include <linux/namei.h>
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 30)
#include <linux/fs_struct.h>
#endif
#include <linux/proc_fs.h>
#include <linux/hash.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 33) && defined(CONFIG_SYSCTL_SYSCALL)
#include <linux/sysctl.h>
#endif
#include <linux/kthread.h>
#include <stdarg.h>
#include <asm/uaccess.h>
#include <net/sock.h>
#include <net/af_unix.h>
#include <net/ip.h>
#include <net/ipv6.h>
#include <net/udp.h>

#ifndef __printf
#define __printf(a,b) __attribute__((format(printf,a,b)))
#endif
#ifndef __packed
#define __packed __attribute__((__packed__))
#endif
#ifndef bool
#define bool _Bool
#endif
#ifndef false
#define false 0
#endif
#ifndef true
#define true 1
#endif

#ifndef __user
#define __user
#endif

#ifndef current_uid
#define current_uid()   (current->uid)
#endif
#ifndef current_gid
#define current_gid()   (current->gid)
#endif
#ifndef current_euid
#define current_euid()  (current->euid)
#endif
#ifndef current_egid
#define current_egid()  (current->egid)
#endif
#ifndef current_suid
#define current_suid()  (current->suid)
#endif
#ifndef current_sgid
#define current_sgid()  (current->sgid)
#endif
#ifndef current_fsuid
#define current_fsuid() (current->fsuid)
#endif
#ifndef current_fsgid
#define current_fsgid() (current->fsgid)
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 38)

/**
 * __list_del_entry - Deletes entry from list without re-initialization.
 *
 * @entry: Pointer to "struct list_head".
 *
 * Returns nothing.
 *
 * This is for compatibility with older kernels.
 */
static inline void __list_del_entry(struct list_head *entry)
{
	__list_del(entry->prev, entry->next);
}

#endif

#ifndef list_for_each_entry_safe

/**
 * list_for_each_entry_safe - Iterate over list of given type safe against removal of list entry.
 *
 * @pos:    The "type *" to use as a loop cursor.
 * @n:      Another "type *" to use as temporary storage.
 * @head:   Pointer to "struct list_head".
 * @member: The name of the list_struct within the struct.
 *
 * This is for compatibility with older kernels.
 */
#define list_for_each_entry_safe(pos, n, head, member)                  \
	for (pos = list_entry((head)->next, typeof(*pos), member),      \
		     n = list_entry(pos->member.next, typeof(*pos), member); \
	     &pos->member != (head);					\
	     pos = n, n = list_entry(n->member.next, typeof(*n), member))

#endif

#ifndef srcu_dereference

/**
 * srcu_dereference - Fetch SRCU-protected pointer with checking.
 *
 * @p:  The pointer to read, prior to dereferencing.
 * @ss: Pointer to "struct srcu_struct".
 *
 * Returns @p.
 *
 * This is for compatibility with older kernels.
 */
#define srcu_dereference(p, ss) rcu_dereference(p)

#endif

#ifndef list_for_each_entry_srcu

/**
 * list_for_each_entry_srcu - Iterate over rcu list of given type.
 *
 * @pos:    The type * to use as a loop cursor.
 * @head:   The head for your list.
 * @member: The name of the list_struct within the struct.
 * @ss:     Pointer to "struct srcu_struct".
 *
 * As of 2.6.36, this macro is not provided because only TOMOYO wants it.
 */
#define list_for_each_entry_srcu(pos, head, member, ss)		      \
	for (pos = list_entry(srcu_dereference((head)->next, ss),     \
			      typeof(*pos), member);		      \
	     prefetch(pos->member.next), &pos->member != (head);      \
	     pos = list_entry(srcu_dereference(pos->member.next, ss), \
			      typeof(*pos), member))

#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(3, 5, 0)

/**
 * from_kuid - Convert kuid_t to uid_t.
 *
 * @ns:  Unused.
 * @uid: kuid_t value.
 *
 * Returns uid seen from init's user namespace.
 */
#define from_kuid(ns, uid) (uid)

/**
 * from_kgid - Convert kgid_t to gid_t.
 *
 * @ns:  Unused.
 * @gid: kgid_t value.
 *
 * Returns gid seen from init's user namespace.
 */
#define from_kgid(ns, gid) (gid)

#endif

/*
 * TOMOYO specific part start.
 */

#include <linux/caitsith.h>

/* Enumeration definition for internal use. */

/* Index numbers for "struct ccs_condition". */
enum ccs_conditions_index {
	/* 0 */
	CCS_SELF_UID,             /* current_uid()   */
	CCS_SELF_EUID,            /* current_euid()  */
	CCS_SELF_SUID,            /* current_suid()  */
	CCS_SELF_FSUID,           /* current_fsuid() */
	CCS_SELF_GID,             /* current_gid()   */
	CCS_SELF_EGID,            /* current_egid()  */
	CCS_SELF_SGID,            /* current_sgid()  */
	CCS_SELF_FSGID,           /* current_fsgid() */
	CCS_SELF_PID,             /* sys_getpid()   */
	CCS_SELF_PPID,            /* sys_getppid()  */
	/* 10 */
	CCS_TASK_TYPE,            /* ((u8) task->ccs_flags) &
				     CCS_TASK_IS_EXECUTE_HANDLER */
	CCS_SELF_DOMAIN,
	CCS_SELF_EXE,
	CCS_EXEC_ARGC,            /* "struct linux_binprm *"->argc */
	CCS_EXEC_ENVC,            /* "struct linux_binprm *"->envc */
	CCS_OBJ_IS_SOCKET,        /* S_IFSOCK */
	CCS_OBJ_IS_SYMLINK,       /* S_IFLNK */
	CCS_OBJ_IS_FILE,          /* S_IFREG */
	CCS_OBJ_IS_BLOCK_DEV,     /* S_IFBLK */
	CCS_OBJ_IS_DIRECTORY,     /* S_IFDIR */
	/* 20 */
	CCS_OBJ_IS_CHAR_DEV,      /* S_IFCHR */
	CCS_OBJ_IS_FIFO,          /* S_IFIFO */
	CCS_MODE_SETUID,          /* S_ISUID */
	CCS_MODE_SETGID,          /* S_ISGID */
	CCS_MODE_STICKY,          /* S_ISVTX */
	CCS_MODE_OWNER_READ,      /* S_IRUSR */
	CCS_MODE_OWNER_WRITE,     /* S_IWUSR */
	CCS_MODE_OWNER_EXECUTE,   /* S_IXUSR */
	CCS_MODE_GROUP_READ,      /* S_IRGRP */
	CCS_MODE_GROUP_WRITE,     /* S_IWGRP */
	/* 30 */
	CCS_MODE_GROUP_EXECUTE,   /* S_IXGRP */
	CCS_MODE_OTHERS_READ,     /* S_IROTH */
	CCS_MODE_OTHERS_WRITE,    /* S_IWOTH */
	CCS_MODE_OTHERS_EXECUTE,  /* S_IXOTH */
	CCS_TASK_EXECUTE_HANDLER, /* CCS_TASK_IS_EXECUTE_HANDLER */
	CCS_HANDLER_PATH,
	CCS_TRANSIT_DOMAIN,
	CCS_MAX_CONDITION_KEYWORD,
	CCS_COND_SARG0,
	CCS_COND_SARG1,
	/* 40 */
	CCS_COND_SARG2,
	CCS_COND_SARG3,
	CCS_COND_NARG0,
	CCS_COND_NARG1,
	CCS_COND_NARG2,
	CCS_COND_IPARG,
	CCS_COND_DOMAIN,
	CCS_IMM_GROUP,
	CCS_IMM_NAME_ENTRY,
	CCS_IMM_NUMBER_ENTRY1,
	/* 50 */
	CCS_IMM_NUMBER_ENTRY2,
#ifdef CONFIG_CAITSITH_NETWORK
	CCS_IMM_IPV4ADDR_ENTRY1,
	CCS_IMM_IPV4ADDR_ENTRY2,
	CCS_IMM_IPV6ADDR_ENTRY1,
	CCS_IMM_IPV6ADDR_ENTRY2,
#endif
	CCS_ARGV_ENTRY,
	CCS_ENVP_ENTRY,
	CCS_PATH_ATTRIBUTE_START = 192,
	CCS_PATH_ATTRIBUTE_END = 255
} __packed;

enum ccs_path_attribute_index {
	CCS_PATH_ATTRIBUTE_UID,
	CCS_PATH_ATTRIBUTE_GID,
	CCS_PATH_ATTRIBUTE_INO,
	CCS_PATH_ATTRIBUTE_TYPE,
	CCS_PATH_ATTRIBUTE_MAJOR,
	CCS_PATH_ATTRIBUTE_MINOR,
	CCS_PATH_ATTRIBUTE_PERM,
	CCS_PATH_ATTRIBUTE_DEV_MAJOR,
	CCS_PATH_ATTRIBUTE_DEV_MINOR,
	CCS_PATH_ATTRIBUTE_FSMAGIC,
	CCS_MAX_PATH_ATTRIBUTE
} __packed;

/* Index numbers for group entries. */
enum ccs_group_id {
	CCS_STRING_GROUP,
	CCS_NUMBER_GROUP,
#ifdef CONFIG_CAITSITH_NETWORK
	CCS_IP_GROUP,
#endif
	CCS_MAX_GROUP
} __packed;

/* Index numbers for functionality. */
enum ccs_mac_index {
	CCS_MAC_EXECUTE,
	CCS_MAC_READ,
	CCS_MAC_WRITE,
	CCS_MAC_APPEND,
	CCS_MAC_CREATE,
	CCS_MAC_UNLINK,
#ifdef CONFIG_CAITSITH_GETATTR
	CCS_MAC_GETATTR,
#endif
	CCS_MAC_MKDIR,
	CCS_MAC_RMDIR,
	CCS_MAC_MKFIFO,
	CCS_MAC_MKSOCK,
	CCS_MAC_TRUNCATE,
	CCS_MAC_SYMLINK,
	CCS_MAC_MKBLOCK,
	CCS_MAC_MKCHAR,
	CCS_MAC_LINK,
	CCS_MAC_RENAME,
	CCS_MAC_CHMOD,
	CCS_MAC_CHOWN,
	CCS_MAC_CHGRP,
	CCS_MAC_IOCTL,
	CCS_MAC_CHROOT,
	CCS_MAC_MOUNT,
	CCS_MAC_UMOUNT,
	CCS_MAC_PIVOT_ROOT,
#ifdef CONFIG_CAITSITH_NETWORK
	CCS_MAC_INET_STREAM_BIND,
	CCS_MAC_INET_STREAM_LISTEN,
	CCS_MAC_INET_STREAM_CONNECT,
	CCS_MAC_INET_STREAM_ACCEPT,
	CCS_MAC_INET_DGRAM_BIND,
	CCS_MAC_INET_DGRAM_SEND,
#ifdef CONFIG_CAITSITH_NETWORK_RECVMSG
	CCS_MAC_INET_DGRAM_RECV,
#endif
	CCS_MAC_INET_RAW_BIND,
	CCS_MAC_INET_RAW_SEND,
#ifdef CONFIG_CAITSITH_NETWORK_RECVMSG
	CCS_MAC_INET_RAW_RECV,
#endif
	CCS_MAC_UNIX_STREAM_BIND,
	CCS_MAC_UNIX_STREAM_LISTEN,
	CCS_MAC_UNIX_STREAM_CONNECT,
	CCS_MAC_UNIX_STREAM_ACCEPT,
	CCS_MAC_UNIX_DGRAM_BIND,
	CCS_MAC_UNIX_DGRAM_SEND,
#ifdef CONFIG_CAITSITH_NETWORK_RECVMSG
	CCS_MAC_UNIX_DGRAM_RECV,
#endif
	CCS_MAC_UNIX_SEQPACKET_BIND,
	CCS_MAC_UNIX_SEQPACKET_LISTEN,
	CCS_MAC_UNIX_SEQPACKET_CONNECT,
	CCS_MAC_UNIX_SEQPACKET_ACCEPT,
#endif
#ifdef CONFIG_CAITSITH_ENVIRON
	CCS_MAC_ENVIRON,
#endif
#ifdef CONFIG_CAITSITH_PTRACE
	CCS_MAC_PTRACE,
#endif
#ifdef CONFIG_CAITSITH_SIGNAL
	CCS_MAC_SIGNAL,
#endif
	CCS_MAC_MODIFY_POLICY,
#ifdef CONFIG_CAITSITH_CAPABILITY
	CCS_MAC_USE_NETLINK_SOCKET,
	CCS_MAC_USE_PACKET_SOCKET,
	CCS_MAC_USE_REBOOT,
	CCS_MAC_USE_VHANGUP,
	CCS_MAC_SET_TIME,
	CCS_MAC_SET_PRIORITY,
	CCS_MAC_SET_HOSTNAME,
	CCS_MAC_USE_KERNEL_MODULE,
	CCS_MAC_USE_NEW_KERNEL,
#endif
#ifdef CONFIG_CAITSITH_AUTO_DOMAIN_TRANSITION
	CCS_MAC_AUTO_DOMAIN_TRANSITION,
#endif
#ifdef CONFIG_CAITSITH_MANUAL_DOMAIN_TRANSITION
	CCS_MAC_MANUAL_DOMAIN_TRANSITION,
#endif
	CCS_MAX_MAC_INDEX
} __packed;

/* Index numbers for statistic information. */
enum ccs_memory_stat_type {
	CCS_MEMORY_POLICY,
	CCS_MEMORY_AUDIT,
	CCS_MEMORY_QUERY,
	CCS_MAX_MEMORY_STAT
} __packed;

enum ccs_matching_result {
	CCS_MATCHING_UNMATCHED,
	CCS_MATCHING_ALLOWED,
	CCS_MATCHING_DENIED,
	CCS_MAX_MATCHING
} __packed;

/* Index numbers for stat(). */
enum ccs_path_stat_index {
	/* Do not change this order. */
	CCS_PATH1,
	CCS_PATH1_PARENT,
	CCS_PATH2,
	CCS_PATH2_PARENT,
	CCS_MAX_PATH_STAT
} __packed;

/* Index numbers for entry type. */
enum ccs_policy_id {
	CCS_ID_GROUP,
#ifdef CONFIG_CAITSITH_NETWORK
	CCS_ID_IP_GROUP,
#endif
	CCS_ID_STRING_GROUP,
	CCS_ID_NUMBER_GROUP,
	CCS_ID_CONDITION,
	CCS_ID_NAME,
	CCS_ID_ACL,
	CCS_ID_DOMAIN,
	CCS_MAX_POLICY
} __packed;

/* Index numbers for statistic information. */
enum ccs_policy_stat_type {
	CCS_STAT_POLICY_UPDATES,
	CCS_STAT_REQUEST_DENIED,
	CCS_MAX_POLICY_STAT
} __packed;

/* Index numbers for /proc/ccs/ interfaces. */
enum ccs_proc_interface_index {
	CCS_POLICY,
	CCS_PROCESS_STATUS,
	CCS_AUDIT,
	CCS_VERSION,
	CCS_QUERY,
#ifdef CONFIG_CAITSITH_EXECUTE_HANDLER
	CCS_EXECUTE_HANDLER,
#endif
} __packed;

/* Index numbers for special mount operations. */
enum ccs_special_mount {
	CCS_MOUNT_BIND,            /* mount --bind /source /dest   */
	CCS_MOUNT_MOVE,            /* mount --move /old /new       */
	CCS_MOUNT_REMOUNT,         /* mount -o remount /dir        */
	CCS_MOUNT_MAKE_UNBINDABLE, /* mount --make-unbindable /dir */
	CCS_MOUNT_MAKE_PRIVATE,    /* mount --make-private /dir    */
	CCS_MOUNT_MAKE_SLAVE,      /* mount --make-slave /dir      */
	CCS_MOUNT_MAKE_SHARED,     /* mount --make-shared /dir     */
	CCS_MAX_SPECIAL_MOUNT
} __packed;

/* Index numbers for type of numeric values. */
enum ccs_value_type {
	CCS_VALUE_TYPE_INVALID,
	CCS_VALUE_TYPE_DECIMAL,
	CCS_VALUE_TYPE_OCTAL,
	CCS_VALUE_TYPE_HEXADECIMAL,
} __packed;

/* Index numbers for type of IP addresses. */
enum ccs_ipaddr_type {
	CCS_ADDRESS_TYPE_INVALID,
	CCS_ADDRESS_TYPE_IPV4,
	CCS_ADDRESS_TYPE_IPV4_RANGE,
	CCS_ADDRESS_TYPE_IPV6,
	CCS_ADDRESS_TYPE_IPV6_RANGE,
} __packed;

/* Constants definition for internal use. */

/*
 * TOMOYO uses this hash only when appending a string into the string table.
 * Frequency of appending strings is very low. So we don't need large (e.g.
 * 64k) hash size. 256 will be sufficient.
 */
#define CCS_HASH_BITS 8
#define CCS_MAX_HASH (1u << CCS_HASH_BITS)

/*
 * TOMOYO checks only SOCK_STREAM, SOCK_DGRAM, SOCK_RAW, SOCK_SEQPACKET.
 * Therefore, we don't need SOCK_MAX.
 */
#define CCS_SOCK_MAX 6

/* Size of temporary buffer for execve() operation. */
#define CCS_EXEC_TMPSIZE     4096

/* Patterns for auditing logs quota. */
#define CCS_MAX_LOG_QUOTA 256

/* Garbage collector is trying to kfree() this element. */
#define CCS_GC_IN_PROGRESS -1

/* Current thread is doing open(3) ? */
#define CCS_OPEN_FOR_IOCTL_ONLY           2
/* Current thread is doing do_execve() ? */
#define CCS_TASK_IS_IN_EXECVE             4
/* Current thread is running as an execute handler program? */
#define CCS_TASK_IS_EXECUTE_HANDLER       8
/* Current thread is allowed to modify policy via /proc/ccs/ interface? */
#define CCS_TASK_IS_MANAGER              16

/*
 * Retry this request. Returned by ccs_supervisor() if policy violation has
 * occurred in enforcing mode and the userspace daemon decided to retry.
 *
 * We must choose a positive value in order to distinguish "granted" (which is
 * 0) and "rejected" (which is a negative value) and "retry".
 */
#define CCS_RETRY_REQUEST 1

/* Size of read buffer for /proc/ccs/ interface. */
#define CCS_MAX_IO_READ_QUEUE 64

/* Structure definition for internal use. */

/* Common header for holding ACL entries. */
struct ccs_acl_head {
	struct list_head list;
	s8 is_deleted; /* true or false or CCS_GC_IN_PROGRESS */
} __packed;

/* Common header for shared entries. */
struct ccs_shared_acl_head {
	struct list_head list;
	atomic_t users;
} __packed;

/* Common header for individual entries. */
struct ccs_acl_info {
	struct list_head list;
	struct list_head acl_info_list;
	struct ccs_condition *cond; /* Maybe NULL. */
	bool is_deleted;
	bool is_deny;
	u16 priority;
	u8 audit;
};

/* Structure for "string_group"/"number_group"/"ip_group" directive. */
struct ccs_group {
	struct ccs_shared_acl_head head;
	/* Name of group (without leading "@"). */
	const struct ccs_path_info *group_name;
	/*
	 * List of "struct ccs_string_group" or "struct ccs_number_group" or
	 * "struct ccs_ip_group".
	 */
	struct list_head member_list;
};

/* Structure for "string_group" directive. */
struct ccs_string_group {
	struct ccs_acl_head head;
	const struct ccs_path_info *member_name;
};

/* Structure for "number_group" directive. */
struct ccs_number_group {
	struct ccs_acl_head head;
	u8 radix;
	unsigned long value[2];
};

/* Structure for "ip_group" directive. */
struct ccs_ip_group {
	struct ccs_acl_head head;
	bool is_ipv6;
	/* Structure for holding an IP address. */
	struct in6_addr ip[2]; /* Big endian. */
};

/* Subset of "struct stat". Used by conditional ACL and audit logs. */
struct ccs_mini_stat {
#if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 5, 0)
	kuid_t uid;
	kgid_t gid;
#else
	uid_t uid;
	gid_t gid;
#endif
	ino_t ino;
	umode_t mode;
	dev_t dev;
	dev_t rdev;
	unsigned long fsmagic;
};

/* Structure for dumping argv[] and envp[] of "struct linux_binprm". */
struct ccs_page_dump {
	struct page *page;    /* Previously dumped page. */
	char *data;           /* Contents of "page". Size is PAGE_SIZE. */
};

/* Structure for entries which follows "struct ccs_condition". */
union ccs_condition_element {
	struct {
		enum ccs_conditions_index left;
		enum ccs_conditions_index right;
		bool is_not;
		u8 radix;
	};
	struct ccs_group *group;
	const struct ccs_path_info *path;
	u32 ip; /* Repeat 4 times if IPv6 address. */
	unsigned long value;
};

/* Structure for optional arguments. */
struct ccs_condition {
	struct ccs_shared_acl_head head;
	u32 size; /* Memory size allocated for this entry. */
	/* union ccs_condition_element condition[]; */
};

/* Structure for holding a token. */
struct ccs_path_info {
	const char *name;
	u32 hash;          /* = full_name_hash(name, strlen(name)) */
	u32 total_len;     /* = strlen(name)                       */
	u32 const_len;     /* = ccs_const_part_length(name)        */
};

/* Structure for request info. */
struct ccs_request_info {
	/* For holding parameters. */
	struct ccs_request_param {
		const struct ccs_path_info *s[4];
		unsigned long i[3];
#ifdef CONFIG_CAITSITH_NETWORK
		const u8 *ip; /* Big endian. */
		bool is_ipv6;
#endif
	} param;
	/* For holding pathnames and attributes. */
	struct {
		/*
		 * True if ccs_get_attributes() was already called, false
		 * otherwise.
		 */
		bool validate_done;
		/* True if @stat[] is valid. */
		bool stat_valid[CCS_MAX_PATH_STAT];
		/* Pointer to file objects. */
		struct path path[2];
		/*
		 * Information on @path[0], @path[0]'s parent directory,
		 * @path[1] and @path[1]'s parent directory.
		 */
		struct ccs_mini_stat stat[CCS_MAX_PATH_STAT];
		/*
		 * Name of @path[0] and @path[1].
		 * Cleared by ccs_crear_request_info().
		 */
		struct ccs_path_info pathname[2];
	} obj;
	struct {
		struct linux_binprm *bprm;
		struct ccs_domain_info *previous_domain;
		/* For execute_handler. */
		char *handler; /* kstrdup(handler_path->name, GFP_NOFS) */
		/* For dumping argv[] and envp[]. */
		struct ccs_page_dump dump;
		/* For temporary use. Size is CCS_EXEC_TMPSIZE bytes. */
		char *tmp;
	};
	/*
	 * Name of current thread's executable.
	 * Cleared by ccs_crear_request_info().
	 */
	struct ccs_path_info exename;
	/*
	 * Matching "struct ccs_acl_info" is copied. Used for ccs-queryd.
	 * Valid until ccs_read_unlock().
	 */
	struct ccs_acl_info *matched_acl;
	/*
	 * Matching handler and domain transition are copied.
	 * Valid until ccs_read_unlock().
	 */
	const struct ccs_path_info *handler_path;
	const struct ccs_path_info *transition;
	const struct ccs_path_info *handler_path_candidate;
	const struct ccs_path_info *transition_candidate;
	/*
	 * For holding operation index used for this request.
	 * One of values in "enum ccs_mac_index".
	 */
	enum ccs_mac_index type;
	/* For holding matching result. */
	enum ccs_matching_result result;
	/*
	 * For counting number of retries made for this request.
	 * This counter is incremented whenever ccs_supervisor() returned
	 * CCS_RETRY_REQUEST.
	 */
	u8 retry;
	/* For holding max audit log count for this matching entry. */
	u8 audit;
	/*
	 * Set to true if condition could not be checked due to out of memory.
	 * This flag is used for returning out of memory flag back to
	 * ccs_check_acl_list(). Thus, this flag will not be set if out of
	 * memory occurred before ccs_check_acl_list() is called.
	 */
	bool failed_by_oom;
};

/* Structure for domain information. */
struct ccs_domain_info {
	struct list_head list;
	/* Name of this domain. Never NULL. */
	const struct ccs_path_info *domainname;
};

/* Structure for holding string data. */
struct ccs_name {
	struct ccs_shared_acl_head head;
	int size; /* Memory size allocated for this entry. */
	struct ccs_path_info entry;
};

/* Structure for reading/writing policy via /proc/ccs/ interfaces. */
struct ccs_io_buffer {
	/* Exclusive lock for this structure.   */
	struct mutex io_sem;
	char __user *read_user_buf;
	size_t read_user_buf_avail;
	struct {
		struct list_head *group;
		struct list_head *acl;
		struct list_head *subacl;
		const union ccs_condition_element *cond;
		size_t avail;
		unsigned int step;
		unsigned int query_index;
		u16 index;
		u8 cond_step;
		u8 w_pos;
		enum ccs_mac_index acl_index;
		bool eof;
		bool print_this_acl_only;
		bool version_done;
		bool stat_done;
		bool quota_done;
		bool group_done;
		const char *w[CCS_MAX_IO_READ_QUEUE];
	} r;
	struct {
		char *data;
		struct ccs_acl_info *acl;
		size_t avail;
		enum ccs_mac_index acl_index;
		bool is_delete;
		bool is_deny;
		u16 priority;
	} w;
	/* Buffer for reading.                  */
	char *read_buf;
	/* Size of read buffer.                 */
	size_t readbuf_size;
	/* Buffer for writing.                  */
	char *write_buf;
	/* Size of write buffer.                */
	size_t writebuf_size;
	/* Type of interface. */
	enum ccs_proc_interface_index type;
	/* Users counter protected by ccs_io_buffer_list_lock. */
	u8 users;
	/* List for telling GC not to kfree() elements. */
	struct list_head list;
};

/* Structure for representing YYYY/MM/DD hh/mm/ss. */
struct ccs_time {
	u16 year;
	u8 month;
	u8 day;
	u8 hour;
	u8 min;
	u8 sec;
};

/* Prototype definition for "struct caitsith_operations". */

void __init ccs_permission_init(void);
void __init ccs_mm_init(void);

/* Prototype definition for internal use. */

bool ccs_dump_page(struct linux_binprm *bprm, unsigned long pos,
		   struct ccs_page_dump *dump);
bool ccs_get_exename(struct ccs_path_info *buf);
bool ccs_manager(void);
bool ccs_transit_domain(const char *domainname);
char *ccs_encode(const char *str);
char *ccs_encode2(const char *str, int str_len);
char *ccs_realpath(struct path *path);
char *ccs_get_exe(void);
int ccs_audit_log(struct ccs_request_info *r);
int ccs_check_acl(struct ccs_request_info *r, const bool clear);
void ccs_del_condition(struct list_head *element);
void ccs_fill_path_info(struct ccs_path_info *ptr);
void ccs_get_attributes(struct ccs_request_info *r);
void ccs_notify_gc(struct ccs_io_buffer *head, const bool is_register);
void ccs_populate_patharg(struct ccs_request_info *r, const bool first);
void ccs_transition_failed(const char *domainname);
void ccs_warn_oom(const char *function);

/* Variable definition for internal use. */

extern bool ccs_policy_loaded;
extern struct ccs_domain_info ccs_kernel_domain;
extern struct ccs_path_info ccs_null_name;
extern struct list_head ccs_acl_list[CCS_MAX_MAC_INDEX];
extern struct list_head ccs_condition_list;
extern struct list_head ccs_domain_list;
extern struct list_head ccs_group_list[CCS_MAX_GROUP];
extern struct list_head ccs_name_list[CCS_MAX_HASH];
extern struct mutex ccs_policy_lock;
extern struct srcu_struct ccs_ss;
extern unsigned int ccs_memory_used[CCS_MAX_MEMORY_STAT];

/* Inlined functions for internal use. */

/**
 * ccs_pathcmp - strcmp() for "struct ccs_path_info" structure.
 *
 * @a: Pointer to "struct ccs_path_info".
 * @b: Pointer to "struct ccs_path_info".
 *
 * Returns true if @a != @b, false otherwise.
 */
static inline bool ccs_pathcmp(const struct ccs_path_info *a,
			       const struct ccs_path_info *b)
{
	return a->hash != b->hash || strcmp(a->name, b->name);
}

/**
 * ccs_read_lock - Take lock for protecting policy.
 *
 * Returns index number for ccs_read_unlock().
 */
static inline int ccs_read_lock(void)
{
	return srcu_read_lock(&ccs_ss);
}

/**
 * ccs_read_unlock - Release lock for protecting policy.
 *
 * @idx: Index number returned by ccs_read_lock().
 *
 * Returns nothing.
 */
static inline void ccs_read_unlock(const int idx)
{
	srcu_read_unlock(&ccs_ss, idx);
}

/**
 * ccs_tasklist_lock - Take lock for reading list of "struct task_struct".
 *
 * Returns nothing.
 */
static inline void ccs_tasklist_lock(void)
{
	rcu_read_lock();
}

/**
 * ccs_tasklist_unlock - Release lock for reading list of "struct task_struct".
 *
 * Returns nothing.
 */
static inline void ccs_tasklist_unlock(void)
{
	rcu_read_unlock();
}

/**
 * ccs_sys_getppid - Copy of getppid().
 *
 * Returns parent process's PID.
 *
 * Alpha does not have getppid() defined. To be able to build this module on
 * Alpha, I have to copy getppid() from kernel/timer.c.
 */
static inline pid_t ccs_sys_getppid(void)
{
	pid_t pid;
	rcu_read_lock();
	pid = task_tgid_vnr(rcu_dereference(current->real_parent));
	rcu_read_unlock();
	return pid;
}

/**
 * ccs_sys_getpid - Copy of getpid().
 *
 * Returns current thread's PID.
 *
 * Alpha does not have getpid() defined. To be able to build this module on
 * Alpha, I have to copy getpid() from kernel/timer.c.
 */
static inline pid_t ccs_sys_getpid(void)
{
	return task_tgid_vnr(current);
}

#if defined(CONFIG_SLOB)

/**
 * ccs_round2 - Round up to power of 2 for calculating memory usage.
 *
 * @size: Size to be rounded up.
 *
 * Returns @size.
 *
 * Since SLOB does not round up, this function simply returns @size.
 */
static inline int ccs_round2(size_t size)
{
	return size;
}

#else

/**
 * ccs_round2 - Round up to power of 2 for calculating memory usage.
 *
 * @size: Size to be rounded up.
 *
 * Returns rounded size.
 *
 * Strictly speaking, SLAB may be able to allocate (e.g.) 96 bytes instead of
 * (e.g.) 128 bytes.
 */
static inline int ccs_round2(size_t size)
{
#if PAGE_SIZE == 4096
	size_t bsize = 32;
#else
	size_t bsize = 64;
#endif
	if (!size)
		return 0;
	while (size > bsize)
		bsize <<= 1;
	return bsize;
}

#endif

/**
 * ccs_put_condition - Drop reference on "struct ccs_condition".
 *
 * @cond: Pointer to "struct ccs_condition". Maybe NULL.
 *
 * Returns nothing.
 */
static inline void ccs_put_condition(struct ccs_condition *cond)
{
	if (cond)
		atomic_dec(&cond->head.users);
}

/**
 * ccs_put_group - Drop reference on "struct ccs_group".
 *
 * @group: Pointer to "struct ccs_group". Maybe NULL.
 *
 * Returns nothing.
 */
static inline void ccs_put_group(struct ccs_group *group)
{
	if (group)
		atomic_dec(&group->head.users);
}

/**
 * ccs_put_name - Drop reference on "struct ccs_name".
 *
 * @name: Pointer to "struct ccs_path_info". Maybe NULL.
 *
 * Returns nothing.
 */
static inline void ccs_put_name(const struct ccs_path_info *name)
{
	if (name)
		atomic_dec(&container_of(name, struct ccs_name, entry)->
			   head.users);
}

/* For importing variables and functions. */
extern const struct caitsith_exports caitsith_exports;

#ifdef CONFIG_CAITSITH_USE_EXTERNAL_TASK_SECURITY

/*
 * Structure for holding "struct ccs_domain_info *" and "u32 ccs_flags" for
 * each "struct task_struct".
 *
 * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
 * are maintained outside that "struct task_struct". Therefore, ccs_security
 * != task_struct . This keeps KABI for distributor's prebuilt kernels but
 * entails slow access.
 *
 * Memory for this structure is allocated when current thread tries to access
 * it. Therefore, if memory allocation failed, current thread will be killed by
 * SIGKILL. Note that if current->pid == 1, sending SIGKILL won't work.
 */
struct ccs_security {
	struct list_head list;
	const struct task_struct *task;
	struct ccs_domain_info *ccs_domain_info;
	u32 ccs_flags;
	struct rcu_head rcu;
};

#define CCS_TASK_SECURITY_HASH_BITS 12
#define CCS_MAX_TASK_SECURITY_HASH (1u << CCS_TASK_SECURITY_HASH_BITS)
extern struct list_head ccs_task_security_list[CCS_MAX_TASK_SECURITY_HASH];

struct ccs_security *ccs_find_task_security(const struct task_struct *task);

/**
 * ccs_current_security - Get "struct ccs_security" for current thread.
 *
 * Returns pointer to "struct ccs_security" for current thread.
 */
static inline struct ccs_security *ccs_current_security(void)
{
	return ccs_find_task_security(current);
}

/**
 * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
 *
 * @task: Pointer to "struct task_struct".
 *
 * Returns pointer to "struct ccs_security" for specified thread.
 */
static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
{
	struct ccs_domain_info *domain;
	rcu_read_lock();
	domain = ccs_find_task_security(task)->ccs_domain_info;
	rcu_read_unlock();
	return domain;
}

/**
 * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
 *
 * Returns pointer to "struct ccs_domain_info" for current thread.
 */
static inline struct ccs_domain_info *ccs_current_domain(void)
{
	return ccs_find_task_security(current)->ccs_domain_info;
}

/**
 * ccs_task_flags - Get flags for specified thread.
 *
 * @task: Pointer to "struct task_struct".
 *
 * Returns flags for specified thread.
 */
static inline u32 ccs_task_flags(struct task_struct *task)
{
	u32 ccs_flags;
	rcu_read_lock();
	ccs_flags = ccs_find_task_security(task)->ccs_flags;
	rcu_read_unlock();
	return ccs_flags;
}

/**
 * ccs_current_flags - Get flags for current thread.
 *
 * Returns flags for current thread.
 */
static inline u32 ccs_current_flags(void)
{
	return ccs_find_task_security(current)->ccs_flags;
}

#else

/*
 * "struct ccs_domain_info *" and "u32 ccs_flags" for each "struct task_struct"
 * are maintained inside that "struct task_struct". Therefore, ccs_security ==
 * task_struct . This allows fast access but breaks KABI checks for
 * distributor's prebuilt kernels due to changes in "struct task_struct".
 */
#define ccs_security task_struct

/**
 * ccs_find_task_security - Find "struct ccs_security" for given task.
 *
 * @task: Pointer to "struct task_struct".
 *
 * Returns pointer to "struct ccs_security".
 */
static inline struct ccs_security *ccs_find_task_security(struct task_struct *
							  task)
{
	return task;
}

/**
 * ccs_current_security - Get "struct ccs_security" for current thread.
 *
 * Returns pointer to "struct ccs_security" for current thread.
 */
static inline struct ccs_security *ccs_current_security(void)
{
	return ccs_find_task_security(current);
}

/**
 * ccs_task_domain - Get "struct ccs_domain_info" for specified thread.
 *
 * @task: Pointer to "struct task_struct".
 *
 * Returns pointer to "struct ccs_security" for specified thread.
 */
static inline struct ccs_domain_info *ccs_task_domain(struct task_struct *task)
{
	struct ccs_domain_info *domain = task->ccs_domain_info;
	return domain ? domain : &ccs_kernel_domain;
}

/**
 * ccs_current_domain - Get "struct ccs_domain_info" for current thread.
 *
 * Returns pointer to "struct ccs_domain_info" for current thread.
 *
 * If current thread does not belong to a domain (which is true for initial
 * init_task in order to hide ccs_kernel_domain from this module),
 * current thread enters into ccs_kernel_domain.
 */
static inline struct ccs_domain_info *ccs_current_domain(void)
{
	struct task_struct *task = current;
	if (!task->ccs_domain_info)
		task->ccs_domain_info = &ccs_kernel_domain;
	return task->ccs_domain_info;
}

/**
 * ccs_task_flags - Get flags for specified thread.
 *
 * @task: Pointer to "struct task_struct".
 *
 * Returns flags for specified thread.
 */
static inline u32 ccs_task_flags(struct task_struct *task)
{
	return ccs_find_task_security(task)->ccs_flags;
}

/**
 * ccs_current_flags - Get flags for current thread.
 *
 * Returns flags for current thread.
 */
static inline u32 ccs_current_flags(void)
{
	return ccs_find_task_security(current)->ccs_flags;
}

#endif

#endif
