• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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