1
0
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:
bell@sanja.is.com.ua
2005-10-28 00:18:23 +03:00
parent bee76b78a2
commit 1b164c7b83
24 changed files with 957 additions and 176 deletions

View File

@ -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