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