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