~drizzle-trunk/drizzle/development

« back to all changes in this revision

Viewing changes to scripts/mysqlaccess.sh

Deleted tons of pointless garbage from scripts.

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