diff -r 000000000000 -r 95b198f216e5 omadrm/drmlicensemanager/src/DRMLicenseManager.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/omadrm/drmlicensemanager/src/DRMLicenseManager.cpp Thu Dec 17 08:52:27 2009 +0200 @@ -0,0 +1,814 @@ +/* +* Copyright (c) 2004-2009 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Implementation of the license manager functionality used in the +* install process +* +*/ + + +// INCLUDE FILES +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include // Disk space checking + +#include "ZipFile.h" +#include "ZipFileMemberIterator.h" +#include "DRMLicenseManager.h" + +// LOCAL CONSTANTS AND MACROS +_LIT(KDefinitionFileName, "datafiles.def"); +_LIT(KSISSuffix, ".sis"); +_LIT(KSISXSuffix, ".sisx"); +_LIT8(KDefaultMIMEType, "application/binary"); +_LIT8( KIssuer , "Rights-Issuer" ); + +const TInt KSISBufferSize = 512; +const TInt KMaxTypeLength = 11 + 2; // Length of "application" + CR + LF +const TInt KMaxFileDescriptionLength = KMaxPath + KMaxPath + KMaxDataTypeLength; + + +// ============================ LOCAL FUNCTIONS ================================ +// ----------------------------------------------------------------------------- +// DriveOfPathL +// ----------------------------------------------------------------------------- +LOCAL_C inline TInt DriveOfPathL( + RFs& aFs, + const TDesC aPathName, + TInt aFallbackDrive = KDefaultDrive ) + { + // find drive for destination for free space check + TInt driveNumber( KDefaultDrive ); + TParsePtrC pptr( aPathName ); + TInt err( KErrNone ); + if ( pptr.DrivePresent() ) + { + err = RFs::CharToDrive( pptr.Drive()[ 0 ], driveNumber ); + User::LeaveIfError( err ); + } + else if ( aFallbackDrive != KDefaultDrive ) + { + driveNumber = aFallbackDrive; + } + else + { + HBufC* sessionPath( HBufC::NewLC( KMaxPath ) ); + TPtr pathPtr( sessionPath->Des() ); + User::LeaveIfError( aFs.SessionPath( pathPtr ) ); + + TParsePtrC sPPtr( pathPtr ); + if ( sPPtr.DrivePresent() ) + { + err = RFs::CharToDrive( sPPtr.Drive()[ 0 ], driveNumber ); + User::LeaveIfError( err ); + } + else + { + driveNumber = RFs::GetSystemDrive(); + } + CleanupStack::PopAndDestroy( sessionPath ); + } + return driveNumber; + } + +// ----------------------------------------------------------------------------- +// CheckNeededFreeSpaceL +// ----------------------------------------------------------------------------- +LOCAL_C void CheckNeededFreeSpaceL( + RFs& aFs, + CZipFile*& aZipFile, + RPointerArray< TDRMDataFile >& aDataFiles, + const TDesC& aDestination, + TInt& aError ) + { + static const TInt KExtraSpaceForDcf( 1024 ); + CArrayFixFlat< TInt >* arrayOfNeededSpaces( NULL ); + // Get target drive for relative files + TInt driveForRelativePath( DriveOfPathL( aFs, aDestination ) ); + + arrayOfNeededSpaces = new ( ELeave ) CArrayFixFlat< TInt >( KMaxDrives ); + CleanupStack::PushL( arrayOfNeededSpaces ); + + arrayOfNeededSpaces->SetReserveL( KMaxDrives ); + for ( TInt j( 0 ); j < KMaxDrives; ++j ) + { + arrayOfNeededSpaces->AppendL(0); + } + + for ( TInt i = 0; i < aDataFiles.Count() && aError == KErrNone; i++ ) + { + TDRMDataFile* dataFile( + static_cast< TDRMDataFile* >( aDataFiles[ i ] ) ); + CZipFileMember* member( + aZipFile->CaseInsensitiveMemberL( dataFile->iSourceName ) ); + if ( member ) + { + CleanupStack::PushL( member ); + TInt driveNumber( DriveOfPathL( + aFs, dataFile->iTargetName, driveForRelativePath ) ); + ( *arrayOfNeededSpaces )[ driveNumber ] += + member->UncompressedSize() + KExtraSpaceForDcf; + CleanupStack::PopAndDestroy( member ); + } + else + { + aError = CDRMLicenseManager::EPIPInvalid; + } + } + + for ( TInt j( 0 ); j < KMaxDrives; ++j ) + { + TUint element( ( *arrayOfNeededSpaces )[ j ] ); + if ( element && // no need to check if no space required + SysUtil::DiskSpaceBelowCriticalLevelL( &aFs, element, j) ) + { + User::Leave( KErrDiskFull ); + } + } + CleanupStack::PopAndDestroy( arrayOfNeededSpaces ); + } + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::CDRMLicenseManager +// C++ default constructor can NOT contain any code, that +// might leave. +// ----------------------------------------------------------------------------- +// +CDRMLicenseManager::CDRMLicenseManager(): + iFs(NULL), iRights(NULL), iRightsIssuer(NULL) + { + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ConstructL +// Symbian 2nd phase constructor can leave. +// ----------------------------------------------------------------------------- +// +void CDRMLicenseManager::ConstructL() + { + iFs = new RFs(); + User::LeaveIfNull(iFs); + User::LeaveIfError(iFs->Connect()); + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::NewL +// Two-phased constructor. +// ----------------------------------------------------------------------------- +// +EXPORT_C CDRMLicenseManager* CDRMLicenseManager::NewL() + { + CDRMLicenseManager* self = new( ELeave ) CDRMLicenseManager; + + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop( self ); + + return self; + } + + +// Destructor +EXPORT_C CDRMLicenseManager::~CDRMLicenseManager() + { + iFs->Close(); + delete iFs; + + iDataFiles.ResetAndDestroy(); + + if (iZipFile) + { + iZipFile->Close(); + delete iZipFile; + } + + if (iRights) + { + delete iRights; + } + + if (iRightsIssuer) + { + delete iRightsIssuer; + } + } + +LOCAL_C TBool GetRightsIssuerL(const TFileName aFileName, HBufC8*& aRightsIssuerURL) + { + TInt err(KErrNotFound); + + HBufC8* name = HBufC8::NewLC(16); + TPtr8 headerName( name->Des() ); + headerName.Copy( KIssuer ); + + DRMCommon* c = DRMCommon::NewL(); + CleanupStack::PushL(c); + err = c->GetFileHeader(aFileName, headerName, aRightsIssuerURL); + CleanupStack::PopAndDestroy(c); + CleanupStack::PopAndDestroy(name); + + if(err == DRMCommon::EOk && aRightsIssuerURL) + { + return ETrue; + } + + return EFalse; + } + +LOCAL_C TBool GetRightsIssuerL(RFile aFileName, HBufC8*& aRightsIssuerURL) + { + TInt err(KErrNotFound); + + HBufC8* name = HBufC8::NewLC(16); + TPtr8 headerName( name->Des() ); + headerName.Copy( KIssuer ); + + DRMCommon* c = DRMCommon::NewL(); + CleanupStack::PushL(c); + err = c->GetFileHeader(aFileName, headerName, aRightsIssuerURL); + CleanupStack::PopAndDestroy(c); + CleanupStack::PopAndDestroy(name); + + if(err == DRMCommon::EOk && aRightsIssuerURL) + { + return ETrue; + } + + return EFalse; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ProcessL +// Read the PIP definition file and encrypt each referenced data file +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CDRMLicenseManager::ProcessL( + const TDesC& aZIPFile, + const TDesC& aDestination) + { + TInt r = KErrNone; + DRMCommon* drm = NULL; + RPointerArray* rights = NULL; + + // Clean up + if (iZipFile) + { + iZipFile->Close(); + delete iZipFile; + iZipFile = NULL; + } + + if (iRights) + { + delete iRights; + iRights = NULL; + } + + if (iRightsIssuer) + { + delete iRightsIssuer; + iRightsIssuer = NULL; + } + + GetRightsIssuerL(aZIPFile, iRightsIssuer); + + iDataFiles.ResetAndDestroy(); + + // Get rights object for the PIP file + iZipFile = CZipFile::NewL(*iFs, aZIPFile); + drm = DRMCommon::NewL(); + CleanupStack::PushL(drm); + r = drm->GetDetailedFileRights(aZIPFile, rights); + + // Read the definition file + if (r == KErrNone) + { + iRights = (*rights)[0]; + rights->Remove(0); + rights->ResetAndDestroy(); + delete rights; + r = ReadDefinitionFileL(); + } + + // Process data files + if (r == KErrNone) + { + r = ProcessDataFilesL(aDestination); + } + + CleanupStack::PopAndDestroy(drm); + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ProcessL +// Read the PIP definition file and encrypt each referenced data file +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CDRMLicenseManager::ProcessL( + RFile& aZIPFile, + const TDesC& aDestination) + { + TInt r = KErrNone; + DRMCommon* drm = NULL; + RPointerArray* rights = NULL; + + // Clean up + if (iZipFile) + { + iZipFile->Close(); + delete iZipFile; + iZipFile = NULL; + } + + if (iRights) + { + delete iRights; + iRights = NULL; + } + + if (iRightsIssuer) + { + delete iRightsIssuer; + iRightsIssuer = NULL; + } + + GetRightsIssuerL(aZIPFile, iRightsIssuer); + + iDataFiles.ResetAndDestroy(); + + // Get rights object for the PIP file + iZipFile = CZipFile::NewL(*iFs, aZIPFile); + drm = DRMCommon::NewL(); + CleanupStack::PushL(drm); + r = drm->GetDetailedFileRights(aZIPFile, rights); + + // Read the definition file + if (r == KErrNone) + { + iRights = (*rights)[0]; + rights->Remove(0); + rights->ResetAndDestroy(); + delete rights; + r = ReadDefinitionFileL(); + } + + // Process data files + if (r == KErrNone) + { + r = ProcessDataFilesL(aDestination); + } + + CleanupStack::PopAndDestroy(drm); + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ExtractSISFileL +// Find the SIS member of the ZIP file and write it to the target destination. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CDRMLicenseManager::ExtractSISFileL( + const TDesC& aZIPFile, + const TDesC& aDestination) + { + CZipFileMember* sisFile = NULL; + TInt r = KErrNone; + + if (iZipFile) + { + iZipFile->Close(); + delete iZipFile; + iZipFile = NULL; + } + + if (iRightsIssuer) + { + delete iRightsIssuer; + iRightsIssuer = NULL; + } + + GetRightsIssuerL(aZIPFile, iRightsIssuer); + + iZipFile = CZipFile::NewL(*iFs, aZIPFile); + + __UHEAP_MARK; + sisFile = GetSISMemberL(); + + if (sisFile) + { + WriteSISMemberL(sisFile, aDestination); + delete sisFile; + } + else + { + r = ESISNotFound; + } + __UHEAP_MARKEND; + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ExtractSISFileL +// Find the SIS member of the ZIP file and write it to the target destination. +// ----------------------------------------------------------------------------- +// +EXPORT_C TInt CDRMLicenseManager::ExtractSISFileL( + RFile& aZIPFile, + const TDesC& aDestination) + { + CZipFileMember* sisFile = NULL; + TInt r = KErrNone; + + if (iZipFile) + { + iZipFile->Close(); + delete iZipFile; + iZipFile = NULL; + } + + if (iRightsIssuer) + { + delete iRightsIssuer; + iRightsIssuer = NULL; + } + + GetRightsIssuerL(aZIPFile, iRightsIssuer); + + iZipFile = CZipFile::NewL(*iFs, aZIPFile); + + __UHEAP_MARK; + sisFile = GetSISMemberL(); + + if (sisFile) + { + WriteSISMemberL(sisFile, aDestination); + delete sisFile; + } + else + { + r = ESISNotFound; + } + __UHEAP_MARKEND; + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::GetSISMemberL +// Finds the SIS member in the ZIP file by looking for the .sis file ending. +// ----------------------------------------------------------------------------- +// +EXPORT_C CZipFileMember* CDRMLicenseManager::GetSISMemberL(void) + { + CZipFileMemberIterator* members = NULL; + CZipFileMember* sisFile = NULL; + CZipFileMember* member = NULL; + + members = iZipFile->GetMembersL(); + CleanupStack::PushL(members); + + member = members->NextL(); + + while (member && !sisFile) + { + if (member->Name()->Right(4).CompareF(KSISSuffix) == 0) + { + sisFile = member; + } + else if (member->Name()->Right(5).CompareF(KSISXSuffix) == 0) + { + sisFile = member; + } + else + { + delete member; + member = NULL; + member = members->NextL(); + } + } + + CleanupStack::PopAndDestroy(members); + + if(!sisFile) + { + User::Leave(KErrNotFound); + } + + return sisFile; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::WriteSISMemberL +// Write a SIS member to disk. +// ----------------------------------------------------------------------------- +// +void CDRMLicenseManager::WriteSISMemberL( + CZipFileMember* aSisMember, + const TDesC& aDestination) + { + RZipFileMemberReaderStream* input = NULL; + RFileWriteStream output; + TBuf8 buffer; + + // Check free space and leave if not enough space available + if ( SysUtil::DiskSpaceBelowCriticalLevelL( + iFs, + aSisMember->UncompressedSize(), + DriveOfPathL( *iFs, aDestination ) ) ) + { + User::Leave( KErrDiskFull ); + } + + iZipFile->GetInputStreamL(aSisMember, input); + CleanupStack::PushL(input); + + iFs->SetSessionPath(aDestination); + User::LeaveIfError(output.Replace(*iFs, *aSisMember->Name(), EFileWrite)); + output.PushL(); + do + { + input->Read(buffer, KSISBufferSize); + if (buffer.Size() > 0) + { + output.WriteL(buffer); + } + } + while (buffer.Size() > 0); + output.Close(); + + CleanupStack::PopAndDestroy(&output); + CleanupStack::PopAndDestroy(input); + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ReadDefinitionFileL +// Read the PIP type and definition lines from the definition file. +// ----------------------------------------------------------------------------- +// +TInt CDRMLicenseManager::ReadDefinitionFileL(void) + { + CZipFileMember* definitionFile = NULL; + RZipFileMemberReaderStream* input = NULL; + TBuf8 type; + TInt r = KErrNone; + + TRAP(r, definitionFile = + iZipFile->CaseInsensitiveMemberL(KDefinitionFileName)); + + if (r == KErrNone && definitionFile) + { + CleanupStack::PushL(definitionFile); + iZipFile->GetInputStreamL(definitionFile, input); + ReadLine(input, type); + while (r == KErrNone) + { + r = ReadFileDescription(input); + } + delete input; + CleanupStack::PopAndDestroy(definitionFile); + } + else + { + r = EPIPInvalid; + } + + if (r == KErrEof) + { + r = KErrNone; + } + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ReadFileDescription +// Read the name, type and target name of a data file. +// ----------------------------------------------------------------------------- +// +TInt CDRMLicenseManager::ReadFileDescription( + RZipFileMemberReaderStream* aStream) + { + TBuf8 description; + TInt r = KErrNone; + TDRMDataFile* dataFile = NULL; + + ReadLine(aStream, description); + description.TrimAll(); + if (description.Length() > 0) + { + TLex8 lex(description); + + dataFile = new TDRMDataFile(); + if( !dataFile ) + { + return KErrNoMemory; + } + + // Get the original file name + lex.SkipSpaceAndMark(); + lex.SkipCharacters(); + CnvUtfConverter::ConvertToUnicodeFromUtf8( + dataFile->iSourceName, lex.MarkedToken()); + + // Get the MIME type. If not present, "application/binary" is used + // and the target file name is the source file name + lex.SkipSpaceAndMark(); + lex.SkipCharacters(); + if (lex.TokenLength() > 0) + { + dataFile->iMimeType = lex.MarkedToken(); + + // Get the target file name. If not present, the target file name + // will be the original file name, stored in the install directory. + lex.SkipSpaceAndMark(); + lex.SkipCharacters(); + if (lex.TokenLength() > 0) + { + CnvUtfConverter::ConvertToUnicodeFromUtf8( + dataFile->iTargetName, lex.MarkedToken()); + } + else + { + dataFile->iTargetName = dataFile->iSourceName; + } + } + else + { + dataFile->iMimeType = KDefaultMIMEType; + dataFile->iTargetName = dataFile->iSourceName; + } + + iDataFiles.Append(dataFile); + } + else + { + r = KErrEof; + } + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ReadLine +// Read one line ending with 0x0d or until the input buffer is full. +// ----------------------------------------------------------------------------- +// +void CDRMLicenseManager::ReadLine( + RZipFileMemberReaderStream* aStream, + TDes8& aLine) + { + TBuf8<1> c; + TInt n = 0; + TBool done = EFalse; + + while (!done) + { + if (aLine.Length() < aLine.MaxLength()) + { + aStream->Read(c, 1); + if (c.Length() > 0 && c[0] != 0x0d) + { + aLine.Append(c); + n++; + if (n == aLine.MaxLength() + 1) + { + done = ETrue; + } + } + else + { + done = ETrue; + } + } + else + { + done = ETrue; + } + } + + if (c.Length() > 0 && c[0] == 0x0d) + { + aStream->Read(c, 1); + } + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::ProcessDataFilesL +// Get all data files from the ZIP file and encrypt them. +// ----------------------------------------------------------------------------- +// +TInt CDRMLicenseManager::ProcessDataFilesL( + const TDesC& aDestination) + { + TDRMDataFile* dataFile( NULL ); + CZipFileMember* member( NULL ); + TInt r( KErrNone ); + + // check if there is enough free space for the process + CheckNeededFreeSpaceL( *iFs, iZipFile, iDataFiles, aDestination, r ); + + for ( TInt i = 0; i < iDataFiles.Count() && r == KErrNone; i++ ) + { + dataFile = static_cast< TDRMDataFile* >( iDataFiles[ i ] ); + member = iZipFile->CaseInsensitiveMemberL( dataFile->iSourceName ); + if ( member ) + { + CleanupStack::PushL(member); + EncryptDataFileL(dataFile, aDestination, member); + CleanupStack::PopAndDestroy(member); + } + else + { + r = EPIPInvalid; + } + } + + return r; + } + +// ----------------------------------------------------------------------------- +// CDRMLicenseManager::EncryptDataFileL +// Encrypt a single data file, reusing the outer PIP's RO. For application +// protection, the file is encrypted again. +// ----------------------------------------------------------------------------- +// +void CDRMLicenseManager::EncryptDataFileL( + TDRMDataFile* aDataFile, + const TDesC& aDestination, + CZipFileMember* aZipMember) + { + RZipFileMemberReaderStream* input = NULL; + RFileWriteStream output; + TBuf8 buffer; + COma1DcfCreator* drm = NULL; + TFileName outputFile; + DRMCommon* common = NULL; + + drm = COma1DcfCreator::NewL(); + CleanupStack::PushL(drm); + + iZipFile->GetInputStreamL(aZipMember, input); + CleanupStack::PushL(input); + + // Set the path so we can use relative paths + iFs->SetSessionPath(aDestination); + + output.PushL(); + // Create the output file stream + User::LeaveIfError(output.Replace(*iFs, aDataFile->iTargetName, + EFileWrite)); + + // Encrypt + drm->EncryptInitializeL(output, aDataFile->iMimeType, iRights); + do + { + input->Read(buffer, KSISBufferSize); + if (buffer.Size() > 0) + { + drm->EncryptUpdateL(buffer); + } + } + while (buffer.Size() > 0); + drm->EncryptFinalizeL(); + output.Close(); + CleanupStack::PopAndDestroy( &output ); + + // Add the rights issuer uri to the file if it exists + if( iRightsIssuer ) + { + common = DRMCommon::NewL(); + CleanupStack::PushL(common); + outputFile.Append( aDataFile->iTargetName ); + common->SetFileHeader( outputFile, KIssuer, + iRightsIssuer->Des()); + CleanupStack::PopAndDestroy(common); + } + CleanupStack::PopAndDestroy(input); + CleanupStack::PopAndDestroy(drm); + } + +