1 /*
2 * Copyright (c) 2021-2022 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 #ifdef WITH_SELINUX
22 #include <policycoreutils.h>
23 #endif // WITH_SELINUX
24 #include "account_error_no.h"
25 #include "account_info.h"
26 #include "account_log_wrapper.h"
27 #include "directory_ex.h"
28 #include "file_ex.h"
29 #include "hisysevent_adapter.h"
30 #include "ohos_account_data_deal.h"
31 namespace OHOS {
32 namespace AccountSA {
33 namespace {
34 const std::string ACCOUNT_CFG_FILE_NAME = "/account.json";
35 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_NAME = "account_name";
36 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID = "raw_uid";
37 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_UID = "open_id";
38 const std::string DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS = "bind_status";
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 } // namespace
45
OhosAccountDataDeal(const std::string & configFileDir)46 OhosAccountDataDeal::OhosAccountDataDeal(const std::string &configFileDir) : configFileDir_(configFileDir)
47 {
48 initOk_ = false;
49 }
50
Init(int32_t userId)51 ErrCode OhosAccountDataDeal::Init(int32_t userId)
52 {
53 std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
54 if (!FileExists(configFile)) {
55 ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
56 BuildJsonFileFromScratch(userId);
57 #ifdef WITH_SELINUX
58 Restorecon(configFile.c_str());
59 #endif // WITH_SELINUX
60 }
61
62 std::ifstream fin(configFile);
63 if (!fin) {
64 ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", configFile.c_str(), errno);
65 ReportOhosAccountOperationFail(userId, OPERATION_INIT_OPEN_FILE_TO_READ, errno, configFile);
66 return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
67 }
68
69 // NOT-allow exceptions when parse json file
70 std::lock_guard<std::mutex> lock(mutex_);
71 jsonData_ = json::parse(fin, nullptr, false);
72 fin.close();
73 if (!jsonData_.is_structured()) {
74 ACCOUNT_LOGE("Invalid json file, remove");
75 if (RemoveFile(configFile)) {
76 ACCOUNT_LOGE("Remove invalid json file %{public}s failed, errno %{public}d.", configFile.c_str(), errno);
77 ReportOhosAccountOperationFail(userId, OPERATION_REMOVE_FILE, errno, configFile);
78 }
79 return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
80 }
81
82 initOk_ = true;
83 return ERR_OK;
84 }
85
AccountInfoFromJson(AccountInfo & accountInfo,int32_t userId)86 ErrCode OhosAccountDataDeal::AccountInfoFromJson(AccountInfo &accountInfo, int32_t userId)
87 {
88 if (!initOk_) {
89 ACCOUNT_LOGE("not init yet!");
90 return ERR_ACCOUNT_DATADEAL_NOT_READY;
91 }
92 return GetAccountInfo(accountInfo, userId);
93 }
94
AccountInfoToJson(const AccountInfo & accountInfo) const95 ErrCode OhosAccountDataDeal::AccountInfoToJson(const AccountInfo &accountInfo) const
96 {
97 if (!initOk_) {
98 ACCOUNT_LOGE("Not init ok");
99 return ERR_ACCOUNT_DATADEAL_NOT_READY;
100 }
101 return SaveAccountInfo(accountInfo);
102 }
103
SaveAccountInfo(const AccountInfo & accountInfo) const104 ErrCode OhosAccountDataDeal::SaveAccountInfo(const AccountInfo &accountInfo) const
105 {
106 std::string scalableDataStr = (accountInfo.ohosAccountInfo_.scalableData_).ToString();
107 nlohmann::json jsonData = json {
108 {DATADEAL_JSON_KEY_BIND_TIME, accountInfo.bindTime_},
109 {DATADEAL_JSON_KEY_USERID, accountInfo.userId_},
110 {DATADEAL_JSON_KEY_OHOSACCOUNT_NAME, accountInfo.ohosAccountInfo_.name_},
111 {DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID, accountInfo.ohosAccountInfo_.GetRawUid()},
112 {DATADEAL_JSON_KEY_OHOSACCOUNT_UID, accountInfo.ohosAccountInfo_.uid_},
113 {DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS, accountInfo.ohosAccountInfo_.status_},
114 {DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME, accountInfo.ohosAccountInfo_.nickname_},
115 {DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR, accountInfo.ohosAccountInfo_.avatar_},
116 {DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA, scalableDataStr}
117 };
118 std::string accountInfoValue = jsonData.dump(-1, ' ', false, json::error_handler_t::ignore);
119 std::string configFile = configFileDir_ + std::to_string(accountInfo.userId_) + ACCOUNT_CFG_FILE_NAME;
120 FILE *fp = fopen(configFile.c_str(), "wb");
121 if (fp == nullptr) {
122 ACCOUNT_LOGE("failed to open %{public}s, errno %{public}d.", configFile.c_str(), errno);
123 ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
124 return ERR_ACCOUNT_COMMON_FILE_OPEN_FAILED;
125 }
126 size_t num = fwrite(accountInfoValue.c_str(), sizeof(char), accountInfoValue.length(), fp);
127 if (num != accountInfoValue.length()) {
128 ACCOUNT_LOGE("failed to fwrite %{public}s, errno %{public}d.", configFile.c_str(), errno);
129 ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
130 fclose(fp);
131 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
132 }
133 if (fflush(fp) != 0) {
134 ACCOUNT_LOGE("failed to fflush %{public}s, errno %{public}d.", configFile.c_str(), errno);
135 ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
136 fclose(fp);
137 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
138 }
139 if (fsync(fileno(fp)) != 0) {
140 ACCOUNT_LOGE("failed to fsync %{public}s, errno %{public}d.", configFile.c_str(), errno);
141 ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_OPEN_FILE_TO_WRITE, errno, configFile);
142 fclose(fp);
143 return ERR_ACCOUNT_COMMON_FILE_WRITE_FAILED;
144 }
145 fclose(fp);
146
147 // change mode
148 if (!ChangeModeFile(configFile, S_IRUSR | S_IWUSR)) {
149 ACCOUNT_LOGE("failed to change mode for file %{public}s, errno %{public}d.", configFile.c_str(), errno);
150 ReportOhosAccountOperationFail(accountInfo.userId_, OPERATION_CHANGE_MODE_FILE, errno, configFile);
151 return ERR_OHOSACCOUNT_SERVICE_FILE_CHANGE_DIR_MODE_ERROR;
152 }
153 return ERR_OK;
154 }
155
ParseJsonFromFile(const std::string & filePath,nlohmann::json & jsonData,int32_t userId)156 ErrCode OhosAccountDataDeal::ParseJsonFromFile(const std::string &filePath, nlohmann::json &jsonData, int32_t userId)
157 {
158 std::ifstream fin(filePath);
159 if (!fin) {
160 ACCOUNT_LOGE("Failed to open config file %{public}s, errno %{public}d.", filePath.c_str(), errno);
161 ReportOhosAccountOperationFail(userId, OPERATION_OPEN_FILE_TO_READ, errno, filePath);
162 return ERR_ACCOUNT_DATADEAL_INPUT_FILE_ERROR;
163 }
164 // NOT-allow exceptions when parse json file
165 jsonData = json::parse(fin, nullptr, false);
166 fin.close();
167 if (!jsonData.is_structured()) {
168 ACCOUNT_LOGE("Invalid json file, %{public}s, remove", filePath.c_str());
169 return ERR_ACCOUNT_DATADEAL_JSON_FILE_CORRUPTION;
170 }
171 return ERR_OK;
172 }
173
GetAccountInfo(AccountInfo & accountInfo,const int32_t userId)174 ErrCode OhosAccountDataDeal::GetAccountInfo(AccountInfo &accountInfo, const int32_t userId)
175 {
176 std::string configFile = configFileDir_ + std::to_string(userId) + ACCOUNT_CFG_FILE_NAME;
177 if (!FileExists(configFile)) {
178 ACCOUNT_LOGI("file %{public}s not exist, create!", configFile.c_str());
179 BuildJsonFileFromScratch(userId); // create default config file for first login
180 #ifdef WITH_SELINUX
181 Restorecon(configFile.c_str());
182 #endif // WITH_SELINUX
183 }
184 std::lock_guard<std::mutex> lock(mutex_);
185 ErrCode ret = ParseJsonFromFile(configFile, jsonData_, userId);
186 if (ret != ERR_OK) {
187 return ret;
188 }
189
190 const auto &jsonObjectEnd = jsonData_.end();
191 if (jsonData_.find(DATADEAL_JSON_KEY_BIND_TIME) != jsonObjectEnd) {
192 accountInfo.bindTime_ = jsonData_.at(DATADEAL_JSON_KEY_BIND_TIME).get<std::time_t>();
193 }
194
195 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME) != jsonObjectEnd) {
196 accountInfo.ohosAccountInfo_.name_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NAME).get<std::string>();
197 }
198
199 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID) != jsonObjectEnd) {
200 std::string rawUid = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_RAW_UID).get<std::string>();
201 accountInfo.ohosAccountInfo_.SetRawUid(rawUid);
202 }
203
204 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_UID) != jsonObjectEnd) {
205 accountInfo.ohosAccountInfo_.uid_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_UID).get<std::string>();
206 }
207
208 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS) != jsonObjectEnd) {
209 accountInfo.ohosAccountInfo_.status_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_STATUS).get<int32_t>();
210 }
211
212 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME) != jsonObjectEnd) {
213 accountInfo.ohosAccountInfo_.nickname_ =
214 jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_NICKNAME).get<std::string>();
215 }
216
217 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR) != jsonObjectEnd) {
218 accountInfo.ohosAccountInfo_.avatar_ = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_AVATAR).get<std::string>();
219 }
220
221 if (jsonData_.find(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA) != jsonObjectEnd) {
222 auto scalableDataJson = jsonData_.at(DATADEAL_JSON_KEY_OHOSACCOUNT_SCALABLEDATA).get<std::string>();
223 sptr<AAFwk::Want> want = AAFwk::Want::FromString(scalableDataJson);
224 if (want == nullptr) {
225 return ERR_ACCOUNT_COMMON_NULL_PTR_ERROR;
226 }
227 accountInfo.ohosAccountInfo_.scalableData_ = *want;
228 }
229 accountInfo.userId_ = userId;
230 return ERR_OK;
231 }
232
BuildJsonFileFromScratch(int32_t userId) const233 void OhosAccountDataDeal::BuildJsonFileFromScratch(int32_t userId) const
234 {
235 AccountInfo accountInfo;
236 accountInfo.userId_ = userId;
237 accountInfo.bindTime_ = 0;
238 accountInfo.ohosAccountInfo_.uid_ = DEFAULT_OHOS_ACCOUNT_UID;
239 accountInfo.ohosAccountInfo_.name_ = DEFAULT_OHOS_ACCOUNT_NAME;
240 accountInfo.ohosAccountInfo_.status_ = ACCOUNT_STATE_UNBOUND;
241 accountInfo.digest_ = "";
242 accountInfo.ohosAccountInfo_.SetRawUid(DEFAULT_OHOS_ACCOUNT_UID);
243 SaveAccountInfo(accountInfo);
244 }
245 } // namespace AccountSA
246 } // namespace OHOS