oracle sql insufficient privilieges in procedure but not in worksheet - oracle

I have two schemas in oracle DB, say A and B.
Schema A has a table tabA and Schema B as a table tabB.
Now in Schema B, this works:
select * from A.tabA
But, I created a package in schema B that has a procedure FOO. The procedure essentially does the same thing..i.e.
PROCEDURE FOO IS
BEGIN
INSERT INTO B.tabB (select * from A.tabA)
END FOO
This doesn't compile and gives ORA-01031 Insufficient privileges error.
I had to go to schema A and explicitly grant SELECT privilege to schema B to make the procedure compile successfully.
Now A.tabA is not the only table and new tables will be added in the future. In the procedure FOO, I fetch the table name dynamically. So, It could be A.tabC tomorrow, A.tabD the day after. I don't want to manually assign the privileges in every new table created in schema A.
Why privileges are specifically required in procedure while not required in worksheet?
How to assign privileges automatically to new tables?

A definer's rights stored procedure can't access permissions granted to a role only those granted directly to the owner. I would guess that B has been given select access on a.tabA via a role, which would work if you ran an ad-hoc SQL statement (assuming the role was enabled for the session) but not for a definer's rights stored procedure. Most likely, whatever administrative process manages to grant the select privilege to the role would need to be modified to grant the privilege directly to b instead of or in addition to the role. Alternately, you could make the procedure an invoker's rights stored procedure (add authid current_user to the declaration before the as). But that would require that any user that wants to execute the procedure would need to have access to a.tabA not just the procedure owner.
If you do want an invoker's rights stored procedure
PROCEDURE FOO
authid current_user
IS
BEGIN
INSERT INTO B.tabB (select * from A.tabA);
END FOO;

Related

Insufficient INHERIT PRIVILEGES for a stored procedure ORACLE

I am having a stored procedure in user META. This SP truncates a table in user STAGE.
CREATE PROCEDURE META.sp_truncate_tablex
AUTHID CURRENT_USER
as
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE STAGE.Tablex';
END;
When I run the SP I get RA-06598: insufficient INHERIT PRIVILEGES.
I have tried to make both users to DBA.
This means if I run SELECT grantee
WHERE granted_role = 'DBA'
ORDER BY grantee;
it shows me that META dn STAGE are DBA.
I have also tried: GRANT INHERIT PRIVILEGES ON USER STAGE TO META; But I still get the same error in Oracle 18.
Your problem is this clause:
AUTHID CURRENT_USER
This means the user who executes the procedure does so with their own privileges. So a user who is not META cannot run the procedure unless they have the DROP ANY TABLE privilege, in which case they don't need to run the procedure as they can truncate the table anyway.
The solution is to declare the procedure with
AUTHID DEFINER
Now the procedure executes with the privileges of its owner - META - who presumably owns the target table. Except they don't. The table is actually owned by STAGE. So STAGE needs to own the procedure as well.
As it happens, DEFINER rights are the default so we don't need to explicitly define them, except for clarity.
CREATE PROCEDURE STAGE.sp_truncate_tablex
AS
BEGIN
EXECUTE IMMEDIATE 'TRUNCATE TABLE STAGE.Tablex';
END;

Create stored procedure in Oracle with Roles privileges

I have a problem with creating a stored procedure.
I have permissions to the table XYZ through Roles, so when I do a SELECT to the table XYZ I don't have problem, but when I want to create a stored procedure (inside my code I call to the table XYZ table) Oracle tell me:
Table or view doesn't exist.
When another user who have directly permissions for table XYZ create the stored procedure with the same code don't have problems.
So I hope you could help me. I think I need to assign another kind of permission to the Role that I use.
From the documentation:
How Roles Work in PL/SQL Blocks
Role behavior in a PL/SQL block is determined by the type of block and
by definer's rights or invoker's rights.
Roles Used in Named Blocks with Definer's Rights
All roles are disabled in any named PL/SQL block that executes with
definer's rights.
Roles Used in Named Blocks with Invoker's Rights and Anonymous PL/SQL
Blocks
Named PL/SQL blocks that execute with invoker's rights and anonymous
PL/SQL blocks are executed based on privileges granted through enabled
roles.
Roles Used in Named Blocks with Definer's Rights
All roles are disabled in any named PL/SQL block that executes with
definer's rights.
Examples of named PL/SQL blocks are stored procedures, functions, and
triggers.
Roles are not used for privilege checking and you cannot set roles
within a definer's rights procedure.
This is from the 19c documentation, but it has been true pretty much forever.
You only have 2 solutions:
either your Oracle user is granted the direct privilege on the table (ie without a role)
or you create a stored procedure with invoker rights.
Here is an example of invoker right procedure.
Use AUTHID CURRENT_USER clause and access table SCHEMA.XYZ with dynamic SQL because invoker rights are not enabled at PL/SQL compilation time but only at PL/SQL run time.
create or replace procedure myproc
authid current_user
as
l number;
begin
execute immediate 'select c from schema.xyz where rownum = 1' into l;
dbms_output.put_line('l= ' || l);
end;
/

Oracle: my DML for Index recreation puzzle

Problem anamnesis:
In order to automate index recreation for a PVJOURNAL table in oracle I wrote a procedure in a package.
The table PVJOURNAL locates in PROVIEW schema. My SPACEMAN user has enough grants in that schema. Here below is a DDL of the package:
CREATE OR REPLACE
PACKAGE spaceman.tmp_itcm4052 is
-- This proc rebuilds ALL indexes of a specific.
PROCEDURE idx_rebuild;
END;
/
CREATE OR REPLACE
PACKAGE BODY spaceman.tmp_itcm4052 is
-- ===========================================================================
PROCEDURE idx_rebuild as
-- This proc rebuilds ALL indexes of a specific table. Run by Job
v_sql_str VARCHAR2(200);
begin
FOR rec in (
select owner ||'.'|| index_name as IDX_NAME,
tablespace_name as TblSpace
from sys.all_indexes
where upper(index_type) = 'NORMAL'
and upper(table_owner) = 'PROVIEW'
and upper(table_name) in ('PVJOURNAL')
)
LOOP
v_sql_str := 'ALTER INDEX '||rec.IDX_NAME||' rebuild tablespace '
||rec.TblSpace||' online';
-- ALTER INDEX ... SHRINK SPACE COMPACT
-- ALTER INDEX ... DEALLOCATE UNUSED SHRINK SPACE COMPACT
dbms_output.put_line('v_sql_str = '||v_sql_str);
execute immediate v_sql_str;
commit;
END LOOP;
end idx_rebuild;
END tmp_ITCM4052;
/
Problem itself:
The problem is that a call of the procedure under my SPACEMAN user
begin
spaceman.tmp_itcm4052.idx_rebuild;
end;
ends up with error
ORA-01031: insufficient privileges - full view of the error
But the direct run of the line, produced by the procedure, saved into v_sql_str variable and visualized by this piece of the procedure:
dbms_output.put_line('v_sql_str = '||v_sql_str);, done under the same SPACEMAN user works like a magic. proof that direct alter does work
Questions:
What wrong have I done to the gods of pl/sql? Why the call to the procedure fails whilst the same command, execurted directly - is not?
UPD: Not only GRANT INDEX ON PROVIEW.PVJOURNAL TO SPACEMAN; didn't help. Moreover, for whatewer reason not yet kown to me, GRANT ALTER ANY INDEX to SPACEMAN; didn't help either.
Had doublechecked it with
SELECT PRIVILEGE
FROM sys.dba_sys_privs
WHERE upper(grantee) = 'SPACEMAN'
UNION
SELECT PRIVILEGE
FROM dba_role_privs rp JOIN role_sys_privs rsp ON (rp.granted_role = rsp.role)
WHERE upper(rp.grantee) = 'SPACEMAN'
ORDER BY 1;
the privilege ALTER ANY INDEX (as well as ALTER ANY INDEXTYPE ) is in the list.
UPD 1: as it turned out - the ALTER ANY INDEX privilege is not sufficient in this case. What did helped me is that link, kindly provided by #Wernfried Domscheit. REspect, man!
The procedure created as
CREATE OR REPLACE
PACKAGE spaceman.tmp_itcm4052 authid CURRENT_USER is
works like a spell.
Inside a PL/SQL block you have only privileges which are granted to the user directly. Privileges which are granted by ROLE (e.g. DBA) do not apply inside a PL/SQL block (except role PUBLIC).
Grant CREATE ANY INDEX directly to the user, then it should work.
The behavior described above is the default, it is called "definer's rights unit". You can change it by adding AUTHID CURRENT_USER to your procedure/package. For more information see Invoker's Rights and Definer's Rights (AUTHID Property)
N.b. COMMIT is not required after a DDL statement. Oracle performs an implicit commit.
Different grants are used when you invoke direct SQL and when it is used in the procedure.
Privileges granted through a role (such as DBA) are not available to
definer's rights stored procedures which is the default.
Only privileges that are granted directly to the user are available in a
definer's rights stored procedure.
You must grant the ALTER ANY INDEX privileges directly to your user.
Cheers!!

Strange ORA-942 when using DBMS_CRYPTO but table exists

This is very strange, and not easy to explain, so please bear with me.
Oracle 12.2.0.1 on Linux x86_64.
We have a user called BATCH who has minimal privileges.
CREATE USER batch IDENTIFIED BY batch
DEFAULT TABLESPACE users
QUOTA UNLIMITED ON users;
GRANT CREATE SESSION TO batch;
GRANT EXECUTE ON DBMS_CRYPTO TO batch;
The is a PLSQL package in a schema called ATLED which is :
CREATE OR REPLACE PACKAGE ALTED.the_pkh AUTHID current_user AS
PROCEDURE crttab;
END;
/
CREATE OR REPLACE PACKAGE BODY ALTED.the_pkh AS
PROCEDURE crttab IS
BEGIN
EXECUTE IMMEDIATE 'CREATE TABLE atled.the_tab AS SELECT id, DBMS_CRYPTO.HASH(cc,2) AS cc FROM ARCHIVE.table_b';
END crttab;
END;
/
We are using Code Based Access Control (CBAC - 12c feature) to restrict/control/allow certain canned actions to an otherwise toothless user, so we create a wrapper procedure, grant that a high priv role, and grant execute on that to the batch user:
CREATE OR REPLACE PROCEDURE ALTED.wrapper_crttab AS
PROCEDURE p1 IS
CURSOR c1 is SELECT * FROM SESSION_PRIVS;
BEGIN
FOR r1 IN c1 LOOP
DBMS_OUTPUT.PUT_LINE( r1.privilege );
END LOOP;
END;
BEGIN
p1;
ALTED.the_pkh.crttab;
END;
/
GRANT IMP_FULL_DATABASE TO ALTED;
GRANT IMP_FULL_DATABASE ALTED.wrapper_crttab;
GRANT EXECUTE ON ALTED.wrapper_crttab TO batch;
Now let's run it:
CONN batch/batch
SET SERVEROUTPUT ON
EXEC ALTED.wrapper_crttab;
This causes the error:
Error at line 1:
ORA-00942: table or view does not exist
The tables referenced do exist.
The call to the p1 proc confirms that all the privileges bundled with IMP_FULL_DATABASE are present, including CREATE ANY TABLE, DROP ANY TABLE, EXECUTE ANY PROCEDURE.
If I do this:
GRANT CREATE ANY TABLE TO batch;
GRANT SELECT ANY TABLE TO batch;
CONN batch/batch
EXEC EXECUTE IMMEDIATE 'CREATE TABLE atled.the_tab AS SELECT id, DBMS_CRYPTO.HASH(cc,2) AS cc FROM ARCHIVE.table_b;
This works.
If I change the CREATE TABLE stmt to remove the DBMS_CRYPTO call, it works as well.
The actual package/proc that is called creates a number of tables fine when run as above, but fails on the case when DBMS_CRYPTO is called in any CREATE TABLE stmt.
If I grant the batch user the CREATE ANY TABLE, SELECT ANY TABLE and EXECUTE ANY PROCEDURE privs directly and run the CREATE TABLE command as batch directly then that works too.
So this is not (I think) a straight ORA-942 error, but something related to a chain of privileges to DBMS_CRYPTO, and only when executed in a package stored procedure, but what exactly I do not know.
UPDATE 1
If I create a wrapper for DBMS_CRYPTO.HASH as follows:
CREATE OR REPLACE FUNCTION batch.crypto_hash ( pcc IN CLOB ) RETURN VARCHAR2 IS
BEGIN
RETURN DBMS_CRYPTO.HASH(pcc,2);
END;
/
Then replace the DBMS_CRYPTO.HASH(cc,2) in the CREATE TABLE stmt with batch.crypto_hash(cc) then it works!!!
So, DEFINITELY not a issue with grants on teh tables being referenced, but more likely something internal with the way DBMS_CRYPTO works. Perhaps it reads a look up table somewhere. I tried GRANT EXECUTE ON UTL_I18N to batch as well before this but that didn't work.
So I have a workaround, but woudl still like to know why this happens.
You're doing this:
... FROM ARCHIVE.table_b
User, who is supposed to select from that table, has to have SELECT privileges on it. It can be granted
via role
directly
If you granted the privilege via role, it works - but not in named PL/SQL procedures. It will work in anonymous PL/SQL, but not in procedures, function, packages, so - check that and, possibly, grant SELECT on table_b directly to that user.

What are invoker's rights with respect to Oracle PL/SQL functions?

The first of the result_cache usage restrictions (--link) is - not defined in a module that has invoker's rights or in an anonymous block.
What does "invoker's rights" mean ? Does it mean the user_procedures.AUTHID shouldnt be "DEFINER" for this function ?
Invoker and Definer Rights When Executing Oracle PL/SQL Code
The rule you are interpreting restricts usage of certain kinds of PL/SQL code that is stored in the database cache. The types of PL/SQL code included are segments that are within:
ANONYMOUS BLOCKS (i.e., these are code snippets run through SQL Plus or some other input without actually being a part of a persistent object in the database, such as a stored procedure, function or package)
DEFINED WITH INVOKER's RIGHTS: (See Below for Explanation)
An INVOKER means that whatever USER account that executes a PL/SQL Object, the procedure runs with the privileges of that USER account instead of the customary privileges which are those of the DEFINER (owner of the object).
Tom Kyte has a good discussion thread on the topic of definer vs. invoker rights on his Ask-Tom site.
The most notable comment from the above reference is this example block of code:
In the above, if user1 created:
create or replace procedure proc1
authid current_user
as
begin
for x in ( select * from my_table ) loop
null;
end loop;
end;
/
In the following line: authid current_user, this is the comment for setting an INVOKER's rights. The table my_table in the reference has multiple possibilities:
When PROC1 is executed where the DEFINER and the INVOKER are the same, (i.e., OWNER or USER1) this table will be: USER1.MY_TABLE
When PROC1 is executed by an INVOKER or user other than the OWNER of the procedure PROC1, (i.e., USER2) this table can be one of these possible targets:
A PUBLIC owned table named MY_TABLE
A Private or Publicly owned SYNONYM for a table typed object called MY_TABLE
A local TABLE owned by USER2 (i.e., USER2.MY_TABLE) of the same name, MY_TABLE.
If the above cases are true, then there is a great deal of ambiguity surrounding the reference involved with the procedure USER1.PROC1. The actual, physical table being used are different based on the context of the invoking user identity and the accessibility/existence of aliased pointers (SYNONYMS).
The result is that the usefulness of a cached value for a procedure with INVOKER's rights enabled is questionable given the variable nature of its internal references.

Resources