Reduce number of error logs in ckm.
[platform/core/security/key-manager.git] / src / manager / service / file-system.cpp
1 /*
2  *  Copyright (c) 2000 - 2014 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        FileSystem.cpp
18  * @author      Bartlomiej Grzelewski (b.grzelewski@samsung.com)
19  * @version     1.0
20  * @brief       Sample service implementation.
21  */
22 #include <string.h>
23 #include <stdio.h>
24 #include <sys/stat.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <dirent.h>
28
29 #include <cstdlib>
30 #include <string>
31 #include <sstream>
32 #include <fstream>
33 #include <memory>
34 #include <stdexcept>
35
36 #include <dpl/errno_string.h>
37 #include <dpl/fstream_accessors.h>
38 #include <dpl/log/log.h>
39
40 #include <exception.h>
41 #include <file-system.h>
42
43 namespace {
44
45 const std::string CKM_DATA_PATH = "/opt/data/ckm/";
46 const std::string CKM_KEY_PREFIX = "key-";
47 const std::string CKM_DB_KEY_PREFIX = "db-key-";
48 const std::string CKM_DB_PREFIX = "db-";
49 const std::string CKM_REMOVED_APP_PREFIX = "removed-app-";
50 const std::string CKM_LOCK_FILE = "/var/run/key-manager.pid";
51
52 } // namespace anonymous
53
54 namespace CKM {
55
56 FileSystem::FileSystem(uid_t uid)
57   : m_uid(uid)
58 {}
59
60 std::string FileSystem::getDBPath() const
61 {
62     std::stringstream ss;
63     ss << CKM_DATA_PATH << CKM_DB_PREFIX << m_uid;
64     return ss.str();
65 }
66
67 std::string FileSystem::getDKEKPath() const {
68     std::stringstream ss;
69     ss << CKM_DATA_PATH << CKM_KEY_PREFIX << m_uid;
70     return ss.str();
71 }
72
73 std::string FileSystem::getDBDEKPath() const {
74     std::stringstream ss;
75     ss << CKM_DATA_PATH << CKM_DB_KEY_PREFIX << m_uid;
76     return ss.str();
77 }
78
79 std::string FileSystem::getRemovedAppsPath() const {
80     std::stringstream ss;
81     ss << CKM_DATA_PATH << CKM_REMOVED_APP_PREFIX << m_uid;
82     return ss.str();
83 }
84
85 RawBuffer FileSystem::loadFile(const std::string &path) const {
86     std::ifstream is(path);
87
88     if (is.fail() && ENOENT == errno)
89         return RawBuffer();
90
91     if (is.fail()) {
92         auto description = GetErrnoString(errno);
93         ThrowErr(Exc::FileSystemFailed,
94                  "Error opening file: ", path, " Reason: ", description);
95     }
96
97     std::istreambuf_iterator<char> begin(is),end;
98     std::vector<char> buff(begin,end); // This trick does not work with boost vector
99
100     RawBuffer buffer(buff.size());
101     memcpy(buffer.data(), buff.data(), buff.size());
102     return buffer;
103 }
104
105 RawBuffer FileSystem::getDKEK() const
106 {
107     return loadFile(getDKEKPath());
108 }
109
110 RawBuffer FileSystem::getDBDEK() const
111 {
112     return loadFile(getDBDEKPath());
113 }
114
115 void FileSystem::saveFile(const std::string &path, const RawBuffer &buffer) const {
116     std::ofstream os(path, std::ios::out | std::ofstream::binary | std::ofstream::trunc);
117     std::copy(buffer.begin(), buffer.end(), std::ostreambuf_iterator<char>(os));
118
119     // Prevent desynchronization in batter remove test.
120     os.flush();
121     fsync(FstreamAccessors<std::ofstream>::GetFd(os)); // flush kernel space buffer
122     os.close();
123
124     if (os.fail())
125         ThrowErr(Exc::FileSystemFailed, "Failed to save file: ", path);
126 }
127
128 void FileSystem::saveDKEK(const RawBuffer &buffer) const {
129     saveFile(getDKEKPath(), buffer);
130 }
131
132 void FileSystem::saveDBDEK(const RawBuffer &buffer) const {
133     saveFile(getDBDEKPath(), buffer);
134 }
135
136 void FileSystem::addRemovedApp(const std::string &smackLabel) const
137 {
138     std::ofstream outfile;
139     outfile.open(getRemovedAppsPath(), std::ios_base::app);
140     outfile << smackLabel << std::endl;
141     outfile.close();
142     if (outfile.fail()) {
143         auto desc = GetErrnoString(errno);
144         ThrowErr(Exc::FileSystemFailed,
145                  "Could not update file: ", getRemovedAppsPath(), " Reason: ", desc);
146     }
147 }
148
149 AppLabelVector FileSystem::clearRemovedsApps() const
150 {
151     // read the contents
152     AppLabelVector removedApps;
153     std::string line;
154     std::ifstream removedAppsFile(getRemovedAppsPath());
155     if (removedAppsFile.is_open()) {
156         while (! removedAppsFile.eof() ) {
157             getline (removedAppsFile,line);
158             if(line.size() > 0)
159                 removedApps.push_back(line);
160         }
161         removedAppsFile.close();
162     }
163     // truncate the contents
164     std::ofstream truncateFile;
165     truncateFile.open(getRemovedAppsPath(), std::ofstream::out | std::ofstream::trunc);
166     truncateFile.close();
167     return removedApps;
168 }
169
170 int FileSystem::init() {
171     errno = 0;
172     if ((mkdir(CKM_DATA_PATH.c_str(), 0700)) && (errno != EEXIST)) {
173         int err = errno;
174         LogError("Error in mkdir " << CKM_DATA_PATH << ". Reason: " << GetErrnoString(err));
175         return -1; // TODO set up some error code
176     }
177     return 0;
178 }
179
180 UidVector FileSystem::getUIDsFromDBFile() {
181     UidVector uids;
182     std::unique_ptr<DIR, std::function<int(DIR*)>>
183         dirp(::opendir(CKM_DATA_PATH.c_str()), ::closedir);
184
185     if (!dirp.get()) {
186         int err = errno;
187         LogError("Error in opendir. Data directory could not be read. Error: " << GetErrnoString(err));
188         return UidVector();
189     }
190
191     size_t len = offsetof(struct dirent, d_name) + pathconf(CKM_DATA_PATH.c_str(), _PC_NAME_MAX) + 1;
192     std::unique_ptr<struct dirent, std::function<void(void*)>>
193         pEntry(static_cast<struct dirent*>(::malloc(len)), ::free);
194
195     if (!pEntry.get()) {
196         LogError("Memory allocation failed.");
197         return UidVector();
198     }
199
200     struct dirent* pDirEntry = NULL;
201
202     while ( (!readdir_r(dirp.get(), pEntry.get(), &pDirEntry)) && pDirEntry ) {
203         // Ignore files with diffrent prefix
204         if (strncmp(pDirEntry->d_name, CKM_KEY_PREFIX.c_str(), CKM_KEY_PREFIX.size())) {
205             continue;
206         }
207
208         // We find database. Let's extract user id.
209         try {
210             uids.push_back(static_cast<uid_t>(std::stoi((pDirEntry->d_name)+CKM_KEY_PREFIX.size())));
211         } catch (const std::invalid_argument) {
212             LogDebug("Error in extracting uid from db file. Error=std::invalid_argument."
213                 "This will be ignored.File=" << pDirEntry->d_name << "");
214         } catch(const std::out_of_range) {
215             LogDebug("Error in extracting uid from db file. Error=std::out_of_range."
216                 "This will be ignored. File="<< pDirEntry->d_name << "");
217         }
218     }
219
220     return uids;
221 }
222
223 int FileSystem::removeUserData() const {
224     int err, retCode = 0;
225
226     if (unlink(getDBPath().c_str())) {
227         retCode = -1;
228         err = errno;
229         LogDebug("Error in unlink user database: " << getDBPath()
230             << "Errno: " << errno << " " << GetErrnoString(err));
231     }
232
233     if (unlink(getDKEKPath().c_str())) {
234         retCode = -1;
235         err = errno;
236         LogDebug("Error in unlink user DKEK: " << getDKEKPath()
237             << "Errno: " << errno << " " << GetErrnoString(err));
238     }
239
240     if (unlink(getDBDEKPath().c_str())) {
241         retCode = -1;
242         err = errno;
243         LogDebug("Error in unlink user DBDEK: " << getDBDEKPath()
244             << "Errno: " << errno << " " << GetErrnoString(err));
245     }
246
247     if (unlink(getRemovedAppsPath().c_str())) {
248         retCode = -1;
249         err = errno;
250         LogDebug("Error in unlink user's Removed Apps File: " << getRemovedAppsPath()
251             << "Errno: " << errno << " " << GetErrnoString(err));
252     }
253
254     return retCode;
255 }
256
257 FileLock FileSystem::lock()
258 {
259     FileLock fl(CKM_LOCK_FILE.c_str());
260     return fl;
261 }
262
263 } // namespace CKM
264