e1ef844a5231b0da2047b656b4aff98b9b2f9b1f
[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
54 wur std::string getPath(const std::string &prefix, uid_t uid)
55 {
56         std::stringstream ss;
57         ss << RW_DATA_DIR << "/" << prefix << uid;
58         return ss.str();
59 }
60
61 } // namespace anonymous
62
63 FileSystem::FileSystem(uid_t uid)
64         : m_uid(uid)
65 {
66 }
67
68 std::string FileSystem::getLegacyDBPath() const
69 {
70         return getPath(CKM_LEGACY_DB_PREFIX, m_uid);
71 }
72
73 std::string FileSystem::getDBPath() const
74 {
75         return getPath(CKM_DB_PREFIX, m_uid);
76 }
77
78 std::string FileSystem::getDKEKPath() const
79 {
80         return getPath(CKM_KEY_PREFIX, m_uid);
81 }
82
83 std::string FileSystem::getDBDEKPath() const
84 {
85         return getPath(CKM_DB_KEY_PREFIX, m_uid);
86 }
87
88 std::string FileSystem::getRemovedAppsPath() const
89 {
90         return getPath(CKM_REMOVED_APP_PREFIX, m_uid);
91 }
92
93 RawBuffer FileSystem::loadFile(const std::string &path) const
94 {
95         std::ifstream is(path);
96
97         if (is.fail() && ENOENT == errno)
98                 return RawBuffer();
99
100         if (is.fail()) {
101                 auto description = GetErrnoString(errno);
102                 ThrowErr(Exc::FileSystemFailed,
103                                  "Error opening file: ", path, " Reason: ", description);
104         }
105
106         std::istreambuf_iterator<char> begin(is), end;
107         std::vector<char> buff(begin,
108                                                    end); // This trick does not work with boost vector
109
110         RawBuffer buffer(buff.size());
111         memcpy(buffer.data(), buff.data(), buff.size());
112         return buffer;
113 }
114
115 RawBuffer FileSystem::getDKEK() const
116 {
117         return loadFile(getDKEKPath());
118 }
119
120 RawBuffer FileSystem::getDBDEK() const
121 {
122         return loadFile(getDBDEKPath());
123 }
124
125 void FileSystem::saveFile(const std::string &path,
126                                                   const RawBuffer &buffer) const
127 {
128         std::ofstream os(path, std::ios::out | std::ofstream::binary |
129                                          std::ofstream::trunc);
130
131         if (os.fail())
132                 ThrowErr(Exc::FileSystemFailed, "Can't open file for writing: ", path);
133
134         std::copy(buffer.begin(), buffer.end(), std::ostreambuf_iterator<char>(os));
135
136         // Prevent desynchronization in battery remove test.
137         os.flush();
138         if (fsync(FstreamAccessors<std::ofstream>::GetFd(os)) != 0) { // flush kernel space buffer
139                 auto desc = GetErrnoString(errno);
140                 ThrowErr(Exc::FileSystemFailed, "Failed to sync file: ", path, " Reason: ", desc);
141         }
142         os.close();
143
144         if (os.fail())
145                 ThrowErr(Exc::FileSystemFailed, "Failed to save file: ", path);
146 }
147
148 void FileSystem::saveDKEK(const RawBuffer &buffer) const
149 {
150         saveFile(getDKEKPath(), buffer);
151 }
152
153 void FileSystem::saveDBDEK(const RawBuffer &buffer) const
154 {
155         saveFile(getDBDEKPath(), buffer);
156 }
157
158 void FileSystem::addRemovedApp(const ClientId &app) const
159 {
160         std::ofstream outfile;
161         outfile.open(getRemovedAppsPath(), std::ios_base::app);
162         outfile << app << std::endl;
163         outfile.close();
164
165         if (outfile.fail()) {
166                 auto desc = GetErrnoString(errno);
167                 ThrowErr(Exc::FileSystemFailed,
168                                  "Could not update file: ", getRemovedAppsPath(), " Reason: ", desc);
169         }
170 }
171
172 ClientIdVector FileSystem::clearRemovedsApps() const
173 {
174         // read the contents
175         ClientIdVector removedApps;
176         std::string line;
177         std::ifstream removedAppsFile(getRemovedAppsPath());
178
179         if (removedAppsFile.is_open()) {
180                 while (!removedAppsFile.eof()) {
181                         getline(removedAppsFile, line);
182
183                         if (line.size() > 0)
184                                 removedApps.push_back(line);
185                 }
186
187                 removedAppsFile.close();
188         }
189
190         // truncate the contents
191         std::ofstream truncateFile;
192         truncateFile.open(getRemovedAppsPath(),
193                                           std::ofstream::out | std::ofstream::trunc);
194         truncateFile.close();
195         return removedApps;
196 }
197
198 int FileSystem::init()
199 {
200         errno = 0;
201
202         if ((mkdir(RW_DATA_DIR, S_IRWXU)) && (errno != EEXIST)) {
203                 int err = errno;
204                 LogError("Error in mkdir " << RW_DATA_DIR << ". Reason: " << GetErrnoString(
205                                          err));
206                 return -1; // TODO set up some error code
207         }
208
209         return 0;
210 }
211
212 UidVector FileSystem::getUIDsFromDBFile()
213 {
214         UidVector uids;
215
216         forEachFile(RW_DATA_DIR, [&uids](const std::string & filename) {
217                 if (strncmp(filename.c_str(), CKM_KEY_PREFIX.c_str(), CKM_KEY_PREFIX.size()))
218                         return;
219
220                 try {
221                         uids.emplace_back(static_cast<uid_t>(std::stoi((filename.c_str())
222                                                                                                  + CKM_KEY_PREFIX.size())));
223                 } catch (const std::invalid_argument &) {
224                         LogDebug("Error in extracting uid from db file. "
225                                          "Error=std::invalid_argument. "
226                                          "This will be ignored.File=" << filename);
227                 } catch (const std::out_of_range &) {
228                         LogDebug("Error in extracting uid from db file. "
229                                          "Error=std::out_of_range. "
230                                          "This will be ignored. File=" << filename);
231                 }
232
233                 return;
234         });
235
236         return uids;
237 }
238
239 int FileSystem::removeUserData() const
240 {
241         const auto unlinkUserPath = [](const std::string &path, const char *logDesc) {
242                 if (!unlink(path.c_str()))
243                         return 0;
244                 const auto err = errno;
245                 if (ENOENT == err)
246                         return 0;
247                 LogDebug("Error in unlink user" << logDesc << ": " << path
248                                  << "Errno: " << err << " " << GetErrnoString(err));
249                 return -1;
250         };
251
252         return unlinkUserPath(getDBPath(), " database")
253                 | unlinkUserPath(getLegacyDBPath(), " legacy database")
254                 | unlinkUserPath(getDKEKPath(), " DKEK")
255                 | unlinkUserPath(getDBDEKPath(), " DBDEK")
256                 | unlinkUserPath(getRemovedAppsPath(), "'s Removed Apps File");
257 }
258
259 FileLock FileSystem::lock()
260 {
261         FileLock fl(CKM_LOCK_FILE.c_str());
262         return fl;
263 }
264
265 } // namespace CKM
266