6
0
mirror of https://github.com/FirebirdSQL/firebird-qa.git synced 2025-01-22 21:43:06 +01:00
firebird-qa/files/core_4731.sql

684 lines
28 KiB
MySQL
Raw Normal View History

2021-11-26 19:15:07 +01:00
set wng off;
set term ^;
execute block as
begin
-- do NOT remote! This can be useful later for debug purposes!
--rdb$set_context('USER_SESSION','DEBUG_RDB_TABLE', 'RDB$PROCEDURES');
end
^
set term ;^
create or alter user %(non_privileged_name)s password '123';
create or alter user %(dba_privileged_name)s password '123';
commit;
revoke all on all from %(non_privileged_name)s;
revoke all on all from %(dba_privileged_name)s;
commit;
grant RDB$ADMIN to %(dba_privileged_name)s;
commit;
grant create TABLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create VIEW to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create PROCEDURE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create FUNCTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create PACKAGE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create GENERATOR to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create SEQUENCE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create DOMAIN to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create EXCEPTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create ROLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create CHARACTER SET to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create COLLATION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant create FILTER to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any TABLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any VIEW to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any PROCEDURE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any FUNCTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any PACKAGE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any GENERATOR to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any SEQUENCE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any DOMAIN to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any EXCEPTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any ROLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any CHARACTER SET to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any COLLATION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant alter any FILTER to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any TABLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any VIEW to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any PROCEDURE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any FUNCTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any PACKAGE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any GENERATOR to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any SEQUENCE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any DOMAIN to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any EXCEPTION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any ROLE to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any CHARACTER SET to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any COLLATION to %(non_privileged_name)s, %(dba_privileged_name)s;
grant drop any FILTER to %(non_privileged_name)s, %(dba_privileged_name)s;
commit;
create or alter view v_passed as select 1 id from rdb$database;
commit;
recreate table vulnerable_on_sys_tables(
sys_table rdb$relation_name,
ord_pos smallint, -- for proper sorting
ret_dbkey smallint default 0, -- 1 ==> this expression CONTAINS 'returning [t.]rdb$dbkey, otherwise 0
sys_dbkey char(8) character set octets, -- value of returned rdb$db_key (to be sure that change really occured)
vulnerable_type char(1),
vulnerable_gdscode int,
vulnerable_sqlcode int,
vulnerable_sqlstate char(5),
vulnerable_expr varchar(1024),
dml_where varchar(255),
actual_role varchar(20),
id int generated by default as identity constraint pk_vulnerable_on_sys_tables primary key
);
commit;
create or alter view v_passed as
select vulnerable_expr -- || ' rollback;'
|| iif(
v.ret_dbkey = 1,
' -- length of returned rdb$dbkey='|| coalesce(octet_length(sys_dbkey),'0'),
''
)
as vulnerable_expr
from vulnerable_on_sys_tables v
where v.vulnerable_gdscode < 0
and (
v.ret_dbkey is distinct from 1
or
coalesce(octet_length(sys_dbkey),0) > 0
)
order by
sys_table
,vulnerable_expr -- before 23.10.2015: "order by sys_table, id" --> FAILED on comparison with expected stdout because 'id' was not included in output
;
commit;
recreate table dml_expr(s varchar(1024));
commit;
insert into dml_expr(s)
select 'create sequence g_common' from rdb$database union all
select 'create exception ex_bad_argument ''argument @1 is invalid''' from rdb$database union all
select 'create collation nums_coll for utf8 from unicode case insensitive ''NUMERIC-SORT=1''' from rdb$database union all
select 'create domain dm_int as int' from rdb$database union all
select 'create domain dm_nums as varchar(20) character set utf8 collate nums_coll' from rdb$database union all
select 'create table test_master(id dm_int primary key using index test_master_pk, txt dm_nums, z computed by( char_length(txt) ), constraint chk_01 check(txt is not null) )' from rdb$database union all
select 'create table test_detail(id dm_int primary key using index test_detail_pk, pid dm_int, constraint fk_01 foreign key(pid) references test_master(id) on delete cascade using index test_detail_fk )' from rdb$database union all
select 'create index test_master_txt on test_master(txt)' from rdb$database union all
select 'create view v_test_master as select * from test_master' from rdb$database union all
select 'create procedure sp_test_master(a_id dm_int) returns(o_txt dm_nums) as begin for select txt from test_master where id=:a_id into o_txt do suspend; end' from rdb$database union all
select 'create function fn_test_master(a_id dm_int) returns dm_nums as begin return (select txt from test_master where id=:a_id); end' from rdb$database union all
select 'create trigger test_master_bi for test_master active before insert as begin new.id=gen_id(g_common,1); end' from rdb$database union all
select 'create package test_pkg as begin procedure pkg_test(a_id dm_int) returns(o_txt dm_nums); end' from rdb$database union all
select 'create package body test_pkg as begin procedure pkg_test(a_id dm_int) returns(o_txt dm_nums) as begin for select txt from test_master where id=:a_id into o_txt do suspend; end end'
from rdb$database
;
commit;
set term ^;
execute block as
declare v_dbname type of column mon$database.mon$database_name;
declare v_usr type of column sec$users.sec$user_name = '%(dba_privileged_name)s';
declare v_pwd varchar(20) = '123';
declare v_role varchar(20) = 'RDB$ADMIN';
begin
v_dbname = 'localhost:' || rdb$get_context('SYSTEM','DB_NAME');
for select s from dml_expr as cursor c
do
execute statement (c.s)
on external (v_dbname)
as user upper(v_usr) password (v_pwd) role (v_role);
end
^
set term ;^
commit;
-- ##################################################################
-- [ 1 ] attempts to create new tables with FKs ref. to SYSTEM tables
-- ##################################################################
set term ^;
create or alter procedure sp_gen_expr_for_creating_fkeys as
declare rel_name varchar(31) character set unicode_fss collate unicode_fss;
declare vulnerable_expr varchar(1024) character set unicode_fss collate unicode_fss;
declare v_fk1 varchar(8192) character set unicode_fss collate unicode_fss;
declare v_fks varchar(8192) character set unicode_fss collate unicode_fss;
declare v_mf varchar(8192) character set unicode_fss collate unicode_fss;
begin
for
with
a as (
select
lower(rc.rdb$relation_name) tab_name
--,rc.rdb$constraint_name cnt_name
,lower(rc.rdb$index_name) idx_name
--,rc.rdb$constraint_type
--,ri.rdb$index_id
,rs.rdb$field_position fld_pos
,lower(rs.rdb$field_name) fld_name
--,rf.rdb$field_name
,rf.rdb$field_source fld_src
,case ff.rdb$field_type
when 7 then 'smallint'
when 8 then 'integer'
when 10 then 'float'
when 14 then 'char' --(' || cast(cast(f.rdb$field_length/iif(ce.rdb$character_set_name=upper('utf8'),4,1) as int) as varchar(5)) || ')'
when 16 then -- dialect 3 only
--case ff.rdb$field_sub_type
case coalesce(ff.rdb$field_sub_type,0) -- null found for rdb$generators.rdb$initial_value AND rdb$triggers.rdb$trigger_type
when 0 then 'bigint'
when 1 then 'numeric' --(15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
when 2 then 'decimal' --(15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
else 'unknown'
end
when 12 then 'date'
when 13 then 'time'
when 27 then -- dialect 1 only
case ff.rdb$field_scale
when 0 then 'double precision'
else 'numeric' -- (15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
end
when 35 then iif(m.dia=1, 'date', 'timestamp')
when 37 then 'varchar' -- (' || cast(cast(f.rdb$field_length/iif(ce.rdb$character_set_name=upper('utf8'),4,1) as int) as varchar(5)) || ')'
when 261 then 'blob' -- sub_type ' || f.rdb$field_sub_type || ' segment size ' || f.rdb$segment_length
else 'unknown'
end as fld_base_type
--,ff.rdb$field_length fld_len
,cast(ff.rdb$field_length / iif(ce.rdb$character_set_name in ( upper('utf8'), upper('un~icode_fss') ), 4, 1) as int) fld_len
,lower(ce.rdb$character_set_name) cset
,lower(co.rdb$collation_name) coll
,dense_rank()over(partition by rc.rdb$relation_name order by rc.rdb$index_name, rs.rdb$field_position) dr1
,dense_rank()over(partition by rc.rdb$relation_name, rc.rdb$index_name order by rs.rdb$field_position) dr2
,dense_rank()over(partition by rc.rdb$relation_name, rc.rdb$index_name order by rs.rdb$field_position desc) dr2d
,count(*)over(partition by rc.rdb$relation_name) fld_cnt
from (select m.mon$sql_dialect as dia from mon$database m) m
cross join rdb$relation_constraints rc
join rdb$relations rr on rc.rdb$relation_name = rr.rdb$relation_name
join rdb$indices ri on rc.rdb$index_name = ri.rdb$index_name
join rdb$index_segments rs on ri.rdb$index_name = rs.rdb$index_name
left join rdb$relation_fields rf on rc.rdb$relation_name = rf.rdb$relation_name and rs.rdb$field_name = rf.rdb$field_name
left join rdb$fields ff on rf.rdb$field_source = ff.rdb$field_name
left join rdb$collations co on ff.rdb$character_set_id=co.rdb$character_set_id and ff.rdb$collation_id=co.rdb$collation_id
left join rdb$character_sets ce on co.rdb$character_set_id=ce.rdb$character_set_id
where
--rc.rdb$relation_name --starting with upper('rdb$')
coalesce(rr.rdb$system_flag,0) is distinct from 0 -- ### S Y S T E M t a b l e s ###
and rr.rdb$relation_type = 0 -- exclude: views, GTTs, external tables
and rr.rdb$relation_name not starting with 'MON$'
AND (RR.RDB$RELATION_NAME = rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') or rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') is null)
)
,b as (
select
tab_name,
idx_name,
fld_pos,
fld_name,
fld_src,
fld_base_type,
fld_len,
cset,
coll,
dr1,
dr2,
dr2d,
fld_cnt,
trim( replace( fld_name, '$','_') )||' '||trim(fld_base_type)
||iif( fld_base_type in ('char','varchar', 'numeric'),
'(' || fld_len || ')' || iif( fld_base_type='numeric', '', ' '||trim(coalesce(' character set '||cset, ''))||' '||trim(coalesce(' collate '||coll, '')))
,''
) fld_full
from a
)
,c as (
select
tab_name,
idx_name,
fld_pos,
fld_name,
fld_src,
fld_base_type,
fld_len,
cset,
coll,
dr1,
dr2,
dr2d,
fld_cnt,
fld_full,
(select list(distinct fld_full) from b x where x.tab_name = b.tab_name) fld_list
from b
)
select *
from c
order by tab_name, idx_name, dr1
as cursor c
do begin
if ( c.dr1 = 1 ) then
begin
vulnerable_expr = 'recreate table ' || trim(replace(c.tab_name,'$','_')) || '(' || c.fld_list;
v_fks = '';
end
if ( c.dr2 = 1 ) then begin
v_fk1 = '';
v_mf = '';
end
if ( c.dr2 = 1 ) then
v_fk1 = v_fk1 || ' ,constraint fk_'
|| lower(trim(replace(c.idx_name,'$','_')))
|| ' foreign key(';
v_fk1 = v_fk1 || iif( c.dr2 = 1, '', ', ') || trim( replace( c.fld_name, '$', '_' ) );
v_mf = v_mf || iif( c.dr2 = 1, '', ', ') || trim( c.fld_name );
if ( c.dr2d = 1 ) then
begin
v_fk1 = v_fk1 || ')' || ' references ' || trim(lower(c.tab_name)) || '(' || v_mf || ')';
v_fks = v_fks || v_fk1;
end
if ( c.dr1 = c.fld_cnt ) then
begin
vulnerable_expr = vulnerable_expr || v_fks || ');';
rel_name = c.tab_name;
insert into vulnerable_on_sys_tables( sys_table, vulnerable_type, vulnerable_expr)
values( :rel_name, 'R', :vulnerable_expr);
end
end
end
^
-- #################################################################
-- [ 2 ] attempts to change SYSTEM tables with DML or DDL statements
-- #################################################################
create or alter procedure sp_gen_expr_for_direct_change as
begin
for
------------------
with recursive
c0 as(
select
r.rdb$relation_name rel_name
,rf.rdb$field_position fld_pos
,rf.rdb$field_name fld_name
,case f.rdb$field_type
when 7 then 'smallint'
when 8 then 'integer'
when 10 then 'float'
when 14 then 'char' --(' || cast(cast(f.rdb$field_length/iif(ce.rdb$character_set_name=upper('utf8'),4,1) as int) as varchar(5)) || ')'
when 16 then -- dialect 3 only
case coalesce(f.rdb$field_sub_type,0) -- null found for rdb$generators.rdb$initial_value AND rdb$triggers.rdb$trigger_type
when 0 then 'bigint'
when 1 then 'numeric' --(15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
when 2 then 'decimal' --(15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
else 'unknown'
end
when 12 then 'date'
when 13 then 'time'
when 27 then -- dialect 1 only
case f.rdb$field_scale
when 0 then 'double precision'
else 'numeric' -- (15,' || cast(-f.rdb$field_scale as varchar(6)) || ')'
end
when 35 then iif(m.dia=1, 'date', 'timestamp')
when 37 then 'varchar' -- (' || cast(cast(f.rdb$field_length/iif(ce.rdb$character_set_name=upper('utf8'),4,1) as int) as varchar(5)) || ')'
when 261 then 'blob' -- sub_type ' || f.rdb$field_sub_type || ' segment size ' || f.rdb$segment_length
else 'unknown'
end as fld_base_type
,iif( coalesce(rf.rdb$null_flag,0) = 0, 1, 0) fld_nullable
,count(*)over(partition by r.rdb$relation_name) fld_count
,sum(iif(rf.rdb$field_name = upper('rdb$system_flag'),1,0))over(partition by r.rdb$relation_name) has_sys_flag
from (select m.mon$sql_dialect as dia from mon$database m) m
join rdb$relations r on 1=1
join rdb$relation_fields rf on r.rdb$relation_name = rf.rdb$relation_name
join rdb$fields f on rf.rdb$field_source = f.rdb$field_name
left join rdb$collations co on f.rdb$character_set_id=co.rdb$character_set_id and f.rdb$collation_id=co.rdb$collation_id
left join rdb$character_sets ce on co.rdb$character_set_id=ce.rdb$character_set_id
where
coalesce(r.rdb$system_flag,0) is distinct from 0 --------------- ### S Y S T E M t a b l e s ###
and r.rdb$relation_type = 0 -- exclude: views, GTTs, external tables
and r.rdb$relation_name not starting with 'MON$'
and f.rdb$computed_source is null ------------------------------ ### exclude COMPUTED BY fields! ###
AND (R.RDB$RELATION_NAME = rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') or rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') is null)
order by rel_name,fld_pos
)
,c1 as (
select
rel_name
,has_sys_flag
,fld_pos
,fld_name
,fld_base_type
,fld_nullable
,fld_count
-- these are values which we'll try to write in insert or update statements
-- if corresponding fields are NOT null:
,decode( fld_base_type,
'smallint', '32767',
'integer', '2147483647',
'bigint', '9223372036854775807',
'float', '0e0',
'numeric', '0.00',
'decimal', '0.00',
'double precision', '0e0',
'date', 'current_date',
'time', 'current_time',
'timestamp', 'current_timestamp',
'char', '''C''',
'varchar', '''V''',
'blob', '''test_for_blob'''
) ins_default
from c0
)
-- select * from c1
,c2 as (
select
rel_name
,fld_pos
,fld_name
,fld_base_type
,fld_nullable
,fld_count
,ins_default
,cast( 'select ' || trim(fld_name)
|| iif( c1.fld_pos+1 = c1.fld_count, ' from '||trim(rel_name)||' rows 1 with lock;', '') as varchar(1024)
) as lok_stt
,cast( 'insert into '
|| trim(rel_name)
|| '('
|| trim(fld_name)
|| iif( c1.fld_pos+1 = c1.fld_count, ')', '') as varchar(1024)
) as ins_stt
,cast( 'values('
|| trim(iif(fld_nullable=1, 'null', ins_default))
|| iif( c1.fld_pos+1 = c1.fld_count, ') returning rdb$db_key;', '') as varchar(1024)
) as ins_val
,cast( 'delete from ' || trim(rel_name) || ' t '
|| trim(iif(has_sys_flag=1, 'where coalesce(rdb$system_flag,0)=0', ''))
|| ' rows 1'
|| ' returning t.rdb$db_key'
|| iif( c1.fld_pos+1 = c1.fld_count, ';', '')
as varchar(1024)
) del_stt
,cast( 'alter table '|| trim(rel_name) || ' add rdb$my_field char(31)' as varchar(1024)) add_fld
,cast( 'alter table '|| trim(rel_name) || ' alter '||trim(fld_name)|| ' DROP NOT null' as varchar(1024)) set_nul
,cast( 'alter table '|| trim(rel_name) || ' add constraint '||left(trim(fld_name)||'_dummy',31) ||' check ('||trim(fld_name) ||' is not distinct from '||trim(fld_name)||')' as varchar(1024)) set_chk
,cast( 'alter table '|| trim(rel_name) || ' alter '||trim(fld_name)|| ' set default '||ins_default as varchar(1024)) set_def
,cast( 'create descending index '||trim(replace(rel_name,'$','_'))||' on '||trim(rel_name)||'('||trim(fld_name)||')' as varchar(1024)) idx_tab
,cast( 'alter table '|| trim(rel_name) || ' drop '||trim(fld_name) as varchar(1024)) kil_fld
,cast( 'drop table '|| trim(rel_name) as varchar(1024)) kil_tab
,iif( c1.fld_pos+1 = c1.fld_count, 1, 0) cmd_end
from c1
where fld_pos = 0
UNION ALL
select
c1.rel_name
,c1.fld_pos
,c1.fld_name
,c1.fld_base_type
,c1.fld_nullable
,c1.fld_count
,c1.ins_default
,c2.lok_stt || ', ' || trim(c1.fld_name) || iif( c1.fld_pos+1 = c1.fld_count, ' from '||trim(c2.rel_name)||' rows 1 with lock;', '')
,c2.ins_stt || ', ' || trim(c1.fld_name) || iif( c1.fld_pos+1 = c1.fld_count, ')', '')
,trim(c2.ins_val) || ', '
|| trim(iif(c1.fld_nullable=1, 'null', c1.ins_default))
|| iif( c1.fld_pos+1 = c1.fld_count, ') returning rdb$db_key;', '')
,trim(c2.del_stt) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.add_fld) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.set_nul) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.set_chk) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.set_def) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.idx_tab) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.kil_fld) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,trim(c2.kil_tab) || iif( c1.fld_pos+1 = c1.fld_count, ';', '')
,iif( c1.fld_pos+1 = c1.fld_count, 1, 0) cmd_end
from c2 join c1 on c2.rel_name = c1.rel_name and c1.fld_pos = c2.fld_pos + 1
)
--select * from c2
,c3 as (
select
c2.rel_name --, c2.ins_stt || ' ' ||c2.ins_val insert_statement, c2.upd_stt update_statement, c2.del_stt delete_statement
,n.op
,decode(
n.op
,'I' ,c2.ins_stt || ' ' ||c2.ins_val
,'L' ,c2.lok_stt
--,'U' ,c2.upd_stt
,'D' ,c2.del_stt
,'A' ,c2.add_fld
,'N' ,c2.set_nul
,'C' ,c2.set_chk
,'F' ,c2.set_def
,'X' ,c2.idx_tab
,'K' ,c2.kil_fld
,'Z' ,c2.kil_tab
) vulnerable_expr
,n.ord_pos
,n.ret_dbkey
from c2
cross join(
select 'I' as op, 10 as ord_pos, 1 as ret_dbkey from rdb$database -- DML, insert
union all select 'L', 20, 0 from rdb$database -- DML, select WITH LOCK
union all select 'D', 40, 1 from rdb$database -- DML, delete
union all select 'A', 50, 0 from rdb$database -- DDL, add column
union all select 'N', 60, 0 from rdb$database -- DDL, alter column set NULL flag
union all select 'C', 65, 0 from rdb$database -- DDL, alter column add new constraint on it
union all select 'F', 70, 0 from rdb$database -- DDL, alter column set DEFAULT value
-- ### commented 11-04-2018: no need anymore because now one may to create index on system tables:
-- ### union all select 'X', 75, 0 from rdb$database -- DDL, CREATE INDEX
union all select 'K', 80, 0 from rdb$database -- DDL, drop column
union all select 'Z', 90, 0 from rdb$database -- DDL, drop RDB$-table
) n
where cmd_end=1
order by rel_name, n.ord_pos
)
,r1 as(
-- Add statements which will try to drop constrains, starting from FK:
select rc.rdb$relation_name rel_name, rc.rdb$constraint_name cnt_name, rc.rdb$constraint_type cnt_type
from rdb$relation_constraints rc
join rdb$relations rr on rc.rdb$relation_name = rr.rdb$relation_name
where
rc.rdb$relation_name not starting with 'MON$'
and coalesce(rr.rdb$system_flag,0) is distinct from 0 --------------- ### S Y S T E M t a b l e s ###
AND (RC.RDB$RELATION_NAME = rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') or rdb$get_context('USER_SESSION','DEBUG_RDB_TABLE') is null)
order by decode(rc.rdb$constraint_type, 'FOREIGN KEY', 0, 1)
)
,r2 as (
select
trim(r1.rel_name) as rel_name
,'R' as op
,'alter table '||trim(r1.rel_name)||' drop constraint '||trim(r1.cnt_name)||';' as vulnerable_expr
,67 as ord_pos
,0 as ret_dbkey
from r1
)
--select * from r2
,cu as (
select
rel_name
,has_sys_flag
,fld_pos
,fld_name
,fld_base_type
,fld_nullable
,fld_count
,ins_default
,cast( 'update ' || trim(rel_name) || ' t '
|| ' set t.'||trim(fld_name)||' = '
|| trim(iif(n.i=0, ins_default, 'null'))||' '
|| trim(iif(has_sys_flag=1, 'where coalesce(rdb$system_flag,0)='||m.k, ''))
|| ' rows 1'
|| ' returning t.rdb$db_key'
|| ';'
as varchar(1024)
) upd_stt
,trim(iif(has_sys_flag=1, 'where coalesce(rdb$system_flag,0)='||m.k, '')) dml_where
,30 as ord_pos
,1 as ret_dbkey
from c1
join (select 0 i from rdb$database union all select 1 from rdb$database) n
on n.i=0 or c1.fld_nullable=1 and n.i=1
join (select 0 k from rdb$database union all select 1 from rdb$database) m
on m.k=0 or c1.has_sys_flag=1 and m.k=1
-- core-4772: fields like rdb$procedure_source have to be updated AFTER all previous (except RDB$SYSTEM_FLAG - this is the LATEST):
-- select 1 from rdb$database where 'RDB$TRIGGER_SOURCE' similar to upper( ascii_char(37) || '#_SOURCE' ) escape '#'; ==> must return 1
order by rel_name, iif( trim( upper(fld_name) ) = upper('RDB$SYSTEM_FLAG'), 3, iif( trim( upper(fld_name) ) similar to upper( ascii_char(37) || '#_SOURCE') escape '#', 2, 1) )
)
-- select * from cu
select rel_name, ord_pos, ret_dbkey, 'U' as vulnerable_type, dml_where, upd_stt as vulnerable_expr
from cu
UNION ALL
select rel_name, ord_pos, ret_dbkey, op, '' as dml_where, vulnerable_expr
from c3
UNION ALL
select rel_name, ord_pos, ret_dbkey, op, '' as dml_where, vulnerable_expr
from r2 -- alter table drop FK
UNION ALL
select 'RDB$GENERATORS', 99, 0, 'G', '', 'alter sequence '||trim(g.rdb$generator_name)||' restart with -1;'
from rdb$generators g
where g.rdb$system_flag = 1
----------
as cursor c
do
insert into vulnerable_on_sys_tables( sys_table, ord_pos, ret_dbkey, vulnerable_type, vulnerable_expr, dml_where)
values( c.rel_name, c.ord_pos, c.ret_dbkey, c.vulnerable_type, c.vulnerable_expr, c.dml_where);
end
^
set term ;^
commit;
-- ###################################################################################
-- E X E C U T E S T A T E M E N T S:
-- A T T E M P T S O F D I R E C T W R I T E T O S Y S T E M T A B L E S
-- ###################################################################################
set term ^;
create or alter procedure sp_run_vulnerable_expressions(
a_usr type of column sec$users.sec$user_name
,a_pwd varchar(20)
,a_role varchar(20)
) as
declare v_dbname type of column mon$database.mon$database_name;
declare v_actual_role varchar(20);
declare v_dbkey char(8) character set octets;
begin
update vulnerable_on_sys_tables
set
vulnerable_gdscode = null
,vulnerable_sqlcode = null
,vulnerable_sqlstate = null
,sys_dbkey = null
,actual_role = null
;
v_dbname = 'localhost:' || rdb$get_context('SYSTEM','DB_NAME');
execute statement 'select current_role from rdb$database'
on external (v_dbname)
as user upper(a_usr) password (a_pwd) role (a_role)
into v_actual_role;
for
select sys_table, vulnerable_expr, dml_where, vulnerable_type, ret_dbkey
from vulnerable_on_sys_tables
order by sys_table, ord_pos, id
as cursor c
do begin
v_dbkey = null;
if ( c.ret_dbkey = 1) then
execute statement c.vulnerable_expr -- this statement ALWAYS should FAIL!
on external (v_dbname)
as user (a_usr) password (a_pwd) role (a_role)
into v_dbkey;
else
execute statement c.vulnerable_expr -- this statement ALWAYS should FAIL!
on external (v_dbname)
as user (a_usr) password (a_pwd) role (a_role);
-- this statement must NOT occur at all. If this record would be added then it means
-- that system table can be DIRECTLY modified by user!
update vulnerable_on_sys_tables set
vulnerable_gdscode = -1
,vulnerable_sqlcode = -1
,vulnerable_sqlstate = 'PASS!'
,sys_dbkey = :v_dbkey
,actual_role = :v_actual_role
where current of c;
when any do
begin
update vulnerable_on_sys_tables
set
vulnerable_gdscode = gdscode
,vulnerable_sqlcode = sqlcode
,vulnerable_sqlstate = sqlstate
,sys_dbkey = null
,actual_role = :v_actual_role
where current of c;
end
end
end
^
set term ;^
commit;
execute procedure sp_gen_expr_for_creating_fkeys;
execute procedure sp_gen_expr_for_direct_change;
-- result: table 'vulnerable_on_sys_tables ' will be filled up by ~1560 rows.
commit;
-- ||||||||||||||||||||||||||||
-- ###################################||| FB 4.0+, SS and SC |||##############################
-- ||||||||||||||||||||||||||||
-- If we check SS or SC and ExtConnPoolLifeTime > 0 (config parameter FB 4.0+) then current
-- DB (bugs.core_NNNN.fdb) will be 'captured' by firebird.exe process and fbt_run utility
-- will not able to drop this database at the final point of test.
-- Moreover, DB file will be hold until all activity in firebird.exe completed and AFTER this
-- we have to wait for <ExtConnPoolLifeTime> seconds after it (discussion and small test see
-- in the letter to hvlad and dimitr 13.10.2019 11:10).
-- This means that one need to kill all connections to prevent from exception on cleanup phase:
-- SQLCODE: -901 / lock time-out on wait transaction / object <this_test_DB> is in use
-- #############################################################################################
delete from mon$attachments where mon$attachment_id != current_connection;
commit;