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