Comment devenir un autre utilisateur sous Oracle? - How to become another user under Oracle?
Introduction
Comment un user peut-il interagir avec les objets d'un autre user? Est-ce facile? Impossible? Les problématiques de droits et de rôles sont complexes avec Oracle mais il existe différentes techniques permettant à un user U1 d'accéder aux objets d'un user U2 et c'est ce que nous allons voir.
Points d'attention
Trop pour les énumérer :-)
Base de tests
N'importe quelle base Oracle.
Exemples
Dans la suite de cet article, j'utiliserais les conventions suivantes :
- U1 : user zztest, avec le droit CREATE SESSION au minimum.
- Au début de chaque test, on créé une table zz01 appelée ci-après T1 ou un dblink.
- U2 : user zztest02, avec le droit CREATE SESSION au minimum voir DBA.
- Entre chaque test on supprime les users pour éviter que des rôles ou droits ne traînent et ne faussent les tests suivants.
Le test a réaliser pour vérifier si on interagit avec un autre schéma est simple : U1 doit supprimer ou interroger un objet du schéma U2.
============================================================================================
Solution 1 : user avec le rôle DBA ou bien user SYS
============================================================================================
Dans ce test, U1 a le rôle DBA ou bien il est SYS : il peut quasiment tout faire, y compris dropper des objets du schéma U2 (sauf les dblinks mais c'est une autre histoire).
SQL> show user
USER est "SYS"
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
SQL> connect / as sysdba
Le test est OK : le user SYS peut intéragir avec les objets du schéma zztest02 par défaut; ici, il drop une table.
SQL> drop table zztest02.zz01;
Table supprimee.
SQL> drop user zztest02 cascade;
============================================================================================
Solution 2 : user qui a reçu des droits sur les objets d'un autre user
============================================================================================
Cette fois U1 n'a pas le rôle DBA mais il a les droits sur les objets de U2, donnés justement par U2.
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant resource, create session to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
SQL> connect / as sysdba
SQL> show user
USER est "SYS"
SQL> connect zztest
SQL> select * from zztest02.zz01;
select * from zztest02.zz01
*
ERREUR a la ligne 1 :
ORA-00942: Table ou vue inexistante
SQL> connect zztest02
SQL> grant select on zz01 to zztest;
Cette fois c'est OK, U1 accède bien à la table de U2.
SQL> connect zztest
SQL> select * from zztest02.zz01;
aucune ligne selectionnee
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 3 : user qui connait le password d'un autre user
============================================================================================
U1 cette fois connaît le mot de passe de U2 : soit on le lui a dit, soit il a été récupéré dans un fichier excel (ne riez pas, c'est courant), soit deviné... Quoi qu'il en soit, U1 devient à un instant t le user U2.
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
Maintenant le user U1 se connecte puis il va se connecter comme U2 pour accéder à ses objets .
SQL> connect zztest
SQL> connect zztest02
U1 saisit le mot de passe de U2 et drop une de ses tables.
SQL> drop table zz01;
Table supprimee.
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 4 : avoir le droit ANY
============================================================================================
Dans la longue liste des privilèges système, il en est une catégorie particulière, celle qui comprends le mot ANY. Elle permet à un utilisateur d'agir sur un autre schéma sans connaître son password... puissant, non?
SQL> select name from SYSTEM_PRIVILEGE_MAP where name like '%ANY%' order by 1;
NAME
------------
...
ALTER ANY INDEX
ALTER ANY PROCEDURE
ALTER ANY ROLE
...
CREATE ANY TABLE
CREATE ANY TRIGGER
...
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> grant create any table to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
Et maintenant, le user U1 va créer une table dans le schéma du user U2; cette table sera en revanche propriété du user U2 et non pas de son créateur.
SQL> connect zztest
SQL> create table zztest02.test_any (id date);
SQL> connect SYS@ORCL as sysdba
SQL> select owner from dba_tables where table_name = 'TEST_ANY';
OWNER
---------------
ZZTEST02
Et on voit même que le créateur de la table ne peut pas faire de SELECT dessus; vous notez qu'on a pas le message "Table inexistante", ce qui prouve que avec le droit CREATE ANY, le user connaît la table qu'il a créé mais il lui faut le droit SELECT dessus pour l'interroger.
SQL> connect zztest
SQL> select * from zztest02.test_any;
select * from zztest02.test_any
*
ERROR at line 1:
ORA-01031: insufficient privileges
============================================================================================
Solution 5 : changer de schéma courant avec CURRENT_SCHEMA
============================================================================================
Avec le paramètre CURRENT_SCHEMA, un user peut se connecter à un autre schéma mais, attention, pas à un autre compte. Il reste lui même mais Oracle va chercher les objets non préfixés par un nom de schéma dans le schéma identifié par CURRENT_SCHEMA.
SQL> show user
USER est "SYS" :
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> grant SELECT ANY DICTIONARY to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
SQL> connect zztest;
SQL> show user
USER est "ZZTEST"
SQL> ALTER SESSION SET CURRENT_SCHEMA = "ZZTEST02";
Session modifiee.
Voilà, on reste le user U1 mais on accède directement au schéma U2 sans avoir à préfixer les objets par le nom du propriétaire.
SQL> select username, schemaname from v$session where sid in (select sid from v$mystat);
USERNAME SCHEMANAME
------------------------------ ------------------------------
ZZTEST ZZTEST02
SQL> select * from zz01;
select * from zz01
*
ERREUR a la ligne 1 :
ORA-00942: Table ou vue inexistante
OK, il faut ajouter pour le premier user le droit SELECT sur la table du user U2 :-)
SQL> connect zztest02
SQL> grant select on zz01 to zztest;
SQL> connect zztest
SQL> ALTER SESSION SET CURRENT_SCHEMA = "ZZTEST02";
SQL> select username, schemaname from v$session where sid in (select sid from v$mystat);
USERNAME SCHEMANAME
------------------------------ ------------------------------
ZZTEST ZZTEST02
Et voilà, en tant que U1 j'ai accès à un objet du schéma U2 sans avoir à préfixer celui-ci par le nom du propriétaire.
SQL> select * from zz01;
aucune ligne selectionnee
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 6 : lancer une procédure créée dans un autre schéma
============================================================================================
Plus complexe, comment supprimer le dblink d'un autre schéma? Même SYS ne le peut pas car il est impossible de préfixer le nom d'un dblink par le nom d'un schéma, comme le dit la doc Oracle et aucun user ne peut supprimer le dblink d'un autre schéma.
https://docs.oracle.com/database/121/SQLRF/statements_8011.htm#SQLRF01514
"Restriction on Dropping Database Links
You cannot drop a database link in another user's schema, and you cannot qualify dblink with the name of a schema, because periods are permitted in names of database links. Therefore, Oracle Database interprets the entire name, such as ralph.linktosales, as the name of a database link in your schema rather than as a database link named linktosales in the schema ralph."
La solution est que U1 crée une procédure dans le schéma U2 et exécute celle-ci : le drop dblink est alors possible puisque la procédure s'exécutera dans le schéma U2!
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> CREATE DATABASE LINK DBLINK01 USING '10.142.111.888:1521/DLAWWW';
SQL> connect sys as sysdba
SQL> show user
USER est "SYS"
SQL> select OWNER, DB_LINK from dba_db_links where db_link like '%01';
OWNER DB_LINK
---------------------------
ZZTEST02 DBLINK01
SYS lui même ne peut pas dropper un dblink d'un autre user car s'il le préfixe par le nom du propriétaire, Oracle considère que le point (.) fait partie du nom de l'objet et le cherche dans le schéma courant, donc celui de SYS... où il n'existe pas!
SQL> drop database link zztest02.DBLINK01;
drop database link zztest02.DBLINK01
*
ERREUR a la ligne 1 :
ORA-02024: lien de base de donnees introuvable
Plus vicieux : si on change le schéma courant du user SYS avec comme objectif de ne pas préfixer le dblink du nom du user, on arrive à toucher celui-ci MAIS on a un autre message d'erreur, disant "Privilèges insuffisants" : personne, pas même SYS, ne peut supprimer le db link d'un autre utilisateur.
SQL> show user
USER is "SYS"
SQL> alter session set current_schema = "ZZTEST02";
Session altered.
SQL> drop database link DBLINK01;
drop database link DBLINK01
*
ERROR at line 1:
ORA-01031: insufficient privileges
On crée une procédure dans le schéma zztest02. Comme on appelle cette procédure depuis un autre schéma, on est donc virtuellement, lors de l'exécution de cette procédure, l'autre user!
CREATE OR REPLACE PROCEDURE ZZTEST02.PROC_DROP_DBLINK IS
BEGIN
execute immediate 'drop database link dblink01';
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line('PB : SQLCODE ' || to_char(SQLCODE) || ': ' || SQLERRM);
END PROC_DROP_DBLINK;
/
Attention, le message "Procedure PL/SQL terminee avec succes." ne signifie pas qu'il n'y a pas eu d'erreur mais juste que la procédure s'est exécutée.
SQL> execute ZZTEST02.PROC_DROP_DBLINK;
Procedure PL/SQL terminee avec succes.
C'est bon!! Plus de dblink dans le schéma U2 :-) On a bien exécuté du code comme étant ce user U2 mais sans connaître son password.
SQL> select OWNER, DB_LINK from dba_db_links where db_link like '%01';
aucune ligne selectionnee
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 7 : package non documenté DBMS_SYS_SQL
============================================================================================
Avec le package PL/SQL de nom DBMS_SYS_SQL, un user peut exécuter du code en étant un autre user, avec tous ses droits. ATTENTION, ce package est non documenté par Oracle, ne l'utilisez pas en production, on ne connaît pas les effets secondaires :-)
Ce package permet de faire du SQL dynamique, comme DBMS_SQL, mais en ajoutant une subtilité qui est de dire quel user va réellement exécuter le code. Vous avez compris? Un user Stagiaire peut devenir SYS avec ce package! Attention, comme pré-requis il faut avoir le droit EXECUTE dessus et SELECT sur DBA_USERS.
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> grant select on dba_users to zztest;
SQL> grant execute on dbms_sys_sql to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> create table zz01 (id number);
SQL> connect zztest
SQL> select * from zztest02.zz01;
select * from zztest02.zz01
*
ERREUR a la ligne 1 :
ORA-00942: Table ou vue inexistante
SQL> connect sys as sysdba
SQL> show user
USER est "SYS"
SQL> desc zztest02.zz01;
Nom NULL ? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
SQL> connect zztest
SQL> desc zztest02.zz01
ERROR:
ORA-04043: objet zztest02.zz01 inexistant
SQL> SET SERVEROUTPUT ON
declare
v_n_uid number;
v_v_sqltext varchar2(100) := 'ALTER TABLE zztest02.zz01 ADD TESTDATE DATE';
v_i_myint integer;
begin
SELECT USER_ID INTO V_N_UID FROM DBA_USERS WHERE USERNAME = 'SYS';
v_i_myint:=sys.dbms_sys_sql.open_cursor()
sys.dbms_sys_sql.parse_as_user(v_i_myint,v_v_sqltext,dbms_sql.native,v_n_uid);
sys.dbms_sys_sql.close_cursor(v_i_myint);
exception
when others then
dbms_output.put_line('failed to execute the specified statement for user: '|| to_char(v_n_uid));
dbms_output.put_line(substr(sqlerrm, 1, 100));
end ;
/
Procedure PL/SQL terminee avec succes.
Pour voir si c'est OK, il faut se connecter comme zztest02 et faire un desc de la table.
Bingo, le test a réussi : U1 a bien modifié un objet appartenant à U2 sans en avoir les droits!
SQL> connect zztest02
SQL> desc zz01
Nom NULL ? Type
----------------------------------------- -------- ----------------------------
ID NUMBER
TESTDATE DATE
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 8 : les proxy users
============================================================================================
La fonctionnalité Proxy User de Oracle permet de se connecter comme un autre user sans connaître son password! Regardons cela de plus près.
SQL> show user
USER est "SYS"
SQL> create user zztest02 identified by TotoTiti31380000;
SQL> grant dba to zztest02;
SQL> create user zztest identified by YukioYukio31380000;
SQL> grant create session to zztest;
La commande magique est ici : le user zztest pourra maintenant se connecter comme zztest02.
SQL> alter user zztest02 grant connect through zztest ;
SQL> connect zztest02
SQL> CREATE DATABASE LINK DBLINK01 USING '10.142.111.888:1521/DLAWWW';
SQL> select OWNER, DB_LINK from dba_db_links where db_link like '%01';
OWNER DB_LINK
----------------------
ZZTEST02 DBLINK01
On se connecte au compte zztest02, sans connaître son password, à partir du compte zztest.
Attention à la syntaxe : compte1[compte2]/password compte 1
SQL> connect zztest[zztest02]/YukioYukio31380000;
SQL> show user
USER est "ZZTEST02"
SQL> drop database link dblink01;
SQL> select OWNER, DB_LINK from dba_db_links where db_link like '%01';
aucune ligne selectionnee
SQL> connect / as sysdba
SQL> alter user zztest02 revoke connect through zztest ;
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 9 : ALTER USER IDENTIFIED BY VALUES - changer le mot de passe temporairement d'un user
============================================================================================
Un user se connecte comme un autre user en changeant « temporairement » son mot de passe car il ne connaît pas son password.
L’ordre SQL est ALTER USER user IDENTIFIED BY VALUES "champ spare4 ou champ password" ;
Je teste sur une autre base, ne soyez pas surpris :-)
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> CREATE DATABASE LINK DBLINK01 USING '127.0.0.1/ORCL';
SQL> connect SYS/oracle@ORCL as sysdba
SQL> show user
USER est "SYS"
SQL> desc user$
Name Null? Type
----------------------------------------- ---------
USER# NOT NULL NUMBER
NAME NOT NULL VARCHAR2(128)
TYPE# NOT NULL NUMBER
PASSWORD VARCHAR2(4000)
DATATS# NOT NULL NUMBER
TEMPTS# NOT NULL NUMBER
CTIME NOT NULL DATE
PTIME DATE
EXPTIME DATE
LTIME DATE
RESOURCE$ NOT NULL NUMBER
AUDIT$ VARCHAR2(38)
DEFROLE NOT NULL NUMBER
DEFGRP# NUMBER
DEFGRP_SEQ# NUMBER
ASTATUS NOT NULL NUMBER
LCOUNT NOT NULL NUMBER
DEFSCHCLASS VARCHAR2(128)
EXT_USERNAME VARCHAR2(4000)
SPARE1 NUMBER
SPARE2 NUMBER
SPARE3 NUMBER
SPARE4 VARCHAR2(1000)
SPARE5 VARCHAR2(1000)
SPARE6 DATE
SPARE7 VARCHAR2(4000)
SPARE8 VARCHAR2(4000)
SPARE9 NUMBER
SPARE10 NUMBER
SPARE11 TIMESTAMP(6)
Avant de changer le mot de passe du user, il faut avoir bien pris soin de récupérer son mot de passe crypté avant.
SQL> SELECT nvl(password, 'RIEN'), spare4 FROM user$ WHERE name = 'ZZTEST02';
NVL(PASSWORD,'RIEN') SPARE4
------------------------------------------
RIEN S:B35FA9749EDA9A6C3CF3A198D2B8BD0F1DCB10101CEEFC48801700F8AFA0;T:B72307284B19A51A5E4BA7596DC3BDBCC99CF89D12FD23E662343EAA26A93B226DD7E60062890EE61E89D1032176311859FB0954CD781C1AC2536ECDBC25E12874F5EC6345D3E69C843F08FB63852026
On saisit un nouveau mot de passe pour U2 et on se contacte à son compte pour dropper le dblink.
SQL> alter user ZZTEST02 identified by toto;
SQL> connect zztest02/toto@orcl;
SQL> drop database link dblink01;
SQL> connect SYS/oracle@ORCL as sysdba
Et maintenant on remet l'ancien password du user en utilisant la valeur cryptée.
SQL> alter user zztest02 identified by values 'S:B35FA9749EDA9A6C3CF3A198D2B8BD0F1DCB10101CEEFC48801700F8AFA0;T:B72307284B19A51A5E4BA7596DC3BDBCC99CF89D12FD23E662343EAA26A93B226DD7E60062890EE61E89D1032176311859FB0954CD781C1AC2536ECDBC25E12874F5EC6345D3E69C843F08FB63852026';
User altered.
C'est bon, l'ancien mot de passe est actif.
SQL> connect zztest02/toto@ORCL;
ERROR:
ORA-01017: invalid username/password; logon denied
Warning: You are no longer connected to ORACLE.
SQL> connect zztest02/YukioYukio31380000@ORCL;
Connected.
SQL> show user
USER is "ZZTEST02"
SQL> select OWNER, DB_LINK from dba_db_links where db_link like '%01';
no rows selected
SQL> drop user zztest;
SQL> drop user zztest02 cascade;
============================================================================================
Solution 10 : fonction système KUPP$PROC
============================================================================================
La fonction KUPP$PROC permet de changer de user; cette astuce fonctionnait en 11 mais visiblement pas en 12.1.
https://vigilance.fr/vulnerabilite/Oracle-DB-elevation-de-privileges-via-BECOME-USER-7339
Les rôles DBA et IMP_FULL_DATABASE possèdent le privilège "BECOME USER" qui permet de changer d'identité. Ce changement d'identité se fait via sys.kupp$proc.change_user().
SQL> show user
USER est "SYS"
SQL> create user zztest identified by TotoTiti31380000 ;
SQL> grant create session to zztest;
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> connect zztest02
SQL> CREATE DATABASE LINK DBLINK01 USING '127.0.0.1/ORCL';
SQL> connect SYS/oracle@ORCL as sysdba
SQL> show user
USER est "SYS"
SQL> exec sys.kupp$proc.change_user('ZZTEST02');
BEGIN sys.kupp$proc.change_user('ZZTEST02'); END;
*
ERROR at line 1:
ORA-31625: Schema ZZTEST02 is needed to import this object, but is unaccessible
ORA-06512: at "SYS.KUPP$PROC", line 45
ORA-06512: at "SYS.KUPP$PROC", line 1006
ORA-06512: at line 1
Si message d'erreur, exécuter la requete ci-dessous et recommencer.
SQL> select sys.kupp$proc.disable_multiprocess from dual;
DISABLE_MULTIPROCESS
--------------------
1
Hum, visiblement cela a été corrigé en 12.1.
SQL> exec sys.kupp$proc.change_user('ZZTEST02');
BEGIN sys.kupp$proc.change_user('ZZTEST02'); END;
*
ERROR at line 1:
ORA-31625: Schema ZZTEST02 is needed to import this object, but is unaccessible
ORA-06512: at "SYS.KUPP$PROC", line 45
ORA-06512: at "SYS.KUPP$PROC", line 1006
ORA-06512: at line 1
On parle d'une correction ici http://www.red-database-security.com/wp/best_of_oracle_security_2011.pdf mais c'est encore KO.
SQL> show user
USER is "SYS"
SQL> create or replace PROCEDURE CHANGE_USER_INT (USERNAME IN VARCHAR2, MP_ENABLED IN BINARY_INTEGER) IS
EXTERNAL NAME "kuppchus" LANGUAGE C LIBRARY KUPP_PROC_LIB WITH CONTEXT
PARAMETERS ( CONTEXT, USERNAME STRING, USERNAME INDICATOR SB2, MP_ENABLED SB4 );
/
Procedure created.
SQL> exec CHANGE_USER_INT('ZZTEST02',0);
BEGIN CHANGE_USER_INT('ZZTEST02',0); END;
*
ERROR at line 1:
ORA-31625: Schema ZZTEST02 is needed to import this object, but is unaccessible
ORA-06512: at "SYS.CHANGE_USER_INT", line 1
ORA-06512: at line 1
OK, je laisse tomber, je n'arrive pas sur une 12.1 à effectuer cette manip.
============================================================================================
Solution 11 : Privilège "BECOME USER"
============================================================================================
Les rôles DBA et IMP_FULL_DATABASE possèdent le privilège "BECOME USER" qui permet de changer d'identité.
En effet, quand le user U1 veut faire un export/import d'un autre schéma ou de la base entière, il doit accéder aux schémas autres que le sien.
Mais je ne pourrai pas tester un changement de user via ce privilège car impossible de trouver un test simple et clair.
============================================================================================
Solution 12 : Le compte PUBLIC
============================================================================================
On arrive au bout de notre voyage, ce sera avec le user très spécial PUBLIC. Il faut savoir que pour Oracle ce user est en réalité un groupe d'utilisateurs et même un rôle. Et comme chaque user appartient à ce groupe, un user peut accéder naturellement aux objets de ce user; c'est l'objet de cet article.
PUBLIC est aussi un rôle caché; il est filtré dans la définition de DBA_ROLES. Attention, pour avoir la définition d'un objet du schéma SYS, il faut se connecter au CDB$ROOT si la base 12 est en mode CDB. Vous noterez qu'un rôle est stocké dans la table des users; de là à dire qu'un rôle est un user spécial...
SQL> create user zztest identified by TotoTiti31380000;
SQL> grant dba to zztest;
SQL> connect SYS/oracle@ORCL as sysdba
SQL> create user zztest02 identified by YukioYukio31380000;
SQL> grant dba to zztest02;
SQL> show user
USER is "SYS"
SQL> alter session set container=CDB$ROOT;
Session altered.
Voyons voir un peu ce fameux user PUBLIC. Ah oui, il est juste après SYS, avec le code 1.
SQL> select user#, name from user$ where user# < 11;
USER# NAME
---------- --
0 SYS
1 PUBLIC
2 CONNECT
3 RESOURCE
4 DBA
5 PDB_DBA
6 AUDIT_ADMIN
7 AUDIT_VIEWER
8 AUDSYS
9 SYSTEM
10 SELECT_CATALOG_ROLE
11 rows selected.
SQL> select dbms_metadata.get_ddl('VIEW', 'DBA_ROLES') from dual;
DBMS_METADATA.GET_DDL('VIEW','DBA_ROLES')
--------------------------------------------------------------------------------
CREATE OR REPLACE FORCE NONEDITIONABLE VIEW "SYS"."DBA_ROLES" ("ROLE", "ROLE_I
D", "PASSWORD_REQUIRED", "AUTHENTICATION_TYPE", "COMMON", "ORACLE_MAINTAINED", "
INHERITED", "IMPLICIT") AS
select name, user#,
decode(password, null,
decode(spare4, null, 'NO',
decode(REGEXP_INSTR(spare4, '[ST]:'), 0, 'NO',
'YES')),
'EXTERNAL', 'EXTERNAL',
'GLOBAL', 'GLOBAL',
'YES'),
decode(password, null,
decode(spare4, null, 'NONE',
decode(REGEXP_INSTR(spare4, '[ST]:'), 0, 'NONE',
'PASSWORD')),
'EXTERNAL', 'EXTERNAL',
'GLOBAL', 'GLOBAL',
'APPLICATION', 'APPLICATION',
'PASSWORD'),
decode(bitand(spare1, 4224), 0, 'NO', 'YES'),
decode(bitand(spare1, 256), 256, 'Y', 'N'),
decode(bitand(spare1, 4224),
128, decode(SYS_CONTEXT('USERENV', 'CON_ID'),
1, 'NO', 'YES'),
4224, decode(SYS_CONTEXT('USERENV', 'IS_APPLICATION_PDB'),
'YES', 'YES', 'NO'),
'NO'),
decode(bitand(spare1, 32768), 32768, 'YES', 'NO')
from user$
where type# = 0 and name not in ('PUBLIC', '_NEXT_USER')
Je crée un synonyme publique, qui, comme son nom l'indique, va dans le schéma PUBLIC.
SQL> connect zztest;
SQL> create table zz01(id date);
SQL> create public synonym PUB_SYN_ZZ01 for zz01;
SQL> select owner from dba_objects where object_name = 'PUB_SYN_ZZ01';
OWNER
------------------------
PUBLIC
Ici, Oracle regarde dans le schéma courant, pas dans PUBLIC puisque l'objet zz01 existe dans le schéma du user connecté.
SQL> select * from zz01;
no rows selected
Les users U1 et U2 ont bien accès au synonyme du schéma PUBLIC, sans faire quoi que ce soit de spécial. Attention à bien encadrer le schéma PUBLIC par des guillemets sinon, mesage d'erreur!
SQL> select * from "PUBLIC".PUB_SYN_ZZ01;
no rows selected
Nous voyons ici que le user U2 accède de deux façons différentes au schéma PUBLIC : soit en préfixant le nom d'un objet par le nom PUBLIC soit en ne le préfixant pas et Oracle va chercher à deux endroits différents, dans le schéma courant et, si l'objet n'existe pas, dans le schéma PUBLIC puisque chaque user y a accès.
SQL> connect zztest02
SQL> select * from "PUBLIC".PUB_SYN_ZZ01;
no rows selected
SQL> select * from PUB_SYN_ZZ01;
no rows selected