How to write stored procedure to check Grant in MySql? - mysql

I want to create a stored procedure to check grant. I have tried by following way but I don't what I am missing here.
//simple Query "SHOW GRANTS FOR testuser #'192.168.1.180'" - It is working
CREATE DEFINER=`abc`#`localhost` PROCEDURE `SP_GetGrantAllPriviledge`(
IN Username TEXT,
IN Hostname TEXT
)
BEGIN
SHOW GRANTS FOR Username #Hostname; //doesn't work
END
Can anybody suggest what I am missing?

You can use the TABLE_PRIVILEGES in the INFORMATION_SCHEMA.
SELECT *
FROM INFORMATION_SCHEMA.TABLE_PRIVILEGES
WHERE `GRANTEE` = CONCAT('''', Username, '''#''', Hostname, '''')

#Hostname; is the source of issue
Update your SP with prepare statement:
CREATE PROCEDURE `SP_GetGrantAllPriviledge`(
IN Username TEXT,
IN Hostname TEXT
)
BEGIN
SET #sql = CONCAT('SHOW GRANTS FOR ',Username,' #',Hostname,'; ');
PREPARE stmt FROM #sql;
EXECUTE stmt;
END

Related

MySQL sugar syntax to create an authenticated, all-privileged user and its database

This is how I create an authenticated, all-privileged user and its database in MySQL through the MySQL CLI in Linux (Ubuntu with Bash):
cat <<-DBSTACK | mysql -u root -p"${dbrootp}"
CREATE (OR RE-CREATE IF NEEDED) USER "${domain}"#"localhost" IDENTIFIED BY "${dbuserp}";
CREATE (OR RE-CREATE IF NEEDED) DATABASE ${domain};
GRANT ALL PRIVILEGES ON ${domain}.* TO "${domain}"#"localhost";
DBSTACK
Is there some sugar syntax, or some high functionality that does all of that in a single line?
(would be better than running 5 lines - 2 for an here-document opener and delimiter, and 3 for MySQL).
I'm not aware of any in-built command that would perform all of these tasks as one, but you can easily define your own stored program to do it:
CREATE PROCEDURE addNewDomain(domain VARCHAR(32), password VARCHAR(32))
BEGIN
DECLARE db VARCHAR(66) DEFAULT CONCAT('`', REPLACE(domain, '`', '``'), '`');
DECLARE ac VARCHAR(76) DEFAULT CONCAT(db, '#localhost');
SET
#a := CONCAT('CREATE USER ', ac, ' IDENTIFIED BY ', QUOTE(password)),
#b := CONCAT('CREATE DATABASE ', db),
#c := CONCAT('GRANT ALL PRIVILEGES ON ', db, '.* TO ', ac)
;
PREPARE stmt FROM #a; EXECUTE stmt; DEALLOCATE PREPARE stmt;
PREPARE stmt FROM #b; EXECUTE stmt; DEALLOCATE PREPARE stmt;
PREPARE stmt FROM #c; EXECUTE stmt; DEALLOCATE PREPARE stmt;
END
Which you would then invoke with a single CALL statement:
CALL addNewDomain('foobar', 's3cr3t')
One advantage of this approach is that the procedure can be defined by a user with full CREATE and GRANT permissions, but permission to EXECUTE it granted to a user who does not have those permissions—then your shell script can connect to MySQL using the lower-privileged account (that can cause less damage, eg only set up new domains, if compromised).
Note that, in order to issue the CREATE PROCEDURE command (which contains ; characters) you will need to ensure your MySQL client's statement delimiter is set to something other than ; or else it will split the command into multiple separate statements when sending to the server. The MySQL CLI does this using the DELIMITER statement:
DELIMITER ;;
CREATE PROCEDURE addNewDomain(domain VARCHAR(32), password VARCHAR(32))
BEGIN
-- etc
END;;
DELIMITER ;
There's no combined syntax per the MySQL docs, presumably because - generally -
CREATE USER and CREATE DATABASE are executed once, while GRANT is executed more than once.
One way to reduce the syntax overhead is to encapsulate the SQL construction in a shell function. For bash, that might look like:
grant_sql() {
local user pass
user="${1:?Missing argument #1: MySQL user name}"
pass="${2:?Missing argument #2: password for MySQL user}"
cat <<EOSQL
CREATE USER "${user}"#"localhost" IDENTIFIED BY "${pass}";
CREATE DATABASE ${user};
GRANT ALL PRIVILEGES ON ${user}.* TO "${user}"#"localhost";
EOSQL
}
Then to fire it off like:
grant_sql "myUser" "itsPassword" | mysql -uroot -p...

How to restrict other user drop root user in MySQL?

I created a user and granted "CREATE USER" privileges. I found that user can drop any other user include root. How can I prevent that happen?
Actually we are implementing Mysql as a Service just like AWS's RDS. We will create a super user which will be used by system management. Our customer will have another user which has most of privileges including "CREATE USER", so that they can manage account themselves. I want to find out a approach other than Mysql normal privileges to get that
If you have AWS RDS, you will find RDS has a 'rdsadmin' user account. If you run DROP USER 'rdsadmin'#'localhost' you will get a error: ERROR 1396 (HY000): Operation DROP USER failed for 'rdsadmin'#'localhost'. I'm curious how to implement that.
I tried add a trigger on mysq.user table to throw a error when user delete 'rdsadmin' from table. but the trigger only work for DELETE FROM USER ... sql not for DROP USER. Do you know the reason, or is there any way to fix it?
It is not possible to grant privileges to specified users, CREATE USER is a global privilege.
I'd suggest you to separate MySQL users, for example - there are can be some of them: for administrating (with root privileges), for developers (to access and change database objects and tables data), and so on...
You can use this work around by creating an database API.
The SQL code should help you.
CREATE TABLE mysql.`created_users` (
`user_name` varchar(255) DEFAULT NULL,
`owner` varchar(255) DEFAULT NULL
)
The table hold the usernames and what user created them.
Note create the Procedures with your root account
Procedure to create an mysql user.
DROP PROCEDURE IF EXISTS mysql.createUser;
DELIMITER //
CREATE PROCEDURE mysql.createUser(IN userName VARCHAR(255), IN userPassword VARCHAR(255))
BEGIN
SET #createUserQuery = CONCAT('
CREATE USER "',userName,'"#"localhost" IDENTIFIED BY "',userPassword,'" '
);
PREPARE stmt FROM #createUserQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #createcreatedUserQuery = CONCAT('
INSERT INTO mysql.created_users (user_name, owner) VALUE("',userName,'", "',USER(),'")'
);
PREPARE stmt FROM #createcreatedUserQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END //
DELIMITER ;
Procedure to drop and with check on created_users table to make sure the user exists and delete right check.
DROP PROCEDURE IF EXISTS mysql.dropUser;
DELIMITER //
CREATE PROCEDURE mysql.dropUser(IN userName VARCHAR(255))
BEGIN
SET #canDeleteUser = 0;
SET #createCountUserQuery = CONCAT('
SELECT COUNT(*) FROM mysql.created_users WHERE user_name = "',userName,'" AND owner = "',USER(),'" INTO #canDeleteUser'
);
PREPARE stmt FROM #createCountUserQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
IF #canDeleteUser = 0 THEN
SIGNAL SQLSTATE '45000'
SET MESSAGE_TEXT = 'The user is not known on the server or you dont have rights to delete this user';
END IF;
IF #canDeleteUser = 1 THEN
SET #createDropUserQuery = CONCAT('
DROP USER "',userName,'"#"localhost"'
);
PREPARE stmt FROM #createDropUserQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
SET #createDeleteUserQuery = CONCAT('
DELETE FROM created_users WHERE user_name = "',userName,'" AND owner = "',USER(),'"'
);
PREPARE stmt FROM #createDeleteUserQuery;
EXECUTE stmt;
DEALLOCATE PREPARE stmt;
END IF;
END //
DELIMITER ;
And to give rights to execute these
GRANT EXECUTE ON PROCEDURE mysql.createUser TO '[user]'#'localhost';
GRANT EXECUTE ON PROCEDURE mysql.dropUser TO '[user]'#'localhost';
And you may want to give the user select priv on mysql.proc so they can see the source code behind the procedures and know the parameters
You can use the database API like this.
CALL mysql.createUser('user', 'password');
CALL mysql.dropUser('user');
Note that root account can only remove users with mysql.dropUser that have the owner root#localhost
As Devart said, You cannot change the privileges of CREATE USER.
However, what it appears like you are doing is provisioning mysql instances out to users to control for themselves. To that end, how about a server management tool. There's many out there, to include froxlor Server Management Studio (which is free and open source): https://www.froxlor.org/
It's just a thought.

Create procedure ERROR 1046 (3D000): No database selected

I am trying to create a simple procedure which would create a new database.
complete code which i am trying to run over mysql is :
SET #DB_NAME := "mydb";
SET #DB_CREATE:= "CREATE DATABASE ";
DELIMITER //
drop procedure if exists create_db //
create procedure create_db(name TEXT)
BEGIN
DECLARE temp TEXT;
DECLARE user TEXT;
SELECT SCHEMA_NAME FROM INFORMATION_SCHEMA.SCHEMATA WHERE SCHEMA_NAME = name INTO temp;
if temp = name then
SIGNAL SQLSTATE '45002' SET MESSAGE_TEXT = 'This database already exist';
else
SELECT USER() INTO user;
SET #s = CONCAT('CREATE DATABASE ', name);
PREPARE stmt_create FROM #s;
EXECUTE stmt_create;
DEALLOCATE PREPARE stmt_create;
SET #s = CONCAT('GRANT ALL PRIVILEGES ON ', name, '.* TO ', user, ' WITH GRANT OPTION');
PREPARE stmt_grant FROM #s;
EXECUTE stmt_grant;
DEALLOCATE PREPARE stmt_grant;
END IF;
END //
DELIMITER ;
call create_db(#DB_NAME);
I took the help of how do I use a variable in create database statement for creating this procedure.
While running this procedure over mysql i am getting error :
ERROR 1046 (3D000): No database selected
I have googled it a lot but is unable to fix it.
While trying different things i tried to execute the above procedure by first executing:
mysql> USE mysql;
Using that, error is gone. And
mysql> show databases;
is displaying all the databases along with the newly created database. Could somebody tell me whether using mysql as default database is correct or not.
If somebody has another method please tell it to me.
Use the :: use database to select the database to which you want the proc to be created or
try using databasename.
create procedure databasename.create_db(name TEXT)
I don't believe you can have functions that are "GLOBAL" i.e. outside the scope of a database, so not selecting a database before calling your function is not possible

syntax error from CREATE USER with variables giving username and password

Stored procedure code:
CREATE DEFINER = `root` #`localhost` PROCEDURE `P_CreateUser3` (
IN _Username NVARCHAR(30), IN _Password NVARCHAR(32), IN _DBName VARCHAR(20))
BEGIN
CREATE USER _Username #'localhost' IDENTIFIED BY _Password ;
GRANT SELECT, UPDATE, DELETE, INSERT
ON _DBName.*
TO _Username #'localhost'
WITH GRANT OPTION ;
END $$
Error Code: 1064
You have an error in your SQL syntax; check the manual that corresponds to your MySQL server version for the right syntax to use near '_Password ;
GRANT
SELECT,
UPDATE,
DELETE,
INSERT
ON
`pr' at line 6
help me please.
Unfortunately, the use of stored procedure input parameters as passwords in a CREATE USER or GRANT statement is documented in this bug as unsupported. So you cannot actually do what you attempted.
It would be possible to PREPARE and EXECUTE a statement which is built by CONCAT() to concatenate in the new password, but this is not a secure method and is therefore not recommended. You lose all the security benefits of the stored procedure if you were to do it that way.
You must use prepared statements because the variables doesn't evaluate directly in queries.
DELIMITER $$
DROP PROCEDURE IF EXISTS `create_user`$$
CREATE PROCEDURE `create_user`(
`user_name` VARCHAR(50),
`passwd` VARCHAR(255),
`ip` VARCHAR(50)
)
BEGIN
set #sql = concat("CREATE USER '",`user_name`,"'#'",`ip`,"' IDENTIFIED BY '",`passwd`,"'");
PREPARE stmt1 FROM #sql;
EXECUTE stmt1;
DEALLOCATE PREPARE stmt1;
set #sql = concat("GRANT ALL PRIVILEGES ON * . * TO '",`user_name`,"'#'",`ip`,"' ");
PREPARE stmt2 FROM #sql;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
FLUSH PRIVILEGES;
END$$
DELIMITER ;

How do I create a mysql view with a user variable in the name

I'm using mysql 5.5, trying to write a script to create users, views, and grant select privileges on those views. Here's what I have so far.
set #type_id := 1;
set #username := 'somecompany';
set #password := 'company1234';
set #prefix := 'somecompany';
CREATE OR REPLACE VIEW CONCAT(#prefix, '_report') AS
SELECT * FROM my_table
WHERE type_id = #type_id;
Which won't work because it isn't looking for a string for the view name. I got around this for creating users with the statement:
INSERT INTO mysql.user (Host, User, Password) VALUES ('%', #username, PASSWORD(#password));
Is there a similar trick I can use to create views and grant select on those views to the user I created?
You can use Prepared Statements to execute this queries. Just construct the query as a string and run it with prepared statements.
Edit
MySQL 5.5.12-log
SET #s = 'CREATE VIEW view_actor AS SELECT * FROM sakila.actor;';
PREPARE stmt2 FROM #s;
EXECUTE stmt2;
DEALLOCATE PREPARE stmt2;
-- Check CREATE VIEW
SHOW CREATE VIEW view_actor;
CREATE ALGORITHM=UNDEFINED DEFINER=`root`#`%` SQL SECURITY DEFINER VIEW `view_actor` AS select `sakila`.`actor`.`actor_id` AS `actor_id`,`sakila`.`actor`.`first_name` AS `first_name`,`sakila`.`actor`.`last_name` AS `last_name`,`sakila`.`actor`.`last_update` AS `last_update` from `sakila`.`actor`