Commit a51ea111 authored by monty@narttu.mysql.fi's avatar monty@narttu.mysql.fi

SHOW GRANTS hided real grants when grants on both column and table (Bug 654)

parent 3bd661a6
drop table if exists t1;
delete from mysql.user where user='mysqltest_1'; delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1'; delete from mysql.db where user='mysqltest_1';
flush privileges; flush privileges;
...@@ -64,8 +65,44 @@ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TE ...@@ -64,8 +65,44 @@ GRANT SELECT, INSERT, UPDATE, DELETE, CREATE, DROP, REFERENCES, INDEX, CREATE TE
revoke all privileges on mysqltest.* from mysqltest_1@localhost; revoke all privileges on mysqltest.* from mysqltest_1@localhost;
delete from mysql.user where user='mysqltest_1'; delete from mysql.user where user='mysqltest_1';
flush privileges; flush privileges;
grant usage on test.* to user@localhost with grant option; grant usage on test.* to mysqltest_1@localhost with grant option;
show grants for user@localhost; show grants for mysqltest_1@localhost;
Grants for user@localhost Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'user'@'localhost' GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT USAGE ON `test`.* TO 'user'@'localhost' WITH GRANT OPTION GRANT USAGE ON `mysqltest`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
GRANT USAGE ON `test`.* TO 'mysqltest_1'@'localhost' WITH GRANT OPTION
delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
create table t1 (a int);
GRANT select,update,insert on t1 to mysqltest_1@localhost;
GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT SELECT, SELECT (a), INSERT, INSERT (a), UPDATE, UPDATE (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost'
select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1";
table_priv column_priv
Select,Insert,Update Select,Insert,Update,References
REVOKE select (a), update on t1 from mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT SELECT, INSERT, INSERT (a), REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost'
REVOKE insert,insert (a) on t1 from mysqltest_1@localhost;
GRANT references on t1 to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
Grants for mysqltest_1@localhost
GRANT USAGE ON *.* TO 'mysqltest_1'@'localhost'
GRANT SELECT, REFERENCES, REFERENCES (a) ON `test`.`t1` TO 'mysqltest_1'@'localhost'
select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1";
table_priv column_priv
Select,References References
delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
drop table t1;
--disable_warnings
drop table if exists t1;
--enable_warnings
# #
# Test that SSL options works properly # Test that SSL options works properly
# #
...@@ -39,6 +43,32 @@ show grants for mysqltest_1@localhost; ...@@ -39,6 +43,32 @@ show grants for mysqltest_1@localhost;
revoke all privileges on mysqltest.* from mysqltest_1@localhost; revoke all privileges on mysqltest.* from mysqltest_1@localhost;
delete from mysql.user where user='mysqltest_1'; delete from mysql.user where user='mysqltest_1';
flush privileges; flush privileges;
grant usage on test.* to user@localhost with grant option; grant usage on test.* to mysqltest_1@localhost with grant option;
show grants for user@localhost; show grants for mysqltest_1@localhost;
delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
#
# Test what happens when you have same table and colum level grants
#
create table t1 (a int);
GRANT select,update,insert on t1 to mysqltest_1@localhost;
GRANT select (a), update (a),insert(a), references(a) on t1 to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1";
REVOKE select (a), update on t1 from mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
REVOKE insert,insert (a) on t1 from mysqltest_1@localhost;
GRANT references on t1 to mysqltest_1@localhost;
show grants for mysqltest_1@localhost;
select table_priv,column_priv from mysql.tables_priv where user="mysqltest_1";
delete from mysql.user where user='mysqltest_1';
delete from mysql.db where user='mysqltest_1';
delete from mysql.tables_priv where user='mysqltest_1';
delete from mysql.columns_priv where user='mysqltest_1';
flush privileges;
drop table t1;
/* Copyright (C) 2000 MySQL AB /* Copyright (C) 2000-2003 MySQL AB
This program is free software; you can redistribute it and/or modify This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by it under the terms of the GNU General Public License as published by
...@@ -193,7 +193,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ...@@ -193,7 +193,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
host.db= get_field(&mem, table,1); host.db= get_field(&mem, table,1);
host.access= get_access(table,2); host.access= get_access(table,2);
host.access= fix_rights_for_db(host.access); host.access= fix_rights_for_db(host.access);
host.sort= get_sort(2,host.host.hostname,host.db); host.sort= get_sort(2,host.host.hostname,host.db);
#ifndef TO_BE_REMOVED #ifndef TO_BE_REMOVED
if (table->fields == 8) if (table->fields == 8)
{ // Without grant { // Without grant
...@@ -213,8 +213,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ...@@ -213,8 +213,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
if (table->field[2]->field_length == 8 && if (table->field[2]->field_length == 8 &&
protocol_version == PROTOCOL_VERSION) protocol_version == PROTOCOL_VERSION)
{ {
sql_print_error( sql_print_error("Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
"Old 'user' table. (Check README or the Reference manual). Continuing --old-protocol"); /* purecov: tested */
protocol_version=9; /* purecov: tested */ protocol_version=9; /* purecov: tested */
} }
...@@ -247,7 +246,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ...@@ -247,7 +246,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
user.sort=get_sort(2,user.host.hostname,user.user); user.sort=get_sort(2,user.host.hostname,user.user);
user.hostname_length= (user.host.hostname ? user.hostname_length= (user.host.hostname ?
(uint) strlen(user.host.hostname) : 0); (uint) strlen(user.host.hostname) : 0);
if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */ if (table->fields >= 31) /* Starting from 4.0.2 we have more fields */
{ {
char *ssl_type=get_field(&mem, table, 24); char *ssl_type=get_field(&mem, table, 24);
if (!ssl_type) if (!ssl_type)
...@@ -259,7 +258,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables) ...@@ -259,7 +258,7 @@ my_bool acl_init(THD *org_thd, bool dont_read_acl_tables)
else /* !strcmp(ssl_type, "SPECIFIED") */ else /* !strcmp(ssl_type, "SPECIFIED") */
user.ssl_type=SSL_TYPE_SPECIFIED; user.ssl_type=SSL_TYPE_SPECIFIED;
user.ssl_cipher= get_field(&mem, table, 25); user.ssl_cipher= get_field(&mem, table, 25);
user.x509_issuer= get_field(&mem, table, 26); user.x509_issuer= get_field(&mem, table, 26);
user.x509_subject= get_field(&mem, table, 27); user.x509_subject= get_field(&mem, table, 27);
...@@ -368,7 +367,14 @@ void acl_free(bool end) ...@@ -368,7 +367,14 @@ void acl_free(bool end)
} }
} }
/* Reload acl list if possible */
/*
Forget current privileges and read new privileges from the privilege tables
SYNOPSIS
acl_reload()
thd Thread handle
*/
void acl_reload(THD *thd) void acl_reload(THD *thd)
{ {
...@@ -493,8 +499,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b) ...@@ -493,8 +499,8 @@ static int acl_compare(ACL_ACCESS *a,ACL_ACCESS *b)
ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
const char *password,const char *message, const char *password,const char *message,
char **priv_user, char *priv_host, char **priv_user, char *priv_host,
bool old_ver, USER_RESOURCES *mqh) bool old_ver, USER_RESOURCES *mqh)
{ {
ulong user_access=NO_ACCESS; ulong user_access=NO_ACCESS;
*priv_user=(char*) user; *priv_user=(char*) user;
...@@ -526,15 +532,15 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ...@@ -526,15 +532,15 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
{ {
#ifdef HAVE_OPENSSL #ifdef HAVE_OPENSSL
Vio *vio=thd->net.vio; Vio *vio=thd->net.vio;
/* /*
In this point we know that user is allowed to connect In this point we know that user is allowed to connect
from given host by given username/password pair. Now from given host by given username/password pair. Now
we check if SSL is required, if user is using SSL and we check if SSL is required, if user is using SSL and
if X509 certificate attributes are OK if X509 certificate attributes are OK
*/ */
switch (acl_user->ssl_type) { switch (acl_user->ssl_type) {
case SSL_TYPE_NOT_SPECIFIED: // Impossible case SSL_TYPE_NOT_SPECIFIED: // Impossible
case SSL_TYPE_NONE: /* SSL is not required to connect */ case SSL_TYPE_NONE: /* SSL is not required to connect */
user_access=acl_user->access; user_access=acl_user->access;
break; break;
case SSL_TYPE_ANY: /* Any kind of SSL is good enough */ case SSL_TYPE_ANY: /* Any kind of SSL is good enough */
...@@ -544,7 +550,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user, ...@@ -544,7 +550,7 @@ ulong acl_getroot(THD *thd, const char *host, const char *ip, const char *user,
case SSL_TYPE_X509: /* Client should have any valid certificate. */ case SSL_TYPE_X509: /* Client should have any valid certificate. */
/* /*
We need to check for absence of SSL because without SSL We need to check for absence of SSL because without SSL
we should reject connection. we should reject connection.
*/ */
if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_)) if (vio_type(vio) == VIO_TYPE_SSL && SSL_get_peer_certificate(vio->ssl_))
user_access=acl_user->access; user_access=acl_user->access;
...@@ -653,12 +659,12 @@ static byte* check_get_key(ACL_USER *buff,uint *length, ...@@ -653,12 +659,12 @@ static byte* check_get_key(ACL_USER *buff,uint *length,
} }
static void acl_update_user(const char *user, const char *host, static void acl_update_user(const char *user, const char *host,
const char *password, const char *password,
enum SSL_type ssl_type, enum SSL_type ssl_type,
const char *ssl_cipher, const char *ssl_cipher,
const char *x509_issuer, const char *x509_issuer,
const char *x509_subject, const char *x509_subject,
USER_RESOURCES *mqh, USER_RESOURCES *mqh,
ulong privileges) ulong privileges)
{ {
for (uint i=0 ; i < acl_users.elements ; i++) for (uint i=0 ; i < acl_users.elements ; i++)
...@@ -707,7 +713,7 @@ static void acl_update_user(const char *user, const char *host, ...@@ -707,7 +713,7 @@ static void acl_update_user(const char *user, const char *host,
static void acl_insert_user(const char *user, const char *host, static void acl_insert_user(const char *user, const char *host,
const char *password, const char *password,
enum SSL_type ssl_type, enum SSL_type ssl_type,
const char *ssl_cipher, const char *ssl_cipher,
const char *x509_issuer, const char *x509_issuer,
...@@ -805,9 +811,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db, ...@@ -805,9 +811,10 @@ static void acl_insert_db(const char *user, const char *host, const char *db,
} }
/*****************************************************************************
** Get privilege for a host, user and db combination /*
*****************************************************************************/ Get privilege for a host, user and db combination
*/
ulong acl_get(const char *host, const char *ip, const char *bin_ip, ulong acl_get(const char *host, const char *ip, const char *bin_ip,
const char *user, const char *db) const char *user, const char *db)
...@@ -929,11 +936,14 @@ int wild_case_compare(const char *str,const char *wildstr) ...@@ -929,11 +936,14 @@ int wild_case_compare(const char *str,const char *wildstr)
DBUG_RETURN (*str != '\0'); DBUG_RETURN (*str != '\0');
} }
/*****************************************************************************
** check if there are any possible matching entries for this host /*
** All host names without wild cards are stored in a hash table, Check if there are any possible matching entries for this host
** entries with wildcards are stored in a dynamic array
*****************************************************************************/ NOTES
All host names without wild cards are stored in a hash table,
entries with wildcards are stored in a dynamic array
*/
static void init_check_host(void) static void init_check_host(void)
{ {
...@@ -1006,10 +1016,6 @@ bool acl_check_host(const char *host, const char *ip) ...@@ -1006,10 +1016,6 @@ bool acl_check_host(const char *host, const char *ip)
return 1; // Host is not allowed return 1; // Host is not allowed
} }
/*****************************************************************************
Change password for the user if it's not an anonymous user
Note: This should write the error directly to the client!
*****************************************************************************/
/* /*
Check if the user is allowed to change password Check if the user is allowed to change password
...@@ -1021,8 +1027,8 @@ bool acl_check_host(const char *host, const char *ip) ...@@ -1021,8 +1027,8 @@ bool acl_check_host(const char *host, const char *ip)
user user name user user name
RETURN VALUE RETURN VALUE
0 OK 0 OK
1 ERROR ; In this case the error is sent to the client. 1 ERROR ; In this case the error is sent to the client.
*/ */
bool check_change_password(THD *thd, const char *host, const char *user) bool check_change_password(THD *thd, const char *host, const char *user)
...@@ -1061,7 +1067,7 @@ bool check_change_password(THD *thd, const char *host, const char *user) ...@@ -1061,7 +1067,7 @@ bool check_change_password(THD *thd, const char *host, const char *user)
RETURN VALUES RETURN VALUES
0 ok 0 ok
1 ERROR; In this case the error is sent to the client. 1 ERROR; In this case the error is sent to the client.
*/ */
bool change_password(THD *thd, const char *host, const char *user, bool change_password(THD *thd, const char *host, const char *user,
char *new_password) char *new_password)
...@@ -1127,7 +1133,7 @@ find_acl_user(const char *host, const char *user) ...@@ -1127,7 +1133,7 @@ find_acl_user(const char *host, const char *user)
{ {
ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*); ACL_USER *acl_user=dynamic_element(&acl_users,i,ACL_USER*);
DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),", DBUG_PRINT("info",("strcmp('%s','%s'), compare_hostname('%s','%s'),",
user,acl_user->user,(host),(acl_user->host))); user,acl_user->user,(host),(acl_user->host)));
if (!acl_user->user && !user[0] || if (!acl_user->user && !user[0] ||
acl_user->user && !strcmp(user,acl_user->user)) acl_user->user && !strcmp(user,acl_user->user))
{ {
...@@ -1140,15 +1146,18 @@ find_acl_user(const char *host, const char *user) ...@@ -1140,15 +1146,18 @@ find_acl_user(const char *host, const char *user)
DBUG_RETURN(0); DBUG_RETURN(0);
} }
/*****************************************************************************
Handle comparing of hostname
A hostname may be of type:
hostname (May include wildcards); monty.pp.sci.fi
ip (May include wildcards); 192.168.0.0
ip/netmask 192.168.0.0/255.255.255.0
A net mask of 0.0.0.0 is not allowed. /*
*****************************************************************************/ Comparing of hostnames
NOTES
A hostname may be of type:
hostname (May include wildcards); monty.pp.sci.fi
ip (May include wildcards); 192.168.0.0
ip/netmask 192.168.0.0/255.255.255.0
A net mask of 0.0.0.0 is not allowed.
*/
static const char *calc_ip(const char *ip, long *val, char end) static const char *calc_ip(const char *ip, long *val, char end)
{ {
...@@ -1195,9 +1204,9 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname, ...@@ -1195,9 +1204,9 @@ static bool compare_hostname(const acl_host_and_ip *host, const char *hostname,
} }
/**************************************************************************** /*
Code to update grants in the user and database privilege tables Update grants in the user and database privilege tables
****************************************************************************/ */
static bool update_user_table(THD *thd, const char *host, const char *user, static bool update_user_table(THD *thd, const char *host, const char *user,
const char *new_password) const char *new_password)
...@@ -1263,7 +1272,7 @@ static bool test_if_create_new_users(THD *thd) ...@@ -1263,7 +1272,7 @@ static bool test_if_create_new_users(THD *thd)
/**************************************************************************** /****************************************************************************
** Handle GRANT commands Handle GRANT commands
****************************************************************************/ ****************************************************************************/
static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
...@@ -1285,8 +1294,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo, ...@@ -1285,8 +1294,8 @@ static int replace_user_table(THD *thd, TABLE *table, const LEX_USER &combo,
if (combo.password.length != HASH_PASSWORD_LENGTH) if (combo.password.length != HASH_PASSWORD_LENGTH)
{ {
my_printf_error(ER_PASSWORD_NO_MATCH, my_printf_error(ER_PASSWORD_NO_MATCH,
"Password hash should be a %d-digit hexadecimal number", "Password hash should be a %d-digit hexadecimal number",
MYF(0),HASH_PASSWORD_LENGTH); MYF(0),HASH_PASSWORD_LENGTH);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
password=combo.password.str; password=combo.password.str;
...@@ -1459,7 +1468,7 @@ static int replace_db_table(TABLE *table, const char *db, ...@@ -1459,7 +1468,7 @@ static int replace_db_table(TABLE *table, const char *db,
char what= (revoke_grant) ? 'N' : 'Y'; char what= (revoke_grant) ? 'N' : 'Y';
DBUG_ENTER("replace_db_table"); DBUG_ENTER("replace_db_table");
// is there such a user in user table in memory ???? /* Check if there is such a user in user table in memory? */
if (!initialized || !find_acl_user(combo.host.str,combo.user.str)) if (!initialized || !find_acl_user(combo.host.str,combo.user.str))
{ {
my_error(ER_PASSWORD_NO_MATCH,MYF(0)); my_error(ER_PASSWORD_NO_MATCH,MYF(0));
...@@ -1471,7 +1480,7 @@ static int replace_db_table(TABLE *table, const char *db, ...@@ -1471,7 +1480,7 @@ static int replace_db_table(TABLE *table, const char *db,
table->field[2]->store(combo.user.str,combo.user.length); table->field[2]->store(combo.user.str,combo.user.length);
table->file->index_init(0); table->file->index_init(0);
if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0, if (table->file->index_read(table->record[0],(byte*) table->field[0]->ptr,0,
HA_READ_KEY_EXACT)) HA_READ_KEY_EXACT))
{ {
if (what == 'N') if (what == 'N')
{ // no row, no revoke { // no row, no revoke
...@@ -1502,7 +1511,7 @@ static int replace_db_table(TABLE *table, const char *db, ...@@ -1502,7 +1511,7 @@ static int replace_db_table(TABLE *table, const char *db,
if (old_row_exists) if (old_row_exists)
{ {
// update old existing row /* update old existing row */
if (rights) if (rights)
{ {
if ((error=table->file->update_row(table->record[1],table->record[0]))) if ((error=table->file->update_row(table->record[1],table->record[0])))
...@@ -1529,11 +1538,11 @@ static int replace_db_table(TABLE *table, const char *db, ...@@ -1529,11 +1538,11 @@ static int replace_db_table(TABLE *table, const char *db,
DBUG_RETURN(0); DBUG_RETURN(0);
/* This could only happen if the grant tables got corrupted */ /* This could only happen if the grant tables got corrupted */
table_error: table_error:
table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
table->file->index_end(); table->file->index_end();
abort: abort:
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
...@@ -1649,7 +1658,7 @@ public: ...@@ -1649,7 +1658,7 @@ public:
if (!(mem_check = new GRANT_COLUMN(*res, if (!(mem_check = new GRANT_COLUMN(*res,
fix_rights_for_column(priv)))) fix_rights_for_column(priv))))
{ {
// Don't use this entry /* Don't use this entry */
privs = cols = 0; /* purecov: deadcode */ privs = cols = 0; /* purecov: deadcode */
return; /* purecov: deadcode */ return; /* purecov: deadcode */
} }
...@@ -1827,7 +1836,7 @@ static int replace_column_table(GRANT_TABLE *g_t, ...@@ -1827,7 +1836,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
key_length, HA_READ_KEY_EXACT)) key_length, HA_READ_KEY_EXACT))
goto end; goto end;
// Scan trough all rows with the same host,db,user and table /* Scan through all rows with the same host,db,user and table */
do do
{ {
ulong privileges = (ulong) table->field[6]->val_int(); ulong privileges = (ulong) table->field[6]->val_int();
...@@ -1877,7 +1886,7 @@ static int replace_column_table(GRANT_TABLE *g_t, ...@@ -1877,7 +1886,7 @@ static int replace_column_table(GRANT_TABLE *g_t,
!key_cmp(table,key,0,key_length)); !key_cmp(table,key,0,key_length));
} }
end: end:
table->file->index_end(); table->file->index_end();
DBUG_RETURN(result); DBUG_RETURN(result);
} }
...@@ -1947,7 +1956,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ...@@ -1947,7 +1956,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
if (revoke_grant) if (revoke_grant)
{ {
// column rights are already fixed in mysql_table_grant ! /* column rights are already fixed in mysql_table_grant */
store_table_rights=j & ~store_table_rights; store_table_rights=j & ~store_table_rights;
} }
else else
...@@ -1983,7 +1992,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ...@@ -1983,7 +1992,7 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
if (rights | col_rights) if (rights | col_rights)
{ {
grant_table->privs= rights; grant_table->privs= rights;
grant_table->cols= col_rights; grant_table->cols= col_rights;
} }
else else
{ {
...@@ -1991,19 +2000,36 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table, ...@@ -1991,19 +2000,36 @@ static int replace_table_table(THD *thd, GRANT_TABLE *grant_table,
} }
DBUG_RETURN(0); DBUG_RETURN(0);
/* This should never happen */ /* This should never happen */
table_error: table_error:
table->file->print_error(error,MYF(0)); /* purecov: deadcode */ table->file->print_error(error,MYF(0)); /* purecov: deadcode */
DBUG_RETURN(-1); /* purecov: deadcode */ DBUG_RETURN(-1); /* purecov: deadcode */
} }
/*
Store table level and column level grants in the privilege tables
SYNOPSIS
mysql_table_grant()
thd Thread handle
table_list List of tables to give grant
user_list List of users to give grant
columns List of columns to give grant
rights Table level grant
revoke_grant Set to 1 if this is a REVOKE command
RETURN
0 ok
1 error
*/
int mysql_table_grant(THD *thd, TABLE_LIST *table_list, int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
List <LEX_USER> &user_list, List <LEX_USER> &user_list,
List <LEX_COLUMN> &columns, ulong rights, List <LEX_COLUMN> &columns, ulong rights,
bool revoke_grant) bool revoke_grant)
{ {
ulong column_priv = 0; ulong column_priv= 0;
List_iterator <LEX_USER> str_list (user_list); List_iterator <LEX_USER> str_list (user_list);
LEX_USER *Str; LEX_USER *Str;
TABLE_LIST tables[3]; TABLE_LIST tables[3];
...@@ -2024,21 +2050,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2024,21 +2050,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
if (columns.elements && !revoke_grant) if (columns.elements && !revoke_grant)
{ {
TABLE *table; TABLE *table;
class LEX_COLUMN *check; class LEX_COLUMN *column;
List_iterator <LEX_COLUMN> iter(columns); List_iterator <LEX_COLUMN> column_iter(columns);
if (!(table=open_ltable(thd,table_list,TL_READ))) if (!(table=open_ltable(thd,table_list,TL_READ)))
DBUG_RETURN(-1); DBUG_RETURN(-1);
while ((check = iter++)) while ((column = column_iter++))
{ {
if (!find_field_in_table(thd,table,check->column.ptr(), if (!find_field_in_table(thd,table,column->column.ptr(),
check->column.length(),0,0)) column->column.length(),0,0))
{ {
my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0), my_printf_error(ER_BAD_FIELD_ERROR,ER(ER_BAD_FIELD_ERROR),MYF(0),
check->column.c_ptr(), table_list->alias); column->column.c_ptr(), table_list->alias);
DBUG_RETURN(-1); DBUG_RETURN(-1);
} }
column_priv |= check->rights | (rights & COL_ACLS); column_priv|= column->rights;
} }
close_thread_tables(thd); close_thread_tables(thd);
} }
...@@ -2148,21 +2174,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list, ...@@ -2148,21 +2174,21 @@ int mysql_table_grant(THD *thd, TABLE_LIST *table_list,
/* If revoke_grant, calculate the new column privilege for tables_priv */ /* If revoke_grant, calculate the new column privilege for tables_priv */
if (revoke_grant) if (revoke_grant)
{ {
class LEX_COLUMN *check; class LEX_COLUMN *column;
List_iterator <LEX_COLUMN> iter(columns); List_iterator <LEX_COLUMN> column_iter(columns);
GRANT_COLUMN *grant_column; GRANT_COLUMN *grant_column;
/* Fix old grants */ /* Fix old grants */
while ((check = iter++)) while ((column = column_iter++))
{ {
grant_column = column_hash_search(grant_table, grant_column = column_hash_search(grant_table,
check->column.ptr(), column->column.ptr(),
check->column.length()); column->column.length());
if (grant_column) if (grant_column)
grant_column->rights&= ~(check->rights | rights); grant_column->rights&= ~(column->rights | rights);
} }
/* scan trough all columns to get new column grant */ /* scan trough all columns to get new column grant */
column_priv=0; column_priv= 0;
for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++) for (uint idx=0 ; idx < grant_table->hash_columns.records ; idx++)
{ {
grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns, grant_column= (GRANT_COLUMN*) hash_element(&grant_table->hash_columns,
...@@ -2259,7 +2285,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, ...@@ -2259,7 +2285,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
if (!revoke_grant) if (!revoke_grant)
create_new_users= test_if_create_new_users(thd); create_new_users= test_if_create_new_users(thd);
// go through users in user_list /* go through users in user_list */
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
VOID(pthread_mutex_lock(&acl_cache->lock)); VOID(pthread_mutex_lock(&acl_cache->lock));
grant_version++; grant_version++;
...@@ -2280,7 +2306,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list, ...@@ -2280,7 +2306,7 @@ int mysql_grant (THD *thd, const char *db, List <LEX_USER> &list,
continue; continue;
} }
if ((replace_user_table(thd, if ((replace_user_table(thd,
tables[0].table, tables[0].table,
*Str, *Str,
(!db ? rights : 0), revoke_grant, (!db ? rights : 0), revoke_grant,
create_new_users))) create_new_users)))
...@@ -2401,7 +2427,16 @@ end: ...@@ -2401,7 +2427,16 @@ end:
} }
/* Reload grant array if possible */ /*
Reload grant array if possible
SYNOPSIS
grant_reload()
thd Thread handler
NOTES
Locked tables are checked by acl_init and doesn't have to be checked here
*/
void grant_reload(THD *thd) void grant_reload(THD *thd)
{ {
...@@ -2410,8 +2445,6 @@ void grant_reload(THD *thd) ...@@ -2410,8 +2445,6 @@ void grant_reload(THD *thd)
MEM_ROOT old_mem; MEM_ROOT old_mem;
DBUG_ENTER("grant_reload"); DBUG_ENTER("grant_reload");
// Locked tables are checked by acl_init and doesn't have to be checked here
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
grant_version++; grant_version++;
old_hash_tables=hash_tables; old_hash_tables=hash_tables;
...@@ -2487,13 +2520,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables, ...@@ -2487,13 +2520,13 @@ bool check_grant(THD *thd, ulong want_access, TABLE_LIST *tables,
pthread_mutex_unlock(&LOCK_grant); pthread_mutex_unlock(&LOCK_grant);
return 0; return 0;
err: err:
pthread_mutex_unlock(&LOCK_grant); pthread_mutex_unlock(&LOCK_grant);
if (!no_errors) // Not a silent skip of table if (!no_errors) // Not a silent skip of table
{ {
const char *command=""; const char *command="";
if (want_access & SELECT_ACL) if (want_access & SELECT_ACL)
command ="select"; command ="select";
else if (want_access & INSERT_ACL) else if (want_access & INSERT_ACL)
command = "insert"; command = "insert";
else if (want_access & UPDATE_ACL) else if (want_access & UPDATE_ACL)
...@@ -2534,7 +2567,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name, ...@@ -2534,7 +2567,7 @@ bool check_grant_column(THD *thd,TABLE *table, const char *name,
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
// reload table if someone has modified any grants /* reload table if someone has modified any grants */
if (table->grant.version != grant_version) if (table->grant.version != grant_version)
{ {
...@@ -2594,7 +2627,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) ...@@ -2594,7 +2627,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
// reload table if someone has modified any grants /* reload table if someone has modified any grants */
if (table->grant.version != grant_version) if (table->grant.version != grant_version)
{ {
...@@ -2604,7 +2637,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) ...@@ -2604,7 +2637,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
table->real_name,0); /* purecov: inspected */ table->real_name,0); /* purecov: inspected */
table->grant.version=grant_version; /* purecov: inspected */ table->grant.version=grant_version; /* purecov: inspected */
} }
// The following should always be true /* The following should always be true */
if (!(grant_table=table->grant.grant_table)) if (!(grant_table=table->grant.grant_table))
goto err; /* purecov: inspected */ goto err; /* purecov: inspected */
...@@ -2619,7 +2652,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) ...@@ -2619,7 +2652,7 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
return 0; return 0;
/* We must use my_printf_error() here! */ /* We must use my_printf_error() here! */
err: err:
pthread_mutex_unlock(&LOCK_grant); pthread_mutex_unlock(&LOCK_grant);
const char *command=""; const char *command="";
...@@ -2639,11 +2672,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table) ...@@ -2639,11 +2672,11 @@ bool check_grant_all_columns(THD *thd, ulong want_access, TABLE *table)
} }
/**************************************************************************** /*
Check if a user has the right to access a database Check if a user has the right to access a database
Access is accepted if he has a grant for any table in the database Access is accepted if he has a grant for any table in the database
Return 1 if access is denied Return 1 if access is denied
****************************************************************************/ */
bool check_grant_db(THD *thd,const char *db) bool check_grant_db(THD *thd,const char *db)
{ {
...@@ -2683,7 +2716,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table) ...@@ -2683,7 +2716,7 @@ ulong get_table_grant(THD *thd, TABLE_LIST *table)
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
grant_table = table_hash_search(thd->host,thd->ip,db,user, grant_table = table_hash_search(thd->host,thd->ip,db,user,
table->real_name,0); table->real_name, 0);
table->grant.grant_table=grant_table; // Remember for column test table->grant.grant_table=grant_table; // Remember for column test
table->grant.version=grant_version; table->grant.version=grant_version;
if (grant_table) if (grant_table)
...@@ -2701,7 +2734,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) ...@@ -2701,7 +2734,7 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
ulong priv; ulong priv;
pthread_mutex_lock(&LOCK_grant); pthread_mutex_lock(&LOCK_grant);
// reload table if someone has modified any grants /* reload table if someone has modified any grants */
if (table->grant.version != grant_version) if (table->grant.version != grant_version)
{ {
table->grant.grant_table= table->grant.grant_table=
...@@ -2726,11 +2759,20 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field) ...@@ -2726,11 +2759,20 @@ ulong get_column_grant(THD *thd, TABLE_LIST *table, Field *field)
return priv; return priv;
} }
/* Help function for mysql_show_grants */
/***************************************************************************** static void add_user_option(String *grant, ulong value, const char *name)
SHOW GRANTS : send to client grant-like strings depicting user@host {
privileges if (value)
*****************************************************************************/ {
char buff[22], *p; // just as in int2str
grant->append(' ');
grant->append(name, strlen(name));
grant->append(' ');
p=int10_to_str(value, buff, 10);
grant->append(buff,p-buff);
}
}
static const char *command_array[]= static const char *command_array[]=
{ {
...@@ -2739,13 +2781,21 @@ static const char *command_array[]= ...@@ -2739,13 +2781,21 @@ static const char *command_array[]=
"SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE", "SUPER", "CREATE TEMPORARY TABLES", "LOCK TABLES", "EXECUTE",
"REPLICATION SLAVE", "REPLICATION CLIENT", "REPLICATION SLAVE", "REPLICATION CLIENT",
}; };
static uint command_lengths[]= static uint command_lengths[]=
{ {
6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18 6,6,6,6,6,4,6,8,7,4,5,10,5,5,14,5,23,11,7,17,18
}; };
int mysql_show_grants(THD *thd,LEX_USER *lex_user) /*
SHOW GRANTS; Send grants for a user to the client
IMPLEMENTATION
Send to client grant-like strings depicting user@host privileges
*/
int mysql_show_grants(THD *thd,LEX_USER *lex_user)
{ {
ulong want_access; ulong want_access;
uint counter,index; uint counter,index;
...@@ -2784,7 +2834,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2784,7 +2834,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
!my_strcasecmp(lex_user->host.str,host)) !my_strcasecmp(lex_user->host.str,host))
break; break;
} }
if (counter == acl_users.elements) if (counter == acl_users.elements)
{ {
my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT), my_printf_error(ER_NONEXISTING_GRANT,ER(ER_NONEXISTING_GRANT),
MYF(0),lex_user->user.str,lex_user->host.str); MYF(0),lex_user->user.str,lex_user->host.str);
...@@ -2815,13 +2865,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2815,13 +2865,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append("ALL PRIVILEGES",14); global.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL)) else if (!(want_access & ~GRANT_ACL))
global.append("USAGE",5); global.append("USAGE",5);
else else
{ {
bool found=0; bool found=0;
ulong j,test_access= want_access & ~GRANT_ACL; ulong j,test_access= want_access & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1) for (counter=0, j = SELECT_ACL;j <= GLOBAL_ACLS;counter++,j <<= 1)
{ {
if (test_access & j) if (test_access & j)
{ {
if (found) if (found)
global.append(", ",2); global.append(", ",2);
...@@ -2831,7 +2881,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2831,7 +2881,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
global.append (" ON *.* TO '",12); global.append (" ON *.* TO '",12);
global.append(lex_user->user.str,lex_user->user.length); global.append(lex_user->user.str,lex_user->user.length);
global.append ("'@'",3); global.append ("'@'",3);
global.append(lex_user->host.str,lex_user->host.length); global.append(lex_user->host.str,lex_user->host.length);
global.append ('\''); global.append ('\'');
...@@ -2854,25 +2904,25 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2854,25 +2904,25 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append(" REQUIRE ",9); global.append(" REQUIRE ",9);
if (acl_user->x509_issuer) if (acl_user->x509_issuer)
{ {
ssl_options++; ssl_options++;
global.append("ISSUER \'",8); global.append("ISSUER \'",8);
global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer)); global.append(acl_user->x509_issuer,strlen(acl_user->x509_issuer));
global.append('\''); global.append('\'');
} }
if (acl_user->x509_subject) if (acl_user->x509_subject)
{ {
if (ssl_options++) if (ssl_options++)
global.append(' '); global.append(' ');
global.append("SUBJECT \'",9); global.append("SUBJECT \'",9);
global.append(acl_user->x509_subject,strlen(acl_user->x509_subject)); global.append(acl_user->x509_subject,strlen(acl_user->x509_subject));
global.append('\''); global.append('\'');
} }
if (acl_user->ssl_cipher) if (acl_user->ssl_cipher)
{ {
if (ssl_options++) if (ssl_options++)
global.append(' '); global.append(' ');
global.append("CIPHER '",8); global.append("CIPHER '",8);
global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher)); global.append(acl_user->ssl_cipher,strlen(acl_user->ssl_cipher));
global.append('\''); global.append('\'');
} }
} }
...@@ -2880,30 +2930,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2880,30 +2930,15 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
(acl_user->user_resource.questions | acl_user->user_resource.updates | (acl_user->user_resource.questions | acl_user->user_resource.updates |
acl_user->user_resource.connections)) acl_user->user_resource.connections))
{ {
global.append(" WITH",5); global.append(" WITH",5);
if (want_access & GRANT_ACL) if (want_access & GRANT_ACL)
global.append(" GRANT OPTION",13); global.append(" GRANT OPTION",13);
if (acl_user->user_resource.questions) add_user_option(&global, acl_user->user_resource.questions,
{ "MAX_QUERIES_PER_HOUR");
char buff[22], *p; // just as in int2str add_user_option(&global, acl_user->user_resource.updates,
global.append(" MAX_QUERIES_PER_HOUR ",22); "MAX_UPDATES_PER_HOUR");
p=int10_to_str(acl_user->user_resource.questions,buff,10); add_user_option(&global, acl_user->user_resource.connections,
global.append(buff,p-buff); "MAX_CONNECTIONS_PER_HOUR");
}
if (acl_user->user_resource.updates)
{
char buff[22], *p; // just as in int2str
global.append(" MAX_UPDATES_PER_HOUR ",22);
p=int10_to_str(acl_user->user_resource.updates,buff,10);
global.append(buff,p-buff);
}
if (acl_user->user_resource.connections)
{
char buff[22], *p; // just as in int2str
global.append(" MAX_CONNECTIONS_PER_HOUR ",26);
p=int10_to_str(acl_user->user_resource.connections,buff,10);
global.append(buff,p-buff);
}
} }
thd->packet.length(0); thd->packet.length(0);
net_store_data(&thd->packet,global.ptr(),global.length()); net_store_data(&thd->packet,global.ptr(),global.length());
...@@ -2929,7 +2964,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2929,7 +2964,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
!my_strcasecmp(lex_user->host.str,host)) !my_strcasecmp(lex_user->host.str,host))
{ {
want_access=acl_db->access; want_access=acl_db->access;
if (want_access) if (want_access)
{ {
String db(buff,sizeof(buff)); String db(buff,sizeof(buff));
db.length(0); db.length(0);
...@@ -2938,7 +2973,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2938,7 +2973,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL))) if (test_all_bits(want_access,(DB_ACLS & ~GRANT_ACL)))
db.append("ALL PRIVILEGES",14); db.append("ALL PRIVILEGES",14);
else if (!(want_access & ~GRANT_ACL)) else if (!(want_access & ~GRANT_ACL))
db.append("USAGE",5); db.append("USAGE",5);
else else
{ {
int found=0, cnt; int found=0, cnt;
...@@ -2954,13 +2989,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2954,13 +2989,13 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
} }
db.append (" ON `",5); db.append(" ON `",5);
db.append(acl_db->db); db.append(acl_db->db);
db.append ("`.* TO '",8); db.append("`.* TO '",8);
db.append(lex_user->user.str,lex_user->user.length); db.append(lex_user->user.str,lex_user->user.length);
db.append ("'@'",3); db.append("'@'",3);
db.append(lex_user->host.str, lex_user->host.length); db.append(lex_user->host.str, lex_user->host.length);
db.append ('\''); db.append('\'');
if (want_access & GRANT_ACL) if (want_access & GRANT_ACL)
db.append(" WITH GRANT OPTION",18); db.append(" WITH GRANT OPTION",18);
thd->packet.length(0); thd->packet.length(0);
...@@ -2979,7 +3014,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2979,7 +3014,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
for (index=0 ; index < hash_tables.records ; index++) for (index=0 ; index < hash_tables.records ; index++)
{ {
const char *user,*host; const char *user,*host;
GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index); GRANT_TABLE *grant_table= (GRANT_TABLE*) hash_element(&hash_tables,index);
if (!(user=grant_table->user)) if (!(user=grant_table->user))
user=""; user="";
...@@ -2989,44 +3024,54 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -2989,44 +3024,54 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
if (!strcmp(lex_user->user.str,user) && if (!strcmp(lex_user->user.str,user) &&
!my_strcasecmp(lex_user->host.str,host)) !my_strcasecmp(lex_user->host.str,host))
{ {
want_access=grant_table->privs; ulong table_access= grant_table->privs;
if ((want_access | grant_table->cols) != 0) if ((table_access | grant_table->cols) != 0)
{ {
String global(buff,sizeof(buff)); String global(buff,sizeof(buff));
global.length(0); global.length(0);
global.append("GRANT ",6); global.append("GRANT ",6);
if (test_all_bits(grant_table->privs,(TABLE_ACLS & ~GRANT_ACL))) if (test_all_bits(table_access, (TABLE_ACLS & ~GRANT_ACL)))
global.append("ALL PRIVILEGES",14); global.append("ALL PRIVILEGES",14);
else else
{ {
int found=0; int found= 0;
ulong j,test_access= (want_access | grant_table->cols) & ~GRANT_ACL; ulong j,test_access= (table_access | grant_table->cols) & ~GRANT_ACL;
for (counter=0, j = SELECT_ACL;j <= TABLE_ACLS; counter++,j <<= 1) for (counter= 0, j= SELECT_ACL; j <= TABLE_ACLS; counter++, j<<= 1)
{ {
if (test_access & j) if (test_access & j)
{ {
if (found) if (found)
global.append(", ",2); global.append(", ",2);
found = 1; found= 1;
global.append(command_array[counter],command_lengths[counter]); global.append(command_array[counter],command_lengths[counter]);
if (grant_table->cols) if (grant_table->cols)
{ {
uint found_col=0; uint found_col= 0;
for (uint col_index=0 ; for (uint col_index=0 ;
col_index < grant_table->hash_columns.records ; col_index < grant_table->hash_columns.records ;
col_index++) col_index++)
{ {
GRANT_COLUMN *grant_column = (GRANT_COLUMN*) GRANT_COLUMN *grant_column = (GRANT_COLUMN*)
hash_element(&grant_table->hash_columns,col_index); hash_element(&grant_table->hash_columns,col_index);
if (grant_column->rights & j) if (grant_column->rights & j)
{ {
if (!found_col) if (!found_col)
{ {
found_col= 1;
/*
If we have a duplicated table level privilege, we
must write the access privilege name again.
*/
if (table_access & j)
{
global.append(", ", 2);
global.append(command_array[counter],
command_lengths[counter]);
}
global.append(" (",2); global.append(" (",2);
found_col=1;
} }
else else
global.append(", ",2); global.append(", ",2);
...@@ -3045,12 +3090,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -3045,12 +3090,12 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
global.append("`.`",3); global.append("`.`",3);
global.append(grant_table->tname); global.append(grant_table->tname);
global.append("` TO '",6); global.append("` TO '",6);
global.append(lex_user->user.str,lex_user->user.length); global.append(lex_user->user.str,lex_user->user.length);
global.append("'@'",3); global.append("'@'",3);
global.append(lex_user->host.str,lex_user->host.length); global.append(lex_user->host.str,lex_user->host.length);
global.append('\''); global.append('\'');
if (want_access & GRANT_ACL) if (table_access & GRANT_ACL)
global.append(" WITH GRANT OPTION",18); global.append(" WITH GRANT OPTION",18);
thd->packet.length(0); thd->packet.length(0);
net_store_data(&thd->packet,global.ptr(),global.length()); net_store_data(&thd->packet,global.ptr(),global.length());
if (my_net_write(&thd->net,(char*) thd->packet.ptr(), if (my_net_write(&thd->net,(char*) thd->packet.ptr(),
...@@ -3063,7 +3108,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user) ...@@ -3063,7 +3108,7 @@ int mysql_show_grants(THD *thd,LEX_USER *lex_user)
} }
} }
end: end:
VOID(pthread_mutex_unlock(&acl_cache->lock)); VOID(pthread_mutex_unlock(&acl_cache->lock));
pthread_mutex_unlock(&LOCK_grant); pthread_mutex_unlock(&LOCK_grant);
......
...@@ -76,8 +76,8 @@ ...@@ -76,8 +76,8 @@
#define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6)) #define get_rights_for_db(A) (((A) & 63) | (((A) & DB_CHUNK1) >> 4) | (((A) & DB_CHUNK2) >> 6))
#define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4)) #define fix_rights_for_table(A) (((A) & 63) | (((A) & ~63) << 4))
#define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4)) #define get_rights_for_table(A) (((A) & 63) | (((A) & ~63) >> 4))
#define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 7)) #define fix_rights_for_column(A) (((A) & 7) | (((A) & ~7) << 8))
#define get_rights_for_column(A) (((A) & 7) | (((A) & ~7) >> 7)) #define get_rights_for_column(A) (((A) & 7) | ((A) >> 8))
/* prototypes */ /* prototypes */
......
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