Commit 55171821 authored by unknown's avatar unknown

Bug#10246 - Parser: bad syntax for GRANT EXECUTE

  Rename some functions
  more fine-grained sp privileges
  make grant/revoke sp grammar less ambigious


mysql-test/r/sp-security.result:
  change test for new syntax
mysql-test/r/system_mysql_db.result:
  change test for new syntax
mysql-test/t/sp-security.test:
  change test for new syntax
scripts/mysql_create_system_tables.sh:
  now store routine_type for procs_priv
scripts/mysql_fix_privilege_tables.sql:
  now store routine_type for procs_priv
sql/item_func.cc:
  rename of function
sql/mysql_priv.h:
  rename of function
sql/sp_head.cc:
  extra arg for check_some_routine_access
sql/sql_acl.cc:
  rename of function. now handle func/proc acls seperately
sql/sql_acl.h:
  rename of function
sql/sql_parse.cc:
  rename of function
  grants for procs handled distinctly from funcs
sql/sql_show.cc:
  check_some_routine_access extra arg
sql/sql_base.cc:
  fix for build
sql/sql_yacc.yy:
  fix for build
parent 9b07cafe
...@@ -23,10 +23,10 @@ root@localhost 1 ...@@ -23,10 +23,10 @@ root@localhost 1
select db(); select db();
db() db()
db1_secret db1_secret
grant execute on db1_secret.stamp to user1@'%'; grant execute on procedure db1_secret.stamp to user1@'%';
grant execute on db1_secret.db to user1@'%'; grant execute on function db1_secret.db to user1@'%';
grant execute on db1_secret.stamp to ''@'%'; grant execute on procedure db1_secret.stamp to ''@'%';
grant execute on db1_secret.db to ''@'%'; grant execute on function db1_secret.db to ''@'%';
call db1_secret.stamp(2); call db1_secret.stamp(2);
select db1_secret.db(); select db1_secret.db();
db1_secret.db() db1_secret.db()
...@@ -105,8 +105,8 @@ select * from t2; ...@@ -105,8 +105,8 @@ select * from t2;
s1 s1
0 0
2 2
grant usage on db2.q to user2@localhost with grant option; grant usage on procedure db2.q to user2@localhost with grant option;
grant execute on db2.q to user1@localhost; grant execute on procedure db2.q to user1@localhost;
use db2; use db2;
call q(); call q();
select * from t2; select * from t2;
...@@ -117,9 +117,9 @@ s1 ...@@ -117,9 +117,9 @@ s1
alter procedure p modifies sql data; alter procedure p modifies sql data;
drop procedure p; drop procedure p;
alter procedure q modifies sql data; alter procedure q modifies sql data;
ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q' ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db2.q'
drop procedure q; drop procedure q;
ERROR 42000: alter procedure command denied to user 'user1'@'localhost' for routine 'db2.q' ERROR 42000: alter routine command denied to user 'user1'@'localhost' for routine 'db2.q'
use db2; use db2;
alter procedure q modifies sql data; alter procedure q modifies sql data;
drop procedure q; drop procedure q;
...@@ -141,52 +141,52 @@ create database sptest; ...@@ -141,52 +141,52 @@ create database sptest;
create table t1 ( u varchar(64), i int ); create table t1 ( u varchar(64), i int );
create procedure sptest.p1(i int) insert into test.t1 values (user(), i); create procedure sptest.p1(i int) insert into test.t1 values (user(), i);
grant insert on t1 to usera@localhost; grant insert on t1 to usera@localhost;
grant execute on sptest.p1 to usera@localhost; grant execute on procedure sptest.p1 to usera@localhost;
show grants for usera@localhost; show grants for usera@localhost;
Grants for usera@localhost Grants for usera@localhost
GRANT USAGE ON *.* TO 'usera'@'localhost' GRANT USAGE ON *.* TO 'usera'@'localhost'
GRANT INSERT ON `test`.`t1` TO 'usera'@'localhost' GRANT INSERT ON `test`.`t1` TO 'usera'@'localhost'
GRANT EXECUTE ON `sptest`.`p1` TO 'usera'@'localhost' GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'usera'@'localhost'
grant execute on sptest.p1 to userc@localhost with grant option; grant execute on procedure sptest.p1 to userc@localhost with grant option;
show grants for userc@localhost; show grants for userc@localhost;
Grants for userc@localhost Grants for userc@localhost
GRANT USAGE ON *.* TO 'userc'@'localhost' GRANT USAGE ON *.* TO 'userc'@'localhost'
GRANT EXECUTE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION
call sptest.p1(1); call sptest.p1(1);
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
ERROR 42000: grant command denied to user 'usera'@'localhost' for routine 'sptest.p1' ERROR 42000: grant command denied to user 'usera'@'localhost' for routine 'sptest.p1'
drop procedure sptest.p1; drop procedure sptest.p1;
ERROR 42000: alter procedure command denied to user 'usera'@'localhost' for routine 'sptest.p1' ERROR 42000: alter routine command denied to user 'usera'@'localhost' for routine 'sptest.p1'
call sptest.p1(2); call sptest.p1(2);
ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1' ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1'
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1' ERROR 42000: execute command denied to user 'userb'@'localhost' for routine 'sptest.p1'
drop procedure sptest.p1; drop procedure sptest.p1;
ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1' ERROR 42000: alter routine command denied to user 'userb'@'localhost' for routine 'sptest.p1'
call sptest.p1(3); call sptest.p1(3);
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
drop procedure sptest.p1; drop procedure sptest.p1;
ERROR 42000: alter procedure command denied to user 'userc'@'localhost' for routine 'sptest.p1' ERROR 42000: alter routine command denied to user 'userc'@'localhost' for routine 'sptest.p1'
call sptest.p1(4); call sptest.p1(4);
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
ERROR 42000: grant command denied to user 'userb'@'localhost' for routine 'sptest.p1' ERROR 42000: grant command denied to user 'userb'@'localhost' for routine 'sptest.p1'
drop procedure sptest.p1; drop procedure sptest.p1;
ERROR 42000: alter procedure command denied to user 'userb'@'localhost' for routine 'sptest.p1' ERROR 42000: alter routine command denied to user 'userb'@'localhost' for routine 'sptest.p1'
select * from t1; select * from t1;
u i u i
usera@localhost 1 usera@localhost 1
userc@localhost 3 userc@localhost 3
userb@localhost 4 userb@localhost 4
grant all privileges on sptest.p1 to userc@localhost; grant all privileges on procedure sptest.p1 to userc@localhost;
show grants for userc@localhost; show grants for userc@localhost;
Grants for userc@localhost Grants for userc@localhost
GRANT USAGE ON *.* TO 'userc'@'localhost' GRANT USAGE ON *.* TO 'userc'@'localhost'
GRANT EXECUTE, ALTER ROUTINE ON `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION GRANT EXECUTE, ALTER ROUTINE ON PROCEDURE `sptest`.`p1` TO 'userc'@'localhost' WITH GRANT OPTION
show grants for userb@localhost; show grants for userb@localhost;
Grants for userb@localhost Grants for userb@localhost
GRANT USAGE ON *.* TO 'userb'@'localhost' GRANT USAGE ON *.* TO 'userb'@'localhost'
GRANT EXECUTE ON `sptest`.`p1` TO 'userb'@'localhost' GRANT EXECUTE ON PROCEDURE `sptest`.`p1` TO 'userb'@'localhost'
revoke all privileges on sptest.p1 from userb@localhost; revoke all privileges on procedure sptest.p1 from userb@localhost;
show grants for userb@localhost; show grants for userb@localhost;
Grants for userb@localhost Grants for userb@localhost
GRANT USAGE ON *.* TO 'userb'@'localhost' GRANT USAGE ON *.* TO 'userb'@'localhost'
......
...@@ -152,10 +152,11 @@ procs_priv CREATE TABLE `procs_priv` ( ...@@ -152,10 +152,11 @@ procs_priv CREATE TABLE `procs_priv` (
`Db` char(64) collate utf8_bin NOT NULL default '', `Db` char(64) collate utf8_bin NOT NULL default '',
`User` char(16) collate utf8_bin NOT NULL default '', `User` char(16) collate utf8_bin NOT NULL default '',
`Routine_name` char(64) collate utf8_bin NOT NULL default '', `Routine_name` char(64) collate utf8_bin NOT NULL default '',
`Routine_type` enum('FUNCTION','PROCEDURE') collate utf8_bin NOT NULL default 'FUNCTION',
`Grantor` char(77) collate utf8_bin NOT NULL default '', `Grantor` char(77) collate utf8_bin NOT NULL default '',
`Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
`Proc_priv` set('Execute','Alter Routine','Grant') character set utf8 NOT NULL default '', `Proc_priv` set('Execute','Alter Routine','Grant') character set utf8 NOT NULL default '',
PRIMARY KEY (`Host`,`Db`,`User`,`Routine_name`), `Timestamp` timestamp NOT NULL default CURRENT_TIMESTAMP on update CURRENT_TIMESTAMP,
PRIMARY KEY (`Host`,`Db`,`User`,`Routine_name`,`Routine_type`),
KEY `Grantor` (`Grantor`) KEY `Grantor` (`Grantor`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Procedure privileges' ) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin COMMENT='Procedure privileges'
show create table proc; show create table proc;
......
...@@ -43,10 +43,10 @@ call stamp(1); ...@@ -43,10 +43,10 @@ call stamp(1);
select * from t1; select * from t1;
select db(); select db();
grant execute on db1_secret.stamp to user1@'%'; grant execute on procedure db1_secret.stamp to user1@'%';
grant execute on db1_secret.db to user1@'%'; grant execute on function db1_secret.db to user1@'%';
grant execute on db1_secret.stamp to ''@'%'; grant execute on procedure db1_secret.stamp to ''@'%';
grant execute on db1_secret.db to ''@'%'; grant execute on function db1_secret.db to ''@'%';
connect (con2user1,localhost,user1,,); connect (con2user1,localhost,user1,,);
connect (con3anon,localhost,anon,,); connect (con3anon,localhost,anon,,);
...@@ -183,10 +183,10 @@ call q(); ...@@ -183,10 +183,10 @@ call q();
select * from t2; select * from t2;
connection con1root; connection con1root;
grant usage on db2.q to user2@localhost with grant option; grant usage on procedure db2.q to user2@localhost with grant option;
connection con4user2; connection con4user2;
grant execute on db2.q to user1@localhost; grant execute on procedure db2.q to user1@localhost;
connection con2user1; connection con2user1;
use db2; use db2;
...@@ -245,9 +245,9 @@ create database sptest; ...@@ -245,9 +245,9 @@ create database sptest;
create table t1 ( u varchar(64), i int ); create table t1 ( u varchar(64), i int );
create procedure sptest.p1(i int) insert into test.t1 values (user(), i); create procedure sptest.p1(i int) insert into test.t1 values (user(), i);
grant insert on t1 to usera@localhost; grant insert on t1 to usera@localhost;
grant execute on sptest.p1 to usera@localhost; grant execute on procedure sptest.p1 to usera@localhost;
show grants for usera@localhost; show grants for usera@localhost;
grant execute on sptest.p1 to userc@localhost with grant option; grant execute on procedure sptest.p1 to userc@localhost with grant option;
show grants for userc@localhost; show grants for userc@localhost;
connect (con2usera,localhost,usera,,); connect (con2usera,localhost,usera,,);
...@@ -257,7 +257,7 @@ connect (con4userc,localhost,userc,,); ...@@ -257,7 +257,7 @@ connect (con4userc,localhost,userc,,);
connection con2usera; connection con2usera;
call sptest.p1(1); call sptest.p1(1);
--error 1370 --error 1370
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
--error 1370 --error 1370
drop procedure sptest.p1; drop procedure sptest.p1;
...@@ -265,32 +265,32 @@ connection con3userb; ...@@ -265,32 +265,32 @@ connection con3userb;
--error 1370 --error 1370
call sptest.p1(2); call sptest.p1(2);
--error 1370 --error 1370
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
--error 1370 --error 1370
drop procedure sptest.p1; drop procedure sptest.p1;
connection con4userc; connection con4userc;
call sptest.p1(3); call sptest.p1(3);
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
--error 1370 --error 1370
drop procedure sptest.p1; drop procedure sptest.p1;
connection con3userb; connection con3userb;
call sptest.p1(4); call sptest.p1(4);
--error 1370 --error 1370
grant execute on sptest.p1 to userb@localhost; grant execute on procedure sptest.p1 to userb@localhost;
--error 1370 --error 1370
drop procedure sptest.p1; drop procedure sptest.p1;
connection con1root; connection con1root;
select * from t1; select * from t1;
grant all privileges on sptest.p1 to userc@localhost; grant all privileges on procedure sptest.p1 to userc@localhost;
show grants for userc@localhost; show grants for userc@localhost;
show grants for userb@localhost; show grants for userb@localhost;
connection con4userc; connection con4userc;
revoke all privileges on sptest.p1 from userb@localhost; revoke all privileges on procedure sptest.p1 from userb@localhost;
connection con1root; connection con1root;
show grants for userb@localhost; show grants for userb@localhost;
......
...@@ -255,10 +255,11 @@ then ...@@ -255,10 +255,11 @@ then
c_pp="$c_pp Db char(64) binary DEFAULT '' NOT NULL," c_pp="$c_pp Db char(64) binary DEFAULT '' NOT NULL,"
c_pp="$c_pp User char(16) binary DEFAULT '' NOT NULL," c_pp="$c_pp User char(16) binary DEFAULT '' NOT NULL,"
c_pp="$c_pp Routine_name char(64) binary DEFAULT '' NOT NULL," c_pp="$c_pp Routine_name char(64) binary DEFAULT '' NOT NULL,"
c_pp="$c_pp Routine_type enum('FUNCTION','PROCEDURE') NOT NULL,"
c_pp="$c_pp Grantor char(77) DEFAULT '' NOT NULL," c_pp="$c_pp Grantor char(77) DEFAULT '' NOT NULL,"
c_pp="$c_pp Timestamp timestamp(14),"
c_pp="$c_pp Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL," c_pp="$c_pp Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL,"
c_pp="$c_pp PRIMARY KEY (Host,Db,User,Routine_name)," c_pp="$c_pp Timestamp timestamp(14),"
c_pp="$c_pp PRIMARY KEY (Host,Db,User,Routine_name,Routine_type),"
c_pp="$c_pp KEY Grantor (Grantor)" c_pp="$c_pp KEY Grantor (Grantor)"
c_pp="$c_pp ) engine=MyISAM" c_pp="$c_pp ) engine=MyISAM"
c_pp="$c_pp CHARACTER SET utf8 COLLATE utf8_bin" c_pp="$c_pp CHARACTER SET utf8 COLLATE utf8_bin"
......
...@@ -67,6 +67,10 @@ ALTER TABLE tables_priv ...@@ -67,6 +67,10 @@ ALTER TABLE tables_priv
ALTER TABLE procs_priv ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin; ALTER TABLE procs_priv ENGINE=MyISAM, CONVERT TO CHARACTER SET utf8 COLLATE utf8_bin;
ALTER TABLE procs_priv ALTER TABLE procs_priv
modify Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL; modify Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL;
ALTER TABLE procs_priv
add Routine_type enum('FUNCTION','PROCEDURE') COLLATE utf8_general_ci NOT NULL AFTER Routine_name;
ALTER TABLE procs_priv
modify Timestamp timestamp(14) AFTER Proc_priv;
CREATE TABLE IF NOT EXISTS columns_priv ( CREATE TABLE IF NOT EXISTS columns_priv (
Host char(60) DEFAULT '' NOT NULL, Host char(60) DEFAULT '' NOT NULL,
...@@ -316,10 +320,11 @@ Host char(60) binary DEFAULT '' NOT NULL, ...@@ -316,10 +320,11 @@ Host char(60) binary DEFAULT '' NOT NULL,
Db char(64) binary DEFAULT '' NOT NULL, Db char(64) binary DEFAULT '' NOT NULL,
User char(16) binary DEFAULT '' NOT NULL, User char(16) binary DEFAULT '' NOT NULL,
Routine_name char(64) binary DEFAULT '' NOT NULL, Routine_name char(64) binary DEFAULT '' NOT NULL,
Routine_type enum('FUNCTION','PROCEDURE') NOT NULL,
Grantor char(77) DEFAULT '' NOT NULL, Grantor char(77) DEFAULT '' NOT NULL,
Timestamp timestamp(14),
Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL, Proc_priv set('Execute','Alter Routine','Grant') COLLATE utf8_general_ci DEFAULT '' NOT NULL,
PRIMARY KEY (Host,Db,User,Routine_name), Timestamp timestamp(14),
PRIMARY KEY (Host,Db,User,Routine_name,Routine_type),
KEY Grantor (Grantor) KEY Grantor (Grantor)
) CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges'; ) CHARACTER SET utf8 COLLATE utf8_bin comment='Procedure privileges';
......
...@@ -4771,13 +4771,13 @@ Item_func_sp::execute(Item **itp) ...@@ -4771,13 +4771,13 @@ Item_func_sp::execute(Item **itp)
#endif #endif
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_procedure_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0)) m_sp->m_db.str, m_sp->m_name.str, 0, 0))
DBUG_RETURN(-1); DBUG_RETURN(-1);
sp_change_security_context(thd, m_sp, &save_ctx); sp_change_security_context(thd, m_sp, &save_ctx);
if (save_ctx.changed && if (save_ctx.changed &&
check_procedure_access(thd, EXECUTE_ACL, check_routine_access(thd, EXECUTE_ACL,
m_sp->m_db.str, m_sp->m_name.str, 0)) m_sp->m_db.str, m_sp->m_name.str, 0, 0))
{ {
sp_restore_security_context(thd, m_sp, &save_ctx); sp_restore_security_context(thd, m_sp, &save_ctx);
thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS; thd->client_capabilities|= old_client_capabilites & CLIENT_MULTI_RESULTS;
......
...@@ -473,12 +473,12 @@ void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0, ...@@ -473,12 +473,12 @@ void close_thread_tables(THD *thd, bool locked=0, bool skip_derived=0,
TABLE *stopper= 0); TABLE *stopper= 0);
bool check_one_table_access(THD *thd, ulong privilege, bool check_one_table_access(THD *thd, ulong privilege,
TABLE_LIST *tables); TABLE_LIST *tables);
bool check_procedure_access(THD *thd,ulong want_access,char *db,char *name, bool check_routine_access(THD *thd,ulong want_access,char *db,char *name,
bool no_errors); bool is_proc, bool no_errors);
bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table); bool check_some_access(THD *thd, ulong want_access, TABLE_LIST *table);
bool check_merge_table_access(THD *thd, char *db, bool check_merge_table_access(THD *thd, char *db,
TABLE_LIST *table_list); TABLE_LIST *table_list);
bool check_some_routine_access(THD *thd, const char *db, const char *name); bool check_some_routine_access(THD *thd, const char *db, const char *name, bool is_proc);
bool multi_update_precheck(THD *thd, TABLE_LIST *tables); bool multi_update_precheck(THD *thd, TABLE_LIST *tables);
bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count); bool multi_delete_precheck(THD *thd, TABLE_LIST *tables, uint *table_count);
bool mysql_multi_update_prepare(THD *thd); bool mysql_multi_update_prepare(THD *thd);
......
...@@ -1111,7 +1111,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access) ...@@ -1111,7 +1111,8 @@ bool check_show_routine_access(THD *thd, sp_head *sp, bool *full_access)
(!strcmp(sp->m_definer_user.str, thd->priv_user) && (!strcmp(sp->m_definer_user.str, thd->priv_user) &&
!strcmp(sp->m_definer_host.str, thd->priv_host))); !strcmp(sp->m_definer_host.str, thd->priv_host)));
if (!*full_access) if (!*full_access)
return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str); return check_some_routine_access(thd, sp->m_db.str, sp->m_name.str,
sp->m_type == TYPE_ENUM_PROCEDURE);
return 0; return 0;
} }
......
...@@ -60,7 +60,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs; ...@@ -60,7 +60,7 @@ static DYNAMIC_ARRAY acl_hosts,acl_users,acl_dbs;
static MEM_ROOT mem, memex; static MEM_ROOT mem, memex;
static bool initialized=0; static bool initialized=0;
static bool allow_all_hosts=1; static bool allow_all_hosts=1;
static HASH acl_check_hosts, column_priv_hash, proc_priv_hash; static HASH acl_check_hosts, column_priv_hash, proc_priv_hash, func_priv_hash;
static DYNAMIC_ARRAY acl_wild_hosts; static DYNAMIC_ARRAY acl_wild_hosts;
static hash_filo *acl_cache; static hash_filo *acl_cache;
static uint grant_version=0; /* Version of priv tables. incremented by acl_init */ static uint grant_version=0; /* Version of priv tables. incremented by acl_init */
...@@ -2136,11 +2136,12 @@ static GRANT_NAME *name_hash_search(HASH *name_hash, ...@@ -2136,11 +2136,12 @@ static GRANT_NAME *name_hash_search(HASH *name_hash,
inline GRANT_NAME * inline GRANT_NAME *
proc_hash_search(const char *host, const char *ip, const char *db, routine_hash_search(const char *host, const char *ip, const char *db,
const char *user, const char *tname, bool exact) const char *user, const char *tname, bool proc, bool exact)
{ {
return (GRANT_TABLE*) name_hash_search(&proc_priv_hash, host, ip, db, return (GRANT_TABLE*)
user, tname, exact); name_hash_search(proc ? &proc_priv_hash : &func_priv_hash,
host, ip, db, user, tname, exact);
} }
...@@ -2466,16 +2467,17 @@ table_error: ...@@ -2466,16 +2467,17 @@ table_error:
} }
static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, static int replace_routine_table(THD *thd, GRANT_NAME *grant_name,
TABLE *table, const LEX_USER &combo, TABLE *table, const LEX_USER &combo,
const char *db, const char *proc_name, const char *db, const char *routine_name,
ulong rights, bool revoke_grant) bool is_proc, ulong rights, bool revoke_grant)
{ {
char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2]; char grantor[HOSTNAME_LENGTH+USERNAME_LENGTH+2];
int old_row_exists= 1; int old_row_exists= 1;
int error=0; int error=0;
ulong store_proc_rights; ulong store_proc_rights;
DBUG_ENTER("replace_proc_table"); byte *key;
DBUG_ENTER("replace_routine_table");
if (!initialized) if (!initialized)
{ {
...@@ -2499,7 +2501,10 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, ...@@ -2499,7 +2501,10 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1); table->field[0]->store(combo.host.str,combo.host.length, &my_charset_latin1);
table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1); table->field[1]->store(db,(uint) strlen(db), &my_charset_latin1);
table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1); table->field[2]->store(combo.user.str,combo.user.length, &my_charset_latin1);
table->field[3]->store(proc_name,(uint) strlen(proc_name), &my_charset_latin1); table->field[3]->store(routine_name,(uint) strlen(routine_name),
&my_charset_latin1);
table->field[4]->store((longlong)(is_proc ?
TYPE_ENUM_PROCEDURE : TYPE_ENUM_FUNCTION));
store_record(table,record[1]); // store at pos 1 store_record(table,record[1]); // store at pos 1
if (table->file->index_read_idx(table->record[0],0, if (table->file->index_read_idx(table->record[0],0,
...@@ -2514,7 +2519,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, ...@@ -2514,7 +2519,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
if (revoke_grant) if (revoke_grant)
{ // no row, no revoke { // no row, no revoke
my_error(ER_NONEXISTING_PROC_GRANT, MYF(0), my_error(ER_NONEXISTING_PROC_GRANT, MYF(0),
combo.user.str, combo.host.str, proc_name); combo.user.str, combo.host.str, routine_name);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
old_row_exists= 0; old_row_exists= 0;
...@@ -2539,7 +2544,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, ...@@ -2539,7 +2544,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
} }
} }
table->field[4]->store(grantor,(uint) strlen(grantor), &my_charset_latin1); table->field[5]->store(grantor,(uint) strlen(grantor), &my_charset_latin1);
table->field[6]->store((longlong) store_proc_rights); table->field[6]->store((longlong) store_proc_rights);
rights=fix_rights_for_procedure(store_proc_rights); rights=fix_rights_for_procedure(store_proc_rights);
...@@ -2566,7 +2571,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name, ...@@ -2566,7 +2571,7 @@ static int replace_proc_table(THD *thd, GRANT_NAME *grant_name,
} }
else else
{ {
hash_delete(&proc_priv_hash,(byte*) grant_name); hash_delete(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
} }
DBUG_RETURN(0); DBUG_RETURN(0);
...@@ -2841,12 +2846,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2841,12 +2846,13 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* /*
Store procedure level grants in the privilege tables Store routine level grants in the privilege tables
SYNOPSIS SYNOPSIS
mysql_procedure_grant() mysql_routine_grant()
thd Thread handle thd Thread handle
table_list List of procedures to give grant table_list List of routines to give grant
is_proc true indicates routine list are procedures
user_list List of users to give grant user_list List of users to give grant
rights Table level grant rights Table level grant
revoke_grant Set to 1 if this is a REVOKE command revoke_grant Set to 1 if this is a REVOKE command
...@@ -2856,7 +2862,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2856,7 +2862,7 @@ bool mysql_table_grant(THD *thd, TABLE_LIST *table_list,
1 error 1 error
*/ */
bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, bool mysql_routine_grant(THD *thd, TABLE_LIST *table_list, bool is_proc,
List <LEX_USER> &user_list, ulong rights, List <LEX_USER> &user_list, ulong rights,
bool revoke_grant, bool no_error) bool revoke_grant, bool no_error)
{ {
...@@ -2865,7 +2871,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2865,7 +2871,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
TABLE_LIST tables[2]; TABLE_LIST tables[2];
bool create_new_users=0, result=0; bool create_new_users=0, result=0;
char *db_name, *table_name; char *db_name, *table_name;
DBUG_ENTER("mysql_procedure_grant"); DBUG_ENTER("mysql_routine_grant");
if (!initialized) if (!initialized)
{ {
...@@ -2884,7 +2890,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2884,7 +2890,7 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
if (!revoke_grant) if (!revoke_grant)
{ {
if (sp_exists_routine(thd, table_list, 0, no_error)<0) if (sp_exists_routine(thd, table_list, is_proc, no_error)<0)
DBUG_RETURN(TRUE); DBUG_RETURN(TRUE);
} }
...@@ -2957,8 +2963,8 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2957,8 +2963,8 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
db_name= table_list->db; db_name= table_list->db;
table_name= table_list->table_name; table_name= table_list->table_name;
grant_name= proc_hash_search(Str->host.str, NullS, db_name, grant_name= routine_hash_search(Str->host.str, NullS, db_name,
Str->user.str, table_name, 1); Str->user.str, table_name, is_proc, 1);
if (!grant_name) if (!grant_name)
{ {
if (revoke_grant) if (revoke_grant)
...@@ -2977,11 +2983,11 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2977,11 +2983,11 @@ bool mysql_procedure_grant(THD *thd, TABLE_LIST *table_list,
result= TRUE; result= TRUE;
continue; continue;
} }
my_hash_insert(&proc_priv_hash,(byte*) grant_name); my_hash_insert(is_proc ? &proc_priv_hash : &func_priv_hash,(byte*) grant_name);
} }
if (replace_proc_table(thd, grant_name, tables[1].table, *Str, if (replace_routine_table(thd, grant_name, tables[1].table, *Str,
db_name, table_name, rights, revoke_grant)) db_name, table_name, is_proc, rights, revoke_grant))
{ {
result= TRUE; result= TRUE;
continue; continue;
...@@ -3133,6 +3139,9 @@ my_bool grant_init(THD *org_thd) ...@@ -3133,6 +3139,9 @@ my_bool grant_init(THD *org_thd)
(void) hash_init(&proc_priv_hash,system_charset_info, (void) hash_init(&proc_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table, 0,0,0, (hash_get_key) get_grant_table,
0,0); 0,0);
(void) hash_init(&func_priv_hash,system_charset_info,
0,0,0, (hash_get_key) get_grant_table,
0,0);
init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0); init_sql_alloc(&memex, ACL_ALLOC_BLOCK_SIZE, 0);
/* Don't do anything if running with --skip-grant */ /* Don't do anything if running with --skip-grant */
...@@ -3206,6 +3215,8 @@ my_bool grant_init(THD *org_thd) ...@@ -3206,6 +3215,8 @@ my_bool grant_init(THD *org_thd)
do do
{ {
GRANT_NAME *mem_check; GRANT_NAME *mem_check;
longlong proc_type;
HASH *hash;
if (!(mem_check=new GRANT_NAME(p_table))) if (!(mem_check=new GRANT_NAME(p_table)))
{ {
/* This could only happen if we are out memory */ /* This could only happen if we are out memory */
...@@ -3224,11 +3235,27 @@ my_bool grant_init(THD *org_thd) ...@@ -3224,11 +3235,27 @@ my_bool grant_init(THD *org_thd)
continue; continue;
} }
} }
if (p_table->field[4]->val_int() == TYPE_ENUM_PROCEDURE)
{
hash= &proc_priv_hash;
}
else
if (p_table->field[4]->val_int() == TYPE_ENUM_FUNCTION)
{
hash= &func_priv_hash;
}
else
{
sql_print_warning("'procs_priv' entry '%s' "
"ignored, bad routine type",
mem_check->tname);
continue;
}
mem_check->privs= fix_rights_for_procedure(mem_check->privs); mem_check->privs= fix_rights_for_procedure(mem_check->privs);
if (! mem_check->ok()) if (! mem_check->ok())
delete mem_check; delete mem_check;
else if (my_hash_insert(&proc_priv_hash,(byte*) mem_check)) else if (my_hash_insert(hash, (byte*) mem_check))
{ {
delete mem_check; delete mem_check;
grant_option= FALSE; grant_option= FALSE;
...@@ -3272,7 +3299,7 @@ end: ...@@ -3272,7 +3299,7 @@ end:
void grant_reload(THD *thd) void grant_reload(THD *thd)
{ {
HASH old_column_priv_hash, old_proc_priv_hash; HASH old_column_priv_hash, old_proc_priv_hash, old_func_priv_hash;
bool old_grant_option; bool old_grant_option;
MEM_ROOT old_mem; MEM_ROOT old_mem;
DBUG_ENTER("grant_reload"); DBUG_ENTER("grant_reload");
...@@ -3281,6 +3308,7 @@ void grant_reload(THD *thd) ...@@ -3281,6 +3308,7 @@ void grant_reload(THD *thd)
grant_version++; grant_version++;
old_column_priv_hash= column_priv_hash; old_column_priv_hash= column_priv_hash;
old_proc_priv_hash= proc_priv_hash; old_proc_priv_hash= proc_priv_hash;
old_func_priv_hash= func_priv_hash;
old_grant_option= grant_option; old_grant_option= grant_option;
old_mem= memex; old_mem= memex;
...@@ -3290,6 +3318,7 @@ void grant_reload(THD *thd) ...@@ -3290,6 +3318,7 @@ void grant_reload(THD *thd)
grant_free(); /* purecov: deadcode */ grant_free(); /* purecov: deadcode */
column_priv_hash= old_column_priv_hash; /* purecov: deadcode */ column_priv_hash= old_column_priv_hash; /* purecov: deadcode */
proc_priv_hash= old_proc_priv_hash; proc_priv_hash= old_proc_priv_hash;
func_priv_hash= old_func_priv_hash;
grant_option= old_grant_option; /* purecov: deadcode */ grant_option= old_grant_option; /* purecov: deadcode */
memex= old_mem; /* purecov: deadcode */ memex= old_mem; /* purecov: deadcode */
} }
...@@ -3297,6 +3326,7 @@ void grant_reload(THD *thd) ...@@ -3297,6 +3326,7 @@ void grant_reload(THD *thd)
{ {
hash_free(&old_column_priv_hash); hash_free(&old_column_priv_hash);
hash_free(&old_proc_priv_hash); hash_free(&old_proc_priv_hash);
hash_free(&old_func_priv_hash);
free_root(&old_mem,MYF(0)); free_root(&old_mem,MYF(0));
} }
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
...@@ -3540,13 +3570,14 @@ bool check_grant_db(THD *thd,const char *db) ...@@ -3540,13 +3570,14 @@ bool check_grant_db(THD *thd,const char *db)
/**************************************************************************** /****************************************************************************
Check procedure level grants Check routine level grants
SYNPOSIS SYNPOSIS
bool check_grant_procedure() bool check_grant_routine()
thd Thread handler thd Thread handler
want_access Bits of privileges user needs to have want_access Bits of privileges user needs to have
procs List of procedures to check. The user should have 'want_access' procs List of routines to check. The user should have 'want_access'
is_proc True if the list is all procedures, else functions
no_errors If 0 then we write an error. The error is sent directly to no_errors If 0 then we write an error. The error is sent directly to
the client the client
...@@ -3555,13 +3586,13 @@ bool check_grant_db(THD *thd,const char *db) ...@@ -3555,13 +3586,13 @@ bool check_grant_db(THD *thd,const char *db)
1 Error: User did not have the requested privielges 1 Error: User did not have the requested privielges
****************************************************************************/ ****************************************************************************/
bool check_grant_procedure(THD *thd, ulong want_access, bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool no_errors) TABLE_LIST *procs, bool is_proc, bool no_errors)
{ {
TABLE_LIST *table; TABLE_LIST *table;
char *user= thd->priv_user; char *user= thd->priv_user;
char *host= thd->priv_host; char *host= thd->priv_host;
DBUG_ENTER("check_grant_procedure"); DBUG_ENTER("check_grant_routine");
want_access&= ~thd->master_access; want_access&= ~thd->master_access;
if (!want_access) if (!want_access)
...@@ -3571,8 +3602,8 @@ bool check_grant_procedure(THD *thd, ulong want_access, ...@@ -3571,8 +3602,8 @@ bool check_grant_procedure(THD *thd, ulong want_access,
for (table= procs; table; table= table->next_global) for (table= procs; table; table= table->next_global)
{ {
GRANT_NAME *grant_proc; GRANT_NAME *grant_proc;
if ((grant_proc= proc_hash_search(host,thd->ip, if ((grant_proc= routine_hash_search(host,thd->ip, table->db, user,
table->db, user, table->table_name, 0))) table->table_name, is_proc, 0)))
table->grant.privilege|= grant_proc->privs; table->grant.privilege|= grant_proc->privs;
if (want_access & ~table->grant.privilege) if (want_access & ~table->grant.privilege)
...@@ -3594,7 +3625,7 @@ err: ...@@ -3594,7 +3625,7 @@ err:
if (want_access & EXECUTE_ACL) if (want_access & EXECUTE_ACL)
command= "execute"; command= "execute";
else if (want_access & ALTER_PROC_ACL) else if (want_access & ALTER_PROC_ACL)
command= "alter procedure"; command= "alter routine";
else if (want_access & GRANT_ACL) else if (want_access & GRANT_ACL)
command= "grant"; command= "grant";
my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0), my_error(ER_PROCACCESS_DENIED_ERROR, MYF(0),
...@@ -3606,7 +3637,7 @@ err: ...@@ -3606,7 +3637,7 @@ err:
/* /*
Check if routine has any of the Check if routine has any of the
procedure level grants routine level grants
SYNPOSIS SYNPOSIS
bool check_routine_level_acl() bool check_routine_level_acl()
...@@ -3619,15 +3650,15 @@ err: ...@@ -3619,15 +3650,15 @@ err:
1 error 1 error
*/ */
bool check_routine_level_acl(THD *thd, const char *db, const char *name) bool check_routine_level_acl(THD *thd, const char *db, const char *name, bool is_proc)
{ {
bool no_routine_acl= 1; bool no_routine_acl= 1;
if (grant_option) if (grant_option)
{ {
GRANT_NAME *grant_proc; GRANT_NAME *grant_proc;
rw_rdlock(&LOCK_grant); rw_rdlock(&LOCK_grant);
if ((grant_proc= proc_hash_search(thd->priv_host, thd->ip, db, if ((grant_proc= routine_hash_search(thd->priv_host, thd->ip, db,
thd->priv_user, name, 0))) thd->priv_user, name, is_proc, 0)))
no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS); no_routine_acl= !(grant_proc->privs & SHOW_PROC_ACLS);
rw_unlock(&LOCK_grant); rw_unlock(&LOCK_grant);
} }
...@@ -3730,6 +3761,11 @@ static uint command_lengths[]= ...@@ -3730,6 +3761,11 @@ static uint command_lengths[]=
}; };
static int show_routine_grants(THD *thd, LEX_USER *lex_user, HASH *hash,
const char *type, int typelen,
char *buff, int buffsize);
/* /*
SHOW GRANTS; Send grants for a user to the client SHOW GRANTS; Send grants for a user to the client
...@@ -4076,12 +4112,40 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -4076,12 +4112,40 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
/* Add procedure access */ if (show_routine_grants(thd, lex_user, &proc_priv_hash,
for (index=0 ; index < proc_priv_hash.records ; index++) "PROCEDURE", 9, buff, sizeof(buff)))
{
error= -1;
goto end;
}
if (show_routine_grants(thd, lex_user, &func_priv_hash,
"FUNCTION", 8, buff, sizeof(buff)))
{
error= -1;
goto end;
}
end:
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
send_eof(thd);
DBUG_RETURN(error);
}
static int show_routine_grants(THD* thd, LEX_USER *lex_user, HASH *hash,
const char *type, int typelen,
char *buff, int buffsize)
{
uint counter, index;
int error= 0;
Protocol *protocol= thd->protocol;
/* Add routine access */
for (index=0 ; index < hash->records ; index++)
{ {
const char *user; const char *user;
GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, index);
index);
if (!(user=grant_proc->user)) if (!(user=grant_proc->user))
user= ""; user= "";
...@@ -4093,7 +4157,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -4093,7 +4157,7 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
ulong proc_access= grant_proc->privs; ulong proc_access= grant_proc->privs;
if (proc_access != 0) if (proc_access != 0)
{ {
String global(buff, sizeof(buff), system_charset_info); String global(buff, buffsize, system_charset_info);
ulong test_access= proc_access & ~GRANT_ACL; ulong test_access= proc_access & ~GRANT_ACL;
global.length(0); global.length(0);
...@@ -4119,6 +4183,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -4119,6 +4183,8 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
global.append(" ON ",4); global.append(" ON ",4);
global.append(type,typelen);
global.append(' ');
append_identifier(thd, &global, grant_proc->db, append_identifier(thd, &global, grant_proc->db,
strlen(grant_proc->db)); strlen(grant_proc->db));
global.append('.'); global.append('.');
...@@ -4143,15 +4209,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -4143,15 +4209,9 @@ bool mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
} }
end: return error;
VOID(pthread_mutex_unlock(&acl_cache->lock));
rw_unlock(&LOCK_grant);
send_eof(thd);
DBUG_RETURN(error);
} }
/* /*
Make a clear-text version of the requested privilege. Make a clear-text version of the requested privilege.
*/ */
...@@ -4977,7 +5037,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list) ...@@ -4977,7 +5037,7 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list)
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
{ {
uint counter, revoked; uint counter, revoked, is_proc;
int result; int result;
ACL_DB *acl_db; ACL_DB *acl_db;
TABLE_LIST tables[GRANT_TABLES]; TABLE_LIST tables[GRANT_TABLES];
...@@ -5092,12 +5152,12 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) ...@@ -5092,12 +5152,12 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
} while (revoked); } while (revoked);
/* Remove procedure access */ /* Remove procedure access */
do { for (is_proc=0; is_proc<2; is_proc++) do {
for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; ) HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
for (counter= 0, revoked= 0 ; counter < hash->records ; )
{ {
const char *user,*host; const char *user,*host;
GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
counter);
if (!(user=grant_proc->user)) if (!(user=grant_proc->user))
user= ""; user= "";
if (!(host=grant_proc->host.hostname)) if (!(host=grant_proc->host.hostname))
...@@ -5106,9 +5166,10 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) ...@@ -5106,9 +5166,10 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
if (!strcmp(lex_user->user.str,user) && if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(system_charset_info, lex_user->host.str, host)) !my_strcasecmp(system_charset_info, lex_user->host.str, host))
{ {
if (!replace_proc_table(thd,grant_proc,tables[4].table,*lex_user, if (!replace_routine_table(thd,grant_proc,tables[4].table,*lex_user,
grant_proc->db, grant_proc->db,
grant_proc->tname, grant_proc->tname,
is_proc,
~0, 1)) ~0, 1))
{ {
revoked= 1; revoked= 1;
...@@ -5146,11 +5207,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list) ...@@ -5146,11 +5207,13 @@ bool mysql_revoke_all(THD *thd, List <LEX_USER> &list)
< 0 Error. Error message not yet sent. < 0 Error. Error message not yet sent.
*/ */
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
{ {
uint counter, revoked; uint counter, revoked;
int result; int result;
TABLE_LIST tables[GRANT_TABLES]; TABLE_LIST tables[GRANT_TABLES];
HASH *hash= is_proc ? &proc_priv_hash : &func_priv_hash;
DBUG_ENTER("sp_revoke_privileges"); DBUG_ENTER("sp_revoke_privileges");
if ((result= open_grant_tables(thd, tables))) if ((result= open_grant_tables(thd, tables)))
...@@ -5162,10 +5225,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) ...@@ -5162,10 +5225,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
/* Remove procedure access */ /* Remove procedure access */
do do
{ {
for (counter= 0, revoked= 0 ; counter < proc_priv_hash.records ; ) for (counter= 0, revoked= 0 ; counter < hash->records ; )
{ {
GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(&proc_priv_hash, GRANT_NAME *grant_proc= (GRANT_NAME*) hash_element(hash, counter);
counter);
if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) && if (!my_strcasecmp(system_charset_info, grant_proc->db, sp_db) &&
!my_strcasecmp(system_charset_info, grant_proc->tname, sp_name)) !my_strcasecmp(system_charset_info, grant_proc->tname, sp_name))
{ {
...@@ -5174,8 +5236,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) ...@@ -5174,8 +5236,9 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
lex_user.user.length= strlen(grant_proc->user); lex_user.user.length= strlen(grant_proc->user);
lex_user.host.str= grant_proc->host.hostname; lex_user.host.str= grant_proc->host.hostname;
lex_user.host.length= strlen(grant_proc->host.hostname); lex_user.host.length= strlen(grant_proc->host.hostname);
if (!replace_proc_table(thd,grant_proc,tables[4].table,lex_user, if (!replace_routine_table(thd,grant_proc,tables[4].table,lex_user,
grant_proc->db, grant_proc->tname, ~0, 1)) grant_proc->db, grant_proc->tname,
is_proc, ~0, 1))
{ {
revoked= 1; revoked= 1;
continue; continue;
...@@ -5211,7 +5274,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name) ...@@ -5211,7 +5274,8 @@ bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name)
< 0 Error. Error message not yet sent. < 0 Error. Error message not yet sent.
*/ */
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name) bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc)
{ {
LEX_USER *combo; LEX_USER *combo;
TABLE_LIST tables[1]; TABLE_LIST tables[1];
...@@ -5249,7 +5313,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name) ...@@ -5249,7 +5313,7 @@ bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name)
thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED; thd->lex->ssl_type= SSL_TYPE_NOT_SPECIFIED;
bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh)); bzero((char*) &thd->lex->mqh, sizeof(thd->lex->mqh));
result= mysql_procedure_grant(thd, tables, user_list, result= mysql_routine_grant(thd, tables, is_proc, user_list,
DEFAULT_CREATE_PROC_ACLS, 0, 1); DEFAULT_CREATE_PROC_ACLS, 0, 1);
DBUG_RETURN(result); DBUG_RETURN(result);
} }
......
...@@ -185,7 +185,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list, ...@@ -185,7 +185,7 @@ bool mysql_grant(THD *thd, const char *db, List <LEX_USER> &user_list,
bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list, bool mysql_table_grant(THD *thd, TABLE_LIST *table, List <LEX_USER> &user_list,
List <LEX_COLUMN> &column_list, ulong rights, List <LEX_COLUMN> &column_list, ulong rights,
bool revoke); bool revoke);
bool mysql_procedure_grant(THD *thd, TABLE_LIST *table, bool mysql_routine_grant(THD *thd, TABLE_LIST *table, bool is_proc,
List <LEX_USER> &user_list, ulong rights, List <LEX_USER> &user_list, ulong rights,
bool revoke, bool no_error); bool revoke, bool no_error);
ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx); ACL_USER *check_acl_user(LEX_USER *user_name, uint *acl_acl_userdx);
...@@ -200,8 +200,8 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant, ...@@ -200,8 +200,8 @@ bool check_grant_column (THD *thd, GRANT_INFO *grant,
bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant, bool check_grant_all_columns(THD *thd, ulong want_access, GRANT_INFO *grant,
const char* db_name, const char *table_name, const char* db_name, const char *table_name,
Field_iterator *fields); Field_iterator *fields);
bool check_grant_procedure(THD *thd, ulong want_access, bool check_grant_routine(THD *thd, ulong want_access,
TABLE_LIST *procs, bool no_error); TABLE_LIST *procs, bool is_proc, bool no_error);
bool check_grant_db(THD *thd,const char *db); bool check_grant_db(THD *thd,const char *db);
ulong get_table_grant(THD *thd, TABLE_LIST *table); ulong get_table_grant(THD *thd, TABLE_LIST *table);
ulong get_column_grant(THD *thd, GRANT_INFO *grant, ulong get_column_grant(THD *thd, GRANT_INFO *grant,
...@@ -216,9 +216,12 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list); ...@@ -216,9 +216,12 @@ bool mysql_rename_user(THD *thd, List <LEX_USER> &list);
bool mysql_revoke_all(THD *thd, List <LEX_USER> &list); bool mysql_revoke_all(THD *thd, List <LEX_USER> &list);
void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant, void fill_effective_table_privileges(THD *thd, GRANT_INFO *grant,
const char *db, const char *table); const char *db, const char *table);
bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name); bool sp_revoke_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name); bool is_proc);
bool check_routine_level_acl(THD *thd, const char *db, const char *name); bool sp_grant_privileges(THD *thd, const char *sp_db, const char *sp_name,
bool is_proc);
bool check_routine_level_acl(THD *thd, const char *db, const char *name,
bool is_proc);
#ifdef NO_EMBEDDED_ACCESS_CHECKS #ifdef NO_EMBEDDED_ACCESS_CHECKS
#define check_grant(A,B,C,D,E,F) 0 #define check_grant(A,B,C,D,E,F) 0
......
...@@ -3307,7 +3307,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table, ...@@ -3307,7 +3307,7 @@ bool get_key_map_from_key_list(key_map *map, TABLE *table,
0) 0)
{ {
my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(), my_error(ER_KEY_COLUMN_DOES_NOT_EXITS, MYF(0), name->c_ptr(),
table->real_name); table->s->table_name);
map->set_all(); map->set_all();
return 1; return 1;
} }
......
...@@ -3669,17 +3669,20 @@ unsent_create_error: ...@@ -3669,17 +3669,20 @@ unsent_create_error:
} }
if (first_table) if (first_table)
{ {
if (!lex->columns.elements && if (lex->type == TYPE_ENUM_PROCEDURE ||
sp_exists_routine(thd, all_tables, 1, 1)) lex->type == TYPE_ENUM_FUNCTION)
{ {
uint grants= lex->all_privileges uint grants= lex->all_privileges
? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL) ? (PROC_ACLS & ~GRANT_ACL) | (lex->grant & GRANT_ACL)
: lex->grant; : lex->grant;
if (grant_option && if (grant_option &&
check_grant_procedure(thd, grants | GRANT_ACL, all_tables, 0)) check_grant_routine(thd, grants | GRANT_ACL, all_tables,
lex->type == TYPE_ENUM_PROCEDURE, 0))
goto error; goto error;
res= mysql_procedure_grant(thd, all_tables, lex->users_list, res= mysql_routine_grant(thd, all_tables,
grants, lex->sql_command == SQLCOM_REVOKE,0); lex->type == TYPE_ENUM_PROCEDURE,
lex->users_list, grants,
lex->sql_command == SQLCOM_REVOKE, 0);
} }
else else
{ {
...@@ -3701,7 +3704,7 @@ unsent_create_error: ...@@ -3701,7 +3704,7 @@ unsent_create_error:
} }
else else
{ {
if (lex->columns.elements) if (lex->columns.elements || lex->type)
{ {
my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE), my_message(ER_ILLEGAL_GRANT_FOR_TABLE, ER(ER_ILLEGAL_GRANT_FOR_TABLE),
MYF(0)); MYF(0));
...@@ -3983,11 +3986,13 @@ unsent_create_error: ...@@ -3983,11 +3986,13 @@ unsent_create_error:
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
/* only add privileges if really neccessary */ /* only add privileges if really neccessary */
if (sp_automatic_privileges && if (sp_automatic_privileges &&
check_procedure_access(thd, DEFAULT_CREATE_PROC_ACLS, check_routine_access(thd, DEFAULT_CREATE_PROC_ACLS,
db, name, 1)) db, name,
lex->sql_command == SQLCOM_CREATE_PROCEDURE, 1))
{ {
close_thread_tables(thd); close_thread_tables(thd);
if (sp_grant_privileges(thd, db, name)) if (sp_grant_privileges(thd, db, name,
lex->sql_command == SQLCOM_CREATE_PROCEDURE))
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_GRANT_FAIL, ER_PROC_AUTO_GRANT_FAIL,
ER(ER_PROC_AUTO_GRANT_FAIL)); ER(ER_PROC_AUTO_GRANT_FAIL));
...@@ -4072,8 +4077,8 @@ unsent_create_error: ...@@ -4072,8 +4077,8 @@ unsent_create_error:
} }
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (check_procedure_access(thd, EXECUTE_ACL, if (check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, 0)) sp->m_db.str, sp->m_name.str, TRUE, 0))
{ {
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
...@@ -4082,8 +4087,8 @@ unsent_create_error: ...@@ -4082,8 +4087,8 @@ unsent_create_error:
} }
sp_change_security_context(thd, sp, &save_ctx); sp_change_security_context(thd, sp, &save_ctx);
if (save_ctx.changed && if (save_ctx.changed &&
check_procedure_access(thd, EXECUTE_ACL, check_routine_access(thd, EXECUTE_ACL,
sp->m_db.str, sp->m_name.str, 0)) sp->m_db.str, sp->m_name.str, TRUE, 0))
{ {
#ifndef EMBEDDED_LIBRARY #ifndef EMBEDDED_LIBRARY
thd->net.no_send_ok= nsok; thd->net.no_send_ok= nsok;
...@@ -4185,8 +4190,9 @@ unsent_create_error: ...@@ -4185,8 +4190,9 @@ unsent_create_error:
} }
else else
{ {
if (check_procedure_access(thd, ALTER_PROC_ACL, sp->m_db.str, if (check_routine_access(thd, ALTER_PROC_ACL, sp->m_db.str,
sp->m_name.str, 0)) sp->m_name.str,
lex->sql_command == SQLCOM_ALTER_PROCEDURE, 0))
goto error; goto error;
memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics)); memcpy(&lex->sp_chistics, &chistics, sizeof(lex->sp_chistics));
if (!trust_routine_creators && mysql_bin_log.is_open() && if (!trust_routine_creators && mysql_bin_log.is_open() &&
...@@ -4244,11 +4250,13 @@ unsent_create_error: ...@@ -4244,11 +4250,13 @@ unsent_create_error:
{ {
db= thd->strdup(sp->m_db.str); db= thd->strdup(sp->m_db.str);
name= thd->strdup(sp->m_name.str); name= thd->strdup(sp->m_name.str);
if (check_procedure_access(thd, ALTER_PROC_ACL, db, name, 0)) if (check_routine_access(thd, ALTER_PROC_ACL, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE, 0))
goto error; goto error;
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (sp_automatic_privileges && if (sp_automatic_privileges &&
sp_revoke_privileges(thd, db, name)) sp_revoke_privileges(thd, db, name,
lex->sql_command == SQLCOM_DROP_PROCEDURE))
{ {
push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN, push_warning(thd, MYSQL_ERROR::WARN_LEVEL_WARN,
ER_PROC_AUTO_REVOKE_FAIL, ER_PROC_AUTO_REVOKE_FAIL,
...@@ -4832,8 +4840,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables, ...@@ -4832,8 +4840,8 @@ check_table_access(THD *thd, ulong want_access,TABLE_LIST *tables,
bool bool
check_procedure_access(THD *thd, ulong want_access,char *db, char *name, check_routine_access(THD *thd, ulong want_access,char *db, char *name,
bool no_errors) bool is_proc, bool no_errors)
{ {
TABLE_LIST tables[1]; TABLE_LIST tables[1];
...@@ -4849,7 +4857,7 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name, ...@@ -4849,7 +4857,7 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
#ifndef NO_EMBEDDED_ACCESS_CHECKS #ifndef NO_EMBEDDED_ACCESS_CHECKS
if (grant_option) if (grant_option)
return check_grant_procedure(thd, want_access, tables, no_errors); return check_grant_routine(thd, want_access, tables, is_proc, no_errors);
#endif #endif
return FALSE; return FALSE;
...@@ -4870,7 +4878,8 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name, ...@@ -4870,7 +4878,8 @@ check_procedure_access(THD *thd, ulong want_access,char *db, char *name,
1 error 1 error
*/ */
bool check_some_routine_access(THD *thd, const char *db, const char *name) bool check_some_routine_access(THD *thd, const char *db, const char *name,
bool is_proc)
{ {
ulong save_priv; ulong save_priv;
if (thd->master_access & SHOW_PROC_ACLS) if (thd->master_access & SHOW_PROC_ACLS)
...@@ -4878,7 +4887,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name) ...@@ -4878,7 +4887,7 @@ bool check_some_routine_access(THD *thd, const char *db, const char *name)
if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) || if (!check_access(thd, SHOW_PROC_ACLS, db, &save_priv, 0, 1) ||
(save_priv & SHOW_PROC_ACLS)) (save_priv & SHOW_PROC_ACLS))
return FALSE; return FALSE;
return check_routine_level_acl(thd, db, name); return check_routine_level_acl(thd, db, name, is_proc);
} }
......
...@@ -2625,7 +2625,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table, ...@@ -2625,7 +2625,8 @@ bool store_schema_proc(THD *thd, TABLE *table, TABLE *proc_table,
definer= get_field(thd->mem_root, proc_table->field[11]); definer= get_field(thd->mem_root, proc_table->field[11]);
if (!full_access) if (!full_access)
full_access= !strcmp(sp_user, definer); full_access= !strcmp(sp_user, definer);
if (!full_access && check_some_routine_access(thd, sp_db, sp_name)) if (!full_access && check_some_routine_access(thd, sp_db, sp_name,
proc_table->field[2]->val_int() == TYPE_ENUM_PROCEDURE))
return 0; return 0;
if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC && if (lex->orig_sql_command == SQLCOM_SHOW_STATUS_PROC &&
......
...@@ -804,7 +804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize); ...@@ -804,7 +804,7 @@ bool my_yyoverflow(short **a, YYSTYPE **b, ulong *yystacksize);
opt_delete_options opt_delete_option varchar nchar nvarchar opt_delete_options opt_delete_option varchar nchar nvarchar
opt_outer table_list table_name opt_option opt_place opt_outer table_list table_name opt_option opt_place
opt_attribute opt_attribute_list attribute column_list column_list_id opt_attribute opt_attribute_list attribute column_list column_list_id
opt_column_list grant_privileges opt_table grant_list grant_option opt_column_list grant_privileges grant_ident grant_list grant_option
object_privilege object_privilege_list user_list rename_list object_privilege object_privilege_list user_list rename_list
clear_privileges flush_options flush_option clear_privileges flush_options flush_option
equal optional_braces opt_key_definition key_usage_list2 equal optional_braces opt_key_definition key_usage_list2
...@@ -3994,6 +3994,7 @@ select_options: ...@@ -3994,6 +3994,7 @@ select_options:
YYABORT; YYABORT;
} }
} }
;
select_option_list: select_option_list:
select_option_list select_option select_option_list select_option
...@@ -7906,9 +7907,36 @@ revoke: ...@@ -7906,9 +7907,36 @@ revoke:
; ;
revoke_command: revoke_command:
grant_privileges ON opt_table FROM grant_list grant_privileges ON opt_table grant_ident FROM grant_list
{ {
Lex->sql_command = SQLCOM_REVOKE; LEX *lex= Lex;
lex->sql_command= SQLCOM_REVOKE;
lex->type= 0;
}
|
grant_privileges ON FUNCTION_SYM grant_ident FROM grant_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_FUNCTION;
}
|
grant_privileges ON PROCEDURE grant_ident FROM grant_list
{
LEX *lex= Lex;
if (lex->columns.elements)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
lex->sql_command= SQLCOM_REVOKE;
lex->type= TYPE_ENUM_PROCEDURE;
} }
| |
ALL opt_privileges ',' GRANT OPTION FROM grant_list ALL opt_privileges ',' GRANT OPTION FROM grant_list
...@@ -7918,11 +7946,50 @@ revoke_command: ...@@ -7918,11 +7946,50 @@ revoke_command:
; ;
grant: grant:
GRANT clear_privileges grant_privileges ON opt_table TO_SYM grant_list GRANT clear_privileges grant_command
{}
;
grant_command:
grant_privileges ON opt_table grant_ident TO_SYM grant_list
require_clause grant_options require_clause grant_options
{ Lex->sql_command= SQLCOM_GRANT; } {
LEX *lex= Lex;
lex->sql_command= SQLCOM_GRANT;
lex->type= 0;
}
|
grant_privileges ON FUNCTION_SYM grant_ident TO_SYM grant_list
require_clause grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_FUNCTION;
}
|
grant_privileges ON PROCEDURE grant_ident TO_SYM grant_list
require_clause grant_options
{
LEX *lex= Lex;
if (lex->columns.elements)
{
yyerror(ER(ER_SYNTAX_ERROR));
YYABORT;
}
lex->sql_command= SQLCOM_GRANT;
lex->type= TYPE_ENUM_PROCEDURE;
}
; ;
opt_table:
/* Empty */
| TABLE_SYM ;
grant_privileges: grant_privileges:
object_privilege_list { } object_privilege_list { }
| ALL opt_privileges | ALL opt_privileges
...@@ -8015,7 +8082,7 @@ require_list_element: ...@@ -8015,7 +8082,7 @@ require_list_element:
} }
; ;
opt_table: grant_ident:
'*' '*'
{ {
LEX *lex= Lex; LEX *lex= Lex;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment