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