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