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