Commit 0ab30e24 authored by unknown's avatar unknown
Browse files

Merge jbruehe@bk-internal.mysql.com:/home/bk/mysql-5.0

into mysql.com:/M50/bug16730-5.0

parents 686bd7ee 8f395ebb
Loading
Loading
Loading
Loading
+184 −103
Original line number Diff line number Diff line
@@ -65,109 +65,6 @@ user_str
mysqltest_dfn@localhost
mysqltest_dfn@localhost

---> connection: default
use mysqltest_db1;
REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;

---> connection: wl2818_definer_con
use mysqltest_db1;
DROP TRIGGER trg1;
SET @new_sum = 0;
SET @old_sum = 0;
---> INSERT INTO statement; BEFORE timing
CREATE TRIGGER trg1 BEFORE INSERT ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
INSERT INTO t1 VALUES(4);
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> INSERT INTO statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER INSERT ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
INSERT INTO t1 VALUES(5);
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> UPDATE statement; BEFORE timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 BEFORE UPDATE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
UPDATE t1 SET num_value = 10;
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> UPDATE statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER UPDATE ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
UPDATE t1 SET num_value = 20;
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> DELETE statement; BEFORE timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 BEFORE DELETE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
DELETE FROM t1;
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> DELETE statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER DELETE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
DELETE FROM t1;
ERROR 42000: SELECT command denied to user 'mysqltest_dfn'@'localhost' for table 't1'

---> connection: default
use mysqltest_db1;
GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_dfn@localhost;
REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_dfn@localhost;

---> connection: wl2818_definer_con
use mysqltest_db1;
DROP TRIGGER trg1;
SET @new_sum = 0;
SET @old_sum = 0;
---> INSERT INTO statement; BEFORE timing
CREATE TRIGGER trg1 BEFORE INSERT ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
INSERT INTO t1 VALUES(4);
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> INSERT INTO statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER INSERT ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
INSERT INTO t1 VALUES(5);
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> UPDATE statement; BEFORE timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 BEFORE UPDATE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
UPDATE t1 SET num_value = 10;
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> UPDATE statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER UPDATE ON t1
FOR EACH ROW
SET @new_sum = @new_sum + NEW.num_value;
UPDATE t1 SET num_value = 20;
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> DELETE statement; BEFORE timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 BEFORE DELETE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
DELETE FROM t1;
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'
---> DELETE statement; AFTER timing
DROP TRIGGER trg1;
CREATE TRIGGER trg1 AFTER DELETE ON t1
FOR EACH ROW
SET @old_sum = @old_sum + OLD.num_value;
DELETE FROM t1;
ERROR 42000: UPDATE command denied to user 'mysqltest_dfn'@'localhost' for table 't1'

---> connection: wl2818_definer_con
use mysqltest_db1;
DROP TRIGGER trg1;
@@ -229,3 +126,187 @@ DROP USER mysqltest_inv@localhost;
DROP DATABASE mysqltest_db1;
Warnings:
Warning	1454	No definer attribute for trigger 'mysqltest_db1'.'trg1'. The trigger will be activated under the authorization of the invoker, which may have insufficient privileges. Please recreate the trigger.
DELETE FROM mysql.user WHERE User LIKE 'mysqltest_%';
DELETE FROM mysql.db WHERE User LIKE 'mysqltest_%';
DELETE FROM mysql.tables_priv WHERE User LIKE 'mysqltest_%';
DELETE FROM mysql.columns_priv WHERE User LIKE 'mysqltest_%';
FLUSH PRIVILEGES;
DROP DATABASE IF EXISTS mysqltest_db1;
CREATE DATABASE mysqltest_db1;
use mysqltest_db1;
CREATE TABLE t1(col CHAR(20));
CREATE TABLE t2(col CHAR(20));
CREATE TABLE t3(col CHAR(20));
CREATE TABLE t4(col CHAR(20));
CREATE USER mysqltest_u1@localhost;
REVOKE ALL PRIVILEGES, GRANT OPTION FROM mysqltest_u1@localhost;
GRANT SUPER ON *.* TO mysqltest_u1@localhost;
GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
SET @mysqltest_var = NULL;

---> connection: default
use mysqltest_db1;
REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
GRANT DELETE ON mysqltest_db1.* TO mysqltest_u1@localhost;
SHOW GRANTS FOR mysqltest_u1@localhost;
Grants for mysqltest_u1@localhost
GRANT SUPER ON *.* TO 'mysqltest_u1'@'localhost'
GRANT DELETE ON `mysqltest_db1`.* TO 'mysqltest_u1'@'localhost'

---> connection: bug15166_u1_con
use mysqltest_db1;
CREATE TRIGGER t1_trg_after_delete AFTER DELETE ON t1
FOR EACH ROW
SET @mysqltest_var = 'Hello, world!';

---> connection: default
use mysqltest_db1;
GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;

---> connection: bug15166_u1_con
use mysqltest_db1;
CREATE TRIGGER t1_trg_err_1 BEFORE INSERT ON t1
FOR EACH ROW
SET @mysqltest_var = NEW.col;
DROP TRIGGER t1_trg_err_1;
CREATE TRIGGER t1_trg_err_2 BEFORE DELETE ON t1
FOR EACH ROW
SET @mysqltest_var = OLD.col;
DROP TRIGGER t1_trg_err_2;
CREATE TRIGGER t2_trg_before_insert BEFORE INSERT ON t2
FOR EACH ROW
SET NEW.col = 't2_trg_before_insert';
CREATE TRIGGER t3_trg_err_1 BEFORE INSERT ON t3
FOR EACH ROW
SET @mysqltest_var = NEW.col;
DROP TRIGGER t3_trg_err_1;
CREATE TRIGGER t3_trg_err_2 BEFORE DELETE ON t3
FOR EACH ROW
SET @mysqltest_var = OLD.col;
DROP TRIGGER t3_trg_err_2;
CREATE TRIGGER t4_trg_before_insert BEFORE INSERT ON t4
FOR EACH ROW
SET NEW.col = 't4_trg_before_insert';

---> connection: default
use mysqltest_db1;
REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
GRANT SELECT(col) on mysqltest_db1.t3 TO mysqltest_u1@localhost;
GRANT SELECT(col) on mysqltest_db1.t4 TO mysqltest_u1@localhost;

---> connection: bug15166_u1_con
use mysqltest_db1;
CREATE TRIGGER t1_trg_after_insert AFTER INSERT ON t1
FOR EACH ROW
SET @mysqltest_var = NEW.col;
CREATE TRIGGER t1_trg_after_update AFTER UPDATE ON t1
FOR EACH ROW
SET @mysqltest_var = OLD.col;
CREATE TRIGGER t2_trg_err_1 BEFORE UPDATE ON t2
FOR EACH ROW
SET NEW.col = 't2_trg_err_1';
DROP TRIGGER t2_trg_err_1;
CREATE TRIGGER t2_trg_err_2 BEFORE UPDATE ON t2
FOR EACH ROW
SET NEW.col = CONCAT(OLD.col, '(updated)');
DROP TRIGGER t2_trg_err_2;
CREATE TRIGGER t3_trg_after_insert AFTER INSERT ON t3
FOR EACH ROW
SET @mysqltest_var = NEW.col;
CREATE TRIGGER t3_trg_after_update AFTER UPDATE ON t3
FOR EACH ROW
SET @mysqltest_var = OLD.col;
CREATE TRIGGER t4_trg_err_1 BEFORE UPDATE ON t4
FOR EACH ROW
SET NEW.col = 't4_trg_err_1';
DROP TRIGGER t4_trg_err_1;
CREATE TRIGGER t4_trg_err_2 BEFORE UPDATE ON t4
FOR EACH ROW
SET NEW.col = CONCAT(OLD.col, '(updated)');
DROP TRIGGER t4_trg_err_2;

---> connection: default
use mysqltest_db1;
REVOKE SELECT ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
REVOKE SELECT ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
GRANT UPDATE ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
GRANT UPDATE ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
REVOKE SELECT(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
REVOKE SELECT(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
GRANT UPDATE(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
GRANT UPDATE(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
INSERT INTO t1 VALUES('line1');
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't1'
SELECT * FROM t1;
col
line1
SELECT @mysqltest_var;
@mysqltest_var
NULL
INSERT INTO t2 VALUES('line2');
SELECT * FROM t2;
col
t2_trg_before_insert
INSERT INTO t3 VALUES('t3_line1');
ERROR 42000: SELECT command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't3'
SELECT * FROM t3;
col
t3_line1
SELECT @mysqltest_var;
@mysqltest_var
NULL
INSERT INTO t4 VALUES('t4_line2');
SELECT * FROM t4;
col
t4_trg_before_insert

---> connection: default
use mysqltest_db1;
REVOKE UPDATE ON mysqltest_db1.t1 FROM mysqltest_u1@localhost;
REVOKE UPDATE ON mysqltest_db1.t2 FROM mysqltest_u1@localhost;
GRANT SELECT ON mysqltest_db1.t1 TO mysqltest_u1@localhost;
GRANT SELECT ON mysqltest_db1.t2 TO mysqltest_u1@localhost;
REVOKE UPDATE(col) ON mysqltest_db1.t3 FROM mysqltest_u1@localhost;
REVOKE UPDATE(col) ON mysqltest_db1.t4 FROM mysqltest_u1@localhost;
GRANT SELECT(col) ON mysqltest_db1.t3 TO mysqltest_u1@localhost;
GRANT SELECT(col) ON mysqltest_db1.t4 TO mysqltest_u1@localhost;
INSERT INTO t1 VALUES('line3');
SELECT * FROM t1;
col
line1
line3
SELECT @mysqltest_var;
@mysqltest_var
line3
INSERT INTO t2 VALUES('line4');
ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't2'
SELECT * FROM t2;
col
t2_trg_before_insert
INSERT INTO t3 VALUES('t3_line2');
SELECT * FROM t3;
col
t3_line1
t3_line2
SELECT @mysqltest_var;
@mysqltest_var
t3_line2
INSERT INTO t4 VALUES('t4_line2');
ERROR 42000: UPDATE command denied to user 'mysqltest_u1'@'localhost' for column 'col' in table 't4'
SELECT * FROM t4;
col
t4_trg_before_insert
DELETE FROM t1;
SELECT @mysqltest_var;
@mysqltest_var
Hello, world!
DROP USER mysqltest_u1@localhost;
DROP DATABASE mysqltest_db1;
+302 −211

File changed.

Preview size limit exceeded, changes collapsed.

+27 −4
Original line number Diff line number Diff line
@@ -5215,6 +5215,7 @@ void Item_insert_value::print(String *str)
    setup_field()
      thd   - current thread context
      table - table of trigger (and where we looking for fields)
      table_grant_info - GRANT_INFO of the subject table

  NOTE
    This function does almost the same as fix_fields() for Item_field
@@ -5228,7 +5229,8 @@ void Item_insert_value::print(String *str)
    table of trigger which uses this item.
*/

void Item_trigger_field::setup_field(THD *thd, TABLE *table)
void Item_trigger_field::setup_field(THD *thd, TABLE *table,
                                     GRANT_INFO *table_grant_info)
{
  bool save_set_query_id= thd->set_query_id;

@@ -5242,6 +5244,7 @@ void Item_trigger_field::setup_field(THD *thd, TABLE *table)
                            0, &field_idx);
  thd->set_query_id= save_set_query_id;
  triggers= table->triggers;
  table_grants= table_grant_info;
}


@@ -5260,22 +5263,42 @@ bool Item_trigger_field::fix_fields(THD *thd, Item **items)
    Since trigger is object tightly associated with TABLE object most
    of its set up can be performed during trigger loading i.e. trigger
    parsing! So we have little to do in fix_fields. :)
    FIXME may be we still should bother about permissions here.
  */

  DBUG_ASSERT(fixed == 0);

  /* Set field. */

  if (field_idx != (uint)-1)
  {
#ifndef NO_EMBEDDED_ACCESS_CHECKS
    /*
      Check access privileges for the subject table. We check privileges only
      in runtime.
    */

    if (table_grants)
    {
      table_grants->want_privilege=
        access_type == AT_READ ? SELECT_ACL : UPDATE_ACL;

      if (check_grant_column(thd, table_grants, triggers->table->s->db,
                             triggers->table->s->table_name, field_name,
                             strlen(field_name), thd->security_ctx))
        return TRUE;
    }
#endif // NO_EMBEDDED_ACCESS_CHECKS

    field= (row_version == OLD_ROW) ? triggers->old_field[field_idx] :
                                      triggers->new_field[field_idx];
    set_field(field);
    fixed= 1;
    return 0;
    return FALSE;
  }

  my_error(ER_BAD_FIELD_ERROR, MYF(0), field_name,
           (row_version == NEW_ROW) ? "NEW" : "OLD");
  return 1;
  return TRUE;
}


+11 −3
Original line number Diff line number Diff line
@@ -2126,6 +2126,8 @@ class Item_trigger_field : public Item_field
  /* Is this item represents row from NEW or OLD row ? */
  enum row_version_type {OLD_ROW, NEW_ROW};
  row_version_type row_version;
  /* Is this item used for reading or updating the value? */
  enum access_types { AT_READ = 0x1, AT_UPDATE = 0x2 };
  /* Next in list of all Item_trigger_field's in trigger */
  Item_trigger_field *next_trg_field;
  /* Index of the field in the TABLE::field array */
@@ -2135,18 +2137,24 @@ class Item_trigger_field : public Item_field

  Item_trigger_field(Name_resolution_context *context_arg,
                     row_version_type row_ver_arg,
                     const char *field_name_arg)
                     const char *field_name_arg,
                     access_types access_type_arg)
    :Item_field(context_arg,
               (const char *)NULL, (const char *)NULL, field_name_arg),
     row_version(row_ver_arg), field_idx((uint)-1)
     row_version(row_ver_arg), field_idx((uint)-1),
     access_type(access_type_arg), table_grants(NULL)
  {}
  void setup_field(THD *thd, TABLE *table);
  void setup_field(THD *thd, TABLE *table, GRANT_INFO *table_grant_info);
  enum Type type() const { return TRIGGER_FIELD_ITEM; }
  bool eq(const Item *item, bool binary_cmp) const;
  bool fix_fields(THD *, Item **);
  void print(String *str);
  table_map used_tables() const { return (table_map)0L; }
  void cleanup();

private:
  access_types access_type;
  GRANT_INFO *table_grants;
};


+20 −34
Original line number Diff line number Diff line
@@ -381,7 +381,12 @@ bool Table_triggers_list::create_trigger(THD *thd, TABLE_LIST *tables,
  for (trg_field= (Item_trigger_field *)(lex->trg_table_fields.first);
       trg_field; trg_field= trg_field->next_trg_field)
  {
    trg_field->setup_field(thd, table);
    /*
      NOTE: now we do not check privileges at CREATE TRIGGER time. This will
      be changed in the future.
    */
    trg_field->setup_field(thd, table, NULL);

    if (!trg_field->fixed &&
        trg_field->fix_fields(thd, (Item **)0))
      return 1;
@@ -828,8 +833,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,

      char *trg_name_buff;
      List_iterator_fast<ulonglong> itm(triggers->definition_modes_list);
      List_iterator_fast<LEX_STRING> it_definer(triggers->
                                                definers_list);
      List_iterator_fast<LEX_STRING> it_definer(triggers->definers_list);
      LEX *old_lex= thd->lex, lex;
      sp_rcontext *save_spcont= thd->spcont;
      ulong save_sql_mode= thd->variables.sql_mode;
@@ -844,6 +848,7 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
      {
        trg_sql_mode= itm++;
        LEX_STRING *trg_definer= it_definer++;

        thd->variables.sql_mode= (ulong)*trg_sql_mode;
        lex_start(thd, (uchar*)trg_create_str->str, trg_create_str->length);

@@ -917,11 +922,11 @@ bool Table_triggers_list::check_n_load(THD *thd, const char *db,
               (Item_trigger_field *)(lex.trg_table_fields.first);
             trg_field;
             trg_field= trg_field->next_trg_field)
          trg_field->setup_field(thd, table);

        triggers->m_spec_var_used[lex.trg_chistics.event]
          [lex.trg_chistics.action_time]=
          lex.trg_table_fields.first ? TRUE : FALSE;
        {
          trg_field->setup_field(thd, table, 
            &triggers->subject_table_grants[lex.trg_chistics.event]
                                           [lex.trg_chistics.action_time]);
        }

        lex_end(&lex);
      }
@@ -1172,33 +1177,14 @@ bool Table_triggers_list::process_triggers(THD *thd, trg_event_type event,
    }

    /*
      If the trigger uses special variables (NEW/OLD), check that we have
      SELECT and UPDATE privileges on the subject table.
      Fetch information about table-level privileges to GRANT_INFO structure for
      subject table. Check of privileges that will use it and information about
      column-level privileges will happen in Item_trigger_field::fix_fields().
    */

    if (is_special_var_used(event, time_type))
    {
      TABLE_LIST table_list, **save_query_tables_own_last;
      bzero((char *) &table_list, sizeof (table_list));
      table_list.db= (char *) table->s->db;
      table_list.db_length= strlen(table_list.db);
      table_list.table_name= (char *) table->s->table_name;
      table_list.table_name_length= strlen(table_list.table_name);
      table_list.alias= (char *) table->alias;
      table_list.table= table;
      save_query_tables_own_last= thd->lex->query_tables_own_last;
      thd->lex->query_tables_own_last= 0;

      err_status= check_table_access(thd, SELECT_ACL | UPDATE_ACL,
                                     &table_list, 0);
      thd->lex->query_tables_own_last= save_query_tables_own_last;
      if (err_status)
      {
        sp_restore_security_context(thd, save_ctx);
        return TRUE;
      }
    }
    
    fill_effective_table_privileges(thd,
                                    &subject_table_grants[event][time_type],
                                    table->s->db, table->s->table_name);
#endif // NO_EMBEDDED_ACCESS_CHECKS

    thd->reset_sub_statement_state(&statement_state, SUB_STMT_TRIGGER);
Loading