/* logcalls.c 
 * by pheisar <pheisar@ccl.pt> 
 * http://www.ccl.pt/~pheisar/pgpkey  
 * 
 * logs specific calls like 'mkdir', 'rmdir', etc, called by users in a logfile (FILENAME). 
 *  
 * note: i wanted to add more log functions for more calls, but i ain't in the mood, so..
 *	 do it yourself. 
 *
 * bash# gcc logcalls.c -o logcalls.so -ldl -shared -O2 -s
 * bash# export LD_PRELOAD=/path/to/logcalls.so
 *
 * note: set the FILENAME and LIBPATH constants to fit your system.
 */

#include <stdio.h>
#include <unistd.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dlfcn.h>
#include <pwd.h>
#include <sys/time.h>

/* don't want to log a specific call? just define it to 0 */
#define MKDIRX 1
#define RMDIRX 2	
#define LINKX 3
#define OPENX 4 /* not tested */

#define FILENAME "/tmp/logfile" 	// logfile
#define LIBPATH "/lib/libc.so.6"	// lib path

FILE *fd; 
int result;
struct passwd *pwd;
struct timeval tm;

/* prototypes */
static void openlog(void);
static void logfunc(int, const char *, const char *, mode_t, int);
void print_time(const struct timeval *);
int mkdir(const char *, mode_t);
int rmdir(const char*);
int link(const char *, const char *);
int my_open(const char *, int);
int (*realmkdir)(const char *, mode_t);
int (*realrmdir)(const char *);
int (*reallink)(const char *, const char *);
int (*realopen)(const char *, int);

//////////////
// logfile  //
//////////////
static void openlog(void)
{
	umask(0);
	fd = fopen(FILENAME, "a");
	if(fd == NULL) {
		perror("fopen()");
		exit(1);
	}
}	
	
//////////////////
// log function //
////////////////// 
static void logfunc(int x, const char *oldpath, const char *pathname, mode_t mode, int result)
{
	openlog();
	
	pwd = getpwuid(getuid());
	if(pwd == NULL) {
		perror("getpwuid()");
		exit(1);
	}
	
	gettimeofday(&tm, 0);

	print_time(&tm);
	fprintf(fd, " - %s(%d) ", pwd->pw_name, pwd->pw_uid);
	fprintf(fd, "called ");
	
	if(x == RMDIRX) fprintf(fd, "rmdir(%s), %s\n", pathname, (!result) ? "success." : "error.");
	if(x == MKDIRX) fprintf(fd, "mkdir(%s, %u), %s\n", pathname, mode, (!result) ? "success." : "error.");
	if(x == LINKX)  fprintf(fd, "link(%s, %s), %s\n", oldpath, pathname, (!result) ? "success." : "error.");
	if(x == OPENX)  fprintf(fd, "open(%s, %d), %s\n", pathname, (!result) ? "success." : "error.");

	fclose(fd);
}

///////////////////////
// mkdir redirection //
/////////////////////// 
int mkdir(const char *pathname, mode_t mode)
{
	void *handle;
	result = 0;
	
	handle = dlopen(LIBPATH, 1);
	if(!handle) {
		fputs(dlerror(), stderr);
		exit(1);
	}
	
	realmkdir = dlsym(handle, "mkdir");
	if(!realmkdir) {
		fputs(dlerror(), stderr);
		exit(1);
	}

	result = realmkdir(pathname, mode);
	
	logfunc(MKDIRX, NULL, pathname, mode, result);

	return result;
}	

///////////////////////
// rmdir redirection //
///////////////////////
int rmdir(const char *pathname)
{
	void *handle;
	result = 0;

	handle = dlopen(LIBPATH, 1);
	if(!handle) {
		fputs(dlerror(), stderr);
		exit(1);
	}

	realrmdir = dlsym(handle, "rmdir");
	if(!realrmdir) {
		fputs(dlerror(), stderr);
		exit(1);
	}

	result = realrmdir(pathname);
	
	logfunc(RMDIRX, NULL, pathname, 0, result);

	return result;
}

//////////////////////
// link redirection //
//////////////////////
int link(const char *oldpath, const char *newpath)
{
	void *handle;

	handle = dlopen(LIBPATH, 1);
	if(!handle) {
		fputs(dlerror(), stderr);
                exit(1);
        }
	
	reallink = dlsym(handle, "link");
	if(!reallink) {
		fputs(dlerror(), stderr);
                exit(1);
        }

	result = reallink(oldpath, newpath);
	
	logfunc(LINKX, oldpath, newpath, 0, result);

	return result;
}  

//////////////////////
// open redirection //
//////////////////////
int my_open(const char *pathname, int flags)
{
	void *handle;
        
        handle = dlopen(LIBPATH, 1);
        if(!handle) {
                fputs(dlerror(), stderr);
                exit(1);
        }

	realopen = dlsym(handle, "open");
	if(!realopen) {
		fputs(dlerror(), stderr);
                exit(1);
        }

	result = realopen(pathname, flags);
	
	logfunc(OPENX, NULL, pathname, 0, result);
	
	return result;
}

///////////////
// timestamp //
///////////////
void print_time(const struct timeval *tm)
{
	register int s;

	s = (tm->tv_sec) % 86400;

	fprintf(fd, "%02d:%02d:%02d", s / 3600, (s % 3600) / 60, s % 60);
}

/* EOF */

