1#!@PERL_PATH@
2## Emacs, this is -*- perl -*- mode? :-)
3
4# Copyright (c) 2000, 2017, Oracle and/or its affiliates. All rights reserved.
5#
6# This program is free software; you can redistribute it and/or
7# modify it under the terms of the GNU Library General Public
8# License as published by the Free Software Foundation; version 2
9# of the License.
10#
11# This program is distributed in the hope that it will be useful,
12# but WITHOUT ANY WARRANTY; without even the implied warranty of
13# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14# Library General Public License for more details.
15#
16# You should have received a copy of the GNU Library General Public
17# License along with this library; if not, write to the Free
18# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
19# MA 02110-1301, USA
20
21##
22##        Permission setter for MySQL
23##
24##        mady by Luuk de Boer (luuk@wxs.nl) 1998.
25##        it's made under GPL ...:-))
26##
27##
28############################################################################
29## History
30##
31## 1.0 first start of the program
32## 1.1 some changes from monty and after that
33##     initial release in mysql 3.22.10 (nov 1998)
34## 1.2 begin screen now in a loop + quit is using 0 instead of 9
35##     after ideas of Paul DuBois.
36## 1.2a Add Grant, References, Index and Alter privilege handling (Monty)
37## 1.3 Applied patch provided by Martin Mokrejs <mmokrejs@natur.cuni.cz>
38##     (General code cleanup, use the GRANT statement instead of updating
39##     the privilege tables directly, added option to revoke privileges)
40## 1.4 Remove option 6 which attempted to erroneously grant global privileges
41
42#### TODO
43#
44# empty ... suggestions ... mail them to me ...
45
46
47$version="1.4";
48
49use DBI;
50use Getopt::Long;
51use strict;
52use vars qw($dbh $sth $hostname $opt_user $opt_password $opt_help $opt_host
53	    $opt_socket $opt_port $host $version);
54
55my $sqlhost = "";
56my $user = "";
57
58$dbh=$host=$opt_user= $opt_password= $opt_help= $opt_host= $opt_socket= "";
59$opt_port=0;
60
61read_my_cnf();		# Read options from ~/.my.cnf
62
63GetOptions("user=s","password=s","help","host=s","socket=s","port=i");
64
65usage() if ($opt_help); # the help function
66
67if ($opt_host eq '')
68{
69  $sqlhost = "localhost";
70}
71else
72{
73  $sqlhost = $opt_host;
74}
75
76# ask for a password if no password is set already
77if ($opt_password eq '')
78{
79  system "stty -echo";
80  print "Password for user $opt_user to connect to MySQL: ";
81  $opt_password = <STDIN>;
82  chomp($opt_password);
83  system "stty echo";
84  print "\n";
85}
86
87
88# make the connection to MySQL
89$dbh= DBI->connect("DBI:mysql:mysql:host=$sqlhost:port=$opt_port:mysql_socket=$opt_socket",$opt_user,$opt_password, {PrintError => 0}) ||
90  die("Can't make a connection to the mysql server.\n The error: $DBI::errstr");
91
92# the start of the program
93&q1();
94exit(0); # the end...
95
96#####
97# below all subroutines of the program
98#####
99
100###
101# the beginning of the program
102###
103sub q1 { # first question ...
104  my ($answer,$end);
105  while (! $end) {
106    print "#"x70;
107    print "\n";
108    print "## Welcome to the permission setter $version for MySQL.\n";
109    print "## made by Luuk de Boer\n";
110    print "#"x70;
111    print "\n";
112    print "What would you like to do:\n";
113    print "  1. Set password for an existing user.\n";
114    print "  2. Create a database + user privilege for that database\n";
115		print "     and host combination (user can only do SELECT)\n";
116    print "  3. Create/append user privilege for an existing database\n";
117		print "     and host combination (user can only do SELECT)\n";
118    print "  4. Create/append broader user privileges for an existing\n";
119		print "     database and host combination\n";
120		print "     (user can do SELECT,INSERT,UPDATE,DELETE)\n";
121    print "  5. Create/append quite extended user privileges for an\n";
122		print "     existing database and host combination (user can do\n";
123		print "     SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,\n";
124		print "     LOCK TABLES,CREATE TEMPORARY TABLES)\n";
125    print "  6. Create/append full privileges for an existing database\n";
126		print "     and host combination (user has FULL privilege)\n";
127    print "  7. Remove all privileges for for an existing database and\n";
128		print "     host combination.\n";
129    print "     (user will have all permission fields set to N)\n";
130    print "  0. exit this program\n";
131    print "\nMake your choice [1,2,3,4,5,6,7,0]: ";
132    while (<STDIN>) {
133      $answer = $_;
134      chomp($answer);
135      if ($answer =~ /^[1234567]$/) {
136        if ($answer == 1) {
137	   setpwd();
138        } elsif ($answer =~ /^[234567]$/) {
139	   addall($answer);
140	} else {
141          print "Sorry, something went wrong. With such option number you should not get here.\n\n";
142          $end = 1;
143        }
144      } elsif ($answer == 0) {
145        print "We hope we can help you next time \n\n";
146	$end = 1;
147      } else {
148        print "Your answer was $answer\n";
149        print "and that's wrong .... Try again\n";
150      }
151      last;
152    }
153  }
154}
155
156###
157# set a password for a user
158###
159sub setpwd
160{
161  my ($user,$pass,$host) = "";
162  print "\n\nSetting a (new) password for a user.\n";
163
164  $user = user();
165  $pass = newpass($user);
166  $host = hosts($user);
167
168  print "#"x70;
169  print "\n\n";
170  print "That was it ... here is an overview of what you gave to me:\n";
171  print "The username 		: $user\n";
172#  print "The password		: $pass\n";
173  print "The host		: $host\n";
174  print "#"x70;
175  print "\n\n";
176  print "Are you pretty sure you would like to implement this [yes/no]: ";
177  my $no = <STDIN>;
178  chomp($no);
179  if ($no =~ /n/i)
180  {
181    print "Okay .. that was it then ... See ya\n\n";
182    return(0);
183  }
184  else
185  {
186    print "Okay ... let's go then ...\n\n";
187  }
188  $user = $dbh->quote($user);
189  $host = $dbh->quote($host);
190  if ($pass eq '')
191  {
192    $pass = "''";
193  }
194  else
195  {
196    $pass = "PASSWORD(". $dbh->quote($pass) . ")";
197  }
198  my $sth = $dbh->prepare("update user set Password=$pass where User = $user and Host = $host") || die $dbh->errstr;
199  $sth->execute || die $dbh->errstr;
200  $sth->finish;
201  print "The password is set for user $user.\n\n";
202
203}
204
205###
206# all things which will be added are done here
207###
208sub addall {
209  my ($todo) = @_;
210  my ($answer,$good,$db,$user,$pass,$host,$priv);
211
212  if ($todo == 2) {
213    $db = newdatabase();
214  } else {
215    $db = database();
216  }
217
218  $user = newuser();
219  $pass = newpass("$user");
220  $host = newhosts();
221
222  print "#"x70;
223  print "\n\n";
224  print "That was it ... here is an overview of what you gave to me:\n";
225  print "The database name	: $db\n";
226  print "The username 		: $user\n";
227#  print "The password		: $pass\n";
228  print "The host(s)		: $host\n";
229  print "#"x70;
230  print "\n\n";
231  print "Are you pretty sure you would like to implement this [yes/no]: ";
232  my $no = <STDIN>;
233  chomp($no);
234  if ($no =~ /n/i) {
235    print "Okay .. that was it then ... See ya\n\n";
236    return(0);
237  } else {
238    print "Okay ... let's go then ...\n\n";
239  }
240
241  if ($todo == 2) {
242    # create the database
243    if ($db) {
244    my $sth = $dbh->do("CREATE DATABASE $db") || $dbh->errstr;
245    } else {
246      print STDERR "What do you want? You wanted to create new database and add new user, right?\n";
247      die "But then specify databasename, please\n";
248  }
249  }
250
251  if ( ( !$todo ) or not ( $todo =~ m/^[2-7]$/ ) ) {
252    print STDERR "Sorry, select option $todo isn't known inside the program .. See ya\n";
253    quit();
254  }
255
256  my @hosts = split(/,/,$host);
257  if (!$user) {
258     die "username not specified: $user\n";
259  }
260  if (!$db) {
261     die "databasename is not specified nor *\n";
262  }
263  foreach $host (@hosts) {
264    # user privileges: SELECT
265    if (($todo == 2) || ($todo == 3)) {
266      $sth = $dbh->do("GRANT SELECT ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr;
267    } elsif ($todo == 4) {
268      # user privileges: SELECT,INSERT,UPDATE,DELETE
269      $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr;
270    } elsif ($todo == 5) {
271      # user privileges: SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES
272      $sth = $dbh->do("GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP,INDEX,LOCK TABLES,CREATE TEMPORARY TABLES ON $db.* TO \'$user\'@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr;
273    } elsif ($todo == 6) {
274       # all privileges
275       $sth = $dbh->do("GRANT ALL ON $db.* TO \'$user\'\@\'$host\' IDENTIFIED BY \'$pass\'") || die $dbh->errstr;
276    } elsif ($todo == 7) {
277       # all privileges set to N
278       $sth = $dbh->do("REVOKE ALL ON $db.* FROM \'$user\'\@\'$host\'") || die $dbh->errstr;
279    }
280    }
281  $dbh->do("FLUSH PRIVILEGES") || print STDERR "Can't flush privileges\n";
282  print "Everything is inserted and mysql privileges have been reloaded.\n\n";
283}
284
285###
286# ask for a new database name
287###
288sub newdatabase {
289  my ($answer,$good,$db);
290  print "\n\nWhich database would you like to add: ";
291  while (<STDIN>) {
292    $answer = $_;
293    $good = 0;
294    chomp($answer);
295    if ($answer) {
296      my $sth = $dbh->prepare("SHOW DATABASES") || die $dbh->errstr;
297      $sth->execute || die $dbh->errstr;
298      while (my @r = $sth->fetchrow_array) {
299        if ($r[0] eq $answer) {
300          print "\n\nSorry, this database name is already in use; try something else: ";
301          $good = 1;
302        }
303      }
304    } else {
305      print "You must type something ...\nTry again: ";
306      next;
307    }
308    last if ($good == 0);
309  }
310  $db = $answer;
311  print "The new database $db will be created\n";
312  return($db);
313}
314
315###
316# select a database
317###
318sub database {
319  my ($answer,$good,$db);
320  print "\n\nWhich database from existing databases would you like to select: \n";
321  print "You can choose from: \n";
322  my $sth = $dbh->prepare("show databases") || die $dbh->errstr;
323  $sth->execute || die $dbh->errstr;
324  while (my @r = $sth->fetchrow_array) {
325    print "  - $r[0] \n";
326  }
327  print "Which database will it be (case sensitive). Type * for any: \n";
328  while (<STDIN>) {
329    $answer = $_;
330    $good = 0;
331    chomp($answer);
332    if ($answer) {
333      if ($answer eq "*") {
334        print "OK, the user entry will NOT be limited to any database";
335        return("*");
336      }
337      my $sth = $dbh->prepare("show databases") || die $dbh->errstr;
338      $sth->execute || die $dbh->errstr;
339      while (my @r = $sth->fetchrow_array) {
340        if ($r[0] eq $answer) {
341          $good = 1;
342          $db = $r[0];
343          last;
344        }
345      }
346    } else {
347        print "Type either database name or * meaning any databasename. That means";
348        print " any of those above but also any which will be created in future!";
349        print " This option gives a user chance to operate on databse mysql, which";
350        print " contains privilege settings. That is really risky!\n";
351      next;
352    }
353    if ($good == 1) {
354      last;
355    } else {
356      print "You must select one from the list.\nTry again: ";
357      next;
358    }
359  }
360  print "The database $db will be used.\n";
361  return($db);
362}
363
364###
365# ask for a new username
366###
367sub newuser
368{
369  my $user = "";
370  my $answer = "";
371
372  print "\nWhat username is to be created: ";
373  while(<STDIN>)
374  {
375    $answer = $_;
376    chomp($answer);
377    if ($answer)
378    {
379      $user = $answer;
380    }
381    else
382    {
383      print "You must type something ...\nTry again: ";
384      next;
385    }
386    last;
387  }
388  print "Username = $user\n";
389  return($user);
390}
391
392###
393# ask for a user which is already in the user table
394###
395sub user
396{
397  my ($answer,$user);
398
399  print "\nFor which user do you want to specify a password: ";
400  while(<STDIN>)
401  {
402    $answer = $_;
403    chomp($answer);
404    if ($answer)
405    {
406      my $sth = $dbh->prepare("select User from user where User = '$answer'") || die $dbh->errstr;
407      $sth->execute || die $dbh->errstr;
408      my @r = $sth->fetchrow_array;
409      if ($r[0])
410      {
411        $user = $r[0];
412      }
413      else
414      {
415       print "Sorry, user $answer isn't known in the user table.\nTry again: ";
416       next;
417     }
418    }
419    else
420    {
421      print "You must type something ...\nTry again: ";
422      next;
423    }
424    last;
425  }
426  print "Username = $user\n";
427  return($user);
428}
429
430###
431# ask for a new password
432###
433sub newpass
434{
435  my ($user) = @_;
436  my ($pass,$answer,$good,$yes);
437
438  print "Would you like to set a password for $user [y/n]: ";
439  $yes = <STDIN>;
440  chomp($yes);
441  if ($yes =~ /y/)
442  {
443    system "stty -echo";
444    print "What password do you want to specify for $user: ";
445    while(<STDIN>)
446    {
447      $answer = $_;
448      chomp($answer);
449      system "stty echo";
450      print "\n";
451      if ($answer)
452      {
453        system "stty -echo";
454        print "Type the password again: ";
455        my $second = <STDIN>;
456        chomp($second);
457        system "stty echo";
458        print "\n";
459        if ($answer ne $second)
460        {
461          print "Passwords aren't the same; we begin from scratch again.\n";
462          system "stty -echo";
463          print "Password please: ";
464          next;
465        }
466        else
467        {
468          $pass = $answer;
469        }
470      }
471      else
472      {
473        print "You must type something ...\nTry again: ";
474        next;
475      }
476      last;
477    }
478#    print "The password for $user is $pass.\n";
479  }
480  else
481  {
482    print "We won't set a password so the user doesn't have to use it\n";
483    $pass = "";
484  }
485  return($pass);
486}
487
488###
489# ask for new hosts
490###
491sub newhosts
492{
493  my ($host,$answer,$good);
494
495  print "We now need to know from what host(s) the user will connect.\n";
496  print "Keep in mind that % means 'from any host' ...\n";
497  print "The host please: ";
498  while(<STDIN>)
499  {
500    $answer = $_;
501    chomp($answer);
502    if ($answer)
503    {
504      $host .= ",$answer";
505      print "Would you like to add another host [yes/no]: ";
506      my $yes = <STDIN>;
507      chomp($yes);
508      if ($yes =~ /y/i)
509      {
510        print "Okay, give us the host please: ";
511        next;
512      }
513      else
514      {
515        print "Okay we keep it with this ...\n";
516      }
517    }
518    else
519    {
520      print "You must type something ...\nTry again: ";
521      next;
522    }
523    last;
524  }
525  $host =~ s/^,//;
526  print "The following host(s) will be used: $host.\n";
527  return($host);
528}
529
530###
531# ask for a host which is already in the user table
532###
533sub hosts
534{
535  my ($user) = @_;
536  my ($answer,$good,$host);
537
538  print "We now need to know which host for $user we have to change.\n";
539  print "Choose from the following hosts: \n";
540  $user = $dbh->quote($user);
541  my $sth = $dbh->prepare("select Host,User from user where User = $user") || die $dbh->errstr;
542  $sth->execute || die $dbh->errstr;
543  while (my @r = $sth->fetchrow_array)
544  {
545    print "  - $r[0] \n";
546  }
547  print "The host please (case sensitive): ";
548  while(<STDIN>)
549  {
550    $answer = $_;
551    chomp($answer);
552    if ($answer)
553    {
554      $sth = $dbh->prepare("select Host,User from user where Host = '$answer' and User = $user") || die $dbh->errstr;
555      $sth->execute || die $dbh->errstr;
556      my @r = $sth->fetchrow_array;
557      if ($r[0])
558      {
559        $host = $answer;
560        last;
561      }
562      else
563      {
564        print "You have to select a host from the list ...\nTry again: ";
565        next;
566      }
567    }
568    else
569    {
570      print "You have to type something ...\nTry again: ";
571      next;
572    }
573    last;
574  }
575  print "The following host will be used: $host.\n";
576  return($host);
577}
578
579###
580# a nice quit (first disconnect and then exit
581###
582sub quit
583{
584  $dbh->disconnect;
585  exit(0);
586}
587
588###
589# Read variables password, port and socket from .my.cnf under the client
590# or perl groups
591###
592
593sub read_my_cnf
594{
595  open(TMP,$ENV{'HOME'} . "/.my.cnf") || return 1;
596  while (<TMP>)
597  {
598    if (/^\[(client|perl)\]/i)
599    {
600      while ((defined($_=<TMP>)) && !/^\[\w+\]/)
601      {
602	print $_;
603	if (/^host\s*=\s*(\S+)/i)
604	{
605	  $opt_host = $1;
606	}
607	elsif (/^user\s*=\s*(\S+)/i)
608	{
609	  $opt_user = $1;
610	}
611	elsif (/^password\s*=\s*(\S+)/i)
612	{
613	  $opt_password = $1;
614	}
615	elsif (/^port\s*=\s*(\S+)/i)
616	{
617	  $opt_port = $1;
618	}
619	elsif (/^socket\s*=\s*(\S+)/i)
620	{
621	  $opt_socket = $1;
622	}
623      }
624    }
625  }
626  close(TMP);
627}
628
629###
630# the help text
631###
632sub usage
633{
634  print <<EOL;
635----------------------------------------------------------------------
636                 The permission setter for MySQL.
637                      version: $version
638
639                 made by: Luuk de Boer <luuk\@wxs.nl>
640----------------------------------------------------------------------
641
642The permission setter is a little program which can help you add users
643or databases or change passwords in MySQL. Keep in mind that we don't
644check permissions which already been set in MySQL. So if you can't
645connect to MySQL using the permission you just added, take a look at
646the permissions which have already been set in MySQL.
647
648The permission setter first reads your .my.cnf file in your Home
649directory if it exists.
650
651Options for the permission setter:
652
653--help		: print this help message and exit.
654
655The options shown below are used for making the connection to the MySQL
656server. Keep in mind that the permissions for the user specified via
657these options must be sufficient to add users / create databases / set
658passwords.
659
660--user		: is the username to connect with.
661--password	: the password of the username.
662--host		: the host to connect to.
663--socket	: the socket to connect to.
664--port		: the port number of the host to connect to.
665
666If you don't give a password and no password is set in your .my.cnf
667file, then the permission setter will ask for a password.
668
669
670EOL
671exit(0);
672}
673