* Copyright (c) 2025 Huawei Device Co., Ltd.
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "access_control_profile.h"
#include "hichain_auth_connector.h"
#include "multiple_user_connector.h"
#include "dm_crypto.h"
#include "dm_auth_state.h"
#include "dm_auth_context.h"
#include "dm_auth_manager_base.h"
#include "dm_auth_state_machine.h"
#include "dm_crypto.h"
#include "dm_softbus_cache.h"
#if defined(SUPPORT_SCREENLOCK)
#include "screenlock_manager.h"
#endif
#include "dm_log.h"
#include <sys/time.h>
namespace OHOS {
namespace DistributedHardware {
const std::map<std::string, int32_t> TASK_TIME_OUT_MAP = {
{ std::string(AUTHENTICATE_TIMEOUT_TASK), CLONE_AUTHENTICATE_TIMEOUT },
{ std::string(NEGOTIATE_TIMEOUT_TASK), CLONE_NEGOTIATE_TIMEOUT },
{ std::string(CONFIRM_TIMEOUT_TASK), CLONE_CONFIRM_TIMEOUT },
{ std::string(ADD_TIMEOUT_TASK), CLONE_ADD_TIMEOUT },
{ std::string(WAIT_NEGOTIATE_TIMEOUT_TASK), CLONE_WAIT_NEGOTIATE_TIMEOUT },
{ std::string(WAIT_REQUEST_TIMEOUT_TASK), CLONE_WAIT_REQUEST_TIMEOUT },
{ std::string(WAIT_PIN_AUTH_TIMEOUT_TASK), CLONE_PIN_AUTH_TIMEOUT },
{ std::string(SESSION_HEARTBEAT_TIMEOUT_TASK), CLONE_SESSION_HEARTBEAT_TIMEOUT }
};
constexpr uint16_t ONBINDRESULT_MAPPING_NUM = 2;
constexpr int32_t MS_PER_SECOND = 1000;
constexpr int32_t US_PER_MSECOND = 1000;
constexpr int32_t GET_SYSTEMTIME_MAX_NUM = 3;
constexpr int32_t PIN_CODE_COUNT_MAX_NUM = 10;
constexpr const static char* ONBINDRESULT_MAPPING_LIST[ONBINDRESULT_MAPPING_NUM] = {
"CollaborationFwk",
"cast_engine_service",
};
constexpr const static char* FLAG_WHITE_LIST[] = {
"wear_link_service",
};
constexpr int32_t FLAG_WHITE_LIST_NUM = std::size(FLAG_WHITE_LIST);
const std::map<DmAuthStateType, DmAuthStatus> NEW_AND_OLD_STATE_MAPPING = {
{ DmAuthStateType::AUTH_SRC_FINISH_STATE, DmAuthStatus::STATUS_DM_AUTH_FINISH },
{ DmAuthStateType::AUTH_SINK_FINISH_STATE, DmAuthStatus::STATUS_DM_SINK_AUTH_FINISH },
{ DmAuthStateType::AUTH_IDLE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_START_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_NEGOTIATE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_CONFIRM_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_PIN_NEGOTIATE_START_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_PIN_INPUT_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_REVERSE_ULTRASONIC_START_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_REVERSE_ULTRASONIC_DONE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_PIN_AUTH_START_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_PIN_AUTH_MSG_NEGOTIATE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_PIN_AUTH_DONE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_CREDENTIAL_EXCHANGE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_CREDENTIAL_AUTH_START_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_CREDENTIAL_AUTH_NEGOTIATE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_CREDENTIAL_AUTH_DONE_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT },
{ DmAuthStateType::AUTH_SRC_DATA_SYNC_STATE, DmAuthStatus::STATUS_DM_AUTH_DEFAULT }
};
const std::map<int32_t, int32_t> NEW_AND_OLD_REPLAY_MAPPING = {
{ DM_ALREADY_AUTHED, SOFTBUS_OK },
{ SOFTBUS_OK, SOFTBUS_OK },
{ DM_BIND_TRUST_TARGET, DM_OK },
{ ERR_DM_SKIP_AUTHENTICATE, DM_OK },
};
int32_t DmAuthState::GetTaskTimeout(std::shared_ptr<DmAuthContext> context, const char* taskName, int32_t taskTimeOut)
{
LOGI("taskName: %{public}s, authType_: %{public}d", taskName, context->authType);
if (AUTH_TYPE_IMPORT_AUTH_CODE == context->authType) {
auto timeout = TASK_TIME_OUT_MAP.find(std::string(taskName));
if (timeout != TASK_TIME_OUT_MAP.end()) {
return timeout->second;
}
}
return taskTimeOut;
}
void DmAuthState::HandleAuthenticateTimeout(std::shared_ptr<DmAuthContext> context, std::string name)
{
LOGI("start timer name %{public}s", name.c_str());
context->timer->DeleteTimer(name);
context->reason = ERR_DM_TIME_OUT;
context->authStateMachine->NotifyEventFinish(DmEventType::ON_FAIL);
LOGI("complete");
}
bool DmAuthState::IsScreenLocked()
{
bool isLocked = false;
#if defined(SUPPORT_SCREENLOCK)
CHECK_NULL_RETURN(OHOS::ScreenLock::ScreenLockManager::GetInstance(), isLocked);
isLocked = OHOS::ScreenLock::ScreenLockManager::GetInstance()->IsScreenLocked();
#endif
LOGI("isLocked: %{public}d.", isLocked);
return isLocked;
}
DmAuthScope DmAuthState::GetAuthorizedScope(int32_t bindLevel)
{
DmAuthScope authorizedScope = DM_AUTH_SCOPE_INVALID;
if (bindLevel == static_cast<int32_t>(APP) || bindLevel == static_cast<int32_t>(SERVICE)) {
authorizedScope = DM_AUTH_SCOPE_APP;
} else if (bindLevel == static_cast<int32_t>(USER)) {
authorizedScope = DM_AUTH_SCOPE_USER;
}
return authorizedScope;
}
void DmAuthState::SourceFinish(std::shared_ptr<DmAuthContext> context)
{
LOGI("reason:%{public}d, state:%{public}d", context->reason, context->state);
if (DmAuthState::IsImportAuthCodeCompatibility(context->authType)) {
HandlePinResultAndCallback(context, context->accesser.pkgName);
}
context->listener->OnAuthResult(context->processInfo, context->peerTargetId.deviceId, context->accessee.tokenIdHash,
GetOutputState(context->state), context->reason);
context->listener->OnBindResult(context->processInfo, context->peerTargetId,
GetOutputReplay(context->accesser.bundleName, context->reason),
GetOutputState(context->state), GenerateBindResultContent(context));
context->successFinished = true;
if (context->reason != DM_OK && context->reason != DM_ALREADY_AUTHED && context->reason != DM_BIND_TRUST_TARGET) {
BindFail(context);
}
LOGI("notify online");
char deviceIdHash[DM_MAX_DEVICE_ID_LEN] = {0};
Crypto::GetUdidHash(context->accessee.deviceId, reinterpret_cast<uint8_t *>(deviceIdHash));
if (SoftbusCache::GetInstance().CheckIsOnline(std::string(deviceIdHash))) {
SetProcessInfo(context);
int32_t authForm = context->accesser.transmitBindType == DM_POINT_TO_POINT_TYPE ?
DmAuthForm::PEER_TO_PEER : context->accesser.transmitBindType;
#ifdef CAR_DEVICE_ENABLE
PeerDevInfo peerDevInfo;
peerDevInfo.deviceId = context->accessee.deviceId;
peerDevInfo.userId = context->accessee.userId;
peerDevInfo.accountId = context->accessee.accountId;
context->softbusConnector->HandleDeviceOnline(context->accessee.deviceId, authForm, peerDevInfo);
#else
context->softbusConnector->HandleDeviceOnline(context->accessee.deviceId, authForm);
#endif
}
context->authUiStateMgr->UpdateUiState(DmUiStateMsg::MSG_CANCEL_PIN_CODE_INPUT);
context->timer->DeleteAll();
}
void DmAuthState::SinkFinish(std::shared_ptr<DmAuthContext> context)
{
LOGI("reason:%{public}d, state:%{public}d", context->reason, context->state);
if (DmAuthState::IsImportAuthCodeCompatibility(context->authType)) {
DistributedDeviceProfile::LocalServiceInfo srvInfo;
JsonObject extraInfoObj;
bool oneTimePinCodeFlag = false;
std::string pkgName = context->accessee.pkgName;
if (PKGNAME_MAPPING.find(pkgName) != PKGNAME_MAPPING.end()) {
pkgName = PKGNAME_MAPPING.at(pkgName);
}
if (GetServiceExtraInfo(pkgName, context->authType, srvInfo, extraInfoObj)) {
if (IsBool(extraInfoObj, TAG_ONE_TIME_PIN_CODE_FLAG)) {
oneTimePinCodeFlag = extraInfoObj[TAG_ONE_TIME_PIN_CODE_FLAG].Get<bool>();
}
}
if (oneTimePinCodeFlag) {
srvInfo.SetPinCode("******");
DeviceProfileConnector::GetInstance().UpdateLocalServiceInfo(srvInfo);
} else {
HandlePinResultAndCallback(context, pkgName);
}
}
context->processInfo.pkgName = context->accessee.pkgName;
context->peerTargetId.serviceId = context->accessee.serviceId;
context->listener->OnSinkBindResult(context->processInfo, context->peerTargetId,
GetOutputReplay(context->accessee.bundleName, context->reason),
GetOutputState(context->state), GenerateBindResultContent(context));
context->successFinished = true;
if (context->reason != DM_OK) {
BindFail(context);
} else {
LOGI("notify online");
NotifyDeviceOnline(context);
}
context->authUiStateMgr->UpdateUiState(DmUiStateMsg::MSG_CANCEL_PIN_CODE_SHOW);
context->authUiStateMgr->UpdateUiState(DmUiStateMsg::MSG_CANCEL_CONFIRM_SHOW);
context->timer->DeleteAll();
context->authMessageProcessor->CreateAndSendMsg(MSG_TYPE_AUTH_RESP_FINISH, context);
}
void DmAuthState::NotifyDeviceOnline(std::shared_ptr<DmAuthContext> context)
{
char deviceIdHash[DM_MAX_DEVICE_ID_LEN] = {0};
Crypto::GetUdidHash(context->accesser.deviceId, reinterpret_cast<uint8_t *>(deviceIdHash));
if (SoftbusCache::GetInstance().CheckIsOnline(std::string(deviceIdHash))) {
SetProcessInfo(context);
int32_t authForm = context->accessee.transmitBindType == DM_POINT_TO_POINT_TYPE ?
DmAuthForm::PEER_TO_PEER : context->accessee.transmitBindType;
#ifdef CAR_DEVICE_ENABLE
PeerDevInfo peerDevInfo;
peerDevInfo.deviceId = context->accesser.deviceId;
peerDevInfo.userId = context->accesser.userId;
peerDevInfo.accountId = context->accesser.accountId;
context->softbusConnector->HandleDeviceOnline(context->accesser.deviceId, authForm, peerDevInfo);
#else
context->softbusConnector->HandleDeviceOnline(context->accesser.deviceId, authForm);
#endif
}
}
std::string DmAuthState::GenerateBindResultContent(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_RETURN(context, "");
DmAccess access = context->direction == DmAuthDirection::DM_AUTH_SOURCE ?
context->accessee : context->accesser;
JsonObject jsonObj;
LOGE("networkId: %{public}s", GetAnonyString(access.networkId).c_str());
jsonObj[DM_BIND_RESULT_NETWORK_ID] = access.networkId;
if (access.deviceId.empty()) {
jsonObj[TAG_DEVICE_ID] = "";
} else {
char deviceIdHash[DM_MAX_DEVICE_ID_LEN] = {0};
Crypto::GetUdidHash(access.deviceId, reinterpret_cast<uint8_t *>(deviceIdHash));
jsonObj[TAG_DEVICE_ID] = deviceIdHash;
}
jsonObj[TAG_CONFIRM_OPERATION_V2] = context->confirmOperation;
if (context->remainingFrozenTime != 0) {
jsonObj[TAG_REMAINING_FROZEN_TIME] = context->remainingFrozenTime;
}
jsonObj[PARAM_KEY_IS_PROXY_BIND] = context->IsProxyBind;
LOGI("remainingFrozenTime: %{public}" PRId64, context->remainingFrozenTime);
std::string content = jsonObj.Dump();
return content;
}
bool DmAuthState::NeedReqUserConfirm(std::shared_ptr<DmAuthContext> context)
{
if (DmAuthState::IsImportAuthCodeCompatibility(context->authType)) {
return true;
}
DmAccess access = context->direction == DM_AUTH_SOURCE ? context->accesser : context->accessee;
if (access.isAuthed) {
return false;
}
return true;
}
bool DmAuthState::NeedAgreeAcl(std::shared_ptr<DmAuthContext> context)
{
if (context == nullptr) {
return true;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (context->direction == DM_AUTH_SOURCE) {
if (context->accesser.isUserLevelAuthed) {
LOGI("accesser user level authed");
return false;
}
if (!context->IsProxyBind || targetList.empty()) {
LOGI("accesser is authed");
return !context->accesser.isAuthed;
}
if (context->IsCallingProxyAsSubject && !context->accesser.isAuthed) {
LOGI("accesser is not authed");
return true;
}
return ProxyNeedAgreeAcl(context);
}
if (context->accessee.isUserLevelAuthed) {
LOGI("accessee user level authed");
return false;
}
if (!context->IsProxyBind || targetList.empty()) {
LOGI("accessee is authed");
return !context->accessee.isAuthed;
}
if (context->IsCallingProxyAsSubject && !context->accessee.isAuthed) {
LOGI("accessee is not authed");
return true;
}
return ProxyNeedAgreeAcl(context);
}
bool DmAuthState::ProxyNeedAgreeAcl(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_RETURN(context, ERR_DM_POINT_NULL);
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
return false;
}
if (context->direction == DM_AUTH_SOURCE) {
for (const auto &app : targetList) {
if (!app.proxyAccesser.isAuthed || app.IsNeedSetProxyRelationShip) {
return true;
}
}
return false;
}
for (const auto &app : targetList) {
if (!app.proxyAccessee.isAuthed || app.IsNeedSetProxyRelationShip) {
return true;
}
}
return false;
}
bool DmAuthState::GetReuseSkId(std::shared_ptr<DmAuthContext> context, int32_t &skId)
{
CHECK_NULL_RETURN(context, ERR_DM_POINT_NULL);
DistributedDeviceProfile::AccessControlProfile profile;
GetReuseACL(context, profile);
if (!profile.GetAccesser().GetAccesserCredentialIdStr().empty() &&
!profile.GetAccessee().GetAccesseeCredentialIdStr().empty()) {
if (context->direction == DM_AUTH_SOURCE) {
if (context->accesser.deviceId == profile.GetAccesser().GetAccesserDeviceId()) {
skId = profile.GetAccesser().GetAccesserSessionKeyId();
context->reUseCreId = profile.GetAccesser().GetAccesserCredentialIdStr();
context->accessee.deviceId = profile.GetAccessee().GetAccesseeDeviceId();
return true;
}
skId = profile.GetAccessee().GetAccesseeSessionKeyId();
context->reUseCreId = profile.GetAccessee().GetAccesseeCredentialIdStr();
context->accessee.deviceId = profile.GetAccesser().GetAccesserDeviceId();
return true;
}
if (context->accessee.deviceId == profile.GetAccessee().GetAccesseeDeviceId()) {
skId = profile.GetAccessee().GetAccesseeSessionKeyId();
context->reUseCreId = profile.GetAccessee().GetAccesseeCredentialIdStr();
context->accesser.deviceId = profile.GetAccesser().GetAccesserDeviceId();
return true;
}
skId = profile.GetAccesser().GetAccesserSessionKeyId();
context->reUseCreId = profile.GetAccesser().GetAccesserCredentialIdStr();
context->accesser.deviceId = profile.GetAccessee().GetAccesseeDeviceId();
return true;
}
return false;
}
void DmAuthState::GetReuseACL(std::shared_ptr<DmAuthContext> context,
DistributedDeviceProfile::AccessControlProfile &profile)
{
if (context == nullptr) {
return;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
return;
}
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
if (!access.aclTypeList.empty()) {
JsonObject aclTypeListJson;
aclTypeListJson.Parse(access.aclTypeList);
if (!aclTypeListJson.IsDiscarded() && aclTypeListJson.Contains("pointTopointAcl") &&
access.aclProfiles.find(DM_POINT_TO_POINT) != access.aclProfiles.end() &&
!access.aclProfiles[DM_POINT_TO_POINT].GetAccessee().GetAccesseeCredentialIdStr().empty() &&
!access.aclProfiles[DM_POINT_TO_POINT].GetAccesser().GetAccesserCredentialIdStr().empty()) {
profile = access.aclProfiles[DM_POINT_TO_POINT];
return;
}
}
for (auto &app : targetList) {
DmProxyAccess &proxyAccess = context->direction == DM_AUTH_SOURCE ? app.proxyAccesser : app.proxyAccessee;
JsonObject aclList;
if (!proxyAccess.aclTypeList.empty()) {
aclList.Parse(proxyAccess.aclTypeList);
}
if (!aclList.IsDiscarded() && aclList.Contains("pointTopointAcl") &&
proxyAccess.aclProfiles.find(DM_POINT_TO_POINT) != proxyAccess.aclProfiles.end() &&
!proxyAccess.aclProfiles[DM_POINT_TO_POINT].GetAccessee().GetAccesseeCredentialIdStr().empty() &&
!proxyAccess.aclProfiles[DM_POINT_TO_POINT].GetAccesser().GetAccesserCredentialIdStr().empty()) {
profile = proxyAccess.aclProfiles[DM_POINT_TO_POINT];
return;
}
}
}
bool DmAuthState::IsImportAuthCodeCompatibility(DmAuthType authType)
{
if (authType == DmAuthType::AUTH_TYPE_IMPORT_AUTH_CODE ||
authType == DmAuthType::AUTH_TYPE_NFC) {
return true;
}
return false;
}
void DmAuthState::SetAclExtraInfo(std::shared_ptr<DmAuthContext> context)
{
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
DmAccess &remoteAccess = (context->direction == DM_AUTH_SOURCE) ? context->accessee : context->accesser;
JsonObject jsonObj;
jsonObj[TAG_DMVERSION] = access.dmVersion;
access.extraInfo = jsonObj.Dump();
remoteAccess.extraInfo = jsonObj.Dump();
}
void DmAuthState::SetAclInfo(std::shared_ptr<DmAuthContext> context)
{
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
DmAccess &remoteAccess = (context->direction == DM_AUTH_SOURCE) ? context->accessee : context->accesser;
SetAclExtraInfo(context);
access.lnnBindType = GetAclBindType(context, access.lnnCredentialId);
remoteAccess.lnnBindType = GetAclBindType(context, remoteAccess.lnnCredentialId);
access.transmitBindType = GetAclBindType(context, access.transmitCredentialId);
remoteAccess.transmitBindType = GetAclBindType(context, remoteAccess.transmitCredentialId);
}
int32_t DmAuthState::GetAclBindType(std::shared_ptr<DmAuthContext> context, std::string credId)
{
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
JsonObject result;
int32_t ret = context->hiChainAuthConnector->QueryCredInfoByCredId(access.userId, credId, result);
if (ret != DM_OK) {
LOGE("QueryCredInfoByCredId failed, ret: %{public}d.", ret);
return DM_UNKNOWN_TYPE;
}
if (!result.Contains(credId)) {
LOGE("result not contains credId.");
return DM_UNKNOWN_TYPE;
}
if (!result[credId].Contains(FILED_CRED_TYPE) ||
!result[credId][FILED_CRED_TYPE].IsNumberInteger()) {
LOGE("credType is invalid.");
return DM_UNKNOWN_TYPE;
}
int32_t credType = result[credId][FILED_CRED_TYPE].Get<int32_t>();
if (credType == DM_AUTH_CREDENTIAL_ACCOUNT_RELATED) {
return DM_SAME_ACCOUNT_TYPE;
}
if (credType == DM_AUTH_CREDENTIAL_ACCOUNT_UNRELATED) {
return DM_POINT_TO_POINT_TYPE;
}
if (credType == DM_AUTH_CREDENTIAL_ACCOUNT_ACROSS) {
return DM_SHARE;
}
return DM_UNKNOWN_TYPE;
}
bool DmAuthState::ValidateCredInfoStructure(const JsonItemObject &credInfo)
{
if (!credInfo.Contains(FILED_CRED_TYPE) || !credInfo[FILED_CRED_TYPE].IsNumberInteger() ||
!credInfo.Contains(FILED_AUTHORIZED_SCOPE) || !credInfo[FILED_AUTHORIZED_SCOPE].IsNumberInteger() ||
!credInfo.Contains(FILED_SUBJECT) || !credInfo[FILED_SUBJECT].IsNumberInteger()) {
LOGE("credType or authorizedScope or subject invalid.");
return false;
}
return true;
}
uint32_t DmAuthState::GetCredType(std::shared_ptr<DmAuthContext> context, const JsonItemObject &credInfo)
{
CHECK_NULL_RETURN(context, DM_INVALIED_TYPE);
if (!ValidateCredInfoStructure(credInfo)) {
return DM_INVALIED_TYPE;
}
int32_t credType = credInfo[FILED_CRED_TYPE].Get<int32_t>();
int32_t authorizedScope = credInfo[FILED_AUTHORIZED_SCOPE].Get<int32_t>();
int32_t subject = credInfo[FILED_SUBJECT].Get<int32_t>();
std::vector<std::string> appList;
credInfo[FILED_AUTHORIZED_APP_LIST].Get(appList);
if (credType == ACCOUNT_RELATED && authorizedScope == SCOPE_USER) {
return DM_IDENTICAL_ACCOUNT;
}
if (credType == ACCOUNT_ACROSS && authorizedScope == SCOPE_USER &&
context->direction == DM_AUTH_SOURCE && subject == SUBJECT_PRIMARY) {
return DM_SHARE;
}
if (credType == ACCOUNT_ACROSS && authorizedScope == SCOPE_USER &&
context->direction == DM_AUTH_SINK && subject == SUBJECT_SECONDARY) {
return DM_SHARE;
}
if (credType == ACCOUNT_UNRELATED && (authorizedScope == SCOPE_APP || authorizedScope == SCOPE_USER)) {
std::vector<std::string> tokenIdHashList;
for (std::string tokenId : appList) {
tokenIdHashList.push_back(Crypto::GetTokenIdHash(tokenId));
}
GetProxyCredInfo(context, credInfo, tokenIdHashList);
if (HaveSameTokenId(context, tokenIdHashList)) {
return DM_POINT_TO_POINT;
}
}
if (credType == ACCOUNT_UNRELATED && authorizedScope == SCOPE_USER && appList.empty()) {
return DM_LNN;
}
return DM_INVALIED_TYPE;
}
int32_t DmAuthState::GetProxyCredInfo(std::shared_ptr<DmAuthContext> context, const JsonItemObject &credInfo,
const std::vector<std::string> &tokenIdHashList)
{
CHECK_NULL_RETURN(context, ERR_DM_POINT_NULL);
if (!context->IsProxyBind) {
return DM_OK;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (targetList.empty()) {
return ERR_DM_INPUT_PARA_INVALID;
}
if (!credInfo.Contains(FILED_CRED_ID) || !credInfo[FILED_CRED_ID].IsString()) {
return static_cast<int32_t>(DM_INVALIED_TYPE);
}
for (auto &app : targetList) {
if (std::find(tokenIdHashList.begin(), tokenIdHashList.end(), app.proxyAccesser.tokenIdHash)
!= tokenIdHashList.end() &&
std::find(tokenIdHashList.begin(), tokenIdHashList.end(), app.proxyAccessee.tokenIdHash)
!= tokenIdHashList.end()) {
JsonObject appCredInfo(credInfo.Dump());
appCredInfo[FILED_CRED_TYPE] = DM_POINT_TO_POINT;
JsonObject credInfoJson;
std::string credInfoJsonStr = context->direction == DM_AUTH_SOURCE ? app.proxyAccesser.credInfoJson :
app.proxyAccessee.credInfoJson;
if (!credInfoJsonStr.empty()) {
credInfoJson.Parse(credInfoJsonStr);
}
credInfoJson.Insert(credInfo[FILED_CRED_ID].Get<std::string>(), appCredInfo);
if (context->direction == DM_AUTH_SOURCE) {
app.proxyAccesser.credInfoJson = credInfoJson.Dump();
} else {
app.proxyAccessee.credInfoJson = credInfoJson.Dump();
}
}
}
return DM_OK;
}
uint32_t DmAuthState::GetCredentialType(std::shared_ptr<DmAuthContext> context, const JsonItemObject &credInfo)
{
CHECK_NULL_RETURN(context, DM_INVALIED_TYPE);
if (!ValidateCredInfoStructure(credInfo)) {
return DM_INVALIED_TYPE;
}
return GetCredType(context, credInfo);
}
bool DmAuthState::HaveSameTokenId(std::shared_ptr<DmAuthContext> context,
const std::vector<std::string> &tokenIdHashList)
{
if (tokenIdHashList.size() < 2) {
LOGE("invalid tokenList size.");
return false;
}
return std::find(tokenIdHashList.begin(), tokenIdHashList.end(),
context->accesser.tokenIdHash) != tokenIdHashList.end() &&
std::find(tokenIdHashList.begin(), tokenIdHashList.end(),
context->accessee.tokenIdHash) != tokenIdHashList.end();
}
int32_t DmAuthState::GetOutputState(int32_t state)
{
LOGI("state %{public}d.", state);
auto it = NEW_AND_OLD_STATE_MAPPING.find(static_cast<DmAuthStateType>(state));
if (it != NEW_AND_OLD_STATE_MAPPING.end()) {
return static_cast<int32_t>(it->second);
}
return static_cast<int32_t>(STATUS_DM_AUTH_DEFAULT);
}
int32_t DmAuthState::GetOutputReplay(const std::string &processName, int32_t replay)
{
LOGI("replay %{public}d.", replay);
bool needMapFlag = false;
for (uint16_t index = 0; index < ONBINDRESULT_MAPPING_NUM; ++index) {
if (std::string(ONBINDRESULT_MAPPING_LIST[index]) == processName) {
LOGI("processName %{public}s new protocol param convert to old protocol param.", processName.c_str());
needMapFlag = true;
break;
}
}
if (needMapFlag) {
auto it = NEW_AND_OLD_REPLAY_MAPPING.find(replay);
if (it != NEW_AND_OLD_REPLAY_MAPPING.end()) {
return static_cast<int32_t>(it->second);
}
}
return replay;
}
uint64_t DmAuthState::GetSysTimeMs()
{
struct timeval time;
time.tv_sec = 0;
time.tv_usec = 0;
int32_t retryNum = 0;
while (retryNum < GET_SYSTEMTIME_MAX_NUM) {
if (gettimeofday(&time, nullptr) != 0) {
retryNum++;
LOGE("failed. retryNum: %{public}d", retryNum);
continue;
}
return (uint64_t) time.tv_sec * MS_PER_SECOND + (uint64_t)time.tv_usec / US_PER_MSECOND;
}
return 0;
}
void DmAuthState::DeleteAcl(std::shared_ptr<DmAuthContext> context,
const DistributedDeviceProfile::AccessControlProfile &profile)
{
CHECK_NULL_VOID(context);
LOGI("direction %{public}d.", static_cast<int32_t>(context->direction));
CHECK_NULL_VOID(context->authMessageProcessor);
CHECK_NULL_VOID(context->hiChainAuthConnector);
DmAccess &access = context->direction == DmAuthDirection::DM_AUTH_SOURCE ? context->accesser : context->accessee;
int32_t userId = access.userId;
int32_t sessionKeyId = access.deviceId == profile.GetAccesser().GetAccesserDeviceId() ?
profile.GetAccesser().GetAccesserSessionKeyId() : profile.GetAccessee().GetAccesseeSessionKeyId();
std::string credId = access.deviceId == profile.GetAccesser().GetAccesserDeviceId() ?
profile.GetAccesser().GetAccesserCredentialIdStr() : profile.GetAccessee().GetAccesseeCredentialIdStr();
context->authMessageProcessor->DeleteSessionKeyToDP(userId, sessionKeyId);
JsonObject credJson;
context->hiChainAuthConnector->QueryCredInfoByCredId(userId, credId, credJson);
if (credJson.Contains(credId)) {
DeleteCredential(context, userId, credJson[credId], profile);
}
DeviceProfileConnector::GetInstance().DeleteAccessControlById(profile.GetAccessControlId());
}
void DmAuthState::DeleteRedundancyAcl(std::shared_ptr<DmAuthContext> context, JsonObject &aclInfo,
const std::set<uint32_t> bindLevelSet, bool isSrc)
{
CHECK_NULL_VOID(context);
DmAccess access = isSrc ? context->accesser : context->accessee;
if (bindLevelSet.empty()) {
LOGE("empty set");
return;
}
if (aclInfo.Contains("pointTopointAcl") && !aclInfo.Contains("lnnAcl") &&
bindLevelSet.find(USER) == bindLevelSet.end() && !context->isServiceBind) {
aclInfo.Erase("pointTopointAcl");
if (access.aclProfiles.find(DM_POINT_TO_POINT) != access.aclProfiles.end()) {
DeleteAcl(context, access.aclProfiles[DM_POINT_TO_POINT]);
}
}
if (!aclInfo.Contains("pointTopointAcl") && aclInfo.Contains("lnnAcl")) {
aclInfo.Erase("lnnAcl");
if (access.aclProfiles.find(DM_LNN) != access.aclProfiles.end()) {
DeleteAcl(context, access.aclProfiles[DM_LNN]);
}
}
}
void DmAuthState::SetProcessInfo(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_VOID(context);
DmAccess localAccess = context->direction == DmAuthDirection::DM_AUTH_SOURCE ?
context->accesser : context->accessee;
std::vector<ProcessInfo> processInfoVec;
ProcessInfo processInfo;
processInfo.userId = localAccess.userId;
uint32_t bindLevel = static_cast<uint32_t>(localAccess.bindLevel);
if (bindLevel == APP || bindLevel == SERVICE) {
processInfo.pkgName = localAccess.pkgName;
processInfo.tokenId = static_cast<uint32_t>(localAccess.tokenId);
} else if (bindLevel == USER) {
processInfo.pkgName = std::string(DM_PKG_NAME);
} else {
LOGE("bindlevel error %{public}d.", bindLevel);
return;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
processInfoVec.push_back(processInfo);
if (context->IsProxyBind && !targetList.empty()) {
for (auto &app : targetList) {
ProcessInfo processInfo;
processInfo.userId = localAccess.userId;
processInfo.pkgName = context->GetAclBundleName(context->direction, app);
processInfoVec.push_back(processInfo);
}
}
context->softbusConnector->SetProcessInfoVec(processInfoVec);
}
void DmAuthState::FilterProfilesByContext(
std::vector<DistributedDeviceProfile::AccessControlProfile> &profiles, std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_VOID(context);
std::vector<DistributedDeviceProfile::AccessControlProfile> aclProfilesVec;
for (auto &item : profiles) {
std::string accesserDeviceIdHash = Crypto::GetUdidHash(item.GetAccesser().GetAccesserDeviceId());
std::string accesseeDeviceIdHash = Crypto::GetUdidHash(item.GetAccessee().GetAccesseeDeviceId());
std::string accesserAccountId = item.GetAccesser().GetAccesserAccountId();
std::string accesseeAccountId = item.GetAccessee().GetAccesseeAccountId();
bool isAccesserCar = (context->accesser.deviceType == static_cast<int32_t>(DmDeviceType::DEVICE_TYPE_CAR));
bool isAccesseeCar = (context->accessee.deviceType == static_cast<int32_t>(DmDeviceType::DEVICE_TYPE_CAR));
bool forwardDirectAccountIdMatch = true;
bool reverseDirectAccountIdMatch = true;
if (isAccesserCar) {
forwardDirectAccountIdMatch = (context->accesser.accountIdHash ==
Crypto::GetAccountIdHash16(accesserAccountId));
reverseDirectAccountIdMatch = (context->accesser.accountIdHash ==
Crypto::GetAccountIdHash16(accesseeAccountId));
}
if (isAccesseeCar) {
forwardDirectAccountIdMatch = forwardDirectAccountIdMatch &&
(context->accessee.accountIdHash == Crypto::GetAccountIdHash16(accesseeAccountId));
reverseDirectAccountIdMatch = reverseDirectAccountIdMatch &&
(context->accessee.accountIdHash == Crypto::GetAccountIdHash16(accesserAccountId));
}
if ((context->accesser.deviceIdHash == accesserDeviceIdHash &&
context->accessee.deviceIdHash == accesseeDeviceIdHash &&
context->accesser.userId == item.GetAccesser().GetAccesserUserId() &&
context->accessee.userId == item.GetAccessee().GetAccesseeUserId() &&
forwardDirectAccountIdMatch) ||
(context->accessee.deviceIdHash == accesserDeviceIdHash &&
context->accesser.deviceIdHash == accesseeDeviceIdHash &&
context->accessee.userId == item.GetAccesser().GetAccesserUserId() &&
context->accesser.userId == item.GetAccessee().GetAccesseeUserId() &&
reverseDirectAccountIdMatch)) {
if (item.GetStatus() == INACTIVE) {
item.SetStatus(ACTIVE);
DeviceProfileConnector::GetInstance().UpdateAclStatus(item);
}
aclProfilesVec.push_back(item);
}
}
profiles.clear();
profiles.assign(aclProfilesVec.begin(), aclProfilesVec.end());
}
bool DmAuthState::GetSessionKey(std::shared_ptr<DmAuthContext> context)
{
int32_t skId = 0;
if (!GetReuseSkId(context, skId)) {
return false;
}
int32_t userId = context->direction == DM_AUTH_SOURCE ? context->accesser.userId : context->accessee.userId;
return context->authMessageProcessor->GetSessionKey(userId, skId) == DM_OK;
}
bool DmAuthState::IsAclHasCredential(const DistributedDeviceProfile::AccessControlProfile &profile,
const std::string &credInfoJson, std::string &credId)
{
JsonObject credInfoJsonObj;
if (!credInfoJson.empty()) {
credInfoJsonObj.Parse(credInfoJson);
}
credId = profile.GetAccesser().GetAccesserCredentialIdStr();
if (credInfoJsonObj.Contains(credId)) {
return true;
}
credId = profile.GetAccessee().GetAccesseeCredentialIdStr();
if (credInfoJsonObj.Contains(credId)) {
return true;
}
return false;
}
void DmAuthState::UpdateCredInfo(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_VOID(context);
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty() || context->reUseCreId.empty()) {
return;
}
std::vector<std::string> tokenIds;
bool isAuthed = context->direction == DM_AUTH_SOURCE ? context->accesser.isAuthed : context->accessee.isAuthed;
if (context->IsCallingProxyAsSubject && !isAuthed) {
tokenIds.push_back(std::to_string(context->accesser.tokenId));
tokenIds.push_back(std::to_string(context->accessee.tokenId));
}
for (auto &app : targetList) {
if (context->direction == DM_AUTH_SOURCE ? app.proxyAccesser.isAuthed : app.proxyAccessee.isAuthed) {
continue;
}
tokenIds.push_back(std::to_string(app.proxyAccesser.tokenId));
tokenIds.push_back(std::to_string(app.proxyAccessee.tokenId));
}
if (tokenIds.empty()) {
return;
}
context->hiChainAuthConnector->AddTokensToCredential(context->reUseCreId, context->direction == DM_AUTH_SOURCE ?
context->accesser.userId : context->accessee.userId, tokenIds);
}
bool DmAuthState::IsNeedBind(std::shared_ptr<DmAuthContext> context)
{
if (context == nullptr) {
return true;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
LOGI("no proxy");
return context->needBind;
}
if (context->authType == DmAuthType::AUTH_TYPE_IMPORT_AUTH_CODE) {
LOGI("authType is import pin code");
return true;
}
if (context->needBind && context->needAgreeCredential && context->IsCallingProxyAsSubject) {
LOGI("subject need bind");
return context->needBind;
}
for (const auto &app : targetList) {
if (app.needBind || app.IsNeedSetProxyRelationShip) {
LOGI("proxy need bind");
return true;
}
}
return false;
}
bool DmAuthState::IsNeedAgreeCredential(std::shared_ptr<DmAuthContext> context)
{
if (context == nullptr) {
return true;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
LOGI("no proxy");
return context->needAgreeCredential;
}
if (!context->needAgreeCredential) {
LOGI("subject not need agree credential");
return context->needAgreeCredential;
}
for (const auto &app : targetList) {
if (!app.needAgreeCredential) {
LOGI("proxy not need agree credential");
return app.needAgreeCredential;
}
}
return true;
}
bool DmAuthState::IsNeedAuth(std::shared_ptr<DmAuthContext> context)
{
if (context == nullptr) {
return true;
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
LOGI("no proxy");
return context->needAuth;
}
if (!context->needAuth) {
LOGI("subject not need auth");
return context->needAuth;
}
for (const auto &app : targetList) {
if (!app.needAuth) {
LOGI("proxy not need auth");
return app.needAuth;
}
}
return true;
}
void DmAuthState::DeleteCredential(std::shared_ptr<DmAuthContext> context, int32_t userId,
const JsonItemObject &credInfo, const DistributedDeviceProfile::AccessControlProfile &profile)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->hiChainAuthConnector);
if (!credInfo.Contains(FILED_CRED_ID) || !credInfo[FILED_CRED_ID].IsString()) {
return;
}
if (!credInfo.Contains(FILED_AUTHORIZED_APP_LIST)) {
context->hiChainAuthConnector->DeleteCredential(userId, credInfo[FILED_CRED_ID].Get<std::string>());
return;
}
std::vector<std::string> appList;
credInfo[FILED_AUTHORIZED_APP_LIST].Get(appList);
auto erIt = std::find(appList.begin(), appList.end(), std::to_string(profile.GetAccesser().GetAccesserTokenId()));
if (erIt != appList.end()) {
appList.erase(erIt);
}
auto eeIt = std::find(appList.begin(), appList.end(), std::to_string(profile.GetAccessee().GetAccesseeTokenId()));
if (eeIt != appList.end()) {
appList.erase(eeIt);
}
if (appList.size() == 0) {
context->hiChainAuthConnector->DeleteCredential(userId, credInfo[FILED_CRED_ID].Get<std::string>());
return;
}
context->hiChainAuthConnector->UpdateCredential(credInfo[FILED_CRED_ID].Get<std::string>(), userId, appList);
}
void DmAuthState::DirectlyDeleteCredential(std::shared_ptr<DmAuthContext> context, int32_t userId,
const JsonItemObject &credInfo)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->hiChainAuthConnector);
if (!credInfo.Contains(FILED_CRED_ID) || !credInfo[FILED_CRED_ID].IsString()) {
return;
}
context->hiChainAuthConnector->DeleteCredential(userId, credInfo[FILED_CRED_ID].Get<std::string>());
}
void DmAuthState::DeleteAclAndSk(std::shared_ptr<DmAuthContext> context,
const DistributedDeviceProfile::AccessControlProfile &profile)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->authMessageProcessor);
DmAccess &access = context->direction == DmAuthDirection::DM_AUTH_SOURCE ? context->accesser : context->accessee;
int32_t userId = access.userId;
int32_t sessionKeyId = access.deviceId == profile.GetAccesser().GetAccesserDeviceId() ?
profile.GetAccesser().GetAccesserSessionKeyId() : profile.GetAccessee().GetAccesseeSessionKeyId();
context->authMessageProcessor->DeleteSessionKeyToDP(userId, sessionKeyId);
DeviceProfileConnector::GetInstance().DeleteAccessControlById(profile.GetAccessControlId());
}
void DmAuthState::GetPeerDeviceId(std::shared_ptr<DmAuthContext> context, std::string &peerDeviceId)
{
CHECK_NULL_VOID(context);
if (context->accesser.aclProfiles.find(DM_IDENTICAL_ACCOUNT) != context->accesser.aclProfiles.end()) {
peerDeviceId = context->accesser.aclProfiles[DM_IDENTICAL_ACCOUNT].GetAccessee().GetAccesseeDeviceId();
if (!peerDeviceId.empty()) {
return;
}
}
if (context->accesser.aclProfiles.find(DM_SHARE) != context->accesser.aclProfiles.end()) {
peerDeviceId = context->accesser.aclProfiles[DM_SHARE].GetAccessee().GetAccesseeDeviceId();
if (peerDeviceId == context->accesser.deviceId) {
peerDeviceId = context->accesser.aclProfiles[DM_SHARE].GetAccesser().GetAccesserDeviceId();
}
if (!peerDeviceId.empty()) {
return;
}
}
if (context->accesser.aclProfiles.find(DM_POINT_TO_POINT) != context->accesser.aclProfiles.end()) {
peerDeviceId = context->accesser.aclProfiles[DM_POINT_TO_POINT].GetAccessee().GetAccesseeDeviceId();
if (peerDeviceId == context->accesser.deviceId) {
peerDeviceId = context->accesser.aclProfiles[DM_POINT_TO_POINT].GetAccesser().GetAccesserDeviceId();
}
if (!peerDeviceId.empty()) {
return;
}
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (!context->IsProxyBind || targetList.empty()) {
return;
}
for (auto &app : targetList) {
if (app.proxyAccesser.aclProfiles.find(DM_POINT_TO_POINT) != app.proxyAccesser.aclProfiles.end()) {
peerDeviceId = app.proxyAccesser.aclProfiles[DM_POINT_TO_POINT].GetAccessee().GetAccesseeDeviceId();
if (peerDeviceId == context->accesser.deviceId) {
peerDeviceId = app.proxyAccesser.aclProfiles[DM_POINT_TO_POINT].GetAccesser().GetAccesserDeviceId();
}
if (!peerDeviceId.empty()) {
return;
}
}
}
LOGE("peerDeviceId is empty.");
}
bool DmAuthState::IsMatchCredentialAndP2pACL(JsonObject &credInfo, std::string &credId,
const DistributedDeviceProfile::AccessControlProfile &profile)
{
LOGI("1:%{public}d, 2:%{public}d, 3:%{public}d",
credInfo.Contains(credId),
credInfo[credId].Contains(FILED_AUTHORIZED_SCOPE),
credInfo[credId][FILED_AUTHORIZED_SCOPE].IsNumberInteger());
LOGI("credId %{public}s contain credInfoJson.", credId.c_str());
if (!credInfo.Contains(credId) || !credInfo[credId].Contains(FILED_AUTHORIZED_SCOPE) ||
!credInfo[credId][FILED_AUTHORIZED_SCOPE].IsNumberInteger()) {
return false;
}
int32_t authorizedScope = credInfo[credId][FILED_AUTHORIZED_SCOPE].Get<int32_t>();
LOGI("authorizedScope:%{public}d, DM_AUTH_SCOPE_USER:%{public}d,"
"GetBindLevel:%{public}d",
authorizedScope,
static_cast<int32_t>(DM_AUTH_SCOPE_USER), profile.GetBindLevel());
if (authorizedScope == static_cast<int32_t>(DM_AUTH_SCOPE_USER) && profile.GetBindLevel() == USER) {
return true;
}
if (authorizedScope == static_cast<int32_t>(DM_AUTH_SCOPE_APP) &&
(profile.GetBindLevel() == SERVICE || profile.GetBindLevel() == APP)) {
return true;
}
return false;
}
void DmAuthState::BindFail(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->hiChainAuthConnector);
if (context->reason == DM_BIND_TRUST_TARGET) {
return;
}
bool isDelLnnAcl = false;
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
if (access.isGeneratedLnnCredThisBind) {
if (!access.lnnCredentialId.empty()) {
context->hiChainAuthConnector->DeleteCredential(access.userId, access.lnnCredentialId);
}
if (access.lnnSessionKeyId != 0) {
DeviceProfileConnector::GetInstance().DeleteSessionKey(access.userId, access.lnnSessionKeyId);
}
isDelLnnAcl = true;
}
std::vector<std::pair<int64_t, int64_t>> tokenIds;
if (!access.isAuthed && access.transmitSessionKeyId != 0) {
DeviceProfileConnector::GetInstance().DeleteSessionKey(access.userId, access.transmitSessionKeyId);
tokenIds.push_back(std::make_pair(context->accesser.tokenId, context->accessee.tokenId));
}
auto &targetList = context->isServiceBind ? context->subjectServiceOnes : context->subjectProxyOnes;
if (context->IsProxyBind && !targetList.empty()) {
for (auto &app : targetList) {
DmProxyAccess &proxyAccess = context->direction == DM_AUTH_SOURCE ? app.proxyAccesser : app.proxyAccessee;
if (proxyAccess.isAuthed || proxyAccess.transmitSessionKeyId == 0) {
continue;
}
DeviceProfileConnector::GetInstance().DeleteSessionKey(access.userId, proxyAccess.transmitSessionKeyId);
tokenIds.push_back(std::make_pair(app.proxyAccesser.tokenId, app.proxyAccessee.tokenId));
}
}
if (access.isGeneratedTransmitThisBind && !access.transmitCredentialId.empty()) {
context->hiChainAuthConnector->DeleteCredential(access.userId, access.transmitCredentialId);
} else if (!context->reUseCreId.empty()) {
RemoveTokenIdsFromCredential(context, context->reUseCreId, tokenIds);
} else {
LOGE("no credential");
}
DeleteAcl(context, isDelLnnAcl, tokenIds);
}
void DmAuthState::DeleteAcl(std::shared_ptr<DmAuthContext> context, bool isDelLnnAcl,
std::vector<std::pair<int64_t, int64_t>> &tokenIds)
{
CHECK_NULL_VOID(context);
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
DmAccess &remoteAccess = (context->direction == DM_AUTH_SOURCE) ? context->accessee : context->accesser;
if (remoteAccess.deviceId.empty()) {
return;
}
if (!isDelLnnAcl && tokenIds.empty()) {
return;
}
std::vector<DistributedDeviceProfile::AccessControlProfile> acls =
DeviceProfileConnector::GetInstance().GetAclList(access.deviceId, access.userId,
remoteAccess.deviceId, remoteAccess.userId);
for (DistributedDeviceProfile::AccessControlProfile acl : acls) {
if (isDelLnnAcl && DeviceProfileConnector::GetInstance().IsLnnAcl(acl)) {
DeviceProfileConnector::GetInstance().DeleteAccessControlById(acl.GetAccessControlId());
continue;
}
auto it = std::find(tokenIds.begin(), tokenIds.end(),
std::make_pair(acl.GetAccesser().GetAccesserTokenId(), acl.GetAccessee().GetAccesseeTokenId()));
if (it != tokenIds.end()) {
DeviceProfileConnector::GetInstance().DeleteAccessControlById(acl.GetAccessControlId());
continue;
}
}
}
void DmAuthState::RemoveTokenIdsFromCredential(std::shared_ptr<DmAuthContext> context, const std::string &credId,
std::vector<std::pair<int64_t, int64_t>> &tokenIds)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->hiChainAuthConnector);
DmAccess &access = (context->direction == DM_AUTH_SOURCE) ? context->accesser : context->accessee;
JsonObject credJson;
context->hiChainAuthConnector->QueryCredInfoByCredId(access.userId, credId, credJson);
if (!credJson.Contains(credId)) {
LOGE("query cred failed");
return;
}
if (!credJson[credId].Contains(FILED_AUTHORIZED_APP_LIST)) {
LOGE("applist is empty");
context->hiChainAuthConnector->DeleteCredential(access.userId, credId);
return;
}
std::vector<std::string> appList;
credJson[credId][FILED_AUTHORIZED_APP_LIST].Get(appList);
for (const auto& it : tokenIds) {
auto erIt = std::find(appList.begin(), appList.end(), std::to_string(it.first));
if (erIt != appList.end()) {
appList.erase(erIt);
}
auto eeIt = std::find(appList.begin(), appList.end(), std::to_string(it.second));
if (eeIt != appList.end()) {
appList.erase(eeIt);
}
}
if (appList.size() == 0) {
LOGE("applist is empty, delete credential");
context->hiChainAuthConnector->DeleteCredential(access.userId, credId);
return;
}
context->hiChainAuthConnector->UpdateCredential(credId, access.userId, appList);
}
void DmAuthState::JoinLnn(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->softbusConnector);
bool isForceJoin = false;
if (!context->accesser.isOnline) {
LOGI("The remote device is offline.");
isForceJoin = true;
}
if (context->connSessionType == CONN_SESSION_TYPE_HML || context->isServiceBind) {
context->softbusConnector->JoinLnnByHml(context->sessionId, context->accesser.transmitSessionKeyId,
context->accessee.transmitSessionKeyId, isForceJoin);
} else {
char udidHashTmp[DM_MAX_DEVICE_ID_LEN] = {0};
if (Crypto::GetUdidHash(context->accessee.deviceId, reinterpret_cast<uint8_t*>(udidHashTmp)) == DM_OK) {
std::string peerUdidHash = std::string(udidHashTmp);
context->softbusConnector->JoinLNNBySkId(context->sessionId, context->accesser.transmitSessionKeyId,
context->accessee.transmitSessionKeyId, context->accessee.addr, peerUdidHash, isForceJoin);
}
}
}
void DmAuthState::UpdatePinErrorCount(const std::string &pkgName, int32_t pinExchangeType)
{
DistributedDeviceProfile::LocalServiceInfo srvInfo;
int32_t dpRet = DeviceProfileConnector::GetInstance().GetLocalServiceInfoByBundleNameAndPinExchangeType(
pkgName, pinExchangeType, srvInfo);
if (dpRet != DM_OK) {
LOGE("GetLocalServiceInfoByBundleNameAndPinExchangeType failed ret=%{public}d", dpRet);
return;
}
std::string extra = srvInfo.GetExtraInfo();
if (extra.empty()) {
LOGE("extra is empty");
return;
}
JsonObject extraInfoObj;
extraInfoObj.Parse(extra);
if (extraInfoObj.IsDiscarded()) {
LOGE("parse extra discarded, skip update to protect original data");
return;
}
int32_t count = 0;
if (!extraInfoObj.IsDiscarded() && IsInt32(extraInfoObj, PIN_ERROR_COUNT)) {
count = extraInfoObj[PIN_ERROR_COUNT].Get<int32_t>();
}
extraInfoObj[PIN_ERROR_COUNT] = ++count;
srvInfo.SetExtraInfo(extraInfoObj.Dump());
int32_t updateRet = DeviceProfileConnector::GetInstance().UpdateLocalServiceInfo(srvInfo);
if (updateRet != DM_OK) {
LOGE("UpdateLocalServiceInfo failed ret=%{public}d", updateRet);
}
}
void DmAuthState::HandlePinResultAndCallback(std::shared_ptr<DmAuthContext> context, const std::string &pkgName)
{
CHECK_NULL_VOID(context);
int32_t count = 0;
uint64_t tokenId = 0;
DmAuthState::GetPinErrorCountAndTokenId(pkgName, context->authType, count, tokenId);
if (context->reason == DM_OK) {
if (context->stopTimerAndDelDpCallback) {
context->stopTimerAndDelDpCallback(pkgName, context->authType, tokenId);
}
return;
}
DmAuthState::UpdatePinErrorCount(pkgName, context->authType);
++count;
if (count >= PIN_CODE_COUNT_MAX_NUM) {
if (context->stopTimerAndDelDpCallback) {
context->stopTimerAndDelDpCallback(pkgName, context->authType, tokenId);
}
if (context->listener != nullptr) {
context->listener->OnAuthCodeInvalid(context->accessee.pkgName, "");
}
}
}
void DmAuthState::GetPinErrorCountAndTokenId(const std::string &bundleName, int32_t pinExchangeType,
int32_t &count, uint64_t &tokenId)
{
DistributedDeviceProfile::LocalServiceInfo srvInfo;
JsonObject extraInfoObj;
if (!GetServiceExtraInfo(bundleName, pinExchangeType, srvInfo, extraInfoObj)) {
LOGE("load extra info failed, use default values");
return;
}
if (IsInt32(extraInfoObj, PIN_ERROR_COUNT)) {
count = extraInfoObj[PIN_ERROR_COUNT].Get<int32_t>();
}
if (IsUint64(extraInfoObj, TAG_TOKENID)) {
tokenId = extraInfoObj[TAG_TOKENID].Get<uint64_t>();
}
}
bool DmAuthState::VerifyFlagXor(std::shared_ptr<DmAuthContext> context)
{
CHECK_NULL_RETURN(context, false);
if (context->ncmBindTarget && context->accesser.bundleName == BUNDLE_NAME_COLLABORATION_FWK) {
LOGE("ncmBindTarget not need check flag");
return true;
}
if (IsInFlagWhiteList(context->accesser.bundleName)) {
LOGE("bundleName %{public}s is in white list, not need check flag", context->accesser.bundleName.c_str());
return true;
}
DistributedDeviceProfile::LocalServiceInfo srvInfo;
JsonObject extraInfoObj;
DmAccess accessSide;
std::string pkgName = "";
if (context->direction == DM_AUTH_SOURCE) {
accessSide = context->accesser;
pkgName = accessSide.pkgName;
} else {
accessSide = context->accessee;
pkgName = accessSide.pkgName;
if (PKGNAME_MAPPING.find(pkgName) != PKGNAME_MAPPING.end()) {
pkgName = PKGNAME_MAPPING.at(pkgName);
}
}
if (!GetServiceExtraInfo(pkgName, context->authType, srvInfo, extraInfoObj)) {
LOGE("load extra failed");
return false;
}
bool localFlag = false;
bool remoteFlag = context->pinCodeFlag;
if (IsBool(extraInfoObj, PIN_MATCH_FLAG)) {
localFlag = extraInfoObj[PIN_MATCH_FLAG].Get<bool>();
}
return remoteFlag ^ localFlag;
}
bool DmAuthState::GetServiceExtraInfo(const std::string &pkgName, int32_t pinExchangeType,
DistributedDeviceProfile::LocalServiceInfo &srvInfo, JsonObject &extraInfoObj)
{
auto dpRet = DeviceProfileConnector::GetInstance().GetLocalServiceInfoByBundleNameAndPinExchangeType(
pkgName, pinExchangeType, srvInfo);
if (dpRet != DM_OK) {
LOGE("GetLocalServiceInfoByBundleNameAndPinExchangeType failed ret=%{public}d", dpRet);
return false;
}
std::string extra = srvInfo.GetExtraInfo();
if (extra.empty()) {
LOGE("extra.empty()");
return false;
}
extraInfoObj.Parse(extra);
if (extraInfoObj.IsDiscarded()) {
LOGE("parse extra discarded");
return false;
}
return true;
}
bool DmAuthState::IsInFlagWhiteList(const std::string &bundleName)
{
if (bundleName.empty()) {
LOGE("bundleName is empty");
return false;
}
uint16_t index = 0;
for (; index < FLAG_WHITE_LIST_NUM; ++index) {
std::string tmp = FLAG_WHITE_LIST[index];
if (bundleName == tmp) {
return true;
}
}
return false;
}
void DmAuthState::DeleteInvalidCredAndAcl(std::shared_ptr<DmAuthContext> context)
{
LOGI("start");
CHECK_NULL_VOID(context);
int32_t currentUserId = (context->direction == DM_AUTH_SOURCE) ?
context->accesser.userId : context->accessee.userId;
char localDeviceId[DEVICE_UUID_LENGTH] = {0};
GetDevUdid(localDeviceId, DEVICE_UUID_LENGTH);
std::string localUdid = std::string(localDeviceId);
std::vector<DistributedDeviceProfile::AccessControlProfile> profiles =
DeviceProfileConnector::GetInstance().GetAllAclIncludeLnnAcl();
std::vector<DistributedDeviceProfile::AccessControlProfile> targetProfiles = {};
for (const auto &item : profiles) {
if (item.GetAccesser().GetAccesserCredentialIdStr().empty() ||
item.GetAccessee().GetAccesseeCredentialIdStr().empty() || item.GetBindType() == DM_IDENTICAL_ACCOUNT) {
continue;
}
if ((item.GetAccesser().GetAccesserDeviceId() == localUdid &&
item.GetAccesser().GetAccesserUserId() == currentUserId) ||
(item.GetAccessee().GetAccesseeDeviceId() == localUdid &&
item.GetAccessee().GetAccesseeUserId() == currentUserId)) {
targetProfiles.push_back(item);
}
}
JsonObject credInfo;
GetShareCredInfoByUserId(context, currentUserId, credInfo);
GetP2PCredInfoByUserId(context, currentUserId, credInfo);
CompatibleAclAndCredInfo(context, currentUserId, targetProfiles, credInfo, localUdid);
}
void DmAuthState::GetShareCredInfoByUserId(std::shared_ptr<DmAuthContext> context, const int32_t userId,
JsonObject &credInfo)
{
LOGI("start.");
CHECK_NULL_VOID(context);
JsonObject queryParams;
queryParams[FILED_CRED_TYPE] = DM_AUTH_CREDENTIAL_ACCOUNT_ACROSS;
CHECK_NULL_VOID(context->hiChainAuthConnector);
int32_t ret = context->hiChainAuthConnector->QueryCredentialInfo(userId, queryParams, credInfo);
if (ret != DM_OK) {
LOGE("QueryCredentialInfo failed ret %{public}d.", ret);
}
}
void DmAuthState::GetP2PCredInfoByUserId(std::shared_ptr<DmAuthContext> context, const int32_t userId,
JsonObject &credInfo)
{
LOGI("start.");
CHECK_NULL_VOID(context);
JsonObject queryParams;
queryParams[FILED_CRED_TYPE] = DM_AUTH_CREDENTIAL_ACCOUNT_UNRELATED;
queryParams[FILED_CRED_OWNER] = "DM";
CHECK_NULL_VOID(context->hiChainAuthConnector);
int32_t ret = context->hiChainAuthConnector->QueryCredentialInfo(userId, queryParams, credInfo);
if (ret != DM_OK) {
LOGE("QueryCredentialInfo failed ret %{public}d.", ret);
}
}
void DmAuthState::CompatibleAclAndCredInfo(std::shared_ptr<DmAuthContext> context, const int32_t userId,
const std::vector<DistributedDeviceProfile::AccessControlProfile> &targetProfiles,
JsonObject &credInfo, const std::string &localUdid)
{
LOGI("start");
CHECK_NULL_VOID(context);
for (const auto &item : credInfo.Items()) {
if (!item.Contains(FILED_CRED_ID) || !item[FILED_CRED_ID].IsString()) {
continue;
}
std::string credId = item[FILED_CRED_ID].Get<std::string>();
LOGI("credId: %{public}s", GetAnonyString(credId).c_str());
bool isExistAcl = false;
for (const auto &profile : targetProfiles) {
bool isAcer = profile.GetAccesser().GetAccesserDeviceId() == localUdid;
bool isAcee = profile.GetAccessee().GetAccesseeDeviceId() == localUdid;
bool iscredr = profile.GetAccesser().GetAccesserCredentialIdStr() == credId;
bool iscrede = profile.GetAccessee().GetAccesseeCredentialIdStr() == credId;
if ((credId == profile.GetAccesser().GetAccesserCredentialIdStr() && isAcer) ||
(credId == profile.GetAccessee().GetAccesseeCredentialIdStr() && isAcee)) {
isExistAcl = true;
}
}
if (!isExistAcl) {
LOGI("DeleteCredential credId:%{public}s", GetAnonyString(credId).c_str());
CHECK_NULL_VOID(context->hiChainAuthConnector);
context->hiChainAuthConnector->DeleteCredential(userId, credId);
}
}
for (const auto &profile : targetProfiles) {
bool isAcer = profile.GetAccesser().GetAccesserDeviceId() == localUdid;
bool isAcee = profile.GetAccessee().GetAccesseeDeviceId() == localUdid;
bool iscredInfor = credInfo.Contains(profile.GetAccesser().GetAccesserCredentialIdStr());
bool iscredInfoe = credInfo.Contains(profile.GetAccessee().GetAccesseeCredentialIdStr());
if ((!credInfo.Contains(profile.GetAccesser().GetAccesserCredentialIdStr()) && isAcer) ||
(!credInfo.Contains(profile.GetAccessee().GetAccesseeCredentialIdStr()) && isAcee)) {
LOGI("delete profileId: %{public}" PRId64"", profile.GetAccessControlId());
DeleteAclSKAndCredId(context, userId, profile, localUdid);
}
}
}
void DmAuthState::DeleteAclSKAndCredId(std::shared_ptr<DmAuthContext> context, const int32_t userId,
const DistributedDeviceProfile::AccessControlProfile &profile, const std::string &localUdid)
{
CHECK_NULL_VOID(context);
CHECK_NULL_VOID(context->softbusConnector);
if (profile.GetAccesser().GetAccesserDeviceId() == localUdid) {
int32_t sessionKeyId = profile.GetAccesser().GetAccesserSessionKeyId();
std::string credId = profile.GetAccesser().GetAccesserCredentialIdStr();
int32_t ret = DeviceProfileConnector::GetInstance().DeleteSessionKey(userId, sessionKeyId);
if (ret != DM_OK) {
LOGE("Delete acceser SessionKey failed.");
}
context->softbusConnector->DeleteCredential({ userId, sessionKeyId, profile.GetAccessControlId(), credId });
}
if (profile.GetAccessee().GetAccesseeDeviceId() == localUdid) {
int32_t sessionKeyId = profile.GetAccessee().GetAccesseeSessionKeyId();
std::string credId = profile.GetAccessee().GetAccesseeCredentialIdStr();
int32_t ret = DeviceProfileConnector::GetInstance().DeleteSessionKey(userId, sessionKeyId);
if (ret != DM_OK) {
LOGE("Delete accesee SessionKey failed.");
}
context->softbusConnector->DeleteCredential({ userId, sessionKeyId, profile.GetAccessControlId(), credId });
}
DeviceProfileConnector::GetInstance().DeleteAccessControlById(profile.GetAccessControlId());
}
}
}