Is it possible to see a sequence in all_sequences without having the SELECT right on the sequence? - oracle

I need to retrieve the list of available sequences of a certain database schema in an Oracle 10g database (10.2.0.3).
With the schema owner, I can simply do something like the following to achieve this:
SELECT sequence_name FROM all_sequences WHERE sequence_owner = 'ABCDEF';
However, If I use a user which has a custom "read-only" role assigned, that user does not get any rows when executing that query.
I've played around a bit and found out that granting the SELECT option on the sequences to the read-only role makes those sequences appear in the all_sequences view when connected with the read-only user.
However this means that the read-only user is able to do
SELECT my_sequence.NEXTVAL FROM DUAL;
which is a no-go for our situation (after all, the read-only user shall not be able to modify anything, not even sequences).
Is there another way for retrieving the sequences which does not allow selecting NEXTVAL?
[Edit:]
If I do
SELECT DISTINCT sequence_owner FROM all_sequences;
I get the following list:
SEQUENCE_OWNER
------------------------------
MDSYS
DMSYS
OLAPSYS
XDB
SYS
5 rows selected
After using the system user to do
GRANT SELECT ANY DICTIONARY TO MY_USER;
the result stays the same (revoke does not change anything either).
Granting the SELECT_CATALOG_ROLE instead does not work either.
Granting SELECT on at least one of the sequences however changes the result to include my own schema owner.

You can try to grant SELECT ANY DICTIONARY privilege, but it's very bad for the security reasons, so, I guess, your DBA will deny it.
Good decision is to create table function publishes required data. By default this function will work with AUTHID DEFINER rights, so you should just grant it to read-only user and it would receive sequences info without any chance to change them.

The best solution I can come up with is to grant the user SELECT ANY DICTIONARY. This will give them access to DBA_SEQUENCES (as well as all of the other DBA_ views) without needing permissions on the objects.

Related

Oracle SELECT granted but still can't access table across users

Can any one see what's wrong with this:
User ABC:
create table def.something (
id number,
ref number references def.anotherTable(id)
);
create role ROUser;
grant select on def.something to ROUser;
grant ROUser to ghi;
User DEF:
select * from something;
...
X rows returned
User GHI:
select * from def.something;
ORA-00942: table or view does not exist
Is the fact that there's a foreign key, that GHI doesn't have access to, on def.something the problem?
EDIT I've just tried this again on another server and it works fine (i.e., as expected). Not entirely sure what's going on here, but I think it may have something to do with some error on my part... As such, I'm voting to close the question.
You are most probably running that SELECT statement in PL/SQL block? In PL/SQL, priviliges granted through roles are not recognized. Try adding direct SELECT privilege on that table and see if it works.

Oracle : check for read/write privileges, automated testing

I have a question about Oracle and checking privileges.
Some background Info
I wrote some php scripts that will 'test' various things in our environment. One of those tasks is checking that a user has execute privileges on a procedure and that the procedure is valid/compiled.
Here is the query
select ao.object_name, utp.grantee, ao.status, utp.privilege
from all_objects ao, user_tab_privs utp
where utp.owner = ao.owner and
ao.object_name = utp.table_name and
upper( ao.object_name ) = :object_name and
ao.object_type = 'PACKAGE' and
utp.privilege = 'EXECUTE' and
ao.status = 'VALID'
This has worked well and has saved us time on procedure privileges; I do realize now that I can also double check the all_tab_privs to check execute access as well.
The problem
Now my question is, how do I do something similar with tables? We ran into an issue where a certain user had SELECT privs on a table but not UPDATE/INSERT privs. How can I check for each of these privileges individually. I've looked into all_tab_privs but haven't found it shows me what I want. It has procedures I can execute but when I check to see if a known table is there it isn't. For example, I'll run the following
select * from all_tab_privs
where table_name = 'KNOWN_TABLE' and
grantee = 'CURRENT_USER'
and privilege in ( 'SELECT', 'UPDATE', 'INSERT' );
but instead of getting back 3 rows for a table I know 100% that I can already select/insert/update it returns nothing.
Any ideas? Thank you.
Disclaimer
I am aware that I could just try inserting/updating data and then deleting it but I'd rather not do this. I'd rather not leave any trace since these scripts will run periodically, should be repeatable, and shouldn't alter the state of any piece of data, even if it's just a sequence on the table.
Also, if you could provide a 'list' of possible queries that I can use to determine privileges that would be fine. For example, to determine if i have select access run query 1, 2 and 3. If either returns data then you have select privs and so on for insert/update.
This looks rather optimistic to me, as the role issue could get really complex, particularly if roles ever get password protected, and I'd never really trust the method 100% without actually trying the DML.
It might be more simple to try queries such as:
select count(*)
from schema_name.table_name
where 1=0;
insert into schema_name.table_name
select *
from schema_name.table_name
where 1=0;
delete from schema_name.table_name
where 1=0;
update schema_name.table_name
set column_name = column_name
where 1=0;
I believe that such queries would fail if no privileges were granted (no database handy to check it), and they would never modify any data.
By the way, the ANY privileges are generally regarded as a security problem, so you might like to fail the system if any user is granted them.
If you have privileges granted via roles, you need a more complicated check. The link in comments gives some queries to use to look at the wider picture, but if you want to check what the current user can see - as one of your queries suggests - then you can query the session_roles view to see what object privileges are currently available to your session via roles, in addition to directly-granted object privileges:
select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
'Direct' as grant_type
from all_tab_privs atp
where atp.grantee = user
union all
select atp.table_schema, atp.table_name, atp.privilege, atp.grantee,
'Via role' as grant_type
from session_roles sr
join all_tab_privs atp on atp.grantee = sr.role;
You can obviously add filters if you want to look at a specific object or privilege, and the grant_type pseudo-column is just for info - not really that useful since you can compare grantee with user to get the same info I suppose.
You might want to look at session_privs as well, to check your user has any system privileges you expect.
But if you want a single query to check the privileges for another user or several users at once, you'll need something more like the linked queries, and the privileges necessary to run them.
I ended up solving this problem using a multi-step approach based around different queries and the results they brought back. I'm executing all the queries with some PHP code so it wasn't 100% necessary that I only have big query to solve it all.
Additionally, our databases are split up physically and they are linked together through database links so I had to do some additional work to make sure that this privilege checking worked across database links.
Currently I'm only checking for SELECT, DELETE, UPDATE, and INSERT privileges; that is all I need really for now.
The procedure
Here is the general procedure in a nut-list.
Get a list of all the database links available to the user.
For the following steps, start with the current database we are logged into and then check each database link retrieved from step 1.
2a. Check to see if the table is visible using a database query.
2b. If the table is visible, check to see if any of the permission queries return that this user has access to the table.
The queries
Here are the queries for each of the steps above.
1 Database links
select db_link from all_db_links
2a Table Visibility
select * from all_tables%DB_LINK% where table_name = :table_name and owner = :owner
The %DB_LINK% above is replaced by #db_link where applicable. If we are checking the current connection then I remove it entirely. Remember, the queries are being executed by a PHP script so I can do some string manipulation on the string to either remove the %DB_LINK% for the current database or replace it with one of the database links we got from step 1.
2b. Users, Roles, Tables
There are 4 queries all together here.
/*****/
/* 1 */
/*****/
select *
from user_tab_privs%DB_LINK%
where
owner = :owner
and
table_name = :table_name
and
privilege = :privilege
/*****/
/* 2 */
/*****/
select * from user_sys_privs%DB_LINK% where privilege = :privilege
/*****/
/* 3 */
/*****/
select * from
(
select distinct granted_role from
(
select null linker, granted_role
from user_role_privs%DB_LINK%
union all
select role linker, granted_role
from role_role_privs%DB_LINK%
)
start with linker is null
connect by prior granted_role = linker
) user_roles join role_tab_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
where
owner = :owner
and
table_name = :table_name
and
rtab.privilege = :privilege
/*****/
/* 4 */
/*****/
select * from
(
select distinct granted_role from
(
select null linker, granted_role
from user_role_privs%DB_LINK%
union all
select role linker, granted_role
from role_role_privs%DB_LINK%
)
start with linker is null
connect by prior granted_role = linker
) user_roles join role_sys_privs%DB_LINK% rtab on user_roles.granted_role = rtab.role
where rtab.privilege = :privilege
Explanations
Database links
In the phpunit tests I pass in two things : table name and schema name ( owner ). However, because of the database links we have to explicitly check the other databases by using the #db_link in the queries. Otherwise I might report a table as being inaccessible when in reality it is accessible via the database link.
Table visibility
If the user can't see the table then there is no point in checking for privileges. Checking for privileges also prevents the case where a user has been given 'SELECT ANY TABLE' privileges but the table itself doesn't actually exist from causing an unwanted failure.
The band of 4 queries
As shown by other posters, a user can be given access to a table in many ways. Specifically, they can be given roles, and those roles can be given roles, and then those roles can be assigned access. Or the user can be given explicit access or generic access through system privileges.
Query 1
The first of the four queries checks to see if the user has been given explicit SELECT, DELETE, etc, privileges on the table. It's easy to understand and would ideally be all that's necessary
Query 2
The second checks to see if the user has been granted any system privileges like DELETE ANY TABLE, SELECT ANY TABLE, INSERT ANY TABLE, etc. These are not granted explicitly on a table but the user can perform any of the referenced actions on any table they have visibility.
Query 3
The third query will see if any of the roles that user has, either directly or indirectly, has been given explicit SELECT, DELETE, etc, privileges on the table. This is similar to query 1 except it's based on the roles given to the user, not the user.
Query 4
The fourth checks to see if any of the roles that user has, either directly or indirectly, has been given any system privileges like DELETE ANY TABLE, SELECT ANY TABLE, INSERT ANY TABLE, etc. This one is similar to query 2.
That's it! I chain these together and use the results returned from each to determine whether a user has the desired privileges or not.
Details worth mentioning
If a user has any privileges across db_link_1 it does NOT mean that they have the same privileges on tables they access across db_link_2. Most should know this but I wanted to make sure I stated it explicitly. For example, select privs on table 1 across db_link_1 does not imply select privs on table 2 across db_link_2.
I check each db_link one at a time. So first I start of with the database I'm connected to directly, no database link required for this. Then, if I can't find the table or don't have the privs on the table I move on to the next database link.
In queries 2 and 4, I use 'SELECT ANY TABLE', 'DELETE ANY TABLE', etc in place of the :privilege variable.
In queries 1 and 3, I use 'SELECT', 'DELETE', 'UPDATE', 'INSERT' in place of the :privilege variable.

Oracle 9i: Synonymed Table Does Not Exist?

I've created a package that contains a stored procedure that I plan to invoke from a separate application. The stored procedure will return a sorted list of all the views and tables in the schema. To do that, it performs a simple select on the DBA_TABLES and DBA_VIEWS synonyms, as shown below:
CREATE OR REPLACE
PACKAGE BODY TITAN_ENTITY AS
PROCEDURE GETSCHEMAOBJECTS (RESULTS IN OUT T_CURSOR)
IS
V_CURSOR T_CURSOR;
BEGIN
OPEN V_CURSOR FOR
SELECT 'T' OBJECTTYPE, TABLE_NAME OBJECTNAME
FROM DBA_TABLES
WHERE OWNER = 'SONAR5'
UNION ALL
SELECT 'V' OBJECTTYPE, VIEW_NAME OBJECTNAME
FROM DBA_VIEWS
WHERE OWNER = 'SONAR5'
ORDER BY OBJECTNAME;
RESULTS := V_CURSOR;
END GETSCHEMAOBJECTS;
END TITAN_ENTITY;
I have verified that the synonyms in question exist, and are public:
CREATE PUBLIC SYNONYM "DBA_TABLES" FOR "SYS"."DBA_TABLES"
CREATE PUBLIC SYNONYM "DBA_VIEWS" FOR "SYS"."DBA_VIEWS"
My understanding is that, because they are public, I don't need any further permissions to get to them. If that understanding is incorrect, I wish someone would disabuse me of the notion and point me to more accurate data.
Now here's my problem: I can open a worksheet in Oracle SQL Developer and select from these tables just fine. I get meaningful data just fine (567 rows, as a matter of fact). But when I try to execute the stored procedure, Oracle complains with a compilation error, as shown below:
Error(9,8): PL/SQL: SQL Statement ignored
Error(10,16): PL/SQL: ORA-00942: table or view does not exist
When I double-click on that second error message, SQL Developer takes me to the first FROM clause ("FROM DBA_TABLES").
So I'm fairly stumped. I know SQL Server pretty well, and I'm new to Oracle, so please bear with me. If you could provide some clues, or point me in the right direction, I'd really appreciate it.
Thanks in advance!
Use ALL_TABLES and ALL_VIEWS instead of DBA_TABLES and DBA_VIEWS. ALL_% views should be accessible to all users.
If you select from a table or a view in a stored PL/SQL-procedure or a stored PL/SQL-function you need a direct grant. A grant via a database role isn't enough.
You probably need a direct grant on view dba_tables. (public) synonyms are just (public) synonyms. You need directly granted select rights.
See here: http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:48704116042682#48798240264807
Edit: Sorry, I glossed over the part where you seem to say that you can select from DBA_TABLES directly. Most likely the issue is that your privileges are granted through a role as someone else answered. But it's still worth explaining that your understanding of PUBLIC synonyms is incomplete, and that using ALL_TABLES would be better if it accomplishes what you need.
The synonym being PUBLIC only means that all users can reference the synonym; it does not grant them any access to the object that the synonym refers to.
What you would do to most directly solve this error is grant SELECT privilege on the SYS views to the user(s) that will run this procedure. However, I think that is a very bad idea.
As suggested by Raimonds, consider whether you can get what you need from USER_TABLES or ALL_TABLES instead. What user is calling this procedure, and what access does that user have to SONAR5's tables?
Generally, if your application is interested in a table, presumably it has some privileges on it, in which case is should be listed in ALL_TABLES.

Correct way to give users access to additional schemas in Oracle

I have two users Bob and Alice in Oracle, both created by running the following commands as sysdba from sqlplus:
create user $blah identified by $password;
grant resource, connect, create view to $blah;
I want Bob to have complete access to Alice's schema (that is, all tables), but I'm not sure what grant to run, and whether to run it as sysdba or as Alice.
Happy to hear about any good pointers to reference material as well -- don't seem to be able to get a good answer to this from either the Internet or "Oracle Database 10g The Complete Reference", which is sitting on my desk.
AFAIK you need to do the grants object one at a time.
Typically you'd use a script to do this, something along the lines of:
SELECT 'GRANT ALL ON '||table_name||' TO BOB;'
FROM ALL_TABLES
WHERE OWNER = 'ALICE';
And similar for other db objects.
You could put a package in each schema that you need to issue the grant from which will go through all call each GRANT statement via an EXECUTE IMMEDIATE.
e.g.
PROCEDURE GRANT_TABLES
IS
BEGIN
FOR tab IN (SELECT table_name
FROM all_tables
WHERE owner = this_user) LOOP
EXECUTE IMMEDIATE 'GRANT SELECT, INSERT, UPDATE, DELETE ON '||tab.table_name||' TO other_user';
END LOOP;
END;
There are many things to consider. When you say access, do you want to prefix the tables with the other users name? You can use public synonyms so that you can hide the original owner, if that is an issue. And then grant privs on the synonym.
You also want to plan ahead as best you can. Later, will you want Frank to be able to access Alice's schema as well? You don't want to have to regrant privileges on N number of tables. Using a database role would be a better solution. Grant the select to role "ALICE_TABLES" for example and when another user needs access, just grant them privilege to the role. This helps to organize the grants you make inside the DB.
Another solution if you have different owner:
BEGIN
FOR x IN (SELECT owner||'.'||table_name ownertab
FROM all_tables
WHERE owner IN ('A', 'B', 'C', 'D'))
LOOP
EXECUTE IMMEDIATE 'GRANT SELECT ON '||x.ownertab||' TO other_user';
END LOOP;
END;

What Oracle privileges do I need to use DBMS_METADATA.GET_DDL?

(Excuse any ignorance of mine here - I'm not a seasoned Oracle user.)
I'm attempting to use the DBMS_METADATA.GET_DDL function (in conjunction with ALL_OBJECTS or some such) to get the DDL for all of the tables in a particular schema. When I do this (either for all objects or for a single specific object) I get an ORA-31603 error ("object "FOO" of type TABLE not found in schema "SCHEMA").
I assume this means that the user I'm logged in with doesn't have whatever privilege is necessary to read the metadata needed for GET_DDL. What privilege is this that's needed? Is there a way when logged in to confirm that the current user does/does not have this privilege?
thanks!
Lee
Read this document, but basically, you need SELECT_CATALOG_ROLE
http://download.oracle.com/docs/cd/B19306_01/appdev.102/b14258/d_metada.htm#i1016867

Resources