sl@0: // Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). sl@0: // All rights reserved. sl@0: // This component and the accompanying materials are made available sl@0: // under the terms of the License "Eclipse Public License v1.0" sl@0: // which accompanies this distribution, and is available sl@0: // at the URL "http://www.eclipse.org/legal/epl-v10.html". sl@0: // sl@0: // Initial Contributors: sl@0: // Nokia Corporation - initial contribution. sl@0: // sl@0: // Contributors: sl@0: // sl@0: // Description: sl@0: // f32test\virus\t_vshook.cpp sl@0: // sl@0: // sl@0: sl@0: #include "t_vshook.h" sl@0: #include sl@0: sl@0: sl@0: _LIT(KVirusScannerName, "This is a test virus scanner"); sl@0: sl@0: sl@0: /** sl@0: Leaving New function for the plugin sl@0: @internalComponent sl@0: */ sl@0: CTestVirusHook* CTestVirusHook::NewL() sl@0: { sl@0: return new(ELeave) CTestVirusHook; sl@0: } sl@0: sl@0: sl@0: /** sl@0: Constructor for the plugin sl@0: @internalComponent sl@0: */ sl@0: CTestVirusHook::CTestVirusHook() sl@0: { sl@0: // RDebug::Print(_L("EMaxClientOperations %d, size of CFsPlugin %d, iSignatureOffset %d"), EMaxClientOperations, sizeof(CFsPlugin), _FOFF(CTestVirusHook, iSignature)); sl@0: ASSERT(iSignature == 0); sl@0: iSignature = 0x1234; sl@0: } sl@0: sl@0: sl@0: /** sl@0: The destructor for the test virus scanner hook. This would sl@0: not be a part of a normal virus scanner implementation as sl@0: normal virus scanners cannot be unloaded - it must be sl@0: provided in the test virus scanner server so that it can sl@0: be tested with the F32 test suite. sl@0: @internalComponent sl@0: */ sl@0: CTestVirusHook::~CTestVirusHook() sl@0: { sl@0: iFs.Close(); sl@0: sl@0: for (TInt i = 0; i < iSignaturesLoaded; i++) sl@0: { sl@0: if (iKnownSignatures[i]) sl@0: { sl@0: delete iKnownSignatures[i]; sl@0: } sl@0: } sl@0: ASSERT(iSignature == 0x1234); sl@0: } sl@0: sl@0: /** sl@0: Initialise the virus scanner. sl@0: Reads the virus definition file and then waits for sl@0: notification that files containing a virus have been sl@0: detected. sl@0: @internalComponent sl@0: */ sl@0: void CTestVirusHook::InitialiseL() sl@0: { sl@0: User::LeaveIfError(RegisterIntercept(EFsFileOpen, EPreIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsFileSubClose, EPostIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsFileRename, EPreIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsRename, EPreIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsDelete, EPreIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsReplace, EPreIntercept)); sl@0: User::LeaveIfError(RegisterIntercept(EFsReadFileSection, EPreIntercept)); sl@0: sl@0: ReadVirusDefinitionFile(); sl@0: } sl@0: sl@0: /** sl@0: Read the virus definition file C:\virusdef.txt and parse sl@0: its contents. Any virus definitions found in that file sl@0: are added to the KnownSignatures array so they can be sl@0: used by the virus scanning hook. sl@0: sl@0: @internalComponent sl@0: sl@0: @return KErrNone if the file was read and parsed sl@0: successfuly. sl@0: */ sl@0: TInt CTestVirusHook::ReadVirusDefinitionFile() sl@0: { sl@0: TInt r = iFs.Connect(); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: r = iFs.SetNotifyChange(EFalse); // Disable change notifications sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: //Open the virus definition file sl@0: RFile vsDefFile; sl@0: r = vsDefFile.Open(iFs, _L("C:\\virusdef.txt"), EFileShareAny); sl@0: if (r != KErrNone) sl@0: return r; sl@0: sl@0: TInt fileSize=0; sl@0: r = vsDefFile.Size(fileSize); sl@0: if (r != KErrNone) sl@0: { sl@0: vsDefFile.Close(); sl@0: return r; sl@0: } sl@0: sl@0: HBufC8* defBuf=NULL; sl@0: sl@0: TRAP(r,defBuf = HBufC8::NewL(fileSize)); sl@0: if (r != KErrNone) sl@0: { sl@0: vsDefFile.Close(); sl@0: return r; sl@0: } sl@0: sl@0: TPtr8 ptr(defBuf->Des()); sl@0: r = vsDefFile.Read(ptr); sl@0: if (r != KErrNone) sl@0: { sl@0: delete defBuf; sl@0: vsDefFile.Close(); sl@0: return r; sl@0: } sl@0: sl@0: //Now parse the definition file, putting the definitions into the hook's sl@0: //array of known virus signatures. sl@0: TInt bytesParsed = 0; sl@0: TInt stringBeginPos = 0; sl@0: TInt stringEndPos = 0; sl@0: TInt stringLength = 0; sl@0: HBufC8* signatureBuf = NULL; sl@0: while (bytesParsed < fileSize) sl@0: { sl@0: ptr.Set(defBuf->Des()); sl@0: ptr.Set(&ptr[bytesParsed], fileSize-bytesParsed, fileSize-bytesParsed); sl@0: stringBeginPos = ptr.MatchF(_L8("startdef:*:enddef*")); sl@0: sl@0: if (stringBeginPos < 0) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: stringBeginPos += 9; //stardef: sl@0: stringBeginPos += bytesParsed; sl@0: ptr.Set(defBuf->Des()); sl@0: ptr.Set(&ptr[stringBeginPos], fileSize-stringBeginPos, fileSize-stringBeginPos); sl@0: stringEndPos = ptr.MatchF(_L8("*:enddef*")); sl@0: sl@0: if (stringEndPos < 0) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: stringEndPos += 9; //stardef: sl@0: stringEndPos += bytesParsed; sl@0: stringLength = stringEndPos - stringBeginPos; sl@0: sl@0: ptr.Set(defBuf->Des()); sl@0: TRAP(r,signatureBuf = HBufC8::NewL(stringLength)); sl@0: sl@0: TPtrC8 actualSig(ptr.Mid(stringBeginPos, stringLength)); sl@0: sl@0: TPtr8 ptr2(signatureBuf->Des()); sl@0: ptr2.Append(actualSig); sl@0: iKnownSignatures[iSignaturesLoaded] = signatureBuf; sl@0: iSignaturesLoaded++; sl@0: sl@0: bytesParsed += 9; //startdef: sl@0: bytesParsed += stringLength; sl@0: bytesParsed += 9; //:enddef\n sl@0: } sl@0: sl@0: //Cleanup sl@0: delete defBuf; sl@0: vsDefFile.Close(); sl@0: sl@0: return r; sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::DoRequestL(TFsPluginRequest& aRequest) sl@0: { sl@0: TInt err = KErrNotSupported; sl@0: sl@0: TInt function = aRequest.Function(); sl@0: sl@0: iDrvNumber = aRequest.DriveNumber(); sl@0: sl@0: switch(function) sl@0: { sl@0: case EFsFileOpen: sl@0: err = VsFileOpen(aRequest); sl@0: break; sl@0: sl@0: case EFsFileSubClose: sl@0: VsFileClose(aRequest); sl@0: break; sl@0: sl@0: case EFsFileRename: sl@0: case EFsRename: sl@0: case EFsReplace: sl@0: err = VsFileRename(aRequest); sl@0: break; sl@0: sl@0: case EFsDelete: sl@0: err = VsFileDelete(aRequest); sl@0: break; sl@0: sl@0: case EFsReadFileSection: sl@0: err = VsReadFileSection(aRequest); sl@0: break; sl@0: sl@0: default: sl@0: break; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VsFileOpen(TFsPluginRequest& aRequest) sl@0: { sl@0: TFileName fileName; sl@0: TInt err = ValidateRequest(aRequest, fileName); sl@0: if (err == KErrNone) sl@0: { sl@0: err = ScanFile(fileName); sl@0: if (err != KErrNone) sl@0: { sl@0: // Clean the infected file sl@0: CleanFile(fileName, EFileOpen); sl@0: } sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: void CTestVirusHook::VsFileClose(TFsPluginRequest& aRequest) sl@0: { sl@0: TFileName fileName; sl@0: TInt err = GetName(&aRequest, fileName); sl@0: if(err == KErrNone) sl@0: { sl@0: err = ScanFile(fileName); sl@0: if (err != KErrNone) sl@0: { sl@0: // Clean the infected file sl@0: CleanFile(fileName, EFileClose); sl@0: } sl@0: } sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VsFileRename(TFsPluginRequest& aRequest) sl@0: { sl@0: sl@0: TInt err = VsDirRename(aRequest); sl@0: if(err != KErrAccessDenied) sl@0: { sl@0: TFileName fileName; sl@0: err = ValidateRequest(aRequest, fileName); sl@0: if (err == KErrNone) sl@0: { sl@0: err = ScanFile(fileName); sl@0: if (err != KErrNone) sl@0: { sl@0: // Clean the infected file sl@0: CleanFile(fileName, EFileRename); sl@0: } sl@0: } sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VsDirRename(TFsPluginRequest& aRequest) sl@0: { sl@0: sl@0: TFileName fileName; sl@0: TInt err = GetName(&aRequest, fileName); sl@0: if(err != KErrNone) sl@0: return(err); sl@0: sl@0: err = fileName.Find(_L("\\system\\lib\\")); sl@0: if (err != KErrNotFound) sl@0: { sl@0: //Don't allow sys\bin to be ever renamed sl@0: return KErrAccessDenied; sl@0: } sl@0: err = fileName.Find(_L("\\sys\\bin\\")); sl@0: if (err != KErrNotFound) sl@0: { sl@0: //Don't allow sys\bin to be ever renamed sl@0: return KErrAccessDenied; sl@0: } sl@0: sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VsFileDelete(TFsPluginRequest& aRequest) sl@0: { sl@0: sl@0: TFileName fileName; sl@0: TInt err = ValidateRequest(aRequest, fileName); sl@0: return err; sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VsReadFileSection(TFsPluginRequest& aRequest) sl@0: { sl@0: sl@0: // The t_virus test uses a filename clean.txt, a read length of 8 and a read position of 0. sl@0: TFileName fileName; sl@0: TInt len; sl@0: TInt pos; sl@0: sl@0: // test getting name on read file section intercept sl@0: TInt err = GetName(&aRequest, fileName); sl@0: if(err != KErrNone) sl@0: { sl@0: return(err); sl@0: } sl@0: TParse parse; sl@0: parse.Set(fileName,NULL,NULL); sl@0: TPtrC name = parse.Name(); sl@0: if(name.CompareF(_L("clean"))!=0) sl@0: { sl@0: return(KErrGeneral); sl@0: } sl@0: TPtrC ext = parse.Ext(); sl@0: if(ext.CompareF(_L(".txt"))!=0) sl@0: { sl@0: return(KErrGeneral); sl@0: } sl@0: sl@0: // test getting read length and required file position on read file section intercept sl@0: err = GetFileAccessInfo(&aRequest, len, pos); sl@0: if(err != KErrNone) sl@0: { sl@0: return(err); sl@0: } sl@0: if ((len != 8) || (pos != 0)) sl@0: { sl@0: return(KErrGeneral); sl@0: } sl@0: sl@0: return KErrNone; sl@0: } sl@0: sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::VirusScannerName(TDes& aName) sl@0: { sl@0: aName = KVirusScannerName; sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Reads the contents of the file passed in and checks sl@0: whether it contains any of the specified virus sl@0: signatures sl@0: sl@0: @return A value depending on whether a known virus is sl@0: found within the file. sl@0: sl@0: @param aFile A CFileCB object which can be used to read the file. sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::ScanFile(const TDesC& aName) sl@0: { sl@0: sl@0: TInt r = KErrNone; sl@0: TInt pos = 0; sl@0: TInt size = 0; sl@0: sl@0: // Rename the file sl@0: TPtrC tmpFile = _L("VS_RENAMED.VSH"); sl@0: TParse parse; sl@0: parse.Set(aName, NULL, NULL); sl@0: parse.Set(parse.DriveAndPath(), &tmpFile, NULL); sl@0: sl@0: r = iFs.Rename(aName, parse.FullName()); sl@0: if(r != KErrNone) sl@0: return r; sl@0: sl@0: RFile file; sl@0: r = file.Open(iFs, parse.FullName(), EFileRead); sl@0: if(r == KErrNone) sl@0: { sl@0: r = file.Size(size); sl@0: } sl@0: sl@0: //If the file size is 0, then the file sl@0: //has just been created - so it can't contain sl@0: //a virus. sl@0: if(r != KErrNone || size == 0) sl@0: { sl@0: file.Close(); sl@0: sl@0: // Rename the file back sl@0: TInt err = iFs.Rename(parse.FullName(), aName); sl@0: if(err != KErrNone) sl@0: return err; sl@0: sl@0: return r; sl@0: } sl@0: sl@0: do sl@0: { sl@0: r = file.Read(pos, iScanBuf); sl@0: sl@0: if (r != KErrNone) sl@0: { sl@0: break; sl@0: } sl@0: sl@0: r = ScanBuffer(); sl@0: pos += iScanBuf.Length(); sl@0: } while ((r == KErrNotFound) && (iScanBuf.Length() == iScanBuf.MaxLength())); sl@0: sl@0: file.Close(); sl@0: sl@0: // Rename the file back sl@0: TInt err = iFs.Rename(parse.FullName(), aName); sl@0: if(err != KErrNone) sl@0: return err; sl@0: sl@0: if (r > 0) sl@0: { sl@0: //We've found an infection sl@0: return KErrAccessDenied; sl@0: } sl@0: else sl@0: { sl@0: return KErrNone; sl@0: } sl@0: } sl@0: sl@0: /** sl@0: Scans the internal buffer which has been loaded with fresh sl@0: file contents, to see if it contains any known virus sl@0: signatures. sl@0: sl@0: @return A value depending on whether a known virus signature sl@0: is found within the buffer. sl@0: sl@0: @internalComponent sl@0: */ sl@0: TInt CTestVirusHook::ScanBuffer() sl@0: { sl@0: //Look through the internal buffer for all known virus signatures. sl@0: sl@0: TInt r; sl@0: for (TInt i = 0; i < iSignaturesLoaded; i++) sl@0: { sl@0: r = iScanBuf.Find(iKnownSignatures[i]->Des()); sl@0: sl@0: if (r != KErrNotFound) sl@0: { sl@0: return r; sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Validate that nobody is trying to touch the virus scanner files. sl@0: sl@0: @internalComponent sl@0: sl@0: @return A value depending on whethe the virus scanner files are sl@0: being fiddled with. sl@0: sl@0: @param aDriveNum The drive number of the request which called into sl@0: the test virus scanning hook. sl@0: sl@0: @param aName The full pathname of the file being accessed by the sl@0: request to the file server hook. sl@0: */ sl@0: TInt CTestVirusHook::ValidateRequest(TFsPluginRequest& aRequest, TFileName& aFileName) sl@0: { sl@0: TInt driveNumber = aRequest.DriveNumber(); sl@0: sl@0: TInt err = GetName(&aRequest, aFileName); sl@0: if(err != KErrNone) sl@0: return(err); sl@0: sl@0: if (driveNumber == EDriveC) sl@0: { sl@0: TInt r = aFileName.Find(_L("\\virusdef.txt")); sl@0: sl@0: if (r != KErrNotFound) sl@0: { sl@0: //Do not allow the deletion of the virus definition file. sl@0: return KErrAccessDenied; sl@0: } sl@0: sl@0: r = aFileName.Find(_L("\\system\\libs\\t_vshook.pxt")); sl@0: if (r != KErrNotFound) sl@0: { sl@0: //Do not allow the deletion of the this dll sl@0: return KErrAccessDenied; sl@0: } sl@0: r = aFileName.Find(_L("\\sys\\bin\\t_vshook.pxt")); sl@0: if (r != KErrNotFound) sl@0: { sl@0: //Do not allow the deletion of the this dll sl@0: return KErrAccessDenied; sl@0: } sl@0: } sl@0: return KErrNone; sl@0: } sl@0: sl@0: /** sl@0: Processes a message which describes the detection of an sl@0: infected file. Appends the relevant text at the end of the sl@0: file to say that it has been "cleaned". This allows the virus sl@0: test program to confirm that the test virus scanner is sl@0: behaving as expected. sl@0: sl@0: @internalComponent sl@0: @param aMessage The message to be processed. sl@0: */ sl@0: void CTestVirusHook::CleanFile(const TDesC& aName, TInt aOperation) sl@0: { sl@0: sl@0: RFile infectedFile; sl@0: TBool bChangedToRw=EFalse; sl@0: TInt pos=0; sl@0: sl@0: TUint fileAtt; sl@0: TInt r = iFs.Att(aName, fileAtt); sl@0: if (r != KErrNone) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: if (fileAtt & KEntryAttReadOnly) sl@0: { sl@0: bChangedToRw = ETrue; sl@0: r = iFs.SetAtt(aName, 0, KEntryAttReadOnly); sl@0: } sl@0: sl@0: r = infectedFile.Open(iFs, aName, EFileShareAny | EFileWrite); sl@0: sl@0: if (r != KErrNone) sl@0: { sl@0: return; sl@0: } sl@0: sl@0: //To show we've fixed the file, append "Infection deleted" to the end of it. sl@0: infectedFile.Seek(ESeekEnd, pos); sl@0: switch (aOperation) sl@0: { sl@0: case EFileOpen: sl@0: infectedFile.Write(_L8("infection detected - file open\\n")); sl@0: break; sl@0: case EFileDelete: sl@0: infectedFile.Write(_L8("infection detected - file delete\\n")); sl@0: break; sl@0: case EFileRename: sl@0: infectedFile.Write(_L8("infection detected - file rename\\n")); sl@0: break; sl@0: case EFileClose: sl@0: infectedFile.Write(_L8("infection detected - file close\\n")); sl@0: break; sl@0: } sl@0: sl@0: infectedFile.Close(); sl@0: sl@0: if (bChangedToRw) sl@0: { sl@0: iFs.SetAtt(aName, KEntryAttReadOnly,0); sl@0: } sl@0: } sl@0: sl@0: //factory functions sl@0: sl@0: class CVsHookFactory : public CFsPluginFactory sl@0: { sl@0: public: sl@0: CVsHookFactory(); sl@0: virtual TInt Install(); sl@0: virtual CFsPlugin* NewPluginL(); sl@0: virtual CFsPlugin* NewPluginConnL(); sl@0: virtual TInt UniquePosition(); sl@0: }; sl@0: sl@0: /** sl@0: Constructor for the plugin factory sl@0: @internalComponent sl@0: */ sl@0: CVsHookFactory::CVsHookFactory() sl@0: { sl@0: } sl@0: sl@0: /** sl@0: Install function for the plugin factory sl@0: @internalComponent sl@0: */ sl@0: TInt CVsHookFactory::Install() sl@0: { sl@0: iSupportedDrives = KPluginAutoAttach; sl@0: sl@0: _LIT(KVsHookName,"VsHook"); sl@0: return(SetName(&KVsHookName)); sl@0: } sl@0: sl@0: /** sl@0: @internalComponent sl@0: */ sl@0: TInt CVsHookFactory::UniquePosition() sl@0: { sl@0: return(0x3EC); sl@0: } sl@0: sl@0: /** sl@0: Plugin factory function sl@0: @internalComponent sl@0: */ sl@0: CFsPlugin* CVsHookFactory::NewPluginL() sl@0: sl@0: { sl@0: return CTestVirusHook::NewL(); sl@0: } sl@0: sl@0: /** sl@0: Plugin factory function sl@0: @internalComponent sl@0: */ sl@0: CFsPlugin* CVsHookFactory::NewPluginConnL() sl@0: sl@0: { sl@0: return CTestVirusHook::NewL(); sl@0: } sl@0: sl@0: /** sl@0: Create a new Plugin sl@0: @internalComponent sl@0: */ sl@0: extern "C" { sl@0: sl@0: EXPORT_C CFsPluginFactory* CreateFileSystem() sl@0: { sl@0: return(new CVsHookFactory()); sl@0: } sl@0: } sl@0: