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