wmdrm/wmdrmengine/wmdrmserver/server/src/wmdrmdatastore.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:52:27 +0200
changeset 0 95b198f216e5
child 12 8a03a285ab14
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2008 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:  WMDRM data store implementation
*
*/


#include <ezlib.h>
#include <e32math.h>
#include <symmetric.h>
#include <bacntf.h>
#include <centralrepository.h> 

#include "wmdrmdatastore.h"
#include "wmdrmprivatecrkeys.h"
#include "wmdrmkeystorage.h"
#include "slotdatacache.h"
#include "wmdrmdb.h"
#include "drmrightsstoringlocation.h"
#include "drmutilityinternaltypes.h"

#define _LOGGING_FILE L"wmdrmserver.txt"

#include "flogger.h"
#include "logfn.h"

const TInt KMegaByte( 1024 * 1024 );
const TInt KTwoHundredMegaBytes ( 200 * 1024 * 1024 );
const TInt KMaxSpaceRatio( 85 );
const TInt KMaxSpaceRatio2( 20 );
const TInt KMaxTInt64BufLength( 20 );
const TInt KDummyDbInitialSize( 0 );

#if defined(FF_PLATFORM_SIMULATOR) || defined(__WINSCW__)
_LIT8( KDummyKey, "0123456789012345" );
#endif

CWmDrmDataStore* CWmDrmDataStore::NewL( CWmDrmServer* aServer )
    {
    LOGFN( "CWmDrmDataStore::NewL" );
    CWmDrmDataStore* self = new ( ELeave ) CWmDrmDataStore( aServer );
    CleanupStack::PushL( self );
    self->ConstructL();
    CleanupStack::Pop( self );
    return self;
    }

CWmDrmDataStore::CWmDrmDataStore( CWmDrmServer* aServer ) 
    : iServer( aServer ), iMinFreeSpace2( 0 )
    {
    LOGFN( "CWmDrmDataStore::CWmDrmDataStore" );
    }

void CWmDrmDataStore::ConstructL()
    {
    TDrmScheme drmScheme( EDrmSchemeWmDrm );
    TFileName tempFile, tempFile2;
    TChar driveLetter;
    
    LOGFN( "CWmDrmDataStore::ConstructL" );
    
    // Check which drive is configured in the Central Repository Key
    // for the desired storing location of WM DRM rights (license store).
	iWmDrmRightsConfigFound = DrmRightsStoringLocation::CheckDrmRightsStorageDriveL(
	    iServer->Fs(), drmScheme, driveLetter );
    
    // If the storing location is configured to other drive than the default 
	// system drive, prepare utility files for that drive, too.
    if ( iWmDrmRightsConfigFound )
        {
        PrepareInfoFilesL( ETrue, driveLetter, iDummyDb2 );
        }
    
    // Prepare the utility files for the default system drive
    PrepareInfoFilesL( EFalse, (TUint)iServer->Fs().GetSystemDriveChar(), 
        iDummyDb );
    }

CWmDrmDataStore::~CWmDrmDataStore()
    {
    LOGFN( "CWmDrmDataStore::~CWmDrmDataStore" );
    iDummyDb.Close();
    // Close the database on the configured drive
    if ( iWmDrmRightsConfigFound )
        {
        iDummyDb2.Close();
        }
    }

void CWmDrmDataStore::ReadInitialFreeSpaceL( const TDesC& aFileName,
    TBool& aConfiguredDrive )
    {
    RFile file;
    TBuf8<KMaxTInt64BufLength + 2 * KAESKeyLength> encryptedData;
    TBuf8<KMaxTInt64BufLength + 2 * KAESKeyLength> decryptedData;
    TBuf8<KAESKeyLength> key;
    TBuf8<KAESKeyLength> iv;
    CBufferedDecryptor* decryptor = NULL;
    CModeCBCDecryptor* cbcDecryptor = NULL;
    CAESDecryptor* aesDecryptor = NULL;
    CPaddingPKCS7* padding = NULL;
    TInt size = 0;
    
    LOGFN( "CWmDrmDataStore::ReadInitialFreeSpaceL" );
    User::LeaveIfError( file.Open( iServer->Fs(), aFileName, EFileRead ) );
    CleanupClosePushL( file );
    
    User::LeaveIfError( file.Size( size ) );
	    
	if( size != ( 2 * KAESKeyLength ) )
	    {
	    User::Leave(KErrCorrupt);
	    }

    User::LeaveIfError( file.Read( iv ) );
	User::LeaveIfError( file.Read( encryptedData ) );
#if defined(FF_PLATFORM_SIMULATOR) || defined(__WINSCW__)
	key.Copy( KDummyKey );
#else
	iServer->Cache()->iKeyStorage->GetDeviceSpecificKeyL( key );
#endif
	aesDecryptor = CAESDecryptor::NewL( key );
    CleanupStack::PushL( aesDecryptor );
    
    cbcDecryptor = CModeCBCDecryptor::NewL( aesDecryptor, iv );
    CleanupStack::Pop( aesDecryptor );
    CleanupStack::PushL( cbcDecryptor );
    
    padding = CPaddingPKCS7::NewL( KAESKeyLength );
    CleanupStack::PushL( padding );
    
    decryptor = CBufferedDecryptor::NewL( cbcDecryptor, padding );
    CleanupStack::Pop( 2, cbcDecryptor ); //padding, cbcDecryptor
    CleanupStack::PushL( decryptor );
	
	decryptor->ProcessFinalL( encryptedData, decryptedData );
	CleanupStack::PopAndDestroy( 2, &file ); //decryptor, file
	TLex8 lex( decryptedData );
	
	if ( aConfiguredDrive )
	    {
	    User::LeaveIfError( lex.Val( iInitialFreeSpace2 ) );
	    }
	else 
	    {
	    User::LeaveIfError( lex.Val( iInitialFreeSpace ) );
	    }    
    }
        
void CWmDrmDataStore::WriteInitialFreeSpaceL( const TDesC& aFileName,
    TBool& aConfiguredDrive )
    {
    RFile file;
    TBuf8<KMaxTInt64BufLength + 2 * KAESKeyLength> encryptedData;
    TBuf8<KMaxTInt64BufLength + 2 * KAESKeyLength> decryptedData;
    TBuf8<KAESKeyLength> key;
    TBuf8<KAESKeyLength> iv;
    CBufferedEncryptor* encryptor = NULL;
    CModeCBCEncryptor* cbcEncryptor = NULL;
    CAESEncryptor* aesEncryptor = NULL;
    CPaddingPKCS7* padding = NULL;
    
    LOGFN( "CWmDrmDataStore::WriteInitialFreeSpaceL" );
    User::LeaveIfError( file.Create( iServer->Fs(), aFileName, EFileWrite ) );
    CleanupClosePushL( file );
    if ( aConfiguredDrive )
        {
        iInitialFreeSpace2 = iServer->FreeSpaceL( aConfiguredDrive );
        }
    else
        {
        iInitialFreeSpace = iServer->FreeSpaceL( aConfiguredDrive );
        }    
    iv.SetLength( KAESKeyLength );
    TRandom::RandomL( iv );
#if defined(FF_PLATFORM_SIMULATOR) || defined(__WINSCW__)
    key.Copy( KDummyKey );
#else
    iServer->Cache()->iKeyStorage->GetDeviceSpecificKeyL( key );
#endif
    aesEncryptor = CAESEncryptor::NewL( key );
    CleanupStack::PushL( aesEncryptor );
    
    cbcEncryptor = CModeCBCEncryptor::NewL( aesEncryptor, iv );
    CleanupStack::Pop( aesEncryptor );
    CleanupStack::PushL( cbcEncryptor );
    
    padding = CPaddingPKCS7::NewL( KAESKeyLength );
    CleanupStack::PushL( padding );
    
    encryptor = CBufferedEncryptor::NewL( cbcEncryptor, padding );
    CleanupStack::Pop( 2, cbcEncryptor ); //padding, cbcEncryptor
    CleanupStack::PushL( encryptor );
    
    if ( aConfiguredDrive )
        {
        decryptedData.AppendNum( iInitialFreeSpace2 );
        }
    else
        {
        decryptedData.AppendNum( iInitialFreeSpace );
        }    
            
    encryptor->ProcessFinalL( decryptedData, encryptedData );
    User::LeaveIfError( file.Write( iv ) );
    User::LeaveIfError( file.Write( encryptedData ) );
    CleanupStack::PopAndDestroy( 2, &file ); //encryptor, file
    }

TWmDrmStoreState CWmDrmDataStore::DataStoreStateL()
    {
    TWmDrmStoreState state;
    TInt64 freeSpace( 0 );
    TInt64 freeSpace2( 0 );
    TInt dataStoreSize( 0 );
    TInt dummyDbSize( 0 );
    TInt ratio( 0 );
    TInt ratio2( 0 );
    TBool internalMassDriveNotFull( ETrue );
    
    LOGFN( "CWmDrmDataStore::DataStoreStateL" );
    freeSpace = iServer->FreeSpaceL( EFalse );
    
    if ( iWmDrmRightsConfigFound )
        {
        // Check free space from the configured drive, too.
        freeSpace2 = iServer->FreeSpaceL( ETrue );
        
        if ( freeSpace2 < iMinFreeSpace2 ) 
            {
            internalMassDriveNotFull = EFalse;
            }
            
        dummyDbSize = DummyDBSizeL( ETrue );
        dataStoreSize = DataStoreSizeL( ETrue );
        ratio2 = dataStoreSize * 100 / iInitialFreeSpace2;
        freeSpace2 += dummyDbSize;
#ifdef _LOGGING        
        TBuf<KMaxTInt64BufLength> free2;
        LOG1( "CWmDrmDataStore::DataStoreStateL: Free space (2): ");
        free2.AppendNumUC( freeSpace2, EDecimal );
        LOG( free2 );
        TBuf<KMaxTInt64BufLength> free2Min;
        LOG1( "CWmDrmDataStore::DataStoreStateL: Minimum free space (2): ");
        free2Min.AppendNumUC( iMinFreeSpace2, EDecimal );
        LOG( free2Min );
#endif             
        }
    
    // Check the system drive storage space next.   
    dummyDbSize = DummyDBSizeL( EFalse );
    dataStoreSize = DataStoreSizeL( EFalse );
    ratio = dataStoreSize * 100 / iInitialFreeSpace;
    freeSpace += dummyDbSize;
#ifdef _LOGGING        
    TBuf<KMaxTInt64BufLength> free;
    LOG1( "CWmDrmDataStore::DataStoreStateL: Free space: ");
    free.AppendNumUC( freeSpace, EDecimal );
    LOG( free );
    TBuf<KMaxTInt64BufLength> freeMin;
    LOG1( "CWmDrmDataStore::DataStoreStateL: Minimum free space: ");
    freeMin.AppendNumUC( iMinFreeSpace, EDecimal );
    LOG( freeMin );
#endif      
    
    // Select the state of the storage space.      
    if ( ( freeSpace > iMinFreeSpace ) && internalMassDriveNotFull ) 
        {
        LOG1( "CWmDrmDataStore::DataStoreStateL: Store space Ok" );
        state = EStoreSpaceOK;
        }
    else
        {
        // The configured drive is running out of space. The system drive 
        // may also be running out of storage space, but calculate
        // the ratio of database size to initial free drive space and the
        // state of the drive storage space from the configured drive because
        // it is likely to fill up faster since the media files may be synced to it. 
        if ( !internalMassDriveNotFull )
            {
            LOG2( "Ratio (2): %d", ratio2 );
            if ( ratio2 <= iMaxSpaceRatio2 )
                {
                LOG1( "CWmDrmDataStore::DataStoreStateL: Store space low (2)" );
                state = EStoreSpaceLow;
                }
            else
                {
                LOG1( "CWmDrmDataStore::DataStoreStateL: Store space full (2)" );
                state = EStoreSpaceFull;
                }
            }
        else
            // Only the system drive is running out of storage space. 
            {
            LOG2( "Ratio: %d", ratio );
            if ( ratio <= iMaxSpaceRatio )
                {
                LOG1( "CWmDrmDataStore::DataStoreStateL Store space low" );
                state = EStoreSpaceLow;
                }
            else
                {
                LOG1( "CWmDrmDataStore::DataStoreStateL Store space full" );
                state = EStoreSpaceFull;
                }
            }    
        }
        
    LOG2( "DataStoreState: %d", state );
    return state;
    }

void CWmDrmDataStore::InitializeDummyDbFileL( const TDesC& aFileName,
    RFile& aDummyDb, TBool& aConfiguredDrive )
    {
    TInt r( KErrNone );
    
    LOGFN( "CWmDrmDataStore::InitializeDummyDbFileL" );
    
    r = aDummyDb.Create( iServer->Fs(), aFileName, EFileWrite );
    if ( r == KErrAlreadyExists )
        {
        User::LeaveIfError( 
            aDummyDb.Open( iServer->Fs(), aFileName, EFileWrite ) );
        }
    else if( !r )
        {
        TInt dataStoreSize( DataStoreSizeL( aConfiguredDrive ) );
        if ( aConfiguredDrive )
            {
            if ( dataStoreSize <= iDummyDbInitialSize2 )
                {
                User::LeaveIfError( 
                    aDummyDb.SetSize( iDummyDbInitialSize2 - dataStoreSize ) );
                }
            else
                {
                User::LeaveIfError( aDummyDb.SetSize( 0 ) );
                }
            }
        else 
            {
            if ( dataStoreSize <= iDummyDbInitialSize )
                {
                User::LeaveIfError( 
                    aDummyDb.SetSize( iDummyDbInitialSize - dataStoreSize ) );
                }
            else
                {
                User::LeaveIfError( aDummyDb.SetSize( 0 ) );
                }
            } 
        }
    else
        {
        User::Leave( r );
        }
    }

void CWmDrmDataStore::UpdateDummyDbFileL( TInt aSize, TBool aConfiguredDrive )
    {
    LOGFN( "CWmDrmDataStore::UpdateDummyDbFileL" );
    LOG2( "aSize: %d", aSize );
    if ( aSize > 0 )
        {
        TInt dummyDbSize( DummyDBSizeL( aConfiguredDrive ) );
        LOG2( "dummyDbSize: %d", dummyDbSize );
        if ( aSize <= dummyDbSize )
            {
            if ( aConfiguredDrive ) 
                {
            	User::LeaveIfError( iDummyDb2.SetSize( dummyDbSize - aSize ) );
            	}
            else
            	{	
            	User::LeaveIfError( iDummyDb.SetSize( dummyDbSize - aSize ) );
            	}
           	} 		
        else
            {
            if ( aConfiguredDrive )
            	{
            	User::LeaveIfError( iDummyDb2.SetSize( 0 ) );
            	}
            else 
            	{
            	User::LeaveIfError( iDummyDb.SetSize( 0 ) );	
          		}
          	}		
        }
    else
        {
        TInt dataStoreSize( DataStoreSizeL( aConfiguredDrive ) );
        LOG2( "dataStoreSize: %d", dataStoreSize );
        if ( aConfiguredDrive )
            {
            if ( dataStoreSize <= iDummyDbInitialSize2 )
                {
                User::LeaveIfError( 
                    iDummyDb2.SetSize( iDummyDbInitialSize2 - dataStoreSize ) );
            	}
            else 
            	{
            	User::LeaveIfError( iDummyDb2.SetSize( 0 ) );
            	}
            }
        else 
            {
            if ( dataStoreSize <= iDummyDbInitialSize )
                {
                User::LeaveIfError( 
                    iDummyDb.SetSize( iDummyDbInitialSize - dataStoreSize ) );
            	}
            else 
            	{
            	User::LeaveIfError( iDummyDb.SetSize( 0 ) );
            	}
            }
        } 
    }

TInt CWmDrmDataStore::DataStoreSizeL( TBool aConfiguredDrive )
    {
    TInt dataStoreSize( iServer->Db()->DataBaseSize( aConfiguredDrive ) );
    User::LeaveIfError( dataStoreSize );
    return dataStoreSize;
    }

TInt CWmDrmDataStore::DummyDBSizeL( TBool aConfiguredDrive )
    {
    TInt dummyDbSize( 0 );
    if ( aConfiguredDrive )
        {
        User::LeaveIfError( iDummyDb2.Size( dummyDbSize ) );
        }
    else
        {
        User::LeaveIfError( iDummyDb.Size( dummyDbSize ) );
        }    
    return dummyDbSize;
    }

void CWmDrmDataStore::PrepareInfoFilesL( TBool aConfiguredDrive, 
    TChar aDriveLetter, RFile& aDummyDb )
    {
    LOGFN( "CWmDrmDataStore::PrepareInfoFilesL" );
    CRepository* repository( NULL );
    TInt r( KErrNone );
    TFileName dummyDbFile; 
    TFileName initialFreeSpaceFile;
    
    initialFreeSpaceFile.Format( KPrivateDir, (TUint)aDriveLetter );
    iServer->Fs().MkDirAll( initialFreeSpaceFile );
    initialFreeSpaceFile.Format( KInitialFreeSpaceFile, (TUint)aDriveLetter );
    dummyDbFile.Format( KDummyDbFile, (TUint)aDriveLetter );
    	
    TRAP( r, WriteInitialFreeSpaceL( initialFreeSpaceFile, 
        aConfiguredDrive ) );
    if ( r )
        {
        r = KErrNone;
        
        // catch the read error
        TRAP( r, ReadInitialFreeSpaceL( initialFreeSpaceFile, 
            aConfiguredDrive ) );
        
        // if an error occurs, this means that we are unable to read the info, 
        // thus we need to delete the file and run write again.
        // hopefully this being a temporary error, but if we fail again we fail
        // until next ConstructL
        if( r != KErrNone )
            {
            // delete the file:
            iServer->Fs().Delete( initialFreeSpaceFile );
            
            // Calc & Write the new info
            WriteInitialFreeSpaceL( initialFreeSpaceFile, aConfiguredDrive );
            }
        }
    
    if ( aConfiguredDrive )
        {
#ifdef _LOGGING        
        TBuf<KMaxTInt64BufLength> freeSpace2;
        LOG1( "CWmDrmDataStore::DataStoreStateL: Initial free space (2): ");
        freeSpace2.AppendNumUC( iInitialFreeSpace2, EDecimal );
        LOG( freeSpace2 );
#endif          
        if ( iInitialFreeSpace2 <= 0 )
            {
            User::Leave( KErrNotReady );
            }
        }
    else 
        {
#ifdef _LOGGING        
        TBuf<KMaxTInt64BufLength> freeSpace;
        LOG1( "CWmDrmDataStore::DataStoreStateL: Initial free space: ");
        freeSpace.AppendNumUC( iInitialFreeSpace, EDecimal );
        LOG( freeSpace );
#endif          
        if ( iInitialFreeSpace <= 0 )
            {
            User::Leave( KErrNotReady );
            }
        }
    
    //LOG1( "CWmDrmDataStore::PrepareInfoFilesL Check Cenrep" );
    
    TRAP( r, repository = CRepository::NewL( KCRUidWMDRM ) );
    if ( repository )
        {
        TInt rate( 0 );
        
        // Check the cenrep key parameters either for the default system drive
        // or for the internal mass drive depending whether the WMDRM rights
        // are configured to be partially stored to the internal mass drive or
        // not. 
        if ( !aConfiguredDrive )
            { 
            r = repository->Get( KWMDRMLicStoreLowMem, rate );
            if ( r )
                {
                iMinFreeSpace = KMegaByte;      
                }
            else
                {
                iMinFreeSpace = rate * KMegaByte;   
                }
            r = repository->Get( KWMDRMLicStoreSizeRatio, iMaxSpaceRatio );
            if ( r )
                {
                iMaxSpaceRatio = KMaxSpaceRatio;
                }
            r = repository->Get( KWMDRMLicStoreReservedSpace, rate );
            if ( r )
                {
                iDummyDbInitialSize = KDummyDbInitialSize;   
                }
            else
                {
                iDummyDbInitialSize = rate * KMegaByte;     
                }
            }
        else 
            {
            r = repository->Get( KWMDRM2LicStoreLowMem, rate );
            if ( r )
                {
                iMinFreeSpace2 = KTwoHundredMegaBytes;      
                }
            else
                {
                iMinFreeSpace2 = rate * KMegaByte;
                }
            r = repository->Get( KWMDRM2LicStoreSizeRatio, iMaxSpaceRatio2 );
            if ( r )
                {
                iMaxSpaceRatio2 = KMaxSpaceRatio2;
                }
            r = repository->Get( KWMDRM2LicStoreReservedSpace, rate );
            if ( r )
                {
                iDummyDbInitialSize2 = KDummyDbInitialSize;   
                }
            else
                {
                iDummyDbInitialSize2 = rate * KMegaByte;     
                }
            }          
        delete repository;
        }
    else
        {
        if ( !aConfiguredDrive )
            {
            iMinFreeSpace = KMegaByte; 
            iMaxSpaceRatio = KMaxSpaceRatio;
            iDummyDbInitialSize = KDummyDbInitialSize;
            }
        else 
            {
            iMinFreeSpace2 = KTwoHundredMegaBytes; 
            iMaxSpaceRatio2 = KMaxSpaceRatio2;
            iDummyDbInitialSize2 = KDummyDbInitialSize;            
            }
        }
     
    InitializeDummyDbFileL( dummyDbFile, aDummyDb, aConfiguredDrive );
    
    }