vpnui/vpnpolins/src/vpndevlockhandler.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 09:14:51 +0200
changeset 0 33413c0669b9
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2007 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:   Utility classes for device lock handling
*
*/



#include <e32std.h>

#include "vpndevlockhandler.h"
#include "policyinstaller_constants.h"
#include "logvpncommon.h"
#include "vpntcstub.h"


// 64bit integer's string representation can be at 
// most 20 bytes (+ sign) long...
#define MAX_INT_STR_LEN 21


//////////////
// CVpnDevLockPolicy implementation

CVpnDevLockPolicy* CVpnDevLockPolicy::NewL(const TInt aPolicy) 
    {
    LOG_("-> CVpnDevLockPolicy::NewL()");
    
    CVpnDevLockPolicy* self = new (ELeave) CVpnDevLockPolicy();
    CleanupStack::PushL(self);
    self->ConstructL(aPolicy);
    CleanupStack::Pop(self);
    
    LOG_("<- CVpnDevLockPolicy::NewL()");
    
    return self;
    }

CVpnDevLockPolicy* CVpnDevLockPolicy::NewLC(const TInt aPolicy) 
    {
    LOG_("-> CVpnDevLockPolicy::NewLC()");
    
    CVpnDevLockPolicy* self = new (ELeave) CVpnDevLockPolicy();
    CleanupStack::PushL(self);
    self->ConstructL(aPolicy);
    
    LOG_("<- CVpnDevLockPolicy::NewLC()");
    
    return self;
    }

CVpnDevLockPolicy* CVpnDevLockPolicy::NewLC() 
    {
    LOG_("-> CVpnDevLockPolicy::NewLC()");
    
    CVpnDevLockPolicy* self = new (ELeave) CVpnDevLockPolicy();
    CleanupStack::PushL(self);
    self->ConstructL();
    
    LOG_("<- CVpnDevLockPolicy::NewLC()");
    
    return self;
    }

CVpnDevLockPolicy::CVpnDevLockPolicy()
    {
    }

CVpnDevLockPolicy::~CVpnDevLockPolicy() 
    {
    LOG_("-> CVpnDevLockPolicy::CVpnDevLockPolicy()");

    // Delete each entry from the policy attributes array, 
    // and then reset the array itself
    if (iPolicyArray) 
        {
        for (TInt i = iPolicyArray->Count() - 1; i >= 0; i--) 
            {
            delete iPolicyArray->At(i);
            }
        iPolicyArray->Reset();
        }

    delete iPolicyArray;

    LOG_("<- CVpnDevLockPolicy::CVpnDevLockPolicy()");
    }

void CVpnDevLockPolicy::ConstructL(const TInt aPolicy) 
    {
    LOG_("-> CVpnDevLockPolicy::ConstructL()");
    ConstructL();
    SetPolicyLevelL(aPolicy);
    LOG_("<- CVpnDevLockPolicy::ConstructL()");
    }

void CVpnDevLockPolicy::ConstructL()
    {
    LOG_("-> CVpnDevLockPolicy::ConstructL()");
    iPolicyArray = new (ELeave) CArrayFixFlat<CVpnDevLockAttribute*>(3);
    LOG_("<- CVpnDevLockPolicy::ConstructL()");
    }

void CVpnDevLockPolicy::SetPolicyAttributeL(const TInt aAttrib, const TInt aVal) 
    {
    LOG_("-> CVpnDevLockPolicy::SetPolicyAttributeL() int variant");

    CVpnDevLockAttribute* attrib = CVpnDevLockAttribute::NewL(aAttrib, aVal);
    CleanupStack::PushL(attrib);
    iPolicyArray->AppendL(attrib);

    // ownership's been transferred to array
    CleanupStack::Pop(attrib); 


    // Remove this (or rather flag for debug builds only)
    TInt val(0);
    attrib->AttributeValueAsIntL(val);

    LOG_1(" Items in array: %d", iPolicyArray->Count());
    LOG8_1("  Attrib  ID: %d", attrib->AttributeId());
    LOG8_1("  Attrib val: %d", val);

    LOG_("<- CVpnDevLockPolicy::SetPolicyAttributeL() int variant");
    }


void CVpnDevLockPolicy::SetPolicyAttributeL(const TInt aAttrib, const TDesC8& aVal) 
    {
    LOG_("-> CVpnDevLockPolicy::SetPolicyAttributeL() str variant");

    // Create a new attribute and add it to the existing array of attributes
    CVpnDevLockAttribute* attrib = CVpnDevLockAttribute::NewL(aAttrib, aVal);
    CleanupStack::PushL(attrib);
    iPolicyArray->AppendL(attrib);
    
    // ownership's been transferred to array
    CleanupStack::Pop(attrib); 

    LOG8_1("  Attrib  ID: %d", attrib->AttributeId());

    LOG_("<- CVpnDevLockPolicy::SetPolicyAttributeL() str variant");
    }

/**
 * Description of device lock levels (from SUB 415-467)
 *
 * 0. Do not enforce device lock
 *   - installing this policy has no impact on the device lock settings
 * 1. Enforce device lock with policy 1
 *   - no special requirements on lock code
 *   - autolock timeout 30 minutes
 *   - wipe after 20 unsuccessful unlocking attempts
 * 2. Enforce device lock with policy 2
 *   - lock code minimum length 5 characters
 *   - autolock timeout 10 minutes
 *   - wipe after 10 unsuccessful unlocking attempts
 * 3. Enforce device lock with policy 3
 *   - lock code mimimum length 5 characters
 *   - both characters and numbers required
 *   - both upper and lower case letters required
 *   - passcode expires every 30 days and must be changed
 *   - new passcode must not match any of the 5 previous passcodes 
 *   - autolock timeout 5 minutes
 *   - wipe after 10 unsuccessful unlocking attempts
 *
 */
void CVpnDevLockPolicy::SetPolicyLevelL(const TInt aPolLevel) 
    {
    LOG_("-> CVpnDevLockPolicy::SetPolicyLevelL()");

    LOG_1(" Setting policy level: %d", aPolLevel);

    // Setting the policy level
    // See VPN device lock SUB for exact device lock policy level descriptions
    switch (aPolLevel) 
        {
        case 0:
            // No changes to existing devlock policy, 
            // when policy level is 0
            break;
        case 1:
            // Only enforce timeout and max number of passcode attempts
            SetPolicyAttributeL(RTerminalControl3rdPartySession::ETimeout, 30);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeMaxAttempts, 20);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EMaxTimeout, 30);
            break;
        case 2:
            // Enforce stricter timeout as well, and a minimum length for passcode
            SetPolicyAttributeL(RTerminalControl3rdPartySession::ETimeout, 10);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeMinLength, 5);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeMaxAttempts, 10);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EMaxTimeout, 10);
            break;
        case 3:
            // Enforce even more password-related rules
            SetPolicyAttributeL(RTerminalControl3rdPartySession::ETimeout, 5);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeMinLength, 5);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeMaxAttempts, 10);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeRequireCharsAndNumbers,
                                1);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeRequireUpperAndLower,
                                1);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeExpiration, 30);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EPasscodeHistoryBuffer, 5);
            SetPolicyAttributeL(RTerminalControl3rdPartySession::EMaxTimeout, 5);
            break;
        default:
            // Policy levels 4+ not supported, leave (tried to instantiate an illegal policy)
            LOG_("<- CVpnDevLockPolicy::SetPolicyLevelL() LEAVE: illegal policy level");
            User::Leave(KErrNotSupported);
            break;
        }

    LOG_("<- CVpnDevLockPolicy::SetPolicyLevelL()");
    }

TInt CVpnDevLockPolicy::AttributeCount() 
    {
    LOG_("-> CVpnDevLockPolicy::AttributeCount()");

    TInt ret(0);
    if (iPolicyArray) 
        {
        ret = iPolicyArray->Count();
        }

    LOG_1("<- CVpnDevLockPolicy::AttributeCount() ret: %d", ret);
    return ret;
    }

CVpnDevLockAttribute* CVpnDevLockPolicy::GetPolicyAttributeAt(const TInt aIdx) 
    {
    LOG_("-> CVpnDevLockPolicy::GetPolicyAttributeAt()");
    CVpnDevLockAttribute* ret(NULL);

    if (iPolicyArray && (aIdx < iPolicyArray->Count()))
        {
        LOG_1(" Found valid attribute at index %d", aIdx);
        ret = iPolicyArray->At(aIdx);
        }

    LOG_("<- CVpnDevLockPolicy::GetPolicyAttributeAt()");
    return ret;
    }


//////////////
// CVpnDevLockHandler implementation

/**
 * Constructor, and
 *
 */
CVpnDevLockHandler::CVpnDevLockHandler()
    {
    LOG_("-> CVpnDevLockHandler::CVpnDevLockHandler()");
    
    LOG_("<- CVpnDevLockHandler::CVpnDevLockHandler()");
    }

void CVpnDevLockHandler::ConstructL() 
    {
    // Connect to terminal control (if available)
    LoadTCLibraryL();
    }

void CVpnDevLockHandler::LoadTCLibraryL()
    {
    LOG_("-> CVpnDevLockHandler::LoadTCLibraryL()");

    TInt status = iTcLib.Load(KVpnDevLockWrapperDll, KNullUid);

    LOG_1(" DLL load status: %d", status);

    if (status == KErrNone)
        {
        LOG_(" Suitable library found, instantiating dev lock object");

        TLibraryFunction entry = iTcLib.Lookup(1);
        
        // Entry point function (NewTcStubL) might leave,
        // although it isn't readily obvious from the syntax
        iTcStub = (CVpnTcStub*)entry();

        LOG_(" Dev lock object instantiated");
        iDevLockAvailable = ETrue;
        }
    else 
        {
        LOG_(" No suitable library found!");
        iDevLockAvailable = EFalse;
        }
    
    LOG_("<- CVpnDevLockHandler::LoadTCLibraryL()");
    }

CVpnDevLockHandler::~CVpnDevLockHandler() 
    {
    LOG_("-> CVpnDevLockHandler::CVpnDevLockHandler()");

    LOG_(" Deleting TC stub");
    delete iTcStub;

    LOG_(" Closing TC library");
    iTcLib.Close();
    
    LOG_("<- CVpnDevLockHandler::CVpnDevLockHandler()");
    }

void CVpnDevLockHandler::TerminalControlSupportsVpnL() 
    {
    LOG_("-> CVpnDevLockHandler::TerminalControlSupportsVpnL()");

    HBufC8* attrib(NULL);

    // If the lib stub is available, try to read a device lock attribute
    // (read may fail))
    if (iTcStub) 
        {
        LOG_(" TC stub is valid");
        attrib = iTcStub->GetTCAttributeL(RTerminalControl3rdPartySession::ETimeout);

        if (attrib) 
            {
            LOG8_1(" Attribute: '%S'", attrib);
            delete attrib;
            }
        else 
            {
            LOG_(" Attribute couldn't be read");
            User::Leave(KErrAccessDenied);
            }
        }
    else 
        {
        LOG_(" No stub available, terminating");
        User::Leave(KErrAccessDenied);
        }

    LOG_("<- CVpnDevLockHandler::TerminalControlSupportsVpnL()");
    }

void CVpnDevLockHandler::SetTerminalControlPolicyL(const TInt aPolLevel) 
    {
    LOG_("-> CVpnDevLockHandler::SetTerminalControlPolicyL()");
    LOG_1(" Setting policy level %d", aPolLevel);

    CVpnDevLockPolicy* devpolicy = CVpnDevLockPolicy::NewL(aPolLevel);
    CleanupStack::PushL(devpolicy);

    // Iterate through all the attributes that VPN policy requires.
    // For each one found, check if it's stricter than the old device lock setting,
    // and only if that is the case, update the actual value on device.

    TInt attribs = devpolicy->AttributeCount();
    LOG_1(" Iterating through %d attributes", attribs);
    
    TBool forceLock(EFalse);

    for (TInt i = 0; i < attribs; i++) 
        {
        CVpnDevLockAttribute* attrib = devpolicy->GetPolicyAttributeAt(i);
        if (!attrib) 
            {
            LOG_("<- CVpnDevLockHandler::SetTerminalControlPolicyL() LEAVE: Not found");
            User::Leave(KErrNotFound);
            }

        LOG_1(" Attribute    ID: %d", attrib->AttributeId());

        // Only set the attribute if the existing one was not as strict
        // (definition of "strict" depends on attribute's semantics)
        TBool override(EFalse);
        TRAPD(err, override = OverrideExistingL(*attrib));

        if ((err == KErrNone && override) || err == KErrNotFound)
            {
            SetDevAttributeL(*attrib);
            forceLock = ETrue;
            }

        }

    // If at least one lock parameter was (succesfully) changed, force device lock after
    // import
    if (forceLock) 
        {
        LOG_(" Forcing device lock activation");

        // Force lock
        CVpnDevLockAttribute* attrib = CVpnDevLockAttribute::NewL(RTerminalControl3rdPartySession::ELock,
                                                                  1);
        CleanupStack::PushL(attrib);

        // Expire password (force password change)
        CVpnDevLockAttribute* attrib2 = 
                                CVpnDevLockAttribute::NewL(RTerminalControl3rdPartySession::EPasscodeExpiration, -1);
        CleanupStack::PushL(attrib2);

        LOG_(" Expiring old passcode");
        SetDevAttributeL(*attrib2);
        CleanupStack::PopAndDestroy(attrib2);

        LOG_(" Forcing device lock");
        SetDevAttributeL(*attrib);
        CleanupStack::PopAndDestroy(attrib);
        }
    
    
    CleanupStack::PopAndDestroy(devpolicy);

    LOG_("<- CVpnDevLockHandler::SetTerminalControlPolicyL()");
    }

TBool CVpnDevLockHandler::OverrideExistingL(const CVpnDevLockAttribute& aNew) 
    {
    LOG_("-> CVpnDevLockHandler::OverrideExisting()");
    TBool ret(EFalse);

    HBufC8* existingAttrib = GetDevAttribValueL(aNew.AttributeId());
    CleanupStack::PushL(existingAttrib);

    // At the moment, we can rely on the fact that all relevant
    // attributes are numerical... This may change in future
    TInt newVal(-1);
    TInt oldVal(-1);
    TLex8 lexer(*existingAttrib);
    User::LeaveIfError(lexer.Val(oldVal));
    aNew.AttributeValueAsIntL(newVal);

    switch (aNew.AttributeId()) 
        {
        case RTerminalControl3rdPartySession::ETimeout:
            // If device lock timeout is set to lower value than the old one,
            // then we need to update the policy
            LOG_(" Case ETimeout");
            if (newVal < oldVal || oldVal == 0) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeMinLength:
            // If passcode minimum length requirement is longer than the
            // old one, then we need to update the policy
            LOG_(" Case EPasscodeMinLength");
            if (newVal > oldVal) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeMaxAttempts:
            // If max attempts lower, override
            LOG_(" Case EPasscodeMaxAttempts");
            if (newVal < oldVal || oldVal == 0) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeRequireCharsAndNumbers:
            // If alphanum requirement didn't exist before, override
            LOG_(" Case EPasscodeRequireCharsAndNumbers");
            if (newVal > oldVal)
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeRequireUpperAndLower:
            // If UC/LC requirement didn't exist before, override
            LOG_(" Case EPasscodeRequireUpperAndLower");
            if (newVal > oldVal) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeExpiration:
            // If less days before passcode expiration, override
            LOG_(" Case EPasscodeExpiration");
            if (newVal < oldVal || oldVal == 0) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EPasscodeHistoryBuffer:
            // If the proposed passcode history is longer, override
            LOG_(" Case EPasscodeHistoryBuffer");
            if (newVal > oldVal) 
                {
                ret = ETrue;
                }
            break;
        case RTerminalControl3rdPartySession::EMaxTimeout:
            // If the proposed max timeout is shorter, override
            LOG_(" Case EMaxTimeout");
            if ((oldVal == 0) || (newVal < oldVal)) 
                {
                ret = ETrue;
                }
            break;
        default:
            LOG_(" ERROR: Case default, unknown attribute!");
            User::Leave(KErrNotFound);
            break;
        }
    CleanupStack::PopAndDestroy(existingAttrib);

    LOG_1("  Old value: %d", oldVal);
    LOG_1("  New value: %d", newVal);
    LOG( if (ret) 
        {
        LOG_("   => Old value needs to be updated");
        }
    );

    LOG_1("<- CVpnDevLockHandler::OverrideExisting() ret: %d", ret);
    return ret;
    }

HBufC8* CVpnDevLockHandler::GetDevAttribValueL(const TInt aAttribId) 
    {
    LOG_("-> CVpnDevLockHandler::GetDevAttribValueL()");

    HBufC8* buffer(NULL);

    if (iTcStub) 
        {
        buffer = iTcStub->GetTCAttributeL(aAttribId);
        if (buffer) 
            {
            LOG8_1(" Buffer: '%S'", buffer);
            }
        }

    LOG_("<- CVpnDevLockHandler::GetDevAttribValueL()");

    return buffer;
    }

void CVpnDevLockHandler::SetDevAttributeL(const CVpnDevLockAttribute& aNew) 
    {
    LOG_("-> CVpnDevLockHandler::SetDevAttribValueL()");

    if (iTcStub) 
        {
        iTcStub->SetTCAttributeL(aNew.AttributeId(), aNew.AttributeValue());
        }

    LOG_("<- CVpnDevLockHandler::SetDevAttribValueL()");
    }


//////////////
// CVpnDevLockAttribute implementation

CVpnDevLockAttribute* CVpnDevLockAttribute::NewL(const TInt aId, const TDesC8& aVal) 
    {
    LOG_("-> CVpnDevLockAttribute::NewL()");
    
    CVpnDevLockAttribute* self = new (ELeave) CVpnDevLockAttribute();
    CleanupStack::PushL(self);
    self->ConstructL(aId, aVal);
    CleanupStack::Pop(self);
    
    LOG_("<- CVpnDevLockAttribute::NewL()");
    return self;
    }

CVpnDevLockAttribute* CVpnDevLockAttribute::NewL(const TInt aId, const TInt aVal) 
    {
    LOG_("-> CVpnDevLockAttribute::NewL()");
    
    CVpnDevLockAttribute* self = new (ELeave) CVpnDevLockAttribute();
    CleanupStack::PushL(self);
    self->ConstructL(aId, aVal);
    CleanupStack::Pop(self);
    
    LOG_("<- CVpnDevLockAttribute::NewL()");
    return self;
    }

CVpnDevLockAttribute* CVpnDevLockAttribute::NewLC(const TInt aId, const TDesC8& aVal) 
    {
    LOG_("-> CVpnDevLockAttribute::NewLC()");
    
    CVpnDevLockAttribute* self = new (ELeave) CVpnDevLockAttribute();
    CleanupStack::PushL(self);
    self->ConstructL(aId, aVal);
    
    LOG_("<- CVpnDevLockAttribute::NewLC()");
    
    return self;
    }

CVpnDevLockAttribute::~CVpnDevLockAttribute() 
    {
    LOG_("-> CVpnDevLockAttribute::~CVpnDevLockAttribute()");
    delete iAttributeVal;
    LOG_("<- CVpnDevLockAttribute::~CVpnDevLockAttribute()");
    }

CVpnDevLockAttribute::CVpnDevLockAttribute() 
    {
    LOG_("-> CVpnDevLockAttribute::CVpnDevLockAttribute()");
    LOG_("<- CVpnDevLockAttribute::CVpnDevLockAttribute()");
    }

void CVpnDevLockAttribute::ConstructL(const TInt aId, const TDesC8& aVal) 
    {
    iAttributeId = aId;
    iAttributeVal = aVal.AllocL();
    }

void CVpnDevLockAttribute::ConstructL(const TInt aId, const TInt aVal) 
    {
    // Convert int to a string
    iAttributeId = aId;
    TBuf8<MAX_INT_STR_LEN> buf;
    buf.Num(aVal);
    iAttributeVal = buf.AllocL();
    }

TPtrC8 CVpnDevLockAttribute::AttributeValue() const
    {
    return *iAttributeVal;
    }

void CVpnDevLockAttribute::AttributeValueAsIntL(TInt& aVal) const
    {
    if (iAttributeVal)
        {
        TLex8 lexer(*iAttributeVal);
        User::LeaveIfError(lexer.Val(aVal));
        }
    }

TInt CVpnDevLockAttribute::AttributeId() const
    {
    return iAttributeId;
    }



CVpnDevLockHandler* CVpnDevLockHandler::NewL() 
    {
    LOG_("-> CVpnDevLockHandler::NewL()");
    
    CVpnDevLockHandler* self = new (ELeave) CVpnDevLockHandler();
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    
    LOG_("<- CVpnDevLockAttribute::NewL()");
    return self;
    }

CVpnDevLockHandler* CVpnDevLockHandler::NewLC() 
    {
    LOG_("-> CVpnDevLockAttribute::NewLC()");
    
    CVpnDevLockHandler* self = new (ELeave) CVpnDevLockHandler();
    CleanupStack::PushL(self);
    self->ConstructL();
    
    LOG_("<- CVpnDevLockAttribute::NewLC()");
    
    return self;
    }