1
Session ID 36652
Database
Oracle Sleuth: Who Did It?
Sitansu S. Mittra, Computer Sciences Corporation
Abstract
The security of a database depends on three main factors:



Prevention of unauthorized activities with the database,
Detection of harmful activities against the database, intentional or
unintentional, and
Correction of impact of such activities, as far as possible.
A DBA addresses the first issue by controlling the user access to data through
passwords, roles, privileges, profile, etc.; the second issue by setting up and
monitoring audit trails, as well as via the LogMiner utility; and the third issue
primarily by using the ‘sql_undo’ and ‘sql redo’ entries of v$logmnr_contents in
LogMiner, where possible.
The presentation discusses each issue with scripts, examples, and reference
materials from the author’s experience as a Senior Oracle DBA. The relevant
features of auditing and usage of LogMiner under Oracle 9i are covered with
references to Oracle 8i for the users who still use 8i. A bibliography appears at
the end of the paper.
Table of Contents
1. Prevention of unauthorized user access – roles, privileges, profiles
2. Detection of harmful activities – AUDIT TRAIL, LogMiner
3. Correction of impact of harmful activities via ‘undo’ and ‘redo’ entries –
LogMiner
4. Roadmap for Ensuring Data Security in Oracle Databases
5. Bibliography
Appendix 1 – LogMiner Scripts for Oracle 8i
Appendix 2 – LogMiner Scripts for Oracle 9i
1.
Prevention of Unauthorized User Access
Oracle administers the user access to the database through a hierarchy as
described below:
2




Create a user account with an account name and a password,
though a password is not mandatory.
Assign one or more roles to the user. Some or all of these roles
can be designated as DEFAULT role(s) for the user.
Assign system level and object level privileges to each role.
Set up a profile for the user and assign it to the user. If no profile is
created and assigned, Oracle assigns the DEFAULT profile to the user.
The relationship among users, roles, privileges, and profiles are as follows:
M:N
USER <<---------------------->> ROLE
M:N
ROLE <<---------------->> PRIVILEGE
M:1
USER <<--------------------> PROFILE
1.1
Roles
A role is a named collection of privileges that are granted to the role. Developers
and DBAs use roles to assign system and object level privileges to users. A role
can be granted to a user or to another role. Roles help the administration of the
privileges granted to users.
1.2
Privileges
A privilege is the capability to perform authorized function(s) in the database. A
privilege can be assigned directly to a user, or can be assigned to a role. In the
latter case, all users who are granted the role get the privilege. A system
privilege enables a user to perform designated tasks in the database. There are
126 such privileges that can be listed with the command:
select distinct NAME from system_privilege_map order by 1;
We can find out which of these privileges are actually granted to roles or users in
a specific database by the following command:
select distinct PRIVILEGE from dba_sys_privs order by 1;
An object privilege enables a user to perform primarily DML type tasks on
designated objects (tables, views, sequences, procedures) in the database.
There are 8 such privileges that can be listed with the command:
select distinct privilege from dba_tab_privs order by 1;
1.3
GRANT and REVOKE
3
Privileges are assigned to roles or users and roles are assigned to other roles or
users via the GRANT command.
Session Transcript
SQL>create role A;
Role created.
SQL>create role B;
Role created.
SQL>create user X identified by *****
2 default tablespace USER_DATA
3 temporary tablespace TEMP_DATA
4 quota 400M on USER_DATA
5 quota 400M on TEMP_DATA
6 quota 0 on SYSTEM;
User created.
(NOTE: Always include the clauses “default tablespace” and “temporary
tablespace”. Otherwise, the SYSTEM tablespace will be assigned as the
default and temporary tablespaces for the user X. Line 6 ensures that X
cannot use the SYSTEM tablespace for any work.)
SQL> grant select any table, execute any procedure, insert any table,
2 delete any table, update any table to A;
Grant succeeded.
SQL> grant create session to A;
Grant succeeded.
SQL> select privilege from dba_sys_privs where grantee = 'A' order by 1;
PRIVILEGE
---------------------------------------CREATE SESSION
DELETE ANY TABLE
EXECUTE ANY PROCEDURE
INSERT ANY TABLE
SELECT ANY TABLE
UPDATE ANY TABLE
6 rows selected.
SQL> select privilege from dba_tab_privs where grantee = 'A' order by 1;
no rows selected
(NOTE: A does not have any object level privilege.)
Privileges granted directly to a role or a user can be displayed by querying
dba_sys_privs or dba_tab_privs, as the case may be. But privileges granted
indirectly to a role or a user cannot be so displayed.
4
Session Transcript
SQL> grant create any table, insert any table, create session to B;
Grant succeeded.
SQL> create role C;
Role created.
SQL> grant B to C;
Grant succeeded.
SQL> grant C to X;
Grant succeeded.
SQL> select grantee, privilege from dba_sys_privs where grantee in ('A',
'B', 'C', 'X')
2 order by grantee, privilege;
GRANTEE
-----------------------------A
A
A
A
A
A
B
B
B
PRIVILEGE
---------------------------------------CREATE SESSION
DELETE ANY TABLE
EXECUTE ANY PROCEDURE
SELECT ANY TABLE
UPDATE ANY TABLE
INSERT ANY TABLE
CREATE ANY TABLE
CREATE SESSION
INSERT ANY TABLE
8 rows selected.
(Note that C and X are not listed since they were granted the privileges
indirectly. But X does have the privileges granted to B. For example,
X can create a table and insert rows into the table, as shown below.)
SQL> connect x/*****
Connected.
SQL> show user
USER is "X"
SQL> create table P
2 (m number not null,
3 n varchar2 (10));
Table created.
SQL> insert into P values (17, 'sample');
1 row created.
SQL> select * from P;
M N
--------- ----------
5
17 sample
SQL> drop table P cascade constraints;
Table dropped.
SQL> commit;
Commit complete.
Privileges granted directly to a role or a user can be taken away from that role or
user via the REVOKE command. But privileges granted indirectly to a role or a
user cannot be so taken away. You must find the direct grantee from whom you
can revoke the privileges.
Session Transcript
SQL> revoke insert any table from A;
Revoke succeeded.
SQL> revoke insert any table from X;
revoke insert any table from X
*
ERROR at line 1:
ORA-01952: system privileges not granted to 'X'
The following data dictionary views contain information about roles and
privileges:
DBA_ROLES
DBA_ROLE_PRIVS
ROLE_ROLE_PRIVS
DBA_SYS_PRIVS
DBA_TAB_PRIVS
1.4
all roles that exist in the database
roles granted to users/roles
roles granted to other roles
system privileges granted to users/roles
object level privileges granted to users/roles
Object Privilege: GRANT WITH GRANT OPTION
One can grant an object privilege to a user WITH GRANT OPTION whereby the
user can grant those privileges to other users or roles. These are called
grantable privileges and can be assigned only to users, but not to roles.
Session Transcript
SQL> grant select, insert, update, delete on invoice_status to X with
grant option;
Grant succeeded.
SQL> connect x/*****
Connected.
SQL> show user
USER is "X"
SQL> grant select, insert, update, delete on invoice_status to B;
6
Grant succeeded.
SQL> grant select any table to X with grant option;
grant select any table to X with grant option
*
ERROR at line 1:
ORA-01939: only the ADMIN OPTION can be specified
(NOTE: ‘select any table’ is NOT an object privilege. It is a system
privilege and must be granted WITH ADMIN OPTION. So, it cannot be
granted WITH GRANT OPTION.)
SQL> select grantee, table_name, privilege, grantable from dba_tab_privs
2 where grantee in ('A', 'B', 'C', 'X')
3 order by grantee, privilege;
GRANTEE
---------B
B
B
B
X
X
X
X
TABLE_NAME
-----------------------------INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
INVOICE_STATUS
PRIVILEGE
---------DELETE
INSERT
SELECT
UPDATE
DELETE
INSERT
SELECT
UPDATE
GRA
--NO
NO
NO
NO
YES
YES
YES
YES
8 rows selected.
1.5
System Privilege: GRANT WITH ADMIN OPTION
One can grant a system privilege to a user or a role WITH ADMIN OPTION
whereby the user can grant those privileges to other users or roles.
Session Transcript
SQL> grant select any table to X with admin option;
Grant succeeded.
SQL> connect x/*****
Connected.
SQL> show user
USER is "X"
SQL> grant select any table to B;
Grant succeeded.
NOTE: WITH GRANT OPTION can be used for object privileges alone and
WITH ADMIN OPTION can be used for system privileges alone.
1.6
DEFAULT ROLE
A user can have one or more roles. By default, when a user logs in, all of his/her
roles are activated. One can designate a subset of these roles as default roles.
In that case, only the default roles are activated at logon time.
7
Session Transcript
SQL> create role D;
Role created.
SQL> grant D to X;
Grant succeeded.
SQL> select * from DBA_ROLE_PRIVS where grantee = 'X'
2 order by GRANTEE, GRANTED_ROLE;
GRANTEE
---------X
X
X
GRANTED_ROLE
-----------------------------B
C
D
ADM
--NO
NO
NO
DEF
--YES
YES
YES
SQL> alter user X default role C, D;
User altered.
SQL> select * from DBA_ROLE_PRIVS where grantee = 'X'
2 order by GRANTEE, GRANTED_ROLE;
GRANTEE
---------X
X
X
1.7
GRANTED_ROLE
-----------------------------B
C
D
ADM
--NO
NO
NO
DEF
--NO
YES
YES
PROFILE for RESOURCE LIMITS and PASSWORD MANAGEMENT
A profile is a collection of quotas and privileges related to the following system
resource limits and password management:
System Resource
 CPU time
 I/O operation
 Idle time
 Connect time
 Memory space as private SQL area for MTS only
 Concurrent sessions
Password Management
 Password aging and expiration
 Password history
 Password complexity verification
 Account locking
A user can have only one profile at a time. Oracle provides a DEFAULT profile
that is assigned to all users unless a different profile is created via CREATE
8
PROFILE command and then assigned to the user via ALTER USER command.
Any created profile can be dropped, but not the DEFAULT profile created by
Oracle. All limits of the DEFAULT profile are UNLIMITED. But the DBA can
change the values via ALTER PROFILE command so that the modified values
apply to all users who are assigned the DEFAULT profile.
Session Transcript
SQL> col profile format a15
SQL> col limit format a10
SQL> select * from dba_profiles order by RESOURCE_TYPE;
PROFILE
---------DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
RESOURCE_NAME
-------------------------------COMPOSITE_LIMIT
SESSIONS_PER_USER
CPU_PER_CALL
LOGICAL_READS_PER_CALL
CONNECT_TIME
IDLE_TIME
LOGICAL_READS_PER_SESSION
CPU_PER_SESSION
PRIVATE_SGA
FAILED_LOGIN_ATTEMPTS
PASSWORD_LIFE_TIME
PASSWORD_REUSE_MAX
PASSWORD_LOCK_TIME
PASSWORD_GRACE_TIME
PASSWORD_VERIFY_FUNCTION
PASSWORD_REUSE_TIME
RESOURCE_TYPE
------------KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
LIMIT
----UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
16 rows selected.
SQL> select username, profile from dba_users where username = 'X';
USERNAME
PROFILE
------------------------------ ---------X
DEFAULT
SQL>
2
3
4
5
create profile NEW_PROFILE limit
CONNECT_TIME 480
SESSIONS_PER_USER 4
FAILED_LOGIN_ATTEMPTS 3
PASSWORD_GRACE_TIME 5;
Profile created.
SQL> select * from dba_profiles order by profile, resource_type;
PROFILE
--------------DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
RESOURCE_NAME
-------------------------------COMPOSITE_LIMIT
SESSIONS_PER_USER
CPU_PER_CALL
LOGICAL_READS_PER_CALL
CONNECT_TIME
IDLE_TIME
LOGICAL_READS_PER_SESSION
RESOURCE
-------KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
LIMIT
---------UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
9
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
CPU_PER_SESSION
PRIVATE_SGA
FAILED_LOGIN_ATTEMPTS
PASSWORD_LIFE_TIME
PASSWORD_REUSE_MAX
PASSWORD_LOCK_TIME
PASSWORD_GRACE_TIME
PASSWORD_VERIFY_FUNCTION
PASSWORD_REUSE_TIME
COMPOSITE_LIMIT
PRIVATE_SGA
CONNECT_TIME
IDLE_TIME
LOGICAL_READS_PER_CALL
KERNEL
KERNEL
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
KERNEL
KERNEL
KERNEL
KERNEL
KERNEL
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
DEFAULT
DEFAULT
480
DEFAULT
DEFAULT
PROFILE
--------------NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
NEW_PROFILE
RESOURCE_NAME
-------------------------------LOGICAL_READS_PER_SESSION
SESSIONS_PER_USER
CPU_PER_CALL
CPU_PER_SESSION
FAILED_LOGIN_ATTEMPTS
PASSWORD_LIFE_TIME
PASSWORD_REUSE_MAX
PASSWORD_LOCK_TIME
PASSWORD_GRACE_TIME
PASSWORD_VERIFY_FUNCTION
PASSWORD_REUSE_TIME
RESOURCE
-------KERNEL
KERNEL
KERNEL
KERNEL
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
LIMIT
---------DEFAULT
4
DEFAULT
DEFAULT
3
DEFAULT
DEFAULT
DEFAULT
5
DEFAULT
DEFAULT
32 rows selected.
SQL> alter user X profile new_profile;
User altered.
SQL> select username, profile from dba_users where username = 'X';
USERNAME
PROFILE
------------------------------ --------------X
NEW_PROFILE
SQL>
2
3
4
alter profile DEFAULT limit
SESSIONS_PER_USER 6
CPU_PER_CALL 3600
PASSWORD_REUSE_MAX 2;
Profile altered.
SQL> select * from dba_profiles where profile = 'DEFAULT'
2 order by RESOURCE_TYPE;
PROFILE
--------------DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
RESOURCE_NAME
RESOURCE_TYPE LIMIT
------------------------------- ------------- -------COMPOSITE_LIMIT
KERNEL
UNLIMITED
SESSIONS_PER_USER
KERNEL
6
CPU_PER_SESSION
KERNEL
UNLIMITED
CPU_PER_CALL
KERNEL
3600
LOGICAL_READS_PER_SESSION
KERNEL
UNLIMITED
LOGICAL_READS_PER_CALL
KERNEL
UNLIMITED
IDLE_TIME
KERNEL
UNLIMITED
CONNECT_TIME
KERNEL
UNLIMITED
10
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
DEFAULT
PRIVATE_SGA
FAILED_LOGIN_ATTEMPTS
PASSWORD_LIFE_TIME
PASSWORD_REUSE_TIME
PASSWORD_REUSE_MAX
PASSWORD_VERIFY_FUNCTION
PASSWORD_LOCK_TIME
PASSWORD_GRACE_TIME
KERNEL
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
PASSWORD
UNLIMITED
UNLIMITED
UNLIMITED
UNLIMITED
2
UNLIMITED
UNLIMITED
UNLIMITED
16 rows selected.
Any changes made to a profile via ALTER PROFILE command are NOT
effective for the current session. They take effect for all subsequent sessions. A
profile that has users assigned to it can be dropped only via the command DROP
PROFILE profile CASCADE. In that case, Oracle assigns the DEFAULT profile
to all users who had the dropped profile as their default profile.
Session Transcript
SQL> drop profile new_profile;
drop profile new_profile
*
ERROR at line 1:
ORA-02382: profile NEW_PROFILE has users assigned, cannot drop without
CASCADE
SQL> drop profile new_profile cascade;
Profile dropped.
SQL> select username, profile from dba_users where username = 'X';
USERNAME
PROFILE
------------------------------ --------------X
DEFAULT
1.8
PUBLIC as User
PUBLIC is a special user in Oracle. Any system level or object level privilege
granted to PUBLIC can be used by all current and future users of the database.
Ideally, privileges should not be granted to PUBLIC. If any privilege is granted
temporarily to PUBLIC, it should be revoked as soon as such privilege is no
longer needed. The privileges granted to PUBLIC can be determined by running
the following queries:
select privilege from dba_sys_privs where grantee = 'PUBLIC' order by 1;
select privilege from dba_tab_privs where grantee = 'PUBLIC' order by 1;
11
2.
Detection of harmful activities
A DBA can track all user activities via the auditing capability provided by Oracle.
Three different types of action can be audited:



login attempts,
database actions, and
access (retrieval and update) to database objects.
The prerequisite to enable any auditing is to set the initialization parameter
AUDIT_TRAIL to the value TRUE or DB (default is FALSE or NONE). Then
audit records are written to the table SYS.AUD$. Oracle offers several DBA_
views containing the various types of audit records depending on the audit type.
2.1
Login Attempts
Proceed as follows:
(a)
(b)
(c)
(d)
Login as a DBA privileged account.
Type “audit session;”
Allow users to login as needed.
Run the following query to see the login and logout activities, both
successful and unsuccessful
select username, os_username,
to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Login Time",
to_char (LOGOFF_TIME, 'dd-mon-yyyy hh24:mi:ss') "Logout Time",
decode (returncode, 0, 'Connected',
01017, 'invalid username/password',
01005, 'null password given',
returncode) "Login Status"
from dba_audit_session
order by 1, 3 desc;
Note that "Login Status" will display the value 'null password given' only if
you enter blanks for the password by hitting the space bar and then press
‘Enter’. If you press only ‘Enter’ for the password, then Oracle ignores
that action and does not create any record in dba_audit_session.
Partial Session Transcript
SQL> audit session;
Audit succeeded.
SQL> commit;
Commit complete.
SQL> connect dqsmith@monami.dev01
Enter password: **********
Connected.
12
SQL> show user
USER is "DQSMITH"
SQL> connect dqsmith@monami.dev01
Enter password: ****
ERROR:
ORA-01005: null password given; logon denied
Warning: You are no longer connected to ORACLE.
SQL> connect sekhar/******@monami.dev01
Connected.
. . . . . . . . . . . .
SQL>
SQL>
SQL>
2
3
4
5
6
7
8
9
col OS_USERNAME format a12
col username format a10
select username, os_username,
to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Login Time",
to_char (LOGOFF_TIME, 'dd-mon-yyyy hh24:mi:ss') "Logout Time",
decode (returncode, 0, 'Connected',
01017, 'invalid username/password',
01005, 'null password given',
returncode) "Login Status"
from dba_audit_session
order by 1, 3 desc;
USERNAME
OS_USERNAME Login Time
Logout Time
---------- ------------ -------------------- -------------------Login Status
---------------------------------------DQSMITH
Mittra
22-jul-2003 09:45:49
null password given
DQSMITH
Connected
Mittra
22-jul-2003 09:40:42 22-jul-2003 09:45:45
DQSMITH
Connected
Mittra
18-jul-2003 15:36:38 18-jul-2003 16:34:46
DQSMITH
Mittra
18-jul-2003 14:04:44
invalid username/password
DQSMITH
Connected
Mittra
18-jul-2003 12:50:06 18-jul-2003 12:51:03
. . . . . . .
14 rows selected.
If a user appears repeatedly with failed login attempts, the DBA can investigate
the account by looking into its profile and privileges.
2.2
Database Actions
A DBA can audit any action affecting a database object such as a table, view,
synonym, database link, tablespace, index, etc. The possible actions such as
CREATE, ALTER, and DROP that can affect a specific object type can be
grouped together during auditing. For example, the command “audit table;” will
13
audit all actions affecting a table. Oracle allows 144 actions each with a numeric
code and its description. You can get a list of all these codes by running the
following query:
select action, name from audit_actions;
Once auditing is activated for an object, all actions pertaining to that object are
recorded in the view DBA_AUDIT_OBJECT. The DBA can run the following
query to get a list of all such actions affecting the audit-activated objects:
select username, os_username, owner, obj_name, action_name,
to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction Time"
from dba_audit_object
order by 1, 4, 6 desc;
The DBA can analyze the result returned by the above query to identify users
responsible for harmful activities such as dropping an important table or deleting
rows, even if inadvertently.
2.3
Access (Retrieval and Update) to Database Objects
This category of auditing applies to the four data retrieval and update
commands, SELECT, INSERT, UPDATE, and DELETE. If an activity appears to
be harmful or if a complaint arises about some missing data, the DBA can further
investigate the situation to find an answer. For example, an unauthorized user
may have retrieved sensitive data, an authorized user may have deleted some
rows or even dropped a table perhaps inadvertently, a deleted row may have
caused a constraint to become invalid causing additional side effects, and so on.
As an Oracle sleuth the DBA can find the “offending” user by tracking and
analyzing the database audit trail as follows:
(a)
(b)
For each table to be audited, enter the command
AUDIT ALL ON table_name BY ACCESS;
where table_name is the name of the table on which you want to turn on
auditing on all types of access. The command activates the auditing
mechanism on the table. The option BY ACCESS causes an audit record
to be written to the table SYS.AUD$ once for each time the table is
accessed. For example, if a user performs four update transactions
(INSERT, UPDATE, DELETE) on the table, then four separate records
are written to SYS.AUD$. The results can be viewed by querying the view
DBA_AUDIT_OBJECT.
Run the query (note that the same query was given at the end of
Section 2.2):
select username, os_username, owner, obj_name, action_name,
to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction Time"
14
from dba_audit_object
order by 1, 4, 6 desc;
The query returns the list of actions taken on the table by all users. The DBA
can identify the user(s) performing retrievals or updates against the table from
the list.
Partial Session Transcript
SQL> audit table;
Audit succeeded.
SQL> audit view;
Audit succeeded.
SQL> audit all on dqsmith.explore by access;
Audit succeeded.
SQL> audit all on EXPLORE_COPY by access;
Audit succeeded.
SQL> audit all on EXPLORE_ORIGINAL by access;
Audit succeeded.
SQL> commit;
Commit complete.
SQL> select username, os_username, owner, obj_name, action_name,
2 to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction Time"
3 from dba_audit_object
4 order by 1, 4, 6 desc;
USERNAME
OS_USERNAME OWNER
OBJ_NAME
ACTION_NAME
---------- ------------ ------------------------------ -------------------------------Transaction Time
-------------------DQSMITH
Mittra
DQSMITH
EXPLORE
CREATE TABLE
18-jul-2003 15:38:36
DQSMITH
Mittra
CREATE TABLE
18-jul-2003 15:38:01
DQSMITH
EXPLORE
DQSMITH
Mittra
SELECT
17-jul-2003 09:09:16
SEKHAR
EXPLORE
DQSMITH
Mittra
SELECT
17-jul-2003 09:09:16
SEKHAR
EXPLORE
DQSMITH
Mittra
INSERT
17-jul-2003 09:08:36
SEKHAR
EXPLORE
DQSMITH
Mittra
DELETE
17-jul-2003 09:07:58
SEKHAR
EXPLORE
DQSMITH
Mittra
INSERT
17-jul-2003 09:07:26
SEKHAR
EXPLORE
15
DQSMITH
Mittra
UPDATE
17-jul-2003 09:05:37
SEKHAR
EXPLORE
DQSMITH
Mittra
SELECT
18-jul-2003 12:50:38
SEKHAR
EXPLORE_ORIGINAL
DQSMITH
Mittra
CREATE VIEW
18-jul-2003 15:39:43
DQSMITH
EXPLORE_VIEW
USERNAME
OS_USERNAME OWNER
OBJ_NAME
ACTION_NAME
---------- ------------ ------------------------------ -------------------------------Transaction Time
-------------------SEKHAR
Mittra
SEKHAR
EXPLORE
RENAME
17-jul-2003 09:12:37
SEKHAR
timsdba
ALTER TABLE
15-jul-2003 16:28:35
SEKHAR
EXPLORE
TIMS
Mittra
SELECT
18-jul-2003 12:49:13
DQSMITH
EXPLORE_COPY
TIMS
timsdba
COMMENT
17-jul-2003 11:23:22
DQSMITH
EXPLORE_COPY
. . . . . . . . . . .
25 rows selected.
Oracle provides the following DBA_ views containing information about auditing
at various levels. There are many common columns among these views.
DBA_AUDIT_EXISTS
audit trail entries produced by AUDIT NOT EXISTS
and AUDIT EXISTS
DBA_AUDIT_OBJECT
audit trail records for all objects in the system
DBA_AUDIT_SESSION
audit trail records concerning CONNECT and
DISCONNECT
DBA_AUDIT_STATEMENT audit trail records concerning GRANT, REVOKE,
AUDIT, NOAUDIT, and ALTER SYSTEM statements
DBA_AUDIT_TRAIL
list of all audit trail entries
DBA_AUDIT_TRAIL contains eleven more columns than DBA_AUDIT_OBJECT
and thus provides more information than DBA_AUDIT_OBJECT.
16
2.4
Storage Management for SYS.AUD$ Table
When auditing is activated on a variety of actions and on several objects BY
ACCESS, a new record is written to SYS.AUD$ for every action and every
access. As a result, this table can grow very rapidly. Since it belongs to
SYSTEM tablespace, that tablespace can get fragmented. To remedy this
situation the DBA should archive the rows from SYS.AUD$ on a regular basis as
follows:



Determine the frequency of archiving based on the growth rate of
SYS.AUD$.
Copy the rows of SYS.AUD$ into another table SYS.AUD$_COPY,
say, created in a non-SYSTEM TABLESPACE.
TRUNCATE the table SYS.AUD$.
The DBA can inactivate auditing by issuing the following commands, as
appropriate:


3.
noaudit session;
noaudit all on owner.table;
Correction of Impact of Harmful Activities
The detection capability provided by the AUDIT TRAIL mechanism has a limited
scope. First, it allows a DBA to identify the users performing harmful activities
such as deleting rows, dropping objects, etc. that should not be done only if a
user logs in using his/her personal account. In case of a generic account such
as APPL, APPLDBA, TESTER, etc. the DBA cannot identify a single individual.
Secondly, even when the DBA identifies a single user performing some
destructive activity, say by mistake, the DBA cannot reverse the changes made.
For instance, deleted rows cannot be re-inserted or dropped objects recreated
without some scripts or data from the user or developer.
The LogMiner utility available with Oracle 8i and above addresses some of these
deficiencies of the AUDIT TRAIL mechanism. For example, LogMiner stores all
DML commands that were executed and the corresponding DML commands to
reverse the results of the executed commands. Also, LogMiner retains session
level information with which a DBA can identify Oracle and Unix processes for a
transaction. Under certain situations the DBA can even identify the individual
user logging into Oracle under a generic username. The utility also works with
the Redo Log files from an Oracle8 database.
17
3.1
Scope of LogMiner under Oracle 8i
As we all know, Oracle records all transactions in the online Redo Log files which
are binary files. If an instance runs in ARCHIVELOG mode, then these files are
copied periodically to the Archived Log files. The Redo Log files contain a
wealth of information about user activities in a database. They contain all the
data needed to make a database recovery and store all transactions made to the
database. LogMiner offers an interface to the contents of these files enabling
DBAs to audit all user activities and to reverse erroneous changes to data or
structures. The utility can read any Redo Log file, online or archived, from
Oracle8 forward. Unlike the AUDIT TRAIL mechanism, it does not impose any
additional data collection overhead since Oracle already collects the data in the
Redo Log files.
LogMiner consists of the following components owned by the SYS schema:
(a)
(b)
(c)
Package DBMS_LOGMNR with three procedures
 ADD_LOGFILE – includes one Redo Log file for LogMiner analysis; if
multiple files are to be included, then the first file takes the argument
‘NEW’ and all other files take the argument ‘ADDFILE’
 START_LOGMNR – starts a LogMiner session
 END_LOGMNR – ends a LogMiner session
Procedure DBMS_LOGMNR_D.BUILD - exports the data dictionary as a
static text file from the database that LogMiner will analyze.
Four V$views as described below:
 V$LOGMNR_CONTENTS – the contents of the Redo Log files being
analyzed
 V$LOGMNR_DICTIONARY– the LogMiner dictionary created by
DBMS_LOGMNR_D.BUILD
 V$LOGMNR_LOGS – the names and other details of the Redo Log
files being analyzed
 V$LOGMNR_PARAMETERS – current parameter settings for
LogMiner
The directory $ORACLE_HOME/rdbms/admin contains two scripts, dbmslm.sql
and dbmslmd.sql. The first script creates the package in (a) with the three
procedures. The second script creates the procedure in (b).
3.1.1 Installation and Operation of LogMiner under Oracle 8i
(a)
Include the initialization parameter utl_file_dir in the init.ora file. The value
of this parameter will be an existing directory to which Oracle has
permissions to write as needed by the PL/SQL procedure
DBMS_LOGMNR_D.BUILD (see Section 3.1 (b)).
18
(b)
(c)
(d)
(e)
(f)
(g)
(h)
If necessary, shutdown the instance and then startup for the new
parameter to take effect. It cannot be changed via the ALTER SYSTEM
command.
Run the script $ORACLE_HOME/rdbms/admin/dbmslmd.sql to create the
procedure DBMS_LOGMNR_D.BUILD allowing the LogMiner dictionary to
be created.
Create LogMiner dictionary.
Run the script $ORACLE_HOME/rdbms/admin/dbmslm.sql to create the
package DBMS_LOGMNR with the three procedures, ADD_LOGFILE,
START_LOGMNR, and END_LOGMNR, needed for LogMiner analysis.
Include Redo Log files for LogMiner analysis.
Start a LogMiner session.
End the session by executing the script
DBMS_LOGMNR.END_LOGMNR. This procedure MUST be called prior
to exiting the LogMiner session. Otherwise, Oracle generates a silent
ORA-00600 error because the PGA is found to be bigger at logoff than it
was at logon, which is considered a space leak.
Appendix 1 contains all the scripts used in the session transcript below.
Session Transcript
SQL> select name, value from v$parameter where name = 'utl_file_dir';
NAME
VALUE
--------------- ------------------------------------------------------utl_file_dir
/tims1/ssmittra/dev01/monami_instance/logminer/logs
devmaster% cd /tims1/ssmittra/dev01/monami_instance/logminer
SQL>connect internal
Connected.
SQL>@create_logmnr_dict_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/create_logmnr_dict_8174.s
ql
SQL>
SQL>BEGIN
2
sys.dbms_logmnr_d.build (
3
dictionary_filename=> 'logminer_dictionary_oracle.dic',
4
dictionary_location =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs'
5
);
6 END;
7 /
PL/SQL procedure successfully completed.
Elapsed: 00:01:47.98
devmaster% cd logs
devmaster% pwd
/tims1/ssmittra/dev01/monami_instance/logminer/logs
devmaster% ls -l
total 3840
19
-rw-r--r-1 oracle
dba
logminer_dictionary_oracle.dic
devmaster% sqlplus internal
1951204 Jul 24 14:56
SQL*Plus: Release 8.1.7.0.0 - Production on Thu Jul 24 15:19:21 2003
(c) Copyright 2000 Oracle Corporation.
All rights reserved.
Connected to:
Oracle8i Enterprise Edition Release 8.1.7.4.0 - Production
With the Partitioning option
JServer Release 8.1.7.4.0 - Production
SQL>@include_redo_logs_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/include_redo_logs_8174.sq
l
SQL>REM Purpose: Include all redo log files for LogMiner analysis
SQL>
SQL>
SQL>BEGIN
2
3 SYS.DBMS_LOGMNR.ADD_LOGFILE(
4
'/home/oracle/oradata/tims/dba/ssmittra/monami_A01.rdl',
5
dbms_logmnr.NEW);
6
7 SYS.DBMS_LOGMNR.ADD_LOGFILE(
8
'/home/oracle/oradata/tims/dba/ssmittra/monami_A02.rdl',
9
dbms_logmnr.ADDFILE);
10
11 END;
12 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.14
SQL>@start_logminer_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/start_logminer_8174.sql
SQL>REM Purpose: Start LogMiner for analyzing the Redo Log files.
SQL>
SQL>
SQL>EXECUTE SYS.DBMS_LOGMNR.START_LOGMNR( >
DICTFILENAME =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs/logminer_dictionary
_oracle.dic');
PL/SQL procedure successfully completed.
Elapsed: 00:00:04.02
SQL>select distinct table_space, seg_name, seg_owner from
v$logmnr_contents
2 where table_space != 'SYSTEM'
3 order by 1, 2;
TABLE_SPACE
-------------------------------USER_MONAMI
USER_MONAMI
SEG_NAME
--------------------EXPLORE_ORIGINAL
INVOICE_STATUS
SEG_OWNER
--------SEKHAR
SEKHAR
20
2 rows selected.
Elapsed: 00:00:02.15
SQL>CREATE TABLE TEST_LOG_MINER
2 (TEST_ID
NUMBER (4) NOT NULL,
3 TEST_DATE
DATE DEFAULT SYSDATE NOT NULL,
4 TESTER_NAME
VARCHAR2 (30) DEFAULT USER NOT NULL,
5 FINDINGS
VARCHAR2 (100))
6 TABLESPACE USER_MONAMI;
Table created.
Elapsed: 00:00:00.42
(INSERT FIVE ROWS INTO TEST_LOG_MINER)
SQL>col findings format a32
SQL>col tester_name format a20
SQL>select * from test_log_miner order by 1;
TEST_ID
---------268
856
1234
1434
errors.
6937
TEST_DATE
--------09-MAY-93
17-MAY-66
24-JUL-03
24-JUL-03
TESTER_NAME
-------------------Sanjukta Banerji
Sakuntala Datta
SYS
SYS
27-OCT-01 Damayanti Mittra
FINDINGS
-----------------------------All success
All success
The test passed successfully.
The test passed with two
FAILED
5 rows selected.
Elapsed: 00:00:00.01
SQL>select distinct table_space, seg_name from v$logmnr_contents where
table_space != 'SYSTEM'
2 order by 1, 2;
TABLE_SPACE
-------------------------------USER_MONAMI
USER_MONAMI
SEG_NAME
-------------------------------EXPLORE_ORIGINAL
INVOICE_STATUS
2 rows selected.
Elapsed: 00:00:02.19
SQL> execute dbms_logmnr.end_logmnr;
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.01
Note that the table TEST_LOG_MINER does not appear as a SEG_NAME
above, because the LogMiner dictionary is static. Any DML activity done after
creating the dictionary with the script create_logmnr_dict_8174.sql is not
recorded in that dictionary. We now start a new session with LogMiner after
having created and populated the table TEST_LOG_MINER.
21
Session Transcript
devmaster% sqlplus internal
SQL*Plus: Release 8.1.7.0.0 - Production on Fri Jul 25 08:27:56 2003
(c) Copyright 2000 Oracle Corporation.
All rights reserved.
Connected to:
Oracle8i Enterprise Edition Release 8.1.7.4.0 - Production
With the Partitioning option
JServer Release 8.1.7.4.0 - Production
SQL>@LogMiner_Session_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/LogMiner_Session_8174.sql
SQL>REM Purpose: provide a single command file to run a LogMiner
Session.
SQL>
SQL>
SQL>set scan on
SQL>
SQL>column get_location new_value LogMiner_Session_spool_file noprint
SQL>
SQL>select 'LogMiner_Session_' || TO_CHAR(SYSDATE, 'DD-MON-YYYY') ||
'.log' get_location from dual;
1 row selected.
Elapsed: 00:00:00.02
SQL>
SQL>spool
/tims1/ssmittra/dev01/monami_instance/logminer/logs/&LogMiner_Session_sp
ool_file
SQL>
SQL>@create_logmnr_dict_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/create_logmnr_dict_8174.s
ql
SQL>
SQL>BEGIN
2
sys.dbms_logmnr_d.build (
3
dictionary_filename=> 'logminer_dictionary_oracle.dic',
4
dictionary_location =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs'
5
);
6 END;
7 /
LogMnr Dictionary Procedure started
LogMnr Dictionary File Opened
TABLE: OBJ$ recorded in LogMnr Dictionary File
(REST OF OUTPUT SUPPRESSED)
Procedure executed successfully - LogMnr Dictionary Created
PL/SQL procedure successfully completed.
Elapsed: 00:01:56.80
SQL>@include_redo_logs_8174.sql
22
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/include_redo_logs_8174.sq
l
SQL>REM Purpose: Include all redo log files for LogMiner analysis
SQL>
SQL>
SQL>BEGIN
2
3 SYS.DBMS_LOGMNR.ADD_LOGFILE(
4
'/home/oracle/oradata/tims/dba/ssmittra/monami_A01.rdl',
5
dbms_logmnr.NEW);
6
7 SYS.DBMS_LOGMNR.ADD_LOGFILE(
8
'/home/oracle/oradata/tims/dba/ssmittra/monami_A02.rdl',
9
dbms_logmnr.ADDFILE);
10
11 END;
12 /
PL/SQL procedure successfully completed.
Elapsed: 00:00:00.06
SQL>
SQL>@start_logminer_8174.sql
SQL>REM File =
/tims1/ssmittra/dev01/monami_instance/logminer/start_logminer_8174.sql
SQL>REM Purpose: Start LogMiner for analyzing the Redo Log files.
SQL>
SQL>
SQL>EXECUTE SYS.DBMS_LOGMNR.START_LOGMNR( >
DICTFILENAME =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs/logminer_dictionary
_oracle.dic');
PL/SQL procedure successfully completed.
Elapsed: 00:00:03.86
SQL>
SQL>select count (*) from v$logmnr_contents;
COUNT(*)
---------3690
1 row selected.
Elapsed: 00:00:02.35
SQL>
SQL>select distinct table_space, seg_name, seg_type_name from
v$logmnr_contents
2 where table_space != 'SYSTEM'
3 order by 1, 2;
TABLE_SPACE
-------------------------------USER_MONAMI
USER_MONAMI
USER_MONAMI
3 rows selected.
SEG_NAME
------------------------EXPLORE_ORIGINAL
INVOICE_STATUS
TEST_LOG_MINER
SEG_TYPE_NAME
------------TABLE
TABLE
TABLE
23
Elapsed: 00:00:02.18
SQL>
SQL>spool off
We now see that TEST_LOG_MINER is included in the LogMiner dictionary.
3.1.2 Output from LogMiner under Oracle 8i
(a)
SQL_REDO and SQL_UNDO
The column V$LOGMNR_CONTENTS.SQL_REDO returns the actual DML
statement that was executed and V$LOGMNR_CONTENTS.SQL_UNDO returns
the statement that reverses the REDO-transaction. Here are a few examples.
Partial Session Transcript
SQL>select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction
Time", sql_redo
2 from v$logmnr_contents
3 where table_space != 'SYSTEM' and timestamp > '15-JUL-2003'
4 order by 1 desc;
Transaction Time
-------------------SQL_REDO
-----------------------------------------------------------------------24-jul-2003 15:51:29
insert into
"SYS"."TEST_LOG_MINER"("TEST_ID","TEST_DATE","TESTER_NAME","FINDINGS")
values (856,TO_DATE('17-MAY-1966 00:00:00', 'DD-M
ON-YYYY HH24:MI:SS'),'Sakuntala Datta','All success');
24-jul-2003 15:50:24
insert into
"SYS"."TEST_LOG_MINER"("TEST_ID","TEST_DATE","TESTER_NAME","FINDINGS")
values (268,TO_DATE('09-MAY-1993 00:00:00', 'DD-M
ON-YYYY HH24:MI:SS'),'Sanjukta Banerji','All success');
SQL>select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction
Time", sql_undo
2 from v$logmnr_contents
3 where table_space != 'SYSTEM' and timestamp > '15-JUL-2003'
4 order by 1 desc;
Transaction Time
-------------------SQL_UNDO
-----------------------------------------------------------------------24-jul-2003 15:51:29
delete from "SYS"."TEST_LOG_MINER" where "TEST_ID" = 856 and "TEST_DATE"
= TO_DATE('17-MAY-1966 00:00:00', 'DD-MON-YYYY HH24:MI:SS')
and "TESTER_NAME" = 'Sakuntala Datta' and "FINDINGS" = 'All success'
and ROWID = 'AAAA7NAAGAAAACPAAE';
24-jul-2003 15:50:24
delete from "SYS"."TEST_LOG_MINER" where "TEST_ID" = 268 and "TEST_DATE"
= TO_DATE('09-MAY-1993 00:00:00', 'DD-MON-YYYY HH24:MI:SS')
24
and "TESTER_NAME" = 'Sanjukta Banerji' and "FINDINGS" = 'All success'
and ROWID = 'AAAA7NAAGAAAACPAAD';
(b)
SESSION_INFO and Related Columns
The column V$LOGMNR_CONTENTS.SESSION_INFO returns user identifying
information such as LoginUserName and OsUserName. Unless both of them
are generic such as SYS, ORACLE, TESTER, etc., the DBA can identify the
individual user. If both are generic, there is no way to identify the user logging
under the generic names.
Session Transcript
09:38:57 SQL>select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss')
"Transaction Time", username,
09:39:00
2 session#, serial#, operation, session_info
09:39:14
3 from v$logmnr_contents
09:39:28
4 where timestamp > '07-AUG-2003'
09:40:14
5 and seg_name in ('EXPLORE', 'EXPLORE_COPY',
'EXPLORE_ORIGINAL')
09:40:19
6 order by 1;
Transaction Time
USERNAME
SESSION#
SERIAL# OPERATION
-------------------- -------------------------------- ---------- --------- -------------------------------SESSION_INFO
----------------------------------------------------------------------------------------------------------------------------------07-aug-2003 09:00:05 TIMS
8
4975 INSERT
LoginUserName = TIMS, ClientInfo = , OsUserName = Mittra, MachineName =
DTS-57\CSC-TIMS33
. . . . . . . . . . .
2 rows selected.
3.2
Scope of LogMiner under Oracle 9i
LogMiner under 9i has several new features beyond what are available under 8i.
I am describing below only two of them that I find useful.
(a)
The LogMiner dictionary is dynamic instead of being static as under 8i.
Under 8i, any transactions entered after the start of a LogMiner session
are not recorded into the dictionary. But under 9i, the LogMiner dictionary
is dynamically updated from the online data dictionary via the option
DICT_FROM_ONLINE_CATALOG. This feature is explained further with
examples in the Session Transcript under Section 3.2.2 (a).
(b)
LogMiner supports DDL statements by ensuring that its internal dictionary
is updated if a DDL event is found in the Redo Log files. This ensures
that SQL_REDO and SQL_UNDO information is correct for objects that
25
are created or modified in the Redo Log files after the LogMiner internal
dictionary was built. The column V$LOGMNR_CONTENTS.OPERATION
returns the value “DDL” and the column SQL_REDO contains the actual
DDL statement for the operation. But this feature is not available with the
option DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG that we have
used. It is available in only two cases:

The dictionary in use is a flat file created via the procedure
DBMS_LOGMNR_D.BUILD

The dictionary is built from the redo log files via the procedure
DBMS_LOGMNR. START_LOGMNR.DICT_FROM_REDO_LOGS
3.2.1 Installation and Operation of LogMiner under Oracle 9i
(a)
(b)
(c)
(d)
(e)
(f)
Include the initialization parameter utl_file_dir in the init.ora file. The value
of this parameter will be an existing directory to which Oracle has
permissions to write as needed by the PL/SQL procedure
DBMS_LOGMNR_D.BUILD, if used.
If necessary, shutdown the instance and then startup for the new
parameter to take effect. It cannot be changed via the ALTER SYSTEM
command.
Run the script $ORACLE_HOME/rdbms/admin/dbmslm.sql to create the
package DBMS_LOGMNR with the five procedures, ADD_LOGFILE,
START_LOGMNR, END_LOGMNR, MINE_VALUE, and
COLUMN_PRESENT, needed for LogMiner analysis.
Include Redo Log files for LogMiner analysis.
Start a LogMiner session.
End the session by executing the script
DBMS_LOGMNR.END_LOGMNR.
This procedure MUST be called prior to exiting the LogMiner session.
Otherwise, Oracle generates a silent ORA-00600 error because the PGA
is found to be bigger at logoff than it was at logon, which is considered a
space leak.
Appendix 2 contains all the scripts used in the session transcript below.
Comparing the above steps with those in Section 3.1.1 we find that steps (c) and
(d) of Section 3.1.1 are not needed. This happens because the LogMiner
dictionary is not created as a flat file. The option
SYS.DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG used in step (e)
creates the LogMiner dictionary from the online data dictionary and keeps it
continually updated.
If we want to create the LogMiner dictionary as a flat file, then we need the
procedure DBMS_LOGMNR_D to execute the following procedure:
26
BEGIN
sys.dbms_logmnr_d.build (
dictionary_filename=> 'logminer_dictionary_oracle.dic',
dictionary_location => 'LOCATION'
);
END;
/
Here 'LOCATION' will be the value returned by the following query:
select value from v$parameter where name = 'utl_file_dir';
But the dictionary file created as a flat file will remain static. It will not reflect
changes made after the start of a LogMiner session as under Oracle 8i.
3.2.2 Output from LogMiner under Oracle 9i
(a)
SQL_REDO and SQL_UNDO
The output below is very similar to the one provided in Section 3.1.2. Note that
after the LogMiner session was started, one insert, two updates, and one delete
were made. They were all included in the SQL_REDO and SQL_UNDO values
generated after these transactions. We may contrast this situation with one we
encountered in Section 3.1.1 where the table TEST_LOG_MINER was not
included in the LogMiner dictionary because the table was created and
populated after the static LogMiner dictionary was created.
Session Transcript
09:25:42 SQL> select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss')
"Transaction Time", username,
09:25:49
2 sql_redo, sql_undo from v$logmnr_contents
09:25:58
3 where TABLE_SPACE = 'TIMSDATA'
09:26:08
4 and to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') > '04aug-2003 11:24:27'
09:27:05
5 order by 1;
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------04-aug-2003 11:25:06 SYS
insert into "TIMS"."EXPLORE"("COL01","COL02","COL03","COL04") values
('35128','a
vav',TO_DATE('02-AUG-03', 'DD-MON-RR'),'17');
delete from "TIMS"."EXPLORE" where "COL01" = '35128' and "COL02" =
'avav' and "C
OL03" = TO_DATE('02-AUG-03', 'DD-MON-RR') and "COL04" = '17' and ROWID =
'AAAHw/
27
AMgAAAM/7AAE';
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------04-aug-2003 12:10:26 TIMS
insert into "TIMS"."EXPLORE_COPY"("COL01","COL02","COL03","COL04")
values ('8766
','Mittra',TO_DATE('06-AUG-03', 'DD-MON-RR'),'11');
delete from "TIMS"."EXPLORE_COPY" where "COL01" = '8766' and "COL02" =
'Mittra'
and "COL03" = TO_DATE('06-AUG-03', 'DD-MON-RR') and "COL04" = '11' and
ROWID = '
AAAHxBAMgAAASOVAAA';
. . . . . . .
4 rows selected.
09:40:48 SQL> insert into tims.explore values (6513, 'Indumati', sysdate
- 3, 16);
1 row created.
09:41:24 SQL> update tims.explore
09:41:31
2 set col02 = sysdate where col01 = 35128;
2 rows updated.
09:43:31 SQL> delete from tims.explore_copy where col02 = 'cxxc';
1 row deleted.
09:44:14 SQL> select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss')
"Transaction Time", username,
09:45:14
2 sql_redo, sql_undo from v$logmnr_contents
09:45:27
3 where TABLE_SPACE = 'TIMSDATA'
09:45:39
4 and to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') > '04aug-2003 11:24:27'
09:45:53
5 order by 1;
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------04-aug-2003 11:25:06 SYS
insert into "TIMS"."EXPLORE"("COL01","COL02","COL03","COL04") values
('35128','a
vav',TO_DATE('02-AUG-03', 'DD-MON-RR'),'17');
delete from "TIMS"."EXPLORE" where "COL01" = '35128' and "COL02" =
'avav' and "C
28
OL03" = TO_DATE('02-AUG-03', 'DD-MON-RR') and "COL04" = '17' and ROWID =
'AAAHw/
AMgAAAM/7AAE';
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------04-aug-2003 12:10:26 TIMS
insert into "TIMS"."EXPLORE_COPY"("COL01","COL02","COL03","COL04")
values ('8766
','Mittra',TO_DATE('06-AUG-03', 'DD-MON-RR'),'11');
delete from "TIMS"."EXPLORE_COPY" where "COL01" = '8766' and "COL02" =
'Mittra'
and "COL03" = TO_DATE('06-AUG-03', 'DD-MON-RR') and "COL04" = '11' and
ROWID = '
AAAHxBAMgAAASOVAAA';
. . . . . . . .
05-aug-2003 09:41:11 SYS
insert into "TIMS"."EXPLORE"("COL01","COL02","COL03","COL04") values
('6513','In
dumati',TO_DATE('02-AUG-03', 'DD-MON-RR'),'16');
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------delete from "TIMS"."EXPLORE" where "COL01" = '6513' and "COL02" =
'Indumati' and
"COL03" = TO_DATE('02-AUG-03', 'DD-MON-RR') and "COL04" = '16' and
ROWID = 'AAA
Hw/AMgAAAM/7AAG';
05-aug-2003 09:42:30 SYS
update "TIMS"."EXPLORE" set "COL02" = '05-AUG-03' where "COL02" = 'avav'
and ROW
ID = 'AAAHw/AMgAAAM/7AAD';
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------update "TIMS"."EXPLORE" set "COL02" = 'avav' where "COL02" = '05-AUG-03'
and ROW
ID = 'AAAHw/AMgAAAM/7AAD';
29
05-aug-2003 09:42:30 SYS
update "TIMS"."EXPLORE" set "COL02" = '05-AUG-03' where "COL02" = 'avav'
and ROW
ID = 'AAAHw/AMgAAAM/7AAE';
update "TIMS"."EXPLORE" set "COL02" = 'avav' where "COL02" = '05-AUG-03'
and ROW
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------ID = 'AAAHw/AMgAAAM/7AAE';
05-aug-2003 09:44:16 SYS
delete from "TIMS"."EXPLORE_COPY" where "COL01" = '2013' and "COL02" =
'cxxc' an
d "COL03" = TO_DATE('04-AUG-03', 'DD-MON-RR') and "COL04" = '11' and
ROWID = 'AA
AHxBAMgAAASOUAAB';
insert into "TIMS"."EXPLORE_COPY"("COL01","COL02","COL03","COL04")
values ('2013
Transaction Time
USERNAME
-------------------- -----------------------------SQL_REDO
------------------------------------------------------------------------------SQL_UNDO
------------------------------------------------------------------------------','cxxc',TO_DATE('04-AUG-03', 'DD-MON-RR'),'11');
8 rows selected.
Note that the INSERT, UPDATE, and DELETE transactions that were made after
the start of the LogMiner session have been picked up by the last query above.
This shows that the LogMiner dictionary is dynamically updated during the
session.
(b)
SESSION_INFO and Related Columns
The column V$LOGMNR_CONTENTS.SESSION_INFO returns user identifying
information such as LoginUserName and OsUserName. Unless both of them
are generic such as SYS, ORACLE, TESTER, APPLDBA, etc., the DBA can
identify the individual user. If both are generic, there is no way to identify the
user logging under the generic names. Therefore, such generic user names
should not be allowed at least at the operating system level.
Session Transcript
30
10:34:41 SQL> select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss')
"Transaction Time", username,
10:36:01
2 session#, serial#, operation, session_info
10:36:53
3 from v$logmnr_contents
10:37:04
4 where TABLE_SPACE = 'TIMSDATA'
10:37:21
5 and to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') > '04aug-2003 11:24:27'
10:38:02
6 order by 1;
Transaction Time
USERNAME
SESSION#
SERIAL#
-------------------- ------------------------------ ---------- --------OPERATION
-------------------------------SESSION_INFO
------------------------------------------------------------------------------04-aug-2003 11:25:06 SYS
19
23394
INSERT
login_username=TIMS client_info= OS_username=Mittra Machine_name=DTS57\CSC-TIMS
33
04-aug-2003 12:10:26 TIMS
23394
INSERT
19
Transaction Time
USERNAME
SESSION#
SERIAL#
-------------------- ------------------------------ ---------- --------OPERATION
-------------------------------SESSION_INFO
------------------------------------------------------------------------------login_username=TIMS client_info= OS_username=Mittra Machine_name=DTS57\CSC-TIMS
33
04-aug-2003 13:42:56 SYS
15
13040
INSERT
login_username=TIMS client_info= OS_username=oracle Machine_name=dba8
OS_termina
l=pts/1 OS_process_id=12524 OS_program name=sqlplus@dba8 (TNS V1-V3)
3.3
Two Issues Worth Mentioning
Two specific issues need some mention here.
(a)
LogMiner must be invoked afresh with each new session. All LogMiner
session information resides in the PGA (Program Global Area) which is a
component of the SGA (System Global Area). PGA is flushed when a
user session ends normally or abnormally and all the session information
is lost. This holds for both Oracle 8i and 9i.
31
A session ends normally when the user executes the procedure
DBMS_LOGMNR.END_LOGMNR to end the session. A session ends
abnormally generating a silent internal Oracle error ORA-00600 when the
user types “exit” or issues the command “connect username/password” to
login as a different user without exiting.
Session Transcript
dba8% sqlplus /nolog
SQL*Plus: Release 9.2.0.3.0 - Production on Fri Aug 1 11:53:07 2003
Copyright (c) 1982, 2002, Oracle Corporation.
SQL> connect / as sysdba
Connected.
SQL> show user
USER is "SYS"
SQL> @include_redo_logs_monami.sql
All rights reserved.
(SESSION AS USER “SYS” STARTS)
(LOG MINER IS INVOKED HERE)
PL/SQL procedure successfully completed.
SQL> @start_logminer_monami.sql
PL/SQL procedure successfully completed.
SQL> connect tims/*******
(SESSION AS USER “SYS” ENDS
Connected.
ABNORMALLY. THE PGA IS FLUSHED.)
SQL> show user
(NEW SESSION AS USER “TIMS” STARTS)
USER is "TIMS"
SQL> select to_char (timestamp, 'dd-mon-yyyy hh24:mi:ss') "Transaction
Time", username,
2 sql_redo, sql_undo from v$logmnr_contents
3 where TABLE_SPACE = 'TIMSDATA'
4 order by 1 desc;
sql_redo, sql_undo from v$logmnr_contents
*
ERROR at line 2:
ORA-01306: dbms_logmnr.start_logmnr() must be invoked before selecting
from v$logmnr_contents
(NOTE:
(b)
PGA FOR SESSION “SYS” HAS BEEN FLUSHED. NEW SESSION “TIMS”
NEEDS A NEW LOG MINER SESSION.)
By default all LogMiner tables are created in the SYSTEM tablespace. As
a result, the SYSTEM tablespace may get fragmented over time. To
avoid this problem Oracle recommends that a separate tablespace be
created to store the tables created and used by LogMiner. The procedure
DBMS_LOGMNR_D.SET_TABLESPACE can be used to create such a
tablespace.
In the example below a tablespace named LOGMNR_TBLSPC is created
for storing the LogMiner segments. As a result, 60 of the LOGMNR
32
segments are stored in LOGMNR_TBLSPC tablespace and the remaining
27 segments in SYSTEM tablespace.
Session Transcript
SQL> create tablespace logmnr_tblspc
2 datafile
'/tims1/ssmittra/dev01/monami_instance/logminer/LOGMNR_TBLSPC01.dbf'
3 size 200M;
Tablespace created.
SQL> commit;
Commit complete.
SQL> EXEC DBMS_LOGMNR_D.SET_TABLESPACE ('logmnr_tblspc');
PL/SQL procedure successfully completed.
SQL> @LogMiner_Session_9203.sql
PL/SQL procedure successfully completed.
PL/SQL procedure successfully completed.
SQL> col TABLESPACE_NAME format a15
SQL> col segment_name format a60
SQL> select tablespace_name, segment_name from dba_segments where
segment_name like 'LOGMNR%'
2 order by 1, 2;
(Partial output shown below)
TABLESPACE_NAME
--------------LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
LOGMNR_TBLSPC
SEGMENT_NAME
-------------------------------------------------------LOGMNRC_DBNAME_UID_MAP
LOGMNRC_DBNAME_UID_MAP_PK
LOGMNRC_GSII
LOGMNRC_GSII_PK
LOGMNRC_GTCS
LOGMNRC_GTCS_PK
LOGMNRC_GTLO
LOGMNRC_GTLO_PK
LOGMNR_AGE_SPILL$
. . . . . . . . . . .
TABLESPACE_NAME
--------------SYSTEM
SYSTEM
SYSTEM
SEGMENT_NAME
-------------------------------------------------------LOGMNRG_TABCOMPART$
LOGMNRG_TABPART$
LOGMNRG_TABSUBPART$
33
SYSTEM
SYSTEM
SYSTEM
SYSTEM
SYSTEM
SYSTEM
SYSTEM
LOGMNRG_TS$
LOGMNRG_TYPE$
LOGMNRG_USER$
LOGMNR_HEADER1$
LOGMNR_HEADER2$
LOGMNR_INTERESTING_COLS
LOGMNR_SESSION$
87 rows selected.
4.
Roadmap for Ensuring Data Security in Oracle Databases
A DBA needs to be vigilant to protect the contents of a database. Prevention,
detection, and correction of harmful user activities, intentional or unintentional,
as discussed above provide a roadmap for such an endeavor. Both AUDIT
TRAIL and LogMiner provide a timestamp for every user activity. As a result, a
DBA can identify the time of occurrence of a malicious activity up to the second.
To bring the database back to a consistent state the DBA can restore it to a point
in time prior to the occurrence of that event.
In addition, it is necessary for any organization to have a database security plan
in place and to review it on a regular basis, say every three months. As far as
possible, generic user accounts for the operating system or for Oracle should not
be allowed. Also, no privilege should be granted to the user PUBLIC (see
Section 1.8).
5.
Bibliography
1.
Kevin Loney and Marlene Theriault – Oracle 8i DBA Handbook, Chapter
9, Oracle Press, 2000.
Kevin Loney and Marlene Theriault – Oracle 9i DBA Handbook, Chapters
10 and 11, Oracle Press, 2002.
Sitansu S. Mittra – Database Performance Tuning and Optimization Using
Oracle, Chapter 5, Springer-Verlag, 2003.
Oracle MetaLink – papers on LogMiner; e.g., Notes 62508.1, 111886.1,
etc.
Marlene Theriault and Aaron Newman – Oracle Security Handbook,
Chapters 16 and 17, Oracle Press, 2001.
2.
3.
4.
5.
34
Appendix 1
LogMiner Scripts for Oracle 8i
1.
LogMiner_Session_8174.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/LogMiner_Session_8174.sql
REM
Purpose: provide a single command file to run a Log Miner Session
under Oracle 8i.
set scan on
column get_location new_value LogMiner_Session_spool_file noprint
select 'LogMiner_Session_' || TO_CHAR(SYSDATE, 'DD-MON-YYYY') || '.log'
get_location from dual;
spool
/tims1/ssmittra/dev01/monami_instance/logminer/logs/&LogMiner_Session_sp
ool_file
@create_logmnr_dict_8174.sql
@include_redo_logs_8174.sql
@start_logminer_8174.sql
spool off
2.
create_logmnr_dict_8174.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/create_logmnr_dict_8174.s
ql
BEGIN
sys.dbms_logmnr_d.build (
dictionary_filename=> 'logminer_dictionary_oracle.dic',
dictionary_location =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs'
);
END;
/
3.
include_redo_logs_8174.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/include_redo_logs_8174.sq
l
REM
Purpose: Include all redo log files for Log Miner analysis under
Oracle 8i
BEGIN
SYS.DBMS_LOGMNR.ADD_LOGFILE(
35
'/home/oracle/oradata/tims/dba/ssmittra/monami_A01.rdl',
dbms_logmnr.NEW);
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/dba/ssmittra/monami_A02.rdl',
dbms_logmnr.ADDFILE);
END;
/
4.
start_logminer_8174.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/start_logminer_8174.sql
REM
Purpose: Start Log Miner for analyzing the Redo Log files under
Oracle 8i.
EXECUTE SYS.DBMS_LOGMNR.START_LOGMNR( DICTFILENAME =>
'/tims1/ssmittra/dev01/monami_instance/logminer/logs/logminer_dictionary
_oracle.dic');
36
Appendix 2
LogMiner Scripts for Oracle 9i
1.
LogMiner_Session_9203.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/LogMiner_Session_9203.sql
REM
Purpose: provide a single command file to run a Log Miner Session
under Oracle 9i.
set scan on
column get_location new_value LogMiner_Session_spool_file noprint
select 'LogMiner_Session_' || TO_CHAR(SYSDATE, 'DD-MON-YYYY') || '.log'
get_location from dual;
spool
/tims1/ssmittra/dev01/monami_instance/logminer/logs/&LogMiner_Session_sp
ool_file
@include_redo_logs_9203.sql
@start_logminer_9203.sql
spool off
2.
include_redo_logs_9203.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/include_redo_logs_9203.sq
l
REM
Purpose: Include all redo log files for Log Miner analysis under
Oracle 9i
BEGIN
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/admin/system/redoA01.log',
SYS.dbms_logmnr.NEW);
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/admin/system/redoA02.log',
SYS.dbms_logmnr.ADDFILE);
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/admin/system/redoA03.log',
SYS.dbms_logmnr.ADDFILE);
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/admin/system/redoA04.log',
SYS.dbms_logmnr.ADDFILE);
SYS.DBMS_LOGMNR.ADD_LOGFILE(
'/home/oracle/oradata/tims/admin/system/redoA05.log',
37
SYS.dbms_logmnr.ADDFILE);
END;
/
3.
start_logminer_9203.sql
REM
File =
/tims1/ssmittra/dev01/monami_instance/logminer/start_logminer_9203.sql
REM
Purpose: Start Log Miner for analyzing the Redo Log files under
Oracle 9i.
EXECUTE SYS.DBMS_LOGMNR.START_LOGMNR( OPTIONS => SYS.DBMS_LOGMNR.DICT_FROM_ONLINE_CATALOG);