• 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 "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 std::string ACCOUNT_CFG_FILE_NAME = "/account.json";
34 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_NAME = "account_name";
35 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID = "raw_uid";
36 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_UID = "open_id";
37 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS = "bind_status";
38 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID = "calling_uid";
39 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME = "account_nickname";
40 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR = "account_avatar";
41 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA = "account_scalableData";
42 const std::string DATADEAL_JSON_KEY_USERID = "user_id";
43 const std::string DATADEAL_JSON_KEY_BIND_TIME = "bind_time";
44 const uint32_t ALG_COMMON_SIZE = 32;
45 } // namespace
46 
OhosAccountDataDeal(const std::string & configFileDir)47 OhosAccountDataDeal::OhosAccountDataDeal(const std::string &configFileDir)
48     : configFileDir_(configFileDir),
49     accountFileWatcherMgr_(AccountFileWatcherMgr::GetInstance())
50 {
51     accountFileOperator_ = accountFileWatcherMgr_.accountFileOperator_;
52     initOk_ = false;
53     checkCallbackFunc_ = [this](const std::string &fileName, const int32_t id, uint32_t event) {
54         ACCOUNT_LOGI("inotify event = %{public}d, fileName = %{public}s", event, fileName.c_str());
55         switch (event) {
56             case IN_MODIFY: {
57                 return DealWithFileModifyEvent(fileName, id);
58             }
59             case IN_MOVE_SELF: {
60                 accountFileWatcherMgr_.RemoveFileWatcher(id, fileName);
61                 ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
62                 break;
63             }
64             case IN_DELETE_SELF: {
65                 DealWithFileDeleteEvent(fileName, id);
66                 break;
67             }
68             default: {
69                 ACCOUNT_LOGW("get event invalid!");
70                 return false;
71             }
72         }
73         return true;
74     };
75 }
76 
DealWithFileModifyEvent(const std::string & fileName,const int32_t id)77 bool OhosAccountDataDeal::DealWithFileModifyEvent(const std::string &fileName, const int32_t id)
78 {
79     ACCOUNT_LOGI("enter");
80     {
81         std::shared_lock<std::shared_timed_mutex> lock(accountFileOperator_->fileLock_);
82         if (accountFileOperator_->GetValidModifyFileOperationFlag(fileName)) {
83             ACCOUNT_LOGD("this is valid service operate, no need to deal with it.");
84             accountFileOperator_->SetValidModifyFileOperationFlag(fileName, false);
85             return true;
86         }
87     }
88     std::lock_guard<std::mutex> lock(accountInfoFileLock_);
89     std::string fileInfoStr;
90     if (accountFileOperator_->GetFileContentByPath(fileName, fileInfoStr) != ERR_OK) {
91         ACCOUNT_LOGE("get content from file %{public}s failed!", fileName.c_str());
92         return false;
93     }
94     uint8_t localDigestData[ALG_COMMON_SIZE] = {0};
95     accountFileWatcherMgr_.GetAccountInfoDigestFromFile(fileName, localDigestData, ALG_COMMON_SIZE);
96     uint8_t newDigestData[ALG_COMMON_SIZE] = {0};
97     GenerateAccountInfoDigest(fileInfoStr, newDigestData, ALG_COMMON_SIZE);
98     if (memcmp(localDigestData, newDigestData, ALG_COMMON_SIZE) == 0) {
99         ACCOUNT_LOGD("No need to recover local file data.");
100         return true;
101     }
102     ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
103     return true;
104 }
105 
DealWithFileDeleteEvent(const std::string & fileName,const int32_t id)106 void OhosAccountDataDeal::DealWithFileDeleteEvent(const std::string &fileName, const int32_t id)
107 {
108     {
109         std::shared_lock<std::shared_timed_mutex> lock(accountFileOperator_->fileLock_);
110         if (accountFileOperator_->GetValidDeleteFileOperationFlag(fileName)) {
111             ACCOUNT_LOGD("this is valid service operate, no need to deal with it.");
112             accountFileOperator_->SetValidDeleteFileOperationFlag(fileName, false);
113             accountFileWatcherMgr_.RemoveFileWatcher(id, fileName);
114             return;
115         }
116         std::string fileDir = configFileDir_ + std::to_string(id);
117         if (!accountFileOperator_->IsExistDir(fileDir)) {
118             ACCOUNT_LOGI("this id is already removed.");
119             return;
120         }
121     }
122     ReportOsAccountDataTampered(id, fileName, "DISTRIBUTED_ACCOUT_INFO");
123 }
124 
AddFileWatcher(const int32_t id)125 void OhosAccountDataDeal::AddFileWatcher(const int32_t id)
126 {
127     std::string configFile = configFileDir_ + std::to_string(id) + ACCOUNT_CFG_FILE_NAME;
128     accountFileWatcherMgr_.AddFileWatcher(id, checkCallbackFunc_, configFile);
129 }
130 
Init(int32_t userId)131 ErrCode OhosAccountDataDeal::Init(int32_t userId)
132 {
133     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
134     if (!FileExists(configFile)) {
135         ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
136         BuildJsonFileFromScratch(userId);
137     }
138 
139     std::ifstream fin(configFile);
140     if (!fin) {
141         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", configFile.c_str(), errno);
142         ReportOhosAccountOperationFail(userId, OPERATION_INIT_OPEN_FILE_TO_READ, errno, configFile);
143         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
144     }
145 
146     // NOT-allow exceptions when parse json file
147     std::lock_guard<std::mutex> lock(mutex_);
148     nlohmann::json jsonData = json::parse(fin, nullptr, false);
149     fin.close();
150     if (!jsonData.is_structured()) {
151         ACCOUNT_LOGE("Invalid json file, remove");
152         if (RemoveFile(configFile)) {
153             ACCOUNT_LOGE("Remove invalid json file %{public}s failed, errno %{public}d.", configFile.c_str(), errno);
154             ReportOhosAccountOperationFail(userId, OPERATION_REMOVE_FILE, errno, configFile);
155         }
156         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
157     }
158 
159     // recover watch for exist account info
160     std::vector<OsAccountInfo> osAccountInfos;
161     IInnerOsAccountManager::GetInstance().QueryAllCreatedOsAccounts(osAccountInfos);
162     for (const auto &info : osAccountInfos) {
163         AddFileWatcher(info.GetLocalId());
164     }
165     initOk_ = true;
166     return ERR_OK;
167 }
168 
AccountInfoFromJson(AccountInfo & accountInfo,int32_t userId)169 ErrCode OhosAccountDataDeal::AccountInfoFromJson(AccountInfo &accountInfo, int32_t userId)
170 {
171     if (!initOk_) {
172         ACCOUNT_LOGE("not init yet!");
173         return ERR_ACCOUNT_DATADEAL_NOT_READY;
174     }
175     return GetAccountInfo(accountInfo, userId);
176 }
177 
AccountInfoToJson(const AccountInfo & accountInfo)178 ErrCode OhosAccountDataDeal::AccountInfoToJson(const AccountInfo &accountInfo)
179 {
180     if (!initOk_) {
181         ACCOUNT_LOGE("Not init ok");
182         return ERR_ACCOUNT_DATADEAL_NOT_READY;
183     }
184     return SaveAccountInfo(accountInfo);
185 }
186 
SaveAccountInfo(const AccountInfo & accountInfo)187 ErrCode OhosAccountDataDeal::SaveAccountInfo(const AccountInfo &accountInfo)
188 {
189     std::lock_guard<std::mutex> lock(accountInfoFileLock_);
190     std::string scalableDataStr = (accountInfo.ohosAccountInfo_.scalableData_).ToString();
191     nlohmann::json jsonData = json {
192         {DATADEAL_JSON_KEY_BIND_TIME, accountInfo.bindTime_},
193         {DATADEAL_JSON_KEY_USERID, accountInfo.userId_},
194         {DATADEAL_JSON_KEY_OHOSACCOUNT_NAME, accountInfo.ohosAccountInfo_.name_},
195         {DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID, accountInfo.ohosAccountInfo_.GetRawUid()},
196         {DATADEAL_JSON_KEY_OHOSACCOUNT_UID, accountInfo.ohosAccountInfo_.uid_},
197         {DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS, accountInfo.ohosAccountInfo_.status_},
198         {DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID, accountInfo.ohosAccountInfo_.callingUid_},
199         {DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME, accountInfo.ohosAccountInfo_.nickname_},
200         {DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR, accountInfo.ohosAccountInfo_.avatar_},
201         {DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA, scalableDataStr}
202     };
203     std::string accountInfoValue = jsonData.dump(-1, ' ', false, json::error_handler_t::ignore);
204     std::string configFile = configFileDir_ + std::to_string(accountInfo.userId_) + ACCOUNT_CFG_FILE_NAME;
205 
206     ErrCode ret = accountFileOperator_->InputFileByPathAndContent(configFile, accountInfoValue);
207     if (ret == ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR) {
208         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_CHANGE_MODE_FILE, errno, configFile);
209     }
210     if (ret != ERR_OK && ret != ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR) {
211         ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
212     }
213     accountFileWatcherMgr_.AddAccountInfoDigest(accountInfoValue, configFile);
214     return ret;
215 }
216 
ParseJsonFromFile(const std::string & filePath,nlohmann::json & jsonData,int32_t userId)217 ErrCode OhosAccountDataDeal::ParseJsonFromFile(const std::string &filePath, nlohmann::json &jsonData, int32_t userId)
218 {
219     std::ifstream fin(filePath);
220     if (!fin) {
221         ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", filePath.c_str(), errno);
222         ReportOhosAccountOperationFail(userId, OPERATION_OPEN_FILE_TO_READ, errno, filePath);
223         return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
224     }
225     // NOT-allow exceptions when parse json file
226     jsonData = json::parse(fin, nullptr, false);
227     fin.close();
228     if (!jsonData.is_structured()) {
229         ACCOUNT_LOGE("Invalid json file,  %{public}s, remove", filePath.c_str());
230         return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
231     }
232     return ERR_OK;
233 }
234 
GetAccountInfoFromJson(const nlohmann::json & jsonData,AccountInfo & accountInfo,const int32_t userId)235 ErrCode OhosAccountDataDeal::GetAccountInfoFromJson(
236     const nlohmann::json &jsonData, AccountInfo &accountInfo, const int32_t userId)
237 {
238     const auto &jsonObjectEnd = jsonData.end();
239     if ((jsonData.find(DATADEAL_JSON_KEY_BIND_TIME) != jsonObjectEnd) &&
240         (jsonData.at(DATADEAL_JSON_KEY_BIND_TIME).is_number())) {
241         accountInfo.bindTime_ = jsonData.at(DATADEAL_JSON_KEY_BIND_TIME).get<std::time_t>();
242     }
243 
244     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME) != jsonObjectEnd) &&
245         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME).is_string())) {
246         accountInfo.ohosAccountInfo_.name_ = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME).get<std::string>();
247     }
248 
249     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID) != jsonObjectEnd) &&
250         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID).is_string())) {
251         std::string rawUid = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID).get<std::string>();
252         accountInfo.ohosAccountInfo_.SetRawUid(rawUid);
253     }
254 
255     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_UID) != jsonObjectEnd) &&
256         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_UID).is_string())) {
257         accountInfo.ohosAccountInfo_.uid_ = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_UID).get<std::string>();
258     }
259 
260     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS) != jsonObjectEnd) &&
261         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS).is_number())) {
262         accountInfo.ohosAccountInfo_.status_ = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS).get<int32_t>();
263     }
264 
265     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID) != jsonObjectEnd) &&
266         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID).is_number())) {
267         accountInfo.ohosAccountInfo_.callingUid_ =
268             jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_CALLINGUID).get<int32_t>();
269     }
270 
271     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME) != jsonObjectEnd) &&
272         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME).is_string())) {
273         accountInfo.ohosAccountInfo_.nickname_ =
274             jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME).get<std::string>();
275     }
276 
277     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR) != jsonObjectEnd) &&
278         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR).is_string())) {
279         accountInfo.ohosAccountInfo_.avatar_ = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR).get<std::string>();
280     }
281 
282     if ((jsonData.find(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA) != jsonObjectEnd) &&
283         (jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA).is_string())) {
284         auto scalableDataJson = jsonData.at(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA).get<std::string>();
285         sptr<AAFwk::Want> want = AAFwk::Want::FromString(scalableDataJson);
286         if (want == nullptr) {
287             return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
288         }
289         accountInfo.ohosAccountInfo_.scalableData_ = *want;
290     }
291     accountInfo.userId_ = userId;
292     return ERR_OK;
293 }
294 
GetAccountInfo(AccountInfo & accountInfo,const int32_t userId)295 ErrCode OhosAccountDataDeal::GetAccountInfo(AccountInfo &accountInfo, const int32_t userId)
296 {
297     if (userId < 0) {
298         ACCOUNT_LOGW("invalid userid = %{public}d", userId);
299         return ERR_OSACCOUNT_SERVICE_MANAGER_ID_ERROR;
300     }
301     std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
302     if (!FileExists(configFile)) {
303         ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
304         BuildJsonFileFromScratch(userId); // create default config file for first login
305     }
306     std::lock_guard<std::mutex> lock(mutex_);
307     nlohmann::json jsonData;
308     ErrCode ret = ParseJsonFromFile(configFile, jsonData, userId);
309     if (ret != ERR_OK) {
310         return ret;
311     }
312     return GetAccountInfoFromJson(jsonData, accountInfo, userId);
313 }
314 
BuildJsonFileFromScratch(int32_t userId)315 void OhosAccountDataDeal::BuildJsonFileFromScratch(int32_t userId)
316 {
317     AccountInfo accountInfo;
318     accountInfo.userId_ = userId;
319     accountInfo.bindTime_ = 0;
320     accountInfo.ohosAccountInfo_.uid_ = DEFAULT_OHOS_ACCOUNT_UID;
321     accountInfo.ohosAccountInfo_.name_ = DEFAULT_OHOS_ACCOUNT_NAME;
322     accountInfo.ohosAccountInfo_.status_ = ACCOUNT_STATE_UNBOUND;
323     accountInfo.ohosAccountInfo_.callingUid_ = DEFAULT_CALLING_UID;
324     accountInfo.digest_ = "";
325     accountInfo.ohosAccountInfo_.SetRawUid(DEFAULT_OHOS_ACCOUNT_UID);
326     SaveAccountInfo(accountInfo);
327     AddFileWatcher(userId);
328 }
329 } // namespace AccountSA
330 } // namespace OHOS