MINI MINI MANI MO

Path : /opt/oracle/product/18c/dbhomeXE/rdbms/admin/
File Upload :
Current File : //opt/oracle/product/18c/dbhomeXE/rdbms/admin/catpvf.sql

Rem
Rem $Header: rdbms/admin/catpvf.sql /st_rdbms_18.0/1 2018/04/23 06:36:58 anbhasu Exp $
Rem
Rem catpvf.sql
Rem
Rem Copyright (c) 2013, 2018, Oracle and/or its affiliates. 
Rem All rights reserved.
Rem
Rem    NAME
Rem      catpvf.sql - Create Password Verify Function, STIG profile 
Rem
Rem    DESCRIPTION
Rem      Creates the password verify functions and their dependent functions.
Rem      This script also creates the STIG compliant user profile
Rem
Rem    NOTES
Rem       STIG profile is created with container = current which means it is 
Rem       a local object. But exception is made in PDB code similar to the 
Rem       DEFAULT profile to make sure the STIG profile is created in every 
Rem       container during DB creation time. 
Rem       
Rem       The password verify functions and their dependent functions are moved 
Rem       from utlpwdmg.sql script
Rem
Rem    MODIFIED   (MM/DD/YY)
Rem    anbhasu     04/18/18 - Backport anbhasu_bug-27522245 from main
Rem    anbhasu     02/20/18 - bug# 27522245 & 27550341 - Password len check 
Rem                           removed and Handles multibyte NLS characters
Rem    anbhasu     04/19/17 - Bug 22730089: Translated error messages
Rem    gaurameh    02/10/17 - Bug 21109302: Password len cannot exceed 30 bytes
Rem    hmohanku    04/04/16 - bug 22934473: add special char to ora12c function
Rem    aanverma    02/11/16 - Bug 22552142: STIG 12c v1 r2 new function
Rem                           ora12c_stig_verify_function
Rem    sumkumar    12/15/15 - Bug 22369990: Make all PVFs as common objects
Rem                           so as to make them available inside PDBs
Rem    sumkumar    12/26/14 - Proj 46885: inactive account time defaulted to
Rem                           30 days for STIG profile
Rem    sumkumar    11/20/14 - Bug 20075483 : Grant execute privilege on
Rem                           ora12c_strong_verify_function to PUBLIC
Rem    himagarw    02/13/14 - Bug #18237713: Raise exception if source or
Rem                           target string is longer than 128 bytes
Rem    surman      12/29/13 - 13922626: Update SQL metadata
Rem    jkati       10/24/13 - bug#17543726 : Create password verify functions
Rem                           and STIG profile
Rem    jkati       10/24/13 - Created
Rem
Rem    BEGIN SQL_FILE_METADATA 
Rem    SQL_SOURCE_FILE: rdbms/admin/catpvf.sql 
Rem    SQL_SHIPPED_FILE: rdbms/admin/catpvf.sql 
Rem    SQL_PHASE: CATPVF
Rem    SQL_STARTUP_MODE: NORMAL 
Rem    SQL_IGNORABLE_ERRORS: NONE 
Rem    SQL_CALLING_FILE: rdbms/admin/catptabs.sql
Rem    END SQL_FILE_METADATA

@@?/rdbms/admin/sqlsessstart.sql

Rem *************************************************************************
Rem BEGIN Helper Function for out-of-the-box Oracle supplied PVFs
Rem *************************************************************************

Rem  Function: "ora_complexity_check" - Verifies the complexity
Rem            of a password string.
Rem
Rem  If not null, each of the following parameters specifies the minimum
Rem  number of characters of the corresponding type from input character set.
Rem  chars   -  All characters (i.e. string length)
Rem  letter  -  Alphabetic characters 
Rem  uppercase   -  Alphabetic uppercase characters 
Rem  lowercase   -  Alphabetic lowercase characters
Rem  digit   -  Numeric characters 
Rem  special -  All non alpha-numeric characters except
Rem             double quote which is a password delimiter

create or replace function ora_complexity_check
(password varchar2,
 chars    integer := null,
 letter   integer := null,
 uppercase    integer := null,
 lowercase    integer := null,
 digit    integer := null,
 special  integer := null)
return boolean is
   cnt_letter  integer := 0;
   cnt_upper   integer := 0;
   cnt_lower   integer := 0;
   cnt_digit   integer := 0;
   cnt_special integer := 0;
   delimiter   boolean := false;
   len         integer := nvl (length(password), 0);
   i           integer ;
   ch          char(1 char);
   lang        varchar2(512 byte);
   message     varchar2(512 char);
   ret         number;
   
begin
   -- Bug 22730089
   -- Get the current session language and use utl_lms to get the messages.
   -- Under the scenario where the language is not supported , 
   -- only the error code shall be displayed.
   lang := sys_context('userenv','lang');

   -- Classify each character in the password.
   for i in 1..len loop
      ch := substr(password, i, 1);
      if ch = '"' then
         delimiter := true;
         -- Got a delimiter, no need to validate other characters.
         exit;
         -- Observes alphabetic, numeric and special characters. 
         -- If a character is neither alphabetic nor numeric, 
         -- it is considered special.
      elsif regexp_instr(ch, '[[:alnum:]]') > 0 then
         if regexp_instr(ch, '[[:digit:]]') > 0 then
            cnt_digit := cnt_digit + 1;
         -- Certain characters can be both, numeric and alphabetic,
         -- Such characters will be counted in both categories.
         -- Ex:Roman Numerals('I'(U+2160),'II'(U+2161),'i'(U+2170),'ii'(U+2171))
         end if;
         if regexp_instr(ch, '[[:alpha:]]') > 0 then
            cnt_letter := cnt_letter + 1;
            if regexp_instr(ch, '[[:lower:]]') > 0 then
               cnt_lower := cnt_lower + 1;
            end if;
            -- Certain alphabetic characters can be both upper- or lowercase.
            -- Such characters will be counted in both categories.
            -- Ex:Latin Digraphs and Ligatures ('Nj'(U+01CB), 'Dz'(U+01F2))
            if regexp_instr(ch, '[[:upper:]]') > 0 then
               cnt_upper := cnt_upper + 1;
            end if;
         end if;
      else 
         cnt_special := cnt_special + 1;
      end if;
   end loop;

   if delimiter = true then
      ret := utl_lms.get_message(28212, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, message);      
   end if;
   if chars is not null and len < chars then
      ret := utl_lms.get_message(28206, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(chars AS PLS_INTEGER)));
   end if;

   if letter is not null and cnt_letter < letter then
      ret := utl_lms.get_message(28213, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(letter AS PLS_INTEGER)));
   end if;
   if uppercase is not null and cnt_upper < uppercase then
      ret := utl_lms.get_message(28214, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(uppercase AS PLS_INTEGER)));
   end if;
   if lowercase is not null and cnt_lower < lowercase then
      ret := utl_lms.get_message(28215, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(lowercase AS PLS_INTEGER)));
   end if;
   if digit is not null and cnt_digit < digit then
      ret := utl_lms.get_message(28216, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(digit AS PLS_INTEGER)));
   end if;
   if special is not null and cnt_special < special then
      ret := utl_lms.get_message(28217, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, utl_lms.format_message(message, CAST(special AS PLS_INTEGER)));
   end if;

   return(true);
end;
/
show errors;


Rem  Function: "ora_string_distance" - Calculates the Levenshtein distance
Rem            between two strings 's' and 't'.
Rem            The Levenshtein distance between two words is the minimum number 
Rem            of single-character edits (insertion, deletion, substitution) 
Rem            required to change one word into the other

create or replace function ora_string_distance
(s varchar2,
 t varchar2)
return integer is 
   s_len    integer := nvl (length(s), 0);
   t_len    integer := nvl (length(t), 0);
   type arr_type is table of number index by binary_integer;
   d_col    arr_type ;
   dist     integer := 0;
   lang     varchar2(512);
   message  varchar2(512);
   ret      number;

begin
   -- Get the cur context lang and use utl_lms for messages- Bug 22730089
   lang := sys_context('userenv','lang');
   lang := substr(lang,1,instr(lang,'_')-1);

   if s_len = 0 then
      dist := t_len;
   elsif t_len = 0 then
      dist := s_len;
   elsif s = t then 
     return(0);
   else
      for j in 1 .. (t_len+1) * (s_len+1) - 1 loop
          d_col(j) := 0 ;
      end loop;
      for i in 0 .. s_len loop
          d_col(i) := i;
      end loop;
      for j IN 1 .. t_len loop
          d_col(j * (s_len + 1)) := j;
      end loop;

      for i in 1.. s_len loop
        for j IN 1 .. t_len loop
          if substr(s, i, 1) = substr(t, j, 1)
          then
             d_col(j * (s_len + 1) + i) := d_col((j-1) * (s_len+1) + i-1) ;
          else
             d_col(j * (s_len + 1) + i) := LEAST (
                       d_col( j * (s_len+1) + (i-1)) + 1,      -- Deletion
                       d_col((j-1) * (s_len+1) + i) + 1,       -- Insertion
                       d_col((j-1) * (s_len+1) + i-1) + 1 ) ;  -- Substitution
          end if ;
        end loop;
      end loop;
      dist :=  d_col(t_len * (s_len+1) + s_len);
   end if;

   return (dist);
end;
/
show errors;

Rem *************************************************************************
Rem END Helper Function for out-of-the-box Oracle supplied PVFs
Rem *************************************************************************
              
Rem *************************************************************************
Rem BEGIN Password Verification Functions
Rem *************************************************************************

Rem Function: "ora12c_verify_function" - provided from 12c onwards
Rem
Rem This function makes the minimum complexity checks like
Rem the minimum length of the password, password not same as the
Rem username, etc. The user may enhance this function according to
Rem the need.
Rem This function must be created in SYS schema.
Rem connect sys/<password> as sysdba before running the script

CREATE OR REPLACE FUNCTION ora12c_verify_function
(username     varchar2,
 password     varchar2,
 old_password varchar2)
RETURN boolean IS
   differ   integer; 
   db_name  varchar2(40);
   i        integer;
   reverse_user dbms_id;
   canon_username dbms_id := username;
   lang     varchar2(512);
   message  varchar2(512);
   ret      number;

BEGIN
   -- Get the cur context lang and use utl_lms for messages- Bug 22730089
   lang := sys_context('userenv','lang');
   lang := substr(lang,1,instr(lang,'_')-1);

   -- Bug 22369990: Dbms_Utility may not be available at this point, so switch
   -- to dynamic SQL to execute canonicalize procedure.
   IF (substr(username,1,1) = '"') THEN
     execute immediate 'begin dbms_utility.canonicalize(:p1,  :p2, 128); end;'
                        using IN username, OUT canon_username;
   END IF;
   IF NOT ora_complexity_check(password, chars => 8, letter => 1, digit => 1,
                               special => 1) THEN
      RETURN(FALSE);
   END IF;

   -- Check if the password contains the username
   IF regexp_instr(password, canon_username, 1, 1, 0, 'i') > 0 THEN
      ret := utl_lms.get_message(28207, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, message);
   END IF;

   -- Check if the password contains the username reversed
   FOR i in REVERSE 1..length(canon_username) LOOP
     reverse_user := reverse_user || substr(canon_username, i, 1);
   END LOOP;
   IF regexp_instr(password, reverse_user, 1, 1, 0, 'i') > 0 THEN
      ret := utl_lms.get_message(28208, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, message);
   END IF;

   -- Check if the password contains the server name
   select name into db_name from sys.v$database;
   IF regexp_instr(password, db_name, 1, 1, 0, 'i') > 0 THEN
      ret := utl_lms.get_message(28209, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, message);
   END IF;

   -- Check if the password contains 'oracle'
   IF regexp_instr(password, 'oracle', 1, 1, 0, 'i') > 0 THEN
      ret := utl_lms.get_message(28210, 'RDBMS', 'ORA', lang, message);
      raise_application_error(-20000, message);
   END IF;

   -- Check if the password differs from the previous password by at least
   -- 3 characters
   IF old_password IS NOT NULL THEN
     differ := ora_string_distance(old_password, password);
     IF differ < 3 THEN
        ret := utl_lms.get_message(28211, 'RDBMS', 'ORA', lang, message);
        raise_application_error(-20000, utl_lms.format_message(message, 'three'));
     END IF;
   END IF ;

   RETURN(TRUE);
END;
/
show errors;

GRANT EXECUTE ON ora12c_verify_function TO PUBLIC container=current;

Rem Function: "verify_function_11G" - provided from 11G onwards.
Rem 
Rem This function makes the minimum complexity checks like
Rem the minimum length of the password, password not same as the
Rem username, etc. The user may enhance this function according to
Rem the need.

CREATE OR REPLACE FUNCTION verify_function_11G
(username varchar2,
 password varchar2,
 old_password varchar2)
RETURN boolean IS
   differ integer;
   db_name varchar2(40);
   i integer;
   i_char varchar2(10);
   simple_password varchar2(10);
   reverse_user dbms_id;
   canon_username dbms_id := username;
BEGIN
   -- Bug 22369990: Dbms_Utility may not be available at this point, so switch
   -- to dynamic SQL to execute canonicalize procedure.
   IF (substr(username,1,1) = '"') THEN
     execute immediate 'begin dbms_utility.canonicalize(:p1,  :p2, 128); end;'
                        using IN username, OUT canon_username;
   END IF;
   IF NOT ora_complexity_check(password, chars => 8, letter => 1, digit => 1) THEN
      RETURN(FALSE);
   END IF;

   -- Check if the password is same as the username or username(1-100)
   IF NLS_LOWER(password) = NLS_LOWER(canon_username) THEN
     raise_application_error(-20002, 'Password same as or similar to user');
   END IF;
   FOR i IN 1..100 LOOP
      i_char := to_char(i);
      if NLS_LOWER(canon_username)|| i_char = NLS_LOWER(password) THEN
        raise_application_error(-20005, 'Password same as or similar to ' || 
                                        'username ');
      END IF;
   END LOOP;

   -- Check if the password is same as the username reversed
   FOR i in REVERSE 1..length(canon_username) LOOP
     reverse_user := reverse_user || substr(canon_username, i, 1);
   END LOOP;
   IF NLS_LOWER(password) = NLS_LOWER(reverse_user) THEN
     raise_application_error(-20003, 'Password same as username reversed');
   END IF;

   -- Check if the password is the same as server name and or servername(1-100)
   select name into db_name from sys.v$database;
   if NLS_LOWER(db_name) = NLS_LOWER(password) THEN
      raise_application_error(-20004, 'Password same as or similar ' ||
                                      'to server name');
   END IF;
   FOR i IN 1..100 LOOP
      i_char := to_char(i);
      if NLS_LOWER(db_name)|| i_char = NLS_LOWER(password) THEN
        raise_application_error(-20005, 'Password same as or similar ' || 
                                        'to server name ');
      END IF;
   END LOOP;

   -- Check if the password is too simple. A dictionary of words may be
   -- maintained and a check may be made so as not to allow the words
   -- that are too simple for the password.
   IF NLS_LOWER(password) IN ('welcome1', 'database1', 'account1', 'user1234',
                              'password1', 'oracle123', 'computer1', 
                              'abcdefg1', 'change_on_install') THEN
      raise_application_error(-20006, 'Password too simple');
   END IF;

   -- Check if the password is the same as oracle (1-100)
    simple_password := 'oracle';
    FOR i IN 1..100 LOOP
      i_char := to_char(i);
      if simple_password || i_char = NLS_LOWER(password) THEN
        raise_application_error(-20006, 'Password too simple ');
      END IF;
    END LOOP;

   -- Check if the password differs from the previous password by at least
   -- 3 letters
   IF old_password IS NOT NULL THEN
     differ := ora_string_distance(old_password, password);
     IF differ < 3 THEN
         raise_application_error(-20011, 'Password should differ from the ' ||  
                                 'old password by at least 3 characters');
     END IF;
   END IF;

   RETURN(TRUE);
END;
/
show errors;

GRANT EXECUTE ON verify_function_11G TO PUBLIC container=current;

-- Below is the older version of the script

-- This script sets the default password resource parameters
-- This script needs to be run to enable the password features.
-- However the default resource parameters can be changed based 
-- on the need.
-- A default password complexity function is also provided.
-- This function makes the minimum complexity checks like
-- the minimum length of the password, password not same as the
-- username, etc. The user may enhance this function according to
-- the need.
-- This function must be created in SYS schema.
-- connect sys/<password> as sysdba before running the script

CREATE OR REPLACE FUNCTION verify_function
(username varchar2,
 password varchar2,
 old_password varchar2)
RETURN boolean IS
   differ integer;
   canon_username dbms_id := username;
BEGIN
   -- Bug 22369990: Dbms_Utility may not be available at this point, so switch
   -- to dynamic SQL to execute canonicalize procedure.
   IF (substr(username,1,1) = '"') THEN
     execute immediate 'begin dbms_utility.canonicalize(:p1,  :p2, 128); end;'
                        using IN username, OUT canon_username;
   END IF;
   -- Check if the password is same as the username
   IF NLS_LOWER(password) = NLS_LOWER(canon_username) THEN
     raise_application_error(-20001, 'Password same as or similar to user');
   END IF;

   -- Check if the password contains at least four characters, including
   -- one letter, one digit and one punctuation mark.
   IF NOT ora_complexity_check(password, chars => 4, letter => 1, digit => 1,
                           special => 1) THEN
      RETURN(FALSE);
   END IF;

   -- Check if the password is too simple. A dictionary of words may be
   -- maintained and a check may be made so as not to allow the words
   -- that are too simple for the password.
   IF NLS_LOWER(password) IN ('welcome', 'database', 'account', 'user', 
                              'password', 'oracle', 'computer', 'abcd') THEN
      raise_application_error(-20002, 'Password too simple');
   END IF;

   -- Check if the password differs from the previous password by at least
   -- 3 letters
   IF old_password IS NOT NULL THEN
     differ := ora_string_distance(old_password, password);
     IF differ < 3 THEN
         raise_application_error(-20004, 'Password should differ by at' ||
                                         'least 3 characters');
     END IF;
   END IF;

   RETURN(TRUE);
END;
/
show errors;

GRANT EXECUTE ON verify_function TO PUBLIC container=current;

Rem
Rem Function: "ora12c_strong_verify_function" - provided from 12c onwards for
Rem           stringent password check requirements.
Rem 

create or replace function ora12c_strong_verify_function
(username     varchar2,
 password     varchar2,
 old_password varchar2)
return boolean IS
   differ   integer;
   lang     varchar2(512);
   message  varchar2(512);
   ret      number;

begin
   -- Get the cur context lang and use utl_lms for messages- Bug 22730089
   lang := sys_context('userenv','lang');
   lang := substr(lang,1,instr(lang,'_')-1);

   if not ora_complexity_check(password, chars => 9, uppercase => 2, 
                           lowercase => 2, digit => 2, special => 2) then 
      return(false);
   end if;

   -- Check if the password differs from the previous password by at least
   -- 4 characters
   if old_password is not null then 
      differ := ora_string_distance(old_password, password);
      if differ < 4 then
         ret := utl_lms.get_message(28211, 'RDBMS', 'ORA', lang, message);
         raise_application_error(-20000, utl_lms.format_message(message, 'four'));
      end if;
   end if;

   return(true);
end;
/
show errors;

GRANT EXECUTE ON ora12c_strong_verify_function TO PUBLIC container=current;

Rem
Rem Function: "ora12c_stig_verify_function" - provided from 12c onwards for
Rem           stringent password check requirements to meet 
Rem           "STIG for Oracle 12c" password complexity check requirement.
Rem 
Rem This function is provided to give stronger password complexity function
Rem that would take into consideration recommendations from Department of
Rem Defense Database Security Technical Implementation Guide (STIG) v1 r2
Rem released on 22-Jan-2016.

create or replace function ora12c_stig_verify_function
 ( username     varchar2,
   password     varchar2,
   old_password varchar2)
 return boolean IS
   differ  integer;
   lang    varchar2(512);
   message varchar2(512);
   ret     number;

begin
   -- Get the cur context lang and use utl_lms for messages- Bug 22730089
   lang := sys_context('userenv','lang');
   lang := substr(lang,1,instr(lang,'_')-1);

   if not ora_complexity_check(password, chars => 15, uppercase => 1, 
                           lowercase => 1, digit => 1, special => 1) then 
      return(false);
   end if;

   -- Check if the password differs from the previous password by at least
   -- 8 characters
   if old_password is not null then 
      differ := ora_string_distance(old_password, password);
      if differ < 8 then
         ret := utl_lms.get_message(28211, 'RDBMS', 'ORA', lang, message);
         raise_application_error(-20000, utl_lms.format_message(message, 'eight'));
      end if;
   end if;

   return(true);
end;
/
show errors;

GRANT EXECUTE ON ora12c_stig_verify_function TO PUBLIC container=current;

Rem *************************************************************************
Rem END Password Verification Functions
Rem *************************************************************************

Rem
Rem STIG Compliant User Profile. If the profile already exists,
Rem do nothing as the update of inactive_account_time and 
Rem password_verify_function is moved to the upgrade script
Rem a1201000.sql
Rem

declare
  profile_exists exception;
  pragma exception_init(profile_exists, -02379);
begin
  execute immediate 'create profile ora_stig_profile limit
                     password_life_time 60
                     password_grace_time 5
                     password_reuse_time 365
                     password_reuse_max 10
                     failed_login_attempts 3
                     password_lock_time unlimited
                     inactive_account_time 35
                     idle_time 15
                     password_verify_function ora12c_stig_verify_function
                     container=current';
exception
  when profile_exists then
    null;
end;
/
show errors;

@?/rdbms/admin/sqlsessend.sql

OHA YOOOO