146 |
rodolico |
1 |
#! /usr/bin/env perl
|
|
|
2 |
|
|
|
3 |
# Copyright (c) 2024, Daily Data, Inc
|
|
|
4 |
#
|
|
|
5 |
# Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following
|
|
|
6 |
# conditions are met:
|
|
|
7 |
#
|
|
|
8 |
# Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
|
|
|
9 |
# Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following
|
|
|
10 |
# disclaimer in the documentation and/or other materials provided with the distribution.
|
|
|
11 |
#
|
|
|
12 |
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING,
|
|
|
13 |
# BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
|
|
|
14 |
# SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
|
|
15 |
# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
|
|
16 |
# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
|
|
|
17 |
# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.[12]
|
|
|
18 |
#
|
|
|
19 |
# Description
|
|
|
20 |
# Script to clean up security log tables on WordPress sites
|
|
|
21 |
# Some wordpress site security suites continously add logs, but do not offer the ability to clean up entries after
|
|
|
22 |
# a certain period of time. This can cause database tables to grow without relief until they threaten to fill
|
|
|
23 |
# the database partition
|
|
|
24 |
# This came to light recently when the half dozen WordPress sites we manage threatened to fill the database partition
|
|
|
25 |
# after a few years of monitoring.
|
|
|
26 |
#
|
|
|
27 |
# Before we ran this script, the 6G partition was 81% full, and after cleaning up, that dropped to 52%, so almost a
|
|
|
28 |
# third of the database size was years of logs, or almost 2G. Of course, you can increase the disk space available on
|
|
|
29 |
# the partition, but we just wanted to keep 4 weeks of logs
|
|
|
30 |
#
|
|
|
31 |
# Designed to be run from a monthly or weekly cron job, it will look for all MySQL databases, then check each one in turn
|
|
|
32 |
# for the existence of the security log tables. If a database contains the tables, it will run the script to remove
|
|
|
33 |
# anything over $KEEPDAYS days old.
|
|
|
34 |
#
|
|
|
35 |
# this is a quick script and has only been tested on one single system, where the root user had access to all MySQL
|
|
|
36 |
# functions without password. Modifications will need to be made on systems which are more secure.
|
147 |
rodolico |
37 |
#
|
|
|
38 |
# This script is available via subversion at
|
|
|
39 |
# svn co http://svn.dailydata.net/svn/sysadmin_scripts/trunk/Wordpress/cleanWPSecLogs
|
|
|
40 |
# NOTE: the above repository is a working copy from Daily Data, which can be modified as required without notification
|
146 |
rodolico |
41 |
|
|
|
42 |
|
|
|
43 |
use strict;
|
|
|
44 |
use warnings;
|
|
|
45 |
|
|
|
46 |
my $KEEPDAYS = 28;
|
|
|
47 |
|
|
|
48 |
# clean up the output from mysqlshow
|
|
|
49 |
# if the name does not match the regular expression
|
|
|
50 |
# return null, else return the matched code
|
|
|
51 |
sub clean {
|
|
|
52 |
my $name = shift;
|
|
|
53 |
# regex matches any database beginning with c## for our ISPConfig setup
|
|
|
54 |
# pretty sloppy regex, but works on our system
|
|
|
55 |
$name =~ m/(c\d+[a-z0-9_]+)/i;
|
|
|
56 |
return $1 ? $1 : '';;
|
|
|
57 |
}
|
|
|
58 |
|
|
|
59 |
# create a temporary sql file which is sent to all valid databases
|
|
|
60 |
# NOTE: it is the responsiblity of the script to remove the temp file (we don't do it here)
|
|
|
61 |
sub createSQL {
|
|
|
62 |
use File::Temp;
|
|
|
63 |
my $fh = File::Temp->new( SUFFIX => '.sql', UNLINK => 0, TEMPLATE=> '/tmp/cleanLogs.XXXXXXXXXX' );
|
|
|
64 |
# NOTE: if you don't want any logs kept, you can use 'truncate wp_itsec_logs' instead, which is faster and also
|
|
|
65 |
# recovers disk space
|
|
|
66 |
# delete anything older over $KEEPDAYS old from wp_itsec_logs. timestamp appears to be UT, so will be off by some
|
|
|
67 |
print $fh "DELETE FROM wp_itsec_logs WHERE timestamp <DATE_SUB(NOW(), INTERVAL $KEEPDAYS DAY);\n";
|
|
|
68 |
# same with wp_itsec_lockouts
|
|
|
69 |
print $fh "delete FROM wp_itsec_lockouts WHERE lockout_expire < DATE_SUB(NOW(), INTERVAL $KEEPDAYS DAY);\n";
|
|
|
70 |
# next two commands recover disk space from tables. You can ignore this after the first run as very little will remain
|
|
|
71 |
# between sessions
|
|
|
72 |
print $fh "optimize table wp_itsec_logs;\n";
|
|
|
73 |
print $fh "optimize table wp_itsec_lockouts;\n";
|
|
|
74 |
close $fh;
|
|
|
75 |
return $fh->filename; # returns the name of the temp file
|
|
|
76 |
}
|
|
|
77 |
|
|
|
78 |
my $sqlFile = &createSQL(); # makes the sql file to be run on each database
|
|
|
79 |
# print "$sqlFile\n";
|
|
|
80 |
|
|
|
81 |
# simple way to get list of all databases, but they need to be cleaned up afterwards
|
|
|
82 |
my @tables = `mysqlshow`;
|
|
|
83 |
for ( my $i = 0; $i < @tables; $i++ ) {
|
|
|
84 |
$tables[$i] = &clean( $tables[$i] );
|
|
|
85 |
}
|
|
|
86 |
#die join( "\n", @tables ) . "\n";
|
|
|
87 |
|
|
|
88 |
# process each table
|
|
|
89 |
for ( my $table = 0; $table < @tables ; $table++ ) {
|
|
|
90 |
next unless $tables[$table]; # skip anything that &clean zapped
|
|
|
91 |
# command passed to mysql to determine if the table wp_itsec_logs exists in database
|
|
|
92 |
my $command = "echo show tables like \\'wp_itsec_logs\\' | mysql $tables[$table]";
|
|
|
93 |
#die "$command\n";
|
|
|
94 |
my $valid = `$command`; # if $command has something, it is valid. If it is the empty string, no table, so not valid
|
|
|
95 |
#die "'$valid'\n";
|
|
|
96 |
if ( $valid ) {
|
|
|
97 |
print "Found in $tables[$table]\n";
|
|
|
98 |
print `mysql $tables[$table] < $sqlFile`; # run mysql against database passing the commands from the temp file in
|
|
|
99 |
}
|
|
|
100 |
}
|
|
|
101 |
# remove the temp file
|
|
|
102 |
unlink( $sqlFile ) or die "Could not delete temp file $sqlFile\n";
|
|
|
103 |
1;
|