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)76 bool 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 
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 
GenerateOhosUdidWithSha256(const std::string &name, const std::string &uid)115 std::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  */
OhosAccountStateChange(const std::string &name, const std::string &uid, const std::string &eventStr)173 ErrCode 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 
OhosAccountStateChange( const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)188 ErrCode 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  */
ClearOhosAccount(AccountInfo &curOhosAccountInfo, std::int32_t clrStatus) const202 bool 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  */
SaveOhosAccountInfo(AccountInfo &ohosAccountInfo) const219 bool 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  */
GetCurrentOhosAccountInfo()234 AccountInfo 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 
GetAccountInfoByUserId(std::int32_t userId, AccountInfo &info)247 ErrCode 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 
SubscribeDistributedAccountEvent(const DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE type, const sptr<IRemoteObject> &eventListener)263 ErrCode OhosAccountManager::SubscribeDistributedAccountEvent(const DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE type,
264     const sptr<IRemoteObject> &eventListener)
265 {
266     return subscribeManager_.SubscribeDistributedAccountEvent(type, eventListener);
267 }
268 
UnsubscribeDistributedAccountEvent(const DISTRIBUTED_ACCOUNT_SUBSCRIBE_TYPE type, const sptr<IRemoteObject> &eventListener)269 ErrCode 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  */
GetCurrentOhosAccountState()280 std::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  */
HandleEvent(AccountInfo &curOhosAccount, const std::string &eventStr)292 bool 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  */
LoginOhosAccount(const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)322 ErrCode 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  */
LogoutOhosAccount( const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)392 ErrCode 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  */
LogoffOhosAccount( const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)437 ErrCode 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  */
HandleOhosAccountTokenInvalidEvent( const int32_t userId, const OhosAccountInfo &ohosAccountInfo, const std::string &eventStr)481 ErrCode 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  */
BuildEventsMapper()521 void 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 
GetInstance()553 OhosAccountManager &OhosAccountManager::GetInstance()
554 {
555     static OhosAccountManager *instance = new (std::nothrow) OhosAccountManager();
556     return *instance;
557 }
558 
OhosAccountManager()559 OhosAccountManager::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  */
OnInitialize()570 bool 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
CreateCommonEventSubscribe()598 bool 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 
OnPackageRemoved(const std::int32_t callingUid)612 void 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  */
HandleDevAccountSwitchEvent()636 void 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 
CheckOhosAccountCanBind(const AccountInfo &currAccountInfo, const OhosAccountInfo &newOhosAccountInfo, const std::string &newOhosUid) const648 bool 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 
GetCurOhosAccountAndCheckMatch(AccountInfo &curAccountInfo, const std::string &inputName, const std::string &inputUid, const std::int32_t callingUserId) const697 bool 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