* Copyright (c) 2022 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 "user_idm_service.h"
#include "string_ex.h"
#include "accesstoken_kit.h"
#include "context_appstate_observer.h"
#include "context_helper.h"
#include "context_pool.h"
#include "credential_updated_manager.h"
#include "event_listener_manager.h"
#include "hdi_wrapper.h"
#include "iam_callback_proxy.h"
#include "iam_check.h"
#include "iam_logger.h"
#include "iam_para2str.h"
#include "iam_defines.h"
#include "iam_time.h"
#include "ipc_common.h"
#include "ipc_skeleton.h"
#include "iam_common_defines.h"
#include "load_mode_handler.h"
#include "nlohmann/json.hpp"
#include "publish_event_adapter.h"
#include "resource_node_pool.h"
#include "resource_node_utils.h"
#include "service_init_manager.h"
#include "system_param_manager.h"
#include "user_idm_database.h"
#include "xcollie_helper.h"
#define LOG_TAG "USER_AUTH_SA"
#define LOG_FILE_ID LOG_FILE_USER_IDM_SERVICE
namespace OHOS {
namespace UserIam {
namespace UserAuth {
REGISTER_SYSTEM_ABILITY_BY_ID(UserIdmService, SUBSYS_USERIAM_SYS_ABILITY_USERIDM, true);
constexpr int32_t USERIAM_IPC_THREAD_NUM = 4;
UserIdmService::UserIdmService(int32_t systemAbilityId, bool runOnCreate)
: SystemAbility(systemAbilityId, runOnCreate), UserIdmStub(true)
{
}
void UserIdmService::OnStart()
{
IAM_LOGI("Sa start UserIdmService");
IPCSkeleton::SetMaxWorkThreadNum(USERIAM_IPC_THREAD_NUM);
if (!Publish(this)) {
IAM_LOGE("failed to publish service");
}
ServiceInitManager::GetInstance().OnIdmServiceStart();
}
void UserIdmService::OnStop()
{
IAM_LOGI("Sa stop UserIdmService");
ServiceInitManager::GetInstance().OnIdmServiceStop();
}
std::string UserIdmService::GetSessionInfoMasked(std::vector<uint8_t> &challenge)
{
std::ostringstream sessionInfo;
constexpr size_t SESSION_INFO_LEN = 2;
constexpr int32_t UINT8_HEX_WITH = 2;
size_t bytesToProcess = std::min(challenge.size(), SESSION_INFO_LEN);
for (size_t i = 0; i < bytesToProcess; i++) {
sessionInfo << std::hex << std::setw(UINT8_HEX_WITH) << std::setfill('0');
sessionInfo << static_cast<uint16_t>(challenge[i]);
}
return sessionInfo.str();
}
int32_t UserIdmService::OpenSession(int32_t userId, std::vector<uint8_t> &challenge)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
CancelCurrentEnrollIfExist();
auto hdi = HdiWrapper::GetHdiInstance();
if (hdi == nullptr) {
IAM_LOGE("bad hdi");
return GENERAL_ERROR;
}
std::lock_guard<std::mutex> lock(mutex_);
int32_t ret = hdi->OpenSession(userId, challenge);
if (ret != HDF_SUCCESS) {
IAM_LOGE("failed to open session, error code:%{public}d", ret);
return GENERAL_ERROR;
}
std::string sessionInfo = GetSessionInfoMasked(challenge);
IAM_LOGI("set sessionInfo:%{public}s", sessionInfo.c_str());
SystemParamManager::GetInstance().SetParam(IDM_SESSION_INFO, sessionInfo);
return SUCCESS;
}
int32_t UserIdmService::CloseSession(int32_t userId)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
auto hdi = HdiWrapper::GetHdiInstance();
if (hdi == nullptr) {
IAM_LOGE("bad hdi");
return GENERAL_ERROR;
}
std::lock_guard<std::mutex> lock(mutex_);
int32_t ret = hdi->CloseSession(userId);
if (ret != HDF_SUCCESS) {
IAM_LOGE("failed to close session, error code:%{public}d", ret);
return GENERAL_ERROR;
}
return SUCCESS;
}
int32_t UserIdmService::GetCredentialInfoInner(int32_t userId, AuthType authType,
std::vector<CredentialInfo> &credInfoList)
{
IAM_LOGD("start");
if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
int32_t ret = UserIdmDatabase::Instance().GetCredentialInfo(userId, authType, credInfos);
if (ret != SUCCESS) {
IAM_LOGE("get credential fail, ret:%{public}d, userId:%{public}d, authType:%{public}d", ret,
userId, authType);
return ret;
}
if (credInfos.empty()) {
IAM_LOGI("no cred enrolled");
return NOT_ENROLLED;
}
for (const auto &credInfo : credInfos) {
if (credInfo == nullptr) {
IAM_LOGE("credInfo is nullptr");
return GENERAL_ERROR;
}
CredentialInfo info = {};
info.credentialId = credInfo->GetCredentialId();
info.templateId = credInfo->GetTemplateId();
info.authType = credInfo->GetAuthType();
info.pinType = credInfo->GetAuthSubType();
info.isAbandoned = credInfo->GetAbandonFlag();
info.validityPeriod = credInfo->GetValidPeriod();
credInfoList.push_back(info);
}
return SUCCESS;
}
int32_t UserIdmService::ConvertGetCredentialResult(int32_t resultCode, bool isNotEnrollReturnSuccess)
{
if (resultCode == SUCCESS) {
return SUCCESS;
}
if (resultCode == NOT_ENROLLED) {
return isNotEnrollReturnSuccess ? SUCCESS : NOT_ENROLLED;
}
IAM_LOGE("GetCredentialInfo fail, resultCode: %{public}d", resultCode);
if (resultCode == INVALID_PARAMETERS || resultCode == CHECK_PERMISSION_FAILED) {
return resultCode;
}
return GENERAL_ERROR;
}
int32_t UserIdmService::GetCredentialInfoImpl(int32_t userId, int32_t authType,
const sptr<IIdmGetCredInfoCallback> &callback)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (callback == nullptr) {
IAM_LOGE("callback is nullptr");
return INVALID_PARAMETERS;
}
std::vector<IpcCredentialInfo> ipcCredInfoList;
std::vector<CredentialInfo> credInfoList;
int32_t ret = GetCredentialInfoInner(userId, static_cast<AuthType>(authType), credInfoList);
if (ret != SUCCESS) {
ret = ConvertGetCredentialResult(ret, false);
credInfoList.clear();
}
bool hasAbandonedCredential = false;
for (auto &iter : credInfoList) {
if (iter.isAbandoned && iter.validityPeriod == 0) {
hasAbandonedCredential = true;
continue;
}
IpcCredentialInfo ipcCredInfo;
ipcCredInfo.authType = static_cast<int32_t>(iter.authType);
ipcCredInfo.pinType = static_cast<int32_t>(iter.pinType.value_or(PIN_SIX));
ipcCredInfo.credentialId = iter.credentialId;
ipcCredInfo.templateId = iter.templateId;
ipcCredInfo.isAbandoned = iter.isAbandoned;
ipcCredInfo.validityPeriod = iter.validityPeriod;
ipcCredInfoList.push_back(ipcCredInfo);
}
auto retCode = callback->OnCredentialInfos(ret, ipcCredInfoList);
if (retCode != SUCCESS) {
IAM_LOGE("OnCredentialInfos fail, ret: %{public}d", retCode);
}
if (hasAbandonedCredential) {
ClearUnavailableCredential(userId);
}
return ret;
}
int32_t UserIdmService::GetCredentialInfo(int32_t userId, int32_t authType,
const sptr<IIdmGetCredInfoCallback> &callback, int32_t &funcResult)
{
funcResult = GetCredentialInfoImpl(userId, authType, callback);
return SUCCESS;
}
int32_t UserIdmService::GetSecInfoInner(int32_t userId, SecUserInfo &secUserInfo)
{
IAM_LOGI("start");
if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
std::shared_ptr<SecureUserInfoInterface> userInfos = nullptr;
int32_t ret = UserIdmDatabase::Instance().GetSecUserInfo(userId, userInfos);
if (ret != SUCCESS) {
IAM_LOGE("get secUserInfo fail, ret:%{public}d, userId:%{public}d", ret, userId);
return ret;
}
if (userInfos == nullptr) {
IAM_LOGE("current userid %{public}d is not existed", userId);
return GENERAL_ERROR;
}
std::vector<std::shared_ptr<EnrolledInfoInterface>> enrolledInfos = userInfos->GetEnrolledInfo();
for (const auto &enrolledInfo : enrolledInfos) {
if (enrolledInfo == nullptr) {
IAM_LOGE("enrolledInfo is nullptr");
return GENERAL_ERROR;
}
EnrolledInfo info = {enrolledInfo->GetAuthType(), enrolledInfo->GetEnrolledId()};
secUserInfo.enrolledInfo.push_back(info);
}
secUserInfo.secureUid = userInfos->GetSecUserId();
return SUCCESS;
}
int32_t UserIdmService::GetSecInfo(int32_t userId, const sptr<IIdmGetSecureUserInfoCallback> &callback)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (callback == nullptr) {
IAM_LOGE("callback is nullptr");
return INVALID_PARAMETERS;
}
IpcSecUserInfo ipcSecUserInfo;
SecUserInfo secUserInfo = {};
int32_t ret = GetSecInfoInner(userId, secUserInfo);
if (ret != SUCCESS) {
IAM_LOGE("GetSecInfoInner fail, ret: %{public}d", ret);
secUserInfo.secureUid = 0;
secUserInfo.enrolledInfo.clear();
}
for (auto &iter : secUserInfo.enrolledInfo) {
IpcEnrolledInfo ipcEnrolledInfo;
ipcEnrolledInfo.authType = static_cast<int32_t>(iter.authType);
ipcEnrolledInfo.enrolledId = iter.enrolledId;
ipcSecUserInfo.enrolledInfo.push_back(ipcEnrolledInfo);
}
ipcSecUserInfo.secureUid = secUserInfo.secureUid;
auto retCode = callback->OnSecureUserInfo(ret, ipcSecUserInfo);
if (retCode != SUCCESS) {
IAM_LOGE("OnSecureUserInfo fail, ret: %{public}d", retCode);
}
return ret;
}
int32_t UserIdmService::StartEnroll(Enrollment::EnrollmentPara ¶,
const std::shared_ptr<ContextCallback> &contextCallback, Attributes &extraInfo, bool needSubscribeAppState)
{
if (!para.isUpdate && para.authType == PIN && !para.token.empty()) {
IAM_LOGI("auth type is pin, clear token");
para.token.clear();
}
auto context = ContextFactory::CreateEnrollContext(para, contextCallback, needSubscribeAppState);
if (context == nullptr || !ContextPool::Instance().Insert(context)) {
IAM_LOGE("failed to insert context");
contextCallback->OnResult(GENERAL_ERROR, extraInfo);
return GENERAL_ERROR;
}
contextCallback->SetTraceRequestContextId(context->GetContextId());
auto cleaner = ContextHelper::Cleaner(context);
contextCallback->SetCleaner(cleaner);
if (!context->Start()) {
IAM_LOGE("failed to start enroll");
contextCallback->OnResult(context->GetLatestError(), extraInfo);
return GENERAL_ERROR;
}
return SUCCESS;
}
bool UserIdmService::GetNeedSubscribeAppState(std::string jsonText, const char *key)
{
if (IpcCommon::CheckPermission(*this, USER_AUTH_FROM_BACKGROUND)) {
IAM_LOGE("check permission success, no need subscribe app state");
return false;
}
if (jsonText.size() == 0) {
IAM_LOGE("jsonText size is 0, need subscribe app state");
return true;
}
if (!nlohmann::json::accept(jsonText)) {
IAM_LOGE("the text is not json, need subscribe app state");
return true;
}
auto root = nlohmann::json::parse(jsonText.c_str());
if (root.is_null() || root.is_discarded()) {
IAM_LOGE("root is nullptr, need subscribe app state");
return true;
}
if (root.find(key) == root.end() || !(root[key].is_boolean())) {
IAM_LOGE("%{public}s not found or not boolean", key);
return true;
}
bool isEnrollBackGround = false;
root.at(key).get_to(isEnrollBackGround);
return !isEnrollBackGround;
}
int32_t UserIdmService::AddCredential(int32_t userId, const IpcCredentialPara &ipcCredentialPara,
const sptr<IIamCallback> &idmCallback, bool isUpdate)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(idmCallback != nullptr, INVALID_PARAMETERS);
Attributes extraInfo;
auto contextCallback = ContextCallback::NewInstance(idmCallback,
isUpdate ? TRACE_UPDATE_CREDENTIAL : TRACE_ADD_CREDENTIAL);
if (contextCallback == nullptr) {
IAM_LOGE("failed to construct context callback");
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
std::string callerName = "";
int32_t callerType = Security::AccessToken::TOKEN_INVALID;
static_cast<void>(IpcCommon::GetCallerName(*this, callerName, callerType));
contextCallback->SetTraceCallerName(callerName);
contextCallback->SetTraceCallerType(callerType);
contextCallback->SetTraceUserId(userId);
contextCallback->SetTraceAuthType(static_cast<AuthType>(ipcCredentialPara.authType));
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
CancelCurrentEnrollIfExist();
Enrollment::EnrollmentPara para = {};
para.authType = static_cast<AuthType>(ipcCredentialPara.authType);
para.userId = userId;
para.pinType = static_cast<PinSubType>(ipcCredentialPara.pinType);
para.tokenId = IpcCommon::GetAccessTokenId(*this);
para.token = ipcCredentialPara.token;
para.isUpdate = isUpdate;
para.sdkVersion = INNER_API_VERSION_10000;
para.callerName = callerName;
para.callerType = callerType;
para.additionalInfo = ipcCredentialPara.additionalInfo;
bool needSubscribeAppState = GetNeedSubscribeAppState(para.additionalInfo, "isEnrollBackground");
return StartEnroll(para, contextCallback, extraInfo, needSubscribeAppState);
}
int32_t UserIdmService::UpdateCredential(int32_t userId, const IpcCredentialPara &ipcCredentialPara,
const sptr<IIamCallback> &idmCallback)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (idmCallback == nullptr) {
IAM_LOGE("callback is nullptr");
return INVALID_PARAMETERS;
}
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
int32_t ret = UserIdmDatabase::Instance().GetCredentialInfo(userId,
static_cast<AuthType>(ipcCredentialPara.authType), credInfos);
if (ret != SUCCESS) {
IAM_LOGE("get credential fail, ret:%{public}d, userId:%{public}d, authType:%{public}d",
ret, userId, ipcCredentialPara.authType);
Attributes extraInfo;
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
if (credInfos.empty()) {
IAM_LOGE("current userid %{public}d has no credential for type %{public}u",
userId, ipcCredentialPara.authType);
Attributes extraInfo;
idmCallback->OnResult(NOT_ENROLLED, extraInfo.Serialize());
return SUCCESS;
}
return AddCredential(userId, ipcCredentialPara, idmCallback, true);
}
int32_t UserIdmService::Cancel(int32_t userId)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
uint32_t tokenId = IpcCommon::GetAccessTokenId(*this);
auto contextList = ContextPool::Instance().Select(CONTEXT_ENROLL);
int32_t ret = GENERAL_ERROR;
for (const auto &context : contextList) {
if (auto ctx = context.lock(); ctx != nullptr && tokenId == ctx->GetTokenId()) {
if (!ctx->Stop()) {
IAM_LOGE("failed stop %{public}s", GET_MASKED_STRING(ctx->GetContextId()).c_str());
ret = ctx->GetLatestError();
}
}
}
return ret;
}
void UserIdmService::CancelCurrentEnrollIfExist()
{
IAM_LOGD("start");
auto contextList = ContextPool::Instance().Select(CONTEXT_ENROLL);
for (const auto &context : contextList) {
if (auto ctx = context.lock(); ctx != nullptr) {
IAM_LOGI("stop the old context %{public}s", GET_MASKED_STRING(ctx->GetContextId()).c_str());
ctx->Stop();
}
}
}
int32_t UserIdmService::EnforceDelUser(int32_t userId, const sptr<IIamCallback> &idmCallback)
{
HILOG_COMM_INFO("user idm service to delete userid: %{public}d", userId);
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(idmCallback != nullptr, INVALID_PARAMETERS);
Attributes extraInfo;
auto contextCallback = ContextCallback::NewInstance(idmCallback, TRACE_ENFORCE_DELETE_USER);
if (contextCallback == nullptr) {
IAM_LOGE("failed to construct context callback");
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
std::string callerName = "";
int32_t callerType = Security::AccessToken::TOKEN_INVALID;
static_cast<void>(IpcCommon::GetCallerName(*this, callerName, callerType));
contextCallback->SetTraceCallerType(callerType);
contextCallback->SetTraceCallerName(callerName);
contextCallback->SetTraceUserId(userId);
if (!IpcCommon::CheckPermission(*this, ENFORCE_USER_IDM)) {
IAM_LOGE("failed to check permission");
contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
CancelCurrentEnrollIfExist();
std::shared_ptr<SecureUserInfoInterface> userInfo = nullptr;
int32_t ret = UserIdmDatabase::Instance().GetSecUserInfo(userId, userInfo);
if (ret != SUCCESS) {
IAM_LOGE("get secUserInfo fail, ret:%{public}d, userId:%{public}d", ret, userId);
contextCallback->OnResult(ret, extraInfo);
return ret;
}
if (userInfo == nullptr) {
HILOG_COMM_ERROR("current userid %{public}d is not existed", userId);
contextCallback->OnResult(GENERAL_ERROR, extraInfo);
return GENERAL_ERROR;
}
CredChangeEventInfo changeInfo = {callerName, callerType, 0, 0, false};
ret = EnforceDelUserInner(userId, contextCallback, "EnforceDeleteUser", changeInfo);
if (ret != SUCCESS) {
HILOG_COMM_ERROR("failed to enforce delete user, ret: %{public}d", ret);
static_cast<void>(extraInfo.SetUint64Value(Attributes::ATTR_CREDENTIAL_ID, 0));
contextCallback->OnResult(ret, extraInfo);
return ret;
}
IAM_LOGI("delete user success");
contextCallback->OnResult(SUCCESS, extraInfo);
return SUCCESS;
}
void UserIdmService::PostProcessForDelete(int32_t userId,
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos,
std::string changeReasonTrace, CredChangeEventType eventType, CredChangeEventInfo &changeInfo)
{
int32_t ret = ResourceNodeUtils::NotifyExecutorToDeleteTemplates(credInfos, changeReasonTrace);
if (ret != SUCCESS) {
IAM_LOGE("failed to delete executor info, err:%{public}d", ret);
}
PublishEventAdapter::GetInstance().PublishDeletedEvent(userId);
bool isExistPin = false;
for (auto cred : credInfos) {
if (cred->GetAuthType() == PIN && cred->GetAbandonFlag()) {
continue;
}
if (cred->GetAuthType() == PIN) {
isExistPin = true;
}
changeInfo.lastCredentialId = cred->GetCredentialId();
CredChangeEventListenerManager::GetInstance().OnNotifyCredChangeEvent(
userId, cred->GetAuthType(), eventType, changeInfo);
}
if (isExistPin) {
CredentialUpdatedManager::GetInstance().ProcessUserDeleted(userId);
}
}
int32_t UserIdmService::DelUser(int32_t userId, const std::vector<uint8_t> &authToken,
const sptr<IIamCallback> &idmCallback)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
HILOG_COMM_INFO("del user, userId: %{public}d", userId);
IF_FALSE_LOGE_AND_RETURN_VAL(idmCallback != nullptr, INVALID_PARAMETERS);
Attributes extraInfo;
auto contextCallback = ContextCallback::NewInstance(idmCallback, TRACE_DELETE_USER);
if (contextCallback == nullptr) {
IAM_LOGE("failed to construct context callback");
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
std::string callerName = "";
int32_t callerType = Security::AccessToken::TOKEN_INVALID;
static_cast<void>(IpcCommon::GetCallerName(*this, callerName, callerType));
contextCallback->SetTraceCallerName(callerName);
contextCallback->SetTraceCallerType(callerType);
contextCallback->SetTraceUserId(userId);
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
CancelCurrentEnrollIfExist();
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
std::vector<uint8_t> rootSecret;
int32_t ret = UserIdmDatabase::Instance().DeleteUser(userId, authToken, credInfos, rootSecret);
if (ret != SUCCESS) {
HILOG_COMM_ERROR("failed to delete user, userId: %{pblic}d", userId);
contextCallback->OnResult(ret, extraInfo);
return ret;
}
if (!extraInfo.SetUint8ArrayValue(Attributes::ATTR_OLD_ROOT_SECRET, rootSecret)) {
IAM_LOGE("set rootsecret to extraInfo failed");
contextCallback->OnResult(ret, extraInfo);
return ret;
}
SetAuthTypeTrace(credInfos, contextCallback);
contextCallback->OnResult(ret, extraInfo);
CredChangeEventInfo changeInfo = {callerName, callerType, 0, 0, false};
PostProcessForDelete(userId, credInfos, "DeleteUser", DEL_USER, changeInfo);
return SUCCESS;
}
int32_t UserIdmService::StartDelete(Deletion::DeleteParam ¶,
const std::shared_ptr<ContextCallback> &contextCallback, Attributes &extraInfo)
{
HILOG_COMM_INFO("user idm delete, userId: %{public}d, credentialId: %{public}s", para.userId,
Common::GetMaskedString(para.credentialId).c_str());
auto context = ContextFactory::CreateDeleteContext(para, contextCallback);
if (context == nullptr || !ContextPool::Instance().Insert(context)) {
IAM_LOGE("failed to insert context");
contextCallback->OnResult(GENERAL_ERROR, extraInfo);
return GENERAL_ERROR;
}
contextCallback->SetTraceRequestContextId(context->GetContextId());
auto cleaner = ContextHelper::Cleaner(context);
contextCallback->SetCleaner(cleaner);
if (!context->Start()) {
HILOG_COMM_ERROR("failed to start context delete");
contextCallback->OnResult(context->GetLatestError(), extraInfo);
return context->GetLatestError();
}
return SUCCESS;
}
int32_t UserIdmService::DelCredential(int32_t userId, uint64_t credentialId,
const std::vector<uint8_t> &authToken, const sptr<IIamCallback> &idmCallback)
{
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(idmCallback != nullptr, INVALID_PARAMETERS);
Attributes extraInfo;
auto contextCallback = ContextCallback::NewInstance(idmCallback, TRACE_DELETE_CREDENTIAL);
if (contextCallback == nullptr) {
IAM_LOGE("failed to construct context callback");
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
std::string callerName = "";
int32_t callerType = Security::AccessToken::TOKEN_INVALID;
static_cast<void>(IpcCommon::GetCallerName(*this, callerName, callerType));
contextCallback->SetTraceCallerName(callerName);
contextCallback->SetTraceCallerType(callerType);
contextCallback->SetTraceUserId(userId);
if (!IpcCommon::CheckPermission(*this, MANAGE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
CancelCurrentEnrollIfExist();
std::shared_ptr<CredentialInfoInterface> credInfo;
Deletion::DeleteParam deleteParam = {
.userId = userId,
.credentialId = credentialId,
.tokenId = IpcCommon::GetAccessTokenId(*this),
.callerName = callerName,
.callerType = callerType,
.token = authToken,
};
return StartDelete(deleteParam, contextCallback, extraInfo);
}
int UserIdmService::Dump(int fd, const std::vector<std::u16string> &args)
{
IAM_LOGI("start");
if (fd < 0) {
IAM_LOGE("invalid parameters");
return INVALID_PARAMETERS;
}
std::string arg0 = (args.empty() ? "" : Str16ToStr8(args[0]));
if (arg0.empty() || arg0.compare("-h") == 0) {
dprintf(fd, "Usage:\n");
dprintf(fd, " -h: command help.\n");
dprintf(fd, " -l: active user info dump.\n");
return SUCCESS;
}
if (arg0.compare("-l") != 0) {
IAM_LOGE("invalid option");
dprintf(fd, "Invalid option\n");
return GENERAL_ERROR;
}
std::optional<int32_t> activeUserId;
if (IpcCommon::GetActiveUserId(activeUserId) != SUCCESS) {
dprintf(fd, "Internal error.\n");
IAM_LOGE("failed to get active id");
return GENERAL_ERROR;
}
dprintf(fd, "Active user is %d\n", activeUserId.value());
std::shared_ptr<SecureUserInfoInterface> userInfo = nullptr;
int32_t ret = UserIdmDatabase::Instance().GetSecUserInfo(activeUserId.value(), userInfo);
if (ret != SUCCESS) {
IAM_LOGE("get secUserInfo fail, ret:%{public}d, userId:%{public}d", ret, activeUserId.value());
return GENERAL_ERROR;
}
if (userInfo == nullptr) {
IAM_LOGE("userInfo is null");
return SUCCESS;
}
auto enrolledInfo = userInfo->GetEnrolledInfo();
for (auto &info : enrolledInfo) {
if (info != nullptr) {
dprintf(fd, "AuthType %s is enrolled.\n", Common::AuthTypeToStr(info->GetAuthType()));
}
}
return SUCCESS;
}
void UserIdmService::SetAuthTypeTrace(const std::vector<std::shared_ptr<CredentialInfoInterface>> &credInfos,
const std::shared_ptr<ContextCallback> &contextCallback)
{
uint32_t authTypeTrace = 0;
for (const auto &credInfo : credInfos) {
if (credInfo == nullptr) {
IAM_LOGE("credInfo is nullptr");
continue;
}
authTypeTrace |= static_cast<uint32_t>(credInfo->GetAuthType());
}
contextCallback->SetTraceAuthType(static_cast<int32_t>(authTypeTrace));
}
int32_t UserIdmService::EnforceDelUserInner(int32_t userId, std::shared_ptr<ContextCallback> callbackForTrace,
std::string changeReasonTrace, CredChangeEventInfo &changeInfo)
{
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
int32_t ret = UserIdmDatabase::Instance().DeleteUserEnforce(userId, credInfos);
if (ret != SUCCESS) {
HILOG_COMM_ERROR("failed to enforce delete user, ret:%{public}d, userId: %{public}d",
ret, userId);
return ret;
}
SetAuthTypeTrace(credInfos, callbackForTrace);
PostProcessForDelete(userId, credInfos, changeReasonTrace, ENFORCE_DEL_USER, changeInfo);
return SUCCESS;
}
int32_t UserIdmService::ClearRedundancyCredentialInner(const std::string &callerName, int32_t callerType)
{
IAM_LOGI("start");
std::vector<int32_t> accountInfo;
int32_t ret = IpcCommon::GetAllUserId(accountInfo);
if (ret != SUCCESS) {
IAM_LOGE("GetAllUserId failed");
return IPC_ERROR;
}
std::vector<std::shared_ptr<UserInfoInterface>> userInfos;
ret = UserIdmDatabase::Instance().GetAllExtUserInfo(userInfos);
if (ret != SUCCESS) {
IAM_LOGE("GetAllExtUserInfo failed");
return INVALID_HDI_INTERFACE;
}
if (userInfos.empty()) {
IAM_LOGE("no userInfo");
return SUCCESS;
}
for (const auto &iter : userInfos) {
int32_t userId = iter->GetUserId();
auto callbackForTrace = ContextCallback::NewDummyInstance(TRACE_DELETE_REDUNDANCY);
if (callbackForTrace == nullptr) {
IAM_LOGE("failed to get callbackForTrace");
continue;
}
callbackForTrace->SetTraceUserId(userId);
callbackForTrace->SetTraceCallerName(callerName);
callbackForTrace->SetTraceCallerType(callerType);
std::vector<int32_t>::iterator it = std::find(accountInfo.begin(), accountInfo.end(), userId);
if (it == accountInfo.end()) {
CredChangeEventInfo changeInfo = {callerName, callerType, 0, 0, false};
ret = EnforceDelUserInner(userId, callbackForTrace, "DeleteRedundancy", changeInfo);
Attributes extraInfo;
callbackForTrace->OnResult(ret, extraInfo);
IAM_LOGE("ClearRedundancytCredential, userId: %{public}d", userId);
}
}
return SUCCESS;
}
int32_t UserIdmService::ClearRedundancyCredential(const sptr<IIamCallback> &idmCallback)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(idmCallback != nullptr, INVALID_PARAMETERS);
Attributes extraInfo;
auto contextCallback = ContextCallback::NewInstance(idmCallback, TRACE_DELETE_REDUNDANCY);
if (contextCallback == nullptr) {
IAM_LOGE("failed to construct context callback");
idmCallback->OnResult(GENERAL_ERROR, extraInfo.Serialize());
return GENERAL_ERROR;
}
std::string callerName = "";
int32_t callerType = Security::AccessToken::TOKEN_INVALID;
static_cast<void>(IpcCommon::GetCallerName(*this, callerName, callerType));
contextCallback->SetTraceCallerName(callerName);
contextCallback->SetTraceCallerType(callerType);
if (!IpcCommon::CheckPermission(*this, CLEAR_REDUNDANCY_PERMISSION)) {
IAM_LOGE("failed to check permission");
contextCallback->OnResult(CHECK_PERMISSION_FAILED, extraInfo);
return CHECK_PERMISSION_FAILED;
}
std::lock_guard<std::mutex> lock(mutex_);
CancelCurrentEnrollIfExist();
int32_t ret = ClearRedundancyCredentialInner(callerName, callerType);
if (ret != SUCCESS) {
HILOG_COMM_ERROR("clear redundancy cred fail, ret:%{public}d, callerName: %{public}s,"
" callerType: %{public}d", ret, callerName.c_str(), callerType);
}
contextCallback->OnResult(ret, extraInfo);
return ret;
}
int32_t UserIdmService::GetCredentialInfoSync(int32_t userId, int32_t authType,
std::vector<IpcCredentialInfo> &ipcCredentialInfoList)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
std::vector<CredentialInfo> credentialInfoList;
int32_t ret = GetCredentialInfoInner(userId, static_cast<AuthType>(authType), credentialInfoList);
if (ret != SUCCESS) {
ret = ConvertGetCredentialResult(ret, true);
credentialInfoList.clear();
}
bool hasAbandonedCredential = false;
for (auto &iter : credentialInfoList) {
if (iter.isAbandoned && iter.validityPeriod == 0) {
hasAbandonedCredential = true;
continue;
}
IpcCredentialInfo ipcCredInfo;
ipcCredInfo.authType = static_cast<int32_t>(iter.authType);
ipcCredInfo.pinType = static_cast<int32_t>(iter.pinType.value_or(PIN_SIX));
ipcCredInfo.credentialId = iter.credentialId;
ipcCredInfo.templateId = iter.templateId;
ipcCredInfo.isAbandoned = iter.isAbandoned;
ipcCredInfo.validityPeriod = iter.validityPeriod;
ipcCredentialInfoList.push_back(ipcCredInfo);
}
if (hasAbandonedCredential) {
ClearUnavailableCredential(userId);
}
IAM_LOGI("GetCredentialInfoSync success, credential num:%{public}zu", ipcCredentialInfoList.size());
return ret;
}
int32_t UserIdmService::RegistCredChangeEventListener(const sptr<IEventListenerCallback> &listener)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(listener != nullptr, INVALID_PARAMETERS);
if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
int32_t result = CredChangeEventListenerManager::GetInstance().RegistEventListener(listener);
if (result != SUCCESS) {
IAM_LOGE("failed to regist cred change event listener");
return result;
}
return SUCCESS;
}
int32_t UserIdmService::UnRegistCredChangeEventListener(const sptr<IEventListenerCallback> &listener)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
IF_FALSE_LOGE_AND_RETURN_VAL(listener != nullptr, INVALID_PARAMETERS);
if (!IpcCommon::CheckPermission(*this, USE_USER_IDM_PERMISSION)) {
IAM_LOGE("failed to check permission");
return CHECK_PERMISSION_FAILED;
}
int32_t result = CredChangeEventListenerManager::GetInstance().UnRegistEventListener(listener);
if (result != SUCCESS) {
IAM_LOGE("failed to unregist cred change event listener");
return result;
}
return SUCCESS;
}
void UserIdmService::ClearUnavailableCredential(int32_t userId)
{
IAM_LOGI("start");
Common::XCollieHelper xcollie(__FUNCTION__, Common::API_CALL_TIMEOUT);
std::vector<std::shared_ptr<CredentialInfoInterface>> credInfos;
int32_t ret = UserIdmDatabase::Instance().ClearUnavailableCredential(userId, credInfos);
if (ret != SUCCESS) {
IAM_LOGE("clear expired credential fail, ret:%{public}d, userId:%{public}d", ret, userId);
return;
}
if (credInfos.empty()) {
IAM_LOGI("no abandoned credential");
return;
}
ret = ResourceNodeUtils::NotifyExecutorToDeleteTemplates(credInfos, "ClearExpiredTemplate");
if (ret != SUCCESS) {
IAM_LOGE("failed to delete executor info, error code : %{public}d", ret);
}
return;
}
int32_t UserIdmService::CallbackEnter([[maybe_unused]] uint32_t code)
{
IAM_LOGI("start, code:%{public}u", code);
return SUCCESS;
}
int32_t UserIdmService::CallbackExit([[maybe_unused]] uint32_t code, [[maybe_unused]] int32_t result)
{
IAM_LOGI("leave, code:%{public}u, result:%{public}d", code, result);
return SUCCESS;
}
}
}
}