add the se-backend for db encryption
[platform/core/security/key-manager.git] / src / manager / service / file-system.cpp
1 /*
2  *  Copyright (c) 2000-2020 Samsung Electronics Co., Ltd. All rights reserved
3  *
4  *  Licensed under the Apache License, Version 2.0 (the "License");
5  *  you may not use this file except in compliance with the License.
6  *  You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *  Unless required by applicable law or agreed to in writing, software
11  *  distributed under the License is distributed on an "AS IS" BASIS,
12  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *  See the License for the specific language governing permissions and
14  *  limitations under the License
15  *
16  *
17  * @file        file-system.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       File related operations.
21  */
22 #include <string.h>
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27
28 #include <cstdlib>
29 #include <string>
30 #include <sstream>
31 #include <fstream>
32 #include <memory>
33 #include <stdexcept>
34
35 #include <dpl/errno_string.h>
36 #include <dpl/fstream_accessors.h>
37 #include <dpl/log/log.h>
38
39 #include <exception.h>
40 #include <for-each-file.h>
41 #include <file-system.h>
42
43 namespace CKM {
44
45 namespace {
46
47 const std::string CKM_KEY_PREFIX = "key-";
48 const std::string CKM_DB_KEY_PREFIX = "db-key-";
49 const std::string CKM_LEGACY_DB_PREFIX = "db-";
50 const std::string CKM_DB_PREFIX = "db0-";
51 const std::string CKM_REMOVED_APP_PREFIX = "removed-app-";
52 const std::string CKM_LOCK_FILE = RUN_DIR "/" SERVICE_NAME "/key-manager.pid";
53 const std::string CKM_TEMP_POSTFIX = ".tmp";
54
55 wur std::string getPath(const std::string &prefix, uid_t uid)
56 {
57         std::stringstream ss;
58         ss << RW_DATA_DIR << "/" << prefix << uid;
59         return ss.str();
60 }
61
62 } // namespace anonymous
63
64 FileSystem::FileSystem(uid_t uid)
65         : m_uid(uid)
66 {
67 }
68
69 std::string FileSystem::getLegacyDBPath() const
70 {
71         return getPath(CKM_LEGACY_DB_PREFIX, m_uid);
72 }
73
74 std::string FileSystem::getDBPath() const
75 {
76         return getPath(CKM_DB_PREFIX, m_uid);
77 }
78
79 std::string FileSystem::getDKEKPath() const
80 {
81         return getPath(CKM_KEY_PREFIX, m_uid);
82 }
83
84 std::string FileSystem::getDBDEKPath() const
85 {
86         return getPath(CKM_DB_KEY_PREFIX, m_uid);
87 }
88
89 std::string FileSystem::getRemovedAppsPath() const
90 {
91         return getPath(CKM_REMOVED_APP_PREFIX, m_uid);
92 }
93
94 RawBuffer FileSystem::loadFile(const std::string &path) const
95 {
96         std::ifstream is(path);
97
98         if (is.fail() && ENOENT == errno)
99                 return RawBuffer();
100
101         if (is.fail()) {
102                 auto description = GetErrnoString(errno);
103                 ThrowErr(Exc::FileSystemFailed,
104                                  "Error opening file: ", path, " Reason: ", description);
105         }
106
107         std::istreambuf_iterator<char> begin(is), end;
108         std::vector<char> buff(begin,
109                                                    end); // This trick does not work with boost vector
110
111         RawBuffer buffer(buff.size());
112         memcpy(buffer.data(), buff.data(), buff.size());
113         return buffer;
114 }
115
116 RawBuffer FileSystem::getDKEK() const
117 {
118         return loadFile(getDKEKPath());
119 }
120
121 RawBuffer FileSystem::getDBDEK() const
122 {
123         return loadFile(getDBDEKPath());
124 }
125
126 void FileSystem::saveFile(const std::string &path,
127                                                   const RawBuffer &buffer) const
128 {
129         std::ofstream os(path + CKM_TEMP_POSTFIX, std::ios::out |
130                                         std::ofstream::binary | std::ofstream::trunc);
131
132         if (os.fail())
133                 ThrowErr(Exc::FileSystemFailed, "Can't open file for writing: ", path);
134
135         std::copy(buffer.begin(), buffer.end(), std::ostreambuf_iterator<char>(os));
136
137         // Prevent desynchronization in battery remove test.
138         os.flush();
139         if (fsync(FstreamAccessors<std::ofstream>::GetFd(os)) != 0) { // flush kernel space buffer
140                 auto desc = GetErrnoString(errno);
141                 ThrowErr(Exc::FileSystemFailed, "Failed to sync file: ", path, " Reason: ", desc);
142         }
143         os.close();
144
145         if (os.fail())
146                 ThrowErr(Exc::FileSystemFailed, "Failed to save file: ", path);
147
148         if (std::rename((path + CKM_TEMP_POSTFIX).c_str(), path.c_str()))
149                 ThrowErr(Exc::FileSystemFailed, "Can't rename file: ", path);
150 }
151
152 void FileSystem::saveDKEK(const RawBuffer &buffer) const
153 {
154         std::string path(getDKEKPath());
155         saveFile(path, buffer);
156 }
157
158 void FileSystem::saveDBDEK(const RawBuffer &buffer) const
159 {
160         std::string path(getDBDEKPath());
161         saveFile(path, buffer);
162 }
163
164 void FileSystem::addRemovedApp(const ClientId &app) const
165 {
166         std::ofstream outfile;
167         outfile.open(getRemovedAppsPath(), std::ios_base::app);
168         outfile << app << std::endl;
169         outfile.close();
170
171         if (outfile.fail()) {
172                 auto desc = GetErrnoString(errno);
173                 ThrowErr(Exc::FileSystemFailed,
174                                  "Could not update file: ", getRemovedAppsPath(), " Reason: ", desc);
175         }
176 }
177
178 ClientIdVector FileSystem::clearRemovedsApps() const
179 {
180         // read the contents
181         ClientIdVector removedApps;
182         std::string line;
183         std::ifstream removedAppsFile(getRemovedAppsPath());
184
185         if (removedAppsFile.is_open()) {
186                 while (!removedAppsFile.eof()) {
187                         getline(removedAppsFile, line);
188
189                         if (line.size() > 0)
190                                 removedApps.push_back(line);
191                 }
192
193                 removedAppsFile.close();
194         }
195
196         // truncate the contents
197         std::ofstream truncateFile;
198         truncateFile.open(getRemovedAppsPath(),
199                                           std::ofstream::out | std::ofstream::trunc);
200         truncateFile.close();
201         return removedApps;
202 }
203
204 int FileSystem::init()
205 {
206         errno = 0;
207
208         if ((mkdir(RW_DATA_DIR, S_IRWXU)) && (errno != EEXIST)) {
209                 int err = errno;
210                 LogError("Error in mkdir " << RW_DATA_DIR << ". Reason: " << GetErrnoString(
211                                          err));
212                 return -1; // TODO set up some error code
213         }
214
215         return 0;
216 }
217
218 UidVector FileSystem::getUIDsFromDBFile()
219 {
220         UidVector uids;
221
222         forEachFile(RW_DATA_DIR, [&uids](const std::string & filename) {
223                 if (strncmp(filename.c_str(), CKM_KEY_PREFIX.c_str(), CKM_KEY_PREFIX.size()))
224                         return;
225
226                 try {
227                         uids.emplace_back(static_cast<uid_t>(std::stoi((filename.c_str())
228                                                                                                  + CKM_KEY_PREFIX.size())));
229                 } catch (const std::invalid_argument &) {
230                         LogDebug("Error in extracting uid from db file. "
231                                          "Error=std::invalid_argument. "
232                                          "This will be ignored.File=" << filename);
233                 } catch (const std::out_of_range &) {
234                         LogDebug("Error in extracting uid from db file. "
235                                          "Error=std::out_of_range. "
236                                          "This will be ignored. File=" << filename);
237                 }
238
239                 return;
240         });
241
242         return uids;
243 }
244
245 int FileSystem::removeUserData() const
246 {
247         const auto unlinkUserPath = [](const std::string &path, const char *logDesc) {
248                 if (!unlink(path.c_str()))
249                         return 0;
250                 const auto err = errno;
251                 if (ENOENT == err)
252                         return 0;
253                 LogDebug("Error in unlink user" << logDesc << ": " << path
254                                  << "Errno: " << err << " " << GetErrnoString(err));
255                 return -1;
256         };
257
258         return unlinkUserPath(getDBPath(), " database")
259                 | unlinkUserPath(getLegacyDBPath(), " legacy database")
260                 | unlinkUserPath(getDKEKPath(), " DKEK")
261                 | unlinkUserPath(getDBDEKPath(), " DBDEK")
262                 | unlinkUserPath(getRemovedAppsPath(), "'s Removed Apps File");
263 }
264
265 FileLock FileSystem::lock()
266 {
267         FileLock fl(CKM_LOCK_FILE.c_str());
268         return fl;
269 }
270
271 } // namespace CKM
272