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