mysqlaccess.sh
上传用户:romrleung
上传日期:2022-05-23
资源大小:18897k
文件大小:108k
- #!@PERL@
- # ****************************
- package MySQLaccess;
- #use strict;
- use File::Temp qw(tempfile tmpnam);
- use Fcntl;
- BEGIN {
- # ****************************
- # static information...
- $VERSION = "2.06, 20 Dec 2000";
- $0 =~ m%/([^/]+)$%o;
- $script = $1;
- $script = 'MySQLAccess' unless $script;
- $script_conf = "$script.conf";
- $script_log = $ENV{'HOME'}."/$script.log";
- # ****************************
- # information on MySQL
- $MYSQL = '@bindir@/mysql'; # path to mysql executable
- $SERVER = '3.21';
- $MYSQL_OPT = ' --batch --unbuffered';
- $ACCESS_DB = 'mysql'; # name of DB with grant-tables
- $ACCESS_H = 'host'; #
- $ACCESS_U = 'user'; #
- $ACCESS_D = 'db'; #
- # Add/Edit privileges
- $ACCESS_H_TMP = 'host_tmp';
- $ACCESS_U_TMP = 'user_tmp';
- $ACCESS_D_TMP = 'db_tmp';
- $ACCESS_H_BCK = 'host_backup';
- $ACCESS_U_BCK = 'user_backup';
- $ACCESS_D_BCK = 'db_backup';
- $DIFF = '/usr/bin/diff';
- $MYSQLDUMP = '@bindir@/mysqldump';
- #path to mysqldump executable
- $MYSQLADMIN= 'http://foobar.com/MySQLadmin';
- #URL of CGI for manipulating
- #the temporary grant-tables
- }
- END {
- unlink $MYSQL_CNF if defined $MYSQL_CNF and not $DEBUG;
- }
- $INFO = <<"_INFO";
- --------------------------------------------------------------------------
- mysqlaccess (Version $VERSION)
- ~~~~~~~~~~~
- Copyright (C) 1997,1998 Yves.Carlier@rug.ac.be
- University of Ghent (RUG), Belgium
- Administratieve Informatieverwerking (AIV)
- report the access-privileges for a USER from a HOST to a DB
- Many thanks go to <monty@mysql.com> and <psmith@BayNetworks.COM>
- for their suggestions, debugging and patches.
- use `$script -?' to get more information on available options.
- From version 2.0x, $script can also be used through a WEB-browser
- if it is ran as a CGI-script. (See the release-notes)
- --------------------------------------------------------------------------
- _INFO
- $OPTIONS = <<_OPTIONS;
- Usage: $script [host [user [db]]] OPTIONS
- -?, --help display this helpscreen and exit
- -v, --version print information on the program `$script'
- -u, --user=# username for logging in to the db
- -p, --password=# validate password for user
- -h, --host=# name or IP-number of the host
- -d, --db=# name of the database
- -U, --superuser=# connect as superuser
- -P, --spassword=# password for superuser
- -H, --rhost=# remote MySQL-server to connect to
- --old_server connect to old MySQL-server (before v3.21) which
- does not yet know how to handle full where clauses.
- -b, --brief single-line tabular report
- -t, --table report in table-format
- --relnotes print release-notes
- --plan print suggestions/ideas for future releases
- --howto some examples of how to run `$script'
- --debug=N enter debuglevel N (0..3)
- --copy reload temporary grant-tables from original ones
- --preview show differences in privileges after making
- changes in (temporary) grant-tables
- --commit copy grant-rules from temporary tables to grant-tables
- (!don't forget to do an mysqladmin reload)
- --rollback undo the last changes to the grant-tables.
- Note:
- + At least the user and the db must be given (even with wildcards)
- + If no host is given, `localhost' is assumed
- + Wilcards (*,?,%,_) are allowed for host, user and db, but be sure
- to escape them from your shell!! (ie type \* or '*')
- _OPTIONS
- $RELEASE = <<'_RELEASE';
-
- Release Notes:
- -------------
- 0.1-beta1: internal
- - first trial.
-
- 0.1-beta2: (1997-02-27)
- - complete rewrite of the granting-rules, based on the documentation
- found in de FAQ.
- - IP-number and name for a host are equiv.
-
- 0.1-beta3: (1997-03-10)
- - more information
- - 'localhost' and the name/ip of the local machine are now equiv.
- 0.1-beta4: (1997-03-11)
- - inform the user if he has not enough priv. to read the mysql db
- 1.0-beta1: (1997-03-12)
- suggestions by Monty:
- - connect as superuser with superpassword.
- - mysqlaccess could also notice if all tables are empty. This means
- that all user have full access!
- - It would be nice if one could optionally start mysqlaccess without
- any options just the arguments 'user db' or 'host user db', where
- host is 'localhost' if one uses only two arguments.
- 1.0-beta2: (1997-03-14)
- - bugfix: translation to reg.expr of _ and %.
- - bugfix: error in matching regular expression and string given
- by user which resulted in
- 'test_123' being matched with 'test'
- 1.0-beta3: (1997-03-14)
- - bugfix: the user-field should not be treated as a sql-regexpr,
- but as a plain string.
- - bugfix: the host-table should not be used if the host isn't empty in db
- or if the host isn't emty in user
- (Monty)
-
- 1.0-beta4: (1997-03-14)
- - bugfix: in an expression "$i = $j or $k", the '=' binds tighter than the or
- which results in problems...
- (by Monty)
- - running mysqlaccess with "perl -w" gives less warnings... ;-)
- 1.0-beta5: (1997-04-04)
- - bugfix: The table sorting was only being applied to the "user" table; all
- the tables need to be sorted. Rewrote the sort algorithm, and
- the table walk algorithm (no temp file anymore), and various
- other cleanups. I believe the access calculation is 100% correct.
- (by Paul D. Smith <psmith@baynetworks.com>)
- - Allow the debug level to be set on the cmd line with --debug=N.
- (by Paul D. Smith <psmith@baynetworks.com>)
- - More -w cleanups; should be totally -w-clean.
- (by Paul D. Smith <psmith@baynetworks.com>)
-
- 1.1-beta1: (1997-04-xx)
- 1.1-beta2: (1997-04-11)
- - new options:
- --all_users : report access-rights for all possible users
- --all_dbs : report access-rights for all possible dbs
- --all_hosts : report access-rights for all possible hosts
- --brief : as brief as possible, don't mention notes,warnings and rules
- --password : validate password for user
- - layout: long messages are wrapped on the report.
- - functionality:
- more descriptive notes and warnings
- wildcards (*,?) are allowed in the user,host and db options
- setting xxxx=* is equiv to using option --all_xxxx
- note: make sure you escape your wildcards, so they don't get
- interpreted by the shell. use * or '*'
- - bugfix: Fieldnames which should be skipped on the output can now have
- a first capital letter.
- - bugfix: any option with a '.' (eg ip-number) was interpreted as
- a wildcard-expression.
- - bugfix: When no entry was found in the db-table, the default accessrights are
- N, instead of the faulty Y in a previous version.
-
- 1.1-beta-3 : (1997-04-xx)
- 1.1-beta-4 : (1997-04-xx)
- 1.1-beta-5 : (1997-04-xx)
- 1.1 : (1997-04-28)
- - new options:
- --rhost : name of mysql-server to connect to
- --plan : print suggestions/ideas for future releases
- --relnotes : display release-notes
- --howto : display examples on how to use mysqlaccess
- --brief : single-line tabular output
- - functionality/bugfix:
- * removed options --all_users,--all_dbs,--all_hosts, which
- were redundant with the wildcard-expressions for the corresponding
- options. They made the processing of the commandline too painful
- and confusing ;-)
- (suggested by psmith)
- * redefined the option --brief, which now gives a single-line
- tabular output
- * Now we check if the right version of the mysql-client is used,
- since we might use an option not yet implemented in an
- older version (--unbuffered, since 3.0.18)
- Also the error-messages the mysql-client reports are
- better interpreted ;-)
- * Wildcards can now be given following the SQL-expression
- (%,_) and the Regular-expression (*,?) syntax.
- - speed: we now open a bidirectional pipe to the mysql-client, and keep
- it open throughout the whole run. Queries are written to,
- and the answers read from the pipe.
- (suggested by monty)
- - bugfixes:
- * the Rules were not properly reset over iterations
- * when in different tables the field-names were not identical,
- eg. Select_priv and select_priv, they were considered as
- definitions of 2 different access-rights.
- * the IP-number of a host with a name containing wildcards should
- not be searched for in Name2IP and IP2Name.
- * various other small things, pointed out by <monty> and <psmith>
- 1.2 : (1997-05-13)
- - bugfix:
- * Fixed bug in acl with anonymous user: Now if one gets accepted by the
- user table as a empty user name, the user name is set to '' when
- checking against the 'db' and 'host' tables. (Bug fixed in MySQL3.20.19)
- 1.2-1 : (1997-xx-xx)
- - bugfix:
- * hashes should be initialized with () instead of {} <psmith>
- * "my" variable $name masks earlier declaration in same scope,
- using perl 5.004 <????>
- 1.2-2 : (1997-06-10)
-
- 2.0p1-3 : (1997-10-xx)
- - new
- * packages
- * log-file for debug-output : /tmp/mysqlaccess.log
- * default values are read from a configuration file $script.conf
- first this file is looked for in the current directory; if not
- found it is looked for in /etc/
- Note that when default-values are given, these can't get overriden
- by empty (blanc) values!
- * CGI-BIN version with HTML and forms interface. Simply place the
- script in an ScriptAliased directory, make the configuration file
- available in the that directory or in /etc, and point your browser
- to the right URL.
- * copy the grant-rules to temporary tables, where you are safe to
- play with them.
- * preview changes in privileges after changing grant-rules,
- before taking them into production
- * copy the new grant-rules from the temporary tables back to the
- grant-tables.
- * Undo all changes made in the grant-tables (1-level undo).
- -new options:
- * --table : as opposite of the --brief option.
- * --copy : (re)load temporary grant-tables from original ones.
- * --preview : preview changes in privileges after changing
- some or more entries in the grant-tables.
- * --commit : copy grant-rules from temporary tables to grant-tables
- (!don't forget to do an mysqladmin reload)
- * --rollback: undo the last changes to the grant-tables.
- - bugfix:
- * if the table db is empty, mysqlaccess freezed
- (by X Zhu <X.Zhu@Bradford.ac.uk>)
- 2.0 : (1997-10-09)
- - fixed some "-w" warnings.
- - complain when certain programs and paths can't be found.
- 2.01 : (1997-12-12)
- - bugfix:
- * rules for db-table where not calculated and reported correctly.
- 2.02 : (1998-01-xx)
- - bugfix:
- * Privileges of the user-table were not AND-ed properly with the
- other privileges. (reported by monty)
- - new option:
- * --old_server: mysqlaccess will now use a full where clause when
- retrieving information from the MySQL-server. If
- you are connecting to an old server (before v3.21)
- then use the option --old_server.
- 2.03 : (1998-02-27)
- - bugfix:
- * in Host::MatchTemplate: incorrect match if host-field was left empty.
- 2.04-alpha1 : (2000-02-11)
- Closes vulnerability due to former implementation requiring passwords
- to be passed on the command line.
- - functionality
- Option values for --password -p -spassword -P may now be omitted from
- command line, in which case the values will be prompted for.
- (fix supplied by Steve Harvey <sgh@vex.net>)
- 2.05: (2000-02-17) Monty
- Moved the log file from /tmp to ~
- 2.06: Don't print '+++USING FULL WHERE CLAUSE+++'
- _RELEASE
- $TODO = <<_TODO;
- Plans:
- -----
- -a full where clause is use now. How can we handle older servers?
- -add some more functionality for DNS.
- -select the warnings more carefuly.
- >> I think that the warnings should either be enhanced to _really_
- >> understand and report real problems accurately, or restricted to
- >> only printing things that it knows with 100% certainty. <psmith)
- >> Why do I have both '%' and 'any_other_host' in there? Isn't that
- >> the same thing? I think it's because I have an actual host '%' in
- >> one of my tables. Probably the script should catch that and not
- >> duplicate output. <psmith>
- _TODO
- # From the FAQ: the Grant-algorithm
- # ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- # The host table is mainly to maintain a list of "secure" servers.
- # At TCX hosts contain a list of all machines on local network. These are granted
- # all privileges.
- # Technically the user grant is calculated by:
- #
- # 1.First sort all entries by host by putting host without wildcards first,
- # after this host with wildcards and entries with host = ".
- # Under each host sort user by the same criterias.
- # 2.Get grant for user from the "db" table.
- # 3.If hostname is "empty" for the found entry, AND the privileges with
- # the privileges for the host in "host" table.
- # (Remove all which is not "Y" in both)
- # 4.OR (add) the privileges for the user from the "user" table.
- # (add all privileges which is "Y" in "user")
- #
- # When matching, use the first found match.
- #
- # -----------------------------------------------------------------------------------
- $HOWTO = <<_HOWTO;
- Examples of how to call $script:
- ~~~~~~~~
- 1)Calling $script with 2 arguments:
- $ $script root mysql
- ->report rights of user root logged on at the local host in db mysql
- Access-rights
- for USER 'root', from HOST 'localhost', to DB 'mysql'
- +-----------------+---+ +-----------------+---+
- | select_priv | Y | | drop_priv | Y |
- | insert_priv | Y | | reload_priv | Y |
- | update_priv | Y | | shutdown_priv | Y |
- | delete_priv | Y | | process_priv | Y |
- | create_priv | Y | | file_priv | Y |
- +-----------------+---+ +-----------------+---+
- BEWARE: Everybody can access your DB as user 'root'
- : WITHOUT supplying a password. Be very careful about it!!
- The following rules are used:
- db : 'No matching rule'
- host : 'Not processed: host-field is not empty in db-table.'
- user : 'localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'
- 2)Calling $script with 3 arguments:
- $ $script foo.bar nobody Foo
- ->report rights of user root logged in at machine foobar to db Foo
- Access-rights
- for USER 'nobody', from HOST 'foo.bar', to DB 'Foo'
- +-----------------+---+ +-----------------+---+
- | select_priv | Y | | drop_priv | N |
- | insert_priv | Y | | reload_priv | N |
- | update_priv | Y | | shutdown_priv | N |
- | delete_priv | Y | | process_priv | N |
- | create_priv | N | | file_priv | N |
- +-----------------+---+ +-----------------+---+
- BEWARE: Everybody can access your DB as user 'nobody'
- : WITHOUT supplying a password. Be very careful about it!!
- The following rules are used:
- db : 'foo.bar','Foo','nobody','Y','Y','Y','N','N','N'
- host : 'Not processed: host-field is not empty in db-table.'
- user : 'foo.bar','nobody','','N','N','N','Y','N','N','N','N','N','N'
- 3)Using wildcards:
- $ $script \* nobody Foo --brief
- ->report access-rights of user nobody from all machines to db Foo,
- and use a matrix-report.
- Sel Ins Upd Del Crea Drop Reld Shut Proc File Host,User,DB
- ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --------------------
- Y Y Y Y N N N N N N localhost,nobody,Foo
- N N N N N N N N N N %,nobody,Foo
- N N N N N N N N N N any_other_host,nobody,Foo
- _HOWTO
- # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
- # START OF THE PROGRAM #
- # +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
- use Getopt::Long;
- use Sys::Hostname;
- use IPC::Open3;
- # ****************************
- # debugging flag
- # can be set to 0,1,2,3
- # a higher value gives more info
- # ! this can also be set on the command-line
- $DEBUG = 0;
- # ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>8
- # Normaly nothing should be changed beneeth this line
- # ****************************
- # no caching on STDOUT
- $|=1;
- $MYSQL_CNF = tmpnam();
- %MYSQL_CNF = (client => { },
- mysql => { },
- mysqldump => { },
- );
- $NEW_USER = 'ANY_NEW_USER';
- $NEW_DB = 'ANY_NEW_DB' ;
- # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
- # mysqlaccess: #
- # ~~~~~~~~~~~ #
- # Lets get to it, #
- # and start the program by processing the parameters #
- # %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
- ($CMD,$CGI) = GetMode();
- # ****************************
- # the copyright message should
- # always be printed (once)
- MySQLaccess::Report::Print_Header();
- # *****************************
- # Read configuration-file
- MySQLaccess::Debug::Print(1, "Reading configuration file...");
- if (-f "./$script_conf") {
- require "./$script_conf";
- }
- elsif (-f "/etc/$script_conf") {
- require "/etc/$script_conf";
- }
- # ****************************
- # Read in all parameters
- if ($MySQLaccess::CMD) { #command-line version
- # ----------------------------
- # Get options from commandline
- $Getopt::Long::ignorecase=0; #case sensitive options
- if ( grep(/-?/,@ARGV) ) { MySQLaccess::Report::Print_Usage(); exit 0; }
- GetOptions("help" => $Param{'help'}
- ,"host|h=s" => $Param{'host'}
- ,"user|u=s" => $Param{'user'}
- ,"password|p:s" => $Param{'password'}
- ,"db|d=s" => $Param{'db'}
- ,"superuser|U=s" => $Param{'superuser'}
- ,"spassword|P:s" => $Param{'spassword'}
- ,"rhost|H=s" => $Param{'rhost'}
- ,"old_server" => $Param{'old_server'}
- ,"debug=i" => $Param{'DEBUG'}
- ,"brief|b" => $Param{'brief'}
- ,"table|t" => $Param{'table'}
- ,"relnotes" => $Param{'relnotes'}
- ,"plan" => $Param{'plan'}
- ,"howto" => $Param{'howto'}
- ,"version|v" => $Param{'version'}
- ,"preview" => $Param{'preview'}
- ,"copy" => $Param{'copy'}
- ,"commit" => $Param{'commit'}
- ,'rollback' => $Param{'rollback'}
- );
- # -----------------------------
- # set DEBUG
- $DEBUG = $Param{'DEBUG'} if ($Param{'DEBUG'}>=$DEBUG);
- # -----------------------------
- # check for things which aren't
- # declared as options:
- # 2 arguments: (user,db) -> ('localhost','user','db')
- if ($#ARGV == 1) {
- MySQLaccess::Debug::Print(2,"$script called with 2 arguments:");
- $Param{'host'} = $Param{'host'} || 'localhost';
- $Param{'user'} = $ARGV[0] || $Param{'user'};
- $Param{'db'} = $ARGV[1] || $Param{'db'};
- }
- # 3 arguments: (host,user,db)
- if ($#ARGV == 2) {
- MySQLaccess::Debug::Print(2,"$script called with 3 arguments:");
- $Param{'host'} = $ARGV[0] || $Param{'host'};
- $Param{'user'} = $ARGV[1] || $Param{'user'};
- $Param{'db'} = $ARGV[2] || $Param{'db'};
- }
- # -------------------------------------
- # prompt for user password if requested
- if ( defined($Param{'password'}) && length($Param{'password'}) == 0 ) {
- $Param{'password'} = PromptPass(
- "Password for MySQL user $Param{'user'}: ");
- }
- }
- if ($MySQLaccess::CGI) { #CGI-version
- require CGI;
- $Q = new CGI;
- $Param{'help'} = $Q->param('help') ;
- $Param{'host'} = $Q->param('host') || $Q->param('h') || $Param{'host'};
- $Param{'user'} = $Q->param('user') || $Q->param('u') || $Param{'user'};
- $Param{'db'} = $Q->param('db') || $Q->param('d') || $Param{'db'};
- $Param{'password'} = $Q->param('password') || $Q->param('p') || $Param{'password'};
- $Param{'superuser'} = $Q->param('superuser') || $Q->param('U') || $Param{'superuser'};
- $Param{'spassword'} = $Q->param('spassword') || $Q->param('P') || $Param{'spassword'};
- $Param{'rhost'} = $Q->param('rhost') || $Q->param('H') || $Param{'rhost'};
- $Param{'old_server'}= $Q->param('old_server')|| $Param{'old_server'};
- $Param{'debug'} = $Q->param('debug') || $Param{'debug'};
- $Param{'brief'} = $Q->param('brief') || $Param{'brief'};
- $Param{'table'} = $Q->param('table') || $Param{'table'};
- $Param{'relnotes'} = $Q->param('relnotes');
- $Param{'plan'} = $Q->param('plan');
- $Param{'howto'} = $Q->param('howto');
- $Param{'version'} = $Q->param('version') ? $Q->param('version') : $Q->param('v');
- $Param{'edit'} = $Q->param('edit');
- $Param{'preview'} = $Q->param('preview');
- $Param{'copy'} = $Q->param('copy');
- $Param{'commit'} = $Q->param('commit');
- $Param{'rollback'} = $Q->param('rollback');
- # -----------------------------
- # set DEBUG
- $DEBUG = $Q->param('debug') if ($Q->param('debug')>=$DEBUG);
- }
- # ----------------------
- # brief and table-format
- # exclude each-other
- # table-format is prefered
- if (defined($Param{'table'})) { undef($Param{'brief'}); }
- if (defined($Param{'preview'}) or
- defined($Param{'copy'}) or
- defined($Param{'commit'}) or
- defined($Param{'rollback'}) ) { $Param{'edit'}='on'; }
- # ----------------------
- # if no host is given
- # assume we mean 'localhost'
- if (!defined($Param{'host'})) { $Param{'host'}='localhost'; }
- # ----------------------
- # perform some checks
- # -> eliminate 'broken pipe' error
- push(@MySQLaccess::Grant::Error,'not_found_mysql') if !(-x $MYSQL);
- push(@MySQLaccess::Grant::Error,'not_found_diff') if !(-x $DIFF);
- push(@MySQLaccess::Grant::Error,'not_found_mysqldump') if !(-x $MYSQLDUMP);
- if (@MySQLaccess::Grant::Error) {
- MySQLaccess::Report::Print_Error_Messages() ;
- exit 0;
- }
- #-----------------------
- # get info/help if necc.
- $print_usage=1;
- if ( defined($Param{'version'}) ) {
- MySQLaccess::Report::Print_Version();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- # exit 0;
- }
- if ( defined($Param{'relnotes'}) ) {
- MySQLaccess::Report::Print_Relnotes();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- # exit 0;
- }
- if ( defined($Param{'plan'}) ) {
- MySQLaccess::Report::Print_Plans();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- # exit 0;
- }
- if ( defined($Param{'howto'}) ) {
- MySQLaccess::Report::Print_HowTo();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- # exit 0;
- }
- # -----------------------------
- # generate a help-screen in CMD-mode
- # or a blanc form in CGI-mode
- if ( defined($Param{'help'})
- or !defined($Param{'user'})
- or !defined($Param{'host'})
- or !defined($Param{'db'})
- ) {
- push(@MySQLaccess::Grant::Error,'user_required') unless defined($Param{'user'});
- push(@MySQLaccess::Grant::Error,'db_required') unless defined($Param{'db'});
- push(@MySQLaccess::Grant::Error,'host_required') unless defined($Param{'host'});
- MySQLaccess::Report::Print_Usage() if $print_usage;
- exit 0;
- }
- # ----------------------------
- # get hostname and local-ip
- # for localhost
- $localhost = MySQLaccess::Host::LocalHost();
- $local_ip = MySQLaccess::Host::Name2IP($localhost);
- $MySQLaccess::Host::localhost = MySQLaccess::Host::LocalHost();
- $MySQLaccess::Host::local_ip = MySQLaccess::Host::Name2IP($localhost);
- MySQLaccess::Debug::Print(3, "localhost name=$localhost, ip=$local_ip");
- #-----------------------------------
- # version of MySQL-server to connect
- # to determine use of full where clause
- $MySQLaccess::Host::SERVER = $Param{'old_server'} ? '3.20' : $SERVER;
- #---------------------------------
- # create the config file for mysql and mysqldump
- # to avoid passing authentication info on the command line
- #
- MergeConfigFiles();
- die "Unsafe config file found: $unsafeConfign" if $unsafeConfig;
- if (defined($Param{'superuser'})) {
- $MYSQL_CNF{'mysql'}{'user'} = $Param{'superuser'};
- $MYSQL_CNF{'mysqldump'}{'user'} = $Param{'superuser'};
- }
- if (defined($Param{'spassword'})) {
- if ( $CMD && length($Param{'spassword'}) == 0 ) {
- $Param{'spassword'} =
- PromptPass("Password for MySQL superuser $Param{'superuser'}: ");
- }
- if ( length($Param{'spassword'}) > 0 ) {
- $MYSQL_CNF{'mysql'}{'password'} = $Param{'spassword'};
- $MYSQL_CNF{'mysqldump'}{'password'} = $Param{'spassword'};
- }
- }
- WriteTempConfigFile();
- #---------------------------------
- # Inform user if he has not enough
- # privileges to read the access-db
- if ( $nerror=MySQLaccess::DB::OpenConnection() ) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- }
- # -----------------------
- # Read MySQL ACL-files
- if ($nerror=MySQLaccess::Grant::ReadTables()) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- };
- if ($Param{'edit'} and $nerror=MySQLaccess::Grant::ReadTables('tmp')) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- }
- #---------------------------------
- # reload temporay grant-tables
- # with data from original ones
- if ( defined($Param{'copy'}) ) {
- $nerror=MySQLaccess::DB::LoadTmpTables();
- if ($nerror) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- }
- my $msg = "The grant-rules are copied from the grant-tables ton"
- . "the temporary tables.";
- MySQLaccess::Report::Print_Message([$msg]);
- # MySQLaccess::Report::Print_Footer();
- # MySQLaccess::DB::CloseConnection();
- # exit 0;
- }
- #---------------------------------
- # preview result of changes in the
- # grant-tables
- if ( defined($Param{'preview'}) ) {
- $aref=MySQLaccess::Grant::Diff_Privileges();
- MySQLaccess::Report::Print_Diff_ACL($aref);
- # MySQLaccess::Report::Print_Footer();
- # MySQLaccess::DB::CloseConnection();
- # exit 0;
- }
- #---------------------------------
- # reload grant-tables
- # with data from temporary tables
- if ( defined($Param{'commit'}) ) {
- if ($nerror = MySQLaccess::DB::CommitGrantTables()) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- }
- my $msg = "The grant-rules have been copied from the temporary tablesn"
- . "to the grant-tables.";
- my $msg1= "Don't forget to do an 'mysqladmin reload' before thesen"
- . "changes take effect.";
- my $msg2= "A backup-version of your original grant-rules are saved in then"
- . "backup-tables, so you can always perform a 1-level rollback.";
- MySQLaccess::Report::Print_Message([$msg,$msg1,$msg2]);
- # MySQLaccess::Report::Print_Footer();
- # MySQLaccess::DB::CloseConnection();
- # exit 0;
- }
- #---------------------------------
- # restore previous grant-rules
- # with data from backup tables
- if ( defined($Param{'rollback'}) ) {
- if ($nerror = MySQLaccess::DB::RollbackGrantTables()) {
- MySQLaccess::Report::Print_Error_Access($nerror);
- exit 0;
- }
- my $msg = "The old grant-rules have been copied back from the backup tablesn"
- . "to the grant-tables.";
- my $msg1= "Don't forget to do an 'mysqladmin reload' before thesen"
- . "changes take effect.";
- MySQLaccess::Report::Print_Message([$msg,$msg1]);
- # MySQLaccess::Report::Print_Footer();
- # MySQLaccess::DB::CloseConnection();
- # exit 0;
- }
- #----------------------------------
- # show edit-taskbar
- if ( defined($Param{'edit'})) {
- if ($MySQLaccess::CGI ) {
- MySQLaccess::Report::Print_Edit();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- }
- else {
- MySQLaccess::Report::Print_Edit();
- $print_usage=0;
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- }
- }
- # -----------------------------
- # Build list of users,dbs,hosts
- # to process...
- @all_dbs = @{MySQLaccess::DB::Get_All_dbs($Param{'db'})};
- @all_users = @{MySQLaccess::DB::Get_All_users($Param{'user'})};
- @all_hosts = @{MySQLaccess::DB::Get_All_hosts($Param{'host'})};
- #if EDIT-mode
- #@all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs($Param{'db'},'tmp')};
- #@all_users_tmp = @{MySQLaccess::DB::Get_All_users($Param{'user'},'tmp')};
- #@all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts($Param{'host'},'tmp')};
- # -----------------------------
- # Report access-rights for each
- # tuple (host,user,db)
- #$headers=0;
- my %Access = ();
- foreach $host (@all_hosts) {
- foreach $user (@all_users) {
- foreach $db (@all_dbs) {
- MySQLaccess::Grant::Initialize();
- %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db);
- MySQLaccess::Report::Print_Access_rights($host,$user,$db,%Access);
- }
- }
- }
- # -----------------------------
- # End script
- MySQLaccess::Report::Print_Footer();
- MySQLaccess::DB::CloseConnection();
- exit 0;
- #############################################################
- # FUNCTIONS #
- ###############
- sub GetMode {
- my $cmd=0;
- my $cgi=0;
- if (defined($ENV{'HTTP_HOST'})) { $cmd=0; $cgi=1; }
- else { $cmd=1; $cgi=0; }
- return ($cmd,$cgi);
- }
- # ================================
- # sub PromptPass
- # prompt tty for a password
- # ================================
- sub PromptPass {
- my ($prompt) = @_;
- my $password;
- $ENV{PATH} = "/bin:/usr/bin";
- $ENV{IFS} = " tn";
- $ENV{SHELL} = "/bin/sh";
- system "stty -echo";
- print $prompt;
- chomp($password = <STDIN>);
- print "n";
- system "stty echo";
- $password;
- }
- # =================================
- # sub CheckUnsafeFile
- # tell if a config file containing a password is unsafe
- # =================================
- sub CheckUnsafeFile {
- my ($fname) = @_;
- my ($dev, $ino, $mode, $nlink,
- $uid, $gid, $rdev, $size,
- $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
- if ( $uid != $< ) { # unsafe if owned by other than current user
- return 1;
- }
- if ( $mode & 066 ) { # unsafe if accessible by other
- return 1;
- }
- $fname =~ s#/[^/]+$##;
- if ( (length $fname) > 0 ) {
- return CheckUnsafeDir($fname);
- }
- return 0;
- }
- # =================================
- # sub CheckUnsafeDir
- # tell if a directory is unsafe
- # =================================
- sub CheckUnsafeDir {
- my ($fname) = @_;
- my ($dev, $ino, $mode, $nlink,
- $uid, $gid, $rdev, $size,
- $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
- # not owned by me or root
- if ( ($uid != $<) && ($uid != 0) ) {
- return 1;
- }
- if ( $mode & 022 ) { # unsafe if writable by other
- return 1 unless $mode & 01000; # but sticky bit ok
- }
- $fname =~ s#/[^/]+$##;
- if ( (length $fname) > 0 ) {
- return CheckUnsafeDir($fname);
- }
- return 0;
- }
- # =================================
- # sub MergeConfigFile
- # merge data from .cnf file
- # =================================
- sub MergeConfigFile {
- my ($fname) = @_;
- my ($group, $item, $value);
- if ( open CNF, $fname ) {
- while (<CNF>) {
- s/^s+//;
- next if /^[#;]/;
- if ( /[s*(w+)s*]/ ) {
- $group = $1;
- $group =~ tr/A-Z/a-z/;
- if ( !exists $MYSQL_CNF{$group} ) {
- undef $group;
- }
- } elsif ( defined $group ) {
- ($item, $value) = /((?:w|-)+)s*=s*(S+)/;
- # don't unquote backslashes as we just write it back out
- if ( defined $item ) {
- if ( $item =~ /^password$/ ) {
- if ( CheckUnsafeFile($fname) ) {
- $unsafeConfig = $fname;
- }
- }
- if ( $group eq 'client' ) {
- $MYSQL_CNF{'mysql'}{$item} = $value;
- $MYSQL_CNF{'mysqldump'}{$item} = $value;
- } else {
- $MYSQL_CNF{$group}{$item} = $value;
- }
- }
- }
- }
- close(CNF);
- }
- }
- # =================================
- # sub MergeConfigFiles
- # merge options from config files
- # NOTE: really should do two separate merges for each
- # client to exactly duplicate order of resulting argument lists
- # =================================
- sub MergeConfigFiles {
- my ($name,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwuid $<;
- MergeConfigFile("/etc/my.cnf");
- MergeConfigFile("$dir/.my.cnf");
- }
- # =================================
- # sub WriteTempConfigFile
- # write
- # =================================
- sub WriteTempConfigFile {
- sysopen CNFFILE, $MYSQL_CNF, O_RDWR|O_CREAT|O_EXCL, 0700
- or die "sysopen $MYSQL_CNF: $!";
-
- # groups may be in any order, generic groups such as [client] assumed
- # here to be empty
- foreach $group (keys %MYSQL_CNF) {
- print CNFFILE "[$group]n";
- foreach $item (keys %{$MYSQL_CNF{$group}}) {
- if ( defined $MYSQL_CNF{$group}{$item} ) {
- print CNFFILE "$item=$MYSQL_CNF{$group}{$item}n";
- } else {
- print CNFFILE "$itemn";
- }
- }
- print CNFFILE "n";
- }
- close(CNFFILE);
- }
- ######################################################################
- package MySQLaccess::DB;
- ###########
- BEGIN {
- $DEBUG = 2;
- $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
- # Error-messages from the MySQL client
- %ACCESS_ERR= ('Access_denied' => 'Access denied'
- ,'Dbaccess_denied' => 'Access to database denied'
- ,'Unrecognized_option' => 'unrecognized option'
- ,'Unknown_table' => "Can't find file:"
- ,'unknown_error' => '^ERROR:'
- );
- }
- # ######################################
- # Connecting to the MYSQL DB
- # ======================================
- # sub OpenConnection
- # Open an connection to the mysql-db
- # questions to MYSQL_Q
- # answers from MYSQL_A
- # ======================================
- sub OpenConnection {
- my $pid;
- MySQLaccess::Debug::Print(2,"OpenConnection:");
- # check path to mysql-client executable
- if (! -f $MySQLaccess::MYSQL) {
- if ($MySQLaccess::CMD) { die "Could not find MySQL-client '$MySQLaccess::MYSQL'"; }
- if ($MySQLaccess::CGI) {
- print "<center>n<font color=Red>n";
- print "ERROR: Could not find MySQL-client '$MySQLaccess::MYSQL'";
- print "</center>n</font>n";
- exit 0;
- }
- }
- # path to mysql executable
- my $connect = "$MySQLaccess::MYSQL --defaults-file=$MySQLaccess::MYSQL_CNF";
- $connect .= " $MySQLaccess::MYSQL_OPT";
- # superuser, spassword transmitted via defaults-file
- if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
- # other options??
- # grant-database
- $connect .= " $MySQLaccess::ACCESS_DB";
- # open connection (not using /bin/sh -c)
- MySQLaccess::Debug::Print(2,"Connecting to: $connect");
- $pid=IPC::Open3::open3(*MYSQL_Q,*MYSQL_A,"",split /s+/,$connect);
- MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
-
- # check connection
- print MYSQL_Q "select 'ok';n";
- $answer = <MYSQL_A>; #answer from mysql
- MySQLaccess::Debug::Print(2,"Answer: $answern");
- foreach $nerror (sort(keys(%ACCESS_ERR))) {
- MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
- if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
- MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
- return $nerror;
- }
- }
- if (0) {
- # check server-version
- print MYSQL_Q "select 'ok';n";
- $answer = <MYSQL_A>; #answer from mysql
- MySQLaccess::Debug::Print(2,"Answer: $answern");
- foreach $nerror (sort(keys(%ACCESS_ERR))) {
- MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
- if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
- MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
- return $nerror;
- }
- }
- }
- my $skip=<MYSQL_A>;
- return 0;
- }
- # ======================================
- # sub CloseConnection
- # Close the connection to the mysql-db
- # ======================================
- sub CloseConnection {
- close MYSQL_Q;
- close MYSQL_A;
- }
- # ===========================================================
- # sub CreateTable($table)
- # Create temporary/backup table
- # ===========================================================
- sub CreateTable {
- my $pid;
- my ($table,$force) = @_;
- my %tables = ( $MySQLaccess::ACCESS_U_TMP => $MySQLaccess::ACCESS_U,
- $MySQLaccess::ACCESS_H_TMP => $MySQLaccess::ACCESS_H,
- $MySQLaccess::ACCESS_D_TMP => $MySQLaccess::ACCESS_D,
- $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
- $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
- $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
- $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
- $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
- $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
- );
- my $tbl;
- my $query="";
- my $delim;
- my $skip;
- my $create;
- my @known_tables=();
- # print STDERR "CreateTable($table)n";
- MySQLaccess::Debug::Print(1,"CreateTable($table):");
- ## error-handling
- return 'Unknown_table' unless defined($tables{$table});
- ## build list of known/existing tables;
- ## if 'force' existing table is dropped first
- if (defined($force) and $force) {
- @known_tables = Show_Tables();
- if (grep(/^$table$/,@known_tables)) {
- $query = "DROP TABLE $table;";
- }
- }
- ## path to mysqldump executable
- my $connect = $MySQLaccess::MYSQLDUMP;
- $connect .= " --defaults-file=$MySQLaccess::MYSQL_CNF --no-data";
- # superuser, spassword transmitted via defaults-file
- if (defined($MySQLaccess::Param{'rhost'})) { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
- $connect .= " $MySQLaccess::ACCESS_DB";
- $connect .= " $tables{$table}";
- ## get creation-data for original table
- $create = '';
- my $mysqldump = $connect;
- $mysqldump =~ s/ $TABLE / $tbl /;
- # open connection (not using /bin/sh -c)
- MySQLaccess::Debug::Print(2,"Connecting to: $connect");
- $pid=IPC::Open3::open3(*DONTCARE,*CREATE,"",split /s+/,$mysqldump);
- MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
- #open(CREATE,"$mysqldump");
- @create = <CREATE>;
- $create = "@create";
- foreach $nerror (sort(keys(%ACCESS_ERR))) {
- MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
- if (grep(/$ACCESS_ERR{$nerror}/i,$create)) {
- MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
- return $nerror;
- }
- }
- close(CREATE);
- close(DONTCARE);
- ## manipulate result for creation-data for temporary table
- $create =~ s/CREATE TABLE $tables{$table} (/CREATE TABLE $table (/;
- ## recreate temporary table
- $query .= "$createn";
- $query .= "select 'ok';";
- ## execute query
- print MYSQL_Q "$queryn";
- # print STDERR $query;
- $answer = <MYSQL_A>; #answer from mysql
- # print STDERR "A>",$answer;
- MySQLaccess::Debug::Print(2,"Answer: $answern");
- foreach $nerror (sort(keys(%ACCESS_ERR))) {
- # print STDERR "->$nerror?";
- MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
- if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
- # print STDERR "Yes!";
- MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
- return $nerror;
- }
- }
- $delim = <MYSQL_A>; # read header
- if ($delim ne "okn") {
- while (($line=<MYSQL_A>) ne "okn")
- { MySQLaccess::Debug::Print(3," A> $line"); }
- $skip = <MYSQL_A>; # skip result 'ok'
- }
- # print STDERR "CreateTable donen";
- return 0;
- }
- # ===========================================================
- # sub CopyTable()
- # Copy the structure and the data of a table to another table
- # ===========================================================
- sub CopyTable {
- my ($from,$to,$force) = @_;
- my @known_tables = Show_Tables();
- my $query = "";
- my $nerror= 0;
- my $skip;
- # print STDERR "CopyTable($from,$to)n";
- MySQLaccess::Debug::Print(1,"MySQLaccess::DB::CopyTable($from,$to)");
- ## error-handling
- if (!grep(/^$from$/,@known_tables)) { return 'Unknown_table'; }
- ## copy structure
- ## if forced
- if (defined($force) and $force) {
- return $nerror if ($nerror=CreateTable($to,$force));
- # print STDERR "Structure copiedn";
- }
- ## copy data
- $query .= "DELETE FROM $to;";
- $query .= "INSERT INTO $to SELECT * FROM $from;";
- $query .= "SELECT 'ok';n";
- MySQLaccess::Debug::Print(2,"Query: $query");
-
- ## execute query
- print MYSQL_Q "$queryn";
- # print STDERR $query;
- ## check for errors...
- my $answer = <MYSQL_A>; #answer from mysql
- # print STDERR $answer;
- MySQLaccess::Debug::Print(2,"Answer: $answern");
- foreach $nerror (sort(keys(%ACCESS_ERR))) {
- MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
- if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) {
- MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
- return $nerror;
- }
- }
- my $delim = <MYSQL_A>; # read header
- # print STDERR $delim;
- if ($delim ne "okn") {
- while (($line=<MYSQL_A>) ne "okn")
- { MySQLaccess::Debug::Print(3," A> $line"); }
- $skip = <MYSQL_A>; # skip result 'ok'
- }
- return 0;
- }
- # ===========================================================
- # sub LoadTmpTables()
- # (Re)load temporary tables with entries of ACL-tables
- # ===========================================================
- sub LoadTmpTables {
- my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
- $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
- $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
- );
- my $tbl;
- my $nerror;
-
- # print STDERR "LoadTmpTables:n";
- MySQLaccess::Debug::Print(1,"LoadTmpTables():");
- foreach $tbl (keys(%tables)) {
- # print STDERR "$tbl -> $tables{$tbl}n";
- MySQLaccess::Debug::Print(2,"Loading table $tbl -> $tables{$tbl}.");
- return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
- }
- return 0;
- }
- # ===========================================================
- # sub BackupGrantTables()
- # Make a backup of the original grant-tables
- # ===========================================================
- sub BackupGrantTables {
- my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
- $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
- $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
- );
- my $tbl;
- my $nerror;
-
- # print STDERR "BackupGrantTables:n";
- MySQLaccess::Debug::Print(1,"BackupGrantTables():");
- foreach $tbl (keys(%tables)) {
- # print STDERR "$tbl -> $tables{$tbl}n";
- MySQLaccess::Debug::Print(2,"Backup table $tbl -> $tables{$tbl}.");
- return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
- }
- return 0;
- }
- # ===========================================================
- # sub RollbackGrantTables()
- # Rollback the backup of the grant-tables
- # ===========================================================
- sub RollbackGrantTables {
- my %tables = ( $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
- $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
- $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
- );
- my $tbl;
- my $nerror;
-
- # print STDERR "RollbackGrantTables:n";
- MySQLaccess::Debug::Print(1,"RollbackGrantTables():");
- foreach $tbl (keys(%tables)) {
- # print STDERR "$tbl -> $tables{$tbl}n";
- MySQLaccess::Debug::Print(2,"Rollback table $tbl -> $tables{$tbl}.");
- return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
- }
- return 0;
- }
- # ===========================================================
- # sub CommitGrantTables()
- # Copy grant-rules from temporary tables to the ACL-tables
- # ===========================================================
- sub CommitGrantTables {
- my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
- $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
- $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
- );
- my $tbl;
- my $query;
- my $delim;
- my $skip;
- my $create;
- print STDERR "CommitGrantTables()n";
- MySQLaccess::Debug::Print(1,"CommitGrantTables():");
-
- ## Make backup of original grant-tables
- MySQLaccess::Debug::Print(2,"Making backup of original grant-tables...");
- BackupGrantTables();
- ## Copy data from temporay tables to grant-tables
- foreach $tbl (keys(%tables)) {
- print STDERR "$tbl -> $tables{$tbl}n";
- MySQLaccess::Debug::Print(2,"Loading data $tables{$tbl} -> $tbl.");
- return $nerror if ($nerror=CopyTable($tables{$tbl},$tbl));
- }
- return 0;
- }
- # ===========================================================
- # sub Show_Fields($table):
- # return (a reference to) a hash which holds the names
- # of all relevant grant-fields, with their index in the record,
- # and (a reference to) an array which holds the fieldnames.
- # ===========================================================
- sub Show_Fields {
- my ($table) = @_;
- my %skip = ('host' => [0,1]
- ,'user' => [0,1,2]
- ,'db' => [0,1,2]
- );
- my %Struct = ();
- my @Struct = ();
- my $query = "show fields from $table;select 'ok';n";
- my $i=0;
- my $line;
- #print STDERR $query;
- MySQLaccess::Debug::Print(1,"Show_Fields($table):");
- MySQLaccess::Debug::Print(2,"SQL: $query");
- print MYSQL_Q "$query";
- my $skip = <MYSQL_A>; #skip header
- while (($line=<MYSQL_A>) ne "okn")
- {
- #print STDERR ">",$line;
- chop($line);
- MySQLaccess::Debug::Print(2," $table>: $line");
- my ($field,$type,$null,$key,$default,$extra) = split(' ',$line);
- $field = ucfirst($field);
- MySQLaccess::Debug::Print(3, " <split: $field - $type - $null - $key - $default - $extra");
- if (! grep(/$i/,@{$skip{$table}}) ){
- $Struct{$field} = $i; #hash
- push(@Struct,$field); #array
- MySQLaccess::Debug::Print(3," ==> added column[$i]: $field ($Struct{$field})");
- }
- else {
- MySQLaccess::Debug::Print(3," ==> skipped column[$i], value=[$field]");
- }
- $i++;
- }
- $skip=<MYSQL_A>; # Get ok row (found already ok header)
- MySQLaccess::Debug::Print(2, "Array:");
- foreach $field (@Struct) { MySQLaccess::Debug::Print(2,"+ $field"); }
- MySQLaccess::Debug::Print(2,"Hash:");
- foreach $field (keys(%Struct)) { MySQLaccess::Debug::Print(2,"+ $field -> $Struct{$field}"); }
- return (%Struct,@Struct);
- }
- # ===========================================================
- # sub Show_Tables():
- # return (a reference to) an array which holds all
- # known tables.
- # ===========================================================
- sub Show_Tables {
- my @Tables = ();
- my $query = "show tables;select 'ok';n";
- my $i=0;
- my $line;
- MySQLaccess::Debug::Print(1,"Show_Tables():");
- MySQLaccess::Debug::Print(2,"SQL: $query");
- print MYSQL_Q "$query";
- my $skip = <MYSQL_A>; #skip header
- while (($line=<MYSQL_A>) ne "okn")
- {
- chop($line);
- push(@Tables,$line); #array
- MySQLaccess::Debug::Print(3," ==> added table: $line");
- }
- $skip=<MYSQL_A>; # Get ok row (found already ok header)
- MySQLaccess::Debug::Print(2, "Array:");
- foreach $tbl (@Tables) { MySQLaccess::Debug::Print(2,"+ $tbl"); }
- return @Tables;
- }
- # ======================================
- # sub Validate_Password($passwd,$host,$user,$encpw)
- # Validate the given password
- # for user '$user'
- # connecting from host '$host'
- # ======================================
- sub Validate_Password {
- my ($password,$host,$user,$encpw) = @_;
- my $valid=0;
- MySQLaccess::Debug::Print(1,"Validate_Password($password,$host,$user,$encpw)");
- my $sql = "select host,user,password from user having "
- ."host='$host' and user='$user' and password='$encpw' "
- ."and password=PASSWORD('$password');n";
- $sql .= "select 'ok';n";
- MySQLaccess::Debug::Print(2,"SQL = $sql");
- print MYSQL_Q "$sql";
-
- # if password is valid, at least 1 row returns before we read 'ok'
- while ( ($line=<MYSQL_A>) ne "okn") {
- MySQLaccess::Debug::Print(2," A> $line");
- $valid = defined($line);
- }
- my $skip = <MYSQL_A>; # read 'ok'
- return $valid;
- }
- # ==========================================================
- # sub Sort_fields: (rewritten by psmith)
- # Build the query for an ordered list of entries
- # ==========================================================
- sub Sort_fields {
- my ($start, $end, $sofar, $this, @rest) = (@_);
- my @where = ("((FIELD not like '\%') AND (FIELD <> ''))",
- "((FIELD like '%\%%') OR (FIELD like '%\_%'))",
- "(FIELD = '')");
- my $res = '';
- $this or return ("$start $sofar $end");
- $sofar .= ' AND ' if $sofar;
- foreach $w (@where) {
- my $f = $w;
- $f =~ s/FIELD/$this/g;
- $res .= Sort_fields($start, $end, "$sofar$f", @rest);
- }
- return ($res);
- }
- # ===========================================================
- # sub Sort_table: (rewritten by psmith)
- # return all entries in the given table,
- # in an ordered fashion
- # ===========================================================
- sub Sort_table {
- my ($tbl, @order) = @_;
- my @res=();
- # as long as there's no full where clause (Distrib 3.20)...
- # use having :-(
- # NOTE: this clause WILL NOT work on 3.21, because of the
- # order of 'ORDER BY' and 'HAVING'
- my $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl ";
- $start .= 'ORDER BY ' . join(',', @order) ." HAVING ";
- my $end = ";n";
- # server version 3.21 has a full where clause :-)
- if ($MySQLaccess::Host::SERVER >= '3.21') {
- # print "+++USING FULL WHERE CLAUSE+++n";
- $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl WHERE ";
- $end = ' ORDER BY ' . join(',', @order) . ";n";
- }
- MySQLaccess::Debug::Print(1,"Sort_table():");
- MySQLaccess::Debug::Print(2,"Sorting table $tbl by `@order'");
- my $tmp;
- foreach $tmp (@order)
- {
- $tmp="UCASE(host)" if ($tmp eq "ucase_host");
- }
- my $query = Sort_fields($start, $end, '', @order);
- $query .= "select 'ok';n";
- MySQLaccess::Debug::Print(2,"Query: $query");
- print MYSQL_Q "$queryn";
- my $delim = <MYSQL_A>; # read header
- MySQLaccess::Debug::Print(3," A> $delim");
- if ($delim ne "okn") {
- if ($delim =~ /^ERROR/) {
- push(@MySQLaccess::Grant::Error,'use_old_server');
- MySQLaccess::Report::Print_Error_Messages() ;
- exit 1;
- }
- while (($line=<MYSQL_A>) ne "okn")
- {
- MySQLaccess::Debug::Print(3," A> $line");
- push(@res,$line);
- }
- }
- my $skip = <MYSQL_A>; # skip result 'ok'
- # remove columnheaders from output
- @res = grep(!/^Q$delimE$/, @res);
- # remove trailing n from each returned record
- chomp(@res);
- # each record has 1 field to much : ucase_host
- @res = grep { /(.*)t.*$/; $_ = $1; } @res;
- MySQLaccess::Debug::Print(2,"Result of sorted table $tbl:");
- foreach $line (@res) { MySQLaccess::Debug::Print(2," >>$line"); }
- return @res;
- }
- # ===========================================================
- # sub Get_All_db(template):
- # return all db the grant-tables are working on,
- # which conform to the template
- # ===========================================================
- sub Get_All_dbs {
- my ($template,$tmp) = @_;
- my @db=();
- my $aref;
- # working with temporary tables or production tables
- if (defined($tmp) and $tmp) {
- $aref = @MySQLaccess::Grant::sorted_db_tmp_table ;
- }
- else {
- $aref = @MySQLaccess::Grant::sorted_db_table;
- }
- MySQLaccess::Debug::Print(1," template=[$template]");
- # get all db for which access-rights can be calculated,
- # which conform to the template.
- # !! these db's don't have to exist yet, so it's not
- # enough to look which db already exist on the system
- $reg_expr = $template;
- if ($template =~ /[*?]/) {
- $reg_expr =~ tr/*?/%_/;
- #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
- }
- $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
- if ( ! ($template =~ /[*?%_]/) ) {
- push(@db,$template);
- return @db;
- }
- MySQLaccess::Debug::Print(2,"#Reading db-table...");
- foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_db_table) {
- my @record=split(/t/,$record);
- my $db = $record[1];
- MySQLaccess::Debug::Print(2,"> $db ");
- if ( (!grep(/$db/i,@db)) and ($db =~/$reg_expr/i) ) {
- push(@db,$db);
- MySQLaccess::Debug::Print(2,"added");
- }
- else {
- MySQLaccess::Debug::Print(2,"skipped");
- }
- }
- # if no rule is found for a certain db in the db-table,
- # the rights of the user are used, so we should inform
- # the user for
- if (!grep(/^%$/,@db)) { push(@db,"$MySQLaccess::NEW_DB"); }
- return @db;
- }
- # ===========================================================
- # sub Get_All_users(template):
- # return all users the grant-tables are working on,
- # which conform to the template
- # ===========================================================
- sub Get_All_users {
- ($template,$tmp) = @_; # nog verder uitwerken!!!
- my @user=();
- my $aref;
- # working with temporary tables or production tables
- if (defined($tmp) and $tmp) {
- $aref = @MySQLaccess::Grant::sorted_user_tmp_table ;
- }
- else {
- $aref = @MySQLaccess::Grant::sorted_user_table;
- }
- MySQLaccess::Debug::Print(1,"Debug Get_All_users:");
- # get all db for which access-rights can be calculated.
- # !! these db's don't have to exist yet, so it's not
- # enough to look which db already exist on the system
- $reg_expr = $template;
- if ($template =~ /[*?]/) {
- $reg_expr =~ tr/*?/%_/;
- #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
- }
- $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
- if ( ! ($template =~ /[*?%_]/) ) {
- push(@user,$template);
- return @user;
- }
- MySQLaccess::Debug::Print(2,"#Reading user-table...");
- foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_user_table) {
- my @record=split(/t/,$record);
- my $user = $record[1];
- MySQLaccess::Debug::Print(2,"> $user ");
- if ( (!grep(/$user/,@user)) and ($user=~/$reg_expr/)) {
- push(@user,$user);
- MySQLaccess::Debug::Print(2, "added");
- }
- else {
- MySQLaccess::Debug::Print(2, "skipped");
- }
- }
- # Any user means also:
- # - the 'empty' user, ie without supplying a username
- # - any user still to be defined/created
- #push(@user,''); #without_suplying_a_username
- push(@user,"$MySQLaccess::NEW_USER");
- #push(@Warnings,'minimum_priv');
- return @user;
- }
- # ===========================================================
- # sub Get_All_hosts(template):
- # return all hosts the grant-tables are working on,
- # which conform to the template
- # ===========================================================
- sub Get_All_hosts {
- my ($template,$tmp) = @_;
- my @host=();
- my $aref;
- my $aref1;
- # working with temporary tables or production tables
- if (defined($tmp) and $tmp) {
- $aref = @MySQLaccess::Grant::sorted_host_tmp_table ;
- $aref1= @MySQLaccess::Grant::sorted_db_tmp_table ;
- }
- else {
- $aref = @MySQLaccess::Grant::sorted_host_table;
- $aref1= @MySQLaccess::Grant::sorted_db_table ;
- }
- MySQLaccess::Debug::Print(1, "Debug Get_All_hosts:");
- # get all db for which access-rights can be calculated.
- # !! these db's don't have to exist yet, so it's not
- # enough to look which db already exist on the system
- $reg_expr = $template;
- if ($template =~ /[*?]/) {
- $reg_expr =~ tr/*?/%_/;
- #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
- }
- $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
- if ( ! ($template =~ /[*?%_]/) ) {
- push(@host,$template);
- return @host;
- }
- MySQLaccess::Debug::Print(1, "#Reading db-table...");
- foreach $record (@{$aref1}) { #MySQLaccess::Grant::sorted_db_table) {
- my @record=split(/t/,$record);
- my $host = $record[0];
- MySQLaccess::Debug::Print(2, "> $host ");
- if (! grep(/$host/i,@host)) {
- push(@host,$host);
- MySQLaccess::Debug::Print(2, "added");
- }
- else {
- MySQLaccess::Debug::Print(2, "skipped");
- }
- }
- MySQLaccess::Debug::Print(1, "#Reading host-table...");
- foreach $record (@{$aref}) {
- my @record=split(/t/,$record);
- my $host = $record[0];
- MySQLaccess::Debug::Print(2, "> $host ");
- if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
- push(@host,$host);
- MySQLaccess::Debug::Print(2, "added");
- }
- else {
- MySQLaccess::Debug::Print(2, "skipped");
- }
- }
- # DOUBT:
- #print "#Reading user-table...n" if ($DEBUG>1);
- #foreach $record (@MySQLaccess::Grant::sorted_user_table) {
- # my @record=split(/t/,$record);
- # my $host = $record[0];
- # print "> $host " if ($DEBUG>2);
- # if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
- # push(@host,$host);
- # print "addedn" if ($DEBUG>2);
- # }
- # else {
- # print "skippedn" if ($DEBUG>2);
- # }
- #}
- # Any host also means:
- # - any host still to be defined/created
- #push(@host,"any_other_host");
- @host = sort(@host);
- return @host;
- }
- ##########################################################################
- package MySQLaccess::Grant;
- ##############
- BEGIN {
- $DEBUG = 0;
- $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
- }
- # ===========================================================
- # sub Diff_Privileges()
- # Calculate diff between temporary and original grant-tables
- # ===========================================================
- sub Diff_Privileges {
- my @before=();
- my @after =();
- my @diffs =();
- # -----------------------------
- # Build list of users,dbs,hosts
- # to process...
- my @all_dbs = @{MySQLaccess::DB::Get_All_dbs('*')};
- my @all_users = @{MySQLaccess::DB::Get_All_users('*')};
- my @all_hosts = @{MySQLaccess::DB::Get_All_hosts('*')};
- #if EDIT-mode
- my @all_dbs_tmp = @{MySQLaccess::DB::Get_All_dbs('*','tmp')};
- my @all_users_tmp = @{MySQLaccess::DB::Get_All_users('*','tmp')};
- my @all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts('*','tmp')};
- my %Access;
- # ------------------------------------
- # Build list of priv. for grant-tables
- foreach $host (@all_hosts) {
- foreach $user (@all_users) {
- foreach $db (@all_dbs) {
- MySQLaccess::Grant::Initialize();
- %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db);
- push(@before,MySQLaccess::Report::Raw_Report($host,$user,$db,%Access));
- }
- }
- }
- # ----------------------------------
- # Build list of priv. for tmp-tables
- foreach $host (@all_hosts_tmp) {
- foreach $user (@all_users_tmp) {
- foreach $db (@all_dbs_tmp) {
- MySQLaccess::Grant::Initialize('tmp');
- %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db,'tmp');
- push(@after,MySQLaccess::Report::Raw_Report($host,$user,$db,%Access));
- }
- }
- }
- # ----------------------------------
- # Write results to temp-file to make
- # DIFF
- @before = sort(@before);
- @after = sort(@after);
- ($hb, $before) = tempfile("$MySQLaccess::script.XXXXXX") or
- push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!");
- ($ha, $after) = tempfile("$MySQLaccess::script.XXXXXX") or
- push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!");
- print $hb join("n",@before);
- print $ha join("n",@after);
- close $hb;
- close $ha;
- # ----------------------------------
- # compute difference
- my $cmd="$MySQLaccess::DIFF $before $after |";
- open(DIFF,"$cmd");
- @diffs = <DIFF>;
- @diffs = grep(/[<>]/,@diffs);
- chomp(@diffs);
- close(DIFF);
- # ----------------------------------
- # cleanup temp. files
- unlink($before);
- unlink($after);
- return @diffs;
- }
- # ===========================================================
- # sub Initialize()
- #
- # ===========================================================
- sub Initialize {
- %MySQLaccess::Grant::Access = %{Default_Access_Rights()};
- @MySQLaccess::Grant::Errors = ();
- @MySQLaccess::Grant::Warnings = ();
- @MySQLaccess::Grant::Notes = ();
- # -----
- # rules
- $MySQLaccess::Grant::Rules{'user'} = 'no_rule_found';
- $MySQLaccess::Grant::Rules{'db'} = 'no_rule_found';
- $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
- $MySQLaccess::Grant::full_access = 1;
- $MySQLaccess::Grant::process_host_table = 0;
- return 1;
- }
- # ===========================================================
- # sub ReadTables()
- #
- # ===========================================================
- sub ReadTables {
- my ($tmp) = @_;
- my ($HOST,$DB,$USER);
- my @tables;
- # build list of available tables
- @tables = MySQLaccess::DB::Show_Tables();
- # reading production grant-tables or temporary tables?
- $tmp = (defined($tmp) and $tmp) ? 1 : 0;
- if ($tmp) { #reading temporary tables
- $HOST=$MySQLaccess::ACCESS_H_TMP;
- $DB =$MySQLaccess::ACCESS_D_TMP;
- $USER=$MySQLaccess::ACCESS_U_TMP;
- # ----------------------------
- # do tables exist?
- if (!grep(/$HOST/,@tables)) { MySQLaccess::DB::CreateTable($HOST); }
- if (!grep(/$USER/,@tables)) { MySQLaccess::DB::CreateTable($USER); }
- if (!grep(/$DB/,@tables)) { MySQLaccess::DB::CreateTable($DB); }
- MySQLaccess::Debug::Print(1,"Finding fields in tmp-ACL files:");
- # -----------------------------
- # Get record-layout
- my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
- my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
- my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
- %MySQLaccess::Grant::H_tmp = %{$h1}; @MySQLaccess::Grant::H_tmp = @{$h2};
- %MySQLaccess::Grant::D_tmp = %{$d1}; @MySQLaccess::Grant::D_tmp = @{$d2};
- %MySQLaccess::Grant::U_tmp = %{$u1}; @MySQLaccess::Grant::U_tmp = @{$u2};
- # @MySQLaccess::Grant::Privileges_tmp=@{Make_Privlist()};
- #
- MySQLaccess::Debug::Print(1, "Reading sorted temp-tables:");
- @MySQLaccess::Grant::sorted_db_tmp_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
- @MySQLaccess::Grant::sorted_host_tmp_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
- @MySQLaccess::Grant::sorted_user_tmp_table= defined($MySQLaccess::Param{'password'}) ?
- MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
- MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
- }
- else { #reading production grant-tables
- $HOST=$MySQLaccess::ACCESS_H;
- $DB =$MySQLaccess::ACCESS_D;
- $USER=$MySQLaccess::ACCESS_U;
- MySQLaccess::Debug::Print(1,"Finding fields in ACL files:");
- # -----------------------------
- # Get record-layout
- my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
- my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
- my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
- %MySQLaccess::Grant::H = %{$h1}; @MySQLaccess::Grant::H = @{$h2};
- %MySQLaccess::Grant::D = %{$d1}; @MySQLaccess::Grant::D = @{$d2};
- %MySQLaccess::Grant::U = %{$u1}; @MySQLaccess::Grant::U = @{$u2};
- @MySQLaccess::Grant::Privileges=@{Make_Privlist()};
- MySQLaccess::Debug::Print(1, "Reading sorted tables:");
- @MySQLaccess::Grant::sorted_db_table = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
- @MySQLaccess::Grant::sorted_host_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
- @MySQLaccess::Grant::sorted_user_table= defined($MySQLaccess::Param{'password'}) ?
- MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
- MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
- }
- return 0;
- }
- # ===========================================================
- # sub Get_Access_Rights(host,user,db)
- # report the access_rights for the tuple ($host,$user,$db).
- # ===========================================================
- sub Get_Access_Rights {
- local ($host,$user,$db,$tmp) = @_;
- my $aref_user;
- my $aref_host;
- my $aref_db;
- # working with temporary tables or production tables
- if (defined($tmp) and $tmp) {
- $aref_user = @MySQLaccess::Grant::sorted_user_tmp_table;
- $aref_host = @MySQLaccess::Grant::sorted_host_tmp_table;
- $aref_db = @MySQLaccess::Grant::sorted_db_tmp_table;
- }
- else {
- $aref_user = @MySQLaccess::Grant::sorted_user_table;
- $aref_host = @MySQLaccess::Grant::sorted_host_table;
- $aref_db = @MySQLaccess::Grant::sorted_db_table;
- }
- my ($refrecord,$refgrant);
- my ($_host_,$_user_,$encpw_);
- my %_Access_;
- MySQLaccess::Debug::Print(1, "for ($host,$user,$db):");
- # ******************************************************************************
- # Create default access-rights
- # default access-rights are no access at all!!
- # ******************************************************************************
- # get hostname for IP-address
- # get IP-address for hostname
- local $host_name = MySQLaccess::Host::IP2Name($host);
- local $host_ip = MySQLaccess::Host::Name2IP($host);
- MySQLaccess::Debug::Print(3,"host=$host, hostname=$host_name, host-ip =$host_ip");
- MySQLaccess::Debug::Print(3,"user=$user");
- MySQLaccess::Debug::Print(3,"db =$db");
- # ***********************************************************************
- # retrieve information on USER
- # check all records in mysql::user for matches with the tuple (host,user)
- # ***********************************************************************
- # 4.OR (add) the privileges for the user from the "user" table.
- # (add all privileges which is "Y" in "user")
- ($refrecord,$refgrant) = Get_grant_from_user($host,$user,$aref_user);
- ($_host_,$_user_,$encpw_) = @{$refrecord};
- %_access_ = %{$refgrant};
- foreach $field (keys(%U)) { ##only priv. set in user-table
- $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
- }
- if ($_user_ eq $MySQLaccess::NEW_USER) {
- push(@Warnings,'minimum_priv');
- }
- if ($_user_ ne $user) {
- $user=$_user_;
- push(@Warnings,'anonymous_access');
- }
- # *******************************************************
- # Validate password if this has been asked to do
- # *******************************************************
- if (defined($password)) {
- $valid = Validate_Password($password,$_host_,$_user_,$_encpw_,$aref_user);
- if (!$valid) { push(@Errors,'invalid_password'); }
- else { push(@Notes,'valid_password'); }
- }
- # ******************************************************************************
- # retrieve information on DB
- # check all records in mysql::db for matches with the triple (host,db,user)
- # first match is used.
- # ******************************************************************************
- # 2.Get grant for user from the "db" table.
- ($refrecord,$refgrant)=Get_grant_from_db($host,$db,$user,$aref_db); #set process_host_table
- ($_host_,$_user_,$encpw_) = @{$refrecord};
- %_access_ = %{$refgrant};
- foreach $field (keys(%D)) { ##only priv. set in db-table
- $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
- }
- # ***********************************************************************
- # retrieve information on HOST
- # check all records in mysql::host for matches with the tuple (host,db)
- #
- # ' The host table is mainly to maintain a list of "secure" servers. '
- # ***********************************************************************
- # 3.If hostname is "empty" for the found entry, AND the privileges with
- # the privileges for the host in "host" table.
- # (Remove all which is not "Y" in both)
- if ($MySQLaccess::Grant::process_host_table) {
- ($refrecord,$refgrant)=Get_grant_from_host($host,$db,$aref_host);
- ($_host_,$_user_,$encpw_) = @{$refrecord};
- %_access_ = %{$refgrant};
- foreach $field (keys(%H)) { ##only priv. set in host-table
- $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} and $_access_{$field});
- }
- }
- MySQLaccess::Debug::Print(1,"done for ($host,$user,$db)");
- return %MySQLaccess::Grant::Access;
- }
- # ####################################
- # FINDING THE RIGHT GRANT-RULE
- # ==========================================================
- # sub Get_grant_from_user:
- # ==========================================================
- sub Get_grant_from_user {
- my ($host,$user,$aref) = @_;
- MySQLaccess::Debug::Print(1, "");
- MySQLaccess::Debug::Print(1, "(host=$host,user=$user)");
- my %Access_user = %{Default_Access_Rights()};
- my $rule_found=0;
- my @record = ();
- my $record;
- foreach $record (@{$aref}) {
- $MySQLaccess::Grant::full_access=0;
- MySQLaccess::Debug::Print(3, "Record= $record");
- @record=split(/t/,$record);
- # check host and db
- # with possible wildcards in field
- # replace mysql-wildcards by reg-wildcards
- my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
- my $user_tpl = $record[1]; #user field isn't pattern-matched!!
- my $passwd = $record[2];
- MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
- MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[1] -> $user_tpl");
- MySQLaccess::Debug::Print(3, "=>password : read=$record[2] -> $passwd");
- if ( MySQLaccess::Host::MatchTemplate($host,$host_tpl) and
- MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user)
- )
- {
- MySQLaccess::Debug::Print(2, "FOUND!!");
- if ($passwd eq '') { push(@Warnings,'insecure_user'); }
- else { push(@Notes,'password_required'); }
- foreach $field (keys(%U)) {
- $Access_user{$field} = $MySQLaccess::Report::Answer{$record[$U{$field}]};
- }
- #print "n" if $DEBUG;
- $MySQLaccess::Grant::Rules{'user'} = $record;
- $rule_found=1;
- last;
- }
- }
- # -------------------------------
- # setting privileges to user-priv
- MySQLaccess::Debug::Print(2, "Rights after parsing user-table..:");
- if (! $rule_found ) {
- @record=();
- MySQLaccess::Debug::Print(2, "NO record found in the user-table!!");
- }
- else {
- MySQLaccess::Debug::Print(2, "Selected record=@record");
- MySQLaccess::Debug::Print(2, "<=?=> $record");
- }
-
- MySQLaccess::Debug::Print(1, "returning @record");
- return (@record,%Access_user); #matching record in user-table
- }
- # ==========================================================
- # sub Get_grant_from_db:
- # ==========================================================
- sub Get_grant_from_db {
- my ($host,$db,$user,$aref) = @_;
- MySQLaccess::Debug::Print(1, "(host=$host,user=$user,db=$db)");
- my %Access_db = %{Default_Access_Rights()};
- my $rule_found=0;
- foreach $record (@{$aref}) {
- $full_access=0;
- MySQLaccess::Debug::Print(2, "Read db: $record");
- @record=split(/t/,$record);
- # check host and db
- # with possible wildcards in field
- # replace mysql-wildcards by reg-wildcards
- my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
- my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]);
- my $user_tpl = $record[2]; #user field isn't pattern matched!!
- MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
- MySQLaccess::Debug::Print(3, "=>db_tpl : read=$record[1] -> $db_tpl");
- MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[2] -> $user_tpl");
- if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
- or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
- or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
- and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) )
- and ( MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user) ) ) {
-
- $MySQLaccess::Grant::process_host_table = ($record[0] eq '');
- if ($user_tpl eq '') { push(@Warnings,'public_database'); }
- foreach $field (keys(%D)) {
- $Access_db{$field} = $MySQLaccess::Report::Answer{$record[$D{$field}]};
- }
- $rule_found=1;
- $MySQLaccess::Grant::Rules{'db'} = $record;
- last;
- }
- }
- # -------------------------------
- # setting privileges to db-priv
- MySQLaccess::Debug::Print(2, "Rights after parsing db-table..:");
- if (! $rule_found ) {
- MySQLaccess::Debug::Print(2, "NO rule found in db-table => no access granted!!");
- }
- return (@record,%Access_db);
- }
- # ==========================================================
- # sub Get_grant_from_host:
- # ==========================================================
- sub Get_grant_from_host {
- my ($host,$db,$aref) = @_;
- MySQLaccess::Debug::Print(1, "Get_grant_from_host()");
- my %Access_host = %{Default_Access_Rights()};
- # the host-table doesn't have to be processed if the host-field
- # in the db-table isn't empty
- if (!$MySQLaccess::Grant::process_host_table) {
- MySQLaccess::Debug::Print(2, ">> Host-table doesn't have to be processed!!");
- $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
- return ([],%Access_host);
- }
- my $rule_found=0;
- my @record = ();
- foreach $record (@{$aref}) {
- $full_access=0;
- MySQLaccess::Debug::Print(2, "host: $record");
- @record=split(/t/,$record);
- # check host and db
- # with possible wildcards in field
- # replace mysql-wildcards by reg-wildcards
- my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
- my $db_tpl = MySQLaccess::Wildcards::SQL2Reg($record[1]);
- MySQLaccess::Debug::Print(3, "=>host_tpl : $record[0] -> $host_tpl");
- MySQLaccess::Debug::Print(3, "=>db_tpl : $record[1] -> $db_tpl");
- if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
- or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
- or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
- and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) ) ) {
- $MySQLaccess::Grant::Rules{'host'} = $record;
- $rule_found=1;
- foreach $field (keys(%H)) {
- $Access_host{$field} = $MySQLaccess::Report::Answer{$record[$H{$field}]};
- }
- last;
- }
- }
- # -------------------------------
- # setting privileges to host-priv
- MySQLaccess::Debug::Print(2, "Rights after parsing host-table..:");
- if (! $rule_found ) {
- @record=();
- MySQLaccess::Debug::Print(2, "NO restrictions found in the host-table!!");
- }
- # --------------------------------
- # debugging access-rights in db
- return (@record,%Access_host); #matching record in host-table
- }
- # ===========================================================
- # sub Default_Access_Rights():
- # return (a reference to) a hash which holds all default
- # priviliges currently defined in the grant-tables.
- # ===========================================================
- sub Default_Access_Rights {
- my %right = ();
- MySQLaccess::Debug::Print(2, "Debug Default_Access_Rights():");
- # add entry for all fields in the HOST-table
- foreach $field (keys(%MySQLaccess::Grant::H)) {
- $right{$field}='0' unless (defined($right{$field}));
- }
- # add entry for all fields in the DB-table
- foreach $field (keys(%MySQLaccess::Grant::D)) {
- $right{$field}='0' unless (defined($right{$field}));
- }
- # add entry for all fields in the USER-table
- foreach $field (keys(%MySQLaccess::Grant::U)) {
- $right{$field}='0' unless (defined($right{$field}));
- }
- # --------------
- # debugging info
- foreach $field (keys(%right)) { MySQLaccess::Debug::Print(3, sprintf("> %15s : %1s",$field,$right{$field})); }
- return %right;
- }
- # ======================================
- # sub Make_Privlist
- # Make an ordered list of the privileges
- # that should be reported
- # ======================================
- sub Make_Privlist {
- # layout:
- #'select_priv', 'create_priv',
- #'insert_priv', 'drop_priv',
- #'update_priv', 'reload_priv',
- #'delete_priv', 'process_priv',
- #'file_priv', 'shutdown_priv');
- my $right;
- my @privlist=();
- foreach $right (@U) {
- if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
- };
- foreach $right (@D) {
- if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
- };
- foreach $right (@H) {
- if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
- };
- # print "Privileges:n";
- # foreach $field (@privlist) { print " > $fieldn"; }
- return @privlist;
- }
- ########################################################################
- package MySQLaccess::Report;
- use Exporter ();
- @EXPORT = qw(&Print_Header());
- BEGIN {
- $FORM = $ENV{'SCRIPT_NAME'};
- $DEBUG = 0;
- $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
- # translation-table for poss. answers
- %Answer = ('Y' => 1 , 'N' => 0
- , 1 => 'Y', 0 => 'N'
- ,'?' => '?', '' => '?'
- );
- $headers = 0;
- $separator = 0;
- # ****************************
- # Notes and warnings
- %MESSAGES = (
- 'insecure_user'
- => "Everybody can access your DB as user `$user' from host `$host'n"
- ."WITHOUT supplying a password.n"
- ."Be very careful about it!!"
- ,'password_required'
- => "A password is required for user `$user' :-("
- ,'invalid_password'
- => "The password '$password' for user `$user' is invalid :-P"
- , 'valid_password'
- => "You supplied the right password for user `$user' :-)"
- ,'public_database'
- => "Any user with the appropriate permissions has access to your DB!n"
- ."Check your users!"
- ,'full_access'
- => "All grant-tables are empty, which gives full access to ALL users !!"
- ,'no_rule_found'
- => "No matching rule"
- ,'no_equiv_host'
- => "Not processed: host-field is not empty in db-table."
- ,'least_priv'
- => "If the final priveliges of the user are more then you gave the user,n"
- ."check the priveliges in the db-table `$db'."
- ,'minimum_priv'
- => "The privileges for any new user are AT LEASTn"
- ."the ones shown in the table above,n"
- ."since these are the privileges of the db `$db'.n"
- ,'not_found_mysql'
- => "The MySQL client program <$MySQLaccess::MYSQL> could not be found.n"
- ."+ Check your path, orn"
- ."+ edit the source of this script to point $MYSQL to the mysql client.n"
- ,'not_found_mysqldump'
- => "The MySQL dump program <$MySQLaccess::MYSQLDUMP> could not be found.n"
- ."+ Check your path, orn"
- ."+ edit the source of this script to point $MYSQLDUMP to the mysqldump program.n"
- ,'not_found_diff'
- => "The diff program <$MySQLaccess::DIFF> could not be found.n"
- ."+ Check your path, orn"
- ."+ edit the source of this script to point $DIFF to the diff program.n"
- ,'Unrecognized_option'
- => "Sorry,n"
- ."You are using an old version of the mysql-program,n"
- ."which does not yet implement a neccessary option.n"
- ."n"
- ."You need at least Version 6.2 of the mysql-client,n"
- ."which was build in MySQL v3.0.18, to use this versionn"
- ."of `$MySQLaccess::script'."
- ,'Access_denied'
- => "Sorry,n"
- ."An error occured when trying to connect to the databasen"
- ."with the grant-tables:n"
- ."* Maybe YOU do not have READ-access to this database?n"
- ."* If you used the -U option, you may have supplied an invalid username?n"
- ." for the superuser?n"
- ."* If you used the -U option, it may be possible you have to supplyn"
- ." a superuser-password to, with the -P option?n"
- ."* If you used the -P option, you may have supplied an invalid password?n"
- ,'Dbaccess_denied'
- => "Sorry,n"
- ."An error occured when trying to connect to the databasen"
- ."with the grant-tables. (dbaccess denied)n"
- ,'Unknown_tmp_table'
- => "Sorry,n"
- ."An error occured when trying to work with the temporary tables in the databasen"
- ."with the grant-tables. (One of the temporary tables does not exist)n"
- ,'Unknown_table'
- => "Sorry,n"
- ."An error occured when trying to work with some tables in the databasen"
- ."with the grant-tables. (table does not exist)n"
- ,'use_old_server'
- => "Sorry,n"
- ."An error occured when executing an SQL statement.n"
- ."You might consider altering the use of the parameter `--old_server' when n"
- ."calling `$MySQLaccess::script'."
- ,'unknown_error'
- => "Sorry,n"
- ."An error occured when trying to connect to the databasen"
- ."with the grant-tables. (unknown error)n"
- ,'anonymous_access'
- => "Accessing the db as an anonymous user.n"
- ."Your username has no relevancen"
- ,'user_required'
- => "You have to supply a userid."
- ,'db_required'
- => "You have to supply the name of a database."
- ,'host_required'
- => "You have to supply the name of a host."
- );
- }
- # =====================================
- # sub Print_Header:
- # print header info
- # =====================================
- sub Print_Header {
- if ($MySQLaccess::CMD) { #command-line mode
- print "$MySQLaccess::script Version $MySQLaccess::VERSIONn"
- ."By RUG-AIV, by Yves Carlier (Yves.Carlier@rug.ac.be)n"
- ."Changes by Steve Harvey (sgh@vex.net)n"
- ."This software comes with ABSOLUTELY NO WARRANTY.n";
- }
- if ($MySQLaccess::CGI) { #CGI-BIN mode
- print "content-type: text/htmlnn"
- . "<HTML>n"
- ."<HEAD>n"
- ."<TITLE>MySQLaccess</TITLE>n"
- ."</HEAD>n"
- ."<BODY>n"
- ."<H1>$MySQLaccess::script Version $MySQLaccess::VERSION</H1>n"
- ."<CENTER>n<ADDRESS>n"
- ."By RUG-AIV, by Yves Carlier (<a href=mailto:Yves.Carlier@rug.ac.be>Yves.Carlier@rug.ac.be</a>)<BR>n"
- ."Changes by Steve Harvey (<a href=mailto:sgh@vex.net>sgh@vex.net</a>)<BR>n"
- ."This software comes with ABSOLUTELY NO WARRANTY.<BR>n"
- ."</ADDRESS>n</CENTER>n"
- ."<HR>n";
- Print_Taskbar();
- print "<HR>n";
- }
- return 1;
- }
- # =====================================
- # sub Print_Footer:
- # print footer info
- # =====================================
- sub Print_Footer {
- if ($MySQLaccess::CMD) { #command-line mode
- print "n"
- ."BUGs can be reported by email to bugs@mysql.comn";
- }
- if ($MySQLaccess::CGI) { #CGI-BIN mode
- if ($MySQLaccess::Param{'brief'}) {
- print "</table>n"; #close table in brief-output
- }
- print "<HR>n"
- ."<ADDRESS>n"
- ."BUGs can be reported by email to <a href=mailto:bugs@mysql.com>bugs@mysql.com</a><BR>n"
- # ."Don't forget to mention the version $VERSION!<BR>n"
- ."</ADDRESS>n"
- ."</BODY>n"
- ."</HTML>n";
- }
- return 1;
- }
- # =====================================
- # sub Print_Taskbar:
- # print taskbar on STDOUT
- # =====================================
- sub Print_Taskbar {
- print "<CENTER>n"
- ."[<a href=$FORM?relnotes=on>Release Notes</a>] n"
- ."[<a href=$FORM?version=on>Version</a>] n"
- ."[<a href=$FORM?plan=on>Future Plans</a>] n"
- ."[<a href=$FORM?howto=on>Examples</a>] n"
- ."[<a href=$FORM?help=on>New check</a>] n"
- ."[<a href=$FORM?edit=on>Change/edit ACL</a>] n"
- ."</CENTER>n";
- return 1;
- }
- # =====================================
- # sub Print_Form:
- # print CGI-form
- # =====================================
- sub Print_Form {
- print <<EOForm;
- <center>
- <!-- Quering -->
- <FORM method=POST action=$FORM>
- <table border width="100%" >
- <tr>
- <th>MySQL server</th>
- <th>User information</th>
- <th>Reports</th>
- </tr>
- <tr>
- <td valign=top>
- <table>
- <tr>
- <td halign=right><b>Host</b><br><font size=-2>(Host on which MySQL-server resides.)</font></td>
- <td valign=top><INPUT name=rhost type=text size=15 maxlength=15 value="$MySQLaccess::Param{'rhost'}"></td>
- </tr>
- <tr>
- <td halign=right><b>Superuser</b><br><font size=-2>(User which has <font color="Red">read-access</font> to grant-tables.)</font></td>
- <td valign=top><INPUT name=superuser type=text size=15 maxlength=15 value="$MySQLaccess::Param{'superuser'}"></td>
- </tr>
- <tr>
- <td halign=right><b>Password</b><br><font size=-2>(of Superuser.)</font></td>
- <td valign=top><INPUT name=spassword type=password size=15 maxlength=15 value="$MySQLaccess::Param{'spassword'}"></td>
- </tr>
- </table>
- </td>
- <td valign=top>
- <table>
- <tr>
- <td halign=right><b><font color=Red>User</font></b><br><font size=-2>(Userid used to connect to MySQL-database.)</font></td>
- <td halign=top><INPUT name=user type=text size=15 maxlength=15 value="$MySQLaccess::Param{'user'}"></td>
- </tr>
- <tr>
- <td halign=right><b>Password</b><br><font size=-2>(Password user has to give to get access to MySQL-database.)</font></td>
- <td valign=top><INPUT name=password type=password size=15 maxlength=15 value="$MySQLaccess::Param{'password'}"></td>
- </tr>
- <tr>
- <td halign=right><b><font color=Red>Database</font></b><br><font size=-2>(Name of MySQL-database user tries to connect to.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td>
- <td valign=top><INPUT name=db type=text size=15 maxlength=15 value="$MySQLaccess::Param{'db'}"></td>
- </tr>
- <tr>
- <td halign=right><b>Host</b><br><font size=-2>(Host from where the user is trying to connect to MySQL-database.</font><br><font size=-2>Wildcards <font color="Green">(*,?,%,_)</font> are allowed.)</font></td>
- <td valign=top><INPUT name=host type=text size=15 maxlength=15 value="$MySQLaccess::Param{'host'}"></td>
- </tr>
- </table>
- </td>
- <td valign=center>
- <table cellspacing=5 cellpadding=2 cols=1 height="100%">
- <tr align=center>
- <td halign=right><INPUT type=submit name=brief value="Brief"><br>
- <INPUT type=submit name=table value="Tabular"></td>
- </tr>
- <tr align=center>
- <td></td>
- </tr>
- <tr align=center>
- <td halign=right><INPUT type=reset value="Clear"></td>
- </tr>
- </table>
- </td>
- </tr>
- </table>
- </form>
- </BODY>
- </HTML>
- EOForm
- return 1;
- }
- # =====================================
- # sub Print_Usage:
- # print some information on STDOUT
- # =====================================
- sub Print_Usage {
- Print_Error_Messages();
- if ($MySQLaccess::CMD) { #command-line mode
- Print_Options();
- }
- if ($MySQLaccess::CGI) { #CGI-BIN mode
- Print_Form();
- }
- return 1;
- }
- # ======================================
- # sub Print_Version:
- # ======================================
- sub Print_Version {
- if ($MySQLaccess::CMD) {
- print $MySQLaccess::INFO;
- }
- if ($MySQLaccess::CGI) {
- print "<PRE>n";
- print $MySQLaccess::INFO;
- print "</PRE>n";
- }
- return 1;
- }
- # ======================================
- # sub Print_Relnotes:
- # ======================================
- sub Print_Relnotes {
- if ($MySQLaccess::CMD) {
- print $MySQLaccess::RELEASE;
- }
- if ($MySQLaccess::CGI) {
- print "<PRE>n";
- print $MySQLaccess::RELEASE;
- print "</PRE>n";
- }
- return 1;
- }
- # ======================================
- # sub Print_Plans:
- # ======================================
- sub Print_Plans {
- if ($MySQLaccess::CMD) {
- print $MySQLaccess::TODO;
- }
- if ($MySQLaccess::CGI) {
- print "<PRE>n";
- print $MySQLaccess::TODO;
- print "</PRE>n";
- }
- return 1;
- }
- # ======================================
- # sub Print_HowTo:
- # ======================================
- sub Print_HowTo {
- if ($MySQLaccess::CMD) {
- print $MySQLaccess::HOWTO;
- }
- if ($MySQLaccess::CGI) {
- print "<PRE>n";
- print $MySQLaccess::HOWTO;
- print "</PRE>n";
- }
- return 1;
- }
- # ======================================
- # sub Print_Options:
- # ======================================
- sub Print_Options {
- if ($MySQLaccess::CGI) { print "<PRE>n"; }
- print $MySQLaccess::OPTIONS;
- if ($MySQLaccess::CGI) { print "</PRE>n"; }
- return 1;
- }
- # ======================================
- # sub Print_Error_Access:
- # ======================================
- sub Print_Error_Access {
- my ($error) = @_;
- print "n";
- if ($MySQLaccess::CGI) { print "<font color=Red>n<PRE>n"; }
- print $MESSAGES{$error};
- if ($MySQLaccess::CGI) { print "</PRE>n</font>n"; }
- print "n";
- return 1;
- }
- # ======================================
- # sub Print_Error_Messages:
- # ======================================
- sub Print_Error_Messages {
- # my ($error) = @_;
- print "n";
- if ($MySQLaccess::CGI) { print "<font color=Red>n<center>n"; }
- foreach $error (@MySQLaccess::Grant::Error) {
- print $MESSAGES{$error};
- print $MySQLaccess::CGI ? "<br>n" : "n";
- }
- if ($MySQLaccess::CGI) { print "</center>n</font>n"; }
- print "n";
- return 1;
- }
- # ======================================
- # sub Print_Message:
- # ======================================
- sub Print_Message {
- my ($aref) = @_;
- my @messages = @{$aref};
- print "n";
- if ($MySQLaccess::CGI) { print "<font color=DarkGreen>n<center>n"; }
- foreach $msg (@messages) {
- print $msg;
- print $MySQLaccess::CGI ? "<br>n" : "n";
- }
- if ($MySQLaccess::CGI) { print "</center>n</font>n"; }
- print "n";
- return 1;
- }
- # ======================================
- # sub Print_Edit:
- # ======================================
- sub Print_Edit {
- print "n";
- if (!$MySQLaccess::CGI) {
- print "Note: Editing the temporary tables is NOT supported in CMD-line mode!n";
- return 0;
- }
- print "<CENTER>n"
- ."<form action=$FORM method=GET>n"
- ."<table width=90% border>n"
- ."<tr>n"
- ." <td><input type=checkbox name=copy value=on> Copy grant-rules to temporary tables<br></td>n"
- ." <td rowspan=5 align=center valign=center><input type=submit value=Go></td>n"
- ."</tr>n"
- ."<tr>n"
- ." <td> Edit temporary tables with external application:<br>"
- ." <a href="$MySQLaccess::MYSQLADMIN">$MySQLaccess::MYSQLADMIN</a></td>n"
- ."</tr>n"
- ."<tr>n"
- ." <td><input type=checkbox name=preview value=on> Preview changes made in temporary tables</td>n"
- ."</tr>n"
- ."<tr>n"
- ." <td><input type=checkbox name=commit value=on> Make changes permanent</td>n"
- ."</tr>n"
- ."<tr>n"
- ." <td><input type=checkbox name=rollback value=on> Restore previous grand-rules</td>n"
- ."</tr>n"
- ."<tr>n"
- ." <td colspan=2 align=center><font size=-2 color=Red>You need write,delete and drop-privileges to perform the above actions</font></td>n"
- ."</tr>n"
- ."</table>n"
- ."</form>n"
- ."</CENTER>n";
- return 1;
- }
- # ======================================
- # sub Print_Access_rights:
- # print the access-rights on STDOUT
- # ======================================
- sub Print_Access_rights {
- my ($host,$user,$db,$refhash) = @_;
- if (defined($MySQLaccess::Param{'brief'})) {
- # if ($MySQLaccess::CGI) { print "<PRE>n"; }
- Matrix_Report($host,$user,$db,$refhash);
- # if ($MySQLaccess::CGI) { print "</PRE>n"; }
- }
- else {
- Tabular_Report($host,$user,$db,$refhash);
- $MySQLaccess::Report::separator = $MySQLaccess::CGI ? "<hr>" : "-"x80;
- }
- return 1;
- }
- # ======================================
- # sub Print_Diff_ACL:
- # print the diff. in the grants before and after
- # ======================================
- sub Print_Diff_ACL {
- my ($aref) = @_;
- my @diffs = @{$aref};
- my %block = ( '<' => 'Before',
- '>' => 'After',
- );
- my %color = ( '<' => 'Green',
- '>' => 'Red',
- );
- my $curblock = '';
- # -----------------------------
- # create column-headers
- foreach $field (@MySQLaccess::Grant::Privileges) {
- push(@headers,substr($field,0,4));
- }
- if ($MySQLaccess::CMD) {
- print "n";
- print "Differences in access-rights BEFORE and AFTER changes in grant-tablesn";
- # print "---------------------------------------------------------------------n";
- my $line1="";
- my $line2="";
- $line1 .= sprintf("| %-30s|",'Host,User,DB');
- $line2 .= sprintf("+-%-30s+",'-' x 30);
- foreach $header (@headers) {
- $line1 .= sprintf("%-4s|",$header);
- $line2 .= sprintf("%s+",'----');
- }
- print "$line2n";
- print "$line1n";
- print "$line2n";
- $format = "format STDOUT = n"
- . "^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< " . " @|||" x 10 ."n"
- . '$host_user_db,@priv' . "n"
- . ".n";
- #print $format;
- eval $format;
- }
- if ($MySQLaccess::CGI) {
- print "<table border width=100%>n";
- print "<tr>n";
- print "<th colspan=11>";
- print "Differences in access-rights <font color=$color{'<'}>BEFORE</font> "
- ."and <font color=$color{'>'}>AFTER</font> changes to grant-tables</font>n";
- print "</th>";
- print "</tr>n";
- print "<tr>n";
- $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
- foreach $header (@headers) {
- $line1 .= sprintf("<th>%-4s</th>",$header);
- }
- print "$line1</tr>n";
- }
- foreach $line (@diffs) {
- $type = substr($line,0,1);
- $line = substr($line,1);
- ($host,$user,$db,@priv) = split(/,/,$line);
- if ($MySQLaccess::CMD) {
- if ($type ne $curblock) {
- $curblock = $type;
- print $block{$curblock},":n";
- }
- #print "$linen";
- write;
- }
- if ($MySQLaccess::CGI) {
- if ($type ne $curblock) {
- $curblock = $type;
- print "<tr><td><b>$block{$curblock}<b></td></tr>n";
- }
- $line1="<td><font color=$color{$type}>$host, $user, $db</font></td>";
- foreach $field (@priv) {
- $line1 .= sprintf("<td align=center><font color=$color{$type}>%-4s</font></td>",$field);
- }
- print "<tr>$line1</tr>n";
- }
- }
- print "n";
- if ($MySQLaccess::CMD) {
- print "---------------------------------------------------------------------n";
- }
- if ($MySQLaccess::CGI) {
- print "</table><br>";
- }
- return 1;
- }
- # ======================================
- # sub Tabular_Report
- # Tabular report,
- # suitable for 1 triple (host,db,user)
- # ======================================
- sub Tabular_Report {
- my ($host,$user,$db,$a) = @_;
- my $column=2;
- # -----------------------------
- # separator
- if ($MySQLaccess::Report::separator) { print "$MySQLaccess::Report::separatorn"; }
-
- # -----------------------------
- # print table of access-rights
- my $rows = int(@MySQLaccess::Grant::Privileges/2); #round up
- my @table=();
- $j=0;
- for $i (0 .. $rows-1) {
- $table[$j]=$MySQLaccess::Grant::Privileges[$i];
- $j = $j+2;
- }
- $j=1;
- for $i ($rows .. $#MySQLaccess::Grant::Privileges) {
- $table[$j]=$MySQLaccess::Grant::Privileges[$i];
- $j = $j+2;
- }
- if ($MySQLaccess::CMD) {
- print "n";
- print "Access-rightsn";
- print "for USER '$user', from HOST '$host', to DB '$db'n";
- }
- if ($MySQLaccess::CGI) {
- print "<table border width=100%>n";
- print "<tr>n";
- }
- if ($MySQLaccess::CGI) {
- print "<th colspan=5>";
- print "<font color=Red>Access-rights</font>n";
- print "for USER '<font color=Green>$user</font>', from HOST '<font color=Green>$host</font>', to DB '<font color=Green>$db</font>'n";
- print "</th>";
- print "</tr>n";
- print "<tr>n";
- }
- if ($MySQLaccess::CMD) {
- print "t+-----------------+---+t+-----------------+---+";
- }
- foreach $field (@table) {
- if ($MySQLaccess::CMD) {
- if ($column==2) { print "nt"; $column=1;}
- else { print "t"; $column=2;}
- printf "| %-15s | %s |",$field,$Answer{$a->{$field}};
- }
- if ($MySQLaccess::CGI) {
- if ($column==2) { print "</tr>n<tr>n"; $column=1;}
- else { print "<td width=10%></td>"; $column=2;}
- printf " <td width=35%><b>%-15s</b></td><td width=10%>%s</td>n",$field,$Answer{$a->{$field}};
- }
- }
- print "n";
- if ($MySQLaccess::CMD) {
- print "t+-----------------+---+t+-----------------+---+n";
- }
- if ($MySQLaccess::CGI) {
- print "</tr>n</table><br>";
- }
- # ---------------
- # print notes:
- foreach $note (@MySQLaccess::Grant::Notes) {
- my $message = $MESSAGES{$note};
- $message =~ s/$user/$user/g;
- $message =~ s/$db/$db/g;
- $message =~ s/$host/$host/g;
- $message =~ s/$password/$password/g;
- $PREFIX='NOTE';
- if ($MySQLaccess::CMD) {
- my @lines = split(/n/,$message);
- foreach $line (@lines) {
- print "$PREFIX:t $linen";
- $PREFIX=' ';
- }
- }
- if ($MySQLaccess::CGI) {
- print "<b>$PREFIX:</b> $message<br>n";
- }
- }
- # ---------------
- # print warnings:
- foreach $warning (@MySQLaccess::Grant::Warnings) {
- my $message = $MESSAGES{$warning};
- $message =~ s/$user/$user/g;
- $message =~ s/$db/$db/g;
- $message =~ s/$host/$host/g;
- $message =~ s/$password/$password/g;
- $PREFIX='BEWARE';
- if ($MySQLaccess::CMD) {
- my @lines = split(/n/,$message);
- foreach $line (@lines) {
- print "$PREFIX:t $linen";
- $PREFIX=' ';
- }
- }
- if ($MySQLaccess::CGI) {
- print "<b>$PREFIX:</b> $message<br>n";
- }
- }
- # ---------------
- # print errors:
- foreach $error (@MySQLaccess::Grant::Errors) {
- my $message = $MESSAGES{$error};
- $message =~ s/$user/$user/g;
- $message =~ s/$db/$db/g;
- $message =~ s/$host/$host/g;
- $message =~ s/$password/$password/g;
- $PREFIX='ERROR';
- if ($MySQLaccess::CMD) {
- my @lines = split(/n/,$message);
- foreach $line (@lines) {
- print "$PREFIX:t $linen";
- $PREFIX=' ';
- }
- }
- if ($MySQLaccess::CGI) {
- print "<b>$PREFIX:</b> $message<br>n";
- }
- }
- # ---------------
- # inform if there are no rules ==> full access for everyone.
- if ($MySQLaccess::Grant::full_access) { print "$MESSAGES{'full_access'}n"; }
- # ---------------
- # print the rules used
- print "n";
- if ($MySQLaccess::CMD) {
- print "The following rules are used:n";
- foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
- my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
- $rule =~ s/t/','/g;
- printf " %-5s : '%s'n",$field,$rule;
- }
- }
- if ($MySQLaccess::CGI) {
- print "<br>n";
- print "<table border width=100%>n";
- print "<tr><th colspan=2>The following rules are used:</th></tr>n";
- foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
- my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
- $rule =~ s/t/','/g;
- printf "<tr><th>%-5s</th><td>'%s'</td></tr>n",$field,$rule;
- }
- print "</table>n";
- }
-
- return 1;
- }
- # ======================================
- # sub Matrix_Report:
- # single-line output foreach triple,
- # no notes,warnings,...
- # ======================================
- sub Matrix_Report {
- my ($host,$user,$db,$a) = @_;
- my @headers = ();
-
- if (! $headers) {
- # -----------------------------
- # create column-headers
- foreach $field (@MySQLaccess::Grant::Privileges) {
- push(@headers,substr($field,0,4));
- }
-
- # -----------------------------
- # print column-headers
- print "n";
- if ($MySQLaccess::CMD) {
- my $line1="";
- my $line2="";
- foreach $header (@headers) {
- $line1 .= sprintf("%-4s ",$header);
- $line2 .= sprintf("%s ",'----');
- }
- $line1 .= sprintf("| %-20s",'Host,User,DB');
- $line2 .= sprintf("+ %-20s",'-' x 20);
- print "$line1n";
- print "$line2n";
- }
- if ($MySQLaccess::CGI) {
- print "<table width=100% border>n";
- my $line1="<tr>";
- foreach $header (@headers) {
- $line1 .= sprintf("<th>%-4s</th>",$header);
- }
- $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
- print "$line1</tr>n";
- }
- # ----------------------------
- # column-headers should only be
- # printed once.
- $MySQLaccess::Report::headers=1;
- }
- # ------------------------
- # print access-information
- if ($MySQLaccess::CMD) {
- foreach $field (@MySQLaccess::Grant::Privileges) {
- printf " %-2s ",$Answer{$a->{$field}};
- }
- printf "| %-20s",join(',',$host,$user,$db);
- print "n";
- }
- if ($MySQLaccess::CGI) {
- print "<tr>";
- foreach $field (@MySQLaccess::Grant::Privileges) {
- printf "<td align=center>%-2s</td>",$Answer{$a->{$field}};
- }
- printf "<td><b>%-20s</b></td>",join(', ',$host,$user,$db);
- print "</tr>n";
- }
- return 1;
- }
- # ======================================
- # sub Raw_Report:
- # single-line output foreach triple,
- # no notes,warnings,...
- # ======================================
- sub Raw_Report {
- my ($host,$user,$db,$a) = @_;
- my @headers = ();
- my $string = "";
-
- # ------------------------
- # print access-information
- $string = "$host,$user,$db,";
- foreach $field (@MySQLaccess::Grant::Privileges) {
- $string .= $Answer{$a->{$field}} . ",";
- }
- return $string;
- }
- #######################################################################
- package MySQLaccess::Wildcards;
- BEGIN {
- $DEBUG = 0;
- $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
- }
- # ############################################
- # SQL, WILDCARDS and REGULAR EXPRESSIONS
- # ============================================
- # translage SQL-expressions to Reg-expressions
- # ============================================
- sub SQL2Reg {
- my ($expr) = @_;
- my $expr_o = $expr;
- $expr =~ s/./\./g;
- $expr =~ s/\%/ 02/g;
- $expr =~ s/%/.*/g;
- $expr =~ s/ 02/%/g;
- $expr =~ s/\_/ 02/g;
- $expr =~ s/_/.+/g;
- $expr =~ s/ 02/_/g;
- MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
- return $expr;
- }
- # translage WILDcards to Reg-expressions
- # ============================================
- sub Wild2Reg {
- my ($expr) = @_;
- my $expr_o = $expr;
- $expr =~ s/./\./g;
- $expr =~ s/\*/ 02/g;
- $expr =~ s/*/.*/g;
- $expr =~ s/ 02/*/g;
- $expr =~ s/\?/ 02/g;
- $expr =~ s/?/.+/g;
- $expr =~ s/ 02/?/g;
- MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
- return $expr;
- }
- # =============================================
- # match a given string with a template
- # =============================================
- sub MatchTemplate {
- my ($tpl,$string) = @_;
- my $match=0;
- if ($string=~ /^$tpl$/ or $tpl eq '') { $match=1; }
- else { $match=0;}
- MySQLaccess::Debug::Print(2,"($tpl,$string) --> $match");
- return $match;
- }
- #######################################################################
- package MySQLaccess::Host;
- BEGIN {
- $localhost = undef;
- $DEBUG = 2;
- $DEBUG = $MySQLaccess::DEBUG unless ($DEBUG);
- }
- # ======================================
- # sub IP2Name
- # return the Name with the corr. IP-nmbr
- # (no aliases yet!!)
- # ======================================
- sub IP2Name {
- my ($ip) = @_;
- my $ip_o = $ip;
- if ($ip !~ /([0-9]+).([0-9]+).([0-9]+).([0-9]+)/o) {
- MySQLaccess::Debug::Print(3,"'$ip' is not an ip-number, returning IP=$ip");
- return $ip;
- }
- MySQLaccess::Debug::Print(4,"IP=$ip split up => $1.$2.$3.$4");
- $ip = pack "C4",$1,$2,$3,$4;
- MySQLaccess::Debug::Print(4,"IP packed -> >>$ip<<n");
- my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($ip, AF_INET);
- MySQLaccess::Debug::Print(3,"IP=$ip_o => hostname=$name");
- MySQLaccess::Debug::Print(4,"aliases=$aliases");
- MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
- return ($name || $ip);
- #return ($name || undef);
- }
- # ======================================
- # sub Name2IP
- # return the IP-number of the host
- # ======================================
- sub Name2IP {
- my ($name) = @_;
- if ($name =~ /[%_]/) {
- MySQLaccess::Debug::Print(3,"'$name' contains SQL-wildcards, returning name=$name");
- return $name;
- }
- my ($_name,$aliases,$addrtype,$length,@addrs) = gethostbyname($name);
- my ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
- my $ip = "$a.$b.$c.$d";
- MySQLaccess::Debug::Print(3,"hostname=$name => IP=$ip");
- MySQLaccess::Debug::Print(4,"aliases=$aliases");
- MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
- #if ($ip ne "") { return "$ip"; }
- #else { return undef; }
- return ($ip || $name);
- }
- # ========================================
- # sub LocalHost
- # some special action has to be taken for
- # the localhost
- # ========================================
- sub LocalHost {
- if (!defined($MySQLaccess::Host::localhost)) {
- $MySQLaccess::Host::localhost = Sys::Hostname::hostname();
- MySQLaccess::Debug::Print(3,"Setting package variable $localhost=$MySQLaccess::Host::localhost");
- }
- my $host = $localhost;
- MySQLaccess::Debug::Print(3,"localhost = $host");
- return $host;
- }
- # ========================================
- # check if the given hostname (or ip)
- # corresponds with the localhost
- # ========================================
- sub Is_localhost {
- my ($host_tpl) = @_;
- my $isit = 0;
- if (($MySQLaccess::host_name eq $localhost) or ($MySQLaccess::host_ip eq $local_ip)) {
- MySQLaccess::Debug::Print(2,"Checking for localhost");
- MySQLaccess::Debug::Print(3,"because ($MySQLaccess::host_name EQ $localhost) AND ($MySQLaccess::host_ip EQ $local_ip)");
- $isit = ( 'localhost' =~ /$host_tpl/ ) ? 1 : 0;
- MySQLaccess::Debug::Print(3," 'localhost' =?= $host_tpl -> $isit");
- return $isit;
- }
- else {
- MySQLaccess::Debug::Print(4,"Not checking for localhost");
- MySQLaccess::Debug::Print(4,"because ($MySQLaccess::host_name != $localhost) AND ($MySQLaccess::host_ip != $local_ip)");
- return 0;
- }
- }
- # =========================================
- # check if host (IP or name) can be matched
- # on the template.
- # =========================================
- sub MatchTemplate {
- my ($host,$tpl) = @_;
- my $match = 0;
-
- MySQLaccess::Debug::Print(1, "($host) =?= ($tpl)");
- my $host_name = IP2Name($host);
- my $host_ip = Name2IP($host);
- MySQLaccess::Debug::Print(2, "name=$host_name ; ip=$host_ip");
- $match = (MySQLaccess::Wildcards::MatchTemplate($tpl,$host_name) or
- MySQLaccess::Wildcards::MatchTemplate($tpl,$host_ip));
- MySQLaccess::Debug::Print(2, "($host_name,$host_ip) =?= ($tpl): $ncount");
- return $match;
- }
- ########################################################################
- package MySQLaccess::Debug;
- BEGIN {
- my $dbg_file = "$MySQLaccess::script_log";
- open(DEBUG,"> $dbg_file") or warn "Could not open outputfile $dbg_file for debugging-infon";
- select DEBUG;
- $| = 1;
- select STDOUT;
- }
- # =========================================
- # Print debugging information on STDERR
- # =========================================
- sub Print {
- my ($level,$mesg) = @_;
- my ($pack,$file,$line,$subname,$hasargs,$wantarray) = caller(1);
- my ($PACK) = split('::',$subname);
- my $DEBUG = ${$PACK."::DEBUG"} ? ${$PACK."::DEBUG"} : $MySQLaccess::DEBUG ;
- my ($sec,$min,$hour) = localtime();
- print DEBUG "[$hour:$min:$sec $subname] $mesgn" if ($DEBUG>=$level);
- }