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