// Copyright (c) 2003-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:
// The base class for Bluetooth Saps
//
//
#include <es_prot.h>
#include "BtSap.h"
#include "secman.h"
#include "codman.h"
#include "BTSec.h"
//Diagnostic string for security check failures, in builds without platsec
//diagnostics this will be NULL.
const char* const KBT_SAP_NAME_DIAG = __PLATSEC_DIAGNOSTIC_STRING("Bluetooth SAP");
CBluetoothSAP::CBluetoothSAP(CBTSecMan& aSecMan, CBTCodServiceMan& aCodMan)
: iSecMan(aSecMan), iCodMan(aCodMan)
{
}
void CBluetoothSAP::ConstructL()
{
TCallBack accessDenied(AccessDeniedCallBack, this);
iAccessDeniedCallBack = new(ELeave) CAsyncCallBack(accessDenied, CActive::EPriorityStandard);
}
TInt CBluetoothSAP::SetDeviceOverride(const TDesC8& aOption)
/**
Provides for overriding of the general *service* security
for given devices.
**/
{
if (aOption.Length() != sizeof(TBTServiceSecurityPerDevice))
{
return KErrArgument;
}
TBTServiceSecurityPerDevice override =
*reinterpret_cast<const TBTServiceSecurityPerDevice*>(aOption.Ptr());
// add this device into the array of overrides for this SAP
// if device is in the list, replace the entry
for (TInt i=0; i<=iDeviceOverrides.Count()-1; i++)
{
if (iDeviceOverrides[i].DeviceAddress() == override.DeviceAddress())
{
// update!
iDeviceOverrides[i].SetDeviceSecurity(override.DeviceSecurity());
return KErrNone;
}
}
// if here, this is a new entry
return iDeviceOverrides.Append(override);
}
TInt CBluetoothSAP::GetDeviceOverride(TDes8& aOption) const
/**
Allows forgetful apps to give us an address, and we'll tell
them the overrides for this service for that device.
*/
{
if (aOption.Length() != sizeof(TBTServiceSecurityPerDevice))
{
return KErrArgument;
}
TBTServiceSecurityPerDevice overrideBuf =
*reinterpret_cast<const TBTServiceSecurityPerDevice*>(aOption.Ptr());
const TBTServiceSecurityPerDevice* override = Override(overrideBuf.DeviceAddress());
if (override)
{
overrideBuf.SetDeviceSecurity(override->DeviceSecurity());
aOption = TPtrC8(reinterpret_cast<TUint8*>(&overrideBuf), sizeof(TBTServiceSecurityPerDevice));
return KErrNone;
}
else
{
return KErrNotFound;
}
}
CBluetoothSAP::~CBluetoothSAP()
{
__ASSERT_DEBUG(!(iCodServiceBits & KBTCodBitsRegdFlag), User::Panic(KBTCodPanic, EBTCodBadDeregister));
iDeviceOverrides.Close();
delete iAccessDeniedCallBack;
}
const TBTServiceSecurity& CBluetoothSAP::Security() const
{
return iSecurity;
}
const TBTServiceSecurityPerDevice* CBluetoothSAP::Override(const TBTDevAddr& aAddress) const
{
//look through overrides for a device override
for (TInt i=0; i<iDeviceOverrides.Count(); i++)
{
if (iDeviceOverrides[i].DeviceAddress() == aAddress)
{
return &iDeviceOverrides[i];
}
}
return NULL;
}
void CBluetoothSAP::IoctlComplete(TInt /*aErr*/, TUint /*aLevel*/, TUint /*aName*/, TDesC8* aBuf)
{
iSocket->IoctlComplete(aBuf);
}
TInt CBluetoothSAP::SecurityCheck(MProvdSecurityChecker *aSecurityChecker)
{
__ASSERT_ALWAYS(aSecurityChecker, User::Panic(KSECURITY_PANIC, EBTPanicNullSecurityChecker));
iSecurityChecker = aSecurityChecker;
return iSecurityChecker->CheckPolicy(KLOCAL_SERVICES, KBT_SAP_NAME_DIAG);
}
void CBluetoothSAP::StartAccessRequest(const CBluetoothSAP& aSAPWithSecuritySettings, TBool aSecurityModeFourOutgoing)
/**
Ask secman to do security
@param aSAPWithSecuritySettings contains the security details
@param aSecurityModeFourOutgoing indicates whether this is a security mode 4 request that comes before
a security mode 2 request. This is to be used for establishing a suitable
this SAP has the remote address connecting
**/
{
const MAccessRequestResponseHandler& handler = *this;
TBTServiceSecurity secReqs(aSAPWithSecuritySettings.Security());
if(aSecurityModeFourOutgoing)
{
// For security mode 4 requests we don't consider the authorisation and any pre-v2.1
// security settings. Note this is only applicable for outgoing access requirements.
//So we set a concrete MITM protection value...
secReqs.SetAuthentication(secReqs.MitmProtection());
// ...then we remove any authorisation, authentication or encryption.
secReqs.SetAuthorisation(EFalse);
secReqs.SetAuthentication(EFalse);
secReqs.SetEncryption(EFalse);
}
// As a note, using the override as-is is infact safe as none of the override values
// can really affect the security mode 4 aspects.
TRAPD(err, SecMan().AccessRequestL(secReqs,
aSAPWithSecuritySettings.Override(RemoteAddress()),
RemoteAddress(),
aSecurityModeFourOutgoing ? EGeneralBondingSecurityMode4Outgoing : EGeneralBonding, // We are doing general bonding
const_cast<MAccessRequestResponseHandler&>(handler)));
if (err != KErrNone)
{
// complete request now...
iAccessDeniedCallBack->CallBack();
}
}
void CBluetoothSAP::CancelAccessRequest()
{
SecMan().CancelRequest(*this);
}
void CBluetoothSAP::AccessRequestComplete(TInt /*aResult*/)
/**
The SAP wasnt expecting security responses
Derivers normally would override (and forward to state)
**/
{
_LIT(KBTSAPPanic, "BTSAP");
User::Panic(KBTSAPPanic, EBTSecUnexpectedSecurityResponse);
}
/*static*/ TInt CBluetoothSAP::AccessDeniedCallBack(TAny* aBtSap)
{
CBluetoothSAP* btSap = static_cast<CBluetoothSAP*>(aBtSap);
btSap->AccessRequestComplete(EBTSecManAccessDenied);
return KErrNone;
}
TInt CBluetoothSAP::SetCodServiceBits(TUint16 aNewCodServiceBits)
/**
Allow SetOpts to set Service bits. These are written to the CoD
when the SAP becomes active.
**/
{
TInt err = KErrNone;
if (aNewCodServiceBits & (~KBTCodValidServiceBits))
{
err = KErrArgument; // SetOpt is attempting to set illegal bits
}
else
{
if (iCodServiceBits & KBTCodBitsRegdFlag)
{
err = KErrAlreadyExists; // This SAP has Service bits already registered
}
else
{
iCodServiceBits = aNewCodServiceBits; // These can be overwritten at this stage
}
}
return err;
}
void CBluetoothSAP::RegisterCodService()
/**
Allows SAPs to register their Service(s)
**/
{
if (iCodServiceBits && !(iCodServiceBits & KBTCodBitsRegdFlag))
{
// Only send to CodMan once
CodMan().RegisterCodService(iCodServiceBits);
}
// Set the regd flag, even if no service bits, this will ensure that late SetOpts are errored
iCodServiceBits |= KBTCodBitsRegdFlag;
}
void CBluetoothSAP::DeregisterCodService()
/**
Allows SAPs to clear their Service bits
**/
{
if (iCodServiceBits && (iCodServiceBits & KBTCodBitsRegdFlag))
{
iCodServiceBits &= (~KBTCodBitsRegdFlag); // reset the registered flag, don't want to confuse CodMan
CodMan().RemoveCodService(iCodServiceBits);
}
iCodServiceBits = 0; // tidy up these service bits + regd flag
}
TInt CBluetoothSAP::SetOption(TUint aLevel,TUint aName,const TDesC8 &aOption)
/**
This is now the default SetOpt handler for SAP protocols.
Common attributes are processed here and the protocol dependent SetOpts are passed on.
**/
{
TInt rerr = KErrNone;
if(aLevel == KSolBtSAPBase)
{
switch (aName)
{
case KBTRegisterCodService:
{
if (aOption.Length() != sizeof(TDesC8))
return KErrArgument;
TUint16 newServiceBits = *reinterpret_cast<const TUint16*>(aOption.Ptr());
rerr = SetCodServiceBits(newServiceBits); // The service bits are saved and then registered when SAP becomes live
}
break;
default:
// Unhandled SetOpt name
rerr = KErrNotSupported;
break;
}
}
else
{
// Process SAP SetOpts
rerr = SAPSetOption(aLevel, aName, aOption);
}
return rerr;
}