Bug #17573 Security Elevation Problem: DROP USER does not drop that users procedures
Submitted: 20 Feb 2006 10:56 Modified: 20 Feb 2006 11:50
Reporter: Kristian Koehntopp Email Updates:
Status: Duplicate Impact on me:
None 
Category:MySQL Server Severity:S2 (Serious)
Version:5.0.18 OS:Linux (Linux)
Assigned to: CPU Architecture:Any

[20 Feb 2006 10:56] Kristian Koehntopp
Description:
DROP USER does not drop that users procedures. The status of these procedures is silently changed to SQL SECURITY INVOKER. 

A procedure that was previously executed with access permissions "a"@"%" is now executed as "root"@"localhost" as demonstrated.

How to repeat:
As root:

root@localhost [mysql]> select version();
+----------------+
| version()      |
+----------------+
| 5.0.18-max-log |
+----------------+
1 row in set (0.00 sec)

root@localhost [mysql]> drop user "a"$$
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> drop user "b"$$
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> delimiter ;
root@localhost [mysql]> create user "a";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> create user "b";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> grant all on boom.* to "a";
Query OK, 0 rows affected (0.00 sec)

root@localhost [mysql]> grant all on boom.* to "b";
Query OK, 0 rows affected (0.00 sec)

As a:
a@localhost [boom]> delimiter $$
a@localhost [boom]> create procedure blah() sql security definer begin select current_user(), session_user(); end; $$
Query OK, 0 rows affected (0.00 sec)

a@localhost [boom]> call blah()$$
+----------------+----------------+
| current_user() | session_user() |
+----------------+----------------+
| a@%            | a@localhost    |
+----------------+----------------+
1 row in set (0.00 sec)

As b:
b@localhost [boom]> call blah();
+----------------+----------------+
| current_user() | session_user() |
+----------------+----------------+
| a@%            | b@localhost    |
+----------------+----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.00 sec)

As root:
root@localhost [(none)]> drop user a;
Query OK, 0 rows affected (0.00 sec)

root@localhost [(none)]> select user, host, password from mysql.user;
+------+-----------+----------+
| user | host      | password |
+------+-----------+----------+
| root | localhost |          |
| b    | %         |          |
+------+-----------+----------+
2 rows in set (0.00 sec)

root@localhost [(none)]> show procedure status\G
*************************** 1. row ***************************
           Db: boom
         Name: blah
         Type: PROCEDURE
      Definer: a@%
     Modified: 2006-02-20 11:49:35
      Created: 2006-02-20 11:49:35
Security_type: DEFINER
      Comment:
root@localhost [(none)]> call boom.blah();
+----------------+----------------+
| current_user() | session_user() |
+----------------+----------------+
| root@localhost | root@localhost |
+----------------+----------------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.01 sec)

Suggested fix:
a) A DROP USER should drop all procedures associated with that user just as DROP DATABASE drops them.
b) Alternatively, the procedure definitions are kept and set to INVALID (this requires the introduction of a status flag for Procedure Objects).
[20 Feb 2006 11:29] Kristian Koehntopp
The same problem affects triggers.

root@localhost [boom]> show create table t\G
*************************** 1. row ***************************
       Table: t
Create Table: CREATE TABLE `t` (
  `id` bigint(20) unsigned NOT NULL,
  `cu` varchar(80) NOT NULL,
  `su` varchar(80) NOT NULL
) ENGINE=MyISAM DEFAULT CHARSET=utf8
1 row in set (0.00 sec)

root@localhost [boom]> show triggers\G
*************************** 1. row ***************************
  Trigger: insert_t
    Event: INSERT
    Table: t
Statement:   begin set new.cu = current_user(), new.su=session_user(); end
   Timing: BEFORE
  Created: NULL
 sql_mode:
  Definer: a@%
1 row in set (0.00 sec)

root@localhost [boom]> insert into t (id) values ( 2);
Query OK, 1 row affected, 2 warnings (0.01 sec)

root@localhost [boom]> select * from t;
+----+-----+----------------+
| id | cu  | su             |
+----+-----+----------------+
|  1 | a@% | a@localhost    |
|  2 | a@% | root@localhost |
+----+-----+----------------+
2 rows in set (0.00 sec)

root@localhost [boom]> drop user a;
Query OK, 0 rows affected (0.00 sec)

root@localhost [boom]> insert into t (id) values ( 3);
Query OK, 1 row affected, 2 warnings (0.00 sec)

root@localhost [boom]> select * from t;
+----+----------------+----------------+
| id | cu             | su             |
+----+----------------+----------------+
|  1 | a@%            | a@localhost    |
|  2 | a@%            | root@localhost |
|  3 | root@localhost | root@localhost |
+----+----------------+----------------+
3 rows in set (0.00 sec)
[20 Feb 2006 11:50] Alexander Nozdrin
This bug is a duplicate of BUG#13198.

1. As it was said in BUG#13198, in 5.0 we can not implement CASCADE/RESTRICT semantics of DROP statements.

2. However, we should deny execution of the routines with non-existent definer.