1/*
2 * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16#include "ohos_account_manager.h"
17#include <cerrno>
18#include <dirent.h>
19#include <dlfcn.h>
20#include <iomanip>
21#include <mbedtls/aes.h>
22#include <mbedtls/cipher.h>
23#include <mbedtls/pkcs5.h>
24#include <sys/types.h>
25#include <sstream>
26#include <string_ex.h>
27#include "accesstoken_kit.h"
28#include "account_constants.h"
29#include "account_event_provider.h"
30#include "account_event_subscribe.h"
31#include "account_helper_data.h"
32#include "account_info.h"
33#include "account_log_wrapper.h"
34#include "account_mgr_service.h"
35#include "account_permission_manager.h"
36#ifdef HAS_CES_PART
37#include "common_event_support.h"
38#endif // HAS_CES_PART
39#include "account_hisysevent_adapter.h"
40#include "distributed_account_subscribe_manager.h"
41#include "ipc_skeleton.h"
42#include "mbedtls/sha256.h"
43#include "system_ability_definition.h"
44#include "tokenid_kit.h"
45
46#ifdef HAS_CES_PART
47using namespace OHOS::EventFwk;
48#endif // HAS_CES_PART
49
50namespace OHOS {
51namespace AccountSA {
52namespace {
53constexpr unsigned int ITERATE_CNT = 1000;
54constexpr std::int32_t OUTPUT_LENGTH_IN_BYTES = 32;
55constexpr std::uint8_t TWO_BYTE_MASK = 0xF0;
56constexpr std::int32_t MAX_RETRY_TIMES = 2; // give another chance when json file corrupted
57constexpr std::uint32_t MAX_NAME_LENGTH = 256;
58constexpr std::uint32_t MAX_UID_LENGTH = 512;
59constexpr std::uint32_t HASH_LENGTH = 32;
60constexpr std::uint32_t WIDTH_FOR_HEX = 2;
61constexpr std::uint32_t OHOS_ACCOUNT_UDID_LENGTH = HASH_LENGTH * 2;
62const std::string KEY_ACCOUNT_EVENT_LOGIN = "LOGIN";
63const std::string KEY_ACCOUNT_EVENT_LOGOUT = "LOGOUT";
64const std::string KEY_ACCOUNT_EVENT_TOKEN_INVALID = "TOKEN_INVALID";
65const std::string KEY_ACCOUNT_EVENT_LOGOFF = "LOGOFF";
66std::string GetAccountEventStr(const std::map<std::string, std::string> &accountEventMap,
67    const std::string &eventKey, const std::string &defaultValue)
68{
69    const auto &it = accountEventMap.find(eventKey);
70    if (it != accountEventMap.end()) {
71        return it->second;
72    }
73    return defaultValue;
74}
75
76bool GetCallerBundleName(std::string &bundleName)
77{
78    uint64_t fullTokenId = IPCSkeleton::GetCallingFullTokenID();
79    Security::AccessToken::AccessTokenID tokenId = fullTokenId & TOKEN_ID_LOWMASK;
80    Security::AccessToken::ATokenTypeEnum tokenType = Security::AccessToken::AccessTokenKit::GetTokenType(tokenId);
81    if ((tokenType == Security::AccessToken::ATokenTypeEnum::TOKEN_HAP) &&
82        (!Security::AccessToken::TokenIdKit::IsSystemAppByFullTokenID(fullTokenId))) {
83        Security::AccessToken::HapTokenInfo hapTokenInfo;
84        int result = Security::AccessToken::AccessTokenKit::GetHapTokenInfo(tokenId, hapTokenInfo);
85        if (result) {
86            ACCOUNT_LOGE("failed to get hap token info, result = %{public}d", result);
87            return false;
88        }
89        bundleName = hapTokenInfo.bundleName;
90    }
91    return true;
92}
93
94std::string ReturnOhosUdidWithSha256(const std::string &uid)
95{
96    unsigned char hash[HASH_LENGTH] = {0};
97    mbedtls_sha256_context context;
98    mbedtls_sha256_init(&context);
99    mbedtls_sha256_starts(&context, 0);
100
101    std::string plainStr = uid;
102    mbedtls_sha256_update(&context, reinterpret_cast<const unsigned char *>(plainStr.c_str()), plainStr.length());
103    mbedtls_sha256_finish(&context, hash);
104    mbedtls_sha256_free(&context);
105
106    std::stringstream ss;
107    for (std::uint32_t i = 0; i < HASH_LENGTH; ++i) {
108        ss << std::hex << std::uppercase << std::setw(WIDTH_FOR_HEX) << std::setfill('0') << std::uint16_t(hash[i]);
109    }
110    std::string ohosUidStr;
111    ss >> ohosUidStr;
112    return ohosUidStr;
113}
114
115std::string GenerateOhosUdidWithSha256(const std::string &name, const std::string &uid)
116{
117    if (name.empty() || name.length() > MAX_NAME_LENGTH) {
118        ACCOUNT_LOGE("input name empty or too long, length %{public}zu", name.length());
119        return std::string("");
120    }
121
122    if (uid.empty() || uid.length() > MAX_UID_LENGTH) {
123        ACCOUNT_LOGE("input uid empty or too long, length %{public}zu", uid.length());
124        return std::string("");
125    }
126
127    std::string bundleName = "";
128    if (!GetCallerBundleName(bundleName)) {
129        ACCOUNT_LOGE("GetCallerBundleName failed");
130        return std::string("");
131    }
132    if (bundleName.empty()) {
133        return ReturnOhosUdidWithSha256(uid);
134    }
135    unsigned char newId[OUTPUT_LENGTH_IN_BYTES + 1] = {};
136    mbedtls_md_context_t md_context;
137    mbedtls_md_init(&md_context);
138    const mbedtls_md_info_t *mbedtls_sha256_info = mbedtls_md_info_from_type(MBEDTLS_MD_SHA256);
139    int ret = mbedtls_md_setup(&md_context, mbedtls_sha256_info, 1);
140    if (ret != 0) {
141        ACCOUNT_LOGE("mbedtls_md_setup failed");
142        mbedtls_md_free(&md_context);
143        return std::string("");
144    }
145    ret = mbedtls_pkcs5_pbkdf2_hmac(&md_context, reinterpret_cast<const unsigned char *>(uid.c_str()), uid.size(),
146        reinterpret_cast<const unsigned char *>(bundleName.c_str()), bundleName.size(), ITERATE_CNT,
147        OUTPUT_LENGTH_IN_BYTES, newId);
148    if (ret != 0) {
149        ACCOUNT_LOGE("mbedtls_pkcs5_pbkdf2_hmac failed");
150        mbedtls_md_free(&md_context);
151        return std::string("");
152    }
153    mbedtls_md_free(&md_context);
154    std::string ohosUidStr;
155    for (int i = 0; i < OUTPUT_LENGTH_IN_BYTES; i++) {
156        if ((newId[i] & TWO_BYTE_MASK) == 0) {
157            ohosUidStr.append("0");
158        }
159        ohosUidStr.append(DexToHexString(newId[i], true));
160    }
161    return ohosUidStr;
162}
163}
164
165/**
166 * Ohos account state change.
167 *
168 * @param name ohos account name
169 * @param uid ohos account uid
170 * @param eventStr ohos account state change event
171 * @return true if the processing was completed, otherwise false
172 */
173ErrCode OhosAccountManager::OhosAccountStateChange(const std::string &name, const std::string &uid,
174    const std::string &eventStr)
175{
176    auto itFunc = eventFuncMap_.find(eventStr);
177    if (itFunc == eventFuncMap_.end()) {
178        ACCOUNT_LOGE("invalid event: %{public}s", eventStr.c_str());
179        return ERR_ACCOUNT_COMMON_INVALID_PARAMETER;
180    }
181    OhosAccountInfo ohosAccountInfo;
182    ohosAccountInfo.name_ = name;
183    ohosAccountInfo.uid_ = uid;
184    std::int32_t userId = AccountMgrService::GetInstance().GetCallingUserID();
185    return (itFunc->second)(userId, ohosAccountInfo, eventStr);
186}
187
188ErrCode OhosAccountManager::OhosAccountStateChange(
189    const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)
190{
191    auto itFunc = eventFuncMap_.find(eventStr);
192    if (itFunc == eventFuncMap_.end()) {
193        ACCOUNT_LOGE("invalid event: %{public}s", eventStr.c_str());
194        return ERR_ACCOUNT_COMMON_INVALID_PARAMETER;
195    }
196    return (itFunc->second)(userId, ohosAccountInfo, eventStr);
197}
198
199/**
200 * Clear current account information
201 */
202bool OhosAccountManager::ClearOhosAccount(AccountInfo &curOhosAccountInfo, std::int32_t clrStatus) const
203{
204    curOhosAccountInfo.clear(clrStatus);
205    ErrCode errCode = dataDealer_->AccountInfoToJson(curOhosAccountInfo);
206    if (errCode != ERR_OK) {
207        ACCOUNT_LOGE("AccountInfoToJson error");
208        return false;
209    }
210    return true;
211}
212
213/**
214 * Config current account config.
215 *
216 * @param ohosAccountInfo distribute account information.
217 * @return true if success.
218 */
219bool OhosAccountManager::SaveOhosAccountInfo(AccountInfo &ohosAccountInfo) const
220{
221    ErrCode errCode = dataDealer_->AccountInfoToJson(ohosAccountInfo);
222    if (errCode != ERR_OK) {
223        ACCOUNT_LOGE("AccountInfoToJson error.");
224        return false;
225    }
226    return true;
227}
228
229/**
230 * Get current account information.
231 *
232 * @return current account information.
233 */
234AccountInfo OhosAccountManager::GetCurrentOhosAccountInfo()
235{
236    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
237
238    AccountInfo currOhosAccountInfo;
239    std::int32_t callingUserId = AccountMgrService::GetInstance().GetCallingUserID();
240    if (dataDealer_->AccountInfoFromJson(currOhosAccountInfo, callingUserId) != ERR_OK) {
241        ACCOUNT_LOGE("get current ohos account info failed, callingUserId %{public}d.", callingUserId);
242        currOhosAccountInfo.clear();
243    }
244    return currOhosAccountInfo;
245}
246
247ErrCode OhosAccountManager::GetAccountInfoByUserId(std::int32_t userId, AccountInfo &info)
248{
249    if (userId == 0) {
250        userId = AccountMgrService::GetInstance().GetCallingUserID();
251    }
252    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
253
254    ErrCode ret = dataDealer_->AccountInfoFromJson(info, userId);
255    if (ret != ERR_OK) {
256        ACCOUNT_LOGE("get ohos account info failed, userId %{public}d.", userId);
257        info.clear();
258        return ret;
259    }
260    return ERR_OK;
261}
262
263ErrCode OhosAccountManager::SubscribeDistributedAccountEvent(const DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE type,
264    const sptr<IRemoteObject> &eventListener)
265{
266    return subscribeManager_.SubscribeDistributedAccountEvent(type, eventListener);
267}
268
269ErrCode OhosAccountManager::UnsubscribeDistributedAccountEvent(const DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE type,
270    const sptr<IRemoteObject> &eventListener)
271{
272    return subscribeManager_.UnsubscribeDistributedAccountEvent(type, eventListener);
273}
274
275/**
276 * Get current account state.
277 *
278 * @return current account state id.
279 */
280std::int32_t OhosAccountManager::GetCurrentOhosAccountState()
281{
282    AccountInfo currOhosAccountInfo = GetCurrentOhosAccountInfo();
283    return currOhosAccountInfo.ohosAccountInfo_.status_;
284}
285
286/**
287 * Process an account event.
288 * @param curOhosAccount current ohos account info
289 * @param eventStr ohos account state change event
290 * @return true if the processing was completed, otherwise false
291 */
292bool OhosAccountManager::HandleEvent(AccountInfo &curOhosAccount, const std::string &eventStr)
293{
294    auto iter = eventMap_.find(eventStr);
295    if (iter == eventMap_.end()) {
296        ACCOUNT_LOGE("invalid event: %{public}s", eventStr.c_str());
297        return false;
298    }
299    int event = iter->second;
300    accountState_->SetAccountState(curOhosAccount.ohosAccountInfo_.status_);
301    bool ret = accountState_->StateChangeProcess(event);
302    if (!ret) {
303        ACCOUNT_LOGE("Handle event %{public}d failed", event);
304        return false;
305    }
306    std::int32_t newState = accountState_->GetAccountState();
307    if (newState != curOhosAccount.ohosAccountInfo_.status_) {
308        ReportOhosAccountStateChange(curOhosAccount.userId_, event, curOhosAccount.ohosAccountInfo_.status_, newState);
309        curOhosAccount.ohosAccountInfo_.status_ = newState;
310    }
311    return true;
312}
313
314/**
315 * login ohos (for distributed network) account.
316 *
317 * @param userId target local account id.
318 * @param ohosAccountInfo ohos account information
319 * @param eventStr ohos account state change event
320 * @return ERR_OK if the processing was completed
321 */
322ErrCode OhosAccountManager::LoginOhosAccount(const int32_t userId, const OhosAccountInfo &ohosAccountInfo,
323    const std::string &eventStr)
324{
325    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
326
327    AccountInfo currAccountInfo;
328    ErrCode res = dataDealer_->AccountInfoFromJson(currAccountInfo, userId);
329    if (res != ERR_OK) {
330        ACCOUNT_LOGE("get current ohos account info failed, userId %{public}d.", userId);
331        return res;
332    }
333    std::string ohosAccountUid = GenerateOhosUdidWithSha256(ohosAccountInfo.name_, ohosAccountInfo.uid_);
334    // current local user cannot be bound again when it has already been bound to an ohos account
335    if (!CheckOhosAccountCanBind(currAccountInfo, ohosAccountInfo, ohosAccountUid)) {
336        ACCOUNT_LOGE("check can be bound failed, userId %{public}d.", userId);
337        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
338    }
339
340#ifdef HAS_CES_PART
341    // check whether need to publish event or not
342    bool isPubLoginEvent = false;
343    if (currAccountInfo.ohosAccountInfo_.status_ != ACCOUNT_STATE_LOGIN) {
344        isPubLoginEvent = true;
345    }
346#endif // HAS_CES_PART
347    // update account status
348    if (!HandleEvent(currAccountInfo, eventStr)) {
349        ACCOUNT_LOGE("HandleEvent %{public}s failed! userId %{public}d.", eventStr.c_str(), userId);
350        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
351    }
352
353    // update account info
354    currAccountInfo.ohosAccountInfo_ = ohosAccountInfo;
355    currAccountInfo.ohosAccountInfo_.SetRawUid(ohosAccountInfo.uid_);
356    currAccountInfo.ohosAccountInfo_.uid_ = ohosAccountUid;
357    currAccountInfo.ohosAccountInfo_.status_ = ACCOUNT_STATE_LOGIN;
358    currAccountInfo.bindTime_ = std::time(nullptr);
359    currAccountInfo.ohosAccountInfo_.callingUid_ = IPCSkeleton::GetCallingUid();
360
361    if (!SaveOhosAccountInfo(currAccountInfo)) {
362        ACCOUNT_LOGE("SaveOhosAccountInfo failed! userId %{public}d.", userId);
363        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
364    }
365    subscribeManager_.Publish(userId, DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE::LOGIN);
366
367#ifdef HAS_CES_PART
368    if (!isPubLoginEvent) {
369        AccountEventProvider::EventPublish(CommonEventSupport::COMMON_EVENT_USER_INFO_UPDATED, userId, nullptr);
370        (void)CreateCommonEventSubscribe();
371        return ERR_OK;
372    }
373    AccountEventProvider::EventPublishAsUser(CommonEventSupport::COMMON_EVENT_HWID_LOGIN, userId);
374    AccountEventProvider::EventPublishAsUser(
375        CommonEventSupport::COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGIN, userId);
376#else  // HAS_CES_PART
377    ACCOUNT_LOGI("No common event part, publish nothing!");
378#endif // HAS_CES_PART
379    (void)CreateCommonEventSubscribe();
380    ACCOUNT_LOGI("LoginOhosAccount success! userId %{public}d", userId);
381    return ERR_OK;
382}
383
384/**
385 * logout ohos (for distributed network) account.
386 *
387 * @param userId target local account id.
388 * @param ohosAccountInfo ohos account information
389 * @param eventStr ohos account state change event
390 * @return ERR_OK if the processing was completed
391 */
392ErrCode OhosAccountManager::LogoutOhosAccount(
393    const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)
394{
395    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
396
397    AccountInfo currentAccount;
398    if (!GetCurOhosAccountAndCheckMatch(currentAccount, ohosAccountInfo.name_,
399                                        ohosAccountInfo.uid_, userId)) {
400        ACCOUNT_LOGE("check match failed, userId %{public}d.", userId);
401        return ERR_ACCOUNT_COMMON_ACCOUNT_NOT_EXIST_ERROR;
402    }
403
404    bool ret = HandleEvent(currentAccount, eventStr); // update account status
405    if (!ret) {
406        ACCOUNT_LOGE("HandleEvent %{public}s failed, userId %{public}d.", eventStr.c_str(), userId);
407        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
408    }
409
410    ret = ClearOhosAccount(currentAccount); // clear account info with ACCOUNT_STATE_UNBOUND
411    if (!ret) {
412        ACCOUNT_LOGE("ClearOhosAccount failed! userId %{public}d.", userId);
413        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
414    }
415    subscribeManager_.Publish(userId, DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE::LOGOUT);
416
417#ifdef HAS_CES_PART
418    AccountEventProvider::EventPublishAsUser(
419        EventFwk::CommonEventSupport::COMMON_EVENT_HWID_LOGOUT, userId);
420    AccountEventProvider::EventPublishAsUser(
421        EventFwk::CommonEventSupport::COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGOUT, userId);
422#else  // HAS_CES_PART
423    ACCOUNT_LOGI("No common event part! Publish nothing!");
424#endif // HAS_CES_PART
425    ACCOUNT_LOGI("LogoutOhosAccount success, userId %{public}d.", userId);
426    return ERR_OK;
427}
428
429/**
430 * logoff ohos (for distributed network) account.
431 *
432 * @param userId target local account id.
433 * @param ohosAccountInfo ohos account information
434 * @param eventStr ohos account state change event
435 * @return ERR_OK if the processing was completed
436 */
437ErrCode OhosAccountManager::LogoffOhosAccount(
438    const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)
439{
440    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
441
442    AccountInfo currentAccount;
443    if (!GetCurOhosAccountAndCheckMatch(currentAccount, ohosAccountInfo.name_, ohosAccountInfo.uid_, userId)) {
444        ACCOUNT_LOGE("check match failed, userId %{public}d.", userId);
445        return ERR_ACCOUNT_COMMON_ACCOUNT_NOT_EXIST_ERROR;
446    }
447
448    bool ret = HandleEvent(currentAccount, eventStr); // update account status
449    if (!ret) {
450        ACCOUNT_LOGE("HandleEvent %{public}s failed, userId %{public}d.", eventStr.c_str(), userId);
451        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
452    }
453
454    ret = ClearOhosAccount(currentAccount); // clear account info with ACCOUNT_STATE_UNBOUND
455    if (!ret) {
456        ACCOUNT_LOGE("ClearOhosAccount failed, userId %{public}d.", userId);
457        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
458    }
459    subscribeManager_.Publish(userId, DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE::LOGOFF);
460
461#ifdef HAS_CES_PART
462    AccountEventProvider::EventPublishAsUser(
463        EventFwk::CommonEventSupport::COMMON_EVENT_HWID_LOGOFF, userId);
464    AccountEventProvider::EventPublishAsUser(
465        EventFwk::CommonEventSupport::COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGOFF, userId);
466#else  // HAS_CES_PART
467    ACCOUNT_LOGI("No common event part, publish nothing for logoff!");
468#endif // HAS_CES_PART
469    ACCOUNT_LOGI("LogoffOhosAccount success, userId %{public}d.", userId);
470    return ERR_OK;
471}
472
473/**
474 * Handle token_invalid event.
475 *
476 * @param userId target local account id.
477 * @param ohosAccountInfo ohos account information
478 * @param eventStr ohos account state change event
479 * @return ERR_OK if the processing was completed
480 */
481ErrCode OhosAccountManager::HandleOhosAccountTokenInvalidEvent(
482    const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)
483{
484    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
485
486    AccountInfo currentOhosAccount;
487    if (!GetCurOhosAccountAndCheckMatch(currentOhosAccount, ohosAccountInfo.name_,
488                                        ohosAccountInfo.uid_, userId)) {
489        ACCOUNT_LOGE("check match failed, userId %{public}d.", userId);
490        return ERR_ACCOUNT_COMMON_ACCOUNT_NOT_EXIST_ERROR;
491    }
492
493    bool ret = HandleEvent(currentOhosAccount, eventStr); // update account status
494    if (!ret) {
495        ACCOUNT_LOGE("HandleEvent %{public}s failed, userId %{public}d.", eventStr.c_str(), userId);
496        return ERR_ACCOUNT_ZIDL_ACCOUNT_SERVICE_ERROR;
497    }
498
499    ret = SaveOhosAccountInfo(currentOhosAccount);
500    if (!ret) {
501        // moving on even if failed to update account info
502        ACCOUNT_LOGW("SaveOhosAccountInfo failed, userId %{public}d.", userId);
503    }
504    subscribeManager_.Publish(userId, DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE::TOKEN_INVALID);
505
506#ifdef HAS_CES_PART
507    AccountEventProvider::EventPublishAsUser(
508        EventFwk::CommonEventSupport::COMMON_EVENT_HWID_TOKEN_INVALID, userId);
509    AccountEventProvider::EventPublishAsUser(
510        EventFwk::CommonEventSupport::COMMON_EVENT_DISTRIBUTED_ACCOUNT_TOKEN_INVALID, userId);
511#else  // HAS_CES_PART
512    ACCOUNT_LOGI("No common event part, publish nothing for token invalid event.");
513#endif // HAS_CES_PART
514    ACCOUNT_LOGI("success, userId %{public}d.", userId);
515    return ERR_OK;
516}
517
518/**
519 * Init event mapper.
520 */
521void OhosAccountManager::BuildEventsMapper()
522{
523    const std::map<std::string, std::string> accountEventMap = AccountHelperData::GetAccountEventMap();
524    std::string eventLogin = GetAccountEventStr(accountEventMap, KEY_ACCOUNT_EVENT_LOGIN, OHOS_ACCOUNT_EVENT_LOGIN);
525    std::string eventLogout = GetAccountEventStr(accountEventMap, KEY_ACCOUNT_EVENT_LOGOUT, OHOS_ACCOUNT_EVENT_LOGOUT);
526    std::string eventTokenInvalid = GetAccountEventStr(accountEventMap, KEY_ACCOUNT_EVENT_TOKEN_INVALID,
527        OHOS_ACCOUNT_EVENT_TOKEN_INVALID);
528    std::string eventLogoff = GetAccountEventStr(accountEventMap, KEY_ACCOUNT_EVENT_LOGOFF, OHOS_ACCOUNT_EVENT_LOGOFF);
529
530    eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(eventLogin, ACCOUNT_BIND_SUCCESS_EVT));
531    eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(eventLogout, ACCOUNT_MANUAL_UNBOUND_EVT));
532    eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(eventTokenInvalid, ACCOUNT_TOKEN_EXPIRED_EVT));
533    eventMap_.insert(std::pair<std::string, ACCOUNT_INNER_EVENT_TYPE>(eventLogoff, ACCOUNT_MANUAL_LOGOFF_EVT));
534
535    eventFuncMap_.insert(std::make_pair(eventLogin,
536        [this] (const std::int32_t userId, const OhosAccountInfo &info, const std::string &eventStr) {
537        return LoginOhosAccount(userId, info, eventStr);
538    }));
539    eventFuncMap_.insert(std::make_pair(eventLogout,
540        [this] (const std::int32_t userId, const OhosAccountInfo &info, const std::string &eventStr) {
541        return LogoutOhosAccount(userId, info, eventStr);
542    }));
543    eventFuncMap_.insert(std::make_pair(eventLogoff,
544        [this] (const std::int32_t userId, const OhosAccountInfo &info, const std::string &eventStr) {
545        return LogoffOhosAccount(userId, info, eventStr);
546    }));
547    eventFuncMap_.insert(std::make_pair(eventTokenInvalid,
548        [this] (const std::int32_t userId, const OhosAccountInfo &info, const std::string &eventStr) {
549        return HandleOhosAccountTokenInvalidEvent(userId, info, eventStr);
550    }));
551}
552
553OhosAccountManager &OhosAccountManager::GetInstance()
554{
555    static OhosAccountManager *instance = new (std::nothrow) OhosAccountManager();
556    return *instance;
557}
558
559OhosAccountManager::OhosAccountManager() : subscribeManager_(DistributedAccountSubscribeManager::GetInstance())
560{
561    accountState_ = std::make_unique<AccountStateMachine>();
562    dataDealer_ = std::make_unique<OhosAccountDataDeal>(ACCOUNT_CFG_DIR_ROOT_PATH);
563    BuildEventsMapper();
564}
565
566/**
567 * Init ohos account manager.
568 *
569 */
570bool OhosAccountManager::OnInitialize()
571{
572    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
573    if (isInit_) {
574        return true;
575    }
576
577    std::int32_t tryTimes = 0;
578    while (tryTimes < MAX_RETRY_TIMES) {
579        tryTimes++;
580        ErrCode errCode = dataDealer_->Init(DEVICE_ACCOUNT_OWNER);
581        if (errCode == ERR_OK) {
582            break;
583        }
584
585        // when json file corrupted, have it another try
586        if ((tryTimes == MAX_RETRY_TIMES) || (errCode != ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION)) {
587            ACCOUNT_LOGE("parse json file failed: %{public}d, tryTime: %{public}d", errCode, tryTimes);
588            eventMap_.clear();
589            eventFuncMap_.clear();
590            return false;
591        }
592    }
593    isInit_ = true;
594    return true;
595}
596
597#ifdef HAS_CES_PART
598bool OhosAccountManager::CreateCommonEventSubscribe()
599{
600    if (accountEventSubscribe_ == nullptr) {
601        AccountCommonEventCallback callback = {
602            [this](int32_t userId) { this->OnPackageRemoved(userId); } };
603        accountEventSubscribe_ = std::make_shared<AccountEventSubscriber>(callback);
604        if (!accountEventSubscribe_->CreateEventSubscribe()) {
605            ACCOUNT_LOGE("CreateEventSubscribe is failed");
606            return false;
607        }
608    }
609    return true;
610}
611
612void OhosAccountManager::OnPackageRemoved(const std::int32_t callingUid)
613{
614    std::vector<OsAccountInfo> osAccountInfos;
615    (void)IInnerOsAccountManager::GetInstance().QueryAllCreatedOsAccounts(osAccountInfos);
616    for (const auto &info : osAccountInfos) {
617        AccountInfo accountInfo;
618        (void)GetAccountInfoByUserId(info.GetLocalId(), accountInfo);
619        if (accountInfo.ohosAccountInfo_.callingUid_ == callingUid) {
620            (void)ClearOhosAccount(accountInfo);
621            AccountEventProvider::EventPublishAsUser(
622                EventFwk::CommonEventSupport::COMMON_EVENT_HWID_LOGOUT, info.GetLocalId());
623            AccountEventProvider::EventPublishAsUser(
624                EventFwk::CommonEventSupport::COMMON_EVENT_DISTRIBUTED_ACCOUNT_LOGOUT, info.GetLocalId());
625        }
626    }
627}
628#endif // HAS_CES_PART
629
630/**
631 * Handle device account switch event.
632 *
633 * @param None
634 * @return None
635 */
636void OhosAccountManager::HandleDevAccountSwitchEvent()
637{
638    std::lock_guard<std::mutex> mutexLock(mgrMutex_);
639    eventMap_.clear();
640    eventFuncMap_.clear();
641
642    // Re-Init
643    if (!OnInitialize()) {
644        ACCOUNT_LOGE("Handle dev Account SwitchEvent failed");
645    }
646}
647
648bool OhosAccountManager::CheckOhosAccountCanBind(const AccountInfo &currAccountInfo,
649    const OhosAccountInfo &newOhosAccountInfo, const std::string &newOhosUid) const
650{
651    if (newOhosUid.length() != OHOS_ACCOUNT_UDID_LENGTH) {
652        ACCOUNT_LOGE("newOhosUid invalid length, %{public}s.", newOhosUid.c_str());
653        return false;
654    }
655
656    // check if current account has been bound or not
657    if ((currAccountInfo.ohosAccountInfo_.status_ == ACCOUNT_STATE_LOGIN) &&
658        ((currAccountInfo.ohosAccountInfo_.uid_ != newOhosUid) ||
659        (currAccountInfo.ohosAccountInfo_.name_ != newOhosAccountInfo.name_))) {
660        ACCOUNT_LOGE("current account has already been bounded. callingUserId %{public}d.",
661            AccountMgrService::GetInstance().GetCallingUserID());
662        return false;
663    }
664
665    // check whether newOhosUid has been already bound to another account or not
666    DIR* rootDir = opendir(ACCOUNT_CFG_DIR_ROOT_PATH.c_str());
667    if (rootDir == nullptr) {
668        ACCOUNT_LOGE("cannot open dir %{public}s, err %{public}d.", ACCOUNT_CFG_DIR_ROOT_PATH.c_str(), errno);
669        return false;
670    }
671    struct dirent* curDir = nullptr;
672    while ((curDir = readdir(rootDir)) != nullptr) {
673        std::string curDirName(curDir->d_name);
674        if (curDirName == "." || curDirName == ".." || curDir->d_type != DT_DIR) {
675            continue;
676        }
677
678        AccountInfo curInfo;
679        std::stringstream sstream;
680        sstream << curDirName;
681        std::int32_t userId = -1;
682        sstream >> userId;
683        if (dataDealer_->AccountInfoFromJson(curInfo, userId) != ERR_OK) {
684            ACCOUNT_LOGI("get ohos account info from user %{public}s failed.", curDirName.c_str());
685            continue;
686        }
687
688        if (curInfo.ohosAccountInfo_.status_ != ACCOUNT_STATE_LOGIN) {
689            continue; // account not bind, skip check
690        }
691    }
692
693    (void)closedir(rootDir);
694    return true;
695}
696
697bool OhosAccountManager::GetCurOhosAccountAndCheckMatch(AccountInfo &curAccountInfo,
698                                                        const std::string &inputName,
699                                                        const std::string &inputUid,
700                                                        const std::int32_t callingUserId) const
701{
702    if (dataDealer_->AccountInfoFromJson(curAccountInfo, callingUserId) != ERR_OK) {
703        ACCOUNT_LOGE("cannot read from config, inputName %{public}s.", inputName.c_str());
704        return false;
705    }
706
707    std::string ohosAccountUid = GenerateOhosUdidWithSha256(inputName, inputUid);
708    if (inputName != curAccountInfo.ohosAccountInfo_.name_ ||
709        ohosAccountUid != curAccountInfo.ohosAccountInfo_.uid_) {
710        ACCOUNT_LOGE("account name %{public}s or ohosAccountUid %{public}s mismatch, calling user %{public}d.",
711            inputName.c_str(), ohosAccountUid.c_str(), callingUserId);
712        return false;
713    }
714    return true;
715}
716} // namespace AccountSA
717} // namespace OHOS
718