• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 #include <cerrno>
16 #include <cstdio>
17 #include <fstream>
18 #include <iostream>
19 #include <unistd.h>
20 #include <vector>
21 #include "account_error_no.h"
22 #include "account_info.h"
23 #include "account_log_wrapper.h"
24 #include "directory_ex.h"
25 #include "file_ex.h"
26 #include "account_hisysevent_adapter.h"
27 #include "iinner_os_account_manager.h"
28 #include "ohos_account_data_deal.h"
29 
30 namespace OHOS {
31 namespace AccountSA {
32 namespace {
33 const char ACCOUNT_CFG_FILE_NAME[] = "/account.json";
34 const char ACCOUNT_AVATAR_NAME[] = "/account_avatar";
35 const char DATADEAL_JSON_KEY_OHOSACCOUNT_NAME[] = "account_name";
36 const char DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID[] = "raw_uid";
37 const char DATADEAL_JSON_KEY_OHOSACCOUNT_UID[] = "open_id";
38 const char DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS[] = "bind_status";
39 const char DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID[] = "calling_uid";
40 const char DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME[] = "account_nickname";
41 const char DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR[] = "account_avatar";
42 const char DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA[] = "account_scalableData";
43 const char DATADEAL_JSON_KEY_OHOSACCOUNT_VERSION[] = "version";
44 const char DATADEAL_JSON_KEY_USERID[] = "user_id";
45 const char DATADEAL_JSON_KEY_BIND_TIME[] = "bind_time";
46 #ifdef ENABLE_FILE_WATCHER
47 const uint32_t ALG_COMMON_SIZE = 32;
48 #endif // ENABLE_FILE_WATCHER
49 } // namespace
50 
51 #ifdef ENABLE_FILE_WATCHER
OhosAccountDataDeal(const std::string & configFileDir)52 OhosAccountDataDeal::OhosAccountDataDeal(const std::string &configFileDir)
53     : configFileDir_(configFileDir),
54     accountFileWatcherMgr_(AccountFileWatcherMgr::GetInstance())
55 {
56     accountFileOperator_ = accountFileWatcherMgr_.accountFileOperator_;
57     initOk_ = false;
58     checkCallbackFunc_ = [this](const std::string &fileName, int32_t id, uint32_t event) {
59         ACCOUNT_LOGI("inotify event = %{public}d, fileName = %{public}s", event, fileName.c_str());
60         switch (event) {
61             case IN_MODIFY: {
62                 return DealWithFileModifyEvent(fileName, id);
63             }
64             case IN_MOVE_SELF: {
65                 accountFileWatcherMgr_.RemoveFileWatcher(id, fileName);
66                 ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
67                 break;
68             }
69             case IN_DELETE_SELF: {
70                 DealWithFileDeleteEvent(fileName, id);
71                 break;
72             }
73             default: {
74                 ACCOUNT_LOGW("get event invalid!");
75                 return false;
76             }
77         }
78         return true;
79     };
80 }
81 #else
OhosAccountDataDeal(const std::string & configFileDir)82 OhosAccountDataDeal::OhosAccountDataDeal(const std::string &configFileDir)
83     : configFileDir_(configFileDir)
84 {
85     accountFileOperator_ = std::make_shared<AccountFileOperator>();
86     initOk_ = false;
87 }
88 #endif // ENABLE_FILE_WATCHER
89 
90 #ifdef ENABLE_FILE_WATCHER
DealWithFileModifyEvent(const std::string & fileName,const int32_t id)91 bool OhosAccountDataDeal::DealWithFileModifyEvent(const std::string &fileName, const int32_t id)
92 {
93     ACCOUNT_LOGI("enter");
94     {
95         std::unique_lock<std::shared_timed_mutex> lock(accountFileOperator_->fileLock_);
96         if (accountFileOperator_->GetValidModifyFileOperationFlag(fileName)) {
97             ACCOUNT_LOGD("this is valid service operate, no need to deal with it.");
98             accountFileOperator_->SetValidModifyFileOperationFlag(fileName, false);
99             return true;
100         }
101     }
102     std::lock_guard<std::mutex> lock(accountInfoFileLock_);
103     std::string fileInfoStr;
104     if (accountFileOperator_->GetFileContentByPath(fileName, fileInfoStr) != ERR_OK) {
105         ACCOUNT_LOGE("get content from file %{public}s failed!", fileName.c_str());
106         return false;
107     }
108     uint8_t localDigestData[ALG_COMMON_SIZE] = {0};
109     accountFileWatcherMgr_.GetAccountInfoDigestFromFile(fileName, localDigestData, ALG_COMMON_SIZE);
110 #ifdef HAS_HUKS_PART
111     uint8_t newDigestData[ALG_COMMON_SIZE] = {0};
112     GenerateAccountInfoDigest(fileInfoStr, newDigestData, ALG_COMMON_SIZE);
113     if (memcmp(localDigestData, newDigestData, ALG_COMMON_SIZE) == 0) {
114         ACCOUNT_LOGD("No need to recover local file data.");
115         return true;
116     }
117 #endif // HAS_HUKS_PART
118     ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
119     return true;
120 }
121 
DealWithFileDeleteEvent(const std::string & fileName,const int32_t id)122 void OhosAccountDataDeal::DealWithFileDeleteEvent(const std::string &fileName, const int32_t id)
123 {
124     {
125         std::unique_lock<std::shared_timed_mutex> lock(accountFileOperator_->fileLock_);
126         if (accountFileOperator_->GetValidDeleteFileOperationFlag(fileName)) {
127             ACCOUNT_LOGD("this is valid service operate, no need to deal with it.");
128             accountFileOperator_->SetValidDeleteFileOperationFlag(fileName, false);
129             accountFileWatcherMgr_.RemoveFileWatcher(id, fileName);
130             return;
131         }
132         std::string fileDir = configFileDir_ + std::to_string(id);
133         if (!accountFileOperator_->IsExistDir(fileDir)) {
134             ACCOUNT_LOGI("this id is already removed.");
135             return;
136         }
137     }
138     ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
139 }
140 
AddFileWatcher(const int32_t id)141 void OhosAccountDataDeal::AddFileWatcher(const int32_t id)
142 {
143     std::string configFile = configFileDir_ + std::to_string(id) + ACCOUNT_CFG_FILE_NAME;
144     accountFileWatcherMgr_.AddFileWatcher(id, checkCallbackFunc_, configFile);
145 }
146 #endif // ENABLE_FILE_WATCHER
147 
Init(int32_t userId)148 ErrCode OhosAccountDataDeal::Init(int32_t userId)
149 {
150     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
151     if (!accountFileOperator_->IsExistFile(configFile)) {
152         ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
153         BuildJsonFileFromScratch(userId);
154     }
155 
156     std::ifstream fin(configFile);
157     if (!fin) {
158         int32_t err = errno;
159         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", configFile.c_str(), err);
160         ReportOhosAccountOperationFail(userId, OPERATION_INIT_OPEN_FILE_TO_READ, err, configFile);
161         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
162     }
163 
164     // NOT-allow exceptions when parse json file
165     std::lock_guard<std::mutex> lock(mutex_);
166     nlohmann::json jsonData = json::parse(fin, nullptr, false);
167     fin.close();
168     if (jsonData.is_discarded() || !jsonData.is_structured()) {
169         ACCOUNT_LOGE("Invalid json file, remove");
170         if (RemoveFile(configFile)) {
171             int32_t err = errno;
172             ACCOUNT_LOGE("Remove invalid json file %{public}s failed, errno %{public}d.", configFile.c_str(), err);
173             ReportOhosAccountOperationFail(userId, OPERATION_REMOVE_FILE, err, configFile);
174         }
175         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
176     }
177 
178     // recover watch for exist account info
179     std::vector<OsAccountInfo> osAccountInfos;
180     IInnerOsAccountManager::GetInstance().QueryAllCreatedOsAccounts(osAccountInfos);
181 #ifdef ENABLE_FILE_WATCHER
182     for (const auto &info : osAccountInfos) {
183         AddFileWatcher(info.GetLocalId());
184     }
185 #endif // ENABLE_FILE_WATCHER
186     initOk_ = true;
187     return ERR_OK;
188 }
189 
AccountInfoFromJson(AccountInfo & accountInfo,int32_t userId)190 ErrCode OhosAccountDataDeal::AccountInfoFromJson(AccountInfo &accountInfo, int32_t userId)
191 {
192     if (!initOk_) {
193         ACCOUNT_LOGE("not init yet!");
194         return ERR_ACCOUNT_DATADEAL_NOT_READY;
195     }
196     return GetAccountInfo(accountInfo, userId);
197 }
198 
AccountInfoToJson(const AccountInfo & accountInfo)199 ErrCode OhosAccountDataDeal::AccountInfoToJson(const AccountInfo &accountInfo)
200 {
201     if (!initOk_) {
202         ACCOUNT_LOGE("Not init ok");
203         return ERR_ACCOUNT_DATADEAL_NOT_READY;
204     }
205     return SaveAccountInfo(accountInfo);
206 }
207 
SaveAccountInfo(const AccountInfo & accountInfo)208 ErrCode OhosAccountDataDeal::SaveAccountInfo(const AccountInfo &accountInfo)
209 {
210     std::lock_guard<std::mutex> lock(accountInfoFileLock_);
211     std::string scalableDataStr = (accountInfo.ohosAccountInfo_.scalableData_).ToString();
212     nlohmann::json jsonData = json {
213         {DATADEAL_JSON_KEY_OHOSACCOUNT_VERSION, accountInfo.version_},
214         {DATADEAL_JSON_KEY_BIND_TIME, accountInfo.bindTime_},
215         {DATADEAL_JSON_KEY_USERID, accountInfo.userId_},
216         {DATADEAL_JSON_KEY_OHOSACCOUNT_NAME, accountInfo.ohosAccountInfo_.name_},
217         {DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID, accountInfo.ohosAccountInfo_.GetRawUid()},
218         {DATADEAL_JSON_KEY_OHOSACCOUNT_UID, accountInfo.ohosAccountInfo_.uid_},
219         {DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS, accountInfo.ohosAccountInfo_.status_},
220         {DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID, accountInfo.ohosAccountInfo_.callingUid_},
221         {DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME, accountInfo.ohosAccountInfo_.nickname_},
222         {DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA, scalableDataStr}
223     };
224 
225     std::string avatarFile = configFileDir_ + std::to_string(accountInfo.userId_) + ACCOUNT_AVATAR_NAME;
226     ErrCode ret = accountFileOperator_->InputFileByPathAndContent(avatarFile, accountInfo.ohosAccountInfo_.avatar_);
227     if (ret != ERR_OK) {
228         ACCOUNT_LOGE("Failed to save avatar! ret = %{public}d", ret);
229         return ret;
230     }
231 
232     std::string accountInfoValue = jsonData.dump(-1, ' ', false, json::error_handler_t::ignore);
233     std::string configFile = configFileDir_ + std::to_string(accountInfo.userId_) + ACCOUNT_CFG_FILE_NAME;
234 
235     ret = accountFileOperator_->InputFileByPathAndContent(configFile, accountInfoValue);
236     if (ret == ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR) {
237         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_CHANGE_MODE_FILE, ret, configFile);
238     }
239     if (ret != ERR_OK && ret != ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR) {
240         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, ret, configFile);
241     }
242 #ifdef ENABLE_FILE_WATCHER
243     accountFileWatcherMgr_.AddAccountInfoDigest(accountInfoValue, configFile);
244 #endif // ENABLE_FILE_WATCHER
245     return ret;
246 }
247 
ParseJsonFromFile(const std::string & filePath,nlohmann::json & jsonData,int32_t userId)248 ErrCode OhosAccountDataDeal::ParseJsonFromFile(const std::string &filePath, nlohmann::json &jsonData, int32_t userId)
249 {
250     std::ifstream fin(filePath);
251     if (!fin) {
252         int32_t err = errno;
253         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", filePath.c_str(), err);
254         ReportOhosAccountOperationFail(userId, OPERATION_OPEN_FILE_TO_READ, err, filePath);
255         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
256     }
257     // NOT-allow exceptions when parse json file
258     jsonData = json::parse(fin, nullptr, false);
259     fin.close();
260     if (jsonData.is_discarded() || !jsonData.is_structured()) {
261         ACCOUNT_LOGE("Invalid json file,  %{public}s, remove", filePath.c_str());
262         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
263     }
264     std::string avatarData;
265     auto it = jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR);
266     if (it != jsonData.end()) {
267         if (it->is_string()) {
268             avatarData = it->get<std::string>();
269             jsonData[DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR] = avatarData;
270         }
271     } else {
272         std::string avatarFile = configFileDir_ + std::to_string(userId) + ACCOUNT_AVATAR_NAME;
273         if (accountFileOperator_->GetFileContentByPath(avatarFile, avatarData) == ERR_OK) {
274             jsonData[DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR] = avatarData;
275         }
276     }
277     return ERR_OK;
278 }
279 
280 template <typename T, typename Callback>
GetJsonField(const nlohmann::json & jsonData,const std::string & key,Callback callback)281 bool GetJsonField(const nlohmann::json &jsonData, const std::string &key, Callback callback)
282 {
283     auto it = jsonData.find(key);
284     if (it == jsonData.end()) {
285         return false;
286     }
287     if constexpr (std::is_same_v<T, int> || std::is_same_v<T, std::time_t>) {
288         if (!it->is_number()) {
289             return false;
290         }
291         T value = it->get<T>();
292         callback(value);
293         return true;
294     }
295     if constexpr (std::is_same_v<T, std::string>) {
296         if (!it->is_string()) {
297             return false;
298         }
299         T value = it->get<T>();
300         callback(value);
301         return true;
302     }
303     return false;
304 }
305 
GetAccountInfoFromJson(const nlohmann::json & jsonData,AccountInfo & accountInfo,const int32_t userId)306 ErrCode OhosAccountDataDeal::GetAccountInfoFromJson(
307     const nlohmann::json &jsonData, AccountInfo &accountInfo, const int32_t userId)
308 {
309     GetJsonField<int>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_VERSION, [&](int value) {
310         accountInfo.version_ = value;
311     });
312 
313     GetJsonField<std::time_t>(jsonData, DATADEAL_JSON_KEY_BIND_TIME, [&](std::time_t value) {
314         accountInfo.bindTime_ = value;
315     });
316 
317     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_NAME, [&](const std::string &value) {
318         accountInfo.ohosAccountInfo_.name_ = value;
319     });
320 
321     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID, [&](const std::string &value) {
322         accountInfo.ohosAccountInfo_.SetRawUid(value);
323     });
324 
325     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_UID, [&](const std::string &value) {
326         accountInfo.ohosAccountInfo_.uid_ = value;
327     });
328 
329     GetJsonField<int>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS, [&](int value) {
330         accountInfo.ohosAccountInfo_.status_ = value;
331     });
332 
333     GetJsonField<int>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID, [&](int value) {
334         accountInfo.ohosAccountInfo_.callingUid_ = value;
335     });
336 
337     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME, [&](const std::string &value) {
338         accountInfo.ohosAccountInfo_.nickname_ = value;
339     });
340 
341     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR, [&](const std::string &value) {
342         accountInfo.ohosAccountInfo_.avatar_ = value;
343     });
344 
345     GetJsonField<std::string>(jsonData, DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA, [&](std::string &value) {
346         sptr<AAFwk::Want> want = AAFwk::Want::FromString(value);
347         if (want != nullptr) {
348             accountInfo.ohosAccountInfo_.scalableData_ = *want;
349         }
350     });
351 
352     accountInfo.userId_ = userId;
353     return ERR_OK;
354 }
355 
GetAccountInfo(AccountInfo & accountInfo,const int32_t userId)356 ErrCode OhosAccountDataDeal::GetAccountInfo(AccountInfo &accountInfo, const int32_t userId)
357 {
358     if (userId < 0) {
359         ACCOUNT_LOGW("invalid userid = %{public}d", userId);
360         return ERR_OSACCOUNT_SERVICE_MANAGER_ID_ERROR;
361     }
362     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
363     ErrCode ret = accountFileOperator_->CheckFileExistence(configFile);
364     if (ret != ERR_OK) {
365         if (ret != ERR_ACCOUNT_COMMON_FILE_NOT_EXIST) {
366             std::string errorMsg = "Stat " + configFile + " failed";
367             ReportOhosAccountOperationFail(userId, OPERATION_OPEN_FILE_TO_READ, ret, errorMsg);
368             return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
369         } else {
370             ACCOUNT_LOGI("File %{public}s not exist, create!", configFile.c_str());
371             BuildJsonFileFromScratch(userId); // create default config file for first login
372         }
373     }
374     std::lock_guard<std::mutex> lock(mutex_);
375     nlohmann::json jsonData;
376     ret = ParseJsonFromFile(configFile, jsonData, userId);
377     if (ret != ERR_OK) {
378         return ret;
379     }
380     return GetAccountInfoFromJson(jsonData, accountInfo, userId);
381 }
382 
BuildJsonFileFromScratch(int32_t userId)383 void OhosAccountDataDeal::BuildJsonFileFromScratch(int32_t userId)
384 {
385     AccountInfo accountInfo;
386     accountInfo.userId_ = userId;
387     accountInfo.bindTime_ = 0;
388     accountInfo.ohosAccountInfo_.uid_ = DEFAULT_OHOS_ACCOUNT_UID;
389     accountInfo.ohosAccountInfo_.name_ = DEFAULT_OHOS_ACCOUNT_NAME;
390     accountInfo.ohosAccountInfo_.status_ = ACCOUNT_STATE_UNBOUND;
391     accountInfo.ohosAccountInfo_.callingUid_ = DEFAULT_CALLING_UID;
392     accountInfo.digest_ = "";
393     accountInfo.ohosAccountInfo_.SetRawUid(DEFAULT_OHOS_ACCOUNT_UID);
394     SaveAccountInfo(accountInfo);
395 #ifdef ENABLE_FILE_WATCHER
396     AddFileWatcher(userId);
397 #endif // ENABLE_FILE_WATCHER
398 }
399 } // namespace AccountSA
400 } // namespace OHOS