1 /*
2 * Copyright (c) 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 <climits>
16 #include <filesystem>
17 #include <fstream>
18 #include <string>
19 #include <sys/mount.h>
20 #include "i18n_hilog.h"
21 #include "parameter.h"
22 #include "signature_verifier.h"
23 #include "utils.h"
24
25
26 namespace OHOS {
27 namespace Global {
28 namespace I18n {
29
30 const std::string CUST_GLOBAL_CARRIER_DIR = "/system/etc/tzdata_distro/";
31 const std::string VERSION_FILE = "version.txt";
32 const std::string CERT_FILE = "CERT.ENC";
33 const std::string VERIFY_FILE = "CERT.SF";
34 const std::string MANIFEST_FILE = "MANIFEST.MF";
35 const std::string SUB_TYPE = "generic";
36 const std::string CFG_PATH =
37 "/data/service/el1/public/update/param_service/install/system/etc/TIMEZONE/generic/current/";
38 const std::string LOCALE_PATH = "/system/etc/TIMEZONE/generic/current/";
39 const std::string SAFE_PATH = "/data/service/el1/public/i18n/timezone/";
40 const std::string PUBKEY_PATH = "/system/etc/LIBPHONENUMBER/generic/";
41 const std::string PUBKEY_NAME = "hota_i18n_upgrade_v1.pem";
42 const std::string COTA_PARAM_TIMEZONE_KEY = "persist.global.tz_override";
43 const int FILE_NAME_INDEX = 6;
44
45 std::vector<std::string> g_dataFiles = {};
46
Init()47 bool Init()
48 {
49 std::string manifestPath = CFG_PATH + MANIFEST_FILE;
50 std::unique_ptr<char[]> resolvedPath = std::make_unique<char[]>(PATH_MAX);
51 if (realpath(manifestPath.c_str(), resolvedPath.get()) == nullptr) {
52 HILOG_ERROR_I18N("MANIFEST_FILE file path isn't exists.");
53 return false;
54 }
55 std::ifstream file(resolvedPath.get());
56 if (file.is_open()) {
57 std::string line;
58 while (std::getline(file, line)) {
59 if (line.find("Name: ") == 0) {
60 g_dataFiles.push_back(line.substr(FILE_NAME_INDEX));
61 }
62 }
63 file.close();
64 return true;
65 } else {
66 return false;
67 }
68 }
69
Mount()70 bool Mount()
71 {
72 if (!IsDirExist(CUST_GLOBAL_CARRIER_DIR.c_str()) ||
73 !IsDirExist(SAFE_PATH.c_str())) {
74 HILOG_ERROR_I18N("Mount: CUST_GLOBAL_CARRIER_DIR or CFG_PATH not exist");
75 return false;
76 }
77
78 std::string cotaOpkeyVersionDir = SAFE_PATH;
79 std::string custOpkeyVersionDir = CUST_GLOBAL_CARRIER_DIR;
80
81 if (mount(cotaOpkeyVersionDir.c_str(), custOpkeyVersionDir.c_str(), nullptr, MS_BIND, nullptr) != 0) {
82 HILOG_ERROR_I18N("Mount: fail to mount: opkey(%{public}s) errno(%{public}s)",
83 cotaOpkeyVersionDir.c_str(), strerror(errno));
84 return false;
85 }
86
87 if (mount(nullptr, custOpkeyVersionDir.c_str(), nullptr, MS_REMOUNT | MS_BIND | MS_RDONLY, nullptr) != 0) {
88 HILOG_ERROR_I18N("Mount: fail to mount read only: opkey(%{public}s) errno(%{public}s)",
89 cotaOpkeyVersionDir.c_str(), strerror(errno));
90 if (umount(custOpkeyVersionDir.c_str()) != 0) {
91 HILOG_ERROR_I18N("Error during unmount: %{public}s\n", strerror(errno));
92 }
93 return false;
94 }
95
96 HILOG_INFO_I18N("Mount: success ro bind cotaDir to custDir: opkey(%{public}s)", cotaOpkeyVersionDir.c_str());
97 return true;
98 }
99
ensureDirectoryExists(const std::filesystem::path & dir_path)100 void ensureDirectoryExists(const std::filesystem::path& dir_path)
101 {
102 std::error_code ec;
103 if (!std::filesystem::exists(dir_path)) {
104 HILOG_ERROR_I18N("Directory does not exist: %{public}s", dir_path.c_str());
105 std::filesystem::create_directories(dir_path, ec);
106 if (ec) {
107 HILOG_ERROR_I18N("Failed to create directory: %{public}s, Error: %{public}s", dir_path.c_str(),
108 ec.message().c_str());
109 }
110 }
111 }
112
clearPath(const std::filesystem::path & dir_path)113 void clearPath(const std::filesystem::path& dir_path)
114 {
115 std::error_code ec;
116 for (const auto& entry : std::filesystem::directory_iterator(dir_path)) {
117 std::filesystem::remove_all(entry.path(), ec);
118 if (ec) {
119 HILOG_ERROR_I18N("clearPath: Error removing file: %{public}s, Error: %{public}s", entry.path().c_str(),
120 ec.message().c_str());
121 }
122 }
123 }
124
copySingleFile(const std::filesystem::path & src_path,const std::filesystem::path & dst_path)125 bool copySingleFile(const std::filesystem::path& src_path, const std::filesystem::path& dst_path)
126 {
127 if (!FileExist(src_path.string())) {
128 HILOG_ERROR_I18N("copySingleFile: Source file does not exist: %{public}s", src_path.c_str());
129 return false;
130 }
131
132 ensureDirectoryExists(dst_path.parent_path());
133 HILOG_INFO_I18N("copySingleFile: copy file: %{public}s, %{public}s", src_path.c_str(), dst_path.c_str());
134 if (!FileCopy(src_path.string(), dst_path.string())) {
135 HILOG_ERROR_I18N("copySingleFile: Failed to copy file: %{public}s", src_path.c_str());
136 return false;
137 }
138
139 return true;
140 }
141
CopyDataFile()142 bool CopyDataFile()
143 {
144 HILOG_INFO_I18N("TimeZone CopyDataFile start");
145 if (!IsDirExist(SAFE_PATH.c_str())) {
146 HILOG_ERROR_I18N("TimeZone CopyDataFile: SAFE_PATH does not exist");
147 return false;
148 }
149
150 std::filesystem::path safe_dir(SAFE_PATH);
151 clearPath(safe_dir);
152
153 bool copySuccess = true;
154 for (const auto& file : g_dataFiles) {
155 std::filesystem::path src_path = std::filesystem::path(CFG_PATH) / file;
156 std::filesystem::path dst_path = std::filesystem::path(SAFE_PATH) / file;
157 if (!copySingleFile(src_path, dst_path)) {
158 HILOG_ERROR_I18N("CopyDataFile: Copy failed for %{public}s", file.c_str());
159 copySuccess = false;
160 break;
161 }
162 }
163
164 if (!copySuccess) {
165 HILOG_ERROR_I18N("CopyDataFile error, clearing the safe directory...");
166 clearPath(safe_dir);
167 }
168
169 return copySuccess;
170 }
171
CheckIfUpdateNecessary()172 bool CheckIfUpdateNecessary()
173 {
174 std::string versionUpdate = SignatureVerifier::LoadFileVersion(CFG_PATH + VERSION_FILE);
175 std::string versionLocale = SignatureVerifier::LoadFileVersion(LOCALE_PATH + VERSION_FILE);
176 HILOG_INFO_I18N("CheckIfUpdateNecessary: Verify: versionUpdate(%{public}s) versionLocale(%{public}s)",
177 versionUpdate.c_str(), versionLocale.c_str());
178
179 if (versionLocale.length() == 0 || versionUpdate.length() == 0) {
180 return false;
181 }
182 if (SignatureVerifier::CompareVersion(versionLocale, versionUpdate) <= 0) {
183 return false;
184 }
185 return true;
186 }
187
CheckFileIntegrity()188 bool CheckFileIntegrity()
189 {
190 std::string certPath = CFG_PATH + CERT_FILE;
191 std::string verifyPath = CFG_PATH + VERIFY_FILE;
192 std::string pubkeyPath = PUBKEY_PATH + PUBKEY_NAME;
193 std::string manifestPath = CFG_PATH + MANIFEST_FILE;
194 if (!SignatureVerifier::VerifyCertFile(certPath, verifyPath, pubkeyPath, manifestPath)) {
195 HILOG_ERROR_I18N("CheckFileIntegrity: VerifyCertFile error");
196 return false;
197 }
198
199 for (unsigned long i = 0; i < g_dataFiles.size(); i++) {
200 HILOG_ERROR_I18N("CheckFileIntegrity: file to verify (%{public}s)", g_dataFiles[i].c_str());
201 std::string filePath = CFG_PATH + g_dataFiles[i];
202 if (!FileExist(filePath.c_str())) {
203 HILOG_ERROR_I18N("CheckFileIntegrity: file not exist (%{public}s)", g_dataFiles[i].c_str());
204 return false;
205 }
206 if (!SignatureVerifier::VerifyParamFile(g_dataFiles[i], CFG_PATH, manifestPath)) {
207 HILOG_ERROR_I18N("CheckFileIntegrity: VerifyParamFile error");
208 return false;
209 }
210 }
211
212 return true;
213 }
214
UpdateTimeZone()215 void UpdateTimeZone()
216 {
217 if (!Init()) {
218 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "false");
219 HILOG_INFO_I18N("UpdateTimeZone: init error");
220 return;
221 }
222 if (!Mount()) {
223 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "false");
224 HILOG_INFO_I18N("UpdateTimeZone: mount error");
225 return;
226 }
227 if (!CheckIfUpdateNecessary()) {
228 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "false");
229 HILOG_INFO_I18N("UpdateTimeZone: CheckIfUpdateNecessary error, no need to update");
230 return;
231 }
232 if (!CheckFileIntegrity()) {
233 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "false");
234 HILOG_INFO_I18N("UpdateTimeZone: CheckFileIntegrity error, no need to update");
235 return;
236 }
237 if (!CopyDataFile()) {
238 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "false");
239 HILOG_INFO_I18N("UpdateTimeZone: CopyDataFile error");
240 return;
241 }
242
243 SetParameter(COTA_PARAM_TIMEZONE_KEY.c_str(), "true");
244 HILOG_INFO_I18N("UpdateTimeZone: UpdateTimeZone");
245 }
246
247 }
248 }
249 }
250
main(int argc,char * argv[])251 int main(int argc, char *argv[])
252 {
253 HILOG_INFO_I18N("hmos_timezone_mount: UpdateTimeZone start");
254 OHOS::Global::I18n::UpdateTimeZone();
255 return 0;
256 }