PL/SQL function in Oracle cannot see DBMS_AQ - oracle

I have problem with Oracle 9.2 and JMS.
I created PL/SQL routine to send XML text (from file or CLOB) to queue,
but this routine do not compile.
My code looks like (filling message omitted):
create or replace procedure jms_test(msg varchar2)
is
id pls_integer;
message sys.aq$_jms_stream_message;
enqueue_options dbms_aq.enqueue_options_t;
message_properties dbms_aq.message_properties_t;
msgid raw(16);
java_exp exception;
v_filehandle_input utl_file.file_type;
v_newline varchar2(32767);
pragma exception_init(java_exp, -24197);
begin
message := sys.aq$_jms_stream_message.construct;
message.set_string_property('FROM', 'TEST');
id := message.clear_body(-1);
end;
And Oracle raports that:
Error(6,21): PLS-00201: identifier 'DBMS_AQ' must be declared
I looked at some newsgroups and tried all that I found, but with no success.
granted (with success) many permisions
GRANT RESOURCE TO user;
GRANT CONNECT TO user;
GRANT EXECUTE ANY PROCEDURE TO user;
GRANT aq_administrator_role TO user;
GRANT aq_user_role TO user;
GRANT EXECUTE ON dbms_aqadm TO user;
GRANT EXECUTE ON dbms_aq TO user;
GRANT EXECUTE ON dbms_aqin TO user;
desc dbms_aq shows many functions like DEQUEUE, ENQUEUE, LISTEN
executed in SQLPlus both catqueue.sql and dbmsaq.plb
Anybody have idea what can be wrong?
EDITED:
I can do all that is described in: http://rwijk.blogspot.com/2009/02/whats-in-my-jms-queue.html, so dbms_aq is somehow visible, but not in my procedure.

Does it work if you do...
SYS.DBMS_AQ
instead of just
DBMS_AQ
If so, you're missing a synonym.
EDIT:
If you're now getting "PLS-00201: identifier 'SYS.DBMS_AQ" then I'd double check your grants.
GRANT EXECUTE ON SYS.DBMS_AQ to <your-user>;
Also, just to confirm, you've granted the execute privilege directly to the user, and not via a role?

In order to use objects in stored procedures, you must have grants WITH GRANT OPTION.
In this case you smust have
GRANT EXECUTE ON SYS.DBMS_AQ WITH GRANT OPTION to ;

Related

Insufficient privileges when using create user in procedure Oracle

I try to create user and grant for them some privileges. I try to create without using procedure:
CREATE USER User1 IDENTIFIED BY password;
It works fine.
But for example, i have thousands of users. So I created a procedure to do it:
CREATE OR REPLACE PROCEDURE CreateUser AS
BEGIN
FOR u IN ( SELECT id FROM User )
LOOP
EXECUTE IMMEDIATE 'CREATE USER User_'||d.id || ' IDENTIFIED BY password';
EXECUTE IMMEDIATE 'GRANT SELECT ON UserInfo_'||d.id||' TO User_'||d.id;
END LOOP;
END
But it throws an error:
ORA-01031: insufficient privileges
How can I handle this problem? Thanks for helping in advance
You need to make sure the user running the procedure has the privileges to create users.
Assuming the user that will run the procedure is MyUser, you need to run :
GRANT CREATE USER to MyUser;
if your SQL is directly (i.e not in a procedure ) but not working from a procedure/function it means that you have the Grants through a role. For a statement to work in a procedure or a function we need direct Grants and not through the role.
You can check that you have the Create user by a role by doing the following and trying your SQL, if it fails it means you have access through a role.
SET role none;
CREATE USER User1 IDENTIFIED BY password;

can we provide an oracle privilege to user which can alter only password of other user

I have created a procedure as shown below. This procedure is present in schema1 and trying to modify the password of another schema/user let's say schema2.
To achieve this the user schema1 must have altered user privilege but I cannot provide the alter user privilege to schema1 due to some restrictions on the application level.
I tried to query using ALTER SESSION in the procedure but it is not working.
Can someone help me with the solution?
code:
Procedure p_demo(p_schema in varchar, p_pswd in varchar2)
is
begin
execute immediate 'alter session set current_schema ='||p_schema;
execute immediate 'alter user '||p_schema||' identified by '||p_pswd;
end;
Changing the current_schema has no impact on permissions or what user is currently logged in. It merely changes how object name resolution works. If you query an object foo when current_schema is set to schema1, Oracle looks in the schema1 schema rather than in the current user's schema. It does nothing to give you access to the schema1.foo table.
I'm not quite sure that I understand the goal. If you are trying to ensure that only the schema2 user can change the schema2 user's password, you can define the procedure to use invoker's rights rather than definer's rights.
create or replace procedure change_my_password( p_username in varchar2,
p_password in varchar2 )
authid current_user
is
begin
execute immediate 'alter user '||p_username||' identified by '||p_password;
end;
/
If the goal is to have the procedure owned by schema1 and to give users other than the schema2 user permission to change schema2's password (i.e. to allow an application user or a helpdesk user to reset the user's password), schema1 would likely need to have the alter user permission. Otherwise, it's probably not doable.
If you're really desperate, you could potentially use the undocumented (and I emphasize undocumented here, subject to change at any time, may have weird side effects, may tend to make Oracle Support unhappy) dbms_sys_sql package. That's the package that APEX uses internally to run code as other users. I don't imagine that a sane DBA would consider giving an application user execute access on that package rather than the much (much, much) safer alter user permission but if you're trying to work around some corporate policy and you're not much concerned about actual security...
There are 3 users involved in this example:
scott, who is trying to change someone else's password (that's your schema1)
mike, whose password should be changed (your schema2)
mydba, who is granted DBA role in my database (if you don't have such an user, SYS would do, but - you'd rather have your own "DBA" user, don't mess up with SYS if you don't have to)
Connected as scott, I can't modify mike's password:
SQL> alter user mike identified by lion;
alter user mike identified by lion
*
ERROR at line 1:
ORA-01031: insufficient privileges
I'm going to connect as mydba and create a stored procedure which looks like yours:
SQL> connect mydba/mypwd#c11gt
Connected.
SQL> create or replace procedure p_demo (p_schema in varchar2, p_pswd in varchar2) is
2 begin
3 execute immediate 'alter user ' || p_schema || ' identified by ' || p_pswd;
4 end;
5 /
Procedure created.
SQL> exec p_demo('mike', 'lion');
PL/SQL procedure successfully completed.
OK; it works. I'll grant execute privilege on it to scott:
SQL> grant execute on p_demo to scott;
Grant succeeded.
Back to scott; see what he can do now:
SQL> connect scott/tiger#c11gt
Connected.
SQL> exec mydba.p_demo('mike', 'friday');
PL/SQL procedure successfully completed.
Do mike's credentials work?
SQL> connect mike/friday#c11gt
Connected.
SQL>
Yes, everything's fine.
So: you don't have to grant alter user to schema1; let it use procedure owned by a privileged user who can change someone else's password.
Cant we do as shown below: Tried doing this but it didn't work.
What i am trying to do is basically give alter user privileges to one role and assign that role to my oracle procedure.
Create role role_name;
GRANT ALTER USER TO role_name
grant all on role_name to procedure

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.

Execute dynamic DDL in PL/SQL procedure through definer role permissions

I want to perform some dynamic DDL in a procedure owned by an admin user. I'd like to execute this procedure with a technical operational user with definer rights (operational user doesn't have the create table role).
The problem is the 'create table' permission is granted to the admin user through use of a role, which doesn't allow me to execute the DDL as it seems that roles don't count in named pl/sql blocks.
create or replace
PROCEDURE test_permissions AUTHID DEFINER AS
v_query_string VARCHAR2(400 CHAR) := 'CREATE TABLE TEST(abcd VARCHAR2(200 CHAR))';
BEGIN
EXECUTE IMMEDIATE v_query_string;
END;
What I tried:
Running the procedure from a function set to AUTHID DEFINER with AUTHID CURRENT_USER on the proc (hoping the function would cascade the definer somehow)
Putting an anonymous block inside the function to execute the DDL (as roles seem to count in anonymous block)
If I set the AUTHID to CURRENT_USER, I can execute the procedure correctly with the admin user.
Is there any way I can work around this without granting CREATE TABLE directly to the admin user?
You can only set a role within a PL/SQL stored procedure/function if it has Invoker's Rights (AUTHID CURRENT_USER)(see doc). Which means that you can't use ops_user to call admin_user's procedure and then access admin_user's roles. If your DBAs insist on using a role to control the CREATE TABLE privilege, here's the approach I've seen before:
create or replace package admin_user.role_test authid current_user is
procedure test_permissions;
end role_test;
/
create or replace package body admin_user.role_test is
procedure test_permissions is
v_query_string VARCHAR2(400 CHAR) := 'begin
dbms_output.put_line(''after'');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
end;';
begin
dbms_output.put_line('before');
for r in (select role from session_roles) loop
dbms_output.put_line(r.role);
end loop;
DBMS_SESSION.SET_ROLE('CREATE_TABLE_ROLE IDENTIFIED BY "SECRET_PASSWORD"');
execute immediate v_query_string;
DBMS_SESSION.SET_ROLE('ALL EXCEPT CREATE_TABLE_ROLE'); -- restore defaults
end;
end role_test;
/
grant execute on admin_user.role_test to ops_user;
This will temporarily grant the role to ops_user just to execute your code. By default the ops_user should not be able to view the admin_user's package body source. You could probably wrap the package body to further protect the password. But password security aside, my biggest concern with this approach is that Oracle doesn't provide a nice way to disable a single role, so if ops_user has other password-protected roles, this code might raise an ORA-01979 when it tries to restore them.
So, there's an answer, but I'd still recommend doing what the other commenters suggested and granting CREATE TABLE to your admin user.

Oracle Procedure

create or replace function gen.sample_func(owner varchar2) return varchar2
as
data_t varchar2(10);
cursor cur is select data_type from SYS.DBA_TAB_COLUMNS;
begin
open cur;
dbms_output.put_line('Done');
close cur;
return data_t;
end sample_func;
On compiling the above function i get the following error
Warning: compiled but with compilation errors
Errors for FUNCTION sample_func
LINE/COL
--------------------------------------------------------------------------------
ERROR
--------------------------------------------------------------------------------
4/8
PLS-00201: identifier 'DBA_TAB_COLUMNS' must be declared
4/8
PL/SQL: Item ignored
7/15
PLS-00320: the declaration of the type of this expression is incomplete or malfo
rmed
7/8
PL/SQL: Statement ignored
I'm not getting this error when i execute the select statement alone in the cursor.
Please help me to resolve this issue.
Your user needs to be granted SELECT ON DBA_TAB_COLUMNS.
Note that granting through a role will not work - it needs to be a direct grant to the user for you to create a function/procedure.
In a definer's rights stored procedure such as the one you are creating, only privileges that are granted directly to the owner of the procedure are considered when resolving object names. Privileges granted through roles are not considered. I would wager that the owner of your procedure has been granted access to the DBA_TAB_COLUMNS view via a role rather than via a direct grant. You would need to ask the DBA to grant access to DBA_TAB_COLUMNS directly to the user that owns your procedure.
You can quickly test whether this is actually the problem you're experiencing. In SQL*Plus, enter the command
SQL> set role none;
and then run your SELECT statement. If you get the same permissions error, then the rpoblem is that you have the grant via a role. Disabling roles means that your interactive session is running with the same privileges that your stored procedure would run with.

Resources