~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to scripts/mysqlaccess.sh

  • Committer: brian
  • Date: 2008-06-25 05:29:13 UTC
  • Revision ID: brian@localhost.localdomain-20080625052913-6upwo0jsrl4lnapl
clean slate

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
#!@PERL@
 
2
# ****************************
 
3
package MySQLaccess;
 
4
#use strict;
 
5
use File::Temp qw(tempfile tmpnam);
 
6
use Fcntl;
 
7
 
 
8
BEGIN {
 
9
        # ****************************
 
10
        # static information...
 
11
        $VERSION     = "2.06, 20 Dec 2000";
 
12
        $0           =~ m%/([^/]+)$%o;
 
13
        $script      = $1;
 
14
        $script      = 'MySQLAccess' unless $script;
 
15
        $script_conf = "$script.conf";
 
16
        $script_log  = $ENV{'HOME'}."/$script.log";
 
17
 
 
18
        # ****************************
 
19
        # information on MySQL
 
20
        $MYSQL     = '@bindir@/mysql';    # path to mysql executable
 
21
        $SERVER    = '3.21';
 
22
        $MYSQL_OPT = ' --batch --unbuffered';
 
23
        $ACCESS_DB = 'mysql';            # name of DB with grant-tables
 
24
        $ACCESS_H  = 'host';             # 
 
25
        $ACCESS_U  = 'user';             # 
 
26
        $ACCESS_D  = 'db';               #
 
27
        # Add/Edit privileges
 
28
        $ACCESS_H_TMP = 'host_tmp';      
 
29
        $ACCESS_U_TMP = 'user_tmp';      
 
30
        $ACCESS_D_TMP = 'db_tmp';        
 
31
        $ACCESS_H_BCK = 'host_backup';   
 
32
        $ACCESS_U_BCK = 'user_backup';   
 
33
        $ACCESS_D_BCK = 'db_backup';     
 
34
        $DIFF      = '/usr/bin/diff'; 
 
35
        $MYSQLDUMP = '@bindir@/mysqldump';
 
36
                                         #path to mysqldump executable
 
37
 
 
38
        $MYSQLADMIN= 'http://foobar.com/MySQLadmin';
 
39
                                         #URL of CGI for manipulating
 
40
                                         #the temporary grant-tables
 
41
}
 
42
 
 
43
END {
 
44
        unlink $MYSQL_CNF if defined $MYSQL_CNF and not $DEBUG;
 
45
}
 
46
 
 
47
$INFO = <<"_INFO";
 
48
--------------------------------------------------------------------------
 
49
   mysqlaccess (Version $VERSION)
 
50
   ~~~~~~~~~~~
 
51
   Copyright (C) 1997,1998 Yves.Carlier\@rug.ac.be
 
52
                           University of Ghent (RUG), Belgium
 
53
                           Administratieve Informatieverwerking (AIV)
 
54
 
 
55
   report the access-privileges for a USER from a HOST to a DB
 
56
 
 
57
   Many thanks go to <monty\@mysql.com> and <psmith\@BayNetworks.COM>
 
58
   for their suggestions, debugging and patches. 
 
59
 
 
60
   use `$script -?' to get more information on available options.
 
61
 
 
62
   From version 2.0x, $script can also be used through a WEB-browser
 
63
   if it is ran as a CGI-script.  (See the release-notes)
 
64
 
 
65
--------------------------------------------------------------------------
 
66
_INFO
 
67
 
 
68
$OPTIONS = <<_OPTIONS;
 
69
 
 
70
Usage: $script [host [user [db]]] OPTIONS
 
71
 
 
72
  -?, --help           display this helpscreen and exit
 
73
  -v, --version        print information on the program `$script'
 
74
 
 
75
  -u, --user=#         username for logging in to the db
 
76
  -p, --password=#     validate password for user
 
77
  -h, --host=#         name or IP-number of the host
 
78
  -d, --db=#           name of the database
 
79
 
 
80
  -U, --superuser=#    connect as superuser
 
81
  -P, --spassword=#    password for superuser
 
82
  -H, --rhost=#        remote MySQL-server to connect to
 
83
      --old_server     connect to old MySQL-server (before v3.21) which 
 
84
                       does not yet know how to handle full where clauses.
 
85
 
 
86
  -b, --brief          single-line tabular report
 
87
  -t, --table          report in table-format
 
88
 
 
89
  --relnotes           print release-notes
 
90
  --plan               print suggestions/ideas for future releases
 
91
  --howto              some examples of how to run `$script'
 
92
  --debug=N            enter debuglevel N (0..3)
 
93
 
 
94
  --copy               reload temporary grant-tables from original ones
 
95
  --preview            show differences in privileges after making
 
96
                       changes in (temporary) grant-tables
 
97
  --commit             copy grant-rules from temporary tables to grant-tables
 
98
                       (!don't forget to do an mysqladmin reload)
 
99
  --rollback           undo the last changes to the grant-tables.
 
100
 
 
101
  Note:
 
102
    + At least the user and the db must be given (even with wildcards)
 
103
    + If no host is given, `localhost' is assumed
 
104
    + Wilcards (*,?,%,_) are allowed for host, user and db, but be sure 
 
105
      to escape them from your shell!! (ie type \\* or '*')
 
106
_OPTIONS
 
107
 
 
108
$RELEASE = <<'_RELEASE';
 
109
 
 
110
Release Notes:
 
111
-------------
 
112
  0.1-beta1: internal
 
113
  - first trial.
 
114
 
 
115
  0.1-beta2: (1997-02-27)
 
116
  - complete rewrite of the granting-rules, based on the documentation
 
117
    found in de FAQ.
 
118
  - IP-number and name for a host are equiv.
 
119
 
 
120
  0.1-beta3: (1997-03-10)
 
121
  - more information
 
122
  - 'localhost' and the name/ip of the local machine are now equiv.
 
123
 
 
124
  0.1-beta4: (1997-03-11)
 
125
  - inform the user if he has not enough priv. to read the mysql db
 
126
 
 
127
  1.0-beta1: (1997-03-12)
 
128
  suggestions by Monty:
 
129
  - connect as superuser with superpassword.
 
130
  - mysqlaccess could also notice if all tables are empty. This means
 
131
    that all user have full access!
 
132
  - It would be nice if one could optionally start mysqlaccess without
 
133
    any options just the arguments 'user db' or 'host user db', where
 
134
    host is 'localhost' if one uses only two arguments.
 
135
 
 
136
  1.0-beta2: (1997-03-14)
 
137
  - bugfix: translation to reg.expr of \_ and \%.
 
138
  - bugfix: error in matching regular expression and string given
 
139
            by user which resulted in
 
140
            'test_123' being matched with 'test'
 
141
 
 
142
  1.0-beta3: (1997-03-14)
 
143
  - bugfix: the user-field should not be treated as a sql-regexpr,
 
144
            but as a plain string.
 
145
  - bugfix: the host-table should not be used if the host isn't empty in db
 
146
                                          or  if the host isn't emty in user
 
147
            (Monty)
 
148
 
 
149
  1.0-beta4: (1997-03-14)
 
150
  - bugfix: in an expression "$i = $j or $k", the '=' binds tighter than the or
 
151
            which results in problems...
 
152
            (by Monty)
 
153
  - running mysqlaccess with "perl -w" gives less warnings...   ;-)
 
154
 
 
155
  1.0-beta5: (1997-04-04)
 
156
  - bugfix: The table sorting was only being applied to the "user" table; all
 
157
            the tables need to be sorted.  Rewrote the sort algorithm, and
 
158
            the table walk algorithm (no temp file anymore), and various
 
159
            other cleanups.  I believe the access calculation is 100% correct.
 
160
            (by Paul D. Smith <psmith\@baynetworks.com>)
 
161
  - Allow the debug level to be set on the cmd line with --debug=N.
 
162
            (by Paul D. Smith <psmith\@baynetworks.com>)
 
163
  - More -w cleanups; should be totally -w-clean.
 
164
            (by Paul D. Smith <psmith\@baynetworks.com>)
 
165
 
 
166
  1.1-beta1: (1997-04-xx) 
 
167
  1.1-beta2: (1997-04-11)
 
168
  - new options:
 
169
             --all_users : report access-rights for all possible users
 
170
             --all_dbs   : report access-rights for all possible dbs
 
171
             --all_hosts : report access-rights for all possible hosts
 
172
             --brief     : as brief as possible, don't mention notes,warnings and rules
 
173
             --password  : validate password for user 
 
174
  - layout: long messages are wrapped on the report.
 
175
  - functionality:
 
176
            more descriptive notes and warnings
 
177
            wildcards (*,?) are allowed in the user,host and db options
 
178
            setting xxxx=* is equiv to using option --all_xxxx
 
179
            note: make sure you escape your wildcards, so they don't get
 
180
                  interpreted by the shell.  use \* or '*'
 
181
  - bugfix: Fieldnames which should be skipped on the output can now have
 
182
            a first capital letter.
 
183
  - bugfix: any option with a '.' (eg ip-number) was interpreted as
 
184
            a wildcard-expression.
 
185
  - bugfix: When no entry was found in the db-table, the default accessrights are
 
186
            N, instead of the faulty Y in a previous version.
 
187
 
 
188
  1.1-beta-3  : (1997-04-xx)
 
189
  1.1-beta-4  : (1997-04-xx)
 
190
  1.1-beta-5  : (1997-04-xx)
 
191
  1.1         : (1997-04-28)
 
192
  - new options:
 
193
            --rhost     : name of mysql-server to connect to
 
194
            --plan      : print suggestions/ideas for future releases
 
195
            --relnotes  : display release-notes
 
196
            --howto     : display examples on how to use mysqlaccess
 
197
            --brief     : single-line tabular output
 
198
  - functionality/bugfix:
 
199
    *      removed options --all_users,--all_dbs,--all_hosts, which 
 
200
           were redundant with the wildcard-expressions for the corresponding
 
201
           options. They made the processing of the commandline too painful 
 
202
           and confusing ;-)
 
203
           (suggested by psmith)
 
204
    *      redefined the option --brief, which now gives a single-line 
 
205
           tabular output
 
206
    *      Now we check if the right version of the mysql-client is used,
 
207
           since we might use an option not yet implemented in an
 
208
           older version (--unbuffered, since 3.0.18)
 
209
           Also the error-messages the mysql-client reports are 
 
210
           better interpreted ;-)  
 
211
    *      Wildcards can now be given following the SQL-expression 
 
212
           (%,_) and the Regular-expression (*,?) syntax.
 
213
  - speed: we now open a bidirectional pipe to the mysql-client, and keep 
 
214
           it open throughout the whole run. Queries are written to,
 
215
           and the answers read from the pipe.
 
216
           (suggested by monty)
 
217
  - bugfixes:
 
218
    *      the Rules were not properly reset over iterations 
 
219
    *      when in different tables the field-names were not identical, 
 
220
           eg. Select_priv and select_priv, they were considered as 
 
221
           definitions of 2 different access-rights.
 
222
    *      the IP-number of a host with a name containing wildcards should
 
223
           not be searched for in Name2IP and IP2Name.
 
224
    *      various other small things, pointed out by <monty> and <psmith>
 
225
 
 
226
  1.2         : (1997-05-13)
 
227
  - bugfix:
 
228
    * Fixed bug in acl with anonymous user:  Now if one gets accepted by the
 
229
      user table as a empty user name, the user name is set to '' when 
 
230
      checking against the 'db' and 'host' tables. (Bug fixed in MySQL3.20.19)
 
231
 
 
232
  1.2-1       : (1997-xx-xx)
 
233
  - bugfix:
 
234
    * hashes should  be initialized with () instead of {} <psmith>
 
235
    * "my" variable $name masks earlier declaration in same scope,
 
236
      using perl 5.004 <????>
 
237
 
 
238
  1.2-2       : (1997-06-10)
 
239
    
 
240
  2.0p1-3     : (1997-10-xx)
 
241
  - new
 
242
    * packages
 
243
    * log-file for debug-output : /tmp/mysqlaccess.log
 
244
    * default values are read from a configuration file $script.conf
 
245
      first this file is looked for in the current directory; if not
 
246
      found it is looked for in /etc/
 
247
      Note that when default-values are given, these can't get overriden
 
248
      by empty (blanc) values!
 
249
    * CGI-BIN version with HTML and forms interface.  Simply place the
 
250
      script in an ScriptAliased directory, make the configuration file
 
251
      available in the that directory or in /etc, and point your browser
 
252
      to the right URL. 
 
253
    * copy the grant-rules to temporary tables, where you are safe to
 
254
      play with them.
 
255
    * preview changes in privileges after changing grant-rules,
 
256
      before taking them into production
 
257
    * copy the new grant-rules from the temporary tables back to the
 
258
      grant-tables.
 
259
    * Undo all changes made in the grant-tables (1-level undo).
 
260
  -new options:
 
261
    * --table   : as opposite of the --brief option.
 
262
    * --copy    : (re)load temporary grant-tables from original ones.
 
263
    * --preview : preview changes in privileges after changing
 
264
                  some or more entries in the grant-tables.
 
265
    * --commit  : copy grant-rules from temporary tables to grant-tables
 
266
                  (!don't forget to do an mysqladmin reload)
 
267
    * --rollback: undo the last changes to the grant-tables.
 
268
 
 
269
  - bugfix:
 
270
    * if the table db is empty, mysqlaccess freezed 
 
271
      (by X Zhu <X.Zhu@Bradford.ac.uk>)
 
272
 
 
273
  2.0         : (1997-10-09)
 
274
  - fixed some "-w" warnings.
 
275
  - complain when certain programs and paths can't be found.
 
276
 
 
277
  2.01        : (1997-12-12)
 
278
  - bugfix:
 
279
    * rules for db-table where not calculated and reported correctly.
 
280
  2.02        : (1998-01-xx)
 
281
  - bugfix:
 
282
    * Privileges of the user-table were not AND-ed properly with the
 
283
      other privileges. (reported by monty)
 
284
  - new option:
 
285
    * --old_server: mysqlaccess will now use a full where clause when
 
286
                    retrieving information from the MySQL-server.  If
 
287
                    you are connecting to an old server (before v3.21)
 
288
                    then use the option --old_server.
 
289
  2.03         : (1998-02-27)
 
290
  - bugfix:
 
291
    * in Host::MatchTemplate: incorrect match if host-field was left empty.
 
292
 
 
293
  2.04-alpha1  : (2000-02-11)
 
294
  Closes vulnerability due to former implementation requiring passwords
 
295
  to be passed on the command line.
 
296
  - functionality
 
297
    Option values for --password -p -spassword -P  may now be omitted from
 
298
    command line, in which case the values will be prompted for.
 
299
      (fix supplied by Steve Harvey <sgh@vex.net>)
 
300
 
 
301
   2.05: (2000-02-17)   Monty
 
302
   Moved the log file from /tmp to ~
 
303
 
 
304
   2.06:  Don't print '+++USING FULL WHERE CLAUSE+++'
 
305
 
 
306
_RELEASE
 
307
 
 
308
$TODO = <<_TODO;
 
309
 
 
310
 Plans:
 
311
 -----
 
312
  -a full where clause is use now.  How can we handle older servers?
 
313
  -add some more functionality for DNS.
 
314
  -select the warnings more carefuly.
 
315
  >>  I think that the warnings should either be enhanced to _really_
 
316
  >>  understand and report real problems accurately, or restricted to
 
317
  >>  only printing things that it knows with 100% certainty. <psmith)
 
318
  >>  Why do I have both '%' and 'any_other_host' in there?  Isn't that
 
319
  >>  the same thing?  I think it's because I have an actual host '%' in
 
320
  >>  one of my tables.  Probably the script should catch that and not
 
321
  >>  duplicate output. <psmith>
 
322
 
 
323
_TODO
 
324
 
 
325
# From the FAQ: the Grant-algorithm
 
326
# ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
327
# The host table is mainly to maintain a list of "secure" servers.
 
328
# At TCX hosts contain a list of all machines on local network. These are granted
 
329
# all privileges.
 
330
# Technically the user grant is calculated by:
 
331
#
 
332
#    1.First sort all entries by host by putting host without wildcards first,
 
333
#      after this host with wildcards and entries with host = ".
 
334
#      Under each host sort user by the same criterias.
 
335
#    2.Get grant for user from the "db" table.
 
336
#    3.If hostname is "empty" for the found entry, AND the privileges with
 
337
#      the privileges for the host in "host" table.
 
338
#      (Remove all which is not "Y" in both)
 
339
#    4.OR (add) the privileges for the user from the "user" table.
 
340
#     (add all privileges which is "Y" in "user")
 
341
#
 
342
#    When matching, use the first found match.
 
343
#
 
344
# -----------------------------------------------------------------------------------
 
345
 
 
346
$HOWTO = <<_HOWTO;
 
347
 
 
348
Examples of how to call $script:
 
349
~~~~~~~~
 
350
1)Calling $script with 2 arguments:
 
351
 
 
352
  \$ $script root mysql
 
353
     ->report rights of user root logged on at the local host in db mysql
 
354
 
 
355
  Access-rights
 
356
  for USER 'root', from HOST 'localhost', to DB 'mysql'
 
357
          +-----------------+---+ +-----------------+---+
 
358
          | select_priv     | Y | | drop_priv       | Y |
 
359
          | insert_priv     | Y | | reload_priv     | Y |
 
360
          | update_priv     | Y | | shutdown_priv   | Y |
 
361
          | delete_priv     | Y | | process_priv    | Y |
 
362
          | create_priv     | Y | | file_priv       | Y |
 
363
          +-----------------+---+ +-----------------+---+
 
364
  BEWARE:  Everybody can access your DB as user 'root'
 
365
        :  WITHOUT supplying a password.  Be very careful about it!!
 
366
 
 
367
  The following rules are used:
 
368
   db    : 'No matching rule'
 
369
   host  : 'Not processed: host-field is not empty in db-table.'
 
370
   user  : 'localhost','root','','Y','Y','Y','Y','Y','Y','Y','Y','Y','Y'
 
371
 
 
372
2)Calling $script with 3 arguments:
 
373
 
 
374
  \$ $script foo.bar nobody Foo 
 
375
     ->report rights of user root logged in at machine foobar to db Foo
 
376
 
 
377
  Access-rights
 
378
  for USER 'nobody', from HOST 'foo.bar', to DB 'Foo'
 
379
          +-----------------+---+ +-----------------+---+
 
380
          | select_priv     | Y | | drop_priv       | N |
 
381
          | insert_priv     | Y | | reload_priv     | N |
 
382
          | update_priv     | Y | | shutdown_priv   | N |
 
383
          | delete_priv     | Y | | process_priv    | N |
 
384
          | create_priv     | N | | file_priv       | N |
 
385
          +-----------------+---+ +-----------------+---+
 
386
  BEWARE:  Everybody can access your DB as user 'nobody'
 
387
        :  WITHOUT supplying a password.  Be very careful about it!!
 
388
 
 
389
  The following rules are used:
 
390
   db    : 'foo.bar','Foo','nobody','Y','Y','Y','N','N','N'
 
391
   host  : 'Not processed: host-field is not empty in db-table.'
 
392
   user  : 'foo.bar','nobody','','N','N','N','Y','N','N','N','N','N','N'
 
393
 
 
394
3)Using wildcards:
 
395
 
 
396
  \$ $script  \\* nobody Foo --brief
 
397
     ->report access-rights of user nobody from all machines to db Foo,
 
398
       and use a matrix-report.
 
399
 
 
400
  Sel  Ins  Upd  Del  Crea Drop Reld Shut Proc File Host,User,DB        
 
401
  ---- ---- ---- ---- ---- ---- ---- ---- ---- ---- --------------------
 
402
   Y    Y    Y    Y    N    N    N    N    N    N   localhost,nobody,Foo
 
403
   N    N    N    N    N    N    N    N    N    N   %,nobody,Foo  
 
404
   N    N    N    N    N    N    N    N    N    N   any_other_host,nobody,Foo
 
405
 
 
406
_HOWTO
 
407
 
 
408
 
 
409
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
 
410
#                       START OF THE PROGRAM                            #
 
411
# +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ #
 
412
 
 
413
use Getopt::Long;
 
414
use Sys::Hostname;
 
415
use IPC::Open3;
 
416
 
 
417
 
 
418
# ****************************
 
419
# debugging flag
 
420
# can be set to 0,1,2,3
 
421
# a higher value gives more info
 
422
# ! this can also be set on the command-line
 
423
        $DEBUG   = 0;
 
424
 
 
425
# ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++>8
 
426
#  Normaly nothing should be changed beneeth this line
 
427
 
 
428
 
 
429
# ****************************
 
430
# no caching on STDOUT
 
431
        $|=1;
 
432
 
 
433
        $MYSQL_CNF = tmpnam();
 
434
        %MYSQL_CNF = (client    => { },
 
435
                      mysql     => { },
 
436
                      mysqldump => { },
 
437
        );
 
438
 
 
439
 
 
440
 
 
441
$NEW_USER = 'ANY_NEW_USER';
 
442
$NEW_DB   = 'ANY_NEW_DB'  ;
 
443
 
 
444
 
 
445
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
 
446
#  mysqlaccess:                                              #
 
447
#  ~~~~~~~~~~~                                               #
 
448
#  Lets get to it,                                           #
 
449
#  and start the program by processing the parameters        #
 
450
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% #
 
451
 
 
452
($CMD,$CGI) = GetMode();
 
453
 
 
454
# ****************************
 
455
# the copyright message should
 
456
# always be printed (once)
 
457
MySQLaccess::Report::Print_Header();
 
458
 
 
459
# *****************************
 
460
# Read configuration-file
 
461
  MySQLaccess::Debug::Print(1, "Reading configuration file...");
 
462
  if (-f "./$script_conf") {
 
463
     require "./$script_conf";
 
464
  }
 
465
  elsif (-f "@sysconfdir@/$script_conf") {
 
466
     require "@sysconfdir@/$script_conf";
 
467
  }
 
468
  elsif (-f "/etc/$script_conf") {
 
469
     require "/etc/$script_conf";
 
470
  }
 
471
 
 
472
# ****************************
 
473
# Read in all parameters
 
474
if ($MySQLaccess::CMD) { #command-line version
 
475
        # ----------------------------
 
476
        # Get options from commandline
 
477
        $Getopt::Long::ignorecase=0; #case sensitive options
 
478
        if ( grep(/\-\?/,@ARGV) ) { MySQLaccess::Report::Print_Usage(); exit 0; }
 
479
        GetOptions("help"          => \$Param{'help'}
 
480
                  ,"host|h=s"      => \$Param{'host'}
 
481
                  ,"user|u=s"      => \$Param{'user'}
 
482
                  ,"password|p:s"  => \$Param{'password'}
 
483
                  ,"db|d=s"        => \$Param{'db'}
 
484
                  ,"superuser|U=s" => \$Param{'superuser'}
 
485
                  ,"spassword|P:s" => \$Param{'spassword'}
 
486
                  ,"rhost|H=s"     => \$Param{'rhost'}
 
487
                  ,"old_server"    => \$Param{'old_server'}
 
488
                  ,"debug=i"       => \$Param{'DEBUG'}
 
489
                  ,"brief|b"       => \$Param{'brief'}
 
490
                  ,"table|t"       => \$Param{'table'}
 
491
                  ,"relnotes"      => \$Param{'relnotes'}
 
492
                  ,"plan"          => \$Param{'plan'}
 
493
                  ,"howto"         => \$Param{'howto'}
 
494
                  ,"version|v"     => \$Param{'version'}
 
495
                  ,"preview"       => \$Param{'preview'}
 
496
                  ,"copy"          => \$Param{'copy'}
 
497
                  ,"commit"        => \$Param{'commit'}
 
498
                  ,'rollback'      => \$Param{'rollback'}
 
499
                  );
 
500
 
 
501
        # -----------------------------
 
502
        # set DEBUG
 
503
        $DEBUG = $Param{'DEBUG'} if ($Param{'DEBUG'}>=$DEBUG);
 
504
 
 
505
        # -----------------------------
 
506
        # check for things which aren't
 
507
        # declared as options:
 
508
        # 2 arguments: (user,db) -> ('localhost','user','db')
 
509
        if ($#ARGV == 1) {
 
510
           MySQLaccess::Debug::Print(2,"$script called with 2 arguments:");
 
511
           $Param{'host'} = $Param{'host'} || 'localhost'; 
 
512
           $Param{'user'} = $ARGV[0] || $Param{'user'};
 
513
           $Param{'db'}   = $ARGV[1] || $Param{'db'}; 
 
514
        }
 
515
        # 3 arguments: (host,user,db)
 
516
        if ($#ARGV == 2) {
 
517
           MySQLaccess::Debug::Print(2,"$script called with 3 arguments:");
 
518
           $Param{'host'} = $ARGV[0] || $Param{'host'};
 
519
           $Param{'user'} = $ARGV[1] || $Param{'user'};
 
520
           $Param{'db'}   = $ARGV[2] || $Param{'db'};
 
521
        }
 
522
 
 
523
        # -------------------------------------
 
524
        # prompt for user password if requested
 
525
        if ( defined($Param{'password'}) && length($Param{'password'}) == 0 ) {
 
526
           $Param{'password'} = PromptPass(
 
527
                                "Password for MySQL user $Param{'user'}: ");
 
528
        }
 
529
}
 
530
if ($MySQLaccess::CGI) { #CGI-version
 
531
        require CGI;
 
532
        $Q = new CGI;
 
533
        $Param{'help'} = $Q->param('help') ;
 
534
        $Param{'host'} = $Q->param('host') || $Q->param('h') || $Param{'host'};
 
535
        $Param{'user'} = $Q->param('user') || $Q->param('u') || $Param{'user'};
 
536
        $Param{'db'}   = $Q->param('db')   || $Q->param('d') || $Param{'db'};
 
537
        $Param{'password'}  = $Q->param('password')  || $Q->param('p') || $Param{'password'};
 
538
        $Param{'superuser'} = $Q->param('superuser') || $Q->param('U') || $Param{'superuser'};
 
539
        $Param{'spassword'} = $Q->param('spassword') || $Q->param('P') || $Param{'spassword'};
 
540
        $Param{'rhost'}     = $Q->param('rhost')     || $Q->param('H') || $Param{'rhost'};
 
541
        $Param{'old_server'}= $Q->param('old_server')|| $Param{'old_server'};
 
542
        $Param{'debug'}     = $Q->param('debug')     || $Param{'debug'};
 
543
        $Param{'brief'}     = $Q->param('brief')     || $Param{'brief'}; 
 
544
        $Param{'table'}     = $Q->param('table')     || $Param{'table'}; 
 
545
        $Param{'relnotes'}  = $Q->param('relnotes');
 
546
        $Param{'plan'}      = $Q->param('plan');
 
547
        $Param{'howto'}     = $Q->param('howto'); 
 
548
        $Param{'version'}   = $Q->param('version') ? $Q->param('version') : $Q->param('v');
 
549
        $Param{'edit'}      = $Q->param('edit'); 
 
550
        $Param{'preview'}   = $Q->param('preview'); 
 
551
        $Param{'copy'}      = $Q->param('copy'); 
 
552
        $Param{'commit'}    = $Q->param('commit'); 
 
553
        $Param{'rollback'}  = $Q->param('rollback'); 
 
554
        # -----------------------------
 
555
        # set DEBUG
 
556
        $DEBUG = $Q->param('debug') if ($Q->param('debug')>=$DEBUG);
 
557
}
 
558
 
 
559
# ----------------------
 
560
# brief and table-format 
 
561
# exclude each-other
 
562
# table-format is prefered
 
563
if (defined($Param{'table'})) { undef($Param{'brief'}); }
 
564
if (defined($Param{'preview'}) or
 
565
    defined($Param{'copy'}) or
 
566
    defined($Param{'commit'}) or
 
567
    defined($Param{'rollback'}) ) { $Param{'edit'}='on'; }
 
568
 
 
569
 
 
570
# ----------------------
 
571
# if no host is given
 
572
# assume we mean 'localhost'
 
573
if (!defined($Param{'host'}))      { $Param{'host'}='localhost'; }
 
574
 
 
575
# ----------------------
 
576
# perform some checks
 
577
# -> eliminate 'broken pipe' error
 
578
push(@MySQLaccess::Grant::Error,'not_found_mysql')     if !(-x $MYSQL);
 
579
push(@MySQLaccess::Grant::Error,'not_found_diff')      if !(-x $DIFF);
 
580
push(@MySQLaccess::Grant::Error,'not_found_mysqldump') if !(-x $MYSQLDUMP);
 
581
if (@MySQLaccess::Grant::Error) {
 
582
   MySQLaccess::Report::Print_Error_Messages() ;
 
583
   exit 0;
 
584
}
 
585
 
 
586
#-----------------------
 
587
# get info/help if necc.
 
588
$print_usage=1;
 
589
if ( defined($Param{'version'}) ) {
 
590
   MySQLaccess::Report::Print_Version();
 
591
   $print_usage=0;
 
592
   MySQLaccess::Report::Print_Footer();
 
593
   MySQLaccess::DB::CloseConnection();
 
594
   exit 0;
 
595
#   exit 0;
 
596
}
 
597
if ( defined($Param{'relnotes'}) ) {
 
598
   MySQLaccess::Report::Print_Relnotes();
 
599
   $print_usage=0;
 
600
   MySQLaccess::Report::Print_Footer();
 
601
   MySQLaccess::DB::CloseConnection();
 
602
   exit 0;
 
603
#   exit 0;
 
604
}
 
605
if ( defined($Param{'plan'}) ) {
 
606
   MySQLaccess::Report::Print_Plans();
 
607
   $print_usage=0;
 
608
   MySQLaccess::Report::Print_Footer();
 
609
   MySQLaccess::DB::CloseConnection();
 
610
   exit 0;
 
611
#   exit 0;
 
612
}
 
613
if ( defined($Param{'howto'}) ) {
 
614
   MySQLaccess::Report::Print_HowTo();
 
615
   $print_usage=0;
 
616
   MySQLaccess::Report::Print_Footer();
 
617
   MySQLaccess::DB::CloseConnection();
 
618
   exit 0;
 
619
#   exit 0;
 
620
}
 
621
 
 
622
# -----------------------------
 
623
# generate a help-screen in CMD-mode
 
624
# or a blanc form in CGI-mode 
 
625
if ( defined($Param{'help'}) 
 
626
     or !defined($Param{'user'}) 
 
627
     or !defined($Param{'host'})
 
628
     or !defined($Param{'db'}) 
 
629
   ) {
 
630
   push(@MySQLaccess::Grant::Error,'user_required') unless defined($Param{'user'});
 
631
   push(@MySQLaccess::Grant::Error,'db_required') unless defined($Param{'db'});
 
632
   push(@MySQLaccess::Grant::Error,'host_required') unless defined($Param{'host'});
 
633
   MySQLaccess::Report::Print_Usage() if $print_usage;
 
634
   exit 0;
 
635
}
 
636
 
 
637
 
 
638
# ----------------------------
 
639
# get hostname and local-ip
 
640
# for localhost
 
641
$localhost = MySQLaccess::Host::LocalHost();
 
642
$local_ip  = MySQLaccess::Host::Name2IP($localhost);
 
643
$MySQLaccess::Host::localhost = MySQLaccess::Host::LocalHost();
 
644
$MySQLaccess::Host::local_ip  = MySQLaccess::Host::Name2IP($localhost);
 
645
MySQLaccess::Debug::Print(3, "localhost name=$localhost, ip=$local_ip");
 
646
 
 
647
#-----------------------------------
 
648
# version of MySQL-server to connect
 
649
# to determine use of full where clause
 
650
$MySQLaccess::Host::SERVER = $Param{'old_server'} ? '3.20' : $SERVER;
 
651
 
 
652
#---------------------------------
 
653
# create the config file for mysql and mysqldump
 
654
# to avoid passing authentication info on the command line
 
655
#
 
656
MergeConfigFiles();
 
657
die "Unsafe config file found: $unsafeConfig\n"  if $unsafeConfig;
 
658
if (defined($Param{'superuser'})) {
 
659
   $MYSQL_CNF{'mysql'}{'user'} = $Param{'superuser'};
 
660
   $MYSQL_CNF{'mysqldump'}{'user'} = $Param{'superuser'};
 
661
}
 
662
if (defined($Param{'spassword'})) {
 
663
   if ( $CMD && length($Param{'spassword'}) == 0 ) {
 
664
      $Param{'spassword'} =
 
665
           PromptPass("Password for MySQL superuser $Param{'superuser'}: ");
 
666
   }
 
667
   if ( length($Param{'spassword'}) > 0 ) {
 
668
      $MYSQL_CNF{'mysql'}{'password'} = $Param{'spassword'};
 
669
      $MYSQL_CNF{'mysqldump'}{'password'} = $Param{'spassword'};
 
670
   }
 
671
}
 
672
WriteTempConfigFile();
 
673
 
 
674
#---------------------------------
 
675
# Inform user if he has not enough
 
676
# privileges to read the access-db
 
677
if ( $nerror=MySQLaccess::DB::OpenConnection() ) {
 
678
    MySQLaccess::Report::Print_Error_Access($nerror);
 
679
    exit 0;
 
680
}
 
681
 
 
682
# -----------------------
 
683
# Read MySQL ACL-files
 
684
if ($nerror=MySQLaccess::Grant::ReadTables()) {
 
685
    MySQLaccess::Report::Print_Error_Access($nerror);
 
686
    exit 0;
 
687
};
 
688
if ($Param{'edit'} and $nerror=MySQLaccess::Grant::ReadTables('tmp')) {
 
689
    MySQLaccess::Report::Print_Error_Access($nerror);
 
690
    exit 0;
 
691
}
 
692
 
 
693
#---------------------------------
 
694
# reload temporay grant-tables 
 
695
# with data from original ones
 
696
if ( defined($Param{'copy'}) ) {
 
697
   $nerror=MySQLaccess::DB::LoadTmpTables();
 
698
   if ($nerror) {
 
699
      MySQLaccess::Report::Print_Error_Access($nerror);
 
700
      exit 0;
 
701
   }
 
702
   my $msg = "The grant-rules are copied from the grant-tables to\n"
 
703
           . "the temporary tables.";
 
704
   MySQLaccess::Report::Print_Message([$msg]);
 
705
#   MySQLaccess::Report::Print_Footer();
 
706
#   MySQLaccess::DB::CloseConnection();
 
707
#   exit 0;
 
708
}
 
709
 
 
710
 
 
711
#---------------------------------
 
712
# preview result of changes in the 
 
713
# grant-tables
 
714
if ( defined($Param{'preview'}) ) {
 
715
   $aref=MySQLaccess::Grant::Diff_Privileges();
 
716
   MySQLaccess::Report::Print_Diff_ACL($aref);
 
717
#   MySQLaccess::Report::Print_Footer();
 
718
#   MySQLaccess::DB::CloseConnection();
 
719
#   exit 0;
 
720
}
 
721
 
 
722
 
 
723
#---------------------------------
 
724
# reload grant-tables 
 
725
# with data from temporary tables
 
726
if ( defined($Param{'commit'}) ) {
 
727
   if ($nerror = MySQLaccess::DB::CommitGrantTables()) {
 
728
      MySQLaccess::Report::Print_Error_Access($nerror);
 
729
      exit 0;
 
730
   }
 
731
   my $msg = "The grant-rules have been copied from the temporary tables\n"
 
732
           . "to the grant-tables.";
 
733
   my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n"
 
734
           . "changes take effect.";
 
735
   my $msg2= "A backup-version of your original grant-rules are saved in the\n"
 
736
           . "backup-tables, so you can always perform a 1-level rollback.";
 
737
   MySQLaccess::Report::Print_Message([$msg,$msg1,$msg2]);
 
738
#   MySQLaccess::Report::Print_Footer();
 
739
#   MySQLaccess::DB::CloseConnection();
 
740
#   exit 0;
 
741
}
 
742
 
 
743
#---------------------------------
 
744
# restore previous grant-rules
 
745
# with data from backup tables
 
746
if ( defined($Param{'rollback'}) ) {
 
747
   if ($nerror = MySQLaccess::DB::RollbackGrantTables()) {
 
748
      MySQLaccess::Report::Print_Error_Access($nerror);
 
749
      exit 0;
 
750
   }
 
751
   my $msg = "The old grant-rules have been copied back from the backup tables\n"
 
752
           . "to the grant-tables.";
 
753
   my $msg1= "Don't forget to do an 'mysqladmin reload' before these\n"
 
754
           . "changes take effect.";
 
755
   MySQLaccess::Report::Print_Message([$msg,$msg1]);
 
756
#   MySQLaccess::Report::Print_Footer();
 
757
#   MySQLaccess::DB::CloseConnection();
 
758
#   exit 0;
 
759
}
 
760
#----------------------------------
 
761
# show edit-taskbar
 
762
if ( defined($Param{'edit'})) {
 
763
   if ($MySQLaccess::CGI ) {
 
764
   MySQLaccess::Report::Print_Edit();
 
765
   $print_usage=0;
 
766
   MySQLaccess::Report::Print_Footer();
 
767
   MySQLaccess::DB::CloseConnection();
 
768
   exit 0;
 
769
   }
 
770
   else {
 
771
   MySQLaccess::Report::Print_Edit();
 
772
   $print_usage=0;
 
773
   MySQLaccess::Report::Print_Footer();
 
774
   MySQLaccess::DB::CloseConnection();
 
775
   exit 0;
 
776
   }
 
777
}
 
778
 
 
779
 
 
780
# -----------------------------
 
781
# Build list of users,dbs,hosts
 
782
# to process...
 
783
@all_dbs   = @{MySQLaccess::DB::Get_All_dbs($Param{'db'})};
 
784
@all_users = @{MySQLaccess::DB::Get_All_users($Param{'user'})};
 
785
@all_hosts = @{MySQLaccess::DB::Get_All_hosts($Param{'host'})};
 
786
#if EDIT-mode
 
787
#@all_dbs_tmp   = @{MySQLaccess::DB::Get_All_dbs($Param{'db'},'tmp')};
 
788
#@all_users_tmp = @{MySQLaccess::DB::Get_All_users($Param{'user'},'tmp')};
 
789
#@all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts($Param{'host'},'tmp')};
 
790
 
 
791
# -----------------------------
 
792
# Report access-rights for each
 
793
# tuple (host,user,db)
 
794
#$headers=0;
 
795
my %Access = ();
 
796
foreach $host (@all_hosts) {
 
797
  foreach $user (@all_users) {
 
798
    foreach $db (@all_dbs) {
 
799
      MySQLaccess::Grant::Initialize();
 
800
      %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db); 
 
801
      MySQLaccess::Report::Print_Access_rights($host,$user,$db,\%Access);
 
802
    }
 
803
  }
 
804
}
 
805
 
 
806
# -----------------------------
 
807
# End script
 
808
MySQLaccess::Report::Print_Footer();
 
809
MySQLaccess::DB::CloseConnection();
 
810
exit 0;
 
811
 
 
812
#############################################################
 
813
#  FUNCTIONS  #
 
814
###############
 
815
sub GetMode {
 
816
   my $cmd=0;
 
817
   my $cgi=0;
 
818
   if (defined($ENV{'HTTP_HOST'})) { $cmd=0; $cgi=1; }
 
819
   else                            { $cmd=1; $cgi=0; } 
 
820
   return ($cmd,$cgi);
 
821
}
 
822
 
 
823
# ================================
 
824
# sub PromptPass
 
825
#  prompt tty for a password
 
826
# ================================
 
827
sub PromptPass {
 
828
    my ($prompt) = @_;
 
829
    my $password;
 
830
    $ENV{PATH} = "/bin:/usr/bin";
 
831
    $ENV{IFS} = " \t\n";
 
832
    $ENV{SHELL} = "/bin/sh";
 
833
    system "stty -echo";
 
834
    print $prompt;
 
835
    chomp($password = <STDIN>);
 
836
    print "\n";
 
837
    system "stty echo";
 
838
    $password;
 
839
}
 
840
 
 
841
# =================================
 
842
# sub CheckUnsafeFile
 
843
#  tell if a config file containing a password is unsafe
 
844
# =================================
 
845
sub CheckUnsafeFile {
 
846
    my ($fname) = @_;
 
847
    my ($dev, $ino, $mode, $nlink,
 
848
        $uid, $gid, $rdev, $size,
 
849
        $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
 
850
 
 
851
    if ( $uid != $< ) {   # unsafe if owned by other than current user
 
852
        return 1;
 
853
    }
 
854
    if ( $mode & 066 ) {  # unsafe if accessible by other
 
855
        return 1;
 
856
    }
 
857
    $fname =~ s#/[^/]+$##;
 
858
    if ( (length $fname) > 0 ) {
 
859
        return CheckUnsafeDir($fname);
 
860
    }
 
861
    return 0;
 
862
}
 
863
 
 
864
# =================================
 
865
# sub CheckUnsafeDir
 
866
#  tell if a directory is unsafe
 
867
# =================================
 
868
sub CheckUnsafeDir {
 
869
    my ($fname) = @_;
 
870
    my ($dev, $ino, $mode, $nlink,
 
871
        $uid, $gid, $rdev, $size,
 
872
        $atime, $mtime, $ctime, $blksize, $blocks) = stat($fname);
 
873
 
 
874
    # not owned by me or root
 
875
    if ( ($uid != $<) && ($uid != 0) ) {
 
876
        return 1;
 
877
    }
 
878
    if ( $mode & 022 ) {  # unsafe if writable by other
 
879
        return 1  unless $mode & 01000;  # but sticky bit ok
 
880
    }
 
881
    $fname =~ s#/[^/]+$##;
 
882
    if ( (length $fname) > 0 ) {
 
883
        return CheckUnsafeDir($fname);
 
884
    }
 
885
    return 0;
 
886
}
 
887
 
 
888
# =================================
 
889
# sub MergeConfigFile
 
890
#  merge data from .cnf file
 
891
# =================================
 
892
sub MergeConfigFile {
 
893
    my ($fname) = @_;
 
894
    my ($group, $item, $value);
 
895
    if ( open CNF, $fname ) {
 
896
         while (<CNF>) {
 
897
             s/^\s+//;
 
898
             next if /^[#;]/;
 
899
             if ( /\[\s*(\w+)\s*]/ ) {
 
900
                 $group = $1;
 
901
                 $group =~ tr/A-Z/a-z/;
 
902
                 if ( !exists $MYSQL_CNF{$group} ) {
 
903
                     undef $group;
 
904
                 }
 
905
             } elsif ( defined $group ) {
 
906
                 ($item, $value) = /((?:\w|-)+)\s*=\s*(\S+)/;
 
907
                 # don't unquote backslashes as we just write it back out
 
908
                 if ( defined $item ) {
 
909
                     if ( $item =~ /^password$/ ) {
 
910
                         if ( CheckUnsafeFile($fname) ) {
 
911
                             $unsafeConfig = $fname;
 
912
                         }
 
913
                     }
 
914
                     if ( $group eq 'client' ) {
 
915
                         $MYSQL_CNF{'mysql'}{$item} = $value;
 
916
                         $MYSQL_CNF{'mysqldump'}{$item} = $value;
 
917
                     } else {
 
918
                         $MYSQL_CNF{$group}{$item} = $value;
 
919
                     }
 
920
                 }
 
921
             }
 
922
         }
 
923
         close(CNF);
 
924
    }
 
925
}
 
926
 
 
927
# =================================
 
928
# sub MergeConfigFiles
 
929
#  merge options from config files
 
930
#  NOTE: really should do two separate merges for each
 
931
#    client to exactly duplicate order of resulting argument lists
 
932
# =================================
 
933
sub MergeConfigFiles {
 
934
    my ($name,$pass,$uid,$gid,$quota,$comment,$gcos,$dir,$shell) = getpwuid $<;
 
935
    MergeConfigFile("@sysconfdir@/my.cnf");
 
936
    MergeConfigFile("/etc/my.cnf");
 
937
    MergeConfigFile("$dir/.my.cnf");
 
938
}
 
939
 
 
940
# =================================
 
941
# sub WriteTempConfigFile
 
942
#  write 
 
943
# =================================
 
944
sub WriteTempConfigFile {
 
945
   sysopen CNFFILE, $MYSQL_CNF, O_RDWR|O_CREAT|O_EXCL, 0700
 
946
      or die "sysopen $MYSQL_CNF: $!";
 
947
   
 
948
   # groups may be in any order, generic groups such as [client] assumed
 
949
   # here to be empty
 
950
   foreach $group (keys %MYSQL_CNF) {
 
951
      print CNFFILE "[$group]\n";
 
952
      foreach $item (keys %{$MYSQL_CNF{$group}}) {
 
953
         if ( defined $MYSQL_CNF{$group}{$item} ) {
 
954
            print CNFFILE "$item=$MYSQL_CNF{$group}{$item}\n";
 
955
         } else {
 
956
            print CNFFILE "$item\n";
 
957
         }
 
958
      }
 
959
      print CNFFILE "\n";
 
960
   }
 
961
   close(CNFFILE);
 
962
}
 
963
 
 
964
######################################################################
 
965
package MySQLaccess::DB;
 
966
###########
 
967
BEGIN {
 
968
    $DEBUG     = 2;
 
969
    $DEBUG     = $MySQLaccess::DEBUG unless ($DEBUG);
 
970
    # Error-messages from the MySQL client
 
971
    %ACCESS_ERR= ('Access_denied'       => 'Access denied' 
 
972
                 ,'Dbaccess_denied'     => 'Access to database denied'
 
973
                 ,'Unrecognized_option' => 'unrecognized option' 
 
974
                 ,'Unknown_table'       => "Can't find file:"
 
975
                 ,'unknown_error'       => '^ERROR:'
 
976
                 );
 
977
}
 
978
# ######################################
 
979
#  Connecting to the MYSQL DB
 
980
# ======================================
 
981
# sub OpenConnection
 
982
#  Open an connection to the mysql-db
 
983
#  questions to MYSQL_Q
 
984
#  answers from MYSQL_A
 
985
# ======================================
 
986
sub OpenConnection {
 
987
    my $pid;
 
988
    MySQLaccess::Debug::Print(2,"OpenConnection:");
 
989
 
 
990
    # check path to mysql-client executable
 
991
    if (! -f $MySQLaccess::MYSQL) {
 
992
       if ($MySQLaccess::CMD) { die "Could not find MySQL-client '$MySQLaccess::MYSQL'"; }
 
993
       if ($MySQLaccess::CGI) { 
 
994
          print "<center>\n<font color=Red>\n";
 
995
          print "ERROR: Could not find MySQL-client '$MySQLaccess::MYSQL'";
 
996
          print "</center>\n</font>\n";
 
997
          exit 0;
 
998
       }
 
999
    }
 
1000
 
 
1001
    # path to mysql executable
 
1002
    my $connect = "$MySQLaccess::MYSQL --defaults-file=$MySQLaccess::MYSQL_CNF";
 
1003
    $connect .= " $MySQLaccess::MYSQL_OPT";
 
1004
    # superuser, spassword transmitted via defaults-file
 
1005
    if (defined($MySQLaccess::Param{'rhost'}))     { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
 
1006
    # other options??
 
1007
 
 
1008
    # grant-database
 
1009
    $connect .= " $MySQLaccess::ACCESS_DB";
 
1010
 
 
1011
    # open connection (not using /bin/sh -c)
 
1012
    MySQLaccess::Debug::Print(2,"Connecting to: $connect");
 
1013
    $pid=IPC::Open3::open3(\*MYSQL_Q,\*MYSQL_A,"",split /\s+/,$connect);
 
1014
    MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
 
1015
    
 
1016
    # check connection 
 
1017
    print MYSQL_Q "select 'ok';\n";
 
1018
    $answer = <MYSQL_A>; #answer from mysql
 
1019
    MySQLaccess::Debug::Print(2,"Answer: $answer\n");
 
1020
    foreach $nerror (sort(keys(%ACCESS_ERR))) {
 
1021
      MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
 
1022
      if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { 
 
1023
         MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
 
1024
         return $nerror; 
 
1025
      }
 
1026
    }
 
1027
 
 
1028
if (0) {
 
1029
    # check server-version 
 
1030
    print MYSQL_Q "select 'ok';\n";
 
1031
    $answer = <MYSQL_A>; #answer from mysql
 
1032
    MySQLaccess::Debug::Print(2,"Answer: $answer\n");
 
1033
    foreach $nerror (sort(keys(%ACCESS_ERR))) {
 
1034
      MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
 
1035
      if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { 
 
1036
         MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
 
1037
         return $nerror; 
 
1038
      }
 
1039
    }
 
1040
}
 
1041
 
 
1042
    my $skip=<MYSQL_A>; 
 
1043
    return 0; 
 
1044
}
 
1045
 
 
1046
# ======================================
 
1047
# sub CloseConnection
 
1048
#  Close the connection to the mysql-db
 
1049
# ======================================
 
1050
sub CloseConnection {
 
1051
    close MYSQL_Q;
 
1052
    close MYSQL_A;
 
1053
}
 
1054
 
 
1055
# ===========================================================
 
1056
# sub CreateTable($table)
 
1057
#  Create temporary/backup table
 
1058
# ===========================================================
 
1059
sub CreateTable {
 
1060
    my $pid;
 
1061
    my ($table,$force) = @_;
 
1062
    my %tables = ( $MySQLaccess::ACCESS_U_TMP => $MySQLaccess::ACCESS_U,
 
1063
                   $MySQLaccess::ACCESS_H_TMP => $MySQLaccess::ACCESS_H,
 
1064
                   $MySQLaccess::ACCESS_D_TMP => $MySQLaccess::ACCESS_D,
 
1065
                   $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
 
1066
                   $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
 
1067
                   $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
 
1068
                   $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
 
1069
                   $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
 
1070
                   $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
 
1071
                 ); 
 
1072
    my $tbl;
 
1073
    my $query="";
 
1074
    my $delim;
 
1075
    my $skip;
 
1076
    my $create;
 
1077
    my @known_tables=();
 
1078
 
 
1079
#    print STDERR "CreateTable($table)\n";
 
1080
    MySQLaccess::Debug::Print(1,"CreateTable($table):");
 
1081
 
 
1082
    ## error-handling
 
1083
    return 'Unknown_table' unless defined($tables{$table});
 
1084
 
 
1085
    ## build list of known/existing tables;
 
1086
    ## if 'force' existing table is dropped first
 
1087
    if (defined($force) and $force) {
 
1088
       @known_tables = Show_Tables();
 
1089
       if (grep(/^$table$/,@known_tables)) {
 
1090
       $query = "DROP TABLE $table;";
 
1091
       }
 
1092
    }
 
1093
 
 
1094
    ## path to mysqldump executable
 
1095
    my $connect = $MySQLaccess::MYSQLDUMP;
 
1096
    $connect .= " --defaults-file=$MySQLaccess::MYSQL_CNF --no-data";
 
1097
    # superuser, spassword transmitted via defaults-file
 
1098
    if (defined($MySQLaccess::Param{'rhost'}))     { $connect .= " --host=$MySQLaccess::Param{'rhost'}"; }
 
1099
    $connect .= " $MySQLaccess::ACCESS_DB";
 
1100
    $connect .= " $tables{$table}";
 
1101
 
 
1102
 
 
1103
    ## get creation-data for original table
 
1104
    $create = '';
 
1105
    my $mysqldump = $connect;
 
1106
    $mysqldump =~ s/ \$TABLE / $tbl /;
 
1107
 
 
1108
    # open connection (not using /bin/sh -c)
 
1109
    MySQLaccess::Debug::Print(2,"Connecting to: $connect");
 
1110
    $pid=IPC::Open3::open3(\*DONTCARE,\*CREATE,"",split /\s+/,$mysqldump);
 
1111
    MySQLaccess::Debug::Print(2,"PID of open pipe: $pid");
 
1112
    #open(CREATE,"$mysqldump");
 
1113
    @create = <CREATE>;
 
1114
    $create = "@create";
 
1115
    foreach $nerror (sort(keys(%ACCESS_ERR))) {
 
1116
       MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
 
1117
       if (grep(/$ACCESS_ERR{$nerror}/i,$create)) { 
 
1118
          MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
 
1119
          return $nerror; 
 
1120
       }
 
1121
    }
 
1122
    close(CREATE);
 
1123
    close(DONTCARE);
 
1124
 
 
1125
    ## manipulate result for creation-data for temporary table
 
1126
    $create =~ s/CREATE TABLE $tables{$table} \(/CREATE TABLE $table \(/;
 
1127
 
 
1128
    ## recreate temporary table
 
1129
    $query .= "$create\n";
 
1130
    $query .= "select 'ok';";
 
1131
 
 
1132
    ## execute query
 
1133
    print MYSQL_Q "$query\n";
 
1134
#    print STDERR $query;
 
1135
 
 
1136
    $answer = <MYSQL_A>; #answer from mysql
 
1137
#    print STDERR "A>",$answer;
 
1138
    MySQLaccess::Debug::Print(2,"Answer: $answer\n");
 
1139
    foreach $nerror (sort(keys(%ACCESS_ERR))) {
 
1140
#       print STDERR "->$nerror?";
 
1141
       MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
 
1142
       if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { 
 
1143
#          print STDERR "Yes!";
 
1144
          MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
 
1145
          return $nerror; 
 
1146
       }
 
1147
    }
 
1148
 
 
1149
    $delim = <MYSQL_A>; # read header
 
1150
    if ($delim ne "ok\n") {
 
1151
       while (($line=<MYSQL_A>) ne "ok\n")
 
1152
       { MySQLaccess::Debug::Print(3," A> $line"); }
 
1153
        $skip = <MYSQL_A>; # skip result 'ok'
 
1154
    }
 
1155
#    print STDERR "CreateTable done\n";
 
1156
    return 0;
 
1157
}
 
1158
 
 
1159
 
 
1160
# ===========================================================
 
1161
# sub CopyTable()
 
1162
#  Copy the structure and the data of a table to another table
 
1163
# ===========================================================
 
1164
sub CopyTable {
 
1165
    my ($from,$to,$force) = @_;
 
1166
    my @known_tables  = Show_Tables();    
 
1167
    my $query = "";
 
1168
    my $nerror= 0;
 
1169
    my $skip;
 
1170
 
 
1171
#    print STDERR "CopyTable($from,$to)\n";
 
1172
    MySQLaccess::Debug::Print(1,"MySQLaccess::DB::CopyTable($from,$to)");
 
1173
 
 
1174
    ## error-handling
 
1175
    if (!grep(/^$from$/,@known_tables)) { return 'Unknown_table'; }
 
1176
 
 
1177
    ## copy structure 
 
1178
    ## if forced
 
1179
    if (defined($force) and $force) {
 
1180
       return $nerror if ($nerror=CreateTable($to,$force)); 
 
1181
#       print STDERR "Structure copied\n";
 
1182
    }
 
1183
 
 
1184
    ## copy data
 
1185
    $query .= "DELETE FROM $to;";
 
1186
    $query .= "INSERT INTO $to SELECT * FROM $from;";
 
1187
    $query .= "SELECT 'ok';\n";
 
1188
    MySQLaccess::Debug::Print(2,"Query: $query");
 
1189
       
 
1190
    ## execute query
 
1191
    print MYSQL_Q "$query\n";
 
1192
#    print STDERR $query;
 
1193
 
 
1194
    ## check for errors...
 
1195
    my $answer = <MYSQL_A>; #answer from mysql
 
1196
#    print STDERR $answer;
 
1197
    MySQLaccess::Debug::Print(2,"Answer: $answer\n");
 
1198
    foreach $nerror (sort(keys(%ACCESS_ERR))) {
 
1199
       MySQLaccess::Debug::Print(3,"check answer for error $ACCESS_ERR{$nerror}");
 
1200
       if (grep(/$ACCESS_ERR{$nerror}/i,$answer)) { 
 
1201
          MySQLaccess::Debug::Print(2,"Answer contain error [$nerror]");
 
1202
          return $nerror; 
 
1203
       }
 
1204
    }
 
1205
 
 
1206
    my $delim = <MYSQL_A>; # read header
 
1207
#    print STDERR $delim;
 
1208
    if ($delim ne "ok\n") {
 
1209
       while (($line=<MYSQL_A>) ne "ok\n")
 
1210
       { MySQLaccess::Debug::Print(3," A> $line"); }
 
1211
       $skip = <MYSQL_A>; # skip result 'ok'
 
1212
    }
 
1213
 
 
1214
    return 0;
 
1215
}
 
1216
 
 
1217
# ===========================================================
 
1218
# sub LoadTmpTables()
 
1219
#  (Re)load temporary tables with entries of ACL-tables
 
1220
# ===========================================================
 
1221
sub LoadTmpTables {
 
1222
    my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
 
1223
                   $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
 
1224
                   $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
 
1225
                 ); 
 
1226
    my $tbl;
 
1227
    my $nerror;
 
1228
    
 
1229
#    print STDERR "LoadTmpTables:\n";
 
1230
    MySQLaccess::Debug::Print(1,"LoadTmpTables():");
 
1231
    foreach $tbl (keys(%tables)) {
 
1232
#       print STDERR "$tbl -> $tables{$tbl}\n";
 
1233
       MySQLaccess::Debug::Print(2,"Loading table $tbl -> $tables{$tbl}.");
 
1234
       return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
 
1235
    }
 
1236
    return 0;
 
1237
}
 
1238
 
 
1239
# ===========================================================
 
1240
# sub BackupGrantTables()
 
1241
#  Make a backup of the original grant-tables
 
1242
# ===========================================================
 
1243
sub BackupGrantTables {
 
1244
    my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_BCK,
 
1245
                   $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_BCK,
 
1246
                   $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_BCK,
 
1247
                 ); 
 
1248
    my $tbl;
 
1249
    my $nerror;
 
1250
    
 
1251
#    print STDERR "BackupGrantTables:\n";
 
1252
    MySQLaccess::Debug::Print(1,"BackupGrantTables():");
 
1253
    foreach $tbl (keys(%tables)) {
 
1254
#       print STDERR "$tbl -> $tables{$tbl}\n";
 
1255
       MySQLaccess::Debug::Print(2,"Backup table $tbl -> $tables{$tbl}.");
 
1256
       return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
 
1257
    }
 
1258
    return 0;
 
1259
}
 
1260
 
 
1261
# ===========================================================
 
1262
# sub RollbackGrantTables()
 
1263
#  Rollback the backup of the grant-tables
 
1264
# ===========================================================
 
1265
sub RollbackGrantTables {
 
1266
    my %tables = ( $MySQLaccess::ACCESS_U_BCK => $MySQLaccess::ACCESS_U,
 
1267
                   $MySQLaccess::ACCESS_H_BCK => $MySQLaccess::ACCESS_H,
 
1268
                   $MySQLaccess::ACCESS_D_BCK => $MySQLaccess::ACCESS_D,
 
1269
                 ); 
 
1270
    my $tbl;
 
1271
    my $nerror;
 
1272
    
 
1273
#    print STDERR "RollbackGrantTables:\n";
 
1274
    MySQLaccess::Debug::Print(1,"RollbackGrantTables():");
 
1275
    foreach $tbl (keys(%tables)) {
 
1276
#       print STDERR "$tbl -> $tables{$tbl}\n";
 
1277
       MySQLaccess::Debug::Print(2,"Rollback table $tbl -> $tables{$tbl}.");
 
1278
       return $nerror if ($nerror=CopyTable($tbl,$tables{$tbl},'force'));
 
1279
    }
 
1280
    return 0;
 
1281
}
 
1282
 
 
1283
 
 
1284
# ===========================================================
 
1285
# sub CommitGrantTables()
 
1286
#  Copy grant-rules from temporary tables to the ACL-tables
 
1287
# ===========================================================
 
1288
sub CommitGrantTables {
 
1289
    my %tables = ( $MySQLaccess::ACCESS_U => $MySQLaccess::ACCESS_U_TMP,
 
1290
                   $MySQLaccess::ACCESS_H => $MySQLaccess::ACCESS_H_TMP,
 
1291
                   $MySQLaccess::ACCESS_D => $MySQLaccess::ACCESS_D_TMP,
 
1292
                 ); 
 
1293
    my $tbl;
 
1294
    my $query;
 
1295
    my $delim;
 
1296
    my $skip;
 
1297
    my $create;
 
1298
 
 
1299
    print STDERR "CommitGrantTables()\n";
 
1300
    MySQLaccess::Debug::Print(1,"CommitGrantTables():");
 
1301
    
 
1302
    ## Make backup of original grant-tables
 
1303
    MySQLaccess::Debug::Print(2,"Making backup of original grant-tables...");
 
1304
    BackupGrantTables();
 
1305
 
 
1306
    ## Copy data from temporay tables to grant-tables
 
1307
    foreach $tbl (keys(%tables)) {
 
1308
       print STDERR "$tbl -> $tables{$tbl}\n";
 
1309
       MySQLaccess::Debug::Print(2,"Loading data $tables{$tbl} -> $tbl.");
 
1310
       return $nerror if ($nerror=CopyTable($tables{$tbl},$tbl));
 
1311
    }
 
1312
    return 0;
 
1313
}
 
1314
 
 
1315
 
 
1316
# ===========================================================
 
1317
# sub Show_Fields($table): 
 
1318
#  return (a reference to) a hash which holds the names
 
1319
#  of all relevant grant-fields, with their index in the record,
 
1320
#  and (a reference to) an array which holds the fieldnames.
 
1321
# ===========================================================
 
1322
sub Show_Fields {
 
1323
    my ($table) = @_;
 
1324
    my %skip = ('host' => [0,1]
 
1325
               ,'user' => [0,1,2]
 
1326
               ,'db'   => [0,1,2]
 
1327
               );
 
1328
    my %Struct = ();
 
1329
    my @Struct = ();
 
1330
    my $query = "show fields from $table;select 'ok';\n";
 
1331
    my $i=0;
 
1332
    my $line;
 
1333
 
 
1334
#print STDERR $query;
 
1335
    MySQLaccess::Debug::Print(1,"Show_Fields($table):");
 
1336
    MySQLaccess::Debug::Print(2,"SQL: $query");
 
1337
 
 
1338
    print MYSQL_Q "$query";
 
1339
    my $skip = <MYSQL_A>;  #skip header
 
1340
    while (($line=<MYSQL_A>) ne "ok\n")
 
1341
    {
 
1342
#print STDERR ">",$line;
 
1343
        chop($line);
 
1344
        MySQLaccess::Debug::Print(2," $table>: $line");
 
1345
        my ($field,$type,$null,$key,$default,$extra) = split(' ',$line);
 
1346
        $field = ucfirst($field); 
 
1347
        MySQLaccess::Debug::Print(3, " <split: $field - $type - $null - $key - $default - $extra");
 
1348
        if (! grep(/$i/,@{$skip{$table}}) ){
 
1349
           $Struct{$field} = $i; #hash
 
1350
           push(@Struct,$field); #array
 
1351
           MySQLaccess::Debug::Print(3," ==> added column[$i]: $field ($Struct{$field})");
 
1352
        } 
 
1353
        else {
 
1354
           MySQLaccess::Debug::Print(3," ==> skipped column[$i], value=[$field]");
 
1355
        }
 
1356
        $i++;
 
1357
    }
 
1358
 
 
1359
    $skip=<MYSQL_A>;  # Get ok row (found already ok header)
 
1360
 
 
1361
    MySQLaccess::Debug::Print(2, "Array:");
 
1362
    foreach $field (@Struct) { MySQLaccess::Debug::Print(2,"+ $field"); }
 
1363
    MySQLaccess::Debug::Print(2,"Hash:");
 
1364
    foreach $field (keys(%Struct)) { MySQLaccess::Debug::Print(2,"+ $field -> $Struct{$field}"); }
 
1365
 
 
1366
    return  (\%Struct,\@Struct); 
 
1367
}
 
1368
 
 
1369
# ===========================================================
 
1370
# sub Show_Tables(): 
 
1371
#  return (a reference to) an array which holds all 
 
1372
#  known tables.
 
1373
# ===========================================================
 
1374
sub Show_Tables {
 
1375
    my @Tables = ();
 
1376
    my $query = "show tables;select 'ok';\n";
 
1377
    my $i=0;
 
1378
    my $line;
 
1379
 
 
1380
    MySQLaccess::Debug::Print(1,"Show_Tables():");
 
1381
    MySQLaccess::Debug::Print(2,"SQL: $query");
 
1382
 
 
1383
    print MYSQL_Q "$query";
 
1384
    my $skip = <MYSQL_A>;  #skip header
 
1385
    while (($line=<MYSQL_A>) ne "ok\n")
 
1386
    {
 
1387
        chop($line);
 
1388
        push(@Tables,$line); #array
 
1389
        MySQLaccess::Debug::Print(3," ==> added table: $line");
 
1390
    }
 
1391
 
 
1392
    $skip=<MYSQL_A>;  # Get ok row (found already ok header)
 
1393
 
 
1394
    MySQLaccess::Debug::Print(2, "Array:");
 
1395
    foreach $tbl (@Tables) { MySQLaccess::Debug::Print(2,"+ $tbl"); }
 
1396
 
 
1397
    return @Tables; 
 
1398
}
 
1399
 
 
1400
# ======================================
 
1401
# sub Validate_Password($passwd,$host,$user,$encpw)
 
1402
#  Validate the given password 
 
1403
#  for user '$user' 
 
1404
#  connecting from host '$host'
 
1405
# ======================================
 
1406
sub Validate_Password {
 
1407
    my ($password,$host,$user,$encpw) = @_;
 
1408
    my $valid=0;
 
1409
 
 
1410
    MySQLaccess::Debug::Print(1,"Validate_Password($password,$host,$user,$encpw)");
 
1411
    my $sql = "select host,user,password from user having "
 
1412
             ."host='$host' and user='$user' and password='$encpw' "
 
1413
             ."and password=PASSWORD('$password');\n";
 
1414
    $sql .= "select 'ok';\n";
 
1415
    MySQLaccess::Debug::Print(2,"SQL = $sql");
 
1416
    print MYSQL_Q "$sql";
 
1417
    
 
1418
    # if password is valid, at least 1 row returns before we read 'ok'
 
1419
    while ( ($line=<MYSQL_A>) ne "ok\n") {
 
1420
      MySQLaccess::Debug::Print(2," A> $line");
 
1421
      $valid = defined($line); 
 
1422
    }
 
1423
    my $skip = <MYSQL_A>; # read 'ok'
 
1424
 
 
1425
    return $valid;
 
1426
}
 
1427
 
 
1428
 
 
1429
# ==========================================================
 
1430
# sub Sort_fields: (rewritten by psmith)
 
1431
#  Build the query for an ordered list of entries
 
1432
# ==========================================================
 
1433
sub Sort_fields {
 
1434
  my ($start, $end, $sofar, $this, @rest) = (@_);
 
1435
  my @where = ("((FIELD not like '\\%') AND (FIELD <> ''))",
 
1436
               "((FIELD like '%\\%%') OR (FIELD like '%\\_%'))",
 
1437
               "(FIELD = '')");
 
1438
  my $res = '';
 
1439
 
 
1440
  $this or return ("$start $sofar $end");
 
1441
 
 
1442
  $sofar .= ' AND ' if $sofar;
 
1443
 
 
1444
  foreach $w (@where) {
 
1445
    my $f = $w;
 
1446
    $f =~ s/FIELD/$this/g;
 
1447
 
 
1448
    $res .= Sort_fields($start, $end, "$sofar$f", @rest);
 
1449
  }
 
1450
 
 
1451
  return ($res);
 
1452
}
 
1453
 
 
1454
# ===========================================================
 
1455
# sub Sort_table: (rewritten by psmith)
 
1456
#  return all entries in the given table,
 
1457
#  in an ordered fashion
 
1458
# ===========================================================
 
1459
sub Sort_table {
 
1460
    my ($tbl, @order) = @_;
 
1461
    my @res=();
 
1462
 
 
1463
    # as long as there's no full where clause (Distrib 3.20)...
 
1464
    # use having :-(
 
1465
    # NOTE: this clause WILL NOT work on 3.21, because of the
 
1466
    # order of 'ORDER BY' and 'HAVING'
 
1467
    my $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl ";
 
1468
    $start   .= 'ORDER BY ' . join(',', @order) ." HAVING ";
 
1469
    my $end   = ";\n";
 
1470
 
 
1471
    # server version 3.21 has a full where clause :-)
 
1472
    if ($MySQLaccess::Host::SERVER >= '3.21') {
 
1473
    # print "+++USING FULL WHERE CLAUSE+++\n";
 
1474
       $start = "SELECT *,UCASE(host) as ucase_host FROM $tbl WHERE ";
 
1475
       $end = ' ORDER BY ' . join(',', @order) . ";\n";
 
1476
    }
 
1477
 
 
1478
    MySQLaccess::Debug::Print(1,"Sort_table():");
 
1479
    MySQLaccess::Debug::Print(2,"Sorting table $tbl by `@order'");
 
1480
 
 
1481
    my $tmp;
 
1482
    foreach $tmp (@order)
 
1483
    {
 
1484
      $tmp="UCASE(host)" if ($tmp eq "ucase_host");
 
1485
    }
 
1486
    my $query  = Sort_fields($start, $end, '', @order);
 
1487
    $query    .= "select 'ok';\n";
 
1488
    MySQLaccess::Debug::Print(2,"Query: $query");
 
1489
 
 
1490
    print MYSQL_Q "$query\n";
 
1491
 
 
1492
    my $delim = <MYSQL_A>; # read header
 
1493
    MySQLaccess::Debug::Print(3," A> $delim");
 
1494
    if ($delim ne "ok\n") {
 
1495
       if ($delim =~ /^ERROR/) {
 
1496
       push(@MySQLaccess::Grant::Error,'use_old_server');
 
1497
       MySQLaccess::Report::Print_Error_Messages() ;
 
1498
       exit 1;
 
1499
       }
 
1500
       while (($line=<MYSQL_A>) ne "ok\n")
 
1501
       {
 
1502
           MySQLaccess::Debug::Print(3," A> $line");
 
1503
           push(@res,$line);
 
1504
       }
 
1505
    }
 
1506
    my $skip = <MYSQL_A>; # skip result 'ok'
 
1507
 
 
1508
    # remove columnheaders from output
 
1509
    @res = grep(!/^\Q$delim\E$/, @res);
 
1510
    # remove trailing \n from each returned record
 
1511
    chomp(@res); 
 
1512
    # each record has 1 field to much : ucase_host
 
1513
    @res = grep { /(.*)\t.*$/; $_ = $1; } @res;
 
1514
 
 
1515
    MySQLaccess::Debug::Print(2,"Result of sorted table $tbl:");
 
1516
    foreach $line (@res) { MySQLaccess::Debug::Print(2," >>$line"); }
 
1517
    return @res;
 
1518
}
 
1519
 
 
1520
# ===========================================================
 
1521
# sub Get_All_db(template): 
 
1522
#  return all db the grant-tables are working on,
 
1523
#  which conform to the template
 
1524
# ===========================================================
 
1525
sub Get_All_dbs {
 
1526
   my ($template,$tmp) = @_;
 
1527
   my @db=();
 
1528
   my $aref;
 
1529
 
 
1530
   # working with  temporary tables or production tables
 
1531
   if (defined($tmp) and $tmp) {
 
1532
      $aref = \@MySQLaccess::Grant::sorted_db_tmp_table ;
 
1533
   }
 
1534
   else {
 
1535
      $aref = \@MySQLaccess::Grant::sorted_db_table;
 
1536
   }
 
1537
 
 
1538
   MySQLaccess::Debug::Print(1," template=[$template]");
 
1539
 
 
1540
   # get all db for which access-rights can be calculated,
 
1541
   # which conform to the template.
 
1542
   # !! these db's don't have to exist yet, so it's not
 
1543
   #    enough to look which db already exist on the system
 
1544
   $reg_expr = $template;
 
1545
   if ($template =~ /[\*\?]/) {
 
1546
      $reg_expr =~ tr/*?/%_/;
 
1547
      #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
 
1548
   }
 
1549
   $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
 
1550
 
 
1551
   if ( ! ($template =~ /[\*\?%_]/) ) {
 
1552
      push(@db,$template);
 
1553
      return \@db;
 
1554
   }
 
1555
 
 
1556
   MySQLaccess::Debug::Print(2,"#Reading db-table...");
 
1557
   foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_db_table) {
 
1558
    my @record=split(/\t/,$record);
 
1559
    my $db = $record[1];
 
1560
    MySQLaccess::Debug::Print(2,"> $db ");
 
1561
    if ( (!grep(/$db/i,@db)) and ($db =~/$reg_expr/i) ) {
 
1562
       push(@db,$db);
 
1563
       MySQLaccess::Debug::Print(2,"added");
 
1564
    } 
 
1565
    else {
 
1566
       MySQLaccess::Debug::Print(2,"skipped");
 
1567
    }
 
1568
   }
 
1569
   # if no rule is found for a certain db in the db-table,
 
1570
   # the rights of the user are used, so we should inform
 
1571
   # the user for
 
1572
   if (!grep(/^%$/,@db)) { push(@db,"$MySQLaccess::NEW_DB"); }
 
1573
   return \@db;
 
1574
}
 
1575
 
 
1576
# ===========================================================
 
1577
# sub Get_All_users(template): 
 
1578
#  return all users the grant-tables are working on,
 
1579
#  which conform to the template
 
1580
# ===========================================================
 
1581
sub Get_All_users {
 
1582
   ($template,$tmp) = @_; # nog verder uitwerken!!!
 
1583
   my @user=();
 
1584
   my $aref;
 
1585
 
 
1586
   # working with  temporary tables or production tables
 
1587
   if (defined($tmp) and $tmp) {
 
1588
      $aref = \@MySQLaccess::Grant::sorted_user_tmp_table ;
 
1589
   }
 
1590
   else {
 
1591
      $aref = \@MySQLaccess::Grant::sorted_user_table;
 
1592
   }
 
1593
 
 
1594
   MySQLaccess::Debug::Print(1,"Debug Get_All_users:");
 
1595
   # get all db for which access-rights can be calculated.
 
1596
   # !! these db's don't have to exist yet, so it's not
 
1597
   #    enough to look which db already exist on the system
 
1598
   $reg_expr = $template;
 
1599
   if ($template =~ /[\*\?]/) {
 
1600
      $reg_expr =~ tr/*?/%_/;
 
1601
      #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
 
1602
   }
 
1603
   $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
 
1604
 
 
1605
   if ( ! ($template =~ /[\*\?%_]/) ) {
 
1606
      push(@user,$template);
 
1607
      return \@user;
 
1608
   }
 
1609
 
 
1610
   MySQLaccess::Debug::Print(2,"#Reading user-table...");
 
1611
   foreach $record (@{$aref}) { #MySQLaccess::Grant::sorted_user_table) {
 
1612
    my @record=split(/\t/,$record);
 
1613
    my $user = $record[1];
 
1614
    MySQLaccess::Debug::Print(2,"> $user ");
 
1615
    if ( (!grep(/$user/,@user)) and ($user=~/$reg_expr/)) {
 
1616
       push(@user,$user);
 
1617
       MySQLaccess::Debug::Print(2, "added");
 
1618
    } 
 
1619
    else {
 
1620
       MySQLaccess::Debug::Print(2, "skipped");
 
1621
    }
 
1622
   }
 
1623
   # Any user means also:
 
1624
   # - the 'empty' user, ie without supplying a username
 
1625
   # - any user still to be defined/created
 
1626
   #push(@user,'');               #without_suplying_a_username
 
1627
   push(@user,"$MySQLaccess::NEW_USER");
 
1628
   #push(@Warnings,'minimum_priv');
 
1629
   return \@user;
 
1630
}
 
1631
 
 
1632
# ===========================================================
 
1633
# sub Get_All_hosts(template): 
 
1634
#  return all hosts the grant-tables are working on,
 
1635
#  which conform to the template
 
1636
# ===========================================================
 
1637
sub Get_All_hosts {
 
1638
   my ($template,$tmp) = @_;
 
1639
   my @host=();
 
1640
   my $aref;
 
1641
   my $aref1;
 
1642
 
 
1643
   # working with  temporary tables or production tables
 
1644
   if (defined($tmp) and $tmp) {
 
1645
      $aref = \@MySQLaccess::Grant::sorted_host_tmp_table ;
 
1646
      $aref1= \@MySQLaccess::Grant::sorted_db_tmp_table ;
 
1647
   }
 
1648
   else {
 
1649
      $aref = \@MySQLaccess::Grant::sorted_host_table;
 
1650
      $aref1= \@MySQLaccess::Grant::sorted_db_table ;
 
1651
   }
 
1652
 
 
1653
   MySQLaccess::Debug::Print(1, "Debug Get_All_hosts:");
 
1654
   # get all db for which access-rights can be calculated.
 
1655
   # !! these db's don't have to exist yet, so it's not
 
1656
   #    enough to look which db already exist on the system
 
1657
   $reg_expr = $template;
 
1658
   if ($template =~ /[\*\?]/) {
 
1659
      $reg_expr =~ tr/*?/%_/;
 
1660
      #$reg_expr = MySQLaccess::Wildcards::Wild2Reg($template);
 
1661
   }
 
1662
   $reg_expr = MySQLaccess::Wildcards::SQL2Reg("$reg_expr");
 
1663
 
 
1664
   if ( ! ($template =~ /[\*\?%_]/) ) {
 
1665
      push(@host,$template);
 
1666
      return \@host;
 
1667
   }
 
1668
 
 
1669
   MySQLaccess::Debug::Print(1, "#Reading db-table...");
 
1670
   foreach $record (@{$aref1}) { #MySQLaccess::Grant::sorted_db_table) {
 
1671
    my @record=split(/\t/,$record);
 
1672
    my $host = $record[0];
 
1673
    MySQLaccess::Debug::Print(2, "> $host ");
 
1674
    if (! grep(/$host/i,@host)) {
 
1675
       push(@host,$host);
 
1676
       MySQLaccess::Debug::Print(2, "added");
 
1677
    } 
 
1678
    else {
 
1679
       MySQLaccess::Debug::Print(2, "skipped");
 
1680
    }
 
1681
   }
 
1682
   MySQLaccess::Debug::Print(1, "#Reading host-table...");
 
1683
   foreach $record (@{$aref}) {
 
1684
    my @record=split(/\t/,$record);
 
1685
    my $host = $record[0];
 
1686
    MySQLaccess::Debug::Print(2, "> $host ");
 
1687
    if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
 
1688
       push(@host,$host);
 
1689
       MySQLaccess::Debug::Print(2, "added");
 
1690
    } 
 
1691
    else {
 
1692
       MySQLaccess::Debug::Print(2, "skipped");
 
1693
    }
 
1694
   }
 
1695
   # DOUBT:
 
1696
   #print "#Reading user-table...\n" if ($DEBUG>1);
 
1697
   #foreach $record (@MySQLaccess::Grant::sorted_user_table) {
 
1698
   # my @record=split(/\t/,$record);
 
1699
   # my $host = $record[0];
 
1700
   # print "> $host " if ($DEBUG>2);
 
1701
   # if ( (!grep(/$host/,@host)) and ($host=~/$reg_expr/)) {
 
1702
   #    push(@host,$host);
 
1703
   #    print "added\n" if ($DEBUG>2);
 
1704
   # } 
 
1705
   # else {
 
1706
   #    print "skipped\n" if ($DEBUG>2);
 
1707
   # }
 
1708
   #}
 
1709
   # Any host also means:
 
1710
   # - any host still to be defined/created
 
1711
   #push(@host,"any_other_host");
 
1712
 
 
1713
   @host = sort(@host);
 
1714
   return \@host;
 
1715
}
 
1716
 
 
1717
 
 
1718
##########################################################################
 
1719
package MySQLaccess::Grant;
 
1720
##############
 
1721
BEGIN {
 
1722
    $DEBUG     = 0;
 
1723
    $DEBUG     = $MySQLaccess::DEBUG unless ($DEBUG);
 
1724
}
 
1725
 
 
1726
 
 
1727
 
 
1728
# ===========================================================
 
1729
# sub Diff_Privileges()
 
1730
#  Calculate diff between temporary and original grant-tables
 
1731
# ===========================================================
 
1732
sub Diff_Privileges {
 
1733
   my @before=();
 
1734
   my @after =();
 
1735
   my @diffs =();
 
1736
 
 
1737
   # -----------------------------
 
1738
   # Build list of users,dbs,hosts
 
1739
   # to process...
 
1740
   my @all_dbs   = @{MySQLaccess::DB::Get_All_dbs('*')};
 
1741
   my @all_users = @{MySQLaccess::DB::Get_All_users('*')};
 
1742
   my @all_hosts = @{MySQLaccess::DB::Get_All_hosts('*')};
 
1743
   #if EDIT-mode
 
1744
   my @all_dbs_tmp   = @{MySQLaccess::DB::Get_All_dbs('*','tmp')};
 
1745
   my @all_users_tmp = @{MySQLaccess::DB::Get_All_users('*','tmp')};
 
1746
   my @all_hosts_tmp = @{MySQLaccess::DB::Get_All_hosts('*','tmp')};
 
1747
 
 
1748
 
 
1749
   my %Access;
 
1750
   # ------------------------------------
 
1751
   # Build list of priv. for grant-tables
 
1752
   foreach $host (@all_hosts) {
 
1753
     foreach $user (@all_users) {
 
1754
       foreach $db (@all_dbs) {
 
1755
         MySQLaccess::Grant::Initialize();
 
1756
         %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db);      
 
1757
         push(@before,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access));
 
1758
       }
 
1759
     }
 
1760
   }
 
1761
 
 
1762
   # ----------------------------------
 
1763
   # Build list of priv. for tmp-tables
 
1764
   foreach $host (@all_hosts_tmp) {
 
1765
     foreach $user (@all_users_tmp) {
 
1766
       foreach $db (@all_dbs_tmp) {
 
1767
         MySQLaccess::Grant::Initialize('tmp');
 
1768
         %Access = MySQLaccess::Grant::Get_Access_Rights($host,$user,$db,'tmp');        
 
1769
         push(@after,MySQLaccess::Report::Raw_Report($host,$user,$db,\%Access));
 
1770
       }
 
1771
     }
 
1772
   }
 
1773
 
 
1774
   # ----------------------------------
 
1775
   # Write results to temp-file to make
 
1776
   # DIFF
 
1777
   @before = sort(@before);
 
1778
   @after  = sort(@after);
 
1779
 
 
1780
   ($hb, $before) = tempfile("$MySQLaccess::script.XXXXXX") or
 
1781
    push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!");
 
1782
   ($ha, $after)  = tempfile("$MySQLaccess::script.XXXXXX") or
 
1783
    push(@MySQLaccess::Report::Errors,"Can't create temporary file: $!");
 
1784
 
 
1785
   print $hb join("\n",@before);
 
1786
   print $ha join("\n",@after);
 
1787
   close $hb;
 
1788
   close $ha;
 
1789
 
 
1790
   # ----------------------------------
 
1791
   # compute difference
 
1792
   my $cmd="$MySQLaccess::DIFF $before $after |";
 
1793
   open(DIFF,"$cmd");
 
1794
   @diffs = <DIFF>;
 
1795
   @diffs = grep(/[<>]/,@diffs);
 
1796
   chomp(@diffs);
 
1797
   close(DIFF);
 
1798
 
 
1799
   # ----------------------------------
 
1800
   # cleanup temp. files
 
1801
   unlink($before);
 
1802
   unlink($after);
 
1803
 
 
1804
   return \@diffs;
 
1805
}
 
1806
 
 
1807
# ===========================================================
 
1808
# sub Initialize()
 
1809
#
 
1810
# ===========================================================
 
1811
sub Initialize {
 
1812
    %MySQLaccess::Grant::Access       = %{Default_Access_Rights()};
 
1813
    @MySQLaccess::Grant::Errors       = ();
 
1814
    @MySQLaccess::Grant::Warnings     = ();
 
1815
    @MySQLaccess::Grant::Notes        = ();
 
1816
    # -----
 
1817
    # rules
 
1818
    $MySQLaccess::Grant::Rules{'user'} = 'no_rule_found';
 
1819
    $MySQLaccess::Grant::Rules{'db'}   = 'no_rule_found';
 
1820
    $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
 
1821
    $MySQLaccess::Grant::full_access   = 1;
 
1822
 
 
1823
    $MySQLaccess::Grant::process_host_table = 0;
 
1824
    return 1;
 
1825
}
 
1826
 
 
1827
# ===========================================================
 
1828
# sub ReadTables()
 
1829
#  
 
1830
# ===========================================================
 
1831
sub ReadTables {
 
1832
    my ($tmp) = @_;
 
1833
    my ($HOST,$DB,$USER);
 
1834
    my @tables;
 
1835
 
 
1836
    # build list of available tables
 
1837
    @tables = MySQLaccess::DB::Show_Tables();
 
1838
 
 
1839
    # reading production grant-tables or temporary tables?
 
1840
    $tmp = (defined($tmp) and $tmp) ? 1 : 0;
 
1841
    if ($tmp) { #reading temporary tables
 
1842
       $HOST=$MySQLaccess::ACCESS_H_TMP;
 
1843
       $DB  =$MySQLaccess::ACCESS_D_TMP;
 
1844
       $USER=$MySQLaccess::ACCESS_U_TMP;
 
1845
 
 
1846
       # ----------------------------
 
1847
       # do tables exist?
 
1848
       if (!grep(/$HOST/,@tables)) { MySQLaccess::DB::CreateTable($HOST); }
 
1849
       if (!grep(/$USER/,@tables)) { MySQLaccess::DB::CreateTable($USER); }
 
1850
       if (!grep(/$DB/,@tables))   { MySQLaccess::DB::CreateTable($DB); }
 
1851
 
 
1852
       MySQLaccess::Debug::Print(1,"Finding fields in tmp-ACL files:");
 
1853
       # -----------------------------
 
1854
       # Get record-layout 
 
1855
       my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
 
1856
       my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
 
1857
       my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
 
1858
       %MySQLaccess::Grant::H_tmp = %{$h1}; @MySQLaccess::Grant::H_tmp = @{$h2};
 
1859
       %MySQLaccess::Grant::D_tmp = %{$d1}; @MySQLaccess::Grant::D_tmp = @{$d2};
 
1860
       %MySQLaccess::Grant::U_tmp = %{$u1}; @MySQLaccess::Grant::U_tmp = @{$u2};
 
1861
 
 
1862
#       @MySQLaccess::Grant::Privileges_tmp=@{Make_Privlist()};
 
1863
#
 
1864
       MySQLaccess::Debug::Print(1, "Reading sorted temp-tables:");
 
1865
       @MySQLaccess::Grant::sorted_db_tmp_table  = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
 
1866
       @MySQLaccess::Grant::sorted_host_tmp_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
 
1867
       @MySQLaccess::Grant::sorted_user_tmp_table= defined($MySQLaccess::Param{'password'}) ?
 
1868
                           MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
 
1869
                           MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
 
1870
    }
 
1871
    else {      #reading production grant-tables
 
1872
       $HOST=$MySQLaccess::ACCESS_H;
 
1873
       $DB  =$MySQLaccess::ACCESS_D;
 
1874
       $USER=$MySQLaccess::ACCESS_U;
 
1875
 
 
1876
       MySQLaccess::Debug::Print(1,"Finding fields in ACL files:");
 
1877
       # -----------------------------
 
1878
       # Get record-layout 
 
1879
       my ($h1,$h2) = MySQLaccess::DB::Show_Fields($HOST);
 
1880
       my ($d1,$d2) = MySQLaccess::DB::Show_Fields($DB);
 
1881
       my ($u1,$u2) = MySQLaccess::DB::Show_Fields($USER);
 
1882
       %MySQLaccess::Grant::H = %{$h1}; @MySQLaccess::Grant::H = @{$h2};
 
1883
       %MySQLaccess::Grant::D = %{$d1}; @MySQLaccess::Grant::D = @{$d2};
 
1884
       %MySQLaccess::Grant::U = %{$u1}; @MySQLaccess::Grant::U = @{$u2};
 
1885
 
 
1886
       @MySQLaccess::Grant::Privileges=@{Make_Privlist()};
 
1887
 
 
1888
       MySQLaccess::Debug::Print(1, "Reading sorted tables:");
 
1889
       @MySQLaccess::Grant::sorted_db_table  = MySQLaccess::DB::Sort_table($DB, 'ucase_host', 'user', 'db');
 
1890
       @MySQLaccess::Grant::sorted_host_table= MySQLaccess::DB::Sort_table($HOST, 'ucase_host', 'db');
 
1891
       @MySQLaccess::Grant::sorted_user_table= defined($MySQLaccess::Param{'password'}) ?
 
1892
                           MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user', 'password'):
 
1893
                           MySQLaccess::DB::Sort_table($USER, 'ucase_host', 'user');
 
1894
    }
 
1895
 
 
1896
    return 0;
 
1897
}
 
1898
 
 
1899
# ===========================================================
 
1900
# sub Get_Access_Rights(host,user,db)
 
1901
#  report the access_rights for the tuple ($host,$user,$db).
 
1902
# ===========================================================
 
1903
sub Get_Access_Rights {
 
1904
  local ($host,$user,$db,$tmp) = @_;
 
1905
 
 
1906
   my $aref_user;
 
1907
   my $aref_host;
 
1908
   my $aref_db;
 
1909
   # working with  temporary tables or production tables
 
1910
   if (defined($tmp) and $tmp) {
 
1911
      $aref_user = \@MySQLaccess::Grant::sorted_user_tmp_table;
 
1912
      $aref_host = \@MySQLaccess::Grant::sorted_host_tmp_table;
 
1913
      $aref_db   = \@MySQLaccess::Grant::sorted_db_tmp_table;   
 
1914
   }
 
1915
   else {
 
1916
      $aref_user = \@MySQLaccess::Grant::sorted_user_table;
 
1917
      $aref_host = \@MySQLaccess::Grant::sorted_host_table;
 
1918
      $aref_db   = \@MySQLaccess::Grant::sorted_db_table; 
 
1919
   }
 
1920
 
 
1921
 
 
1922
  my ($refrecord,$refgrant);
 
1923
  my ($_host_,$_user_,$encpw_);
 
1924
  my %_Access_;
 
1925
 
 
1926
  MySQLaccess::Debug::Print(1, "for ($host,$user,$db):");  
 
1927
 
 
1928
  # ******************************************************************************
 
1929
  # Create default access-rights
 
1930
  #   default access-rights are no access at all!!
 
1931
 
 
1932
 
 
1933
  # ******************************************************************************
 
1934
  # get hostname for IP-address
 
1935
  # get IP-address for hostname
 
1936
  local $host_name = MySQLaccess::Host::IP2Name($host);
 
1937
  local $host_ip   = MySQLaccess::Host::Name2IP($host);
 
1938
 
 
1939
  MySQLaccess::Debug::Print(3,"host=$host, hostname=$host_name, host-ip =$host_ip");
 
1940
  MySQLaccess::Debug::Print(3,"user=$user");
 
1941
  MySQLaccess::Debug::Print(3,"db  =$db");
 
1942
 
 
1943
  # ***********************************************************************
 
1944
  # retrieve information on USER
 
1945
  #  check all records in mysql::user for matches with the tuple (host,user)
 
1946
  # ***********************************************************************
 
1947
  #    4.OR (add) the privileges for the user from the "user" table.
 
1948
  #     (add all privileges which is "Y" in "user")
 
1949
  ($refrecord,$refgrant)    = Get_grant_from_user($host,$user,$aref_user);
 
1950
  ($_host_,$_user_,$encpw_) = @{$refrecord};
 
1951
  %_access_                 = %{$refgrant};
 
1952
 
 
1953
  foreach $field (keys(%U)) { ##only priv. set in user-table
 
1954
    $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
 
1955
  }
 
1956
 
 
1957
  if ($_user_ eq $MySQLaccess::NEW_USER) { 
 
1958
     push(@Warnings,'minimum_priv');
 
1959
  }
 
1960
  if ($_user_ ne $user) {
 
1961
     $user=$_user_;
 
1962
     push(@Warnings,'anonymous_access');
 
1963
  }
 
1964
 
 
1965
  # *******************************************************
 
1966
  #  Validate password if this has been asked to do
 
1967
  # *******************************************************
 
1968
  if (defined($password)) {
 
1969
     $valid = Validate_Password($password,$_host_,$_user_,$_encpw_,$aref_user);
 
1970
     if (!$valid) { push(@Errors,'invalid_password'); }
 
1971
     else         { push(@Notes,'valid_password'); }
 
1972
  }
 
1973
 
 
1974
  # ******************************************************************************
 
1975
  # retrieve information on DB
 
1976
  #  check all records in mysql::db for matches with the triple (host,db,user)
 
1977
  #  first match is used.
 
1978
  # ******************************************************************************
 
1979
  #    2.Get grant for user from the "db" table.
 
1980
 
 
1981
  ($refrecord,$refgrant)=Get_grant_from_db($host,$db,$user,$aref_db); #set process_host_table
 
1982
  ($_host_,$_user_,$encpw_) = @{$refrecord};
 
1983
  %_access_                 = %{$refgrant};
 
1984
 
 
1985
  foreach $field (keys(%D)) { ##only priv. set in db-table
 
1986
    $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} or $_access_{$field});
 
1987
  }
 
1988
 
 
1989
  # ***********************************************************************
 
1990
  # retrieve information on HOST
 
1991
  #  check all records in mysql::host for matches with the tuple (host,db)
 
1992
  #
 
1993
  #  ' The host table is mainly to maintain a list of "secure" servers. '
 
1994
  # ***********************************************************************
 
1995
  #    3.If hostname is "empty" for the found entry, AND the privileges with
 
1996
  #      the privileges for the host in "host" table.
 
1997
  #      (Remove all which is not "Y" in both)
 
1998
 
 
1999
  if ($MySQLaccess::Grant::process_host_table) {
 
2000
     ($refrecord,$refgrant)=Get_grant_from_host($host,$db,$aref_host);
 
2001
     ($_host_,$_user_,$encpw_) = @{$refrecord};
 
2002
     %_access_                 = %{$refgrant};
 
2003
 
 
2004
     foreach $field (keys(%H)) {  ##only priv. set in host-table 
 
2005
       $MySQLaccess::Grant::Access{$field} = ($MySQLaccess::Grant::Access{$field} and $_access_{$field});
 
2006
     } 
 
2007
  }
 
2008
 
 
2009
  MySQLaccess::Debug::Print(1,"done for ($host,$user,$db)");
 
2010
  return %MySQLaccess::Grant::Access;
 
2011
}
 
2012
 
 
2013
# ####################################
 
2014
# FINDING THE RIGHT GRANT-RULE
 
2015
# ==========================================================
 
2016
# sub Get_grant_from_user:
 
2017
# ==========================================================
 
2018
sub Get_grant_from_user {
 
2019
  my ($host,$user,$aref) = @_;
 
2020
 
 
2021
  MySQLaccess::Debug::Print(1, "");
 
2022
  MySQLaccess::Debug::Print(1, "(host=$host,user=$user)");
 
2023
 
 
2024
  my %Access_user = %{Default_Access_Rights()}; 
 
2025
 
 
2026
  my $rule_found=0;
 
2027
  my @record = ();
 
2028
  my $record;
 
2029
 
 
2030
  foreach $record (@{$aref}) {
 
2031
    $MySQLaccess::Grant::full_access=0;
 
2032
    MySQLaccess::Debug::Print(3, "Record= $record");
 
2033
    @record=split(/\t/,$record);
 
2034
 
 
2035
    # check host and db
 
2036
    # with possible wildcards in field
 
2037
    # replace mysql-wildcards by reg-wildcards
 
2038
    my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
 
2039
    my $user_tpl = $record[1]; #user field isn't pattern-matched!!
 
2040
    my $passwd   = $record[2];
 
2041
 
 
2042
    MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
 
2043
    MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[1] -> $user_tpl");
 
2044
    MySQLaccess::Debug::Print(3, "=>password : read=$record[2] -> $passwd");
 
2045
 
 
2046
 
 
2047
    if ( MySQLaccess::Host::MatchTemplate($host,$host_tpl) and
 
2048
         MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user)
 
2049
       ) 
 
2050
    {
 
2051
  MySQLaccess::Debug::Print(2, "FOUND!!");
 
2052
        if ($passwd eq '') { push(@Warnings,'insecure_user');  }
 
2053
        else               { push(@Notes,'password_required'); }
 
2054
 
 
2055
        foreach $field (keys(%U)) {
 
2056
          $Access_user{$field} = $MySQLaccess::Report::Answer{$record[$U{$field}]};
 
2057
        }
 
2058
        #print "\n" if $DEBUG;
 
2059
        $MySQLaccess::Grant::Rules{'user'} = $record;
 
2060
        $rule_found=1;
 
2061
        last;
 
2062
    }
 
2063
  }
 
2064
 
 
2065
  # -------------------------------
 
2066
  #  setting privileges to user-priv
 
2067
  MySQLaccess::Debug::Print(2, "Rights after parsing user-table..:");
 
2068
  if (! $rule_found ) {
 
2069
     @record=();
 
2070
     MySQLaccess::Debug::Print(2, "NO record found in the user-table!!");
 
2071
  }
 
2072
  else {
 
2073
     MySQLaccess::Debug::Print(2, "Selected record=@record");
 
2074
     MySQLaccess::Debug::Print(2, "<=?=> $record");
 
2075
  }
 
2076
 
 
2077
  MySQLaccess::Debug::Print(1, "returning @record");
 
2078
 
 
2079
  return (\@record,\%Access_user); #matching record in user-table
 
2080
}
 
2081
 
 
2082
# ==========================================================
 
2083
# sub Get_grant_from_db:
 
2084
# ==========================================================
 
2085
sub Get_grant_from_db {
 
2086
  my ($host,$db,$user,$aref) = @_;
 
2087
 
 
2088
  MySQLaccess::Debug::Print(1, "(host=$host,user=$user,db=$db)");
 
2089
 
 
2090
  my %Access_db    = %{Default_Access_Rights()};
 
2091
  my $rule_found=0;
 
2092
 
 
2093
  foreach $record (@{$aref}) {
 
2094
    $full_access=0;
 
2095
    MySQLaccess::Debug::Print(2, "Read db: $record");
 
2096
    @record=split(/\t/,$record);
 
2097
 
 
2098
    # check host and db
 
2099
    # with possible wildcards in field
 
2100
    # replace mysql-wildcards by reg-wildcards
 
2101
    my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
 
2102
    my $db_tpl   = MySQLaccess::Wildcards::SQL2Reg($record[1]);
 
2103
    my $user_tpl = $record[2]; #user field isn't pattern matched!!
 
2104
    MySQLaccess::Debug::Print(3, "=>host_tpl : read=$record[0] -> converted=$host_tpl");
 
2105
    MySQLaccess::Debug::Print(3, "=>db_tpl   : read=$record[1] -> $db_tpl");
 
2106
    MySQLaccess::Debug::Print(3, "=>user_tpl : read=$record[2] -> $user_tpl");
 
2107
 
 
2108
    if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
 
2109
           or  MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
 
2110
           or  MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
 
2111
         and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) )
 
2112
         and ( MySQLaccess::Wildcards::MatchTemplate($user_tpl,$user) ) ) {
 
2113
 
 
2114
      $MySQLaccess::Grant::process_host_table = ($record[0] eq '');
 
2115
 
 
2116
      if ($user_tpl eq '') { push(@Warnings,'public_database'); }
 
2117
 
 
2118
      foreach $field (keys(%D)) {
 
2119
        $Access_db{$field} = $MySQLaccess::Report::Answer{$record[$D{$field}]};
 
2120
      }
 
2121
      $rule_found=1;
 
2122
      $MySQLaccess::Grant::Rules{'db'} = $record;
 
2123
      last;
 
2124
    }
 
2125
  }
 
2126
 
 
2127
  # -------------------------------
 
2128
  #  setting privileges to db-priv
 
2129
  MySQLaccess::Debug::Print(2, "Rights after parsing db-table..:");
 
2130
  if (! $rule_found ) {
 
2131
    MySQLaccess::Debug::Print(2, "NO rule found in db-table => no access granted!!");
 
2132
  }
 
2133
 
 
2134
  return (\@record,\%Access_db);
 
2135
}
 
2136
 
 
2137
# ==========================================================
 
2138
# sub Get_grant_from_host:
 
2139
# ==========================================================
 
2140
sub Get_grant_from_host {
 
2141
  my ($host,$db,$aref) = @_;
 
2142
 
 
2143
  MySQLaccess::Debug::Print(1, "Get_grant_from_host()");
 
2144
 
 
2145
  my %Access_host = %{Default_Access_Rights()};
 
2146
 
 
2147
  # the host-table doesn't have to be processed if the host-field
 
2148
  # in the db-table isn't empty
 
2149
  if (!$MySQLaccess::Grant::process_host_table) {
 
2150
    MySQLaccess::Debug::Print(2, ">> Host-table doesn't have to be processed!!");
 
2151
    $MySQLaccess::Grant::Rules{'host'} = 'no_equiv_host';
 
2152
    return ([],\%Access_host);
 
2153
  }
 
2154
 
 
2155
  my $rule_found=0;
 
2156
  my @record = ();
 
2157
 
 
2158
  foreach $record (@{$aref}) {
 
2159
    $full_access=0;
 
2160
    MySQLaccess::Debug::Print(2, "host: $record");
 
2161
    @record=split(/\t/,$record);
 
2162
 
 
2163
    # check host and db
 
2164
    # with possible wildcards in field
 
2165
    # replace mysql-wildcards by reg-wildcards
 
2166
    my $host_tpl = MySQLaccess::Wildcards::SQL2Reg($record[0]);
 
2167
    my $db_tpl   = MySQLaccess::Wildcards::SQL2Reg($record[1]);
 
2168
    MySQLaccess::Debug::Print(3, "=>host_tpl : $record[0] -> $host_tpl");
 
2169
    MySQLaccess::Debug::Print(3, "=>db_tpl   : $record[1] -> $db_tpl");
 
2170
 
 
2171
    if ( ( MySQLaccess::Host::Is_localhost($host_tpl)
 
2172
           or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_name)
 
2173
           or MySQLaccess::Wildcards::MatchTemplate($host_tpl,$host_ip) )
 
2174
         and ( MySQLaccess::Wildcards::MatchTemplate($db_tpl,$db) ) ) {
 
2175
 
 
2176
      $MySQLaccess::Grant::Rules{'host'} = $record;
 
2177
      $rule_found=1;
 
2178
      foreach $field (keys(%H)) {
 
2179
        $Access_host{$field} = $MySQLaccess::Report::Answer{$record[$H{$field}]};
 
2180
      }
 
2181
      last;
 
2182
    }
 
2183
  }
 
2184
 
 
2185
  # -------------------------------
 
2186
  #  setting privileges to host-priv
 
2187
  MySQLaccess::Debug::Print(2, "Rights after parsing host-table..:");
 
2188
  if (! $rule_found ) {
 
2189
     @record=();
 
2190
     MySQLaccess::Debug::Print(2, "NO restrictions found in the host-table!!");
 
2191
  }
 
2192
 
 
2193
  # --------------------------------
 
2194
  # debugging access-rights in db 
 
2195
 
 
2196
  return (\@record,\%Access_host); #matching record in host-table
 
2197
}
 
2198
 
 
2199
 
 
2200
 
 
2201
# ===========================================================
 
2202
# sub Default_Access_Rights():
 
2203
#  return (a reference to) a hash which holds all default
 
2204
#  priviliges currently defined in the grant-tables.
 
2205
# ===========================================================
 
2206
sub Default_Access_Rights {
 
2207
    my %right = ();
 
2208
 
 
2209
    MySQLaccess::Debug::Print(2, "Debug Default_Access_Rights():");
 
2210
    # add entry for all fields in the HOST-table
 
2211
    foreach $field (keys(%MySQLaccess::Grant::H)) {
 
2212
        $right{$field}='0' unless (defined($right{$field}));
 
2213
    }
 
2214
    # add entry for all fields in the DB-table
 
2215
    foreach $field (keys(%MySQLaccess::Grant::D)) {
 
2216
        $right{$field}='0' unless (defined($right{$field}));
 
2217
    }
 
2218
    # add entry for all fields in the USER-table
 
2219
    foreach $field (keys(%MySQLaccess::Grant::U)) {
 
2220
        $right{$field}='0' unless (defined($right{$field}));
 
2221
    }
 
2222
    # --------------
 
2223
    # debugging info
 
2224
    foreach $field (keys(%right)) { MySQLaccess::Debug::Print(3, sprintf("> %15s : %1s",$field,$right{$field})); }
 
2225
 
 
2226
    return \%right;
 
2227
}
 
2228
 
 
2229
# ======================================
 
2230
# sub Make_Privlist
 
2231
#  Make an ordered list of the privileges
 
2232
#  that should be reported
 
2233
# ======================================
 
2234
sub Make_Privlist {
 
2235
    # layout:
 
2236
    #'select_priv',     'create_priv',
 
2237
    #'insert_priv',     'drop_priv',
 
2238
    #'update_priv',     'reload_priv',
 
2239
    #'delete_priv',     'process_priv',
 
2240
    #'file_priv',       'shutdown_priv');
 
2241
    my $right;
 
2242
    my @privlist=();
 
2243
    foreach $right (@U) {
 
2244
        if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
 
2245
    };
 
2246
    foreach $right (@D) {
 
2247
        if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
 
2248
    };
 
2249
    foreach $right (@H) {
 
2250
        if (! grep(/$right/,@privlist)) { push(@privlist,$right); }
 
2251
    };
 
2252
#       print "Privileges:\n";
 
2253
#       foreach $field (@privlist) { print " > $field\n"; }
 
2254
    return \@privlist;
 
2255
}
 
2256
 
 
2257
 
 
2258
 
 
2259
########################################################################
 
2260
package MySQLaccess::Report;
 
2261
use Exporter ();
 
2262
@EXPORT = qw(&Print_Header());
 
2263
BEGIN {
 
2264
    $FORM = $ENV{'SCRIPT_NAME'};
 
2265
    $DEBUG     = 0;
 
2266
    $DEBUG     = $MySQLaccess::DEBUG unless ($DEBUG);
 
2267
 
 
2268
    # translation-table for poss. answers
 
2269
    %Answer =  ('Y' =>  1 , 'N' =>  0
 
2270
               , 1  => 'Y',  0  => 'N'
 
2271
               ,'?' => '?', ''  => '?'
 
2272
               );
 
2273
    $headers   = 0;
 
2274
    $separator = 0;
 
2275
 
 
2276
# ****************************
 
2277
# Notes and warnings
 
2278
%MESSAGES = ( 
 
2279
  'insecure_user' 
 
2280
   => "Everybody can access your DB as user `\$user' from host `\$host'\n"
 
2281
     ."WITHOUT supplying a password.\n"
 
2282
     ."Be very careful about it!!"
 
2283
 ,'password_required' 
 
2284
   => "A password is required for user `\$user' :-("
 
2285
 ,'invalid_password'
 
2286
   => "The password '\$password' for user `\$user' is invalid :-P"
 
2287
 , 'valid_password'
 
2288
   => "You supplied the right password for user `\$user' :-)"
 
2289
 ,'public_database' 
 
2290
   => "Any user with the appropriate permissions has access to your DB!\n"
 
2291
     ."Check your users!"
 
2292
 ,'full_access' 
 
2293
   => "All grant-tables are empty, which gives full access to ALL users !!"
 
2294
 ,'no_rule_found'
 
2295
   => "No matching rule"
 
2296
 ,'no_equiv_host' 
 
2297
   => "Not processed: host-field is not empty in db-table."
 
2298
 ,'least_priv'
 
2299
   => "If the final priveliges of the user are more then you gave the user,\n"
 
2300
     ."check the priveliges in the db-table `\$db'."
 
2301
 ,'minimum_priv'
 
2302
   => "The privileges for any new user are AT LEAST\n"
 
2303
     ."the ones shown in the table above,\n"
 
2304
     ."since these are the privileges of the db `\$db'.\n"
 
2305
 ,'not_found_mysql'
 
2306
   => "The MySQL client program <$MySQLaccess::MYSQL> could not be found.\n"
 
2307
     ."+ Check your path, or\n"
 
2308
     ."+ edit the source of this script to point \$MYSQL to the mysql client.\n"
 
2309
 ,'not_found_mysqldump'
 
2310
   => "The MySQL dump program <$MySQLaccess::MYSQLDUMP> could not be found.\n"
 
2311
     ."+ Check your path, or\n"
 
2312
     ."+ edit the source of this script to point \$MYSQLDUMP to the mysqldump program.\n"
 
2313
 ,'not_found_diff'
 
2314
   => "The diff program <$MySQLaccess::DIFF> could not be found.\n"
 
2315
     ."+ Check your path, or\n"
 
2316
     ."+ edit the source of this script to point \$DIFF to the diff program.\n"
 
2317
 ,'Unrecognized_option'
 
2318
   => "Sorry,\n"
 
2319
     ."You are using an old version of the mysql-program,\n"
 
2320
     ."which does not yet implement a neccessary option.\n"
 
2321
     ."\n"
 
2322
     ."You need at least Version 6.2 of the mysql-client,\n"
 
2323
     ."which was build in MySQL v3.0.18, to use this version\n"
 
2324
     ."of `$MySQLaccess::script'."
 
2325
 ,'Access_denied'
 
2326
   => "Sorry,\n"
 
2327
     ."An error occured when trying to connect to the database\n"
 
2328
     ."with the grant-tables:\n"
 
2329
     ."* Maybe YOU do not have READ-access to this database?\n"
 
2330
     ."* If you used the -U option, you may have supplied an invalid username?\n"
 
2331
     ."  for the superuser?\n"
 
2332
     ."* If you used the -U option, it may be possible you have to supply\n"
 
2333
     ."  a superuser-password to, with the -P option?\n"
 
2334
     ."* If you used the -P option, you may have supplied an invalid password?\n"
 
2335
 ,'Dbaccess_denied'
 
2336
   => "Sorry,\n"
 
2337
     ."An error occured when trying to connect to the database\n"
 
2338
     ."with the grant-tables. (dbaccess denied)\n"
 
2339
 ,'Unknown_tmp_table'
 
2340
   => "Sorry,\n"
 
2341
     ."An error occured when trying to work with the temporary tables in the database\n"
 
2342
     ."with the grant-tables. (One of the temporary tables does not exist)\n"
 
2343
 ,'Unknown_table'
 
2344
   => "Sorry,\n"
 
2345
     ."An error occured when trying to work with some tables in the database\n"
 
2346
     ."with the grant-tables. (table does not exist)\n"
 
2347
 ,'use_old_server'
 
2348
   => "Sorry,\n"
 
2349
     ."An error occured when executing an SQL statement.\n"
 
2350
     ."You might consider altering the use of the parameter `--old_server' when \n"
 
2351
     ."calling `$MySQLaccess::script'."
 
2352
 ,'unknown_error'
 
2353
   => "Sorry,\n"
 
2354
     ."An error occured when trying to connect to the database\n"
 
2355
     ."with the grant-tables. (unknown error)\n"
 
2356
 ,'anonymous_access'
 
2357
   => "Accessing the db as an anonymous user.\n"
 
2358
     ."Your username has no relevance\n"
 
2359
 ,'user_required'
 
2360
   => "You have to supply a userid."
 
2361
 ,'db_required'
 
2362
   => "You have to supply the name of a database."
 
2363
 ,'host_required'
 
2364
   => "You have to supply the name of a host."
 
2365
 );
 
2366
 
 
2367
 
 
2368
 
2369
# =====================================
 
2370
# sub Print_Header:
 
2371
#  print header info
 
2372
# =====================================
 
2373
sub Print_Header {
 
2374
    if ($MySQLaccess::CMD) { #command-line mode
 
2375
    print "$MySQLaccess::script Version $MySQLaccess::VERSION\n"
 
2376
         ."By RUG-AIV, by Yves Carlier (Yves.Carlier\@rug.ac.be)\n"
 
2377
         ."Changes by Steve Harvey (sgh\@vex.net)\n"
 
2378
         ."This software comes with ABSOLUTELY NO WARRANTY.\n";
 
2379
    }
 
2380
    if ($MySQLaccess::CGI) { #CGI-BIN mode
 
2381
    print "content-type: text/html\n\n" 
 
2382
       . "<HTML>\n"
 
2383
         ."<HEAD>\n"
 
2384
         ."<TITLE>MySQLaccess</TITLE>\n"
 
2385
         ."</HEAD>\n"
 
2386
         ."<BODY>\n"
 
2387
         ."<H1>$MySQLaccess::script Version $MySQLaccess::VERSION</H1>\n" 
 
2388
         ."<CENTER>\n<ADDRESS>\n"
 
2389
         ."By RUG-AIV, by Yves Carlier (<a href=mailto:Yves.Carlier\@rug.ac.be>Yves.Carlier\@rug.ac.be</a>)<BR>\n"
 
2390
         ."Changes by Steve Harvey (<a href=mailto:sgh\@vex.net>sgh\@vex.net</a>)<BR>\n"
 
2391
         ."This software comes with ABSOLUTELY NO WARRANTY.<BR>\n"
 
2392
         ."</ADDRESS>\n</CENTER>\n"
 
2393
         ."<HR>\n";
 
2394
    Print_Taskbar();
 
2395
    print "<HR>\n";
 
2396
    }
 
2397
    return 1;
 
2398
}
 
2399
 
 
2400
# =====================================
 
2401
# sub Print_Footer:
 
2402
#  print footer info
 
2403
# =====================================
 
2404
sub Print_Footer {
 
2405
    if ($MySQLaccess::CMD) { #command-line mode
 
2406
    print "\n"
 
2407
         ."BUGs can be reported by email to bugs\@mysql.com\n";
 
2408
    }
 
2409
    if ($MySQLaccess::CGI) { #CGI-BIN mode
 
2410
    if ($MySQLaccess::Param{'brief'}) {
 
2411
    print "</table>\n";  #close table in brief-output
 
2412
    }
 
2413
    print "<HR>\n"
 
2414
         ."<ADDRESS>\n"
 
2415
         ."BUGs can be reported by email to <a href=mailto:bugs\@mysql.com>bugs\@mysql.com</a><BR>\n"
 
2416
#         ."Don't forget to mention the version $VERSION!<BR>\n"
 
2417
         ."</ADDRESS>\n"
 
2418
         ."</BODY>\n"
 
2419
         ."</HTML>\n";
 
2420
    }
 
2421
    return 1;
 
2422
}
 
2423
 
 
2424
# =====================================
 
2425
# sub Print_Taskbar:
 
2426
#  print taskbar on STDOUT
 
2427
# =====================================
 
2428
sub Print_Taskbar {
 
2429
    print "<CENTER>\n"
 
2430
         ."[<a href=$FORM?relnotes=on>Release&nbsp;Notes</a>] \n"
 
2431
         ."[<a href=$FORM?version=on>Version</a>] \n"
 
2432
         ."[<a href=$FORM?plan=on>Future&nbsp;Plans</a>] \n"
 
2433
         ."[<a href=$FORM?howto=on>Examples</a>] \n"
 
2434
         ."[<a href=$FORM?help=on>New check</a>] \n"
 
2435
         ."[<a href=$FORM?edit=on>Change/edit ACL</a>] \n"
 
2436
         ."</CENTER>\n";
 
2437
    return 1;
 
2438
}
 
2439
 
 
2440
# =====================================
 
2441
# sub Print_Form:
 
2442
#  print CGI-form
 
2443
# =====================================
 
2444
sub Print_Form {
 
2445
print <<EOForm;
 
2446
<center>
 
2447
<!-- Quering -->
 
2448
<FORM method=POST action=$FORM>
 
2449
 
 
2450
<table border width="100%" >
 
2451
<tr>
 
2452
  <th>MySQL server</th>
 
2453
  <th>User information</th>
 
2454
  <th>Reports</th>
 
2455
  </tr>
 
2456
 
 
2457
<tr>
 
2458
  <td valign=top>
 
2459
  <table>
 
2460
  <tr>
 
2461
    <td halign=right><b>Host</b><br><font size=-2>(Host on which MySQL-server resides.)</font></td>
 
2462
    <td valign=top><INPUT name=rhost type=text size=15 maxlength=15 value="$MySQLaccess::Param{'rhost'}"></td>
 
2463
    </tr>
 
2464
  <tr>
 
2465
    <td halign=right><b>Superuser</b><br><font size=-2>(User which has <font color="Red">read-access</font> to grant-tables.)</font></td>
 
2466
    <td valign=top><INPUT name=superuser type=text size=15 maxlength=15 value="$MySQLaccess::Param{'superuser'}"></td>
 
2467
    </tr>
 
2468
  <tr>
 
2469
    <td halign=right><b>Password</b><br><font size=-2>(of Superuser.)</font></td>
 
2470
    <td valign=top><INPUT name=spassword type=password size=15 maxlength=15 value="$MySQLaccess::Param{'spassword'}"></td>
 
2471
    </tr>
 
2472
  </table>
 
2473
  </td>
 
2474
 
 
2475
  <td valign=top>
 
2476
  <table>
 
2477
  <tr>
 
2478
    <td halign=right><b><font color=Red>User</font></b><br><font size=-2>(Userid used to connect to MySQL-database.)</font></td>
 
2479
    <td halign=top><INPUT name=user type=text size=15 maxlength=15 value="$MySQLaccess::Param{'user'}"></td>
 
2480
    </tr>
 
2481
  <tr>
 
2482
    <td halign=right><b>Password</b><br><font size=-2>(Password user has to give to get access to MySQL-database.)</font></td>
 
2483
    <td valign=top><INPUT name=password type=password size=15 maxlength=15 value="$MySQLaccess::Param{'password'}"></td>
 
2484
    </tr>
 
2485
  <tr>
 
2486
    <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>
 
2487
    <td valign=top><INPUT name=db type=text size=15 maxlength=15 value="$MySQLaccess::Param{'db'}"></td>
 
2488
    </tr>
 
2489
  <tr>
 
2490
    <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>
 
2491
    <td valign=top><INPUT name=host type=text size=15 maxlength=15 value="$MySQLaccess::Param{'host'}"></td>
 
2492
    </tr>
 
2493
  </table>
 
2494
  </td>
 
2495
 
 
2496
  <td valign=center>
 
2497
  <table cellspacing=5 cellpadding=2 cols=1 height="100%">
 
2498
  <tr align=center>
 
2499
    <td halign=right><INPUT type=submit name=brief value="Brief"><br>
 
2500
                     <INPUT type=submit name=table value="Tabular"></td>
 
2501
    </tr>
 
2502
  <tr align=center>
 
2503
    <td></td>
 
2504
    </tr>
 
2505
  <tr align=center>
 
2506
    <td halign=right><INPUT type=reset value="Clear"></td>
 
2507
    </tr>
 
2508
  </table>
 
2509
  </td>
 
2510
  </tr>
 
2511
 
 
2512
</table>
 
2513
</form>
 
2514
 
 
2515
 
 
2516
</BODY>
 
2517
</HTML>
 
2518
EOForm
 
2519
    return 1;
 
2520
}
 
2521
 
 
2522
# =====================================
 
2523
# sub Print_Usage:
 
2524
#  print some information on STDOUT
 
2525
# =====================================
 
2526
sub Print_Usage {
 
2527
    Print_Error_Messages();
 
2528
    if ($MySQLaccess::CMD) { #command-line mode
 
2529
        Print_Options();
 
2530
    }
 
2531
    if ($MySQLaccess::CGI) { #CGI-BIN mode
 
2532
        Print_Form();
 
2533
    }    
 
2534
    return 1;
 
2535
}
 
2536
 
 
2537
# ======================================
 
2538
# sub Print_Version:
 
2539
# ======================================
 
2540
sub Print_Version {
 
2541
    if ($MySQLaccess::CMD) {
 
2542
       print $MySQLaccess::INFO;
 
2543
    }
 
2544
    if ($MySQLaccess::CGI) { 
 
2545
       print "<PRE>\n"; 
 
2546
       print $MySQLaccess::INFO;
 
2547
       print "</PRE>\n"; 
 
2548
    }
 
2549
    return 1;
 
2550
}
 
2551
 
 
2552
# ======================================
 
2553
# sub Print_Relnotes:
 
2554
# ======================================
 
2555
sub Print_Relnotes {
 
2556
    if ($MySQLaccess::CMD) {
 
2557
       print $MySQLaccess::RELEASE;
 
2558
    }
 
2559
    if ($MySQLaccess::CGI) { 
 
2560
       print "<PRE>\n";
 
2561
       print $MySQLaccess::RELEASE;
 
2562
       print "</PRE>\n"; 
 
2563
    }
 
2564
    return 1;
 
2565
}
 
2566
 
 
2567
# ======================================
 
2568
# sub Print_Plans:
 
2569
# ======================================
 
2570
sub Print_Plans {
 
2571
    if ($MySQLaccess::CMD) {
 
2572
       print $MySQLaccess::TODO;
 
2573
    }
 
2574
    if ($MySQLaccess::CGI) { 
 
2575
       print "<PRE>\n";
 
2576
       print $MySQLaccess::TODO;
 
2577
       print "</PRE>\n"; 
 
2578
    }
 
2579
    return 1;
 
2580
}
 
2581
 
 
2582
# ======================================
 
2583
# sub Print_HowTo:
 
2584
# ======================================
 
2585
sub Print_HowTo {
 
2586
    if ($MySQLaccess::CMD) {
 
2587
       print $MySQLaccess::HOWTO;
 
2588
    }
 
2589
    if ($MySQLaccess::CGI) { 
 
2590
       print "<PRE>\n"; 
 
2591
       print $MySQLaccess::HOWTO;
 
2592
       print "</PRE>\n"; 
 
2593
    }
 
2594
    return 1;
 
2595
}
 
2596
 
 
2597
# ======================================
 
2598
# sub Print_Options:
 
2599
# ======================================
 
2600
sub Print_Options {
 
2601
    if ($MySQLaccess::CGI) { print "<PRE>\n"; }
 
2602
    print $MySQLaccess::OPTIONS;
 
2603
    if ($MySQLaccess::CGI) { print "</PRE>\n"; }
 
2604
    return 1;
 
2605
}
 
2606
 
 
2607
# ======================================
 
2608
# sub Print_Error_Access:
 
2609
# ======================================
 
2610
sub Print_Error_Access {
 
2611
    my ($error) = @_;
 
2612
    print "\n";
 
2613
    if ($MySQLaccess::CGI) { print "<font color=Red>\n<PRE>\n"; }
 
2614
    print $MESSAGES{$error};
 
2615
    if ($MySQLaccess::CGI) { print "</PRE>\n</font>\n"; }
 
2616
    print "\n";
 
2617
    return 1;
 
2618
}
 
2619
 
 
2620
# ======================================
 
2621
# sub Print_Error_Messages:
 
2622
# ======================================
 
2623
sub Print_Error_Messages {
 
2624
#    my ($error) = @_;
 
2625
    print "\n";
 
2626
    if ($MySQLaccess::CGI) { print "<font color=Red>\n<center>\n"; }
 
2627
    foreach $error (@MySQLaccess::Grant::Error) {
 
2628
       print $MESSAGES{$error};
 
2629
       print $MySQLaccess::CGI ? "<br>\n" : "\n";
 
2630
    }
 
2631
    if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; }
 
2632
    print "\n";
 
2633
    return 1;
 
2634
}
 
2635
 
 
2636
# ======================================
 
2637
# sub Print_Message:
 
2638
# ======================================
 
2639
sub Print_Message {
 
2640
    my ($aref) = @_;
 
2641
    my @messages = @{$aref};
 
2642
    print "\n";
 
2643
    if ($MySQLaccess::CGI) { print "<font color=DarkGreen>\n<center>\n"; }
 
2644
    foreach $msg (@messages) {
 
2645
       print $msg;
 
2646
       print $MySQLaccess::CGI ? "<br>\n" : "\n";
 
2647
    }
 
2648
    if ($MySQLaccess::CGI) { print "</center>\n</font>\n"; }
 
2649
    print "\n";
 
2650
    return 1;
 
2651
}
 
2652
 
 
2653
# ======================================
 
2654
# sub Print_Edit:
 
2655
# ======================================
 
2656
sub Print_Edit {
 
2657
    print "\n";
 
2658
    if (!$MySQLaccess::CGI) { 
 
2659
       print "Note: Editing the temporary tables is NOT supported in CMD-line mode!\n";
 
2660
       return 0;
 
2661
    }
 
2662
    print "<CENTER>\n"
 
2663
         ."<form action=$FORM method=GET>\n"
 
2664
         ."<table width=90% border>\n"
 
2665
         ."<tr>\n"
 
2666
         ." <td><input type=checkbox name=copy value=on> Copy grant-rules to temporary tables<br></td>\n"
 
2667
         ." <td rowspan=5 align=center valign=center><input type=submit value=Go></td>\n"
 
2668
         ."</tr>\n"
 
2669
         ."<tr>\n"
 
2670
         ." <td> Edit temporary tables with external application:<br>"
 
2671
         ." <a href=\"$MySQLaccess::MYSQLADMIN\">$MySQLaccess::MYSQLADMIN</a></td>\n"
 
2672
         ."</tr>\n"
 
2673
         ."<tr>\n"
 
2674
         ." <td><input type=checkbox name=preview value=on> Preview changes made in temporary tables</td>\n"
 
2675
         ."</tr>\n"
 
2676
         ."<tr>\n"
 
2677
         ." <td><input type=checkbox name=commit value=on> Make changes permanent</td>\n"
 
2678
         ."</tr>\n"
 
2679
         ."<tr>\n"
 
2680
         ." <td><input type=checkbox name=rollback value=on> Restore previous grand-rules</td>\n"
 
2681
         ."</tr>\n"
 
2682
         ."<tr>\n"
 
2683
         ." <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"
 
2684
         ."</tr>\n"
 
2685
         ."</table>\n"
 
2686
         ."</form>\n"
 
2687
         ."</CENTER>\n";
 
2688
 
 
2689
    return 1;
 
2690
}
 
2691
 
 
2692
 
 
2693
# ======================================
 
2694
# sub Print_Access_rights:
 
2695
#  print the access-rights on STDOUT
 
2696
# ======================================
 
2697
sub Print_Access_rights {
 
2698
    my ($host,$user,$db,$refhash) = @_;
 
2699
 
 
2700
    if (defined($MySQLaccess::Param{'brief'})) { 
 
2701
#       if ($MySQLaccess::CGI) { print "<PRE>\n"; }
 
2702
       Matrix_Report($host,$user,$db,$refhash);  
 
2703
#       if ($MySQLaccess::CGI) { print "</PRE>\n"; }
 
2704
    }
 
2705
    else { 
 
2706
       Tabular_Report($host,$user,$db,$refhash); 
 
2707
       $MySQLaccess::Report::separator = $MySQLaccess::CGI ? "<hr>" : "-"x80;
 
2708
    }
 
2709
    return 1;
 
2710
}
 
2711
 
 
2712
# ======================================
 
2713
# sub Print_Diff_ACL:
 
2714
#  print the diff. in the grants before and after
 
2715
# ======================================
 
2716
sub Print_Diff_ACL {
 
2717
    my ($aref) = @_;
 
2718
    my @diffs = @{$aref};
 
2719
    my %block = ( '<' => 'Before',
 
2720
                  '>' => 'After',
 
2721
                );
 
2722
    my %color = ( '<' => 'Green',
 
2723
                  '>' => 'Red',
 
2724
                ); 
 
2725
    my $curblock = '';
 
2726
 
 
2727
    # -----------------------------
 
2728
    # create column-headers
 
2729
    foreach $field (@MySQLaccess::Grant::Privileges) {
 
2730
      push(@headers,substr($field,0,4));
 
2731
    }
 
2732
 
 
2733
    if ($MySQLaccess::CMD) {
 
2734
    print "\n";
 
2735
    print "Differences in access-rights BEFORE and AFTER changes in grant-tables\n";
 
2736
#    print "---------------------------------------------------------------------\n";
 
2737
      my $line1="";
 
2738
      my $line2="";
 
2739
      $line1 .= sprintf("| %-30s|",'Host,User,DB');
 
2740
      $line2 .= sprintf("+-%-30s+",'-' x 30);
 
2741
      foreach $header (@headers) {
 
2742
        $line1 .= sprintf("%-4s|",$header);
 
2743
        $line2 .= sprintf("%s+",'----');
 
2744
      }
 
2745
      print "$line2\n";
 
2746
      print "$line1\n";
 
2747
      print "$line2\n";
 
2748
 
 
2749
      $format = "format STDOUT = \n"
 
2750
              . "^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< " . " @|||" x 10 ."\n"
 
2751
              . '$host_user_db,@priv' . "\n"
 
2752
              . ".\n";
 
2753
#print $format;
 
2754
      eval $format;
 
2755
    }
 
2756
    if ($MySQLaccess::CGI) {
 
2757
    print "<table border width=100%>\n";
 
2758
    print "<tr>\n";
 
2759
    print "<th colspan=11>";
 
2760
    print "Differences in access-rights <font color=$color{'<'}>BEFORE</font> "
 
2761
         ."and <font color=$color{'>'}>AFTER</font> changes to grant-tables</font>\n";
 
2762
    print "</th>";
 
2763
    print "</tr>\n";
 
2764
    print "<tr>\n";    
 
2765
    $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
 
2766
    foreach $header (@headers) {
 
2767
      $line1 .= sprintf("<th>%-4s</th>",$header);
 
2768
    }
 
2769
    print "$line1</tr>\n";
 
2770
    }
 
2771
 
 
2772
    foreach $line (@diffs) {
 
2773
        $type = substr($line,0,1);
 
2774
        $line = substr($line,1);
 
2775
        ($host,$user,$db,@priv) = split(/,/,$line);
 
2776
        if ($MySQLaccess::CMD) {
 
2777
           if ($type ne $curblock) {
 
2778
              $curblock = $type;
 
2779
              print $block{$curblock},":\n";
 
2780
           }
 
2781
           #print "$line\n";
 
2782
           write;
 
2783
        }
 
2784
        if ($MySQLaccess::CGI) {
 
2785
           if ($type ne $curblock) {
 
2786
              $curblock = $type;
 
2787
              print "<tr><td><b>$block{$curblock}<b></td></tr>\n";
 
2788
           }
 
2789
           $line1="<td><font color=$color{$type}>$host, $user, $db</font></td>";
 
2790
           foreach $field (@priv) {
 
2791
              $line1 .= sprintf("<td align=center><font color=$color{$type}>%-4s</font></td>",$field);
 
2792
           }
 
2793
           print "<tr>$line1</tr>\n";
 
2794
        }
 
2795
    }
 
2796
    print      "\n";
 
2797
    if ($MySQLaccess::CMD) {
 
2798
    print "---------------------------------------------------------------------\n";
 
2799
    }
 
2800
    if ($MySQLaccess::CGI) {
 
2801
    print      "</table><br>";
 
2802
    }
 
2803
 
 
2804
 
 
2805
    return 1;
 
2806
}
 
2807
 
 
2808
# ======================================
 
2809
# sub Tabular_Report
 
2810
#  Tabular report,
 
2811
#  suitable for 1 triple (host,db,user)
 
2812
# ======================================
 
2813
sub Tabular_Report {
 
2814
    my ($host,$user,$db,$a) = @_;
 
2815
    my $column=2;
 
2816
 
 
2817
    # -----------------------------
 
2818
    # separator
 
2819
    if ($MySQLaccess::Report::separator) { print "$MySQLaccess::Report::separator\n"; }
 
2820
    
 
2821
    # -----------------------------
 
2822
    # print table of access-rights
 
2823
    my $rows = int(@MySQLaccess::Grant::Privileges/2);  #round up
 
2824
    my @table=();
 
2825
    $j=0;
 
2826
    for $i (0 .. $rows-1) {
 
2827
      $table[$j]=$MySQLaccess::Grant::Privileges[$i];
 
2828
      $j = $j+2;
 
2829
    }
 
2830
    $j=1;
 
2831
    for $i ($rows .. $#MySQLaccess::Grant::Privileges) {
 
2832
      $table[$j]=$MySQLaccess::Grant::Privileges[$i];
 
2833
      $j = $j+2;
 
2834
    }
 
2835
    if ($MySQLaccess::CMD) {
 
2836
    print "\n";
 
2837
    print "Access-rights\n";
 
2838
    print "for USER '$user', from HOST '$host', to DB '$db'\n";
 
2839
    }
 
2840
    if ($MySQLaccess::CGI) {
 
2841
    print "<table border width=100%>\n";
 
2842
    print "<tr>\n";
 
2843
    }
 
2844
    if ($MySQLaccess::CGI) {
 
2845
    print "<th colspan=5>";
 
2846
    print "<font color=Red>Access-rights</font>\n";
 
2847
    print "for USER '<font color=Green>$user</font>', from HOST '<font color=Green>$host</font>', to DB '<font color=Green>$db</font>'\n";
 
2848
    print "</th>";
 
2849
    print "</tr>\n";
 
2850
    print "<tr>\n";
 
2851
    }
 
2852
    if ($MySQLaccess::CMD) {
 
2853
    print      "\t+-----------------+---+\t+-----------------+---+";
 
2854
    }
 
2855
    foreach $field (@table) {
 
2856
        if ($MySQLaccess::CMD) {
 
2857
          if ($column==2) { print "\n\t"; $column=1;}
 
2858
          else            { print "\t";   $column=2;}
 
2859
          printf "| %-15s | %s |",$field,$Answer{$a->{$field}}; 
 
2860
        }
 
2861
        if ($MySQLaccess::CGI) {
 
2862
          if ($column==2) { print "</tr>\n<tr>\n"; $column=1;}
 
2863
          else            { print "<td width=10%></td>";   $column=2;}
 
2864
          printf " <td width=35%><b>%-15s</b></td><td width=10%>%s</td>\n",$field,$Answer{$a->{$field}}; 
 
2865
        }
 
2866
    }
 
2867
    print      "\n";
 
2868
    if ($MySQLaccess::CMD) {
 
2869
    print      "\t+-----------------+---+\t+-----------------+---+\n";
 
2870
    }
 
2871
    if ($MySQLaccess::CGI) {
 
2872
    print      "</tr>\n</table><br>";
 
2873
    }
 
2874
 
 
2875
    # ---------------
 
2876
    # print notes:
 
2877
    foreach $note (@MySQLaccess::Grant::Notes) {
 
2878
      my $message = $MESSAGES{$note};
 
2879
      $message =~ s/\$user/$user/g; 
 
2880
      $message =~ s/\$db/$db/g;
 
2881
      $message =~ s/\$host/$host/g;
 
2882
      $message =~ s/\$password/$password/g;
 
2883
      $PREFIX='NOTE';
 
2884
      if ($MySQLaccess::CMD) {
 
2885
      my @lines = split(/\n/,$message);
 
2886
      foreach $line (@lines) { 
 
2887
        print "$PREFIX:\t $line\n"; 
 
2888
        $PREFIX='    ';
 
2889
      }
 
2890
      }
 
2891
      if ($MySQLaccess::CGI) {
 
2892
      print "<b>$PREFIX:</b> $message<br>\n";
 
2893
      }
 
2894
    } 
 
2895
 
 
2896
    # ---------------
 
2897
    # print warnings:
 
2898
    foreach $warning (@MySQLaccess::Grant::Warnings) {
 
2899
      my $message = $MESSAGES{$warning};
 
2900
      $message =~ s/\$user/$user/g;
 
2901
      $message =~ s/\$db/$db/g;
 
2902
      $message =~ s/\$host/$host/g;
 
2903
      $message =~ s/\$password/$password/g;
 
2904
      $PREFIX='BEWARE';
 
2905
      if ($MySQLaccess::CMD) {
 
2906
      my @lines = split(/\n/,$message);
 
2907
      foreach $line (@lines) { 
 
2908
        print "$PREFIX:\t $line\n"; 
 
2909
        $PREFIX='      ';
 
2910
      }
 
2911
      }
 
2912
      if ($MySQLaccess::CGI) {
 
2913
      print "<b>$PREFIX:</b> $message<br>\n";
 
2914
      }
 
2915
    }
 
2916
 
 
2917
    # ---------------
 
2918
    # print errors:
 
2919
    foreach $error (@MySQLaccess::Grant::Errors) {
 
2920
      my $message = $MESSAGES{$error};
 
2921
      $message =~ s/\$user/$user/g;
 
2922
      $message =~ s/\$db/$db/g;
 
2923
      $message =~ s/\$host/$host/g;
 
2924
      $message =~ s/\$password/$password/g;
 
2925
      $PREFIX='ERROR';
 
2926
      if ($MySQLaccess::CMD) {
 
2927
      my @lines = split(/\n/,$message);
 
2928
      foreach $line (@lines) { 
 
2929
        print "$PREFIX:\t $line\n"; 
 
2930
        $PREFIX='    ';
 
2931
      }
 
2932
      }
 
2933
      if ($MySQLaccess::CGI) {
 
2934
      print "<b>$PREFIX:</b> $message<br>\n";
 
2935
      }
 
2936
    }
 
2937
 
 
2938
    # ---------------
 
2939
    # inform if there are no rules ==> full access for everyone.
 
2940
    if ($MySQLaccess::Grant::full_access) { print "$MESSAGES{'full_access'}\n"; }
 
2941
 
 
2942
    # ---------------
 
2943
    # print the rules used
 
2944
    print "\n";
 
2945
    if ($MySQLaccess::CMD) {
 
2946
    print "The following rules are used:\n";
 
2947
    foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
 
2948
      my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
 
2949
      $rule =~ s/\t/','/g;
 
2950
      printf " %-5s : '%s'\n",$field,$rule;
 
2951
    }
 
2952
    }
 
2953
    if ($MySQLaccess::CGI) {
 
2954
    print "<br>\n";
 
2955
    print "<table border width=100%>\n";
 
2956
    print "<tr><th colspan=2>The following rules are used:</th></tr>\n";
 
2957
    foreach $field (sort(keys(%MySQLaccess::Grant::Rules))) {
 
2958
      my $rule = (defined($MESSAGES{$MySQLaccess::Grant::Rules{$field}}) ? $MESSAGES{$MySQLaccess::Grant::Rules{$field}} : $MySQLaccess::Grant::Rules{$field});
 
2959
      $rule =~ s/\t/','/g;
 
2960
      printf "<tr><th>%-5s</th><td>'%s'</td></tr>\n",$field,$rule;
 
2961
    }
 
2962
    print "</table>\n";
 
2963
    }
 
2964
 
 
2965
    return 1;
 
2966
}
 
2967
 
 
2968
# ======================================
 
2969
# sub Matrix_Report:
 
2970
#  single-line output foreach triple,
 
2971
#  no notes,warnings,...
 
2972
# ======================================
 
2973
sub Matrix_Report {
 
2974
    my ($host,$user,$db,$a) = @_;
 
2975
    my @headers = ();
 
2976
    
 
2977
    if (! $headers) {
 
2978
       # -----------------------------
 
2979
       # create column-headers
 
2980
       foreach $field (@MySQLaccess::Grant::Privileges) {
 
2981
         push(@headers,substr($field,0,4));
 
2982
       }
 
2983
    
 
2984
       # -----------------------------
 
2985
       # print column-headers
 
2986
       print "\n";
 
2987
       if ($MySQLaccess::CMD) {
 
2988
         my $line1="";
 
2989
         my $line2="";
 
2990
         foreach $header (@headers) {
 
2991
           $line1 .= sprintf("%-4s ",$header);
 
2992
           $line2 .= sprintf("%s ",'----');
 
2993
         }
 
2994
         $line1 .= sprintf("| %-20s",'Host,User,DB');
 
2995
         $line2 .= sprintf("+ %-20s",'-' x 20);
 
2996
         print "$line1\n";
 
2997
         print "$line2\n";
 
2998
       }
 
2999
       if ($MySQLaccess::CGI) {
 
3000
         print "<table width=100% border>\n";
 
3001
         my $line1="<tr>";
 
3002
         foreach $header (@headers) {
 
3003
           $line1 .= sprintf("<th>%-4s</th>",$header);
 
3004
         }
 
3005
         $line1 .= sprintf("<th>%-20s</th>",'Host, User, DB');
 
3006
         print "$line1</tr>\n";
 
3007
       }
 
3008
 
 
3009
       # ----------------------------
 
3010
       # column-headers should only be 
 
3011
       # printed once.
 
3012
       $MySQLaccess::Report::headers=1;
 
3013
    }
 
3014
 
 
3015
    # ------------------------
 
3016
    # print access-information
 
3017
    if ($MySQLaccess::CMD) {
 
3018
      foreach $field (@MySQLaccess::Grant::Privileges) {
 
3019
          printf " %-2s  ",$Answer{$a->{$field}}; 
 
3020
      }
 
3021
      printf "| %-20s",join(',',$host,$user,$db);
 
3022
      print "\n";
 
3023
    }
 
3024
    if ($MySQLaccess::CGI) {
 
3025
      print "<tr>";
 
3026
      foreach $field (@MySQLaccess::Grant::Privileges) {
 
3027
          printf "<td align=center>%-2s</td>",$Answer{$a->{$field}}; 
 
3028
      }
 
3029
      printf "<td><b>%-20s</b></td>",join(', ',$host,$user,$db);
 
3030
      print "</tr>\n";
 
3031
    }
 
3032
 
 
3033
    return 1;
 
3034
}
 
3035
 
 
3036
 
 
3037
# ======================================
 
3038
# sub Raw_Report:
 
3039
#  single-line output foreach triple,
 
3040
#  no notes,warnings,...
 
3041
# ======================================
 
3042
sub Raw_Report {
 
3043
    my ($host,$user,$db,$a) = @_;
 
3044
    my @headers = ();
 
3045
    my $string = "";
 
3046
    
 
3047
    # ------------------------
 
3048
    # print access-information
 
3049
    $string = "$host,$user,$db,";
 
3050
    foreach $field (@MySQLaccess::Grant::Privileges) {
 
3051
          $string .= $Answer{$a->{$field}} . ","; 
 
3052
    }
 
3053
    return $string;
 
3054
}
 
3055
 
 
3056
 
 
3057
#######################################################################
 
3058
package MySQLaccess::Wildcards;
 
3059
BEGIN {
 
3060
    $DEBUG     = 0;
 
3061
    $DEBUG     = $MySQLaccess::DEBUG unless ($DEBUG);
 
3062
}
 
3063
# ############################################
 
3064
# SQL, WILDCARDS and REGULAR EXPRESSIONS 
 
3065
# ============================================
 
3066
# translage SQL-expressions to Reg-expressions
 
3067
# ============================================
 
3068
sub SQL2Reg {
 
3069
    my ($expr) = @_;
 
3070
    my $expr_o = $expr;
 
3071
    $expr  =~ s/\./\\./g;
 
3072
    $expr  =~ s/\\%/\002/g;
 
3073
    $expr  =~ s/%/.*/g;
 
3074
    $expr  =~ s/\002/%/g;
 
3075
    $expr  =~ s/\\_/\002/g;
 
3076
    $expr  =~ s/_/.+/g;
 
3077
    $expr  =~ s/\002/_/g;
 
3078
    MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
 
3079
    return $expr;
 
3080
}
 
3081
 
 
3082
# translage WILDcards to Reg-expressions
 
3083
# ============================================
 
3084
sub Wild2Reg {
 
3085
    my ($expr) = @_;
 
3086
    my $expr_o = $expr;
 
3087
    $expr  =~ s/\./\\./g;
 
3088
    $expr  =~ s/\\\*/\002/g;
 
3089
    $expr  =~ s/\*/.*/g;
 
3090
    $expr  =~ s/\002/*/g;
 
3091
    $expr  =~ s/\\\?/\002/g;
 
3092
    $expr  =~ s/\?/.+/g;
 
3093
    $expr  =~ s/\002/?/g;
 
3094
    MySQLaccess::Debug::Print(2,"$expr_o --> $expr");
 
3095
    return $expr;
 
3096
}
 
3097
 
 
3098
# =============================================
 
3099
# match a given string with a template
 
3100
# =============================================
 
3101
sub MatchTemplate {
 
3102
    my ($tpl,$string) = @_;
 
3103
    my $match=0;
 
3104
    if ($string=~ /^$tpl$/ or $tpl eq '') { $match=1; }
 
3105
    else                                  { $match=0;}
 
3106
    MySQLaccess::Debug::Print(2,"($tpl,$string) --> $match");
 
3107
    return $match;
 
3108
}
 
3109
 
 
3110
#######################################################################
 
3111
package MySQLaccess::Host;
 
3112
BEGIN {
 
3113
    $localhost = undef;
 
3114
    $DEBUG     = 2;
 
3115
    $DEBUG     = $MySQLaccess::DEBUG unless ($DEBUG);
 
3116
}
 
3117
# ======================================
 
3118
# sub IP2Name
 
3119
#  return the Name with the corr. IP-nmbr
 
3120
#  (no aliases yet!!)
 
3121
# ======================================
 
3122
sub IP2Name {
 
3123
    my ($ip) = @_;
 
3124
    my $ip_o = $ip;
 
3125
    if ($ip !~ /([0-9]+)\.([0-9]+)\.([0-9]+)\.([0-9]+)/o) {
 
3126
       MySQLaccess::Debug::Print(3,"'$ip' is not an ip-number, returning IP=$ip");
 
3127
       return $ip;
 
3128
    }
 
3129
    MySQLaccess::Debug::Print(4,"IP=$ip split up => $1.$2.$3.$4");
 
3130
    $ip = pack "C4",$1,$2,$3,$4;
 
3131
    MySQLaccess::Debug::Print(4,"IP packed -> >>$ip<<\n");
 
3132
    my ($name,$aliases,$addrtype,$length,@addrs) = gethostbyaddr($ip, AF_INET);
 
3133
    MySQLaccess::Debug::Print(3,"IP=$ip_o => hostname=$name");
 
3134
    MySQLaccess::Debug::Print(4,"aliases=$aliases");
 
3135
    MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
 
3136
    return ($name || $ip);
 
3137
    #return ($name || undef);
 
3138
}
 
3139
 
 
3140
# ======================================
 
3141
# sub Name2IP
 
3142
#  return the IP-number of the host
 
3143
# ======================================
 
3144
sub Name2IP {
 
3145
    my ($name) = @_;
 
3146
    if ($name =~ /[%_]/) { 
 
3147
       MySQLaccess::Debug::Print(3,"'$name' contains SQL-wildcards, returning name=$name");
 
3148
       return $name; 
 
3149
    }
 
3150
    my ($_name,$aliases,$addrtype,$length,@addrs) = gethostbyname($name);
 
3151
    my ($a,$b,$c,$d) = unpack('C4',$addrs[0]);
 
3152
    my $ip = "$a.$b.$c.$d";
 
3153
    MySQLaccess::Debug::Print(3,"hostname=$name => IP=$ip");
 
3154
    MySQLaccess::Debug::Print(4,"aliases=$aliases");
 
3155
    MySQLaccess::Debug::Print(4,"addrtype=$addrtype - length=$length");
 
3156
    #if ($ip ne "") { return "$ip"; }
 
3157
    #else           { return undef; }
 
3158
    return ($ip || $name);
 
3159
}
 
3160
 
 
3161
# ========================================
 
3162
# sub LocalHost
 
3163
#  some special action has to be taken for
 
3164
#  the localhost
 
3165
# ========================================
 
3166
sub LocalHost {
 
3167
    if (!defined($MySQLaccess::Host::localhost)) {
 
3168
       $MySQLaccess::Host::localhost = Sys::Hostname::hostname();
 
3169
       MySQLaccess::Debug::Print(3,"Setting package variable \$localhost=$MySQLaccess::Host::localhost");
 
3170
    }
 
3171
    my $host = $localhost;
 
3172
    MySQLaccess::Debug::Print(3,"localhost = $host");
 
3173
    return $host;
 
3174
}
 
3175
 
 
3176
# ========================================
 
3177
# check if the given hostname (or ip)
 
3178
# corresponds with the localhost
 
3179
# ========================================
 
3180
sub Is_localhost {
 
3181
    my ($host_tpl) = @_;
 
3182
    my $isit = 0;
 
3183
    if (($MySQLaccess::host_name eq $localhost) or ($MySQLaccess::host_ip eq $local_ip)) {
 
3184
        MySQLaccess::Debug::Print(2,"Checking for localhost");
 
3185
      MySQLaccess::Debug::Print(3,"because ($MySQLaccess::host_name EQ $localhost) AND ($MySQLaccess::host_ip EQ $local_ip)");
 
3186
      $isit = ( 'localhost' =~ /$host_tpl/ ) ? 1 : 0;
 
3187
      MySQLaccess::Debug::Print(3," 'localhost' =?= $host_tpl  -> $isit");
 
3188
      return $isit;
 
3189
    }
 
3190
    else {
 
3191
      MySQLaccess::Debug::Print(4,"Not checking for localhost");
 
3192
      MySQLaccess::Debug::Print(4,"because ($MySQLaccess::host_name != $localhost) AND ($MySQLaccess::host_ip != $local_ip)");
 
3193
      return 0;
 
3194
    }
 
3195
}
 
3196
 
 
3197
 
 
3198
# =========================================
 
3199
# check if host (IP or name) can be matched
 
3200
# on the template.
 
3201
# =========================================
 
3202
sub MatchTemplate {
 
3203
    my ($host,$tpl) = @_;
 
3204
    my $match = 0;
 
3205
   
 
3206
    MySQLaccess::Debug::Print(1, "($host) =?= ($tpl)");
 
3207
 
 
3208
    my $host_name = IP2Name($host);
 
3209
    my $host_ip   = Name2IP($host);
 
3210
 
 
3211
    MySQLaccess::Debug::Print(2, "name=$host_name ; ip=$host_ip");
 
3212
    $match = (MySQLaccess::Wildcards::MatchTemplate($tpl,$host_name) or
 
3213
             MySQLaccess::Wildcards::MatchTemplate($tpl,$host_ip));
 
3214
 
 
3215
    MySQLaccess::Debug::Print(2, "($host_name,$host_ip) =?= ($tpl): $ncount");
 
3216
 
 
3217
    return $match;
 
3218
}
 
3219
 
 
3220
########################################################################
 
3221
package MySQLaccess::Debug;
 
3222
BEGIN {
 
3223
   my $dbg_file = "$MySQLaccess::script_log";
 
3224
   open(DEBUG,"> $dbg_file") or warn "Could not open outputfile $dbg_file for debugging-info\n";
 
3225
   select DEBUG;
 
3226
   $| = 1;
 
3227
   select STDOUT;
 
3228
}
 
3229
# =========================================
 
3230
# Print debugging information on STDERR
 
3231
# =========================================
 
3232
sub Print {
 
3233
    my ($level,$mesg) = @_;
 
3234
    my ($pack,$file,$line,$subname,$hasargs,$wantarray) = caller(1);
 
3235
    my ($PACK)  = split('::',$subname); 
 
3236
    my $DEBUG = ${$PACK."::DEBUG"} ? ${$PACK."::DEBUG"} : $MySQLaccess::DEBUG ;
 
3237
    my ($sec,$min,$hour) = localtime();
 
3238
    print DEBUG "[$hour:$min:$sec $subname] $mesg\n" if ($DEBUG>=$level);
 
3239
}
 
3240