signon  8.58
crypto-handlers.cpp
Go to the documentation of this file.
00001 /* -*- Mode: C++; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
00002 /*
00003  * This file is part of signon
00004  *
00005  * Copyright (C) 2009-2010 Nokia Corporation.
00006  *
00007  * Contact: Aurel Popirtac <ext-aurel.popirtac@nokia.com>
00008  * Contact: Alberto Mardegan <alberto.mardegan@canonical.com>
00009  *
00010  * This library is free software; you can redistribute it and/or
00011  * modify it under the terms of the GNU Lesser General Public License
00012  * version 2.1 as published by the Free Software Foundation.
00013  *
00014  * This library is distributed in the hope that it will be useful, but
00015  * WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00017  * Lesser General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU Lesser General Public
00020  * License along with this library; if not, write to the Free Software
00021  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
00022  * 02110-1301 USA
00023  */
00024 
00025 #include <sys/mount.h>
00026 #include <errno.h>
00027 #include <fcntl.h>
00028 #include <stdlib.h>
00029 #include <libcryptsetup.h>
00030 
00031 #include <QDataStream>
00032 #include <QTextStream>
00033 #include <QProcess>
00034 #include <QLatin1Char>
00035 #include <QFileInfo>
00036 #include <QDir>
00037 
00038 #include "crypto-handlers.h"
00039 #include "debug.h"
00040 #include "misc.h"
00041 
00042 #define SIGNON_LUKS_DEFAULT_HASH  "ripemd160"
00043 
00044 #define SIGNON_LUKS_CIPHER_NAME   "aes"
00045 #define SIGNON_LUKS_CIPHER_MODE   "xts-plain"
00046 #define SIGNON_LUKS_CIPHER        \
00047     SIGNON_LUKS_CIPHER_NAME "-" SIGNON_LUKS_CIPHER_MODE
00048 #define SIGNON_LUKS_KEY_SIZE      256
00049 #define SIGNON_LUKS_BASE_KEYSLOT  0
00050 
00051 #define SIGNON_EXTERNAL_PROCESS_READ_TIMEOUT 300
00052 
00053 #define KILO_BYTE_SIZE 1024
00054 #define MEGA_BYTE_SIZE (KILO_BYTE_SIZE * 1024)
00055 
00056 /*  ------------- SystemCommandLineCallHandler implementation -------------- */
00057 
00058 SystemCommandLineCallHandler::SystemCommandLineCallHandler()
00059 {
00060     connect(&m_process, SIGNAL(error(QProcess::ProcessError)),
00061             this, SLOT(error(QProcess::ProcessError)));
00062 }
00063 
00064 SystemCommandLineCallHandler::~SystemCommandLineCallHandler()
00065 {
00066 }
00067 
00068 bool SystemCommandLineCallHandler::makeCall(const QString &appPath,
00069                                             const QStringList &args,
00070                                             bool readOutput)
00071 {
00072     QString trace;
00073     QTextStream stream(&trace);
00074     stream << appPath << QLatin1Char(' ') << args.join(QLatin1String(" "));
00075     TRACE() << trace;
00076 
00077     m_process.start(appPath, args);
00078     if (!m_process.waitForStarted()) {
00079         BLAME() << "Wait for started failed";
00080         return false;
00081     }
00082 
00083     if (readOutput) {
00084         m_output.clear();
00085 
00086         if (m_process.waitForReadyRead(SIGNON_EXTERNAL_PROCESS_READ_TIMEOUT)) {
00087             if (!m_process.bytesAvailable()) {
00088                 BLAME() << "Coult not read output of external process ";
00089                 return false;
00090             }
00091 
00092             while(m_process.bytesAvailable())
00093                 m_output += m_process.readAllStandardOutput();
00094         }
00095     }
00096 
00097     if (!m_process.waitForFinished()) {
00098         TRACE() << "Wait for finished failed";
00099         return false;
00100     }
00101 
00102     return true;
00103 }
00104 
00105 void SystemCommandLineCallHandler::error(QProcess::ProcessError err)
00106 {
00107     TRACE() << "Process erorr:" << err;
00108 }
00109 
00110 
00111 /*  ------------------ PartitionHandler implementation --------------------- */
00112 
00113 bool PartitionHandler::createPartitionFile(const QString &fileName,
00114                                            const quint32 fileSize)
00115 {
00116     int fd = open(fileName.toLatin1().data(),
00117                   O_RDWR | O_CREAT,
00118                   666);
00119 
00120     if (fd < 0) {
00121         BLAME() << "FAILED to create signon secure FS partition file. ERRNO:"
00122                 << errno;
00123         return false;
00124     }
00125 
00126     if (ftruncate(fd, fileSize * MEGA_BYTE_SIZE) == -1) {
00127         BLAME() << "FAILED to set signon secure FS partition file size. ERRNO:"
00128                 << errno;
00129         return false;
00130     }
00131 
00132     if (close(fd) < 0)
00133         TRACE() << "Failed to close secure FS partition file after creation.";
00134 
00135     if (!setFilePermissions(fileName, signonFilePermissions))
00136         TRACE() << "Failed to set file permissions "
00137                    "for the secure storage container.";
00138 
00139     return true;
00140 }
00141 
00142 bool PartitionHandler::formatPartitionFile(const QString &fileName,
00143                                            const quint32 fileSystemType)
00144 {
00145     QString mkfsApp = QString::fromLatin1("/sbin/mkfs.ext2");
00146     switch (fileSystemType) {
00147         case Ext2: mkfsApp = QString::fromLatin1("/sbin/mkfs.ext2"); break;
00148         case Ext3: mkfsApp = QString::fromLatin1("/sbin/mkfs.ext3"); break;
00149         case Ext4: mkfsApp = QString::fromLatin1("/sbin/mkfs.ext4"); break;
00150         default: break;
00151     }
00152 
00153     SystemCommandLineCallHandler handler;
00154     return handler.makeCall(
00155                         mkfsApp,
00156                         QStringList() << fileName);
00157 }
00158 
00159 
00160 /*  --------------------- MountHandler implementation ---------------------- */
00161 
00162 bool MountHandler::mount(const QString &toMount,
00163                          const QString &mountPath,
00164                          const QString &fileSystemTtpe)
00165 {
00166     /* Mount a filesystem.  */
00167     return (::mount(toMount.toUtf8().constData(),
00168                     mountPath.toUtf8().constData(),
00169                     fileSystemTtpe.toUtf8().constData(),
00170                     MS_SYNCHRONOUS | MS_NOEXEC, NULL) == 0);
00171 }
00172 
00173 bool MountHandler::umount(const QString &mountPath)
00174 {
00175     /* Unmount a filesystem.  */
00176 
00177     //TODO - investigate why errno is EINVAL
00178 
00179     TRACE() << mountPath.toUtf8().constData();
00180     int ret = ::umount2(mountPath.toUtf8().constData(), MNT_FORCE);
00181     TRACE() << ret;
00182 
00183     switch (errno) {
00184     case EAGAIN: TRACE() << "EAGAIN"; break;
00185     case EBUSY: TRACE() << "EBUSY"; break;
00186     case EFAULT: TRACE() << "EFAULT"; break;
00187     case EINVAL: TRACE() << "EINVAL"; break;
00188     case ENAMETOOLONG: TRACE() << "ENAMETOOLONG"; break;
00189     case ENOENT: TRACE() << "ENOENT"; break;
00190     case ENOMEM: TRACE() << "ENOMEM"; break;
00191     case EPERM: TRACE() << "EPERM"; break;
00192     default: TRACE() << "umount unknown error - ignoring.";
00193     }
00194 
00195     //TODO - Remove 1st, uncommend 2nd lines after the fix above.
00196     //       This is tmp hack so that the tests will work.
00197     return true;
00198     //return (ret == 0);
00199 }
00200 
00201 /*  ----------------------- LosetupHandler implementation ----------------------- */
00202 
00203 bool LosetupHandler::setupDevice(const QString &deviceName,
00204                                  const QString &blockDevice)
00205 {
00206     SystemCommandLineCallHandler handler;
00207     return handler.makeCall(
00208                         QLatin1String("/sbin/losetup"),
00209                         QStringList() << deviceName << blockDevice);
00210 }
00211 
00212 QString LosetupHandler::findAvailableDevice()
00213 {
00214     SystemCommandLineCallHandler handler;
00215     QString deviceName;
00216     bool ret = handler.makeCall(
00217                             QLatin1String("/sbin/losetup"),
00218                             QStringList() << QLatin1String("-f"),
00219                             true);
00220 
00221     deviceName = QString::fromLocal8Bit(handler.output().trimmed());
00222 
00223     if (ret)
00224         return deviceName;
00225 
00226     return QString();
00227 }
00228 
00229 bool LosetupHandler::releaseDevice(const QString &deviceName)
00230 {
00231     SystemCommandLineCallHandler handler;
00232     return handler.makeCall(QLatin1String("/sbin/losetup"),
00233                             QStringList() <<
00234                             QString::fromLatin1("-d") << deviceName);
00235 }
00236 
00237 /*  -------------------- CrytpsetupHandler implementation ------------------ */
00238 
00239 /*
00240     Callbacks for the interface callbacks struct in crypt_options struct.
00241 */
00242 static int yesDialog(char *msg)
00243 {
00244     Q_UNUSED(msg);
00245     return 0;
00246 }
00247 
00248 static void cmdLineLog(int type, char *msg)
00249 {
00250     switch (type) {
00251         case CRYPT_LOG_NORMAL:
00252             TRACE() << msg;
00253             break;
00254         case CRYPT_LOG_ERROR:
00255             TRACE() << "Error: " << msg;
00256             break;
00257         default:
00258             TRACE() << "Internal error on logging class for msg: " << msg;
00259             break;
00260     }
00261 }
00262 
00263 static void log_wrapper(int level, const char *msg, void *usrptr)
00264 {
00265     void (*xlog)(int level, char *msg) = (void (*)(int, char*)) usrptr;
00266     xlog(level, (char *)msg);
00267 }
00268 
00269 static int yesDialog_wrapper(const char *msg, void *usrptr)
00270 {
00271     int (*xyesDialog)(char *msg) = (int (*)(char*)) usrptr;
00272     return xyesDialog((char*)msg);
00273 }
00274 
00275 int crypt_luksFormatBinary(struct crypt_options *options,
00276                            const char *pwd,
00277                            unsigned int pwdLen)
00278 {
00279     struct crypt_device *cd = NULL;
00280     struct crypt_params_luks1 cp = {
00281         options->hash,
00282         options->align_payload
00283     };
00284     int r;
00285 
00286     if ((r = crypt_init(&cd, options->device)))
00287         return -EINVAL;
00288 
00289     crypt_set_log_callback(cd, log_wrapper, (void*) options->icb->log);
00290     crypt_set_confirm_callback(cd, yesDialog_wrapper,
00291                                (void*) options->icb->yesDialog);
00292 
00293     crypt_set_timeout(cd, options->timeout);
00294     crypt_set_password_retry(cd, options->tries);
00295     crypt_set_iterarion_time(cd, options->iteration_time ?: 1000);
00296     crypt_set_password_verify(cd, options->flags & CRYPT_FLAG_VERIFY);
00297 
00298     r = crypt_format(cd, CRYPT_LUKS1,
00299                      SIGNON_LUKS_CIPHER_NAME, SIGNON_LUKS_CIPHER_MODE,
00300                      NULL, NULL, options->key_size, &cp);
00301     if (r < 0)
00302         goto out;
00303 
00304     /* Add keyslot using internally stored volume key generated during format */
00305     r = crypt_keyslot_add_by_volume_key(cd, options->key_slot, NULL, 0,
00306                                         pwd, pwdLen);
00307 out:
00308     crypt_free(cd);
00309     return (r < 0) ? r : 0;
00310 
00311 }
00312 
00313 bool CryptsetupHandler::formatFile(const QByteArray &key,
00314                                    const QString &deviceName)
00315 {
00316     struct crypt_options options;
00317 
00318     options.key_size = SIGNON_LUKS_KEY_SIZE / 8;
00319     options.key_slot = SIGNON_LUKS_BASE_KEYSLOT;
00320 
00321     char *localDeviceName = (char *)malloc(deviceName.length() + 1);
00322     Q_ASSERT(localDeviceName != NULL);
00323 
00324     strcpy(localDeviceName, deviceName.toLatin1().constData());
00325     options.device = localDeviceName;
00326 
00327     options.cipher = SIGNON_LUKS_CIPHER;
00328     options.new_key_file = NULL;
00329 
00330     char *localKey = (char *)malloc(key.length());
00331     Q_ASSERT(localKey != NULL);
00332     memcpy(localKey, key.constData(), key.length());
00333 
00334     options.flags = 0;
00335     options.iteration_time = 1000;
00336     options.timeout = 0;
00337     options.align_payload = 0;
00338 
00339     static struct interface_callbacks cmd_icb;
00340     cmd_icb.yesDialog = 0;
00341     cmd_icb.log = 0;
00342     options.icb = &cmd_icb;
00343 
00344     TRACE() << "Device: [" << options.device << "]";
00345     TRACE() << "Key size:" << key.length();
00346 
00347     int ret = crypt_luksFormatBinary(&options, localKey, key.length());
00348 
00349     if (ret != 0)
00350         TRACE() << "LUKS format API call result:" << ret << "." << error();
00351 
00352     if (localDeviceName)
00353         free(localDeviceName);
00354 
00355     if (localKey) {
00356         memset(localKey, 0x00, key.length());
00357         free(localKey);
00358     }
00359 
00360     return (ret == 0);
00361 }
00362 
00363 int crypt_luksOpenBinary(struct crypt_options *options,
00364                          const char *pwd, unsigned int pwdLen)
00365 {
00366     struct crypt_device *cd = NULL;
00367     uint32_t flags = 0;
00368     int r;
00369 
00370     if ((r = crypt_init(&cd, options->device)))
00371         return -EINVAL;
00372 
00373     crypt_set_log_callback(cd, log_wrapper, (void*) options->icb->log);
00374     crypt_set_confirm_callback(cd, yesDialog_wrapper,
00375                                (void*) options->icb->yesDialog);
00376 
00377     crypt_set_timeout(cd, options->timeout);
00378     crypt_set_password_retry(cd, options->tries);
00379     crypt_set_iterarion_time(cd, options->iteration_time ?: 1000);
00380     crypt_set_password_verify(cd, options->flags & CRYPT_FLAG_VERIFY);
00381 
00382     if ((r = crypt_load(cd, CRYPT_LUKS1, NULL))) {
00383         crypt_free(cd);
00384         return r;
00385     }
00386 
00387     if (options->flags & CRYPT_FLAG_READONLY)
00388         flags |= CRYPT_ACTIVATE_READONLY;
00389 
00390     if (options->flags & CRYPT_FLAG_NON_EXCLUSIVE_ACCESS)
00391         flags |= CRYPT_ACTIVATE_NO_UUID;
00392 
00393     if (options->key_file)
00394         r = -1;
00395     else
00396         r = crypt_activate_by_passphrase(cd, options->name,
00397                                          CRYPT_ANY_SLOT,
00398                                          pwd, pwdLen, flags);
00399 
00400     crypt_free(cd);
00401     return (r < 0) ? r : 0;
00402 }
00403 
00404 bool CryptsetupHandler::openFile(const QByteArray &key,
00405                                  const QString &deviceName,
00406                                  const QString &deviceMap)
00407 {
00408     struct crypt_options options;
00409 
00410     char *localDeviceMap = (char *)malloc(deviceMap.length() + 1);
00411     Q_ASSERT(localDeviceMap != NULL);
00412     strcpy(localDeviceMap, deviceMap.toLatin1().constData());
00413     options.name = localDeviceMap;
00414 
00415     char *localDeviceName = (char *)malloc(deviceName.length() + 1);
00416     Q_ASSERT(localDeviceName != NULL);
00417     strcpy(localDeviceName, deviceName.toLatin1().constData());
00418     options.device = localDeviceName;
00419 
00420     char *localKey = (char *)malloc(key.length());
00421     Q_ASSERT(localKey != NULL);
00422     memcpy(localKey, key.constData(), key.length());
00423 
00424     options.key_file = NULL;
00425     options.timeout = 0;
00426     /*
00427         Do not change this:
00428         1) In case of failure to open, libcryptsetup code will
00429         enter infinite loop - library BUG/FEATURE.
00430         2) There is no need for multiple tries, option is intended for
00431         command line use of the utility.
00432     */
00433     options.tries = 0;
00434     options.flags = 0;
00435 
00436     static struct interface_callbacks cmd_icb;
00437     cmd_icb.yesDialog = yesDialog;
00438     cmd_icb.log = cmdLineLog;
00439     options.icb = &cmd_icb;
00440 
00441     TRACE() << "Device [" << options.device << "]";
00442     TRACE() << "Map name [" << options.name << "]";
00443     TRACE() << "Key size:" << key.length();
00444 
00445     int ret = crypt_luksOpenBinary(&options, localKey, key.length());
00446 
00447     if (ret != 0)
00448         TRACE() << "LUKS open API call result:" << ret << "." << error() << ".";
00449 
00450     if (localDeviceName)
00451         free(localDeviceName);
00452 
00453     if (localDeviceMap)
00454         free(localDeviceMap);
00455 
00456     if (localKey) {
00457         memset(localKey, 0x00, key.length());
00458         free(localKey);
00459     }
00460 
00461     return (ret == 0);
00462 }
00463 
00464 bool CryptsetupHandler::closeFile(const QString &deviceMap)
00465 {
00466     struct crypt_options options;
00467 
00468     char *localDeviceMap = (char *)malloc(deviceMap.length() + 1);
00469     Q_ASSERT(localDeviceMap != NULL);
00470     strcpy(localDeviceMap, deviceMap.toLatin1().constData());
00471     options.name = localDeviceMap;
00472 
00473     static struct interface_callbacks cmd_icb;
00474     cmd_icb.yesDialog = yesDialog;
00475     cmd_icb.log = cmdLineLog;
00476     options.icb = &cmd_icb;
00477 
00478     TRACE() << "Map name [" << options.name << "]";
00479 
00480     int ret = crypt_remove_device(&options);
00481 
00482     if (ret != 0)
00483         TRACE() << "Cryptsetup remove API call result:" << ret <<
00484             "." <<  error();
00485 
00486     if (localDeviceMap)
00487         free(localDeviceMap);
00488 
00489     return (ret == 0);
00490 }
00491 
00492 bool CryptsetupHandler::removeFile(const QString &deviceName)
00493 {
00494     Q_UNUSED(deviceName);
00495     //todo - delete file system (wipe credentials storege) is based on this
00496     return false;
00497 }
00498 
00499 int crypt_luksAddKeyBinary(struct crypt_options *options,
00500                            const char *pwd, unsigned int pwdLen,
00501                            const char *newPwd, unsigned int newPwdLen)
00502 {
00503     struct crypt_device *cd = NULL;
00504     int r;
00505 
00506     if ((r = crypt_init(&cd, options->device)))
00507         return -EINVAL;
00508 
00509     crypt_set_log_callback(cd, log_wrapper, (void*) options->icb->log);
00510     crypt_set_confirm_callback(cd, yesDialog_wrapper,
00511                                (void*) options->icb->yesDialog);
00512 
00513     crypt_set_timeout(cd, options->timeout);
00514     crypt_set_password_retry(cd, options->tries);
00515     crypt_set_iterarion_time(cd, options->iteration_time ?: 1000);
00516     crypt_set_password_verify(cd, options->flags & CRYPT_FLAG_VERIFY);
00517 
00518     if ((r = crypt_load(cd, CRYPT_LUKS1, NULL))) {
00519         crypt_free(cd);
00520         return r;
00521     }
00522 
00523     if (options->key_file || options->new_key_file)
00524         r = -1;
00525     else
00526         r = crypt_keyslot_add_by_passphrase(cd, options->key_slot,
00527                                             pwd, pwdLen, newPwd, newPwdLen);
00528 
00529     crypt_free(cd);
00530     return (r < 0) ? r : 0;
00531 }
00532 
00533 bool CryptsetupHandler::addKeySlot(const QString &deviceName,
00534                                    const QByteArray &key,
00535                                    const QByteArray &existingKey)
00536 {
00537     struct crypt_options options;
00538 
00539     options.key_size = SIGNON_LUKS_KEY_SIZE / 8;
00540     options.cipher = SIGNON_LUKS_CIPHER;
00541 
00542     char *localDeviceName = (char *)malloc(deviceName.length() + 1);
00543     Q_ASSERT(localDeviceName != NULL);
00544     strcpy(localDeviceName, deviceName.toLatin1().constData());
00545 
00546     options.device = localDeviceName;
00547     options.new_key_file = NULL;
00548     options.key_file = NULL;
00549     options.key_slot = -1;
00550 
00551     options.flags = 0;
00552     options.iteration_time = 1000;
00553     options.timeout = 0;
00554     options.tries = 0;
00555 
00556     static struct interface_callbacks cmd_icb;
00557     cmd_icb.yesDialog = yesDialog;
00558     cmd_icb.log = cmdLineLog;
00559     options.icb = &cmd_icb;
00560 
00561     int ret = crypt_luksAddKeyBinary(&options,
00562                                      existingKey.constData(),
00563                                      existingKey.length(),
00564                                      key.constData(), key.length());
00565 
00566     if (localDeviceName)
00567         free(localDeviceName);
00568 
00569     if (ret != 0)
00570         TRACE() << "Cryptsetup add key API call result:" << ret <<
00571             "." <<  error();
00572 
00573     return (ret == 0);
00574 }
00575 
00576 int crypt_luksRemoveKeyBinary(struct crypt_options *options,
00577                               const char *pwdToRemove,
00578                               unsigned int pwdToRemoveLen)
00579 {
00580     struct crypt_device *cd = NULL;
00581     int key_slot;
00582     int r;
00583 
00584     if ((r = crypt_init(&cd, options->device)))
00585         return -EINVAL;
00586 
00587     crypt_set_log_callback(cd, log_wrapper, (void*) options->icb->log);
00588     crypt_set_confirm_callback(cd, yesDialog_wrapper,
00589                                (void*) options->icb->yesDialog);
00590 
00591     crypt_set_timeout(cd, options->timeout);
00592     crypt_set_password_retry(cd, options->tries);
00593     crypt_set_iterarion_time(cd, options->iteration_time ?: 1000);
00594     crypt_set_password_verify(cd, options->flags & CRYPT_FLAG_VERIFY);
00595 
00596     if ((r = crypt_load(cd, CRYPT_LUKS1, NULL))) {
00597         crypt_free(cd);
00598         return r;
00599     }
00600 
00601     if ((key_slot = crypt_keyslot_by_passphrase(cd, NULL, pwdToRemove,
00602                                                 pwdToRemoveLen, 0, NULL)) < 0) {
00603         r = -EPERM;
00604         goto out;
00605     }
00606 
00607     r = crypt_keyslot_destroy(cd, key_slot);
00608 
00609 out:
00610     crypt_free(cd);
00611     return (r < 0) ? r : 0;
00612 }
00613 
00614 bool CryptsetupHandler::removeKeySlot(const QString &deviceName,
00615                                       const QByteArray &key,
00616                                       const QByteArray &remainingKey)
00617 {
00618     struct crypt_options options;
00619 
00620     options.key_size = SIGNON_LUKS_KEY_SIZE / 8;
00621     options.cipher = SIGNON_LUKS_CIPHER;
00622 
00623     char *localDeviceName = (char *)malloc(deviceName.length() + 1);
00624     Q_ASSERT(localDeviceName != NULL);
00625     strcpy(localDeviceName, deviceName.toLatin1().constData());
00626 
00627     options.device = localDeviceName;
00628     options.new_key_file = NULL;
00629     options.key_file = NULL;
00630     options.key_slot = -1;
00631 
00632     options.flags = 0;
00633     options.timeout = 0;
00634 
00635     static struct interface_callbacks cmd_icb;
00636     cmd_icb.yesDialog = yesDialog;
00637     cmd_icb.log = cmdLineLog;
00638     options.icb = &cmd_icb;
00639 
00640     int ret = crypt_luksRemoveKeyBinary(&options, key.constData(), key.length());
00641 
00642     if (localDeviceName)
00643         free(localDeviceName);
00644 
00645     if (ret != 0)
00646         TRACE() << "Cryptsetup remove key API call result:" << ret <<
00647             "." <<  error();
00648 
00649     return (ret == 0);
00650 }
00651 
00652 bool CryptsetupHandler::loadDmMod()
00653 {
00654     SystemCommandLineCallHandler handler;
00655     return handler.makeCall(
00656                         QLatin1String("/sbin/modprobe"),
00657                         QStringList() << QString::fromLatin1("dm_mod"));
00658 }
00659 
00660 QString CryptsetupHandler::error()
00661 {
00662     char buf[260];
00663     crypt_get_error(buf, 256);
00664     return QString::fromLocal8Bit(buf);
00665 }
00666