Edit File: securemysql
#!/usr/local/cpanel/3rdparty/bin/perl # cpanel - securemysql Copyright 2010 cPanel, Inc. # All rights Reserved. # copyright@cpanel.net http://cpanel.net # This code is subject to the cPanel license. Unauthorized copying is prohibited use strict; use warnings; use Getopt::Std; use Cpanel::MysqlUtils::Check (); use Cpanel::MysqlUtils::Dir (); use Cpanel::SafeRun::Simple (); use Cpanel::MysqlUtils::Connect (); use Cpanel::MysqlUtils::MyCnf::Basic (); use Cpanel::AdminBin::Serializer (); # PPI USE OK - loadConfig speed use Try::Tiny; # Only run if executed by root exit if ( $> != 0 ); # Don't run if MySQL is not used exit if ( -e '/etc/securemysqldisable' || -e '/etc/mysqldisable' ); my $version = qq{0.3}; my $verbose = 1; my $fast = 0; my $help = 0; my $actions = q{}; my %options; getopts( 'qFha:', \%options ); if ( exists $options{'q'} ) { $verbose = 0; } if ( exists $options{'F'} ) { $fast = 1; } if ( exists $options{'h'} ) { $help = 1; } if ( exists $options{'a'} ) { $actions = $options{'a'}; if ( !defined $actions || $actions eq '' ) { $actions = 'all'; } } my @actions; if ( $actions ne 'all' && $actions ne '' ) { $actions =~ s{ [^a-z0-9,]+ }{}gxms; @actions = split /,/, $actions; } my $actionsall = 0; if ( $actions eq 'all' || grep m{ \A all \z }xms, @actions ) { $actionsall = 1; } if ($actionsall) { print "Performing all actions.\n" if $verbose; } my %actions = ( 'removeanon' => $actionsall, 'removetestdb' => $actionsall, 'removelockntmp' => $actionsall, 'removeremoteroot' => $actionsall, 'removehordeallhosts' => $actionsall, 'removehordeblankpass' => $actionsall, 'chowndatadir' => $actionsall, ); foreach my $action (@actions) { if ( exists $actions{$action} || $actionsall ) { $actions{$action} = 1; } elsif ($verbose) { print "Invalid action $action ignored.\n"; } } if ( !-t STDOUT ) { $verbose = 0; } if ( $help || ( $verbose && !$fast ) ) { print <<"EOM"; securemysql $version Options: -q - Quiet execution -F - Bypass the help message -a - Specify additional actions (comma separated list), or blank for all -h - Print this message and exit. This script attempts to secure the MySQL configuration by doing the following: (always executed) Ensure root password for MySQL is set. (always executed) Changes ownership of /var/db/mysql or /var/lib/mysql to mysql Additionally, the following actions can be specified: [optional] removeanon - Remove any anonymous users removetestdb - Remove test database removelockntmp - Remove global lock tables and create tmp table privileges from users removeremoteroot - Remove remote root login removehordeallhosts - Remove insecure horde login and privileges removehordeblankpass - Remove horde users with blank password chowndatadir - Chown the mysql data directory to mysql:mysql Examples: ./securemysql -q -F -a removeanon,removetestdb,removelockntmp,removeremoteroot ./securemysql -q -F -a "removeanon, removetestdb, removelockntmp" ./securemysql -q -F -aremovehordeallhosts EOM exit if $help; sleep 5; } if ( Cpanel::MysqlUtils::MyCnf::Basic::is_remote_mysql() ) { print "Remote MySQL configured. Exiting.\n" if $verbose; exit; } if ( delete $actions{'chowndatadir'} ) { # Set db ownership my $mysqldatadir = Cpanel::MysqlUtils::Dir::getmysqldir(); print Cpanel::SafeRun::Simple::saferun( '/bin/chown', '-R', 'mysql', '--', $mysqldatadir ) if -d $mysqldatadir; } my $mysqlrootcnf = '/root/.my.cnf'; my ( $mode, $uid, $gid ) = ( stat($mysqlrootcnf) )[ 2, 4, 5 ]; # Ensure /root/.my.cnf perms if ( defined $mode ) { chown 0, 0, $mysqlrootcnf if $uid != 0 || $gid != 0; chmod 0600, $mysqlrootcnf if $mode & 07777 != 0600; } my $err; my $dbh; try { $dbh = Cpanel::MysqlUtils::Connect::get_dbi_handle(); } catch { $err = $_; }; if ( !$dbh ) { my $ret = Cpanel::SafeRun::Simple::saferun( '/usr/local/cpanel/scripts/restartsrv_mysql', '--check' ); my $check_ok = $? == 0 ? 1 : 0; if ( !$check_ok ) { # This will force a password reset if password is wrong/blank $check_ok = Cpanel::MysqlUtils::Check::check_mysql_password_works_or_reset(); if ( !$check_ok ) { # Case 169937, if I die here it will show like an error on the main # screen. print "Mysql is not running: $ret: $err\n"; exit; } } $dbh = Cpanel::MysqlUtils::Connect::get_dbi_handle(); } # Check to see if actions specified my @values = values %actions; my $val = 0; foreach (@values) { $val += $_; } if ($val) { my $cmds = ''; if ( $actions{'removeanon'} ) { print "Removing anonymous users ... " if $verbose; $dbh->do(qq{DELETE FROM mysql.user WHERE User='';\n}); print "Done\n" if $verbose; } if ( $actions{'removeremoteroot'} ) { print "Removing remote root login ... " if $verbose; $dbh->do(qq{DELETE FROM mysql.user WHERE User='root' AND Host!='localhost';\n}); print "Done\n" if $verbose; } if ( $actions{'removelockntmp'} ) { print "Dropping global lock tables and create tmp tables permissions ... " if $verbose; $dbh->do(qq{UPDATE mysql.user SET Lock_tables_priv='N',Create_tmp_table_priv='N' WHERE User!='root';\n}); print "Done\n" if $verbose; } if ( $actions{'removehordeallhosts'} ) { print "Removing insecure horde login ... " if $verbose; $dbh->do(qq{DELETE FROM mysql.user WHERE User='horde' AND Host='%';\n}); $dbh->do(qq{DELETE FROM mysql.db WHERE User='horde' AND Host='%';\n}); $dbh->do(qq{DELETE FROM mysql.tables_priv WHERE User='horde' AND Host='%';\n}); $dbh->do(qq{DELETE FROM mysql.columns_priv WHERE User='horde' AND Host='%';\n}); print "Done\n" if $verbose; } if ( $actions{'removehordeblankpass'} ) { print "Removing horde user entries with blank password ... " if $verbose; $dbh->do(qq{DELETE FROM mysql.user WHERE User='horde' AND Password='';\n}); print "Done\n" if $verbose; } if ( $actions{'removetestdb'} ) { print "Removing all privileges for test db ... " if $verbose; $dbh->do(qq{DELETE FROM mysql.db WHERE Db LIKE 'test%' AND User='';\n}); print "Done\n" if $verbose; } print "Flushing privileges table ... " if $verbose; $dbh->do(qq{FLUSH PRIVILEGES;\n}); print "Done.\n" if $verbose; # This needs to be last because if the db 'test' doesn't exist, then # mysql client exits. if ( $actions{'removetestdb'} ) { print "Dropping test database... " if $verbose; $dbh->do(qq{DROP DATABASE IF EXISTS test;\n}); print "Done\n" if $verbose; } }