Progress
Version 9
Product Update Bulletin


RCODE–INFO Handle

The RCODE–INFO handle allows you to read the r-code CRC from an r-code file. You can use this value to build a procedure security table, and then to verify the integrity of your application r-code against it. You can also use this value in a deployment procedure that you run in a secure context to automatically install database schema trigger definitions.

Getting the R-code CRC

To read the r-code CRC from an r-code file, first set the FILE–NAME attribute of the RCODE–INFO handle to the pathname of your r-code file. Then read the value of the CRC–VALUE attribute:

DEFINE VARIABLE rCRC AS INTEGER.
RCODE-INFO:FILE-NAME = "sports/crcust.r".
rCRC = RCODE-INFO:CRC-VALUE. 

NOTE: The RCODE–INFO handle cannot read the r-code CRC from a session compile. For source (.p) procedures, the CRC–VALUE attribute returns the unknown value (?).

Example — Verifying Application R-code Integrity

This example shows how you might provide r-code integrity and security in your application.

  1. Build the procedure security table, RcodeSecurity, with these fields:
    • Filename — CHARACTER field for the pathname of each r-code file.
    • CRC — INTEGER field for the r-code CRC of the specified r-code file.
  2. Construct a text file, crctable.dat, that contains a list of the relative pathnames for all the secure procedures called by your application.
  3. Compile and save the r-code for all the secure procedures in your application.
  4. Run a procedure that contains code like this to build the RcodeSecurity table:
  5. DEFINE VARIABLE i AS INTEGER.
    DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
    DEFINE VARIABLE rCRC AS INTEGER.
    
    INPUT FROM "crctable.dat". /* List of r-code file pathnames */
    
    i = 0.
    REPEAT:
        SET proc-name.
        FIND RcodeSecurity WHERE Filename = proc-name NO-ERROR.
        IF NOT AVAILABLE(RcodeSecurity) THEN
            CREATE RcodeSecurity.
        RCODE-INFO:FILE-NAME = proc-name.
        SET RcodeSecurity.Filename = proc-name
            RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE.
        i = i + 1.
    END.
    
    INPUT CLOSE.
    MESSAGE i "procedure security records created". 
    

  6. At each point where you call a secure procedure in your application, insert this code:
  7. FIND RcodeSecurity WHERE Filename = "secret.r".
    RCODE-INFO:FILE-NAME = "secret.r".
    
    IF RcodeSecurity.Crc = RCODE-INFO:CRC-VALUE THEN
        RUN secret.
    ELSE DO:
        MESSAGE "Procedure secret.r is invalid.".
        QUIT.
    END. 
    

Example — Deploying Schema Triggers

The following procedure installs new schema trigger definitions in an existing database. It reads dump files that contain the new data for table and field metaschema trigger records and updates these records with the new trigger procedure names and CRCs:

p-trload.p
/* p-trload.p */
DEFINE VARIABLE i AS INTEGER.
DEFINE VARIABLE event AS CHARACTER FORMAT "x(6)".
DEFINE VARIABLE proc-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE table-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE field-name AS CHARACTER FORMAT "x(32)".
DEFINE VARIABLE rCRC AS INTEGER.
INPUT FROM "_file-tr.dat". /* Table trigger data */
i = 0.
_fl-loop:
REPEAT:
  SET table-name event proc-name.
  RCODE-INFO:FILE-NAME = proc-name.
  rCRC = RCODE-INFO:CRC-VALUE.
  FIND _file WHERE _file-name = table-name.
  FIND _file-trig WHERE _file-recid = RECID(_file) AND
                        _event = event NO-ERROR.
  IF AVAILABLE _file-trig THEN DO:    
    IF  _File-trig._Proc-name = proc-name
    AND _File-trig._Trig-CRC  = rCRC THEN 
        NEXT _fl-loop.
    ELSE DO:
    /* Progress doesn’t let you modify a trigger record, so delete and
       recreate. */
      DELETE _File-trig.
      CREATE _File-trig.
      ASSIGN _File-trig._File-recid = RECID(_File)
             _File-trig._Event      = event
             _File-trig._Override = TRUE
             _File-trig._Proc-Name  = proc-Name
             _File-trig._Trig-CRC   = rCRC
             i = i + 1. 
    END.
  END.
END. 
INPUT CLOSE.
MESSAGE i "_file-trig records updated.".
INPUT FROM "_field-t.dat". /* Field trigger data */
i = 0.
_fld-loop:
REPEAT:
  SET table-name field-name event proc-name.
  RCODE-INFO:FILE-NAME = proc-name.
  rCRC = RCODE-INFO:CRC-VALUE.
  FIND _file WHERE _file-name = table-name.
  FIND _field WHERE _file-recid = RECID(_file) AND 
                    _field-name = field-name.
  FIND _field-trig WHERE _field-trig._file-recid = RECID(_file) AND
                         _field-trig._field-recid = RECID(_field) AND
                         _event = event NO-ERROR.
  IF AVAILABLE _Field-trig      
      AND _Field-trig._Proc-name = proc-name 
      AND _Field-trig._Trig-CRC  = rCRC THEN NEXT _fld-loop.
  ELSE DO:
    DELETE _Field-trig.
CREATE _Field-trig.
    ASSIGN
      _Field-trig._File-recid  = RECID(_File)
      _Field-trig._Field-recid = RECID(_Field)
      _Field-trig._Event       = event
      _Field-trig._Override    = TRUE
      _Field-trig._Proc-Name   = proc-Name
      _Field-trig._Trig-CRC    = rCRC
      i = i + 1.
  END.  
END.
INPUT CLOSE.
MESSAGE i "_field-trig records updated.". 

NOTE: As this example shows, you must use the RECID function rather than the ROWID function to reference metaschema table record locations.


Copyright © 2004 Progress Software Corporation
www.progress.com
Voice: (781) 280-4000
Fax: (781) 280-4095