tizen 2.4 release
[framework/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 <file-system.h>
41
42 namespace {
43
44 const std::string CKM_DATA_PATH = "/opt/data/ckm/";
45 const std::string CKM_KEY_PREFIX = "key-";
46 const std::string CKM_KEY_BACKUP_PREFIX = "key-backup-";
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 = "/run/key-manager.pid";
51
52 } // namespace anonymous
53
54 namespace CKM {
55
56 FileSystem::FileSystem(const ClientID &clientID)
57   : m_clientID(clientID)
58 {}
59
60 std::string FileSystem::getDBPath() const
61 {
62     std::stringstream ss;
63     ss << CKM_DATA_PATH << CKM_DB_PREFIX << m_clientID;
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_clientID;
70     return ss.str();
71 }
72
73 std::string FileSystem::getDKEKBackupPath() const {
74     std::stringstream ss;
75     ss << CKM_DATA_PATH << CKM_KEY_BACKUP_PREFIX << m_clientID;
76     return ss.str();
77 }
78
79 std::string FileSystem::getDBDEKPath() const {
80     std::stringstream ss;
81     ss << CKM_DATA_PATH << CKM_DB_KEY_PREFIX << m_clientID;
82     return ss.str();
83 }
84
85 std::string FileSystem::getRemovedAppsPath() const {
86     std::stringstream ss;
87     ss << CKM_DATA_PATH << CKM_REMOVED_APP_PREFIX << m_clientID;
88     return ss.str();
89 }
90
91 RawBuffer FileSystem::loadFile(const std::string &path) const {
92     std::ifstream is(path);
93
94     if (is.fail() && ENOENT == errno)
95         return RawBuffer();
96
97     if (is.fail()) {
98         auto description = GetErrnoString(errno);
99         LogError("Error opening file: " << path << " Reason: " << description);
100         ThrowMsg(Exception::OpenFailed,
101                  "Error opening file: " << path << " Reason: " << description);
102     }
103
104     std::istreambuf_iterator<char> begin(is),end;
105     std::vector<char> buff(begin,end); // This trick does not work with boost vector
106
107     RawBuffer buffer(buff.size());
108     memcpy(buffer.data(), buff.data(), buff.size());
109     return buffer;
110 }
111
112 RawBuffer FileSystem::getDKEK() const
113 {
114     return loadFile(getDKEKPath());
115 }
116
117 RawBuffer FileSystem::getDKEKBackup() const
118 {
119     return loadFile(getDKEKBackupPath());
120 }
121
122 RawBuffer FileSystem::getDBDEK() const
123 {
124     return loadFile(getDBDEKPath());
125 }
126
127 void FileSystem::saveFile(const std::string &path, const RawBuffer &buffer) const {
128     std::ofstream os(path, std::ios::out | std::ofstream::binary | std::ofstream::trunc);
129     std::copy(buffer.begin(), buffer.end(), std::ostreambuf_iterator<char>(os));
130
131     // Prevent desynchronization in batter remove test.
132     os.flush();
133     fsync(FstreamAccessors<std::ofstream>::GetFd(os)); // flush kernel space buffer
134     os.close();
135
136     if (os.fail())
137         ThrowMsg(Exception::SaveFailed, "Failed to save file: " << path);
138 }
139
140 void FileSystem::saveDKEK(const RawBuffer &buffer) const {
141     saveFile(getDKEKPath(), buffer);
142 }
143
144 void FileSystem::moveFile(const std::string &from, const std::string &to) const {
145     if (0 == ::rename(from.c_str(), to.c_str())) {
146         return;
147     }
148     auto description = GetErrnoString(errno);
149     LogError("Error during rename file DKEKBackup to DKEK: " << description);
150     ThrowMsg(Exception::RenameFailed,
151              "Error during rename file DKEKBackup to DKEK: " << description);
152 }
153
154 void FileSystem::restoreDKEK() const {
155     moveFile(getDKEKBackupPath(), getDKEKPath());
156 }
157
158 void FileSystem::createDKEKBackup() const {
159     moveFile(getDKEKPath(), getDKEKBackupPath());
160 }
161
162 void FileSystem::removeDKEKBackup() const {
163     if (0 == unlink(getDKEKBackupPath().c_str())) {
164         return;
165     }
166     // Backup is accessible only during "change password transaction"
167     auto description = GetErrnoString(errno);
168     LogDebug("Error in unlink file DKEKBackup: " << description);
169 }
170
171 void FileSystem::saveDBDEK(const RawBuffer &buffer) const {
172     saveFile(getDBDEKPath(), buffer);
173 }
174
175 void FileSystem::addRemovedApp(const std::string &smackLabel) const
176 {
177     std::ofstream outfile;
178     outfile.open(getRemovedAppsPath(), std::ios_base::app);
179     outfile << smackLabel << std::endl;
180     outfile.close();
181     if (outfile.fail()) {
182         auto desc = GetErrnoString(errno);
183         LogError("Could not update file: " << getRemovedAppsPath() << " Reason: " << desc);
184         ThrowMsg(Exception::SaveFailed,
185                  "Could not update file: " << getRemovedAppsPath() << " Reason: " << desc);
186     }
187 }
188
189 AppLabelVector FileSystem::clearRemovedsApps() const
190 {
191     // read the contents
192     AppLabelVector removedApps;
193     std::string line;
194     std::ifstream removedAppsFile(getRemovedAppsPath());
195     if (removedAppsFile.is_open()) {
196         while (! removedAppsFile.eof() ) {
197             getline (removedAppsFile,line);
198             if(line.size() > 0)
199                 removedApps.push_back(line);
200         }
201         removedAppsFile.close();
202     }
203     // truncate the contents
204     std::ofstream truncateFile;
205     truncateFile.open(getRemovedAppsPath(), std::ofstream::out | std::ofstream::trunc);
206     truncateFile.close();
207     return removedApps;
208 }
209
210 int FileSystem::init() {
211     errno = 0;
212     if ((mkdir(CKM_DATA_PATH.c_str(), 0700)) && (errno != EEXIST)) {
213         int err = errno;
214         LogError("Error in mkdir " << CKM_DATA_PATH << ". Reason: " << GetErrnoString(err));
215         return -1; // TODO set up some error code
216     }
217     return 0;
218 }
219
220 ClientIDVector FileSystem::getClientIDsFromDBFile(const std::string zone) {
221     ClientIDVector clientIDVec;
222     std::unique_ptr<DIR, std::function<int(DIR*)>>
223         dirp(::opendir(CKM_DATA_PATH.c_str()), ::closedir);
224
225     if (!dirp.get()) {
226         int err = errno;
227         LogError("Error in opendir. Data directory could not be read. Error: " << GetErrnoString(err));
228         return ClientIDVector();
229     }
230
231     size_t len = offsetof(struct dirent, d_name) + pathconf(CKM_DATA_PATH.c_str(), _PC_NAME_MAX) + 1;
232     std::unique_ptr<struct dirent, std::function<void(void*)>>
233         pEntry(static_cast<struct dirent*>(::malloc(len)), ::free);
234
235     if (!pEntry.get()) {
236         LogError("Memory allocation failed.");
237         return ClientIDVector();
238     }
239
240     struct dirent* pDirEntry = NULL;
241
242     while ( (!readdir_r(dirp.get(), pEntry.get(), &pDirEntry)) && pDirEntry ) {
243         if (strncmp(pDirEntry->d_name, CKM_KEY_PREFIX.c_str(), CKM_KEY_PREFIX.size())) {
244             LogDebug("Not DomainKEK file.");
245             continue;
246         }
247 #ifdef DB_PER_ZONE_ENABLE
248         if (strlen(pDirEntry->d_name + CKM_KEY_PREFIX.size()) <= zone.size()) {
249             LogError("Should not happen. "
250                 "Key file[" << pDirEntry->d_name << "] clientID(zone + uid) length should be longer than zone name size");
251             continue;
252         }
253         if (strncmp(pDirEntry->d_name + CKM_KEY_PREFIX.size(), zone.c_str(), zone.size())) {
254             LogDebug("Another zone's DomainKEK file.");
255             continue;
256         }
257 #else
258         (void) zone;
259 #endif
260         try {
261             clientIDVec.push_back(pDirEntry->d_name + CKM_KEY_PREFIX.size());
262         } catch (const std::invalid_argument) {
263             LogError("Error in extracting uid from db file. Error=std::invalid_argument."
264                 "This will be ignored.File=" << pDirEntry->d_name << "");
265         } catch(const std::out_of_range) {
266             LogError("Error in extracting uid from db file. Error=std::out_of_range."
267                 "This will be ignored. File="<< pDirEntry->d_name << "");
268         }
269     }
270     return clientIDVec;
271 }
272
273 int FileSystem::removeUserData() const {
274
275     if (removeFile(getDBPath())
276         || removeFile(getDKEKPath())
277         || removeFile(getDKEKBackupPath())
278         || removeFile(getDBDEKPath())
279         || removeFile(getRemovedAppsPath())) {
280
281         return -1;
282     }
283
284     return 0;
285 }
286
287 int FileSystem::removeFile(const std::string &path) const
288 {
289     if (access(path.c_str(), F_OK) == 0
290         && unlink(path.c_str()) != 0) {
291
292         int err = errno;
293
294         LogError("Unlink Path[" << path
295             << "] Errno[" << errno
296             << "] ErrnoString[" << GetErrnoString(err) << "]");
297
298        return -1;
299     }
300
301     return 0;
302 }
303
304 FileLock FileSystem::lock()
305 {
306     FileLock fl(CKM_LOCK_FILE.c_str());
307     return fl;
308 }
309
310 } // namespace CKM
311