mirror of
https://github.com/FirebirdSQL/firebird-qa.git
synced 2025-01-22 13:33:07 +01:00
684 lines
28 KiB
MySQL
684 lines
28 KiB
MySQL
|
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;
|