Grant statements not running in Oracle - sql

I wrote this script to grant execute on functions on the source DB so that they are accessible from another DB using the DBlink. The scripts runs without issues, but I still cannot access the functions.
DECLARE
FNC_STRNG VARCHAR2(4000);
CURSOR CUR IS
SELECT * FROM USER_OBJECTS
WHERE OBJECT_TYPE = 'FUNCTION';
BEGIN
FOR I IN CUR LOOP
BEGIN
FNC_STRNG := 'GRANT EXECUTE ON schema_name.' || I.OBJECT_NAME || ' TO
DB_LNK';
EXECUTE IMMEDIATE FNC_STRNG;
EXCEPTION
WHEN OTHERS THEN
NULL;
END;
END LOOP;
END;
Once I run this script...
PL/SQL procedure successfully completed.
Then when I try to access the functions using this script:
SELECT schema_name.func_name#db_link(param1, param2) FROM schema_name.table_name#db_link;
And I get this error:
00904. 00000 - "%s: invalid identifier"

Related

how to resolve error while using grant admin option in execute immediate

I am trying to run the below script. My script works fine without ' WITH ADMIN OPTION' in EXECUTE IMMEDIATE. But when using ' WITH ADMIN OPTION' i get below error.
"Error report - ORA-00900: invalid SQL statement ORA-06512: at line 17
00900. 00000 - "invalid SQL statement"".
SET SERVEROUTPUT ON;
DECLARE
v_Model_UserName VARCHAR2(30) := UPPER('&Model_UserName');
v_Cloned_UserName VARCHAR2(30) := UPPER('&Cloned_UserName');
v_dba_role_privs VARCHAR2(3000); -- for dba_role_privs
--- selecting the roles from model user (from dba_role_privs table)
CURSOR c_role_privs (var01 Varchar2 )is
SELECT granted_role from dba_role_privs where grantee = var01;
BEGIN
--- granting the roles from model user to cloned user (from dba_role_privs table)
OPEN c_role_privs (v_Model_UserName);
LOOP
FETCH c_role_privs INTO v_dba_role_privs;
EXIT WHEN c_role_privs%NOTFOUND;
EXECUTE IMMEDIATE 'grant'||v_dba_role_privs||' to '||v_Cloned_UserName||' WITH ADMIN OPTION';
END LOOP;
CLOSE c_role_privs;
END;
/
Try to add a space after grant keyword:
EXECUTE IMMEDIATE 'grant '||v_dba_role_privs||' to '||v_Cloned_UserName||' WITH ADMIN OPTION';

Oracle - Why is EXECUTE IMMEDIATE allowed in stored procedures?

Why is EXECUTE IMMEDIATE allowed in stored procedures, if stored procedures are meant to mitigate SQL injection attacks? The accepted answer to the following question refers to them as a step against such attacks:
What is a stored procedure? https://stackoverflow.com/a/459531/3163495
"Stored procedures also have a security benefit in that you can grant
execute rights to a stored procedure but the user will not need to
have read/write permissions on the underlying tables. This is a good
first step against SQL injection."
...unless the stored procedure is using EXECUTE IMMEDIATE.
This PL/SQL code returns a product's description (second parameter).
CREATE OR REPLACE PROCEDURE prodDescr(vname IN VARCHAR2, vresult OUT VARCHAR2) AS
vsql VARCHAR2(4000);
BEGIN
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
EXECUTE IMMEDIATE vsql INTO vresult;
END;
Malicious user input.
A' AND 1=2 UNION SELECT password FROM members WHERE username='admin
Generated Query.
SELECT description FROM products WHERE name='A' OR 1=2 UNION SELECT password FROM members WHERE username='admin'
When the query is executed, the attacker gets the administrator’s password.
As you can see, although we used a stored procedure, an attacker can still exploit a vulnerability just as easily as if we were an amateur developer concatenating some SELECT statement in PHP without sanitizing input. To me, it seems it can be very misleading to say to developers that stored procedures will help keep your database safe.
Execute Immediate can still be used in a safe way. It all comes down to the logic of the stored proc. The concat is making the code unsafe not the execute immediate.
vsql := 'SELECT description FROM products WHERE name=''' || vname || '''';
Should be using bind variables or a dbms_assert call.
vsql := 'select count(1) from all_objects where owner = :1'
EXECUTE IMMEDIATE vsql into vresult using vname ;
OR
vsql := 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(vname);
EXECUTE IMMEDIATE vsql into vresult ;
In a full example below using both methods. The first has bind(s) and the second is wrappered with DBMS_ASSERT.
SQL>declare
v_in varchar2(2000);
ret varchar2(2000);
begin
v_in := 'KLRICE';
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner = :1' into ret using v_in ;
dbms_output.put_line('First Object Count : ' || ret);
EXECUTE IMMEDIATE 'select count(1) from all_objects where owner ='||DBMS_ASSERT.ENQUOTE_LITERAL(v_in) into ret ;
dbms_output.put_line('Second Object Count : ' || ret);
end
SQL> /
First Object Count : 74
Second Object Count : 74
PL/SQL procedure successfully completed.
SQL>
Stored procedures do not keep your database safe. That has never been true.
No language, framework, or API can keep your database safe.
It is the developer's responsibility to write safe code.
If you use EXECUTE IMMEDIATE in an unsafe way, then you have a vulnerability.
The same is true when you don't use stored procedures — if you write dynamic SQL using any application language, you have the same risk of creating SQL injection vulnerabilities.

Grant all on procedures to user

When i execute the following Statement by substituting object_type to table [OBJECT_TYPE='TABLE'], it executes successfully, by when i try it to procedure like the following, it returns error: table or view does not exit.
BEGIN
FOR R IN (SELECT OWNER, OBJECT_NAME FROM ALL_OBJECTS WHERE owner = 'MY_SCHEMA' AND OBJECT_TYPE='PROCEDURE') LOOP
execute IMMEDIATE 'GRANT ALL ON '|| R.OWNER ||'.'||R.OBJECT_NAME ||' TO MyUser';
END LOOP;
END;
Note: when i also try to execute as single statement it runs successfully.
GRANT ALL ON MY_SCHEMA.ProcedureName TO MyUser;
So what is difference, and why does not work on procedures.
try to show all the statements and then run all of them. one of it will definitely give you that error!
Try this:
SET serveroutput ON;
DECLARE
v_sql VARCHAR2(4000);
BEGIN
FOR R IN
(SELECT OWNER,
OBJECT_NAME
FROM ALL_OBJECTS
WHERE owner = 'MY_SCHEMA'
AND OBJECT_TYPE='PROCEDURE'
)
LOOP
v_sql:= 'GRANT ALL ON '|| R.OWNER ||'.'||R.OBJECT_NAME ||' TO MyUser';
dbms_output.put_line(v_sql);
END LOOP;
END;
and then run all those statements, in order to find the exact statement that gives you error.

Error report - ORA-00900: invalid SQL statement

I am new to oracle, I am trying to grant the roles to the users via a procedure. I am receiving the following error. can someone please help me with this?
declare stmnt2 varchar(10000);
p_user_name varchar2(20);
v_role_name varchar2(20);
begin
v_role_name := 'ROLE';
p_user_name := 'TOM';
stmnt2 := 'grant '||v_role_name||' to '
||v_user_name||'; '
||' grant connect to '
||v_user_name ;
execute immediate stmnt2;
end;
/
Error report -
ORA-00900: invalid SQL statement
ORA-06512: at line 10
00900. 00000 - "invalid SQL statement"
Thank you
You don't have spaces in your statement:
stmnt2 := 'grant '||v_role_name||' to '||p_user_name;
This must work better.

Execute immediate throws error when using record attribute in dynamic statement

I am executing the following snippet of code
set serveroutput on;
DECLARE
TYPE emp_rec_type IS record (emp_id NUMBER,salary NUMBER);
emp_rec emp_rec_type;
l_out number;
l_statement varchar2(1000);
BEGIN
emp_rec.emp_id := 1;
emp_rec.salary := 1000;
SELECT emp_rec.salary INTO l_out FROM dual WHERE 1=1;
dbms_output.put_line(l_out);
l_statement := 'select emp_rec.salary from dual where 1=1';
execute immediate l_statement into l_out;
dbms_output.put_line(l_out);
END;
I am getting the below output
Error report:
ORA-00904: "EMP_REC"."SALARY": invalid identifier
ORA-06512: at line 23
00904. 00000 - "%s: invalid identifier"
*Cause:
*Action:
1000
I am expecting the output to be
1000
1000
Why is it that the dynamic statement execution insists on emp_rec.salary being an invalid identifer while the Select into statement works fine?
Is there something else I need to do to make it work?
The content of the EXECUTE IMMEDIATE statement is running in a completely different scope to the rest of your PL/SQL code - you can't reference PL/SQL variables directly.
If you want to use the contents of emp_rec.salary in the dynamic statement, you should bind in the value like so:
l_statement := 'SELECT :1 FROM dual WHERE 1=1';
EXECUTE IMMEDIATE l_statement INTO l_out USING emp_rec.salary;