пятница, 2 ноября 2012 г.

*nix su comand for Oracle


Интересную вещь надыбал.
В оракле, оказывается, есть механизм который позволяет получить результат аналогичный su - <username> под рутом, то есть переключиться на другого юзера БД без смены пароля в рамках одной сесси.

Как это реализуется?
Недокументированной процедурой
sys.kupp$proc.change_user(' ');
Эта процедура входит в состав АПИ dbms_datapump, где она проворачивает один из механизмов REMAP_SCHEMA. То есть работает в 10-ой и 11-ой версии.

Как работает?
По умолчанию такая возможность закрыта

SQL> begin
  2  sys.kupp$proc.change_user('SYSMAN');
  3  end;
  4   /
begin
*
ERROR at line 1:
ORA-31625: Schema SYSMAN is needed to import this object, but is unaccessible
ORA-06512: at "SYS.KUPP$PROC", line 45
ORA-06512: at "SYS.KUPP$PROC", line 930
ORA-06512: at line 2

Раскрывается это  через вызов функции
SQL> select sys.kupp$proc.disable_multiprocess from dual; 

DISABLE_MULTIPROCESS
--------------------
                   1

Так же сие работает и в PL/SQL

SQL> declare
  2  outp varchar2(200);
  3  begin
  4  outp := sys.kupp$proc.disable_multiprocess();
  5  sys.kupp$proc.change_user('SCOTT');
  6  select count(*) into outp from user_sys_privs;
  7  dbms_output.put_line('Scott privs: '||outp);
  8  sys.kupp$proc.change_user('DBSNMP');
  9  select count(*) into outp from user_sys_privs;
10  dbms_output.put_line('Dbsnmp privs: '||outp);
11  sys.kupp$proc.change_user('SYS');
12  select count(*) into outp from user_sys_privs;
13  dbms_output.put_line('SYS privs: '||outp);
14  end;
15  /
Scott privs: 2
Dbsnmp privs: 4
SYS privs: 200

PL/SQL procedure successfully completed.

SQL> show user
USER is "SYS"
SQL> select user from dual;

USER
------------------------------
SYS

Но не забывайте «вернуться» обратно, если вдруг чего. ;)

SQL> declare
  2  outp varchar2(200);
  3  begin
  4  outp := sys.kupp$proc.disable_multiprocess();
  5  sys.kupp$proc.change_user('SCOTT');
  6  select count(*) into outp from user_sys_privs;
  7  dbms_output.put_line('Scott privs: '||outp);
  8  sys.kupp$proc.change_user('DBSNMP');
  9  select count(*) into outp from user_sys_privs;
10  dbms_output.put_line('Dbsnmp privs: '||outp);
11  --sys.kupp$proc.change_user('SYS');
12  --select count(*) into outp from user_sys_privs;
13  --dbms_output.put_line('SYS privs: '||outp);
14  end;
15  /
Scott privs: 2
Dbsnmp privs: 4

PL/SQL procedure successfully completed.

SQL> show user
USER is "SYS"
SQL> select user from dual;

USER
------------------------------
DBSNMP

SQL> exec sys.kupp$proc.change_user('SYS');
BEGIN sys.kupp$proc.change_user('SYS'); END;

      *
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00201: identifier 'SYS.KUPP$PROC' must be declared
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored

У кого такая возможность есть по умолчанию ?
Определяется наличием привилегии BECOME USER, так что нужно быть осторожным ;)

SQL> select privilege, grantee from dba_sys_privs where privilege  like 'BECOM%';

PRIVILEGE                                GRANTEE
---------------------------------------- ------------------------------
BECOME USER                              SYS
BECOME USER                              DBA
BECOME USER                              IMP_FULL_DATABASE


Update:
в 11.2.0.4 данная возможность не открывается с помощью

  sys.kupp$proc.disable_multiprocess();

Хотя внутренность кода на первый взгляд не отличается, но данный хак работает только в 11.2.0.3 и ниже

четверг, 1 ноября 2012 г.

Increase SCN manualy


Один из способов, но самый простой и рабочий.
SCN состоит из двух частей - 0x0000.00000000
0000 - SCN WRAP
00000000 - SCN BASE

Этот метод увеличивает часть  «SCN BASE».

Тесткейс
Для начала необходима установка параметра
SQL> alter system set "_allow_error_simulation"=TRUE scope=spfile;

System altered.

Без него этот метод не работает.
Далее необходим эвент  adjust_scn

SQL> alter system set events 'immediate trace name adjust_scn level ';

System altered.

Где n – это  1,2,3….и т д.
Каждый  уровень увеличивает SCN на 1073741824 единицы, НО отталкиваясь от текущего SCN БД.
То есть.

SQL> select to_char(dbms_flashback.get_system_change_number) from dual;

TO_CHAR(DBMS_FLASHBACK.GET_SYSTEM_CHANGE
----------------------------------------
3221225473

SQL> alter system set events 'immediate trace name adjust_scn level 1'; --попытаемся выдать меньше, чем текущий

System altered.

В алерте будет вот такое
Wed Oct 31 17:37:50 EET 2012
Errors in file /oracle/admin/prime/udump/prime_ora_3995.trc:
ORA-00600: internal error code, arguments: [2256], [0], [1073741824], [0], [3221225705], [], [], []
Wed Oct 31 17:37:52 EET 2012
OS Pid: 3995 executed alter system set events 'immediate trace name adjust_scn level 1'

У этой 600-ой  аргументы
[1073741824] – то, что мы пытаемся вставить в SCN BASE
[3221225705] – то, что там уже  есть, а учитывая что первый и третий аргумент – это SCN WRAP, то в данном случае это есть текучий SCN БД.

Соответвено, у SCN остается прежним

SQL> select to_char(dbms_flashback.get_system_change_number) from dual;

TO_CHAR(DBMS_FLASHBACK.GET_SYSTEM_CHANGE
----------------------------------------
3221225756

А если возьмем больше, то получим больше ;)

SQL> alter system set events 'immediate trace name adjust_scn level 8';

System altered.

SQL> select to_char(dbms_flashback.get_system_change_number) from dual;

TO_CHAR(DBMS_FLASHBACK.GET_SYSTEM_CHANGE
----------------------------------------
8589934594