diff options
Diffstat (limited to 'sql/sp_head.cc')
-rw-r--r-- | sql/sp_head.cc | 190 |
1 files changed, 186 insertions, 4 deletions
diff --git a/sql/sp_head.cc b/sql/sp_head.cc index 9965c48935a..e39efd78d7e 100644 --- a/sql/sp_head.cc +++ b/sql/sp_head.cc @@ -1097,6 +1097,7 @@ sp_head::execute(THD *thd) thd->restore_active_arena(&execute_arena, &backup_arena); + thd->spcont->pop_all_cursors(); // To avoid memory leaks after an error /* Restore all saved */ old_packet.swap(thd->packet); @@ -1158,6 +1159,161 @@ sp_head::execute(THD *thd) m_first_instance->m_first_free_instance->m_recursion_level == m_recursion_level + 1)); m_first_instance->m_first_free_instance= this; + + DBUG_RETURN(err_status); +} + + +#ifndef NO_EMBEDDED_ACCESS_CHECKS +/* + set_routine_security_ctx() changes routine security context, and + checks if there is an EXECUTE privilege in new context. If there is + no EXECUTE privilege, it changes the context back and returns a + error. + + SYNOPSIS + set_routine_security_ctx() + thd thread handle + sp stored routine to change the context for + is_proc TRUE is procedure, FALSE if function + save_ctx pointer to an old security context + + RETURN + TRUE if there was a error, and the context wasn't changed. + FALSE if the context was changed. +*/ + +bool +set_routine_security_ctx(THD *thd, sp_head *sp, bool is_proc, + Security_context **save_ctx) +{ + *save_ctx= 0; + if (sp_change_security_context(thd, sp, save_ctx)) + return TRUE; + + /* + If we changed context to run as another user, we need to check the + access right for the new context again as someone may have revoked + the right to use the procedure from this user. + + TODO: + Cache if the definer has the right to use the object on the + first usage and only reset the cache if someone does a GRANT + statement that 'may' affect this. + */ + if (*save_ctx && + check_routine_access(thd, EXECUTE_ACL, + sp->m_db.str, sp->m_name.str, is_proc, FALSE)) + { + sp_restore_security_context(thd, *save_ctx); + *save_ctx= 0; + return TRUE; + } + + return FALSE; +} +#endif // ! NO_EMBEDDED_ACCESS_CHECKS + + +/* + Execute a trigger: + - changes security context for triggers + - switch to new memroot + - call sp_head::execute + - restore old memroot + - restores security context + + SYNOPSIS + sp_head::execute_trigger() + thd Thread handle + db database name + table table name + grant_info GRANT_INFO structure to be filled with + information about definer's privileges + on subject table + + RETURN + FALSE on success + TRUE on error +*/ + +bool +sp_head::execute_trigger(THD *thd, const char *db, const char *table, + GRANT_INFO *grant_info) +{ + sp_rcontext *octx = thd->spcont; + sp_rcontext *nctx = NULL; + bool err_status= FALSE; + MEM_ROOT call_mem_root; + Query_arena call_arena(&call_mem_root, Query_arena::INITIALIZED_FOR_SP); + Query_arena backup_arena; + + DBUG_ENTER("sp_head::execute_trigger"); + DBUG_PRINT("info", ("trigger %s", m_name.str)); + +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *save_ctx; + if (sp_change_security_context(thd, this, &save_ctx)) + DBUG_RETURN(TRUE); + + /* + NOTE: TRIGGER_ACL should be used here. + */ + if (check_global_access(thd, SUPER_ACL)) + { + sp_restore_security_context(thd, save_ctx); + DBUG_RETURN(TRUE); + } + + /* + 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(). + */ + fill_effective_table_privileges(thd, grant_info, db, table); +#endif // NO_EMBEDDED_ACCESS_CHECKS + + /* + Prepare arena and memroot for objects which lifetime is whole + duration of trigger call (sp_rcontext, it's tables and items, + sp_cursor and Item_cache holders for case expressions). We can't + use caller's arena/memroot for those objects because in this case + some fixed amount of memory will be consumed for each trigger + invocation and so statements which involve lot of them will hog + memory. + + TODO: we should create sp_rcontext once per command and reuse it + on subsequent executions of a trigger. + */ + init_sql_alloc(&call_mem_root, MEM_ROOT_BLOCK_SIZE, 0); + thd->set_n_backup_active_arena(&call_arena, &backup_arena); + + if (!(nctx= new sp_rcontext(m_pcont, 0, octx)) || + nctx->init(thd)) + { + err_status= TRUE; + goto err_with_cleanup; + } + +#ifndef DBUG_OFF + nctx->sp= this; +#endif + + thd->spcont= nctx; + + err_status= execute(thd); + +err_with_cleanup: + thd->restore_active_arena(&call_arena, &backup_arena); +#ifndef NO_EMBEDDED_ACCESS_CHECKS + sp_restore_security_context(thd, save_ctx); +#endif // NO_EMBEDDED_ACCESS_CHECKS + delete nctx; + call_arena.free_items(); + free_root(&call_mem_root, MYF(0)); + thd->spcont= octx; + DBUG_RETURN(err_status); } @@ -1165,8 +1321,12 @@ sp_head::execute(THD *thd) /* Execute a function: - evaluate parameters + - changes security context for SUID routines + - switch to new memroot - call sp_head::execute + - restore old memroot - evaluate the return value + - restores security context SYNOPSIS sp_head::execute_function() @@ -1293,6 +1453,15 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } thd->spcont= nctx; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *save_security_ctx; + if (set_routine_security_ctx(thd, this, FALSE, &save_security_ctx)) + { + err_status= TRUE; + goto err_with_cleanup; + } +#endif + binlog_save_options= thd->options; if (need_binlog_call) { @@ -1333,7 +1502,7 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, reset_dynamic(&thd->user_var_events); } - if (m_type == TYPE_ENUM_FUNCTION && !err_status) + if (!err_status) { /* We need result only in function but not in trigger */ @@ -1344,8 +1513,9 @@ sp_head::execute_function(THD *thd, Item **argp, uint argcount, } } - - nctx->pop_all_cursors(); // To avoid memory leaks after an error +#ifndef NO_EMBEDDED_ACCESS_CHECKS + sp_restore_security_context(thd, save_security_ctx); +#endif err_with_cleanup: delete nctx; @@ -1368,8 +1538,10 @@ err_with_cleanup: The function does the following steps: - Set all parameters + - changes security context for SUID routines - call sp_head::execute - copy back values of INOUT and OUT parameters + - restores security context RETURN FALSE on success @@ -1490,6 +1662,12 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) thd->spcont= nctx; +#ifndef NO_EMBEDDED_ACCESS_CHECKS + Security_context *save_security_ctx= 0; + if (!err_status) + err_status= set_routine_security_ctx(thd, this, TRUE, &save_security_ctx); +#endif + if (!err_status) err_status= execute(thd); @@ -1534,10 +1712,14 @@ sp_head::execute_procedure(THD *thd, List<Item> *args) } } +#ifndef NO_EMBEDDED_ACCESS_CHECKS + if (save_security_ctx) + sp_restore_security_context(thd, save_security_ctx); +#endif + if (!save_spcont) delete octx; - nctx->pop_all_cursors(); // To avoid memory leaks after an error delete nctx; thd->spcont= save_spcont; |