signon 8.54

- Main Page
- Related Pages
- Namespaces
- Classes
- Files

- File List
- File Members

crypto-manager.cpp
Go to the documentation of this file.
1 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of signon
4 *
5 * Copyright (C) 2009-2010 Nokia Corporation.
6 *
7 * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
8 * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
9 *
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public License
12 * version 2.1 as published by the Free Software Foundation.
13 *
14 * This library is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * Lesser General Public License for more details.
18 *
19 * You should have received a copy of the GNU Lesser General Public
20 * License along with this library; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
22 * 02110-1301 USA
23 */
24
25
26 #include "crypto-manager.h"
27 #include "crypto-handlers.h"
28 #include "debug.h"
29 #include "misc.h"
30
31 #include <QFile>
32 #include <QDir>
33 #include <QMetaEnum>
34 #include <QSettings>
35
36 #define DEVICE_MAPPER_DIR "/dev/mapper/"
37 #define EXT2 "ext2"
38 #define EXT3 "ext3"
39 #define EXT4 "ext4"
40
41 const uint CryptoManager::signonMinumumDbSize = 8;
42 const char CryptoManager::signonDefaultFileSystemName[] = "signonfs";
43 const char CryptoManager::signonDefaultFileSystemType[] = EXT2;
44
45 const QString CryptoManager::keychainFilePath() const
46 {
47 return m_fileSystemMountPath + QDir::separator() + QLatin1String("keychain");
48 }
49
50 void CryptoManager::addKeyToKeychain(const QByteArray &key) const
51 {
52 //If key is already present do not add it - backwards compat. feature
53 if (keychainContainsKey(key)) return;
54
55 QSettings keychain(keychainFilePath(), QSettings::IniFormat);
56 int keyCount = keychain.allKeys().count();
57 keychain.setValue(QString::number(++keyCount), QVariant(key));
58 }
59
60 void CryptoManager::removeKeyFromKeychain(const QByteArray &key) const
61 {
62 QSettings keychain(keychainFilePath(), QSettings::IniFormat);
63 foreach (QString keyIt, keychain.allKeys()) {
64 if (keychain.value(keyIt).toByteArray() == key) {
65 keychain.remove(keyIt);
66 break;
67 }
68 }
69 }
70
71 bool CryptoManager::keychainContainsKey(const QByteArray &key) const
72 {
73 QSettings keychain(keychainFilePath(), QSettings::IniFormat);
74 foreach (QString keyIt, keychain.allKeys()) {
75 if (keychain.value(keyIt).toByteArray() == key)
76 return true;
77 }
78
79 return false;
80 }
81
82 CryptoManager::CryptoManager(QObject *parent):
83 SignOn::AbstractCryptoManager(parent),
84 m_fileSystemPath(QString()),
85 m_fileSystemMapPath(QString()),
86 m_fileSystemName(QString()),
87 m_fileSystemMountPath(QString()),
88 m_loopDeviceName(QString()),
89 m_fileSystemType(Ext2),
90 m_fileSystemSize(4)
91 {
92 updateMountState(Unmounted);
93 if (!CryptsetupHandler::loadDmMod())
94 BLAME() << "Could not load `dm_mod`!";
95 }
96
97 CryptoManager::~CryptoManager()
98 {
99 unmountFileSystem();
100 }
101
102 bool CryptoManager::initialize(const QVariantMap &configuration)
103 {
104 QString storagePath =
105 QDir(configuration.value(QLatin1String("StoragePath")).toString()).path();
106 if (storagePath.startsWith(QLatin1Char('~')))
107 storagePath.replace(0, 1, QDir::homePath());
108
109 QString encryptedFSPath =
110 storagePath + QDir::separator() +
111 QLatin1String(signonDefaultFileSystemName);
112
113 bool isOk = false;
114 quint32 storageSize =
115 configuration.value(QLatin1String("Size")).toUInt(&isOk);
116 if (!isOk || storageSize < signonMinumumDbSize) {
117 storageSize = signonMinumumDbSize;
118 TRACE() << "Less than minimum possible storage size configured."
119 << "Setting to the minimum of:" << signonMinumumDbSize << "Mb";
120 }
121
122 QString fileSystemType =
123 configuration.value(QLatin1String("FileSystemType")).toString();
124
125 setFileSystemPath(encryptedFSPath);
126 setFileSystemSize(storageSize);
127 setFileSystemType(fileSystemType);
128
129 checkFileSystemSetup();
130 return true;
131 }
132
133 void CryptoManager::setFileSystemPath(const QString &path)
134 {
135 m_fileSystemPath = path;
136
137 QFileInfo fsFileInfo(path);
138
139 m_fileSystemName = fsFileInfo.fileName();
140 m_fileSystemMapPath = QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName;
141 m_fileSystemMountPath = path + QLatin1String("-mnt");
142 }
143
144 bool CryptoManager::setFileSystemSize(const quint32 size)
145 {
146 if (size < MINUMUM_ENCRYPTED_FILE_SYSTEM_SIZE) {
147 TRACE() << "Minumum encrypted file size is 4 Mb.";
148 return false;
149 }
150 m_fileSystemSize = size;
151 return true;
152 }
153
154 bool CryptoManager::setFileSystemType(const QString &type)
155 {
156 QString cmpBase = type.toLower();
157 if (cmpBase == QLatin1String(EXT2)) {
158 m_fileSystemType = Ext2;
159 return true;
160 } else if (cmpBase == QLatin1String(EXT3)) {
161 m_fileSystemType = Ext3;
162 return true;
163 } else if (cmpBase == QLatin1String(EXT4)) {
164 m_fileSystemType = Ext4;
165 return true;
166 }
167 return false;
168 }
169
170 void CryptoManager::checkFileSystemSetup()
171 {
172 setFileSystemSetup(QFile::exists(m_fileSystemPath));
173 }
174
175 bool CryptoManager::setupFileSystem()
176 {
177 if (m_mountState == Mounted) {
178 TRACE() << "Ecrypyted file system already mounted.";
179 return false;
180 }
181
182 if (encryptionKey().isEmpty()) {
183 TRACE() << "No access code set. Stopping mount process.";
184 return false;
185 }
186
187 if (!CryptsetupHandler::loadDmMod()) {
188 BLAME() << "Could not load `dm_mod`!";
189 return false;
190 }
191
192 clearFileSystemResources();
193
194 m_loopDeviceName = LosetupHandler::findAvailableDevice();
195 if (m_loopDeviceName.isNull()) {
196 BLAME() << "No free loop device available!";
197 return false;
198 }
199
200 if (!PartitionHandler::createPartitionFile(m_fileSystemPath,
201 m_fileSystemSize)) {
202 BLAME() << "Could not create partition file.";
203 unmountFileSystem();
204 return false;
205 }
206 checkFileSystemSetup();
207
208 if (!LosetupHandler::setupDevice(m_loopDeviceName,
209 m_fileSystemPath)) {
210 BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
211 unmountFileSystem();
212 return false;
213 }
214 updateMountState(LoopSet);
215
216 if (!CryptsetupHandler::formatFile(encryptionKey(), m_loopDeviceName)) {
217 BLAME() << "Failed to LUKS format.";
218 unmountFileSystem();
219 return false;
220 }
221 updateMountState(LoopLuksFormatted);
222
223 //attempt luks close, in case of a leftover.
224 if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
225 TRACE() << "Filesystem exists, closing";
226 CryptsetupHandler::closeFile(m_fileSystemName);
227 }
228
229 if (!CryptsetupHandler::openFile(encryptionKey(),
230 m_loopDeviceName,
231 m_fileSystemName)) {
232 BLAME() << "Failed to LUKS open";
233 unmountFileSystem();
234 return false;
235 }
236 updateMountState(LoopLuksOpened);
237
238 if (!PartitionHandler::formatPartitionFile(m_fileSystemMapPath,
239 m_fileSystemType)) {
240 BLAME() << "Could not format mapped partition.";
241 unmountFileSystem();
242 return false;
243 }
244
245 if (!mountMappedDevice()) {
246 BLAME() << "Failed to mount ecrypted file system.";
247 unmountFileSystem();
248 return false;
249 }
250
251 addKeyToKeychain(encryptionKey());
252 updateMountState(Mounted);
253 return true;
254 }
255
256 //TODO - add checking for LUKS header in case of preavious app run formatting
257 //failure
258 bool CryptoManager::mountFileSystem()
259 {
260 if (m_mountState == Mounted) {
261 TRACE() << "Ecrypyted file system already mounted.";
262 return false;
263 }
264
265 if (encryptionKey().isEmpty()) {
266 TRACE() << "No access code set. Stopping mount process.";
267 return false;
268 }
269
270 clearFileSystemResources();
271
272 if (!CryptsetupHandler::loadDmMod()) {
273 BLAME() << "Could not load `dm_mod`!";
274 return false;
275 }
276
277 m_loopDeviceName = LosetupHandler::findAvailableDevice();
278 if (m_loopDeviceName.isNull()) {
279 BLAME() << "No free loop device available!";
280 return false;
281 }
282
283 if (!LosetupHandler::setupDevice(m_loopDeviceName, m_fileSystemPath)) {
284 BLAME() << "Failed to setup loop device:" << m_loopDeviceName;
285 unmountFileSystem();
286 return false;
287 }
288 updateMountState(LoopSet);
289
290 //attempt luks close, in case of a leftover.
291 if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName))
292 CryptsetupHandler::closeFile(m_fileSystemName);
293
294 if (!CryptsetupHandler::openFile(encryptionKey(),
295 m_loopDeviceName,
296 m_fileSystemName)) {
297 BLAME() << "Failed to LUKS open.";
298 unmountFileSystem();
299 return false;
300 }
301 updateMountState(LoopLuksOpened);
302
303 if (!mountMappedDevice()) {
304 TRACE() << "Failed to mount ecrypted file system.";
305 unmountFileSystem();
306 return false;
307 }
308
309 addKeyToKeychain(encryptionKey());
310 updateMountState(Mounted);
311 return true;
312 }
313
314 void CryptoManager::clearFileSystemResources()
315 {
316 /*
317 This method is a `just in case call` for the situations
318 when signond closes whithout handling the unmounting of
319 the secure storage.
320 */
321
322 TRACE() << "--- START clearing secure storage possibly used resources."
323 " Ignore possible errors. ---";
324
325 if (!unmountMappedDevice())
326 TRACE() << "Unmounting mapped device failed.";
327
328 if (QFile::exists(QLatin1String(DEVICE_MAPPER_DIR) + m_fileSystemName)) {
329 if (!CryptsetupHandler::closeFile(m_fileSystemName))
330 TRACE() << "Failed to LUKS close.";
331 }
332
333 /*
334 TODO - find a way to check which loop device was previously used by
335 signond and close that specific one, until then this will be
336 skipped as it might close devices used by different processes.
337
338 if (!LosetupHandler::releaseDevice(m_loopDeviceName)) {
339 TRACE() << "Failed to release loop device.";
340 */
341
342 TRACE() << "--- DONE clearing secure storage possibly used resources. ---";
343 }
344
345 bool CryptoManager::unmountFileSystem()
346 {
347 if (m_mountState == Unmounted) {
348 TRACE() << "Ecrypyted file system not mounted.";
349 return true;
350 }
351
352 setFileSystemMounted(false);
353 bool isOk = true;
354
355 if ((m_mountState >= Mounted)
356 && !unmountMappedDevice()) {
357 TRACE() << "Failed to unmount mapped loop device.";
358 isOk = false;
359 } else {
360 TRACE() << "Mapped loop device unmounted.";
361 }
362
363 if ((m_mountState >= LoopLuksOpened)
364 && (!CryptsetupHandler::closeFile(m_fileSystemName))) {
365 TRACE() << "Failed to LUKS close.";
366 isOk = false;
367 } else {
368 TRACE() << "Luks close succeeded.";
369 }
370
371 if ((m_mountState >= LoopSet)
372 && (!LosetupHandler::releaseDevice(m_loopDeviceName))) {
373 TRACE() << "Failed to release loop device.";
374 isOk = false;
375 } else {
376 TRACE() << "Loop device released.";
377 }
378
379 updateMountState(Unmounted);
380 return isOk;
381 }
382
383 bool CryptoManager::deleteFileSystem()
384 {
385 if (m_mountState > Unmounted) {
386 if (!unmountFileSystem())
387 return false;
388 }
389
390 //TODO - implement effective deletion in specific handler object
391 return false;
392 }
393
394 QString CryptoManager::fileSystemMountPath() const
395 {
396 return m_fileSystemMountPath;
397 }
398
399 QStringList CryptoManager::backupFiles() const
400 {
401 return QStringList() << m_fileSystemPath;
402 }
403
404 void CryptoManager::updateMountState(const FileSystemMountState state)
405 {
406 TRACE() << "Updating mount state:" << state;
407 if (state == m_mountState) return;
408
409 m_mountState = state;
410 setFileSystemMounted(state == Mounted);
411 }
412
413 bool CryptoManager::mountMappedDevice()
414 {
415 //create mnt dir if not existant
416 if (!QFile::exists(m_fileSystemMountPath)) {
417 QDir dir;
418 if (!dir.mkpath(m_fileSystemMountPath)) {
419 BLAME() << "Could not create target mount dir path.";
420 return false;
421 }
422
423 if (!setUserOwnership(m_fileSystemMountPath))
424 TRACE() << "Failed to set User ownership for "
425 "the secure storage mount target.";
426 }
427
428 MountHandler::mount(m_fileSystemMapPath, m_fileSystemMountPath);
429 return true;
430 }
431
432 bool CryptoManager::unmountMappedDevice()
433 {
434 return MountHandler::umount(m_fileSystemMountPath);
435 }
436
437 bool CryptoManager::addEncryptionKey(const SignOn::Key &key,
438 const SignOn::Key &existingKey)
439 {
440 /*
441 * TODO -- limit number of stored keys to the total available slots - 1.
442 */
443 if (m_mountState >= LoopLuksOpened) {
444 if (CryptsetupHandler::addKeySlot(
445 m_loopDeviceName, key, existingKey)) {
446
447 addKeyToKeychain(key);
448 return true;
449 }
450 }
451 TRACE() << "FAILED to occupy key slot on the encrypted file system header.";
452 return false;
453 }
454
455 bool CryptoManager::removeEncryptionKey(const SignOn::Key &key,
456 const SignOn::Key &remainingKey)
457 {
458 if (m_mountState >= LoopLuksOpened) {
459 if (CryptsetupHandler::removeKeySlot(
460 m_loopDeviceName, key, remainingKey))
461
462 removeKeyFromKeychain(key);
463 return true;
464 }
465 TRACE() << "FAILED to release key slot from the encrypted file system "
466 "header.";
467 return false;
468 }
469
470 bool CryptoManager::encryptionKeyInUse(const SignOn::Key &key)
471 {
472 if (fileSystemIsMounted() && (encryptionKey() == key))
473 return true;
474
475 if(!fileSystemIsMounted()) {
476 setEncryptionKey(key);
477 return mountFileSystem();
478 }
479
480 /* Variant that tests if the key is in the LUKS keychain
481 * by using a file on the encrypted storage containing the keychain.
482 */
483 return keychainContainsKey(key);
484
485 /*
486 * Variant that tests if the key is in the LUKS keychain
487 * by directly accessing the LUKS system
488 *
489 * QByteArray dummyKey("dummy");
490 * if (addEncryptionKey(dummyKey, key)) {
491 * if (!removeEncryptionKey(dummyKey, key))
492 * BLAME() << "Could not remove dummy auxiliary key "
493 * "from encrypted file system header.";
494 * return true;
495 * }
496 *
497 * return false;
498 */
499 }
500
501 //TODO - remove this after stable version is achieved.
502 void CryptoManager::serializeData()
503 {
504 TRACE() << "m_accessCode" << encryptionKey();
505 TRACE() << "m_fileSystemPath" << m_fileSystemPath;
506 TRACE() << "m_fileSystemMapPath" << m_fileSystemMapPath;
507 TRACE() << "m_fileSystemName" << m_fileSystemName;
508 TRACE() << "m_loopDeviceName" << m_loopDeviceName;
509 TRACE() << "m_fileSystemType" << m_fileSystemType;
510 TRACE() << "m_fileSystemSize" << m_fileSystemSize;
511 }
512
LosetupHandler::setupDevice
static bool setupDevice(const QString &deviceName, const QString &blockDevice)
Mounts a block device to loopback device.
Definition: crypto-handlers.cpp:203
misc.h
EXT3
#define EXT3
Definition: crypto-manager.cpp:38
CryptoManager::deleteFileSystem
bool deleteFileSystem()
Deletes the encrypted file system.
Definition: crypto-manager.cpp:383
PartitionHandler::formatPartitionFile
static bool formatPartitionFile(const QString &fileName, const quint32 fileSystemType)
Formats a file (block device) for a specific file system type (ext2,ext3,ext4)
Definition: crypto-handlers.cpp:142
CryptoManager::~CryptoManager
~CryptoManager()
Destroys a CryptoManager object.
Definition: crypto-manager.cpp:97
PartitionHandler::createPartitionFile
static bool createPartitionFile(const QString &fileName, const quint32 fileSize)
Creates a random data file of fileSize Mb.
Definition: crypto-handlers.cpp:113
BLAME
#define BLAME()
Definition: debug.h:32
CryptoManager::mountFileSystem
bool mountFileSystem()
Mounts the encrypted file system.
Definition: crypto-manager.cpp:258
CryptoManager::removeEncryptionKey
bool removeEncryptionKey(const SignOn::Key &key, const SignOn::Key &remainingKey)
Releases an existing used keyslot in the LUKS partition&#39;s header.
Definition: crypto-manager.cpp:455
CryptsetupHandler::formatFile
static bool formatFile(const QByteArray &key, const QString &deviceName)
Formats the file system.
Definition: crypto-handlers.cpp:313
DEVICE_MAPPER_DIR
#define DEVICE_MAPPER_DIR
Definition: crypto-manager.cpp:36
CryptoManager::initialize
bool initialize(const QVariantMap &configuration)
Definition: crypto-manager.cpp:102
CryptsetupHandler::loadDmMod
static bool loadDmMod()
Loads the dm_mod kernel module.
Definition: crypto-handlers.cpp:652
debug.h
CryptoManager::backupFiles
QStringList backupFiles() const
Definition: crypto-manager.cpp:399
CryptsetupHandler::closeFile
static bool closeFile(const QString &deviceName)
Closes the file system.
Definition: crypto-handlers.cpp:464
MountHandler::umount
static bool umount(const QString &target)
Unmounts a block device from a specific location.
Definition: crypto-handlers.cpp:173
CryptoManager::Ext2
Definition: crypto-manager.h:71
crypto-manager.h
setUserOwnership
bool setUserOwnership(const QString &filePath)
Definition: misc.cpp:33
EXT4
#define EXT4
Definition: crypto-manager.cpp:39
CryptoManager::CryptoManager
CryptoManager(QObject *parent=0)
Constructs a CryptoManager object with the given parent.
Definition: crypto-manager.cpp:82
CryptsetupHandler::removeKeySlot
static bool removeKeySlot(const QString &deviceName, const QByteArray &key, const QByteArray &remainingKey)
Removes a key ocupying an encryption header slot.
Definition: crypto-handlers.cpp:614
TRACE
#define TRACE()
Definition: debug.h:28
CryptoManager::encryptionKeyInUse
bool encryptionKeyInUse(const SignOn::Key &key)
Definition: crypto-manager.cpp:470
MINUMUM_ENCRYPTED_FILE_SYSTEM_SIZE
#define MINUMUM_ENCRYPTED_FILE_SYSTEM_SIZE
Definition: crypto-manager.h:38
CryptoManager::fileSystemMountPath
QString fileSystemMountPath() const
Definition: crypto-manager.cpp:394
CryptsetupHandler::addKeySlot
static bool addKeySlot(const QString &deviceName, const QByteArray &key, const QByteArray &existingKey)
Adds a key to a free encryption header slot.
Definition: crypto-handlers.cpp:533
CryptoManager::Ext3
Definition: crypto-manager.h:72
CryptoManager::addEncryptionKey
bool addEncryptionKey(const SignOn::Key &key, const SignOn::Key &existingKey)
Adds an encryption key to one of the available keyslots of the LUKS partition&#39;s header.
Definition: crypto-manager.cpp:437
CryptoManager::Ext4
Definition: crypto-manager.h:73
CryptoManager::unmountFileSystem
bool unmountFileSystem()
Unmounts the encrypted file system.
Definition: crypto-manager.cpp:345
MountHandler::mount
static bool mount(const QString &source, const QString &target, const QString &fileSystemType=QLatin1String("ext2"))
Mounts a block device to a specific location.
Definition: crypto-handlers.cpp:162
LosetupHandler::releaseDevice
static bool releaseDevice(const QString &deviceName)
Releases a used loopback device.
Definition: crypto-handlers.cpp:229
EXT2
#define EXT2
Definition: crypto-manager.cpp:37
LosetupHandler::findAvailableDevice
static QString findAvailableDevice()
Finds an available loopback device.
Definition: crypto-handlers.cpp:212
crypto-handlers.h
CryptsetupHandler::openFile
static bool openFile(const QByteArray &key, const QString &deviceName, const QString &deviceMap)
Opens the file system.
Definition: crypto-handlers.cpp:404
CryptoManager::setupFileSystem
bool setupFileSystem()
Sets up an encrypted file system.
Definition: crypto-manager.cpp:175