Oracle Virtual Private Database (VPD): trigger privileges / function generates invalid predicate - oracle

Two questons during creation of Virtual Private Database.
Which privileges are needed to run a database logon trigger? The users need special privileges?
Error message: problem with the function, but the function works well.
The codes from the user and table creation:
-- as SYS:
-- in the pdb:
alter session set container = orclpdb;
create user orders identified by orders;
create user vpd_admin identified by vpd_admin;
create user hanna identified by hanna;
create user smith identified by smith;
grant create session to orders, vpd_admin, hanna, smith;
grant create table, unlimited tablespace to orders, vpd_admin;
grant execute on dbms_rls to vpd_admin;
grant create procedure to vpd_admin;
-- in SQL Developer, you can build connections now
-- service name = orclpdb
-- in ORDERS schema:
create table orderinfo2
(ordid number,
product varchar2(10),
custid number);
create table customers
(custid number,
name varchar2(10));
insert into orderinfo2 values (6001, 'coctail', 101);
insert into orderinfo2 values (6002, 'wine', 101);
insert into orderinfo2 values (6003, 'coctail', 102);
insert into customers values (101, 'hanna');
insert into customers values (102, 'smith');
grant select on customers to vpd_admin, hanna, smith;
grant select on orderinfo2 to vpd_admin, hanna, smith;
-- in SYS:
alter session set container = orclpdb;
grant create any trigger to vpd_admin;
grant administer database trigger to vpd_admin;
Package01: custid into kod variable
-- in vpd_admin schema:
create or replace package
vpd_admin.order_sec_ident
is procedure kod_variable;
end;
/
 
create or replace package body
vpd_admin.order_sec_ident
is procedure
kod_variable
is
kod number;
begin
select custid into kod
from orders.customers where
trim(upper(name)) =
sys_context('USERENV', 'SESSION_USER');
dbms_session.set_context
('ORDER_NS', 'KOD_ARG', to_char(kod));
exception
when no_data_found then
dbms_session.set_context
('ORDER_NS', 'KOD_ARG', '-1');
end;
end order_sec_ident;
/
grant execute on order_sec_ident to public;
logon trigger:
create or replace trigger logon_trigger
after logon
on database
begin vpd_admin.order_sec_ident.kod_variable;
end;
/
package2: condition into policy
create or replace package vpd_admin.orders_cond as
function cond
(schema_v varchar2,
table_v varchar2)
return varchar2;
pragma restrict_references (cond, wnds);
end;
/
create or replace package body vpd_admin.orders_cond as
function cond
(schema_v varchar2,
table_v varchar2)
return varchar2
is
wherevalue varchar2(2000);
begin
if
trim(upper(user)) <> schema_v
and trim(upper(user)) <> 'SYS'
and trim(upper(user)) <>'SYSTEM' then
wherevalue := 'trim(upper(name)) =
sys_context (''ORDER_NS'', ''KOD_ARG'')';
else wherevalue := '1=1';
end if;
return wherevalue;
end cond;
end;
/
dbms_rls.add_policy
begin
dbms_rls.add_policy
('orders',
'orderinfo2',
'ord_sec_pol2',
'vpd_admin',
'orders_cond.cond',
'SELECT');
end;
/
problem1: user cannot logon due to the logon_trigger
question1: the users have not enough privileges to run the trigger, what privileges need to be granted?
An error was encountered performing the requested operation:
ORA-04088: error during execution of trigger 'VPD_ADMIN.LOGON_TRIGGER'
ORA-00604: error occurred at recursive SQL level 1
ORA-01031: insufficient privileges
ORA-06512: at "SYS.DBMS_SESSION", line 130
ORA-06512: at "VPD_ADMIN.ORDER_SEC_IDENT", line 12
ORA-06512: at line 1
04088. 00000 - "error during execution of trigger '%s.%s'"
*Cause: A runtime error occurred during execution of a trigger.
*Action: Check the triggers which were involved in the operation.
Vendor code 4088
-- (as sys granted dba to smith so I can continue testing)
question2-1: how can I review the trace file?
question2-2: what is the problem with the function?
-- in smith schema:
select * from orders.orderinfo2;
ORA-28113: policy predicate has error
28113. 00000 - "policy predicate has error"
*Cause: Policy function generates invalid predicate.
*Action: Review the trace file for detailed error information.
running the fucntion script separetely, it works:
-- in vpd_admin:
create or replace
function cond
(schema_v varchar2,
table_v varchar2)
return varchar2
is
wherevalue varchar2(2000);
begin
if
trim(upper(user)) <> schema_v
and trim(upper(user)) <> 'SYS'
and trim(upper(user)) <>'SYSTEM' then
wherevalue := 'trim(upper(name)) =
sys_context (''ORDER_NS'', ''KOD_ARG'')';
else wherevalue := '1=1';
end if;
return wherevalue;
end cond;
/
declare
x varchar2(20) := 'aa';
y varchar2(20) := 'bb';
begin
dbms_output.put_line(cond(x, y));
end;
/
-- result: trim(upper(name)) =
sys_context ('ORDER_NS', 'KOD_ARG')

In response to:
question1: the users have not enough privileges to run the trigger,
what privileges need to be granted?
The problem here is that the trigger executes but throws an exception. An exception in login stops the logon and can have widespread impact on the database, which is of course undesirable. Because of this, logon triggers are often created to be exception-free or carefully control any possible exceptions.
In this example, vpd_admin.order_sec_ident has some handling for no data found, but can throw other exceptions and the handler itself could throw an exception. Some implementations make use of EXCEPTION WHEN OTHERS in database-wide logon triggers to ensure no exceptions. If the exception in the trigger is resolved here, users will be able to log in again.
The priv problem you are seeing may be from the use of DBMS_SESSION.SET_CONTEXT in the procedure. Ensuring vpd_admin has access and runs the context setup in its auth can address the priv problem.
In response to:
question2-1: how can I review the trace file?
Alerts, trace file conditions, locations, etc. are configurable. Documentation has more info
In response to:
question2-2: what is the problem with the function?
Table orderinfo2 does not have a name column. The name in the clause 'trim(upper(name)) = sys_context ('ORDER_NS', 'KOD_ARG')' yields invalid sql when it is executed.
A policy on orderinfo2 must be valid for columns ordid, product, or custid (or valid and not include any columns, as with the 1=1 in your example).
This exception will be corrected by changing the 'trim(upper(name)) = sys_context ('ORDER_NS', 'KOD_ARG')' condition so it would be valid in a statement like SELECT * FROM ORDERINFO2 WHERE <<predicate>>;

Related

"No data found" error during execute the procedure in oracle trigger

i have a trigger in different and want execute procedure for different schema to extract the data.
executing procedure with parameter in trigger is not working.
create or replace TRIGGER TRIGER_LEAD_INSERT
AFTER INSERT ON AT_NEO_CM.LEAD_INFORMATION
FOR EACH ROW
DECLARE
--PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
IF :new.LEAD_REFERENCE_NUMBER IS NOT NULL THEN
AT_NEO_CAS_LMS.PKG_LEAD_DATA.USP_INSERT_NEWAPP(:NEW.LEAD_REFERENCE_NUMBER,:NEW.ID );
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO LEADDATA VALUES( :NEW.ID, :NEW.LEAD_REFERENCE_NUMBER,2322, 'NO DATA FOUND');
END TRIGER_LEAD_INSERT;
Using a another table in procedure with same primary key which passed in procedure as parameter.
To call a procedure from another schema, you just need to set the right grants:
CREATE USER u1 IDENTIFIED BY u1 QUOTA 1M ON USERS;
CREATE USER u2 IDENTIFIED BY u2 QUOTA 1M ON USERS;
GRANT CONNECT, RESOURCE TO u1;
GRANT CONNECT, RESOURCE TO u2;
User u1 has a procedure p1 and grants it to user u2:
CREATE PROCEDURE p1(p NUMBER) AS BEGIN NULL; END p1;
GRANT EXECUTE ON p1 TO u2;
User u2 can now execute this procedure:
CONNECT u2/u2;
EXEC u1.p1(1);
or use it in a trigger:
CREATE TABLE t2 (id NUMBER);
CREATE OR REPLACE TRIGGER tr2 AFTER INSERT ON t2
FOR EACH ROW
BEGIN
IF :new.id IS NOT NULL THEN
u1.p1(:new.id);
END IF;
END tr2;
/

Oracle How to grant CREATE ANY DIRECTORY with the restriction that all directories must be created inside a given directory?

I want to grant the CREATE ANY DIRECTORY permission to a user, with the following restriction: all directories created by this user must be inside of /foo/bar, and any attempt to create a directory outside of this should fail with a permission error. How may I do this on Oracle 11G or 12C?
That depends, if you want to restrict which OS directories Oracle can access from utl_file commands, you can set the utl_file_dir parameter. Unfortunately, this parameter is system wide, so you won't be able to grant/revoke for a specific user using this parameter. Also keep in mind that if you make changes to this parameter, those changes won't go into effect until the Oracle database is restarted:
alter system set utl_file_dir = '/foo/bar' scope=spfile;
shutdown immediate;
startup open;
Consult the 12.1 Oracle Docs for more information regarding utl_file_dir.
That said, if you really want to restrict who can create Oracle Directories to specific OS directories, a procedure would be appropriate for that task since that would allow you to have finer grained control (and limit who has the very powerful create any directory privilege to the owner of the procedure):
sqlplus kjohnston
create or replace procedure mydircreate (p_dir varchar2)
as
ex_custom EXCEPTION;
PRAGMA EXCEPTION_INIT( ex_custom, -20001 );
begin
if lower(p_dir) not like '/foo/bar/%' then
raise_application_error( -20001, 'Not authorized' );
end if;
execute immediate 'create or replace directory mydir as ''' || p_dir || '''';
end mydircreate;
create user testuser identified by <password>;
grant create session to testuser;
grant execute on kjohnston.mydircreate to testuser;
exit;
sqlplus testuser
SQL> exec kjohnston.mydircreate('mydir', '/randomdir');
ORA-20001: Not authorized
SQL> exec kjohnston.mydircreate('mydir', '/foo/bar/baz');
PL/SQL procedure successfully completed.
You can include this restriction in trigger. List of system events and attributes Working with system events
CREATE OR REPLACE TRIGGER trg_before_ddl
BEFORE DDL ON DATABASE
declare
v_sql ORA_NAME_LIST_T;
v_ddl varchar2(4000);
v_cnt BINARY_INTEGER;
is_valid number;
begin
if ora_sysevent in ('CREATE') and ora_dict_obj_type = 'DIRECTORY' then
v_cnt := ora_sql_txt (v_sql);
FOR i IN 1..v_cnt LOOP
v_ddl := v_ddl || RTRIM (v_sql (i), CHR (0));
END LOOP;
v_ddl := regexp_substr(v_ddl,'AS ''(.*)''', 1, 1, 'i', 1 ); -- get path from ddl_statement
-- check valid directory here, path is in v_ddl ;
is_valid := REGEXP_instr(v_ddl,'^/valid_dir/.*$');
if (is_valid = 0) then
raise_application_error(-20000,'Directory is not valid' || v_ddl);
end if;
end if;
END;
/
CREATE DIRECTORY valid_dir AS '/valid_dir/xyz';
CREATE DIRECTORY invalid_dir AS '/invalid_dir/xyz';

oracle logon/logoff- Trigger, what privilegs are nessesary?

I have to protocol some Information concerning logon/logoff to an Oracle database, a short code snipped als follows:
(create table for logs, create Trigger on logon/logoff)
CREATE TABLE WHEREVER.LOG_TABLE (
TIMESTAMP DATE DEFAULT SYSDATE,
WHAT VARCHAR2(32),
TERMINAL VARCHAR2(32)
)
/
CREATE OR REPLACE TRIGGER WHEREVER.TRIGGER_LOGON AFTER LOGON ON DATABASE
DECLARE PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO WHEREVER.LOG_TABLE (
WHAT,
TERMINAL
)
SELECT
'LOGON',
SYS_CONTEXT('USERENV','TERMINAL')
FROM DUAL
;
COMMIT;
END
/
CREATE OR REPLACE TRIGGER WHEREVER.TRIGGER_LOGOFF BEFORE LOGOFF ON DATABASE
DECLARE PRAGMA AUTONOMOUS_TRANSACTION;
BEGIN
INSERT INTO WHEREVER.LOG_TABLE (
WHAT,
TERMINAL
)
SELECT
'LOGOFF',
SYS_CONTEXT('USERENV','TERMINAL')
FROM DUAL
;
COMMIT;
END
/
If I start this script (w/o logon- trigger) as sys as sysdba i get no errors.
But user, who wants to disconnect gets an error
ORA 04045: errr during recompilation/revalidation of Trigger
ORA 01031: insufficient privileges
I assume, that inserting is not allowed to user.
What could be the minimum Privileg situation, that this table/trigger - combination works, even for users, that are inserted later? who should be owner for table and triggers and in which schema I should put these things (WHEREVER)

PLS-00201 - identifier must be declared

I executed a PL/SQL script that created the following table
TABLE_NAME VARCHAR2(30) := 'B2BOWNER.SSC_Page_Map';
I made an insert function for this table using arguments
CREATE OR REPLACE FUNCTION F_SSC_Page_Map_Insert(
p_page_id IN B2BOWNER.SSC_Page_Map.Page_ID_NBR%TYPE,
p_page_type IN B2BOWNER.SSC_Page_Map.Page_Type%TYPE,
p_page_dcpn IN B2BOWNER.SSC_Page_Map.Page_Dcpn%TYPE)
I was notified I had to declare B2BOWNER.SSC_Page_Map prior to it appearing as an argument to my function. Why am I getting this error?
EDIT: Actual error
Warning: compiled but with compilation errors
Errors for FUNCTION F_SSC_PAGE_MAP_INSERT
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/48 PLS-00201: identifier 'SSC_PAGE_MAP.PAGE_ID_NBR' must be declared
0/0 PL/SQL: Compilation unit analysis terminated
EDIT: Complete PL/SQL Function
RETURN INTEGER
IS
TABLE_DOES_NOT_EXIST exception;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942); -- ORA-00942
BEGIN
INSERT INTO
B2BOWNER.SSC_Page_Map VALUES(
p_page_id,
p_page_type,
p_page_dcpn);
RETURN 0;
EXCEPTION
WHEN TABLE_DOES_NOT_EXIST THEN
RETURN -1;
WHEN DUP_VAL_ON_INDEX THEN
RETURN -2;
WHEN INVALID_NUMBER THEN
RETURN -3;
WHEN OTHERS THEN
RETURN -4;
END;
SHOW ERRORS PROCEDURE F_SSC_Page_Map_Insert;
GRANT EXECUTE ON F_SSC_Page_Map_Insert TO B2B_USER_DBROLE;
RETURN INTEGER
EDIT: I change the arguments and received a new error related to the insert command
CREATE OR REPLACE FUNCTION F_SSC_Page_Map_Insert(
p_page_id IN INTEGER,
p_page_type IN VARCHAR2,
p_page_dcpn IN VARCHAR2)
RETURN INTEGER
IS
TABLE_DOES_NOT_EXIST exception;
PRAGMA EXCEPTION_INIT(TABLE_DOES_NOT_EXIST, -942); -- ORA-00942
BEGIN
INSERT INTO
B2BOWNER.SSC_Page_Map VALUES(
p_page_id,
p_page_type,
p_page_dcpn);
The error
Errors for FUNCTION F_SSC_PAGE_MAP_INSERT
LINE/COL ERROR
-------- -----------------------------------------------------------------
17/18 PL/SQL: ORA-00942: table or view does not exist
16/5 PL/SQL: SQL Statement ignored
The tables has been verified within the correct schema and with the correct attribute names and types
EDIT: I executed the following command to check if I have access
DECLARE
count_this INTEGER;
BEGIN
select count(*) into count_this
from all_tables
where owner = 'B2BOWNER'
and table_name = 'SSC_PAGE_MAP';
DBMS_OUTPUT.PUT_LINE(count_this);
END;
The output I received is
1
PL/SQL procedure successfully completed.
I have access to the table.
EDIT:
So I finally conducted an insert into the table via the schema using PL/SQL and it worked fine. It appears I simply do not have authority to create functions but that is an assumption.
EDIT:
Actual table DDL statement
v_create := 'CREATE TABLE ' || TABLE_NAME || ' (
PAGE_ID_NBR NUMERIC(10) NOT NULL Check(Page_ID_NBR > 0),
PAGE_TYPE VARCHAR2(50) NOT NULL,
PAGE_DCPN VARCHAR2(100) NOT NULL,
PRIMARY KEY(Page_ID_NBR, Page_Type))';
EXECUTE IMMEDIATE v_create;
COMMIT WORK;
COMMIT COMMENT 'Create Table';
When creating the TABLE under B2BOWNER, be sure to prefix the PL/SQL function with the Schema name; i.e. B2BOWNER.F_SSC_Page_Map_Insert.
I did not realize this until the DBAs pointed it out. I could have created the table under my root USER/SCHEMA and the PL/SQL function would have worked fine.
The procedure name should be in caps while creating procedure in database.
You may use small letters for your procedure name while calling from Java class like:
String getDBUSERByUserIdSql = "{call getDBUSERByUserId(?,?,?,?)}";
In database the name of procedure should be:
GETDBUSERBYUSERID -- (all letters in caps only)
This serves as one of the solutions for this problem.
you should give permission on your db
grant execute on (packageName or tableName) to user;

Some mistake in calling one procedure from another

Due to a requirement I have to call one stored procedure from another.
The problem seems to be somewhere around the output parameter out_result_size, which I am using. When I test main_func it works fine but when I test synonym_proc it says
synonym_proc is invalid
I have to, ultimately, call synonym_proc from Java using JPA's #NamedNativeQuery
CREATE OR REPLACE PROCEDURE synonym_proc (
result_cursor OUT SYS_REFCURSOR,
in_cp_id IN NUMBER,
in_cp_name IN VARCHAR2 := NULL,
in_country_name IN VARCHAR2 := NULL,
in_industry_name IN VARCHAR2 := NULL,
in_max_result_size IN NUMBER
) AS
out_result_size NUMBER;
BEGIN
result_cursor := someSchema.somePackage.main_func(in_cp_id,
in_cp_name,
in_country_name,
in_industry_name,
in_max_result_size,
out_result_size);
END;
UPDATE: Apologies for not mentioning the changes in the question which I didn't notice earlier. The main_func is a function (not procedure), which returns a cursor and resides inside some package which is in some schema. When I compile I get the following compilation errors:
Error: PLS-00201: identifier 'SOMESCHEMA.SOMEPACKAGE' must be
declared.. statement ignored.
Update 2
SomeSchema definition
CREATE OR REPLACE PACKAGE someSchema."SomePackage"
is
...
function mainFunc
(
in_cp_id in gem.tcp_real_profile_main_approved.cp%type
, in_cp_name in gem.tcp_real_profile_main_approved.name%type
, in_country_name in gem.tcp_real_profile_main_approved.country_name%type
, in_industry_name in gem.tcp_real_profile_main_approved.industry_name%type
, in_max_result_size in number
, out_result_size out number
)
return search_result_type_cursor;
ADDED
type search_result_type_cursor
is ref cursor
return search_type;
And yes the datatypes are correct since I described the function (main_func) and cross verified the datatypes.
Based on the comments, particularly that you can describe and test the procedure in the other schema, it looks like this may be a permission issue. If your privileges on the objects in the other schema are granted via a role then you will be able to execute the package procedure directly, but roles aren't recognised inside named blocks. If this is the issue then you will have to get execute permission on someSchema.somePackage granted directly to the user that is creating the stored procedure.
To demonstrate the issue, I can create a package in my SCOTT schema and grant execute on it to a role, and grant that role to a user - both of which I've created for the test. As SYS:
create role scott_tmp_role;
grant connect to someuser identified by <password>;
grant scott_tmp_role to someuser;
grant create procedure to someuser;
As SCOTT:
create package p42 as
procedure proc;
end p42;
/
Package created.
create package body p42 as
procedure proc is
begin
null;
end proc;
end p42;
/
Package body created.
grant execute on p42 to scott_tmp_role;
Grant succeeded.
As my new SOMEUSER, verify the roles I have:
select * from session_roles;
ROLE
------------------------------
CONNECT
SCOTT_TMP_ROLE
I can execute the procedure in an anonymous block:
begin
scott.p42.proc;
end;
/
PL/SQL procedure successfully completed.
... but not in a named block:
create or replace procedure sp42 as
begin
scott.p42.proc;
end;
/
Warning: Procedure created with compilation errors.
show errors
Errors for PROCEDURE SP42:
LINE/COL ERROR
-------- -----------------------------------------------------------------
3/2 PL/SQL: Statement ignored
3/2 PLS-00201: identifier 'SCOTT.P42' must be declared
If SCOTT grants the permission directly to my new user:
grant execute on p42 to someuser;
... then the named block now works:
create or replace procedure sp42 as
begin
scott.p42.proc;
end;
/
Procedure created.
If you want to see where you might be getting the execute permission from, you can run a query like this, although there may be a hierarchy of roles to pick through:
select grantee, privilege from all_tab_privs
where table_schema = 'SomeSchema'
and table_name = 'SomePackage';
You can't specify the size of parameters for a procedure or function. Try removing the sizes, as well as moving the commit as Vincent suggested.
CREATE OR REPLACE PROCEDURE synonym_proc(result_cursor OUT SYS_REFCURSOR,
in_cp_id IN NUMBER,
in_cp_name IN VARCHAR2,
in_country_name IN VARCHAR2,
in_industry_name IN VARCHAR2,
in_max_result_size IN NUMBER) AS
out_result_size NUMBER;
BEGIN
main_proc(result_cursor,
in_cp_id,
in_cp_name,
in_country_name,
in_industry_name,
in_max_result_size,
out_result_size);
COMMIT;
END;
You should be getting an error like PLS-00103: Encountered the symbol "(" when expecting one of the following: ...
Syntax for Oracle SP is
CREATE OR REPLACE PROCEDURE procedure_name(--parameter list) AS
--Local Variables
BEGIN
--Body
END;
Now you have made a mistake that instead of putting COMMIT before END you have placed it after END. It should be like this
COMMIT;
END;

Resources