Tuesday, January 14, 2014

Protecting SSH Accesss

Problem

In home instead of a typical router I have a PandaBoard with Debian installed. This very flexible solution allows for running fully customized firewall (iptables), web-proxy (squid) with parental-control and blacklists (dansguardian). This box is a front device of my internal network and allows SSH access. I was rather uncomfortable observing logwatch reports which say about continuous break-in attempts into root and other accounts. While it is quite impossible to guess my password, I rarely change it, so it could be somehow hijacked. So I made a few additional obstacles to reach the SSH while keeping it relatively simple to use.

First option is to limit the access to SSH service itself by terms of PAM. Here are requirements. First I edited /etc/pam.d/sshd file and uncommented third line in the excerpt below:

[...]
# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
account  required     pam_access.so
Then I adjusted /etc/security/access.conf:
[...]
+ : root : 10.1.     89.174.214.
+ : root : kedra.org .kedra.org
# User "root" should be denied to get access from all other sources.
- : root : ALL
# jurek accesses from all sources
+ : jurek : ALL
Above looks good enough to limit unauthorized access for root. The local network and known remote locations are granted SSH access to root. Connection as root from other location is impossible.

OneTimePasswords

Google Authenticator is one time passwords generator, which is use to protect my Gmail and AWS accounts. It gives my a sense of security - without my phone which generates one time password, it is very hard to gain the access to the account. Naturally one time password is an additional level of access so it means I have to provide the classic password + the Google Authenticator one.

First step is to install libpam-google-authenticator (apt-get install), then create an access file which allows to skip pam_google_authenticator when connecting from local network (/etc/security/access-local.conf) with the following content:

# only allow from local IP range
+ : ALL : 10.1.0.0/24
+ : ALL : LOCAL
- : ALL : ALL

then adjust /etc/pam.d/sshd:

[...]
# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
account  required     pam_access.so

# skip one-time password if logging in from the local network
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/access-local.conf
auth required pam_google_authenticator.so

# Standard Un*x authorization.
@include common-account

# Standard Un*x session setup and teardown.
@include common-session
[...]

The last change is to allow for one time passwords authentication in /etc/ssh/sshd_config:


# Change to yes to enable challenge-response passwords (beware issues with
# some PAM modules and threads)
ChallengeResponseAuthentication yes

Restart the SSH daemon /etc/init.d/ssh restart and generate the key by google-authenticator. The command is verbose and intuitive. On my Android phone I use "Google Authenticator" - it supports QR code scanning or I have to retype just generated key from google-authenticator command. The google-authenticator command creates ~/.google_authenticator only-owner-readable file which stores the key. That's should be it - it works. Well not really.


Configuration Extension

Google Authenticator setup in a way as above is a global configuration for all users. It means the given user has to create its own .google_authenticator file (can't be system shared file until you want to have it world readable) or the user won't be able to login. This is not really what I want here. I'd like to have a situation when user (actually me only) has an option to decide by himself if he wants or not to be protected by it. I'd like also an option to have only a single key (.google_authentication file) but I don't like the idea of having it readable for all users.

There are multiple options to archive above goals. The most straightforward is suggested by the google-authenticator man page. It requires to add a following line:
auth [default=1 success=ignore] pam_succeed_if.so quiet user ingroup root
auth required pam_google_authenticator.so

It requires for user to be in group "root" (last argument) before GoogleAuth is required. I'm not PAM guru so in effect it removed the effect of previous line, that with accessfile=/etc/security/access-local.conf. There is probably an option to overcome it somehow but there was no curiosity to follow this path.

apt-get remove libpam-google-authenticator
apt-get install libpam0g-dev libqrencode3
wget https://google-authenticator.googlecode.com/files/libpam-google-authenticator-1.0-source.tar.bz2
You can check if there is a new version here.
tar jvxf libpam-google-authenticator-1.0-source.tar.bz2
cd libpam-google-authenticator-1.0/
make
make install

Now I can log in without one time password for users where .google_authenticator file is not present the home directory. I also can preview one-time-passwords when typing. The sshd_config needs to be adjusted:
auth required pam_google_authenticator.so nullok echo_verification_code
This is something good to know and good to have. However, since I'm the only user of the system, I'd rather have a common .google_authenticator file, root owned, root only readable. For the internal network I'd like to login without one time passwords, but for the external I want to have it as mandatory. So the final solution is:
# Uncomment and edit /etc/security/access.conf if you need to set complex
# access limits that are hard to express in sshd_config.
#account required pam_access.so

# skip one-time password if logging in from the local network
auth [success=1 default=ignore] pam_access.so accessfile=/etc/security/access-local.conf
auth required pam_google_authenticator.so user=root secret=/root/.google_authenticator echo_verification_code

Finally I decided to open the SSH world wide, no exceptions (pam_access.so commented out in /etc/pam.d/sshd).

References

  1. Remi Bergsma's blog
  2.  How to Setup Two-Factor Authentication (Google Authenticator) for SSH Logins

Friday, January 10, 2014

JDBC Connection Failover

FAN

With JDBC thin 11.2 and simplefan.jar (oracle.simplefan package) I was able to perform tests only with ONS client running locally. The program and the test environment has been described at Martin Bach's blog. Ons can be installed with the full version of Oracle 11.2 Windows client (standard install). It requires changes in the ons.config: usesharedinstall=false and nodes=node1:6200,node2:6200,node3:6200. By default usessharedinstall is set to true, which makes the lock file appending the hostname to it. Consequently it renders the example being not able to found it by the standard name. I didn't investigate how to fix it at the code level.

Speaking on JDBC thin it is suprising how little of information I could find in the Internet. The only valuable information from Oracle comes with Oracle Database RAC FAN Events Java 11g Release 2 (11.2) E13993-01 and there is not working example in Oracle Database JDBC Developer's Guide 11g Release 2 (11.2). Not working not only because it is not quite complete, but because it refers to not existing methods: Actually didn't find methods like getServiceMemberStatus, getServiceCompositeEvent and some others within simplefan.jar and the above API documentation. Searching with Google for these methods returns the above (not working) example only. In a similar way, existing function don't handle coming events properly. The "SHUTDOWN" event is an example here.

The code below is original Oracle's example mixed with Martin Bach's code:

package org.kedra.fan1;
import java.util.Properties;
import oracle.simplefan.FanEventListener;
import oracle.simplefan.FanManager;
import oracle.simplefan.FanSubscription;
import oracle.simplefan.LoadAdvisoryEvent;
import oracle.simplefan.NodeDownEvent;
import oracle.simplefan.ServiceDownEvent;
import oracle.simplefan.ServiceDownEvent.ServiceMemberEvent;

public class Test1 {
 Test1() {
  FanManager fm = FanManager.getInstance();

  //Properties fmProps = new Properties();
  //fmProps.setProperty("onsNodes",
  //  "plabb241:6200,plabb230:6200,plabb229:6200");
  // fmProps.setProperty(key, value)
  // fm.configure(fmProps);

  System.setProperty("oracle.ons.oraclehome",
    "c:\\Oracle2\\product\\11.2.0\\client_1");
  System.out.println(System.getProperty("oracle.ons.oraclehome"));

  Properties props = new Properties();
  props.put("serviceName", "AMQS1");

  FanSubscription sub = fm.subscribe(props);
  System.out.println("I'm subscribed!");

  sub.addListener(new FanEventListener() {

   public void handleEvent(ServiceDownEvent event) {
    System.out.println("ServiceDownEvent!");

    try {
     System.out.println(event.getTimestamp());
     System.out.println("getServiceName: "
       + event.getServiceName());
     System.out.println("getDatabaseUniqueName: "
       + event.getDatabaseUniqueName());
     System.out.println("getReason: " + event.getReason());
     System.out.println("getKind: " + event.getKind());

     ServiceMemberEvent me = event.getServiceMemberEvent();
     if (me != null) {
      System.out.println("getServiceMemberEvent");
      System.out.println("\t getInstanceName: "
        + me.getInstanceName());
      System.out.println("\t getNodeName: "
        + me.getNodeName());
      // System.out.println(me.getServiceMemberStatus());
     }
     // ServiceCompositeEvent ce = se.getServiceCompositeEvent();
     // if (ce != null) {
     // System.out.println(ce.getServiceCompositeStatus());
     // }
    } catch (Throwable t) {
     // handle all exceptions and errors
     System.err.println("handleEvent - ServiceDownEvent");
     t.printStackTrace(System.err);
    }
   }

   public void handleEvent(NodeDownEvent event) {
    System.out.println("Node Down Event!");

    try {
     System.out.println(event.getTimestamp());
     System.out.println("getNodeName: " + event.getNodeName());
     // ServiceCompositeEvent ce = se.getServiceCompositeEvent();
     // if (ce != null) {
     // System.out.println(ce.getServiceCompositeStatus());
     // }
    } catch (Throwable t) {
     System.err.println("handleEvent - ServiceDownEvent");
     t.printStackTrace(System.err);
    }
   }

   public void handleEvent(LoadAdvisoryEvent arg0) {
    System.out.println("Load Advisory event");

    System.out.println("originating database: "
      + arg0.getDatabaseUniqueName());
    System.out.println("originating instance: "
      + arg0.getInstanceName());
    System.out.println("Service Quality     : "
      + arg0.getServiceQuality());
    System.out.println("Percent             : " + arg0.getPercent());
    System.out.println("Service Name        : "
      + arg0.getServiceName());
    System.out.println("Service Quality     : "
      + arg0.getServiceQuality());
    System.out.println("Observed at         : "
      + arg0.getTimestamp() + "\n\n");
   }
  });
 }

 public static void main(String[] args) {
  Test1 tc = new Test1();

  int i = 0;
  while (i < 100000) {
   try {
    Thread.sleep(100);
    i++;
   } catch (Exception e) {
    System.out.println(e);
   }
  }

  System.out.println("execution ended");
 }
}

I would like to see a support for a remote ONS. There is a method configure() in the FanManager class which takes a list of ONS servers but requires mandatory oracle wallet and password as well. This is not something I expect - for I don't want the communication with ONS server over SSL.

Oracle admits it is "the initial release" so the functionality of this library is fairly limited.

Fast Connection Failover

Fast Connection Failover (FCF) and for JDBC thin it us usable with Universal Connection Pool (UCP). There is an option to use JDBC Implicit Connection Cache (ICC) but Oracle considers the feature to be replaced by UCP.

  1. Automatic Workload Management with Oracle Real Application Clusters 11g Release 2 - FAN, FCF
  2. Maximum Availability Architecture, Oracle Best Practices For High Availability: Client Failover Best Practices for Highly Available Oracle  Databases: Oracle Database 11g Release 2 - Standby database oriented.
  3. Fast Connection Failover Example JDBC Thin - this is about 10g High Availability and JDBC. Requires ons.jar or ONS working on the client side. Great resource for hands-on experience.
  4. How to Verify Universal Connection Pool (UCP) / Fast Connection Failover (FCF) Setup (Metalink Doc ID 1064652.1)
  5. JDBC and Universal Connection Pool
  6. UCP Demos Page (Oracle)
  7. TAF vs FAN, FCF vs ONS
  8.  Metalink Resources:


    Monday, December 30, 2013

    Oracle's New Features

    Top New Features As Used by Me

    Subquery Factoring aka WITH clause

    What a surprise such the useful clause has been ignored by me until now. And it is here since 9i. I found it in a book "Cost Based Oracle: Fundamentals" by Jonathan Lewis. There is an in-depth article at Oracle-Base about the feature.

    Virtual Columns

    The virtual column is an extra column in a table which can be a result of calculation based on existing real columns. It came with Oracle 11g and simplified queries very much. It can be used for table partitioning,

    Monday, October 21, 2013

    Corkscrew

       I work in a place where I have no direct access to the outside world in a way other than HTTP (through an authenticated proxy) and email. However sometimes I need to access the external world, usually through SSH to pick some external resources, push GIT repository or so. And this is not a problem with PuTTY for it has a variety proxies build-in:





       But while working on my Linux running on Oracle VirtualBox I have to rely on pure OpenSSH only. And there is no HTTP proxy support in OpenSSH just out of the box. And there is a solution for OpenSSH as well - this is Corkscrew, a small utility but it does the work and supports HTTP authentication even!


    For github.com purpose I use following config in the file ~/.ssh/config:

    Host github.com
      ProxyCommand corkscrew proxy.acme.com 80 %h %p ~/.ssh/proxyauth
      ServerAliveInterval 60


    In the ssh config above the clause "Host github.com" means the configuration applies only for the target like ssh git@github.com. And this is exactly what git is doing when pushing to a github repository. It pushes through ssh. Following clause "ProxyCommand corkscrew [...]" means ssh has to run corkscrew commands with the following arguments. Here you have the simplest corkscrew syntax:

    $ corkscrew -h
    corkscrew 2.0 (agroman@agroman.net)
    usage: corkscrew <proxyhost> <proxyport> <desthost> <destport> [authfile]
    $


    First two arguments identify the proxy and its port Proxy.acme.com 80. The target hostname and the port is delivered by ssh itself through variables %h and %p. The last argument is the auth file - if you need credentials for your proxy, create a file, insert the username:password inside (just one line) and your connection through proxy will be authenticated. Usually you don't need it.
    The extra line with ServerAliveInterval is useful when I have an idle interactive ssh connection. You can safely remove it from github.com configuration.

    That's it! Try it out.

    Links

    1. Corkscrew homepage.
    2. Corkscrew, how to setup.

    Tuesday, October 15, 2013

    FGA Notes

    FGA Notes @11G


    To create a fine-grained audit policy, you must have EXECUTE privileges on the DBMS_FGA PL/SQL package. The package is owned by the SYS user.

    To create a fine-grained audit policy, use the DBMS_FGA.ADD_POLICY procedure. This procedure creates an audit policy using the supplied predicate as the audit condition. Oracle Database executes the policy predicate with the privileges of the user who created the policy. The maximum number of fine-grained policies on any table or view object is 256. Oracle Database stores the policy in the data dictionary table, but you can create the policy on any table or view that is not in the SYS schema.
    After you create the fine-grained audit policy, it does not reside in any specific schema, although the definition for the policy is stored in the SYS.FGA$ data dictionary table.
    You cannot modify a fine-grained audit policy after you have created it. If you need to modify the policy, drop it and then recreate it.

    DBMS_FGA.ADD_POLICY(
       object_schema      VARCHAR2, 
       object_name        VARCHAR2, 
       policy_name        VARCHAR2, 
       audit_condition    VARCHAR2, 
       audit_column       VARCHAR2, 
       handler_schema     VARCHAR2, 
       handler_module     VARCHAR2, 
       enable             BOOLEAN, 
       statement_types    VARCHAR2,
       audit_trail        BINARY_INTEGER IN DEFAULT,
       audit_column_opts  BINARY_INTEGER IN DEFAULT);
     
    In this specification:
    • object_schema: Specifies the schema of the object to be audited. (If NULL, the current log-on user schema is assumed.)
    • object_name: Specifies the name of the object to be audited.
    • policy_name: Specifies the name of the policy to be created. Ensure that this name is unique.
    • audit_condition: Specifies a Boolean condition in a row. NULL is allowed and acts as TRUE. See "Auditing Specific Columns and Rows" for more information. If you specify NULL or no audit condition, then any action on a table with that policy creates an audit record, whether or not rows are returned
    • audit_column: Specifies one or more columns to audit, including hidden columns. If set to NULL or omitted, all columns are audited. These can include Oracle Label Security hidden columns or object type columns. The default, NULL, causes audit if any column is accessed or affected.
    • handler_schema: If an alert is used to trigger a response when the policy is violated, specifies the name of the schema that contains the event handler. The default, NULL, uses the current schema. See also "Tutorial: Adding an Email Alert to a Fine-Grained Audit Policy".
    • handler_module: Specifies the name of the event handler. Include the package the event handler is in. This function is invoked only after the first row that matches the audit condition in the query is processed.
      Follow these guidelines:
      • Do not create recursive fine-grained audit handlers. For example, suppose you create a handler that executes an INSERT statement on the HR.EMPLOYEES table. The policy that is associated with this handler is for INSERT statements (as set by the statement_types parameter). When the policy is used, the handler executes recursively until the system has run out of memory. This can raise the error ORA-1000: maximum open cursors exceeded or ORA-00036: maximum number of recursive SQL levels (50) exceeded.
      • Do not issue the DBMS_FGA.ENABLE_POLICY or DBMS_FGA.DISABLE_POLICY statement from a policy handler. Doing so can raise the ORA-28144: Failed to execute fine-grained audit handler error.
    • enable: Enables or disables the policy using true or false. If omitted, the policy is enabled. The default is TRUE.
    • statement_types: Specifies the SQL statements to be audited: INSERT, UPDATE, DELETE, or SELECT only.
    • audit_trail: Specifies the destination (DB or XML) of fine-grained audit records. Also specifies whether to populate LSQLTEXT and LSQLBIND in FGA_LOG$. However, be aware that sensitive data, such as credit card information, can be recorded in clear text. See "Auditing Sensitive Information" for how you can handle this scenario.
      If you set the audit_trail parameter to XML, then the XML files are written to the directory specified by the AUDIT_FILE_DEST initialization parameter.
      For read-only databases, Oracle Database writes the fine-grained audit trail to XML files, regardless of the audit_trail setting.
    • audit_column_opts: If you specify more than one column in the audit_column parameter, then this parameter determines whether to audit all or specific columns. See "Auditing Specific Columns and Rows" for more information.
    BEGIN
      DBMS_FGA.ADD_POLICY(
       object_schema      => 'HR',
       object_name        => 'EMPLOYEES',
       policy_name        => 'chk_hr_employees',
       enable             =>  TRUE,
       statement_types    => 'INSERT, UPDATE, SELECT, DELETE',
       audit_trail        =>  DBMS_FGA.DB+DBMS_FGA.EXTENDED);
    END;
    /
    
    DBMS_FGA.DISABLE_POLICY(
      object_schema        => 'HR',
      object_name          => 'EMPLOYEES',
      policy_name          => 'chk_hr_employees');
    
    DBMS_FGA.DROP_POLICY(
      object_schema      => 'HR',
      object_name        => 'EMPLOYEES',
      policy_name        => 'chk_hr_employees'); 
     
    SELECT * FROM DBA_AUDIT_POLICIES; 
     
     
    SYS@DEV1> show parameter audit_trail;
    NAME                                 TYPE        VALUE
    ------------------------------------ ----------- ------------------------------
    audit_trail                          string      DB 
     
    SYS@DEV1> SET SERVEROUTPUT ON
    BEGIN
    IF
    DBMS_AUDIT_MGMT.IS_CLEANUP_INITIALIZED(
               DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD)
      THEN
         DBMS_OUTPUT.PUT_LINE('AUD$ is initialized for cleanup');
      ELSE
         DBMS_OUTPUT.PUT_LINE('AUD$ is not initialized for cleanup.');
      END IF;
    END;
    SYS@DEV1>
    AUD$ is not initialized for cleanup.
    PL/SQL procedure successfully completed.
    SYS@DEV1>
     
    Here is an excerpt form the documentation: DEFAULT_CLEANUP_INTERVAL: Specify the desired default hourly purge interval (for example, 12 for every 12 hours). The DBMS_AUDIT_MGMT procedures use this value to determine how to purge audit records. The timing begins when you run the DBMS_AUDIT_MGMT.INIT_CLEANUP procedure. To update this value later, set the DBMS_AUDIT_MGMT.CLEAN_UP_INTERVAL property of the DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_PROPERTY procedure. The DEFAULT_CLEANUP_INTERVAL setting must indicate the frequency in which DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL is called. If you are uncertain about the frequency, set it to an approximate value. You can change this value later on by using the DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_PROPERTY procedure.

    BEGIN
     DBMS_AUDIT_MGMT.INIT_CLEANUP(
      AUDIT_TRAIL_TYPE            => DBMS_AUDIT_MGMT.AUDIT_TRAIL_ALL,
      DEFAULT_CLEANUP_INTERVAL    => 48 );
    END;
    /
     
    You can cancel the DBMS_AUDIT_MGMT.INIT_CLEANUP settings, that is, the default cleanup interval, by invoking the DBMS_AUDIT_MGMT.DEINIT_CLEANUP procedure. For example, to cancel all purge settings for the standard audit trail:

    BEGIN
     DBMS_AUDIT_MGMT.DEINIT_CLEANUP(
      AUDIT_TRAIL_TYPE  => DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD);
    END;
    /

    Views:

    SELECT * FROM DBA_AUDIT_POLICIES;

    SELECT * FROM DBA_FGA_AUDIT_TRAIL;
    SELECT * FROM DBA_AUDIT_MGMT_CLEAN_EVENTS;
    SELECT * FROM DBA_AUDIT_MGMT_CLEANUP_JOBS;
    SELECT * FROM DBA_AUDIT_MGMT_CONFIG_PARAMS;
    SELECT * FROM DBA_AUDIT_MGMT_LAST_ARCH_TS;

    Documentation Pointers

    1. Oracle® Database Security Guide 11g Release 2 (11.2)

    Tuesday, September 10, 2013

    Oracle 11G Auditing

    Password change for the application user is the main reason I want auditing now. I have an user called PASGEN, password has been changed but still some application processes exit which try to connect using the wrong password. Existing profiles make the account immediately locked so I had to (temporarily) alter the profile and make failed_login_attempts unlimited:

    ALTER PROFILE nonexpiring LIMIT failed_login_attempts UNLIMITED;

    After that I setup an audit to find out whats the issue:

    AUDIT SESSION BY PASGEN BY ACCESS WHENEVER NOT SUCCESSFUL;

    Then I had an hour or longer wasted trying to find out why I see wrong records from SYS.AUD$. I tried to filter only new entries using ntimestamp# - for unknown reason timestamp# (type DATE) has not been populated. Anway - ntimestamp# appears to be in UTC timezone and it took me some time to figure it out. Finally I found DBA_AUDIT_TRAIL and this is where I should start.

    So query which work best for me is:

    SELECT os_username,username,userhost,os_process,terminal, action_name,comment_text, timestamp
        FROM dba_audit_trail
    WHERE returncode = 1017
        AND timestamp > localtimestamp - 1/24/60 * 5 -- last 5 minutes
        AND username='PASGEN'
    ORDER BY timestamp, os_username,userhost,os_process;


    And sometimes - to see more details - I put asterisk instead of list of columns for SELECT above.

    Another interesting issue with the database based audit trail (standard audit trail) is this log grows quickly if there is a lot of entries to be stored. That's particularly true statement when you have an application trying to connect with the wrong password over and over, sometimes a couple of times per second. So the SYSAUX tablespace may be overflowed quickly. This is the reason I implemented automatic cleanup for this tablespace:



    SYS@DEV1> show parameter audit_trail;
    NAME TYPE   VALUE

    ----------- ------------------------------
    audit_trail string DB
    SYS@DEV1>
    SET SERVEROUTPUT ON
    BEGIN
      IF
        DBMS_AUDIT_MGMT.IS_CLEANUP_INITIALIZED(
        DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD)
      THEN
        DBMS_OUTPUT.PUT_LINE('AUD$ is initialized for cleanup');
      ELSE
        DBMS_OUTPUT.PUT_LINE('AUD$ is not initialized for cleanup.');
      END IF;
    END;
    /
    SYS@DEV1>
    AUD$ is not initialized for cleanup.
    PL/SQL procedure successfully completed.
    SYS@DEV1>


    Here is an excerpt form the documentation:

    DEFAULT_CLEANUP_INTERVAL: Specify the desired default hourly purge interval (for example, 12 for every 12 hours). The DBMS_AUDIT_MGMT procedures use this value to determine how to purge audit records. The timing begins when you run the DBMS_AUDIT_MGMT.INIT_CLEANUP procedure. To update this value later, set the DBMS_AUDIT_MGMT.CLEAN_UP_INTERVAL property of the DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_PROPERTY procedure.

    The DEFAULT_CLEANUP_INTERVAL setting must indicate the frequency in which DBMS_AUDIT_MGMT.CLEAN_AUDIT_TRAIL is called. If you are uncertain about the frequency, set it to an approximate value. You can change this value later on by using the DBMS_AUDIT_MGMT.SET_AUDIT_TRAIL_PROPERTY procedure.

    BEGIN
     DBMS_AUDIT_MGMT.INIT_CLEANUP(
      AUDIT_TRAIL_TYPE            => DBMS_AUDIT_MGMT.AUDIT_TRAIL_ALL,
      DEFAULT_CLEANUP_INTERVAL    => 48 );
    END;
    /
     

    You can cancel the DBMS_AUDIT_MGMT.INIT_CLEANUP settings, that is, the default cleanup interval, by invoking the DBMS_AUDIT_MGMT.DEINIT_CLEANUP procedure.
    For example, to cancel all purge settings for the standard audit trail:

    BEGIN
     DBMS_AUDIT_MGMT.DEINIT_CLEANUP(
      AUDIT_TRAIL_TYPE  => DBMS_AUDIT_MGMT.AUDIT_TRAIL_AUD_STD);
    END;
    /

    Views


    SELECT * FROM DBA_FGA_AUDIT_TRAIL;
    SELECT * FROM DBA_AUDIT_MGMT_CLEAN_EVENTS;
    SELECT * FROM DBA_AUDIT_MGMT_CLEANUP_JOBS;
    SELECT * FROM DBA_AUDIT_MGMT_CONFIG_PARAMS;
    SELECT * FROM DBA_AUDIT_MGMT_LAST_ARCH_TS;

     

    Documentation Pointers

    1. Oracle® Database Security Guide 11g Release 2 (11.2)



    Tuesday, August 6, 2013

    Statistics in 11.2

    Collecting Stats Faster

    The problem is collecting optimizer statistics with DBMS_STATS.GATHER_SCHEMA_STATS happens serially and takes incredibly long time for huge databases. Particularly when we have LOB tables. Usually I need rebuild statistics after a schema is imported from previous version of the database to the latest one. So I don't care what load it brings to the database - it might be very intense operation but I want it to finish as soon as possible. And usually the load incurred by the usual GATHER_SCHEMA_STATS procedure is minimal so making it running in parallel would be an excellent idea.

    One night, when statistics collection already taken a long time, I decided to terminated and go this way:

    BEGIN
       DBMS_STATS.GATHER_SYSTEM_STATS('INTERVAL', 180); 
       DBMS_STATS.SET_GLOBAL_PREFS('CONCURRENT','TRUE');
       DBMS_STATS.GATHER_SCHEMA_STATS( 'MYUSER',
            degree  => DBMS_STATS.AUTO_DEGREE,
            options => 'GATHER',
            cascade => TRUE,
            no_invalidate => FALSE
    );
    END;
    /

    The effect was terrific. Mainly because it depends on the parameter job_queue_processes and it was set to 1000. So the database was really under a load for some time but the process finished in 30 minutes. I don't think the job_queue_processed is set to a reasonable parameter here for daily operation but at least it worked for this case!
    I specified options=>'GATHER' is required when you want to collects statistics for all objects in the schema. With the default 'GATHER AUTO' Oracle implicitly determines which objects need new statistics, and determines how to gather those statistics. When GATHER AUTO is specified, the only additional valid parameters are ownname, stattab, statid, objlist and statown; all other parameter settings are ignored. Returns a list of processed objects.

    Checking the current status of concurrent statistics collection:

    SELECT DBMS_STATS.GET_PREFS('CONCURRENT') pref FROM dual;
    
    

    Resources

    1. GATHER_SCHEMA_STATS in 11.2
    2. Concurrent Statistics Gathering.
    3. Understanding Optimizer Statistics (PDF).