Created a virus scanning procedure.
Download file to server, perform AV check, re-import whatever's left. If the file isn't there, delete it from MIP as it may be malicious. git-svn-id: http://locode01.ad.dom/svn/WEBMIP/trunk@3696 248e525c-4dfb-0310-94bc-949c084e9493
This commit is contained in:
@@ -4,29 +4,52 @@ CREATE OR REPLACE PACKAGE mip_virus_check IS
|
||||
-- Created : 23/01/2008 09:55:52
|
||||
-- Purpose : Virus checking package
|
||||
-- Updates : MULLENMD - added functionality to run the virus checker for a file
|
||||
--
|
||||
PROCEDURE write_file(p_name IN wwv_flow_files.NAME%TYPE
|
||||
,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
|
||||
,p_fs_name IN VARCHAR2);
|
||||
|
||||
-- added load file (to replace BLOB)
|
||||
PROCEDURE write_file(p_name IN wwv_flow_files.NAME%TYPE,
|
||||
p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
|
||||
p_fs_name IN VARCHAR2);
|
||||
|
||||
/**
|
||||
check_file - allows MIP to run an anti-virus scan on a given file
|
||||
|
||||
%param p_name - the APEX name of the file
|
||||
%param p_location - the directory on the server where the file will be tested
|
||||
%param p_fs_name - the actual filename of the file to test
|
||||
*/
|
||||
PROCEDURE check_file(p_name IN wwv_flow_files.NAME%TYPE
|
||||
,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
|
||||
,p_fs_name IN VARCHAR2);
|
||||
check_file - allows MIP to run an anti-virus scan on a given file
|
||||
|
||||
%param p_name - the APEX name of the file
|
||||
%param p_location - the directory on the server where the file will be tested
|
||||
*/
|
||||
PROCEDURE check_file(p_name IN wwv_flow_files.NAME%TYPE,
|
||||
p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS');
|
||||
--
|
||||
|
||||
/**
|
||||
get_fs_name - returns the file name from teh APEX doc's URI
|
||||
|
||||
%param p_name - the APEX doc URI (in format unique ID/filename)
|
||||
%return VARCHAR2 - the actual name of the file
|
||||
*/
|
||||
FUNCTION get_fs_name(p_name IN documents.uri%TYPE) RETURN VARCHAR2;
|
||||
--
|
||||
PROCEDURE pl(p_in VARCHAR2);
|
||||
END mip_virus_check;
|
||||
/
|
||||
CREATE OR REPLACE PACKAGE BODY mip_virus_check IS
|
||||
/**
|
||||
Updates:
|
||||
MM 25-Feb-2008 added the load file
|
||||
*/
|
||||
PROCEDURE pl(p_in VARCHAR2) IS
|
||||
l_fh utl_file.file_type;
|
||||
BEGIN
|
||||
dbms_application_info.set_module('mip_virus_check', p_in);
|
||||
l_fh := utl_file.fopen(location => 'WEBMIP_VIRUS',
|
||||
filename => 'WEBMIP_VIRUS.txt',
|
||||
open_mode => 'A');
|
||||
utl_file.put_line(l_fh,
|
||||
to_char(SYSDATE, 'DD/MM/YYYY HH24:MI:SS') || ',' || p_in);
|
||||
utl_file.fclose(l_fh);
|
||||
END pl;
|
||||
|
||||
PROCEDURE write_file(p_name IN wwv_flow_files.NAME%TYPE
|
||||
,p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS'
|
||||
,p_fs_name IN VARCHAR2) IS
|
||||
PROCEDURE write_file(p_name IN wwv_flow_files.NAME%TYPE,
|
||||
p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
|
||||
p_fs_name IN VARCHAR2) IS
|
||||
l_lob_loc BLOB;
|
||||
l_buffer RAW(32767);
|
||||
l_buffer_size BINARY_INTEGER;
|
||||
@@ -36,12 +59,12 @@ CREATE OR REPLACE PACKAGE BODY mip_virus_check IS
|
||||
l_out_file utl_file.file_type;
|
||||
|
||||
BEGIN
|
||||
|
||||
pl('Writing file ' || p_name || ', ' || p_fs_name);
|
||||
SELECT blob_content
|
||||
INTO l_lob_loc
|
||||
FROM wwv_flow_files
|
||||
WHERE NAME = p_name;
|
||||
|
||||
WHERE upper(NAME) = upper(p_name);
|
||||
pl('Got file from APEX. Downloading');
|
||||
l_chunksize := dbms_lob.getchunksize(l_lob_loc);
|
||||
|
||||
IF (l_chunksize < 32767) THEN
|
||||
@@ -52,28 +75,27 @@ CREATE OR REPLACE PACKAGE BODY mip_virus_check IS
|
||||
|
||||
l_amount := l_buffer_size;
|
||||
|
||||
dbms_lob.OPEN(l_lob_loc
|
||||
,dbms_lob.lob_readonly);
|
||||
dbms_lob.OPEN(l_lob_loc, dbms_lob.lob_readonly);
|
||||
|
||||
l_out_file := utl_file.fopen(location => p_location
|
||||
,filename => p_fs_name
|
||||
,open_mode => 'wb'
|
||||
,max_linesize => 32767);
|
||||
l_out_file := utl_file.fopen(location => p_location,
|
||||
filename => p_fs_name,
|
||||
open_mode => 'wb',
|
||||
max_linesize => 32767);
|
||||
|
||||
WHILE l_amount >= l_buffer_size LOOP
|
||||
|
||||
dbms_lob.READ(lob_loc => l_lob_loc
|
||||
,amount => l_amount
|
||||
,offset => l_offset
|
||||
,buffer => l_buffer);
|
||||
dbms_lob.READ(lob_loc => l_lob_loc,
|
||||
amount => l_amount,
|
||||
offset => l_offset,
|
||||
buffer => l_buffer);
|
||||
|
||||
l_offset := l_offset + l_amount;
|
||||
|
||||
utl_file.put_raw(file => l_out_file
|
||||
,buffer => l_buffer
|
||||
,autoflush => TRUE);
|
||||
utl_file.put_raw(file => l_out_file,
|
||||
buffer => l_buffer,
|
||||
autoflush => TRUE);
|
||||
|
||||
--utl_file.fflush(file => l_out_file);
|
||||
--utl_file.fflush(file => l_out_file);
|
||||
|
||||
END LOOP;
|
||||
|
||||
@@ -83,90 +105,218 @@ CREATE OR REPLACE PACKAGE BODY mip_virus_check IS
|
||||
|
||||
dbms_lob.CLOSE(l_lob_loc);
|
||||
END write_file;
|
||||
|
||||
--
|
||||
FUNCTION trigger_av_scan(p_location IN VARCHAR2
|
||||
,p_fs_name IN VARCHAR2) RETURN BOOLEAN IS
|
||||
|
||||
/**
|
||||
load_file - procedure to reload the resultant file after virus checking is complete.
|
||||
|
||||
%param p_uri - the file's unique URI as stored in the Apex view
|
||||
*/
|
||||
PROCEDURE load_file(p_uri wwv_flow_files.NAME%TYPE) IS
|
||||
l_directory_path all_directories.directory_path%TYPE;
|
||||
l_source_file BFILE;
|
||||
l_source_file_length BINARY_INTEGER;
|
||||
l_blob BLOB;
|
||||
l_filename VARCHAR2(250);
|
||||
BEGIN
|
||||
NULL;
|
||||
|
||||
pl('reload_after_av');
|
||||
dbms_lob.createtemporary(lob_loc => l_blob, cache => TRUE);
|
||||
-- lock the table by selecting for update
|
||||
SELECT f.blob_content
|
||||
INTO l_blob
|
||||
FROM wwv_flow_files f
|
||||
|
||||
WHERE f.NAME = p_uri
|
||||
FOR UPDATE;
|
||||
|
||||
SELECT directory_path
|
||||
INTO l_directory_path
|
||||
FROM all_directories
|
||||
WHERE directory_name = 'WEBMIP_VIRUS';
|
||||
|
||||
l_filename := REPLACE(p_uri, '/', '!');
|
||||
|
||||
l_source_file := bfilename('WEBMIP_VIRUS', l_filename);
|
||||
l_source_file_length := dbms_lob.getlength(l_source_file);
|
||||
|
||||
dbms_lob.OPEN(file_loc => l_source_file,
|
||||
open_mode => dbms_lob.lob_readonly);
|
||||
|
||||
dbms_lob.loadfromfile(dest_lob => l_blob,
|
||||
src_lob => l_source_file,
|
||||
amount => l_source_file_length);
|
||||
|
||||
-- update the BLOB
|
||||
UPDATE wwv_flow_files f
|
||||
SET f.blob_content = l_blob
|
||||
WHERE f.NAME = p_uri;
|
||||
|
||||
--close the file
|
||||
dbms_lob.fileclose(file_loc => l_source_file);
|
||||
|
||||
pl('Loaded:' || l_filename);
|
||||
END load_file;
|
||||
--
|
||||
|
||||
/*\**
|
||||
trigger_av_scan - triggers the anti-virus scan on the file
|
||||
|
||||
%param p_location - the location of the file on the file server
|
||||
%param p_fs_name - the name of the file to check
|
||||
*\
|
||||
FUNCTION trigger_av_scan(p_fs_name IN VARCHAR2) RETURN BOOLEAN IS
|
||||
av_cmd VARCHAR2(250);
|
||||
av_checker VARCHAR2(250);
|
||||
l_location VARCHAR2(250);
|
||||
BEGIN
|
||||
dbms_output.put_line('Checking file.');
|
||||
av_checker := cout_system_configuration.get_configuration_item('AV_LOCATION');
|
||||
l_location := cout_system_configuration.get_configuration_item('AV_DIRECTORY');
|
||||
|
||||
av_cmd := '"' || av_checker ||'" /automation '||l_location||'\'||p_fs_name;
|
||||
|
||||
dbms_output.put_line('about to check');
|
||||
dbms_output.put_line(av_cmd);
|
||||
|
||||
mip_systemcall.syscall(p_cmd_str => av_cmd);
|
||||
|
||||
dbms_output.put_line('Finished checking');
|
||||
|
||||
RETURN TRUE;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
dbms_output.put_line(SQLERRM);
|
||||
RETURN NULL;
|
||||
END trigger_av_scan;
|
||||
--
|
||||
--*/
|
||||
|
||||
--
|
||||
FUNCTION check_file_exists(p_location IN VARCHAR2
|
||||
,p_fs_name IN VARCHAR2) RETURN BOOLEAN IS
|
||||
/**
|
||||
check_file_exists - tests if the file is still on the server
|
||||
if the file is no longer there then it has
|
||||
failed the virus scan and been quarantined
|
||||
|
||||
%param p_location - the location of the file on the file server
|
||||
%param p_fs_name - the name of the file to check
|
||||
*/
|
||||
FUNCTION check_file_exists(p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
|
||||
p_fs_name IN VARCHAR2) RETURN BOOLEAN IS
|
||||
l_file_exists BOOLEAN;
|
||||
l_file_length NUMBER;
|
||||
l_block_size NUMBER;
|
||||
BEGIN
|
||||
utl_file.fgetattr(location => p_location
|
||||
,filename => p_fs_name
|
||||
,fexists => l_file_exists
|
||||
,file_length => l_file_length
|
||||
,block_size => l_block_size);
|
||||
|
||||
utl_file.fgetattr(location => p_location,
|
||||
filename => p_fs_name,
|
||||
fexists => l_file_exists,
|
||||
file_length => l_file_length,
|
||||
block_size => l_block_size);
|
||||
pl('File exists:' || sys.diutil.bool_to_int(l_file_exists));
|
||||
RETURN l_file_exists;
|
||||
EXCEPTION
|
||||
WHEN OTHERS THEN
|
||||
WHEN OTHERS THEN
|
||||
RETURN FALSE;
|
||||
END check_file_exists;
|
||||
--
|
||||
|
||||
--
|
||||
PROCEDURE delete_file_from_server(p_location IN VARCHAR2
|
||||
,p_fs_name IN VARCHAR2) IS
|
||||
|
||||
/**
|
||||
delete_file_from_server - removes the files from the server once AV
|
||||
scan is complete. Housekeeping.
|
||||
|
||||
%param p_location - the location of the file on the file server
|
||||
%param p_fs_name - the name of the file to check
|
||||
*/
|
||||
PROCEDURE delete_file_from_server(p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
|
||||
p_fs_name IN VARCHAR2) IS
|
||||
BEGIN
|
||||
utl_file.fremove(location => p_location
|
||||
,filename => p_fs_name);
|
||||
utl_file.fremove(location => p_location, filename => p_fs_name);
|
||||
END delete_file_from_server;
|
||||
--
|
||||
|
||||
--
|
||||
PROCEDURE delete_file_from_MIP(p_name IN wwv_flow_files.NAME%TYPE) IS
|
||||
|
||||
/**
|
||||
delete_file_from_MIP - removes an infected file from the MIP system
|
||||
|
||||
%param p_location - the location of the file on the file server
|
||||
%param p_fs_name - the name of the file to check
|
||||
*/
|
||||
PROCEDURE delete_file_from_mip(p_doc_id documents.id%TYPE) IS
|
||||
l_result BOOLEAN;
|
||||
BEGIN
|
||||
NULL;
|
||||
END delete_file_from_MIP;
|
||||
--
|
||||
l_result := mip_files.delete_file(p_id => p_doc_id,
|
||||
p_doc_status => 'REMOVED MALICIOUS',
|
||||
p_reason => 'Malicious content found - deleted by Anti-virus.');
|
||||
|
||||
END delete_file_from_mip;
|
||||
--
|
||||
|
||||
/**
|
||||
check_file - allows MIP to run an anti-virus scan on a given file
|
||||
|
||||
%param p_name - the APEX name of the file
|
||||
%param p_location - the directory on the server where the file will be tested
|
||||
*/
|
||||
PROCEDURE check_file(p_name IN wwv_flow_files.NAME%TYPE,
|
||||
p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS',
|
||||
p_fs_name IN VARCHAR2) IS
|
||||
p_location IN VARCHAR2 DEFAULT 'WEBMIP_VIRUS') IS
|
||||
av_scan_result BOOLEAN;
|
||||
file_result BOOLEAN;
|
||||
l_fs_name VARCHAR2(250);
|
||||
l_doc_id documents.id%TYPE;
|
||||
BEGIN
|
||||
-- need to remove the slash from the URI so we can store multiple files
|
||||
-- change it to a "!" for now.
|
||||
l_fs_name := REPLACE(p_name, '/', '!');
|
||||
|
||||
SELECT doc.id INTO l_doc_id FROM documents doc WHERE doc.uri = p_name;
|
||||
|
||||
-- write the file to the file system, trigger a scan, check if the file is still there
|
||||
-- and then act accordingly if it isn't.
|
||||
write_file(p_name => p_name,
|
||||
p_location => p_location,
|
||||
p_fs_name => p_fs_name);
|
||||
p_fs_name => l_fs_name);
|
||||
|
||||
av_scan_result := trigger_av_scan(p_location => p_location,
|
||||
p_fs_name => p_fs_name);
|
||||
--dbms_lock.sleep(5);
|
||||
|
||||
IF av_scan_result THEN
|
||||
file_result := check_file_exists(p_location => p_location,
|
||||
p_fs_name => p_fs_name);
|
||||
|
||||
IF NOT file_result THEN
|
||||
delete_file_from_mip(p_name => p_name);
|
||||
ELSE
|
||||
delete_file_from_server(p_location => p_location,
|
||||
p_fs_name => p_fs_name);
|
||||
END IF;
|
||||
pl('Checking file exists:' || l_fs_name);
|
||||
file_result := check_file_exists(p_fs_name => l_fs_name);
|
||||
|
||||
IF NOT file_result THEN
|
||||
delete_file_from_mip(p_doc_id => l_doc_id);
|
||||
pl('File removed from MIP');
|
||||
ELSE
|
||||
raise_application_error(-20099,
|
||||
'Error whilst running anti-virus on file ' ||
|
||||
p_fs_name);
|
||||
-- reload the leftovers into MIP
|
||||
load_file(p_uri => p_name);
|
||||
|
||||
pl('Delete file from server');
|
||||
delete_file_from_server(p_location => p_location,
|
||||
p_fs_name => l_fs_name);
|
||||
|
||||
mip_documents.set_doc_available(p_docu_id => l_doc_id,
|
||||
p_description => 'Virus checked by MIP');
|
||||
|
||||
END IF;
|
||||
|
||||
END check_file;
|
||||
--
|
||||
|
||||
/**
|
||||
get_fs_name - returns the file name from the APEX doc's URI
|
||||
|
||||
BEGIN
|
||||
-- Initialization
|
||||
NULL;
|
||||
%param p_name - the APEX doc URI (in format unique ID/filename)
|
||||
%return VARCHAR2 - the actual name of the file
|
||||
*/
|
||||
FUNCTION get_fs_name(p_name IN documents.uri%TYPE) RETURN VARCHAR2 IS
|
||||
ret_fs_name VARCHAR2(250);
|
||||
seperator_pos NUMBER;
|
||||
BEGIN
|
||||
seperator_pos := instr(p_name, '/', -1);
|
||||
|
||||
IF NOT seperator_pos = 0 THEN
|
||||
ret_fs_name := substr(p_name, seperator_pos + 1);
|
||||
|
||||
RETURN ret_fs_name;
|
||||
ELSE
|
||||
RETURN NULL;
|
||||
END IF;
|
||||
END get_fs_name;
|
||||
--
|
||||
END mip_virus_check;
|
||||
/
|
||||
|
||||
Reference in New Issue
Block a user