/*
 * (C) Copyright Fuji Xerox Co., Ltd. All rights are reserved.
 * 
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 * 2017/12/16	nobuo.iwata@fujixerox.co.jp
 */

#include "fxlsm_lsm.h"
#include "fxlsm_lsm_defaults.h"
#include "fxlsm_ops.h"
#include "fxlsm_net.h"
#include "fxlsm_list.h"
#include "fxlsm_prof.h"
#include "fxlsm_event.h"
#include "fxlsm_sysfs.h"
#include "fxlsm_log.h"
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>

MODULE_DESCRIPTION("lsm for fxlsm");
MODULE_AUTHOR("nobuo.iwata@fujixerox.co.jp");
MODULE_LICENSE("GPL");

static char *fxlsm_enabled = FXLSM_ENABLED_DEFAULT;
static char *fxlsm_through = FXLSM_THROUGH_DEFAULT;
static int fxlsm_secondary = FXLSM_SECONDARY_DEFAULT;
static char *fxlsm_capture = FXLSM_CAPTURE_DEFAULT;
static int fxlsm_capture_load = FXLSM_CAPTURE_LOAD_DEFAULT;
static int fxlsm_comms = FXLSM_COMMS_DEFAULT;
static int fxlsm_lds = FXLSM_LDS_DEFAULT;
static int fxlsm_creatx = FXLSM_CREATX_DEFAULT;
static int fxlsm_chmodx = FXLSM_CHMODX_DEFAULT;
static int fxlsm_net = FXLSM_NET_DEFAULT;
static int fxlsm_max_capture = FXLSM_MAX_CAPTURE_DEFAULT;
static int fxlsm_max_events = FXLSM_MAX_EVENTS_DEFAULT;

static void set_params(void)
{
	fxlsm_set_enabled(fxlsm_enabled);
	fxlsm_set_through(fxlsm_through);
	fxlsm_set_secondary(fxlsm_secondary);
	fxlsm_set_capture(fxlsm_capture);
	fxlsm_set_capture_load(fxlsm_capture_load);
	fxlsm_set_comms(fxlsm_comms);
	fxlsm_set_lds(fxlsm_lds);
	fxlsm_set_creatx(fxlsm_creatx);
	fxlsm_set_chmodx(fxlsm_chmodx);
	fxlsm_set_net(fxlsm_net);
	fxlsm_set_max_capture(fxlsm_max_capture);
	fxlsm_set_max_events(fxlsm_max_events);
}

#ifdef FXLSM_LOADABLE
module_param(fxlsm_enabled, charp, S_IRUGO);
MODULE_PARM_DESC(fxlsm_enabled, "fxlsm_enabled");
module_param(fxlsm_through, charp, S_IRUGO);
MODULE_PARM_DESC(fxlsm_through, "fxlsm_through");
module_param(fxlsm_secondary, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_secondary, "fxlsm_secondary");
module_param(fxlsm_capture, charp, S_IRUGO);
MODULE_PARM_DESC(fxlsm_capture, "fxlsm_capture");
module_param(fxlsm_capture_load, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_capture_load, "fxlsm_capture_load");
module_param(fxlsm_comms, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_comms, "fxlsm_comms");
module_param(fxlsm_lds, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_lds, "fxlsm_lds");
module_param(fxlsm_creatx, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_creatx, "fxlsm_creatx");
module_param(fxlsm_chmodx, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_chmodx, "fxlsm_chmodx");
module_param(fxlsm_net, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_net, "fxlsm_net");
module_param(fxlsm_max_capture, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_max_capture, "fxlsm_max_capture");
module_param(fxlsm_max_events, int, S_IRUGO);
MODULE_PARM_DESC(fxlsm_max_events, "fxlsm_max_events");
#endif

#ifdef FXLSM_LSM_NEW
#include <linux/lsm_hooks.h>
#ifdef FXLSM_LOADABLE
static unsigned long adr_security_hook_heads;
module_param(adr_security_hook_heads, ulong, S_IRUGO);
MODULE_PARM_DESC(adr_security_hook_heads, "adr_security_hook_heads");
static struct security_hook_heads *p_security_hook_heads;
#ifdef FXLSM_HAVE_LSM_NAMES
static unsigned long adr_lsm_names;
module_param(adr_lsm_names, ulong, S_IRUGO);
MODULE_PARM_DESC(adr_lsm_names, "adr_lsm_names");
static char *p_lsm_names;
#endif /* FXLSM_HAVE_LSM_NAMES */
#endif /* FXLSM_LOADABLE */
#endif /* FXLSM_LSM_NEW */

#ifdef FXLSM_LSM_OLD
#ifdef FXLSM_LOADABLE
static unsigned long adr_security_ops;
module_param(adr_security_ops, ulong, S_IRUGO);
MODULE_PARM_DESC(adr_security_ops, "adr_security_ops");
static struct security_operations *p_security_ops;
int (*fxlsm_org_file_open)
		(struct file *file, const struct cred *cred);
#ifdef CONFIG_SECURITY_PATH
int (*fxlsm_org_path_unlink)
		(struct path *dir, struct dentry *dentry);
int (*fxlsm_org_path_mkdir)
		(struct path *dir, struct dentry *dentry, umode_t mode);
int (*fxlsm_org_path_rmdir)
		(struct path *dir, struct dentry *dentry);
int (*fxlsm_org_path_mknod)
		(struct path *dir, struct dentry *dentry, umode_t mode,
			unsigned int dev);
int (*fxlsm_org_path_symlink)
		(struct path *dir, struct dentry *dentry, const char *old_name);
int (*fxlsm_org_path_link)
		(struct dentry *old_dentry,
			struct path *new_dir, struct dentry *new_dentry);
int (*fxlsm_org_path_rename)
		(struct path *old_dir, struct dentry *old_dentry,
			struct path *new_dir, struct dentry *new_dentry);
int (*fxlsm_org_path_chmod)
		(struct path *path, umode_t mode);
int (*fxlsm_org_path_chown)
		(struct path *path, kuid_t uid, kgid_t gid);
int (*fxlsm_org_path_chroot)
		(struct path *path);
int (*fxlsm_org_path_truncate)
		(struct path *path);
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
int (*fxlsm_org_socket_bind)
		(struct socket *sock, struct sockaddr *address, int addrlen);
int (*fxlsm_org_socket_connect)
		(struct socket *sock, struct sockaddr *address, int addrlen);
int (*fxlsm_org_socket_listen)
		(struct socket *sock, int backlog);
int (*fxlsm_org_socket_accept)
		(struct socket *sock, struct socket *newsock);
int (*fxlsm_org_socket_sendmsg)
		(struct socket *sock, struct msghdr *msg, int size);
int (*fxlsm_org_socket_recvmsg)
		(struct socket *sock, struct msghdr *msg, int size, int flags);
void (*fxlsm_org_sock_graft)
		(struct sock *sk, struct socket *parent);
#endif /* CONFIG_SECURITY_NETWORK */
#endif /* FXLSM_LOADABLE */
#endif /* FXLSM_LSM_OLD */

static int sub_init(void)
{
	int ret;

	/*
	 * must be first! it will be used in other inits.
	 */
	fxlsm_prof_init();

	ret = fxlsm_sysfs_init();
	if (ret)
		goto err_out;
	ret = fxlsm_event_init();
	if (ret)
		goto err_sysfs_exit;
	ret = fxlsm_list_init();
	if (ret)
		goto err_event_exit;

	set_params();

	return 0;
err_event_exit:
	fxlsm_event_exit();
err_sysfs_exit:
	fxlsm_sysfs_exit();
err_out:
	return ret;
}

static void sub_exit(void)
{
	fxlsm_list_exit();
	fxlsm_event_exit();
	fxlsm_sysfs_exit();
}

#ifdef FXLSM_LSM_NEW
#ifdef FXLSM_LOADABLE
#ifdef CONFIG_SECURITY_PATH
#define NUM_HOOKS_PATH 11
#else
#define NUM_HOOKS_PATH 0
#endif
#ifdef CONFIG_SECURITY_NETWORK
#define NUM_HOOKS_NETWORK 7
#else
#define NUM_HOOKS_NETWORK 0
#endif
#define NUM_HOOKS (NUM_HOOKS_PATH + NUM_HOOKS_NETWORK + 1)

static struct security_hook_list fxlsm_hooks[NUM_HOOKS];

#ifdef FXLSM_HAVE_SECURITY_HOOK_LIST_LSM
#define add_hook(I, HEAD, HOOK) \
	do { \
	memset(&fxlsm_hooks[I], 0, sizeof(struct security_hook_list)); \
	fxlsm_hooks[I].head = &p_security_hook_heads->HEAD; \
	fxlsm_hooks[I].hook.HEAD = HOOK; \
	fxlsm_hooks[I].lsm = lsm_name; \
	list_add_tail_rcu(&fxlsm_hooks[I].list, fxlsm_hooks[I].head); \
	++(I); \
	} while (0)
#define del_hook(I, HEAD, HOOK) \
	if (HOOKS[I].head) { \
		struct security_hook_list *pos, *n; \
		list_for_each_entry_safe( \
			pos, n, fxlsm_hooks[I].head, list) { \
			if (pos->hook.HEAD == HOOK && \
				strcmp(pos->lsm, lsm_name) == 0) \
				list_del_rcu(&pos->list); \
		} \
	} \
	do { \
	++(I); \
	} while (0)
#else
#define add_hook(I, HEAD, HOOK) \
	do { \
	memset(&fxlsm_hooks[I], 0, sizeof(struct security_hook_list)); \
	fxlsm_hooks[I].head = &p_security_hook_heads->HEAD; \
	fxlsm_hooks[I].hook.HEAD = HOOK; \
	list_add_tail_rcu(&fxlsm_hooks[I].list, fxlsm_hooks[I].head); \
	++(I); \
	} while (0)
#define del_hook(I, HEAD, HOOK) \
	if (fxlsm_hooks[I].head) { \
		struct security_hook_list *pos, *n; \
		list_for_each_entry_safe( \
			pos, n, fxlsm_hooks[I].head, list) { \
			if (pos->hook.HEAD == HOOK ) \
				list_del_rcu(&pos->list); \
		} \
	} \
	do { \
	++(I); \
	} while (0)
#endif /* !FXLSM_HAVE_SECURITY_HOOK_LIST_LSM */

#ifdef FXLSM_HAVE_LSM_NAMES
static int add_lsm_name(const char *name)
{
	char *s;

	if (p_lsm_names)
		s = kasprintf(GFP_KERNEL, "%s,%s", p_lsm_names, name);
	else
		s = kstrdup(name, GFP_KERNEL);
	if (!s) {
		ERR("alloc name");
		return -ENOMEM;
	}
	p_lsm_names = s;
	return 0;
}

static void del_lsm_name(const char *name)
{
	char *s = p_lsm_names, *e;
	int name_len = strlen(name), len;

	while (1) {
		e = strchr(s, ',');
		if (e) {
			len = e - s;
			if (len == name_len && memcmp(s, name, len) == 0) {
				strcpy(s, e + 1);
				break;
			}
			s = e + 1;
		} else {
			if (strcmp(s, name) == 0) {
				if (s > p_lsm_names && *(s - 1) == ',')
					*(s - 1) = 0;
				else
					*s = 0;
			}
			break;
		}
	}
}

static char *lsm_name = "fxlsm";
#endif /* FXLSM_HAVE_LSM_NAMES */

static int __init fxlsm_init(void)
{
	int index = 0;
	int ret;

	ret = sub_init();
	if (ret)
		goto err_out;

	if (!adr_security_hook_heads) {
		ERR("undefined addr security_hook_heads");
		ret = -EINVAL;
		goto err_sub_exit;
	}
	p_security_hook_heads =
		(struct security_hook_heads *)adr_security_hook_heads;
	INFO("security_hook_heads:%p", p_security_hook_heads);
#ifdef FXLSM_HAVE_LSM_NAMES
	if (!adr_lsm_names) {
		ERR("undefined addr lsm_names");
		ret = -EINVAL;
		goto err_sub_exit;
	}
	p_lsm_names = (char *)adr_lsm_names;
	INFO("lsm_names:%p", p_lsm_names);
#endif
	add_hook(index, file_open, fxlsm_file_open);
#ifdef CONFIG_SECURITY_PATH
	add_hook(index, path_unlink, fxlsm_path_unlink);
	add_hook(index, path_mkdir, fxlsm_path_mkdir);
	add_hook(index, path_rmdir, fxlsm_path_rmdir);
	add_hook(index, path_mknod, fxlsm_path_mknod);
	add_hook(index, path_symlink, fxlsm_path_symlink);
	add_hook(index, path_link, fxlsm_path_link);
	add_hook(index, path_rename, fxlsm_path_rename);
	add_hook(index, path_chmod, fxlsm_path_chmod);
	add_hook(index, path_chown, fxlsm_path_chown);
	add_hook(index, path_chroot, fxlsm_path_chroot);
	add_hook(index, path_truncate, fxlsm_path_truncate);
#else
	ERR("CONFIG_SECURITY_PATH is not defined: path hooks are desabled.");
#endif
#ifdef CONFIG_SECURITY_NETWORK
	add_hook(index, socket_bind, fxlsm_socket_bind);
	add_hook(index, socket_connect, fxlsm_socket_connect);
	add_hook(index, socket_listen, fxlsm_socket_listen);
	add_hook(index, socket_accept, fxlsm_socket_accept);
	add_hook(index, socket_sendmsg, fxlsm_socket_sendmsg);
	add_hook(index, socket_recvmsg, fxlsm_socket_recvmsg);
	add_hook(index, sock_graft, fxlsm_sock_graft);
#else
	ERR("CONFIG_SECURITY_NETWORK is not defined: net hooks are desabled.");
#endif
#ifdef FXLSM_HAVE_LSM_NAMES
	ret = add_lsm_name(lsm_name);
	if (ret)
		goto err_sub_exit;
#endif
	fxlsm_notify_started();
	return 0;
err_sub_exit:
	sub_exit();
err_out:
	return ret;
}

static void __exit fxlsm_exit(void)
{
	int index = 0;

	del_hook(index, file_open, fxlsm_file_open);
#ifdef CONFIG_SECURITY_PATH
	del_hook(index, path_unlink, fxlsm_path_unlink);
	del_hook(index, path_mkdir, fxlsm_path_mkdir);
	del_hook(index, path_rmdir, fxlsm_path_rmdir);
	del_hook(index, path_mknod, fxlsm_path_mknod);
	del_hook(index, path_symlink, fxlsm_path_symlink);
	del_hook(index, path_link, fxlsm_path_link);
	del_hook(index, path_rename, fxlsm_path_rename);
	del_hook(index, path_chmod, fxlsm_path_chmod);
	del_hook(index, path_chown, fxlsm_path_chown);
	del_hook(index, path_chroot, fxlsm_path_chroot);
	del_hook(index, path_truncate, fxlsm_path_truncate);
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	del_hook(index, socket_bind, fxlsm_socket_bind);
	del_hook(index, socket_connect, fxlsm_socket_connect);
	del_hook(index, socket_listen, fxlsm_socket_listen);
	del_hook(index, socket_accept, fxlsm_socket_accept);
	del_hook(index, socket_sendmsg, fxlsm_socket_sendmsg);
	del_hook(index, socket_recvmsg, fxlsm_socket_recvmsg);
	del_hook(index, sock_graft, fxlsm_sock_graft);
#endif /* CONFIG_SECURITY_NETWORK */
#ifdef FXLSM_HAVE_LSM_NAMES
	del_lsm_name(lsm_name);
#endif
	sub_exit();
	fxlsm_notify_stopped();
}

module_init(fxlsm_init);
module_exit(fxlsm_exit);
#else /* FXLSM_LOADABLE */
static struct security_hook_list fxlsm_hooks[] = {
	LSM_HOOK_INIT(file_open, fxlsm_file_open),
#ifdef CONFIG_SECURITY_PATH
	LSM_HOOK_INIT(path_unlink, fxlsm_path_unlink),
	LSM_HOOK_INIT(path_mkdir, fxlsm_path_mkdir),
	LSM_HOOK_INIT(path_rkdir, fxlsm_path_rkdir),
	LSM_HOOK_INIT(path_mknod, fxlsm_path_mknod),
	LSM_HOOK_INIT(path_symlink, fxlsm_path_symlink),
	LSM_HOOK_INIT(path_link, fxlsm_path_link),
	LSM_HOOK_INIT(path_rename, fxlsm_path_rename),
	LSM_HOOK_INIT(path_chmod, fxlsm_path_chmod),
	LSM_HOOK_INIT(path_chown, fxlsm_path_chown),
	LSM_HOOK_INIT(path_chroot, fxlsm_path_chroot),
	LSM_HOOK_INIT(path_truncate, fxlsm_path_truncate),
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	LSM_HOOK_INIT(socket_bind, fxlsm_socket_bind),
	LSM_HOOK_INIT(socket_connect, fxlsm_socket_connect),
	LSM_HOOK_INIT(socket_listen, fxlsm_socket_listen),
	LSM_HOOK_INIT(socket_accept, fxlsm_socket_accept),
	LSM_HOOK_INIT(socket_sendmsg, fxlsm_socket_sendmsg),
	LSM_HOOK_INIT(socket_recvmsg, fxlsm_socket_recvmsg),
	LSM_HOOK_INIT(sock_graft, fxlsm_sock_graft),
#endif /* CONFIG_SECURITY_NETWORK */
};

static int __init fxlsm_init(void)
{
	int ret;

	ret = sub_init();
	if (ret)
		goto err_out;

	security_add_hooks(fxlsm_hooks, ARRAY_SIZE(fxlsm_hooks), "fxlsm");
	fxlsm_notify_started();
	return 0;
err_out:
	return ret;
}
security_initcall(fxlsm_init);
#endif /* !FXLSM_LOADABLE */
#endif /* FXLSM_LSM_NEW */

#ifdef FXLSM_LSM_OLD
#ifdef FXLSM_LOADABLE
static int __init fxlsm_init(void)
{
	int ret;

	ret = sub_init();
	if (ret)
		goto err_out;

	INFO("security_ops:%lx", adr_security_ops);
	if (!adr_security_ops) {
		ERR("undefined addr security_ops");
		ret = -EINVAL;
		goto err_sub_exit;
	}
	p_security_ops = *((struct security_operations **)adr_security_ops);
	fxlsm_org_file_open = p_security_ops->file_open;
#ifdef CONFIG_SECURITY_PATH
	fxlsm_org_path_unlink = p_security_ops->path_unlink;
	fxlsm_org_path_mkdir = p_security_ops->path_mkdir;
	fxlsm_org_path_rmdir = p_security_ops->path_rmdir;
	fxlsm_org_path_mknod = p_security_ops->path_mknod;
	fxlsm_org_path_symlink = p_security_ops->path_symlink;
	fxlsm_org_path_link = p_security_ops->path_link;
	fxlsm_org_path_rename = p_security_ops->path_rename;
	fxlsm_org_path_chmod = p_security_ops->path_chmod;
	fxlsm_org_path_chown = p_security_ops->path_chown;
	fxlsm_org_path_chroot = p_security_ops->path_chroot;
	fxlsm_org_path_truncate = p_security_ops->path_truncate;
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	fxlsm_org_socket_bind = p_security_ops->socket_bind;
	fxlsm_org_socket_connect = p_security_ops->socket_connect;
	fxlsm_org_socket_listen = p_security_ops->socket_listen;
	fxlsm_org_socket_accept = p_security_ops->socket_accept;
	fxlsm_org_socket_sendmsg = p_security_ops->socket_sendmsg;
	fxlsm_org_socket_recvmsg = p_security_ops->socket_recvmsg;
	fxlsm_org_sock_graft = p_security_ops->sock_graft;
#endif /* CONFIG_SECURITY_NETWORK */
	p_security_ops->file_open = fxlsm_file_open;
#ifdef CONFIG_SECURITY_PATH
	p_security_ops->path_unlink = fxlsm_path_unlink;
	p_security_ops->path_mkdir = fxlsm_path_mkdir;
	p_security_ops->path_rmdir = fxlsm_path_rmdir;
	p_security_ops->path_mknod = fxlsm_path_mknod;
	p_security_ops->path_symlink = fxlsm_path_symlink;
	p_security_ops->path_link = fxlsm_path_link;
	p_security_ops->path_rename = fxlsm_path_rename;
	p_security_ops->path_chmod = fxlsm_path_chmod;
	p_security_ops->path_chown = fxlsm_path_chown;
	p_security_ops->path_chroot = fxlsm_path_chroot;
	p_security_ops->path_truncate = fxlsm_path_truncate;
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	p_security_ops->socket_bind = fxlsm_socket_bind;
	p_security_ops->socket_connect = fxlsm_socket_connect;
	p_security_ops->socket_listen = fxlsm_socket_listen;
	p_security_ops->socket_accept = fxlsm_socket_accept;
	p_security_ops->socket_sendmsg = fxlsm_socket_sendmsg;
	p_security_ops->socket_recvmsg = fxlsm_socket_recvmsg;
	p_security_ops->sock_graft = fxlsm_sock_graft;
#endif /* CONFIG_SECURITY_NETWORK */
	fxlsm_notify_started();
	return 0;
err_sub_exit:
	sub_exit();
err_out:
	return ret;
}

static void __exit fxlsm_exit(void)
{
	p_security_ops->file_open = fxlsm_org_file_open;
#ifdef CONFIG_SECURITY_PATH
	p_security_ops->path_unlink = fxlsm_org_path_unlink;
	p_security_ops->path_mkdir = fxlsm_org_path_mkdir;
	p_security_ops->path_rmdir = fxlsm_org_path_rmdir;
	p_security_ops->path_mknod = fxlsm_org_path_mknod;
	p_security_ops->path_symlink = fxlsm_org_path_symlink;
	p_security_ops->path_link = fxlsm_org_path_link;
	p_security_ops->path_rename = fxlsm_org_path_rename;
	p_security_ops->path_chmod = fxlsm_org_path_chmod;
	p_security_ops->path_chown = fxlsm_org_path_chown;
	p_security_ops->path_chroot = fxlsm_org_path_chroot;
	p_security_ops->path_truncate = fxlsm_org_path_truncate;
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	p_security_ops->socket_bind = fxlsm_org_socket_bind;
	p_security_ops->socket_connect = fxlsm_org_socket_connect;
	p_security_ops->socket_listen = fxlsm_org_socket_listen;
	p_security_ops->socket_accept = fxlsm_org_socket_accept;
	p_security_ops->socket_sendmsg = fxlsm_org_socket_sendmsg;
	p_security_ops->socket_recvmsg = fxlsm_org_socket_recvmsg;
	p_security_ops->sock_graft = fxlsm_org_sock_graft;
#endif /* CONFIG_SECURITY_NETWORK */
	sub_exit();
	fxlsm_notify_stopped();
}

module_init(fxlsm_init);
module_exit(fxlsm_exit);
#else /* FXLSM_LOADABLE */
static struct security_operations fxlsm_ops = {
	.name = "fxlsm",
	.file_open = fxlsm_file_open,
#ifdef CONFIG_SECURITY_PATH
	.path_unlink = fxlsm_path_unlink,
	.path_mkdir = fxlsm_path_mkdir,
	.path_rmdir = fxlsm_path_rmdir,
	.path_mknod = fxlsm_path_mknod,
	.path_symlink = fxlsm_path_symlink,
	.path_link = fxlsm_path_link,
	.path_rename = fxlsm_path_rename,
	.path_chmod = fxlsm_path_chmod,
	.path_chown = fxlsm_path_chown,
	.path_chroot = fxlsm_path_chroot,
	.path_truncate = fxlsm_path_truncate,
#endif /* CONFIG_SECURITY_PATH */
#ifdef CONFIG_SECURITY_NETWORK
	.socket_bind = fxlsm_socket_bind,
	.socket_connect = fxlsm_socket_connect,
	.socket_listen = fxlsm_socket_listen,
	.socket_accept = fxlsm_socket_accept,
	.socket_sendmsg = fxlsm_socket_sendmsg,
	.socket_recvmsg = fxlsm_socket_recvmsg,
	.sock_graft = fxlsm_sock_graft,
#endif /* CONFIG_SECURITY_NETWORK */
};

static int __init fxlsm_init(void)
{
	int ret;

	ret = sub_init();
	if (ret)
		goto err_out;

	ret = register_security(&fxlsm_ops);
	if (ret) {
		ERR("register fxlsm_ops");
		goto err_sub_exit;
	}
	fxlsm_notify_started();
	return 0;
err_sub_exit:
	sub_exit();
err_out:
	return ret;
}

security_initcall(fxlsm_init);
#endif /* !FXLSM_LOADABLE */
#endif /* FXLSM_LSM_OLD */
