mirror of
https://github.com/MariaDB/server.git
synced 2025-07-30 16:24:05 +03:00
support of view underlying tables and SP functions security check added (BUG#9505) (WL#2787)
This commit is contained in:
233
sql/table.cc
233
sql/table.cc
@ -1798,41 +1798,43 @@ void st_table_list::calc_md5(char *buffer)
|
||||
|
||||
|
||||
/*
|
||||
set ancestor TABLE for table place holder of VIEW
|
||||
set underlying TABLE for table place holder of VIEW
|
||||
|
||||
DESCRIPTION
|
||||
Replace all views that only uses one table with the table itself.
|
||||
This allows us to treat the view as a simple table and even update
|
||||
it
|
||||
it (it is a kind of optimisation)
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::set_ancestor()
|
||||
st_table_list::set_underlying_merge()
|
||||
*/
|
||||
|
||||
void st_table_list::set_ancestor()
|
||||
void st_table_list::set_underlying_merge()
|
||||
{
|
||||
TABLE_LIST *tbl;
|
||||
|
||||
if ((tbl= ancestor))
|
||||
if ((tbl= merge_underlying_list))
|
||||
{
|
||||
/* This is a view. Process all tables of view */
|
||||
DBUG_ASSERT(view);
|
||||
DBUG_ASSERT(view && effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
do
|
||||
{
|
||||
if (tbl->ancestor) // This is a view
|
||||
if (tbl->merge_underlying_list) // This is a view
|
||||
{
|
||||
DBUG_ASSERT(tbl->view &&
|
||||
tbl->effective_algorithm == VIEW_ALGORITHM_MERGE);
|
||||
/*
|
||||
This is the only case where set_ancestor is called on an object
|
||||
that may not be a view (in which case ancestor is 0)
|
||||
*/
|
||||
tbl->ancestor->set_ancestor();
|
||||
tbl->merge_underlying_list->set_underlying_merge();
|
||||
}
|
||||
} while ((tbl= tbl->next_local));
|
||||
|
||||
if (!multitable_view)
|
||||
{
|
||||
table= ancestor->table;
|
||||
schema_table= ancestor->schema_table;
|
||||
table= merge_underlying_list->table;
|
||||
schema_table= merge_underlying_list->schema_table;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1842,12 +1844,9 @@ void st_table_list::set_ancestor()
|
||||
setup fields of placeholder of merged VIEW
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::setup_ancestor()
|
||||
st_table_list::setup_underlying()
|
||||
thd - thread handler
|
||||
|
||||
NOTES
|
||||
ancestor is list of tables and views used by view (underlying tables/views)
|
||||
|
||||
DESCRIPTION
|
||||
It is:
|
||||
- preparing translation table for view columns
|
||||
@ -1858,10 +1857,11 @@ void st_table_list::set_ancestor()
|
||||
TRUE - error
|
||||
*/
|
||||
|
||||
bool st_table_list::setup_ancestor(THD *thd)
|
||||
bool st_table_list::setup_underlying(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::setup_ancestor");
|
||||
if (!field_translation)
|
||||
DBUG_ENTER("st_table_list::setup_underlying");
|
||||
|
||||
if (!field_translation && merge_underlying_list)
|
||||
{
|
||||
Field_translator *transl;
|
||||
SELECT_LEX *select= &view->select_lex;
|
||||
@ -1875,10 +1875,10 @@ bool st_table_list::setup_ancestor(THD *thd)
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
|
||||
for (tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->ancestor &&
|
||||
tbl->setup_ancestor(thd))
|
||||
if (tbl->merge_underlying_list &&
|
||||
tbl->setup_underlying(thd))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
@ -1941,7 +1941,7 @@ bool st_table_list::prep_where(THD *thd, Item **conds,
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prep_where");
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->view && tbl->prep_where(thd, conds, no_where_clause))
|
||||
{
|
||||
@ -2023,7 +2023,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prep_check_option");
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
/* see comment of check_opt_type parameter */
|
||||
if (tbl->view &&
|
||||
@ -2046,7 +2046,7 @@ bool st_table_list::prep_check_option(THD *thd, uint8 check_opt_type)
|
||||
}
|
||||
if (check_opt_type == VIEW_CHECK_CASCADED)
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->check_option)
|
||||
item= and_conds(item, tbl->check_option);
|
||||
@ -2085,16 +2085,21 @@ void st_table_list::hide_view_error(THD *thd)
|
||||
{
|
||||
/* Hide "Unknown column" or "Unknown function" error */
|
||||
if (thd->net.last_errno == ER_BAD_FIELD_ERROR ||
|
||||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST)
|
||||
thd->net.last_errno == ER_SP_DOES_NOT_EXIST ||
|
||||
thd->net.last_errno == ER_PROCACCESS_DENIED_ERROR ||
|
||||
thd->net.last_errno == ER_COLUMNACCESS_DENIED_ERROR)
|
||||
{
|
||||
TABLE_LIST *top= top_table();
|
||||
thd->clear_error();
|
||||
my_error(ER_VIEW_INVALID, MYF(0), view_db.str, view_name.str);
|
||||
my_error(ER_VIEW_INVALID, MYF(0), top->view_db.str, top->view_name.str);
|
||||
}
|
||||
else if (thd->net.last_errno == ER_NO_DEFAULT_FOR_FIELD)
|
||||
{
|
||||
TABLE_LIST *top= top_table();
|
||||
thd->clear_error();
|
||||
// TODO: make correct error message
|
||||
my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0), view_db.str, view_name.str);
|
||||
my_error(ER_NO_DEFAULT_FOR_VIEW_FIELD, MYF(0),
|
||||
top->view_db.str, top->view_name.str);
|
||||
}
|
||||
}
|
||||
|
||||
@ -2115,10 +2120,10 @@ void st_table_list::hide_view_error(THD *thd)
|
||||
st_table_list *st_table_list::find_underlying_table(TABLE *table_to_find)
|
||||
{
|
||||
/* is this real table and table which we are looking for? */
|
||||
if (table == table_to_find && ancestor == 0)
|
||||
if (table == table_to_find && merge_underlying_list == 0)
|
||||
return this;
|
||||
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
TABLE_LIST *result;
|
||||
if ((result= tbl->find_underlying_table(table_to_find)))
|
||||
@ -2201,7 +2206,7 @@ int st_table_list::view_check_option(THD *thd, bool ignore_failure)
|
||||
bool st_table_list::check_single_table(st_table_list **table, table_map map,
|
||||
st_table_list *view)
|
||||
{
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
{
|
||||
if (tbl->table)
|
||||
{
|
||||
@ -2243,8 +2248,8 @@ bool st_table_list::set_insert_values(MEM_ROOT *mem_root)
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_ASSERT(view && ancestor);
|
||||
for (TABLE_LIST *tbl= ancestor; tbl; tbl= tbl->next_local)
|
||||
DBUG_ASSERT(view && merge_underlying_list);
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
if (tbl->set_insert_values(mem_root))
|
||||
return TRUE;
|
||||
}
|
||||
@ -2390,6 +2395,159 @@ TABLE_LIST *st_table_list::last_leaf_for_name_resolution()
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Register access mode which we need for underlying tables
|
||||
|
||||
SYNOPSIS
|
||||
register_want_access()
|
||||
want_access Acess which we require
|
||||
*/
|
||||
|
||||
void st_table_list::register_want_access(ulong want_access)
|
||||
{
|
||||
/* Remove SHOW_VIEW_ACL, because it will be checked during making view */
|
||||
want_access&= ~SHOW_VIEW_ACL;
|
||||
if (belong_to_view)
|
||||
{
|
||||
grant.want_privilege= want_access;
|
||||
if (table)
|
||||
table->grant.want_privilege= want_access;
|
||||
}
|
||||
for (TABLE_LIST *tbl= merge_underlying_list; tbl; tbl= tbl->next_local)
|
||||
tbl->register_want_access(want_access);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
Load security context infoemation for this view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_view_securety_context()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
bool st_table_list::prepare_view_securety_context(THD *thd)
|
||||
{
|
||||
DBUG_ENTER("st_table_list::prepare_view_securety_context");
|
||||
DBUG_PRINT("enter", ("table: %s", alias));
|
||||
|
||||
DBUG_ASSERT(!prelocking_placeholder && view);
|
||||
if (view_suid)
|
||||
{
|
||||
DBUG_PRINT("info", ("This table is suid view => load contest"));
|
||||
DBUG_ASSERT(view && view_sctx);
|
||||
if (acl_getroot_no_password(view_sctx,
|
||||
definer.user.str,
|
||||
definer.host.str,
|
||||
definer.host.str,
|
||||
thd->db))
|
||||
{
|
||||
my_error(ER_NO_SUCH_USER, MYF(0), definer.user.str, definer.host.str);
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
}
|
||||
DBUG_RETURN(FALSE);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Find security context of current view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::find_view_security_context()
|
||||
thd [in] thread handler
|
||||
|
||||
*/
|
||||
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *st_table_list::find_view_security_context(THD *thd)
|
||||
{
|
||||
Security_context *sctx;
|
||||
TABLE_LIST *upper_view= this;
|
||||
DBUG_ENTER("st_table_list::find_view_security_context");
|
||||
|
||||
DBUG_ASSERT(view);
|
||||
while (upper_view && !upper_view->view_suid)
|
||||
{
|
||||
DBUG_ASSERT(!upper_view->prelocking_placeholder);
|
||||
upper_view= upper_view->referencing_view;
|
||||
}
|
||||
if (upper_view)
|
||||
{
|
||||
DBUG_PRINT("info", ("Securety context of view %s will be used",
|
||||
upper_view->alias));
|
||||
sctx= upper_view->view_sctx;
|
||||
DBUG_ASSERT(sctx);
|
||||
}
|
||||
else
|
||||
{
|
||||
DBUG_PRINT("info", ("Current global context will be used"));
|
||||
sctx= thd->security_ctx;
|
||||
}
|
||||
DBUG_RETURN(sctx);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
Prepare security context and load underlying tables priveleges for view
|
||||
|
||||
SYNOPSIS
|
||||
st_table_list::prepare_security()
|
||||
thd [in] thread handler
|
||||
|
||||
RETURN
|
||||
FALSE OK
|
||||
TRUE Error
|
||||
*/
|
||||
|
||||
bool st_table_list::prepare_security(THD *thd)
|
||||
{
|
||||
List_iterator_fast<TABLE_LIST> tb(*view_tables);
|
||||
TABLE_LIST *tbl;
|
||||
#ifndef NO_EMBEDDED_ACCESS_CHECKS
|
||||
Security_context *save_security_ctx= thd->security_ctx;
|
||||
DBUG_ENTER("st_table_list::prepare_security");
|
||||
|
||||
DBUG_ASSERT(!prelocking_placeholder);
|
||||
if (prepare_view_securety_context(thd))
|
||||
{
|
||||
DBUG_RETURN(TRUE);
|
||||
}
|
||||
thd->security_ctx= find_view_security_context(thd);
|
||||
while ((tbl= tb++))
|
||||
{
|
||||
DBUG_ASSERT(tbl->referencing_view);
|
||||
char *db, *table_name;
|
||||
if (tbl->view)
|
||||
{
|
||||
db= tbl->view_db.str;
|
||||
table_name= tbl->view_name.str;
|
||||
}
|
||||
else
|
||||
{
|
||||
db= tbl->db;
|
||||
table_name= tbl->table_name;
|
||||
}
|
||||
fill_effective_table_privileges(thd, &tbl->grant, db, table_name);
|
||||
if (tbl->table)
|
||||
tbl->table->grant= grant;
|
||||
}
|
||||
thd->security_ctx= save_security_ctx;
|
||||
DBUG_RETURN(FALSE);
|
||||
#else
|
||||
while ((tbl= tb++))
|
||||
tbl->grant.privilege= ~NO_ACCESS;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
Natural_join_column::Natural_join_column(Field_translator *field_param,
|
||||
TABLE_LIST *tab)
|
||||
{
|
||||
@ -2498,6 +2656,9 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
||||
GRANT_INFO *grant;
|
||||
const char *db_name;
|
||||
const char *table_name;
|
||||
Security_context *save_security_ctx= 0;
|
||||
Security_context *new_sctx= table_ref->security_ctx;
|
||||
bool res;
|
||||
|
||||
if (view_field)
|
||||
{
|
||||
@ -2514,7 +2675,15 @@ Natural_join_column::check_grants(THD *thd, const char *name, uint length)
|
||||
table_name= table_ref->table->s->table_name;
|
||||
}
|
||||
|
||||
return check_grant_column(thd, grant, db_name, table_name, name, length);
|
||||
if (new_sctx)
|
||||
{
|
||||
save_security_ctx= thd->security_ctx;
|
||||
thd->security_ctx= new_sctx;
|
||||
}
|
||||
res= check_grant_column(thd, grant, db_name, table_name, name, length);
|
||||
if (save_security_ctx)
|
||||
thd->security_ctx= save_security_ctx;
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
Reference in New Issue
Block a user