Oracle DBMS_PREPROCESSOR Built-In Package
Versions 10.2 - 19.3

Security Advisory
This package provides an interface for printing and retrieving the source text of a PL/SQL unit in its post-processed form.

Oracle is far too liberal with tools that can be used by unprivileged users to reverse engineer PL/SQL code.

SELECT dbms_metadata.get_ddl(..., ..., ...) FROM dual;
SELECT * FROM all_source;
SELECT * FROM all_source_ae;
SELECT * FROM user_source;
SELECT * FROM user_source_ae;

On the "good" side of the equation Oracle does provide the wrap executable that can be used to defeat these tools.
On the "bad" side of the equation very few organizations utilize wrap and in a large number of cases Oracle Corp. doesn't use it either.

The issue with DBMS_PREPROCESSOR is that for no justifiable reason EXECUTE is granted to PUBLIC by default.
 
Recommended Security Rules

 NEVER
  • Accept Oracle's default grant of EXECUTE to PUBLIC for this package
 WITH GREAT CARE
  • Verify in a pre-production environment that code/applications that will be hosted do not require EXECUTE
  • If any code/application requires EXECUTE grant EXECUTE explicitly and document the change
  • Revoke EXECUTE from PUBLIC
 CAUTIONS
  • When improving security by revoking default grants such as EXECUTE to PUBLIC be sure to add them to your testing when upgrading to newer versions or upgrading the application(s) deployed and utilizing the database.
 
 
DBMS_PREPROCESSOR Package Information
AUTHID CURRENT_USER
Data Types TYPE source_lines_t IS TABLE OF VARCHAR2(32767)
INDEX BY BINARY_INTEGER;
Dependencies
ALL_SOURCE DBMS_STANDARD PLITBLM
DBMS_OUTPUT DBMS_SYS_ERROR  
Documented Yes
Exceptions
Error Code Reason
ORA-00931 Missing identifier. The object_name should not be NULL
ORA-06502 Numeric or value error
ORA-24234 Insufficient privileges or object does not exist
ORA-24235 Invalid object type: Must be one of PACKAGE, PACKAGE BODY, PROCEDURE, FUNCTION, TYPE, TYPE, BODY or TRIGGER
ORA-24236 Source text is empty
ORA-24241 Source text is in wrapped format
First Available 10gR2
Security Model Owned by SYS with EXECUTE granted to PUBLIC
Source {ORACLE_HOME}/rdbms/admin/dbmspp.sql
Subprograms
 
GET_POST_PROCESSED_SOURCE
Returns post-processed source text

Overload 1
dbms_preprocessor.get_post_processed_source (
object_type IN VARCHAR2, 
schema_name IN VARCHAR2,
object_name IN VARCHAR2)
RETURN source_lines_t;
CREATE OR REPLACE FUNCTION test_func RETURN NUMBER AUTHID DEFINER IS
 i user_tables.blocks%TYPE := 1;
BEGIN
  -- a demo comment in the code
  i := i + 1;
  RETURN i;
END test_func;
/

set serveroutput on

DECLARE
 retval_t  dbms_preprocessor.source_lines_t;
BEGIN
  retval_t := dbms_preprocessor.get_post_processed_source(
  'FUNCTION', 'UWCLASS', 'TEST_FUNC');

  FOR i IN 1..retval_t.LAST
  LOOP
    dbms_output.put_line(retval_t(i));
  END LOOP;
END;
/

FUNCTION test_func RETURN NUMBER AUTHID DEFINER IS

i user_tables.blocks%TYPE := 1;

BEGIN

-- a demo comment in the code

i := i + 1;

RETURN i;

END test_func;


PL/SQL procedure successfully completed.

-- after wrapping the test_func source code above the anonymous block was rerun
-- to prove that the package cannot be used to reverse engineer wrapped PL/SQL
-- See Exception ORA-24241 (above)


CREATE OR REPLACE FUNCTION test_func wrapped
a000000
b2
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
abcd
8
7f be
tb+RDMRsWcBdvT66bdcZOiaX6SUwg2LwLZ7hfy9EO06UZC3TNrrWlUPCs5XHrsKYAlyesyXU
TrXwcK3Q7i5SiPAXr5swls06QlXM+jSe25b0xTnEtheRxVakkx1qjScDqC4aBSHXhpOxn5jT
M1uK4Fr1kb1MHoW05Oi1bMZn8TgaPPIoxj0fHu+oeQ==

/



DECLARE
 retval_t  dbms_preprocessor.source_lines_t;
BEGIN
  retval_t := dbms_preprocessor.get_post_processed_source(
  'FUNCTION', 'UWCLASS', 'TEST_FUNC');

  FOR i IN 1..retval_t.LAST
  LOOP
    dbms_output.put_line(retval_t(i));
  END LOOP;
END;
/
DECLARE
*
ERROR at line 1:
ORA-24241: source text is in wrapped format
ORA-06512: at "SYS.DBMS_PREPROCESSOR", line 84
ORA-06512: at "SYS.DBMS_PREPROCESSOR", line 197
ORA-06512: at line 4
Overload 2 dbms_preprocessor(source IN VARCHAR2) RETURN source_lines_t;
set serveroutput on

DECLARE
 instring  VARCHAR2(32767);
 retval_t  dbms_preprocessor.source_lines_t;
BEGIN
  instring := 'BEGIN ' || 
              '  FOR i IN 1 .. 100 LOOP ' ||
              '    NULL; ' ||
              '  END LOOP; ' ||
              'END;';

  retval_t := dbms_preprocessor.get_post_processed_source(instring);

  FOR i IN 1..retval_t.LAST
  LOOP
    dbms_output.put_line(retval_t(i));
  END LOOP;
END;
/
BEGIN FOR i IN 1 .. 100 LOOP NULL; END LOOP; END;

PL/SQL procedure successfully completed.
Overload 3 dbms_preprocessor(source_lines_t IN VARCHAR2) RETURN source_lines_t;
set serveroutput on

DECLARE
 inval_t  dbms_preprocessor.source_lines_t;
 retval_t dbms_preprocessor.source_lines_t;
BEGIN
  inval_t(1) := 'BEGIN ';
  inval_t(2) := '  FOR i IN 1 .. 100 LOOP ';
  inval_t(3) := '    NULL; ';
  inval_t(4) := '  END LOOP; ';
  inval_t(5) := 'END;';

  retval_t := dbms_preprocessor.get_post_processed_source(inval_t);

  FOR i IN 1..retval_t.LAST
  LOOP
    dbms_output.put_line(retval_t(i));
  END LOOP;
END;
/
BEGIN FOR i IN 1 .. 100 LOOP NULL; END LOOP; END;

PL/SQL procedure successfully completed.
 
PRINT_POST_PROCESSED_SOURCE
Given a stored PL/SQL unit, print its post-processed source text

Overload 1
dbms_preprocessor.print_post_processed_source(
object_type IN VARCHAR2,
schema_name IN VARCHAR2,
object_name IN VARCHAR2);
set serveroutput on

BEGIN
  dbms_preprocessor.print_post_processed_source('FUNCTION', 'UWCLASS', 'TEST_FUNC');
END;
/
Overload 2 dbms_preprocessor.print_post_processed_source(source IN VARCHAR2);
set serveroutput on

DECLARE
 str VARCHAR2(32767) := 'BEGIN NULL; END;';
BEGIN
  dbms_preprocessor.print_post_processed_source(str);
END;
/
Overload 3 dbms_preprocessor.print_post_processed_source(source IN source_lines_t);
set serveroutput on

DECLARE
 inval_t dbms_preprocessor.source_lines_t;
BEGIN
  inval_t(1) := 'BEGIN ';
  inval_t(2) := 'FOR i IN 1 .. 100 LOOP ';
  inval_t(3) := 'NULL; ';
  inval_t(4) := 'END LOOP; ';
  inval_t(5) := 'END;';

  dbms_preprocessor.print_post_processed_source(inval_t);
END;
/

Related Topics
DBMS_METADATA