{*******************************************************} { } { FileService } { } { Copyright (C) 2022 kku } { } {*******************************************************} unit FileService; interface uses Tocsg.Files, System.SysUtils, System.Classes, System.Generics.Collections, Vcl.Graphics, Tocsg.Thread, ManagerPattern, GlobalDefine, Winapi.Windows, ManagerModel; const IGNORE_MONITOR_EXT = 'inf|cat|db|AMS|dll|trm|xml|trc|DBF|tmp|igpi|$kv|' + 'crdownload|cab|uro|cach|sys'; IGNORE_PATH = '_marked.|_mask.|.rbs|.log|.uro|~$|pdmsa.prop|admsa.prop|uprism\cache|\$RECYCLE.BIN\|' + // IGNORE_PATH = '_marked.|_mask.|.rbs|.log|.uro|pdmsa.prop|admsa.prop|uprism\cache|\$RECYCLE.BIN\|' + ':\Windows\|\ProgramData\HE\|:\CubeLog\|\Windows\WER\Temp\|\AppData\Local\Microsoft\Office\Features\|' + 'ks_folder_watcher.txt|\Bs1Backup\'{AdobeReader 실행 시 탐지 발생}; // '\Windows\SoftwareDistribution\Download\'; IGNORE_DEL_PATH = '\Drivers\|\Chrome|\Bs1Backup\|' + '$WINDOWS|Program Files\|Program Files (x86)\|' + // Tocsg\|_TOCSG|' + '\Microsoft\Outlook\|ntuser.dat|.cach|.timestamp|\.oracle|' + 'desktop.ini|Visual Studio|.vssettings|\BSD2\|bootmgr.exe|' + '\Boot\|cisco\|\HDMessenger|\CTILog|ncky.bin|n5tmp.bin|\.eclipse|' + '\eclipse|org.eclipse|\Rsupport\|\Exosphere|\System Volume|' + '\KESS\|\MarkAny\|eCrmHome|WinSxS|ProgramData\|store.bin|' + 'Workspace\|AppData\|\Windows\INetCache\'; type TThdDelFiles = class(TTgThread) private qFiles_: TQueue; protected procedure Execute; override; public Constructor Create; Destructor Destroy; override; procedure Clear; procedure Push(sPath: String); end; TWaitEntTask = (wetExtrTxt, wetDoDRM, wetSendFile, wetPopup); TWaitEntTasks = set of TWaitEntTask; PWaitEnt = ^TWaitEnt; TWaitEnt = record sPath: String; Tasks: TWaitEntTasks; LogInfo: TLogInfo; bBlock, bIgrDrmBlock: Boolean; nMinMB, nLimitMB: Integer; dwAction: DWORD; end; TThdWaitProc = class(TTgThread) private qEnts_: TQueue; FList_: TStringList; procedure OnNotifyEnt(Sender: TObject; const Item: PWaitEnt; Action: TCollectionNotification); protected procedure Execute; override; public Constructor Create; Destructor Destroy; override; procedure Clear; function HashPath(sPath: String): Boolean; procedure Push(pEnt: PWaitEnt; bForce: Boolean = false); end; TThdEncFiles = class(TTgThread) private qFiles_: TQueue; sPass_: String; protected procedure Execute; override; public Constructor Create; Destructor Destroy; override; procedure Clear; procedure Push(sPath: String); end; PIgr1PInfo = ^TIgr1PInfo; TIgr1PInfo = record dwTick, dwMilSec: DWORD; end; TFileService = class(TTgDirWatchBase) private BlkRenameF_, BlkRenameDF_, MaskedList_, // 이미 마스킹 처리된 파일들을 일정 시간 반복 처리 하지 않기 위해 사용 22_0511 10:26:12 kku IgPathList_, ImgExtList_, DrmExtList_, MaskExtList_, IgMonExtList_, IgMonDirList_, IgBlockDirList_, MonExtList_, BlockExtList_, IgDelPathList_: TStringList; bIsWorking_: Boolean; MgPtn_: TManagerPattern; PatternEntList_: TPatternEntList; dwLangID_: WORD; ThdDelFiles_: TThdDelFiles; // ThdEncFiles_: TThdEncFiles; ThdWaitProc_: TThdWaitProc; // 수정 로그 2초에 한번 남게 23_1106 14:41:15 kku dwLastModTick_: DWORD; sLastModPath_: String; bBlockRename_, bPopupRename_: Boolean; sOldName_, sIgMonDirs_, sIgBlockDirs_, sMonExts_, sBlockExts_, sBlkRenameF_, sBlkRenameDF_, sBlkFRename_, sIgrBlkFRename_: String; UsbList_, ExpUsbList_, Igr1PathList_: TStringList; function IsIgrExt(sPath: String): Boolean; function IsIgrPath(sPath: String): Boolean; function IsIgrMonDir(sPath: String): Boolean; function IsIgrDelPath(sPath: String): Boolean; procedure ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); override; public Constructor Create; Destructor Destroy; override; procedure StartService; procedure StopService; procedure AddDriveWatch(sDrive: String; bIsUsb: Boolean = false; bExpUsb: Boolean = false); procedure AddIgr1Path(sPath: String; wAliveSec: WORD = 0); procedure DelDriveWatch(sDrive: String); function HasIgr1Path(sPath: String): Boolean; property IsWorking: Boolean read bIsWorking_; end; implementation uses Tocsg.Safe, Tocsg.Strings, Tocsg.Path, ManagerService, superobject, Tocsg.Exception, Condition, Tocsg.Disk, Tocsg.PCRE, Tocsg.Network, Tocsg.Process, CttSchDefine, Tocsg.Json, Tocsg.KvFilter.adinfo, Tocsg.DRM.Encrypt, Tocsg.Encrypt, KDL.Localizer, Tocsg.Packet, BsKwdSchKvCttSchClient, ManagerCampaign, Tocsg.Trace, Tocsg.Driver, Tocsg.Convert; resourcestring RS_WARNING_MSG = '중요문서 무단 반출 시 법적 제재를 받을수 있으며 모든 출력물은 모니터링 됩니다'; var PATTERNLIST: array [0..13] of String = ( '\d{2}[01]\d[0123]\d-\d{7}', '\d{2}[01]\d[0123]\d{8}', '\d\d[01]\d[0123]\d-\d{7}', '\d{2}[01]\d[0123]\d[ ]\d{7}', '\d{2}[01]\d[0123]\d-\d{7}', '\d{2}[01]\d[0123]\d{8}', '\d\d[01]\d[0123]\d-\d{7}', '\d{2}[01]\d[0123]\d[ ]\d{7}', '[0][1][016789][-) ]\d{3,4}[- ]\d{4}', '\d{2,4}[-) ][0-9]{3,4}[- ][0-9]{4}', '[a-zA-Z]{1}[0-9a-zA-Z]{1}[0-9]{7}', '([가-힣]{2}(\s|-)?|[가-힣]{2}-?)(\s|-)?\d{2}(\s|-)?\d{6}(\s|-)?\d{2}', '(?<=[^0-9a-zA-Z])([M|S|R|O|D|m|s|r|o|d][0-9]{8})(?=[^0-9a-zA-Z])', '(?<=[^0-9a-zA-Z])([a-zA-Z]{2}[0-9]{7})(?=[^0-9a-zA-Z])'); PATTERN_NAME_LIST: array [0..13] of String = ('&SSN&', '&SSN&', '&SSN&', '&SSN&', '&SSN&', '&SSN&', '&SSN&', '&SSN&', '&mobile&', '&mobile&', '&passport&', '&licenseNumber&', '&passport&', '&passport&'); KEYWORDLIST: array [0..64] of String = ( 'confident', 'confidence', 'disclose', 'secret', 'Antitrust Laws', 'legal', 'unpublish', 'financial', 'trade', 'patent', 'price','pricing', 'authorise', 'insecure','uncontroll' ,'Code of Ethics' ,'Prices', 'Costs','Profits','Offerings of products and services' ,'Terms of sale conditions','sales volume','Production capacity','Market share','Quote decisions' ,'Distribution methodology','Violations','Unauthorized', 'Complaint','Harassment' ,'audit','agency','assembly','industrial', '신뢰', '공개','비밀', '독점 금지법','반트러스트법', '범죄', '민감한', '기밀에 관련된', '법률상의', '철회', '금융', '재정상의', '거래', '특허', '가격', '가격 책정', '윤리강령', '판매 약관', '시장 점유율', '고객 선택', '판매 영역', '위반', '무단', '권한이 없는', '희롱', '감사', '회계감사', 'crime', 'sensitive', 'authorize', 'uncontrol' ); { TThdDelFiles } Constructor TThdDelFiles.Create; begin Inherited Create; qFiles_ := TQueue.Create; end; Destructor TThdDelFiles.Destroy; begin FreeAndNil(qFiles_); Inherited; end; procedure TThdDelFiles.Push(sPath: String); begin Lock; try qFiles_.Enqueue(sPath); finally Unlock; end; end; procedure TThdDelFiles.Clear; begin Lock; try qFiles_.Clear; finally Unlock; end; end; procedure TThdDelFiles.Execute; var sPath: String; bChkDrm: Boolean; fs: TFileStream; LogInfo: TLogInfo; begin while not Terminated and not GetWorkStop do begin try if qFiles_.Count = 0 then begin Sleep(500); continue; end; Lock; try sPath := qFiles_.Dequeue; finally Unlock; end; if sPath.Length > 0 then begin bChkDrm := sPath[1] = '*'; if bChkDrm then begin // DRM 적용된거 예외는 로그도 별도 처리해준다... 24_0528 14:56:58 kku var bBlock: Boolean := true; var bOpenFail: Boolean := false; Delete(sPath, 1, 1); if not FileExists(sPath) then continue; try // DRM 적용된거면 삭제안함 24_0528 14:08:46 kku Guard(fs, TFileStream.Create(sPath, fmOpenRead)); if TTgEncrypt.CheckSign(fs, SIG_DRM) then bBlock := false; except // 사용중등의 이유로 실패하면 다시 시도하게 Push('*' + sPath); Sleep(500); bOpenFail := true; end; if bOpenFail then continue; ZeroMemory(@LogInfo, SizeOf(LogInfo)); if bBlock then LogInfo.sCode := LOGCODE_PREVENT_FILEIO else LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; LogInfo.sPath := sPath; LogInfo.sSummary := Format('[Create] %s', [sPath]); gMgSvc.SendEventLogEx(@LogInfo, bBlock); if gMgSvc.ModePolicy.FileBlock.IsNoti then begin if bBlock then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, LogInfo.sSummary) else if CUSTOMER_TYPE <> CUSTOMER_SERVE1 then // 서브원은 팝업 안함 24_0711 08:45:55 kku gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, LogInfo.sSummary); end; if not bBlock then continue; end; if FileExists(sPath) then begin if not DeleteFile(PChar(sPath)) then begin Push(sPath); Sleep(500); end; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Execute()') end; end; end; { TThdWaitProc } Constructor TThdWaitProc.Create; begin Inherited Create; FList_ := TStringList.Create; FList_.CaseSensitive := false; qEnts_ := TQueue.Create; end; Destructor TThdWaitProc.Destroy; begin Clear; FreeAndNil(qEnts_); FreeAndNil(FList_); Inherited; end; procedure TThdWaitProc.OnNotifyEnt(Sender: TObject; const Item: PWaitEnt; Action: TCollectionNotification); begin if Action = cnRemoved then Dispose(Item); end; procedure TThdWaitProc.Clear; begin Lock; try qEnts_.OnNotify := OnNotifyEnt; qEnts_.Clear; FList_.Clear; finally qEnts_.OnNotify := nil; Unlock; end; end; function TThdWaitProc.HashPath(sPath: String): Boolean; begin Lock; try Result := FList_.IndexOf(sPath) <> -1; finally Unlock; end; end; procedure TThdWaitProc.Push(pEnt: PWaitEnt; bForce: Boolean = false); begin Lock; try if bForce or (FList_.IndexOf(pEnt.sPath) = -1) then begin if bForce then begin if FList_.IndexOf(pEnt.sPath) = -1 then FList_.Add(pEnt.sPath); end; qEnts_.Enqueue(pEnt); end; finally Unlock; end; end; procedure TThdWaitProc.Execute; var pEnt: PWaitEnt; fs: TFileStream; n: Integer; bIsDrm: Boolean; llSize: LONGLONG; begin while not Terminated and not GetWorkStop do begin bIsDrm := false; pEnt := nil; try Lock; try if qEnts_.Count > 0 then pEnt := qEnts_.Dequeue; finally Unlock; end; if pEnt = nil then begin Sleep(100); continue; end; if FileExists(pEnt.sPath) then begin // if GetFileSize_path(pEnt.sPath) > 5242880 then // begin // // 5MB 이상은 원문, 원본 수집 안되도록 보완 24_0725 15:50:15 kku // Exclude(pEnt.Tasks, wetSendFile); // Exclude(pEnt.Tasks, wetExtrTxt); // end; if (wetExtrTxt in pEnt.Tasks) or (pEnt.bBlock and pEnt.bIgrDrmBlock) then begin try Guard(fs, TFileStream.Create(pEnt.sPath, fmOpenRead)); bIsDrm := TTgEncrypt.CheckSign(fs, SIG_DRM); except Push(pEnt, true); Sleep(500); continue; end; if not bIsDrm and (wetExtrTxt in pEnt.Tasks) then pEnt.LogInfo.sBody := ExtrTextFromFile(pEnt.sPath); Exclude(pEnt.Tasks, wetExtrTxt); end; if pEnt.bBlock then begin if wetSendFile in pEnt.Tasks then begin if bIsDrm then begin if pEnt.bIgrDrmBlock then pEnt.bBlock := false; end; end else if bIsDrm and pEnt.bIgrDrmBlock then begin // 삭제 안함 end else if not DeleteFile(PChar(pEnt.sPath)) then begin // 삭제 실패 ? _Trace('파일 생성 차단 : 삭제 실패 .. Path = "%s"', [pEnt.sPath], 4); Push(pEnt, true); continue; end; end; if wetSendFile in pEnt.Tasks then begin try Guard(fs, TFileStream.Create(pEnt.sPath, fmOpenRead)); except // 사용중 등의 이유로 읽기 실패하면 재시도 _Trace('Fail .. Execute() .. wetSendFile .. 파일을 읽을 수 없습니다, Path=%s', [pEnt.sPath], 1); Push(pEnt, true); Sleep(1000); continue; end; llSize := GetFileSize_path(pEnt.sPath); if (llSize >= (LONGLONG(pEnt.nMinMB) * 1048576)) and (llSize <= (LONGLONG(pEnt.nLimitMB) * 1048576)) then begin pEnt.LogInfo.sFileCompId := gMgSvc.MakeComponentId(pEnt.sPath); if wetDoDRM in pEnt.Tasks then begin if IsUseEncOnlyAIP or gMgSvc.FirstAip then begin if CUSTOMER_TYPE = CUSTOMER_KDNVN then gMgSvc.SendFile(pEnt.LogInfo, 'quarantineLogCollect.do', pEnt.sPath, pEnt.nMinMB, pEnt.nLimitMB, crtAIP, BooleanToInt(pEnt.dwAction = 1, 30, 0)) else gMgSvc.SendFile(pEnt.LogInfo, 'quarantineLogCollect.do', pEnt.sPath, pEnt.nMinMB, pEnt.nLimitMB, crtAIP); end else gMgSvc.SendFile(pEnt.LogInfo, 'quarantineLogCollect.do', pEnt.sPath, pEnt.nMinMB, pEnt.nLimitMB, crtDRM); Exclude(pEnt.Tasks, wetDoDRM); end else if pEnt.bBlock then gMgSvc.SendFile(pEnt.LogInfo, 'quarantineLogCollect.do', pEnt.sPath, pEnt.nMinMB, pEnt.nLimitMB, crtDelete) else gMgSvc.SendFile(pEnt.LogInfo, 'quarantineLogCollect.do', pEnt.sPath, pEnt.nMinMB, pEnt.nLimitMB); end else if pEnt.bBlock and not DeleteFile(PChar(pEnt.sPath)) then // 크기제한에 걸린거면 바로 삭제 추가 24_0919 15:33:42 kku begin // 삭제 실패 ? _Trace('파일 생성 차단 : 삭제 실패2 .. Path = "%s"', [pEnt.sPath], 4); Push(pEnt, true); continue; end; Exclude(pEnt.Tasks, wetSendFile); end; if wetDoDRM in pEnt.Tasks then begin if IsUseEncOnlyAIP or gMgSvc.FirstAip then gMgSvc.ThdReact.AddEnt(crtAIP, pEnt.sPath, gMgSvc.ModePolicy.FileMonEncDelaySec) else gMgSvc.ThdReact.AddEnt(crtDRM, pEnt.sPath, gMgSvc.ModePolicy.FileMonEncDelaySec); Exclude(pEnt.Tasks, wetDoDRM); end; end; if wetPopup in pEnt.Tasks then begin if pEnt.bBlock then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, pEnt.LogInfo.sSummary) else gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, pEnt.LogInfo.sSummary); Exclude(pEnt.Tasks, wetPopup); end; gMgSvc.SendEventLogEx(@pEnt.LogInfo, pEnt.bBlock); Lock; try n := FList_.IndexOf(pEnt.sPath); if n <> -1 then FList_.Delete(n); finally Unlock; end; Dispose(pEnt); except // .. Sleep(200); if pEnt <> nil then Push(pEnt, true); end; end; end; { TThdEncFiles } Constructor TThdEncFiles.Create; begin Inherited Create; qFiles_ := TQueue.Create; sPass_ := GetMK; end; Destructor TThdEncFiles.Destroy; begin FreeAndNil(qFiles_); Inherited; end; procedure TThdEncFiles.Push(sPath: String); begin Lock; try qFiles_.Enqueue(sPath); finally Unlock; end; end; procedure TThdEncFiles.Clear; begin Lock; try qFiles_.Clear; finally Unlock; end; end; procedure TThdEncFiles.Execute; var sPath, sTaskDir, sTgEncPath: String; enc: TTgDrmEnc; bResult: Boolean; begin sTaskDir := 'C:\ProgramData\HE\EncTask\'; while not Terminated and not GetWorkStop do begin try if qFiles_.Count = 0 then begin Sleep(500); continue; end; Lock; try sPath := qFiles_.Dequeue; finally Unlock; end; if FileExists(sPath) and ForceDirectories(sTaskDir) then begin if TTgEncrypt.CheckSign(sPath, SIG_DRM) then continue; sTgEncPath := GetSameFileNameInc(sTaskDir + '$Tmp' + ExtractFileName(sPath)); if not MoveFile_wait(sPath, sTgEncPath, 3) then begin Push(sPath); Sleep(500); continue; end; SaveStrToFile(sTgEncPath + '.i', sPath, TEncoding.UTF8); bResult := false; enc := TTgDrmEnc.Create(sPath); try enc.SetHaed(PASS_DRM_HEAD, SIG_DRM, gMgSvc.EmpNo, gMgSvc.UserName, 'none', 'none', CUSTOMER_TYPE); bResult := enc.EncryptFromFile(sPass_, sTgEncPath); finally FreeAndNil(enc); end; if bResult then begin DeleteFile(PChar(sTgEncPath)); DeleteFile(PChar(sTgEncPath + '.i')); end else begin MoveFile_wait(sTgEncPath, sPath, 3); DeleteFile(PChar(sTgEncPath + '.i')); TTgTrace.T('Fail .. TThdEncFiles.EncFile(), Path=%s', [sPath]); end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. Execute()') end; end; end; { TFileService } Constructor TFileService.Create; procedure InitFilter; var sTemp: String; begin SetFilter(FILE_NOTIFY_CHANGE_FILE_NAME or FILE_NOTIFY_CHANGE_SIZE or FILE_NOTIFY_CHANGE_LAST_WRITE); SplitString(DOC_EXTS, '|', MaskExtList_); SplitString(IMAGE_EXTS, '|', ImgExtList_); sTemp := IGNORE_PATH + '|' + GetRunExePathDir; case CUSTOMER_TYPE of CUSTOMER_SANKYO : sTemp := sTemp + '|C:\HIWARE\|C:\HIWARE 6\'; CUSTOMER_CNSCERT : sTemp := sTemp + '|C:\WWNTUSER\'; CUSTOMER_ALADIN : sTemp := sTemp + '|\APPDATA\LOCAL\|\APPDATA\ROAMING\'; end; SplitString(UpperCase(sTemp), '|', IgPathList_); SplitString(UpperCase(IGNORE_DEL_PATH), '|', IgDelPathList_); sTemp := IGNORE_MONITOR_EXT; case CUSTOMER_TYPE of CUSTOMER_SANKYO : sTemp := sTemp + '|rbf|rtf|chm'; CUSTOMER_NHL : sTemp := sTemp + '|bmp|xsd|ico|exe'; end; SplitString(sTemp, '|', IgMonExtList_); end; begin Inherited Create(true, false); bIsWorking_ := false; sOldName_ := ''; sIgMonDirs_ := ''; sIgBlockDirs_ := ''; sMonExts_ := ''; sBlockExts_ := ''; sBlkRenameF_ := ''; sBlkRenameDF_ := ''; sBlkFRename_ := ''; sIgrBlkFRename_ := ''; bBlockRename_ := false; bPopupRename_ := false; DrmExtList_ := TStringList.Create; DrmExtList_.CaseSensitive := false; SplitString(DRM_EXTS, '|', DrmExtList_); MaskExtList_ := TStringList.Create; MaskExtList_.CaseSensitive := false; ImgExtList_ := TStringList.Create; ImgExtList_.CaseSensitive := false; IgPathList_ := TStringList.Create; IgPathList_.CaseSensitive := false; IgDelPathList_ := TStringList.Create; IgDelPathList_.CaseSensitive := false; IgMonExtList_ := TStringList.Create; IgMonExtList_.CaseSensitive := false; IgMonDirList_ := TStringList.Create; IgMonDirList_.CaseSensitive := false; IgBlockDirList_ := TStringList.Create; IgBlockDirList_.CaseSensitive := false; MaskedList_ := TStringList.Create; MaskedList_.CaseSensitive := false; BlkRenameF_ := TStringList.Create; BlkRenameDF_ := TStringList.Create; MonExtList_ := TStringList.Create; MonExtList_.CaseSensitive := false; BlockExtList_ := TStringList.Create; BlockExtList_.CaseSensitive := false; UsbList_ := TStringList.Create; UsbList_.CaseSensitive := false; ExpUsbList_ := TStringList.Create; ExpUsbList_.CaseSensitive := false; Igr1PathList_ := TStringList.Create; Igr1PathList_.CaseSensitive := false; sLastModPath_ := ''; dwLastModTick_ := 0; MgPtn_ := TManagerPattern.Create; PatternEntList_ := TPatternEntList.Create(false); MgPtn_.GetUsePatternEnt(PatternEntList_); dwLangID_ := GetSystemDefaultLangID; // todo : 설정된 LangID 가져오기 추가 22_0713 16:18:41 kku ThdDelFiles_ := TThdDelFiles.Create; // ThdEncFiles_ := TThdEncFiles.Create; ThdWaitProc_ := TThdWaitProc.Create; InitFilter; end; Destructor TFileService.Destroy; begin StopService; Inherited; FreeAndNil(Igr1PathList_); FreeAndNil(ExpUsbList_); FreeAndNil(UsbList_); FreeAndNil(BlkRenameDF_); FreeAndNil(BlkRenameF_); FreeAndNil(MaskedList_); FreeAndNil(BlockExtList_); FreeAndNil(MonExtList_); FreeAndNil(IgBlockDirList_); FreeAndNil(IgMonDirList_); FreeandNil(IgMonExtList_); FreeAndNil(IgDelPathList_); FreeAndNil(IgPathList_); FreeAndNil(ImgExtList_); FreeAndNil(MaskExtList_); FreeAndNil(DrmExtList_); FreeAndNil(ThdWaitProc_); // FreeAndNil(ThdEncFiles_); FreeAndNil(ThdDelFiles_); FreeAndNil(PatternEntList_); FreeAndNil(MgPtn_); end; procedure TFileService.StartService; var dwLogicalDrv: DWORD; i: Integer; sDrive: String; DriveInfo: TDriveInfo; begin if not bIsWorking_ then begin bIsWorking_ := true; dwLogicalDrv := GetLogicalDrives; for i := 0 to 31 do if (dwLogicalDrv and (1 shl i)) > 0 then begin sDrive := Format('%s:\', [Char(Integer('A')+i)]); if CUSTOMER_TYPE <> CUSTOMER_NHL then begin // 불량(?) 디스크 걸러내기 // NHL에서는 이렇게 하면 인식하지 못한다.. 내부 보안모듈 때문인듯 22_0923 11:16:27 kku // if GetDriveExtent(sDrive).liExtentLength.QuadPart = 0 then if not DirectoryExists(sDrive) then continue; end; GetDriveDetail(sDrive, @DriveInfo); AddDriveWatch(sDrive, Pos('USB', UpperCase(DriveInfo.sSerial)) = 1); // AddDriveWatch(sDrive, GetDriveType(PChar(sDrive)) = DRIVE_REMOVABLE); // 외장 디스크는 "DRIVE_FIXED"로 인식됨 24_0829 11:12:27 kku end; ThdDelFiles_.StartThread; // ThdEncFiles_.StartThread; ThdWaitProc_.StartThread; Processor_.StartThread; end; end; procedure TFileService.StopService; begin if bIsWorking_ then begin bIsWorking_ := false; ThdDelFiles_.Clear; ThdDelFiles_.PauseThread; // ThdEncFiles_.Clear; // ThdEncFiles_.PauseThread; ThdWaitProc_.Clear; ThdWaitProc_.PauseThread; Processor_.Clear; Processor_.PauseThread; ExpUsbList_.Clear; UsbList_.Clear; Igr1PathList_.Clear; sLastModPath_ := ''; dwLastModTick_ := 0; try ClearDirWatch; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. StopService()'); end; end; end; procedure TFileService.AddDriveWatch(sDrive: String; bIsUsb: Boolean = false; bExpUsb: Boolean = false); begin if sDrive = '' then exit; if bIsUsb and (UsbList_.IndexOf(sDrive[1]) = -1) then UsbList_.Add(sDrive[1]); if bExpUsb and (ExpUsbList_.IndexOf(sDrive[1]) = -1) then ExpUsbList_.Add(sDrive[1]); AddDirWatch(sDrive); end; // 1회 감시 무시, DRM 임시 파일등 처리 23_1215 10:12:36 kku procedure TFileService.AddIgr1Path(sPath: String; wAliveSec: WORD = 0); var i: Integer; pEnt: PIgr1PInfo; begin try Lock; try i := Igr1PathList_.IndexOf(sPath); if i = -1 then begin if wAliveSec > 0 then begin New(pEnt); pEnt.dwTick := GetTickCount; pEnt.dwMilSec := wAliveSec * 1000; Igr1PathList_.AddObject(sPath, TObject(pEnt)); end else Igr1PathList_.Add(sPath); end else begin if wAliveSec > 0 then begin pEnt := PIgr1PInfo(Igr1PathList_.Objects[i]); if pEnt = nil then begin New(pEnt); Igr1PathList_.Objects[i] := TObject(pEnt); end; pEnt.dwTick := GetTickCount; pEnt.dwMilSec := wAliveSec * 1000; end; end; finally Unlock; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. AddIgr1Path()'); end; end; procedure TFileService.DelDriveWatch(sDrive: String); var n: Integer; begin if sDrive = '' then exit; n := UsbList_.IndexOf(sDrive[1]); if n <> -1 then UsbList_.Delete(n); n := ExpUsbList_.IndexOf(sDrive[1]); if n <> -1 then ExpUsbList_.Delete(n); DelDirWatch(sDrive); end; function TFileService.HasIgr1Path(sPath: String): Boolean; var i: Integer; pEnt: PIgr1PInfo; dwTick: DWORD; begin Result := false; try Lock; try if Igr1PathList_.Count = 0 then exit; dwTick := GetTickCount; for i := Igr1PathList_.Count - 1 downto 0 do begin pEnt := PIgr1PInfo(Igr1PathList_.Objects[i]); if pEnt <> nil then begin if (dwTick - pEnt.dwTick) > pEnt.dwMilSec then begin Dispose(pEnt); Igr1PathList_.Delete(i); end; end; end; i := Igr1PathList_.IndexOf(sPath); if i <> -1 then begin if Igr1PathList_.Objects[i] = nil then Igr1PathList_.Delete(i); Result := true; end; finally Unlock; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. HasIgr1Path()'); end; end; function TFileService.IsIgrExt(sPath: String): Boolean; begin Result := false; try if sPath = '' then exit; // USB라면 확장자 예외 무시 24_0722 09:56:01 kku if (UsbList_.Count > 0) and (UsbList_.IndexOf(sPath[1]) <> -1) then exit; Result := IgMonExtList_.IndexOf(GetFileExt(sPath)) <> -1; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. IsIgrExt()'); end; end; function TFileService.IsIgrPath(sPath: String): Boolean; var i: Integer; begin Result := false; try if sPath = '' then exit; // USB라면 확장자 예외 무시 24_0722 09:56:01 kku if (UsbList_.Count > 0) and (UsbList_.IndexOf(sPath[1]) <> -1) then exit; sPath := UpperCase(sPath); for i := 0 to IgPathList_.Count - 1 do begin if sPath.Contains(IgPathList_[i]) then begin Result := true; exit; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. IsIgrPath()'); end; end; function TFileService.IsIgrMonDir(sPath: String): Boolean; var i: Integer; begin Result := false; try if sPath = '' then exit; sPath := UpperCase(sPath); for i := 0 to IgMonDirList_.Count - 1 do begin if sPath.Contains(IgMonDirList_[i].ToUpper) then begin Result := true; exit; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. IsIgrPath()'); end; end; function TFileService.IsIgrDelPath(sPath: String): Boolean; var i: Integer; begin Result := false; try if sPath = '' then exit; // USB라면 확장자 예외 무시 24_0722 09:56:01 kku if (UsbList_.Count > 0) and (UsbList_.IndexOf(sPath[1]) <> -1) then exit; sPath := UpperCase(sPath); for i := 0 to IgDelPathList_.Count - 1 do begin if sPath.Contains(IgDelPathList_[i]) then begin Result := true; exit; end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. IsIgrDelPath()'); end; end; procedure TFileService.ProcessDirWatchEnt(Sender: TObject; pInfo: PDirWatchEnt); var PO: TPrefModel; bFileMonPO, bFileBlockPO, bIsCollectTxt, bIsCollectFile: Boolean; function CheckIgrFile(sPath: String): Boolean; var i: Integer; begin Result := true; sPath := UpperCase(sPath); if CUSTOMER_TYPE <> CUSTOMER_GEC then begin { if (sExt = 'DOC') or (sExt = 'XLS') or (sExt = 'PPT') or (sExt = 'DOT') or (sExt = 'PPS') or (sExt = 'POT') then begin Result := IsAipEncrytedOldOfficeDoc(sPath, sTempDir); if not Result then Result := IsAipEncrytedOfficeDoc(sPath, sTempDir); end else if (sExt = 'DOCX') or (sExt = 'XLSX') or (sExt = 'PPTX') or (sExt = 'DOCM') or (sExt = 'DOTX') or (sExt = 'XLSM') or (sExt = 'XLSB') then begin } // 별도 처리 추가 (NH 요청) 22_0809 13:58:28 kku if sPath.Contains('MICROSOFT') then begin var sExt: String := GetFileExt(sPath); if (sExt = 'DOC') or (sExt = 'DOCX') or (sExt = 'RTF') or (sExt = 'XLS') or (sExt = 'XLSX') or (sExt = 'PPT') or // 추가 25_0106 13:19:44 kku (sExt = 'DOT') or (sExt = 'PPS') or (sExt = 'POT') or (sExt = 'DOCM') or (sExt = 'DOTX') or (sExt = 'XLSM') or (sExt = 'XLSB') or (sExt = 'PDF') or (sExt = 'PPTX') or (sExt = 'TXT') then Exit(true) else Exit(false); end; end; if IsIgrDelPath(sPath) then begin Result := false; exit; end; end; function ExtrTxtData(aType: TCttSchTaskType; sSrcPath, sDestPath: String; sAssocInfo: String = ''): Boolean; var sExe, sParam: String; O: ISuperObject; Opt: TCttSimpleOpt; begin Result := false; sExe := GetRunExePathDir + EXE_KVCTTSCH; if not FileExists(sExe) then exit; Opt.sSrcPath := sSrcPath; Opt.sDestPath := sDestPath; Opt.sAssocInfo := sAssocInfo; sParam := GetRunExePathDir + '$kvcs.dat'; O := SO; O.I['CSTT'] := Integer(aType); O.O['SOpt'] := TTgJson.ValueToJsonObject(Opt); if SaveJsonObjToFile(O, sParam) then begin if ExecuteAppWaitUntilTerminate(sExe, Format('-p "%s"', [sParam]), SW_HIDE, 20000) then Result := FileExists(sDestPath); end; end; // yhkim 251203 파일 변경 감시/파일 생성 차단 예외 폴더 지정시 예약어 추가 procedure SetReplaceDir(DirList: TStringList); var i: Integer; userProfile: string; begin userProfile := GetEnvironmentVariable('USERPROFILE'); // C:\Users\<계정명> for i := 0 to DirList.Count - 1 do begin if (Length(DirList[i]) > 2) and (DirList[i][1] = '%') and (DirList[i][Length(DirList[i])] = '%') then begin if SameText(DirList[i], '%USERPROFILE%') then DirList[i] := userProfile else if SameText(DirList[i], '%Desktop%') then DirList[i] := userProfile + '\Desktop' else if SameText(DirList[i], '%Documents%') then DirList[i] := userProfile + '\Documents' else if SameText(DirList[i], '%APPDATA%') then DirList[i] := userProfile + '\AppData' else if SameText(DirList[i], '%LOCALAPPDATA%') then DirList[i] := userProfile + '\AppData\Local' else if SameText(DirList[i], '%TEMP%') then DirList[i] := userProfile + '\AppData\Local\Temp' else if SameText(DirList[i], '%Downloads%') then DirList[i] := userProfile + '\Downloads' else if SameText(DirList[i], '%Windows%') then DirList[i] := 'C:\Windows' else if SameText(DirList[i], '%ProgramData%') then DirList[i] := 'C:\ProgramData'; end; end; end; procedure UpdateExtInfo; begin if PO.IsOldPolicy then begin if sMonExts_ <> PO.FileMonExt then begin sMonExts_ := PO.FileMonExt; SplitString(StringReplace(sMonExts_, '.', '', [rfReplaceAll]), '|', MonExtList_); SplitString(StringReplace(sMonExts_, '.', '', [rfReplaceAll]), '|', BlockExtList_); end; end else begin if sMonExts_ <> PO.FileMon.sExts then begin sMonExts_ := PO.FileMon.sExts; SplitString(StringReplace(sMonExts_, '.', '', [rfReplaceAll]), '|', MonExtList_); end; if sBlockExts_ <> PO.FileBlock.sExts then begin sBlockExts_ := PO.FileBlock.sExts; SplitString(StringReplace(sBlockExts_, '.', '', [rfReplaceAll]), '|', BlockExtList_); end; if sIgMonDirs_ <> PO.FileMon.sExceptPath then begin sIgMonDirs_ := PO.FileMon.sExceptPath; SplitString(sIgMonDirs_, '|', IgMonDirList_); SetReplaceDir(IgMonDirList_); end; if sIgBlockDirs_ <> PO.FileBlock.sExceptPath then begin sIgBlockDirs_ := PO.FileBlock.sExceptPath; SplitString(sIgBlockDirs_, '|', IgBlockDirList_); SetReplaceDir(IgBlockDirList_); end; end; end; function GetEventToStr: String; begin case pInfo.dwAction of 1 : Result := 'Create'; 3 : Result := 'Modify'; 5 : begin // 오피스 파일의 경우 파일 수정 시 "~WND2391.tmp"의 임시 파일을 이름 변경으로 저장한다.. 이를 보정 23_1204 19:41:55 kku if (sOldName_ <> '') and (sOldName_[1] = '~') and (GetFileExt(sOldName_).ToUpper = 'TMP') then Result := 'Modify' else Result := 'Rename'; end else Result := Format('Unknown-%d', [pInfo.dwAction]); end; end; {$IFDEF WIN64} procedure MaskingFromFile(nType: Integer; sSrcPath, sOrgPath: String); const DOC_HEADER_FMT = '%s%s'; var StrList: TStringList; sData, sClass, sFormat, sHeader, sResult, sDestPath: String; i, c: Integer; DocInfo: TAdDocInfo; O: ISuperObject; llSize: LONGLONG; begin try Guard(StrList, TStringList.Create); sData := ExtractTextSafe(sSrcPath); if PO.IsOldPolicy then begin // 키뷰로 아래한글등 문서내용을 추출 못하는 경우가 있다. if sData <> '' then begin for i := 0 to PatternEntList_.Count - 1 do begin if TTgPcre.GetMatchValues(sData, PatternEntList_[i].GetSearchText, sResult) > 0 then begin SplitString(sResult, ',', StrList, false, true); for c := 0 to StrList.Count - 1 do sData := StringReplace(sData, StrList[c], '&' + PatternEntList_[i].Name + '&', [rfReplaceAll]); end; end; if GetUserDefaultLangID = $412 then sFormat := '&키워드&' else sFormat := '&Keyword&'; for i := Low(KEYWORDLIST) to High(KEYWORDLIST) do sData := StringReplace(sData, KEYWORDLIST[i], sFormat, [rfReplaceAll]); StrList.Text := sData; StrList.SaveToFile(sSrcPath, TEncoding.UTF8); if sData.Length > 1500 then SetLength(sData, 1500); end; gMgSvc.PopupMessage(nType, sOrgPath); sDestPath := GetRunExePathDir + 'Task\'; if not ForceDirectories(sDestPath) then exit; sDestPath := sDestPath + ExtractFileName(pInfo.sPath) + '.tmp'; try if not ExtrTxtData(csttExtrDocInfo, sOrgPath, sDestPath) then exit; if not LoadJsonObjFromFile(O, sDestPath) then exit; if O.O['Info'] = nil then exit; finally if FileExists(sDestPath) then DeleteFile(PChar(sDestPath)); end; DocInfo := TTgJson.GetDataAsType(O.O['Info']); if (DocInfo.eClass > -1) and (DocInfo.eClass < 22) then sClass := ENdocClassDescStrs[DocInfo.eClass] else sClass := 'Unknown format'; if (DocInfo.eFormat > -1) and (DocInfo.eFormat < 437) then sFormat := ENdocFmtDescStrs[DocInfo.eFormat] else sFormat := 'No Format Found'; sHeader := Format(DOC_HEADER_FMT, [sClass, sFormat]); sResult := Format('[%s] %s%s%s', [GetEventToStr, sOrgPath, sHeader, sData]); case nType of TYPE_MSG_PREVENT_FILECHANGE : sHeader := LOGCODE_PREVENT_FILEMONITOR; TYPE_MSG_PREVENT_FILEMASK : sHeader := LOGCODE_PREVENT_FILEMASK; TYPE_MSG_PREVENT_FILEWRITE : sHeader := LOGCODE_PREVENT_FILEIO; TYPE_MSG_PREVENT_FILEDRMENC : sHeader := PREVENT_DRM_ENCRYPT; end; gMgSvc.SendEventLog(URI_USER_ACTION, sHeader, sResult); end else begin sDestPath := GetRunExePathDir + 'Task\'; if ForceDirectories(sDestPath) then begin sDestPath := sDestPath + ExtractFileName(pInfo.sPath) + '.tmp'; if ExtrTxtData(csttExtrDocInfo, sOrgPath, sDestPath) then begin try if LoadJsonObjFromFile(O, sDestPath) then begin DocInfo := TTgJson.GetDataAsType(O.O['Info']); if (DocInfo.eClass > -1) and (DocInfo.eClass < 22) then sClass := ENdocClassDescStrs[DocInfo.eClass] else sClass := 'Unknown format'; if (DocInfo.eFormat > -1) and (DocInfo.eFormat < 437) then sFormat := ENdocFmtDescStrs[DocInfo.eFormat] else sFormat := 'No Format Found'; sHeader := Format(DOC_HEADER_FMT, [sClass, sFormat]); end; finally DeleteFile(PChar(sDestPath)); end; end; end; var LogInfo: TLogInfo; ZeroMemory(@LogInfo, SizeOf(LogInfo)); case nType of TYPE_MSG_PREVENT_FILECHANGE : LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; TYPE_MSG_PREVENT_FILEMASK : LogInfo.sCode := LOGCODE_PREVENT_FILEMASK; TYPE_MSG_PREVENT_FILEWRITE : LogInfo.sCode := LOGCODE_PREVENT_FILEIO; TYPE_MSG_PREVENT_FILEDRMENC : LogInfo.sCode := PREVENT_DRM_ENCRYPT; end; if (bFileMonPO and bIsCollectTxt) or (bFileBlockPO and PO.FileBlock.IsCollectTxt) then LogInfo.sBody := sData; if (bFileMonPO and bIsCollectFile) or (bFileBlockPO and PO.FileBlock.IsCollectFile) then begin llSize := GetFileSize_path(sOrgPath); if (llSize >= (LONGLONG(PO.FileMonMinMB) * 1048576)) and (llSize <= (LONGLONG(PO.FileMonLimitMB) * 1048576)) then begin LogInfo.sFileCompId := gMgSvc.MakeComponentId(sOrgPath); if bFileMonPO and bIsCollectFile and PO.FileMon.DoEnc then begin if IsUseEncOnlyAIP or gMgSvc.FirstAip then gMgSvc.SendFile(LogInfo, 'quarantineLogCollect.do', sOrgPath, PO.FileMonMinMB, PO.FileMonLimitMB, crtAIP, PO.FileMonEncDelaySec) else gMgSvc.SendFile(LogInfo, 'quarantineLogCollect.do', sOrgPath, PO.FileMonMinMB, PO.FileMonLimitMB, crtDRM, PO.FileMonEncDelaySec); end else if bFileBlockPO and PO.FileBlock.IsCollectFile then gMgSvc.SendFile(LogInfo, 'quarantineLogCollect.do', sOrgPath, PO.FileMonMinMB, PO.FileBlkLimitMB, crtDelete) else gMgSvc.SendFile(LogInfo, 'quarantineLogCollect.do', sOrgPath, PO.FileMonMinMB, PO.FileBlkLimitMB); end; end; LogInfo.sPath := sOrgPath; // Action : 1 = Add, 2 = Delete, 3 = Modify, 4 = Rename, 5 = NewName if pInfo.dwAction = 5 then begin if (sOldName_ <> '') and (sOldName_[1] = '~') and (GetFileExt(sOldName_).ToUpper = 'TMP') then LogInfo.sSummary := Format('[Modify] %s', [sOrgPath]) else LogInfo.sSummary := Format('[Rename] %s', [sOrgPath + ' < Old : ' + sOldName_]); end else LogInfo.sSummary := Format('[%s] %s', [GetEventToStr, sOrgPath]); if bFileMonPO and PO.FileMon.DoEnc and not bIsCollectFile then begin if IsUseEncOnlyAIP or gMgSvc.FirstAip then gMgSvc.ThdReact.AddEnt(crtAIP, sOrgPath, PO.FileMonEncDelaySec) else gMgSvc.ThdReact.AddEnt(crtDRM, sOrgPath, PO.FileMonEncDelaySec); end; gMgSvc.SendEventLogEx(@LogInfo, LogInfo.sCode = LOGCODE_PREVENT_FILEIO); if PO.FileMon.IsNoti then gMgSvc.PopupMessage(nType, LogInfo.sSummary); end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. MaskingFromFile()') end; end; procedure RefineRecentMask; var i: Integer; begin for i := MaskedList_.Count - 1 downto 0 do begin if (GetTickCount - DWORD(MaskedList_.Objects[i])) >= 5000 then MaskedList_.Delete(i) end; end; function CheckRecentMask(sPath: String): Boolean; var i: Integer; begin Result := false; i := MaskedList_.IndexOf(sPath); if i = -1 then exit; Result := (GetTickCount - DWORD(MaskedList_.Objects[i])) < 5000; end; {$ENDIF} var sExt, sDir, sFName, sIgCheck, sDestPath: String; bLoadFail: Boolean; i, nRetryCnt: Integer; LogInfo: TLogInfo; llSize: LONGLONG; // 파일이 사용중일 수 있다. 1초 간격으로 5번까지 시도해본다. Label LB_Retry1, LB_Retry2; begin try sDir := ExtractFilePath(pInfo.sPath); sFName := ExtractFileName(pInfo.sPath); sExt := GetFileExt(sFName); PO := gMgSvc.ModePolicy; // DRM 임시파일 무시 23_1215 09:55:23 kku sIgCheck := GetCapsuleStr('#', '_', pInfo.sPath); if (sIgCheck <> '') and (StrToIntDef(sIgCheck, 0) <> 0) then exit; if HasIgr1Path(pInfo.sPath) then exit; case pInfo.dwAction of 1, 3 : ; // 추가, 수정, 새이름 아니면 무시 2 : // 삭제 begin if (PO.FileMon.Kind <> fmkNone) and PO.FileMon.DeleteEvt then begin if PO.FileMon.OnlyUSB and (Length(sDir) > 0) and (UsbList_.IndexOf(sDir[1]) = -1) then exit; UpdateExtInfo; case PO.FileMon.Kind of fmkNone : bFileMonPO := false; fmkAll : bFileMonPO := true; fmkIncExt : bFileMonPO := (MonExtList_.IndexOf(sExt) <> -1) or ((sExt = '') and (MonExtList_.IndexOf('!EXT') <> -1)); fmkIgrExt : begin bFileMonPO := MonExtList_.IndexOf(sExt) = -1; if bFileMonPO and (sExt = '') then bFileMonPO := MonExtList_.IndexOf('!EXT') = -1; end; end; if bFileMonPO then begin if IsIgrPath(pInfo.sPath) then exit; // if IsIgrExt(pInfo.sPath) then // exit; if IsIgrMonDir(pInfo.sPath) then exit; if PO.IsOldPolicy then begin gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_FILEMONITOR, Format('[Delete] %s', [pInfo.sPath])); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, pInfo.sPath); end else begin if PO.FileMon.DoEnc and gMgSvc.HasEncIgr(pInfo.sPath) then exit; ZeroMemory(@LogInfo, SizeOf(LogInfo)); LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; LogInfo.sPath := pInfo.sPath; LogInfo.sSummary := Format('[Delete] %s', [pInfo.sPath]); gMgSvc.SendEventLogEx(@LogInfo, false); if PO.FileMon.IsNoti then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, LogInfo.sSummary); end; end; end; exit; end; 4 : begin sOldName_ := sFName; if sIgrBlkFRename_ = sFName then begin sIgrBlkFRename_ := ''; exit; end; case PO.BlockFRename of bfrExe : if (sExt = '') or (sExt.ToUpper <> 'EXE') then exit; bfrNoExe : if (sExt = '') or (sExt.ToUpper = 'EXE') then exit; end; var sChkPath: String := UpperCase(sFName); if PO.BlockFRename <> bfrFalse then begin if PO.BlockFRenames <> sBlkRenameF_ then begin sBlkRenameF_ := PO.BlockFRenames; SplitString(UpperCase(sBlkRenameF_), '|', BlkRenameF_); end; for i := 0 to BlkRenameF_.Count - 1 do begin if Pos(BlkRenameF_[i], sChkPath) > 0 then begin sBlkFRename_ := sFName; case PO.BlockFRename of bfrAll, bfrExe, bfrNoExe : bBlockRename_ := true; bfrPopup : bPopupRename_ := true; end; exit; end; end; end; sChkPath := UpperCase(pInfo.sPath); if PO.BlockFdRename <> bdrFalse then begin if PO.BlockDirFileRenames <> sBlkRenameDF_ then begin sBlkRenameDF_ := PO.BlockDirFileRenames; SplitString(UpperCase(sBlkRenameDF_), '|', BlkRenameDF_); end; for i := 0 to BlkRenameDF_.Count - 1 do begin case Pos(BlkRenameDF_[i], sChkPath) of 1, 2: begin case PO.BlockFdRename of bdrAll, bdrLog : sBlkFRename_ := sFName; bdrPopup : begin sBlkFRename_ := sFName; bPopupRename_ := true; end; bdrThis : begin var sChkDir1: String := IncludeTrailingPathDelimiter(BlkRenameDF_[i]); var sChkDir2: String := ExtractFilePath(sChkPath); // :\Temp\ 비교를 위해 앞을 하나 잘라줌 if sChkDir1[1] = ':' then Delete(sChkDir2, 1, 1); if sChkDir1 = sChkDir2 then sBlkFRename_ := sFName; end; end; break; end; end; end; if not bPopupRename_ then bBlockRename_ := (sBlkFRename_ <> '') and (PO.BlockFdRename <> bdrLog); end; exit; end; 5 : begin // 이름 변경 복구 체크 if sBlkFRename_ <> '' then begin if bBlockRename_ then begin sIgrBlkFRename_ := sFName; bBlockRename_ := false; if MoveFile_wait(pInfo.sPath, sDir + sBlkFRename_, 5) then begin gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILERENAME, sBlkFRename_ + '|' + sFName + '|' + sDir); gMgSvc.SendEventLog(URI_USER_ACTION, PREVENT_FILERENAME, Format('[Rename] OrgName : %s, NewName : %s, Path : %s', [sBlkFRename_, sFName, sDir])); sFName := sBlkFRename_; pInfo.sPath := sDir + sFName; end; end else begin if bPopupRename_ then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILERENAME, sBlkFRename_ + '|' + sFName + '|' + sDir + '|M'); gMgSvc.SendEventLog(URI_USER_ACTION, MONITOR_FILERENAME, Format('[Rename] OrgName : %s, NewName : %s, Path : %s', [sBlkFRename_, sFName, sDir]), false); end; sBlkFRename_ := ''; bPopupRename_ := false; end; end; else exit; end; // 존재하는 파일만 처리 if not FileExists(pInfo.sPath) then exit; // 처리 무시 체크 if IsIgrPath(pInfo.sPath) then exit; // 원래 삭제 무시 체크 해서 삭제 작업만 구분 하려고 했지만... // 모든 파일 대상으로 처리 함 22_0504 16:06:35 kku if not CheckIgrFile(pInfo.sPath) then exit; {$IFDEF WIN64} RefineRecentMask; {$ENDIF} UpdateExtInfo; if PO.IsPreventDownloads then begin // 다운로드 폴더 차단 추가 sDestPath := UpperCase(sDir); if Pos('\DOWNLOADS\', sDestPath) > 0 then begin ThdDelFiles_.Push(pInfo.sPath); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, pInfo.sPath); gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_FILEIO, Format('%s', [pInfo.sPath])); exit; // 파일 쓰기 차단 처리 후 탈출 end; end else if CUSTOMER_TYPE = CUSTOMER_ALADIN then begin sDestPath := UpperCase(sDir); if Pos('\DOWNLOADS\', sDestPath) > 0 then exit; end; if PO.IsWaterMark then begin if ImgExtList_.IndexOf(sExt) <> -1 then begin // var sToday: String := FormatDateTime('yyyy-mm-dd hh:nn:ss', Now); var sWaterTxt: String; // var sAppend: String := sToday;// + '/' + gMgSvc.EmpNo +'/' + gMgSvc.HandleConfig.UserName; if IsWatermarkNH then sWaterTxt := RS_WARNING_MSG else if IsWatermarkKFTC then sWaterTxt := gMgSvc.EmpNo + '/' + gMgSvc.HandleConfig.UserName + '/' + gMgSvc.NicService.GetIP + '/' else sWaterTxt := gMgSvc.HandleConfig.UserName + '/' + gMgSvc.NicService.GetIP + '/'; sDestPath := CutFileExt(pInfo.sPath) + '_marked.' + sExt; if ExtrTxtData(csttWaterMarkImg, pInfo.sPath, sDestPath, sWaterTxt) then begin DeleteFile(PChar(pInfo.sPath)); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_WARTERMARK, pInfo.sPath); if not PO.IsOldPolicy then begin ZeroMemory(@LogInfo, SizeOf(LogInfo)); LogInfo.sCode := LOGCODE_PREVENT_WATERMARK; LogInfo.sPath := pInfo.sPath; LogInfo.sSummary := 'Water marked : ' + ExtractFileName(pInfo.sPath); gMgSvc.SendEventLogEx(@LogInfo); end else gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_WATERMARK, 'Water marked : ' + pInfo.sPath); end; exit; // 워터마크 처리 후 탈출 end; end; case PO.FileMon.Kind of fmkNone : bFileMonPO := false; fmkAll : bFileMonPO := true; fmkIncExt : begin bFileMonPO := (MonExtList_.IndexOf(sExt) <> -1) or ((sExt = '') and (MonExtList_.IndexOf('!EXT') <> -1)); if pInfo.dwAction = 5 then begin if not bFileMonPO and PO.FileMon.RenameEvt and (sOldName_ <> '') then begin var sOldExt: String := GetFileExt(sOldName_); bFileMonPO := (MonExtList_.IndexOf(sOldExt) <> -1) or ((sOldExt = '') and (MonExtList_.IndexOf('!EXT') <> -1)); end; end; end; fmkIgrExt : begin bFileMonPO := MonExtList_.IndexOf(sExt) = -1; if bFileMonPO and (sExt = '') then bFileMonPO := MonExtList_.IndexOf('!EXT') = -1; if pInfo.dwAction = 5 then begin if not bFileMonPO and PO.FileMon.RenameEvt and (sOldName_ <> '') then begin var sOldExt: String := GetFileExt(sOldName_); bFileMonPO := MonExtList_.IndexOf(sOldExt) = -1; if bFileMonPO and (sOldExt = '') then bFileMonPO := MonExtList_.IndexOf('!EXT') = -1; end; end; end; end; // 파일 변경 감시 - USB 사용시에만 체크 if bFileMonPO and PO.FileMon.OnlyUSB and (Length(sDir) > 0) and (UsbList_.IndexOf(sDir[1]) = -1) then bFileMonPO := false; if bFileMonPO then begin if gMgSvc.IsNewApi then begin // Action : 1 = Add, 2 = Delete, 3 = Modify, 4 = Rename, 5 = NewName case pInfo.dwAction of 1 : begin bFileMonPO := PO.FileMon.CreateEvt; if bFileMonPO and PO.FileMon.DoEnc and gMgSvc.HasEncIgr(pInfo.sPath) then exit; end; 2 : bFileMonPO := PO.FileMon.DeleteEvt; 3 : begin if (sLastModPath_ = pInfo.sPath) and ((GetTickCount - dwLastModTick_) < 1200) then exit; sLastModPath_ := pInfo.sPath; dwLastModTick_ := GetTickCount; bFileMonPO := PO.FileMon.ModifyEvt; if bFileMonPO and PO.FileMon.DoEnc and gMgSvc.HasEncIgr(pInfo.sPath, true) then exit; end; 5 : bFileMonPO := PO.FileMon.RenameEvt; end; end; if bFileMonPO then begin if IsIgrMonDir(pInfo.sPath) then bFileMonPO := false; if bFileMonPO and (PO.FileMon.Kind = fmkAll) and IsIgrExt(pInfo.sPath) then bFileMonPO := false; end; end; case PO.FileBlock.Kind of fmkNone : bFileBlockPO := false; fmkAll : bFileBlockPO := true; fmkIncExt : bFileBlockPO := (BlockExtList_.IndexOf(sExt) <> -1) or ((sExt = '') and (BlockExtList_.IndexOf('!EXT') <> -1)); fmkIgrExt : begin bFileBlockPO := BlockExtList_.IndexOf(sExt) = -1; if bFileBlockPO and (sExt = '') then bFileBlockPO := BlockExtList_.IndexOf('!EXT') = -1; end; end; // 파일 생성 차단 - USB 사용시에만 체크 if bFileBlockPO and PO.FileBlock.OnlyUSB and (Length(sDir) > 0) and (UsbList_.IndexOf(sDir[1]) = -1) then bFileBlockPO := false; bFileBlockPO := bFileBlockPO and (pInfo.dwAction = 1); // 파일 생성 차단으로 기능 변경 23_0811 08:32:06 kku if bFileBlockPO and (IgBlockDirList_.Count > 0) then begin for i := 0 to IgBlockDirList_.Count - 1 do begin sIgCheck := UpperCase(pInfo.sPath); if sIgCheck.Contains(IgBlockDirList_[i].ToUpper) then begin bFileBlockPO := false; break; end; end; end; // 파일 생성 차단 - 컨텐츠 필터, 파일 변경 감시보다 우선 순위 위 if bFileBlockPO and PO.FileBlock.ContentFilter.bActive and (PO.FileBlock.ContentFilter.sPatterns <> '') then begin bFileBlockPO := false; if CheckRecentMask('FileMon:' + pInfo.sPath) then exit; MaskedList_.AddObject('FileMon:' + pInfo.sPath, TObject(GetTickCount)); try if gKvKwdSch <> nil then begin var Send: ISendPacket := TTgPacket.Create(KVC_REQUEST_KEYWORD_SEARCH); Send.S['Path'] := pInfo.sPath; if gMgSvc.IsNewApi then Send.S['Ptrn'] := gMgSvc.MgRule.GetRuleSearchStrFromIds(PO.FileBlock.ContentFilter.sPatterns) else Send.S['Ptrn'] := PO.FileBlock.ContentFilter.sPatterns; Send.I['Action'] := FILEMON_WRITEBLOCK; Send.I['Event'] := pInfo.dwAction; Send.S['OldName'] := sOldName_; Send.I['LimitHit'] := PO.FileBlock.ContentFilter.nHitLimit; gKvKwdSch.SendPacket(Send); end; except // ... end; end; // 파일 변경 감시 - 컨텐츠 필터, 파일 생성 차단보다 우선 순위 아래 if bFileMonPO and PO.FileMon.ContentFilter.bActive and (PO.FileMon.ContentFilter.sPatterns <> '') then begin bFileMonPO := false; if CheckRecentMask('FileMon:' + pInfo.sPath) then exit; MaskedList_.AddObject('FileMon:' + pInfo.sPath, TObject(GetTickCount)); try if gKvKwdSch <> nil then begin var Send: ISendPacket := TTgPacket.Create(KVC_REQUEST_KEYWORD_SEARCH); Send.S['Path'] := pInfo.sPath; if gMgSvc.IsNewApi then Send.S['Ptrn'] := gMgSvc.MgRule.GetRuleSearchStrFromIds(PO.FileMon.ContentFilter.sPatterns) else Send.S['Ptrn'] := PO.FileMon.ContentFilter.sPatterns; Send.I['Action'] := FILEMON_WRITEMON; Send.I['Event'] := pInfo.dwAction; Send.S['OldName'] := sOldName_; Send.I['LimitHit'] := PO.FileMon.ContentFilter.nHitLimit; // 사용하지 않음. 나중에 삭제 필요 25_0623 15:52:05 kku // Send.B['DoEnc'] := ((CUSTOMER_TYPE = CUSTOMER_WELFNI) or (CUSTOMER_TYPE = CUSTOMER_WELFND)) and PO.FileMon.DoEnc; gKvKwdSch.SendPacket(Send); end; except // ... end; end; // DRM 컨텐츠 필터 적용 추가 23_0424 13:01:52 kku if PO.DrmCF.bActive and (DrmExtList_.IndexOf(sExt) <> -1) then begin if bFileBlockPO then bFileBlockPO := false; // 쓰기 차단 무시 23_0424 13:04:02 kku // DRM 열람 시 생성되는 파일 체크해서 거름 23_0424 14:04:33 kku if (sFName <> '') and (sFName[1] = '#') and (Pos('_', sFName) > 3) then exit; if CheckRecentMask('DoDrm:' + pInfo.sPath) then exit; MaskedList_.AddObject('DoDrm:' + pInfo.sPath, TObject(GetTickCount)); try if gKvKwdSch <> nil then begin var Send: ISendPacket := TTgPacket.Create(KVC_REQUEST_KEYWORD_SEARCH); Send.S['Path'] := pInfo.sPath; Send.S['Ptrn'] := PO.DrmCF.sPatterns; Send.I['Action'] := FILEMON_DRM; Send.I['LimitHit'] := PO.DrmCF.nHitLimit; gKvKwdSch.SendPacket(Send); end; except // ... end; end; if bFileBlockPO and PO.FileBlock.ContentFilter.bActive and (PO.FileBlock.ContentFilter.sPatterns <> '') then begin bFileBlockPO := false; if CheckRecentMask('FileBlock:' + pInfo.sPath) then exit; MaskedList_.AddObject('FileBlock:' + pInfo.sPath, TObject(GetTickCount)); try if gKvKwdSch <> nil then begin var Send: ISendPacket := TTgPacket.Create(KVC_REQUEST_KEYWORD_SEARCH); Send.S['Path'] := pInfo.sPath; Send.S['Ptrn'] := PO.FileBlock.ContentFilter.sPatterns; Send.I['Action'] := FILEMON_WRITEBLOCK; Send.I['LimitHit'] := PO.FileBlock.ContentFilter.nHitLimit; gKvKwdSch.SendPacket(Send); end; except // ... end; end; bIsCollectTxt := PO.FileMon.IsCollectTxt; if not bIsCollectTxt then begin case pInfo.dwAction of 1 : bIsCollectTxt := PO.FmCreateCol.bTxt; // Add 3 : bIsCollectTxt := PO.FmModifyCol.bTxt; // Modify 5 : bIsCollectTxt := PO.fmRenameCol.bTxt; // Rename end; end; bIsCollectFile := PO.FileMon.IsCollectFile; if not bIsCollectFile then begin case pInfo.dwAction of 1 : bIsCollectFile := PO.FmCreateCol.bFile; // Add 3 : bIsCollectFile := PO.FmModifyCol.bFile; // Modify 5 : bIsCollectFile := PO.fmRenameCol.bFile; // Rename end; end; if PO.IsOldPolicy then begin // 2.7 이하 서버 대응 처리 if (MaskExtList_.IndexOf(sExt) <> -1) then // 저장 차단 정책 있으면 마스킹 하지 않음 22_0725 12:57:54 kku begin try if CheckRecentMask(pInfo.sPath) then exit; MaskedList_.AddObject(pInfo.sPath, TObject(GetTickCount)); // if not PrefModel.IsMasking or (PrefModel.DrmEncKind <> dekNone) then if not PO.IsMasking then begin sDestPath := GetRunExePathDir + 'Task\'; ForceDirectories(sDestPath); sDestPath := sDestPath + sFName + '.tmp'; end else sDestPath := CutFileExt(pInfo.sPath) + '_mask.txt'; try if bFileBlockPO then begin // MaskingFromFile(TYPE_MSG_PREVENT_FILEWRITE, sDestPath, pInfo.sPath); var bBlock: Boolean := true; // 예외 등록된 USB 장치면 로그만 남도록 24_0528 14:34:14 kku if PO.FileBlock.OnlyUSB and (pInfo.sPath.Length > 0) and (ExpUsbList_.IndexOf(pInfo.sPath[1]) <> -1) then begin bBlock := false; end else if PO.IsDrmAttAbleFB then begin // DRM 적용된건 허용할 경우 24_0528 14:05:46 kku ThdDelFiles_.Push('*' + pInfo.sPath); exit; end else ThdDelFiles_.Push(pInfo.sPath); gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_FILEIO, Format('[%s] %s', [GetEventToStr, pInfo.sPath])); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, pInfo.sPath); end else if PO.IsMasking then begin // ExtrTxtData() 이게 실패해도 아래 암호화등의 처리가 필요 하다 22_1025 15:49:11 kku ExtrTxtData(csttExtrSimple, pInfo.sPath, sDestPath); MaskingFromFile(TYPE_MSG_PREVENT_FILEMASK, sDestPath, pInfo.sPath); ThdDelFiles_.Push(pInfo.sPath); end else if bFileMonPO then begin if (PO.FileMon.Kind <> fmkAll) or not IsIgrExt(pInfo.sPath) then begin // ExtrTxtData() 이게 실패해도 아래 암호화등의 처리가 필요 하다 22_1025 15:49:11 kku ExtrTxtData(csttExtrSimple, pInfo.sPath, sDestPath); MaskingFromFile(TYPE_MSG_PREVENT_FILECHANGE, sDestPath, pInfo.sPath); end; end; finally if FileExists(sDestPath) then DeleteFile(PChar(sDestPath)); end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ProcessMasking..'); end; end else begin if bFileBlockPO then begin var bBlock: Boolean := true; // 예외 등록된 USB 장치면 로그만 남도록 24_0528 14:34:14 kku if PO.FileBlock.OnlyUSB and (pInfo.sPath.Length > 0) and (ExpUsbList_.IndexOf(pInfo.sPath[1]) <> -1) then begin bBlock := false; end else if PO.IsDrmAttAbleFB then begin // DRM 적용된건 허용할 경우 24_0528 14:05:46 kku ThdDelFiles_.Push('*' + pInfo.sPath); exit; end else ThdDelFiles_.Push(pInfo.sPath); gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_FILEIO, Format('[%s] %s', [GetEventToStr, pInfo.sPath])); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, pInfo.sPath); end else if bFileMonPO and ((PO.FileMon.Kind <> fmkAll) or not IsIgrExt(pInfo.sPath)) then begin gMgSvc.SendEventLog(URI_USER_ACTION, LOGCODE_PREVENT_FILEMONITOR, Format('[%s] %s', [GetEventToStr, pInfo.sPath])); gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, pInfo.sPath); end; end; end else begin //////////////////////////////////////////////////////////////////////////// /// // 2.7 이상 서버 대응 처리 if bFileBlockPO then begin var bBlock: Boolean := true; // 예외 등록된 USB 장치면 로그만 남도록 24_0528 14:34:14 kku if PO.FileBlock.OnlyUSB and (pInfo.sPath.Length > 0) and (ExpUsbList_.IndexOf(pInfo.sPath[1]) <> -1) then begin bBlock := false; end; ZeroMemory(@LogInfo, SizeOf(LogInfo)); if bBlock then LogInfo.sCode := LOGCODE_PREVENT_FILEIO else LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; LogInfo.sPath := pInfo.sPath; LogInfo.sSummary := Format('[%s] %s', [GetEventToStr, pInfo.sPath]); if PO.FileBlock.IsCollectTxt or PO.FileBlock.IsCollectFile then begin // 차단 전 수집을 위해 지연 처리 추가 24_0725 15:14:47 kku var pEnt: PWaitEnt; New(pEnt); ZeroMemory(pEnt, SizeOf(TWaitEnt)); pEnt.sPath := pInfo.sPath; pEnt.LogInfo := LogInfo; pEnt.bBlock := bBlock; pEnt.bIgrDrmBlock := PO.IsDrmAttAbleFB; pEnt.nMinMB := PO.FileBlkMinMB; pEnt.nLimitMB := PO.FileBlkLimitMB; pEnt.dwAction := pInfo.dwAction; if PO.FileBlock.IsCollectTxt then Include(pEnt.Tasks, wetExtrTxt); if PO.FileBlock.IsCollectFile then Include(pEnt.Tasks, wetSendFile); if PO.FileBlock.IsNoti then Include(pEnt.Tasks, wetPopup); ThdWaitProc_.Push(pEnt); exit; end else if bBlock then begin if PO.IsDrmAttAbleFB then begin // DRM 적용된건 허용할 경우 24_0528 14:05:46 kku ThdDelFiles_.Push('*' + pInfo.sPath); exit; end else ThdDelFiles_.Push(pInfo.sPath); end; gMgSvc.SendEventLogEx(@LogInfo, bBlock); if PO.FileBlock.IsNoti then begin if bBlock then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILEWRITE, LogInfo.sSummary) else gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, LogInfo.sSummary); end; end else if bFileMonPO then begin if CheckRecentMask('FileMon:' + pInfo.sPath) then exit; MaskedList_.AddObject('FileMon:' + pInfo.sPath, TObject(GetTickCount)); ZeroMemory(@LogInfo, SizeOf(LogInfo)); LogInfo.sCode := LOGCODE_PREVENT_FILEMONITOR; LogInfo.sPath := pInfo.sPath; if pInfo.dwAction = 5 then LogInfo.sSummary := Format('[Rename] %s', [pInfo.sPath + ' < Old : ' + sOldName_]) else LogInfo.sSummary := Format('[%s] %s', [GetEventToStr, pInfo.sPath]); if bIsCollectTxt or bIsCollectFile then begin // LogInfo.sBody := ExtrTextFromFile(pInfo.sPath); // 큰용량 파일의 경우 지연 처리를 위해 추가 24_0725 15:06:13 kku var pEnt: PWaitEnt; New(pEnt); ZeroMemory(pEnt, SizeOf(TWaitEnt)); pEnt.sPath := pInfo.sPath; pEnt.LogInfo := LogInfo; pEnt.nMinMB := PO.FileMonMinMB; pEnt.nLimitMB := PO.FileMonLimitMB; pEnt.dwAction := pInfo.dwAction; if bIsCollectTxt then Include(pEnt.Tasks, wetExtrTxt); if bIsCollectFile then Include(pEnt.Tasks, wetSendFile); if Po.FileMon.DoEnc then Include(pEnt.Tasks, wetDoDRM); if PO.FileMon.IsNoti then Include(pEnt.Tasks, wetPopup); ThdWaitProc_.Push(pEnt); exit; end else // if bIsCollectFile then // 대용량 파일 생성중 업로드가 안되는 현상 때문에 위 조건으로 합침 25_1126 16:23:52 kku // begin // llSize := GetFileSize_path(pInfo.sPath); // if (llSize >= (LONGLONG(PO.FileMonMinMB) * 1048576)) and (llSize <= (LONGLONG(PO.FileMonLimitMB) * 1048576)) then // begin // // 원본 파일 수집 // LogInfo.sFileCompId := gMgSvc.MakeComponentId(pInfo.sPath); // if PO.FileMon.DoEnc then // begin // if IsUseEncOnlyAIP or gMgSvc.FirstAip then // gMgSvc.SendFile(LogInfo.sFileCompId, 'quarantineLogCollect.do', pInfo.sPath, PO.FileMonMinMB, PO.FileMonLimitMB, crtAIP, PO.FileMonEncDelaySec) // else // gMgSvc.SendFile(LogInfo.sFileCompId, 'quarantineLogCollect.do', pInfo.sPath, PO.FileMonMinMB, PO.FileMonLimitMB, crtDRM, PO.FileMonEncDelaySec); // end else // gMgSvc.SendFile(LogInfo.sFileCompId, 'quarantineLogCollect.do', pInfo.sPath, PO.FileMonMinMB, PO.FileMonLimitMB); // end; // end else if PO.FileMon.DoEnc then begin // [대응] 암호화 if IsUseEncOnlyAIP or gMgSvc.FirstAip then gMgSvc.ThdReact.AddEnt(crtAIP, pInfo.sPath, PO.FileMonEncDelaySec) else gMgSvc.ThdReact.AddEnt(crtDRM, pInfo.sPath, PO.FileMonEncDelaySec); end; gMgSvc.SendEventLogEx(@LogInfo, false); if PO.FileMon.IsNoti then gMgSvc.PopupMessage(TYPE_MSG_PREVENT_FILECHANGE, LogInfo.sSummary); end; end; except on E: Exception do ETgException.TraceException(Self, E, 'Fail .. ProcessDirWatchEntry()') end; end; end.