From 6095bc10ad5fc08d8202e3a8f05a7998253f6e6c Mon Sep 17 00:00:00 2001 From: Timothy Pearson Date: Mon, 14 Sep 2015 20:46:15 -0500 Subject: Add cryptographic card support to LUKS configuration --- kcontrol/hwmanager/cryptpassworddlg.cpp | 33 ++++- kcontrol/hwmanager/cryptpassworddlg.h | 5 +- kcontrol/hwmanager/cryptpassworddlgbase.ui | 16 ++ kcontrol/hwmanager/devicepropsdlg.cpp | 228 ++++++++++++++++++++++++++++- kcontrol/hwmanager/devicepropsdlgbase.ui | 24 +++ kcontrol/hwmanager/hwmanager.cpp | 27 +++- kcontrol/hwmanager/hwmanager.h | 1 + 7 files changed, 319 insertions(+), 15 deletions(-) diff --git a/kcontrol/hwmanager/cryptpassworddlg.cpp b/kcontrol/hwmanager/cryptpassworddlg.cpp index 43d714e12..1d66d89c1 100644 --- a/kcontrol/hwmanager/cryptpassworddlg.cpp +++ b/kcontrol/hwmanager/cryptpassworddlg.cpp @@ -46,11 +46,13 @@ #include #include #include +#include #include "cryptpassworddlg.h" -CryptPasswordDialog::CryptPasswordDialog(TQWidget *parent, TQString passwordPrompt, TQString caption) - : KDialogBase(Plain, ((caption == "")?i18n("Enter Password"):caption), Ok|Cancel, Ok, parent, 0L, true, true) +CryptPasswordDialog::CryptPasswordDialog(TQWidget *parent, TQString passwordPrompt, TQString caption, bool allow_card, KSSLCertificate* card_cert, bool* use_card) + : KDialogBase(Plain, ((caption == "")?i18n("Enter Password"):caption), Ok|Cancel, Ok, parent, 0L, true, true), + m_useCard(use_card) { m_base = new CryptPasswordDialogBase(plainPage()); @@ -61,8 +63,19 @@ CryptPasswordDialog::CryptPasswordDialog(TQWidget *parent, TQString passwordProm m_base->passwordPrompt->setText(passwordPrompt); m_base->passwordIcon->setPixmap(SmallIcon("password.png")); + if (!allow_card) { + m_base->cardKeyButton->hide(); + m_base->cardKeyInfo->hide(); + } + else { + if (card_cert) { + m_base->cardKeyInfo->setText(card_cert->getSubject()); + } + } + connect(m_base->textPasswordButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(processLockouts())); connect(m_base->filePasswordButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(processLockouts())); + connect(m_base->cardKeyButton, TQT_SIGNAL(clicked()), this, TQT_SLOT(processLockouts())); connect(m_base->textPasswordEntry, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(processLockouts())); connect(m_base->filePasswordURL, TQT_SIGNAL(textChanged(const TQString&)), this, TQT_SLOT(processLockouts())); @@ -78,9 +91,14 @@ CryptPasswordDialog::~CryptPasswordDialog() TQByteArray CryptPasswordDialog::password() { if (m_base->textPasswordButton->isOn() == true) { m_password.duplicate(m_base->textPasswordEntry->password(), strlen(m_base->textPasswordEntry->password())); + if (m_useCard) *m_useCard = false; } - else { + else if (m_base->filePasswordButton->isOn() == true) { m_password = TQFile(m_base->filePasswordURL->url()).readAll(); + if (m_useCard) *m_useCard = false; + } + else { + if (m_useCard) *m_useCard = true; } return m_password; @@ -90,6 +108,7 @@ void CryptPasswordDialog::processLockouts() { if (m_base->textPasswordButton->isOn() == true) { m_base->textPasswordEntry->setEnabled(true); m_base->filePasswordURL->setEnabled(false); + m_base->textPasswordEntry->setFocus(); if (strlen(m_base->textPasswordEntry->password()) > 0) { enableButtonOK(true); } @@ -97,9 +116,10 @@ void CryptPasswordDialog::processLockouts() { enableButtonOK(false); } } - else { + else if (m_base->filePasswordButton->isOn() == true) { m_base->textPasswordEntry->setEnabled(false); m_base->filePasswordURL->setEnabled(true); + m_base->filePasswordURL->setFocus(); if (TQFile(m_base->filePasswordURL->url()).exists()) { enableButtonOK(true); } @@ -107,6 +127,11 @@ void CryptPasswordDialog::processLockouts() { enableButtonOK(false); } } + else { + m_base->textPasswordEntry->setEnabled(false); + m_base->filePasswordURL->setEnabled(false); + enableButtonOK(true); + } } void CryptPasswordDialog::virtual_hook( int id, void* data ) diff --git a/kcontrol/hwmanager/cryptpassworddlg.h b/kcontrol/hwmanager/cryptpassworddlg.h index 8cec6e55b..d595c4a73 100644 --- a/kcontrol/hwmanager/cryptpassworddlg.h +++ b/kcontrol/hwmanager/cryptpassworddlg.h @@ -23,6 +23,8 @@ #include "cryptpassworddlgbase.h" +class KSSLCertificate; + /** * * Dialog to enter LUKS passwords or password files @@ -39,7 +41,7 @@ public: * Create a dialog that allows a user to enter LUKS passwords or password files * @param parent Parent widget */ - CryptPasswordDialog(TQWidget *parent, TQString passwordPrompt, TQString caption=TQString::null); + CryptPasswordDialog(TQWidget *parent, TQString passwordPrompt, TQString caption=TQString::null, bool allow_card=false, KSSLCertificate* card_cert=NULL, bool* use_card=NULL); virtual ~CryptPasswordDialog(); TQByteArray password(); @@ -53,6 +55,7 @@ private slots: private: CryptPasswordDialogBase* m_base; TQByteArray m_password; + bool* m_useCard; class CryptPasswordDialogPrivate; CryptPasswordDialogPrivate* d; diff --git a/kcontrol/hwmanager/cryptpassworddlgbase.ui b/kcontrol/hwmanager/cryptpassworddlgbase.ui index 7c61187ae..549a591b0 100644 --- a/kcontrol/hwmanager/cryptpassworddlgbase.ui +++ b/kcontrol/hwmanager/cryptpassworddlgbase.ui @@ -112,6 +112,22 @@ 17 + + + cardKeyButton + + + Cryptographic Card + + + + + cardKeyInfo + + + + + diff --git a/kcontrol/hwmanager/devicepropsdlg.cpp b/kcontrol/hwmanager/devicepropsdlg.cpp index 7ce36f1b3..a1ef81c2b 100644 --- a/kcontrol/hwmanager/devicepropsdlg.cpp +++ b/kcontrol/hwmanager/devicepropsdlg.cpp @@ -41,6 +41,7 @@ #include #include #include +#include #include "cryptpassworddlg.h" @@ -800,12 +801,47 @@ void DevicePropertiesDialog::updateCryptographicCardStatusDisplay() { int status = cdevice->cardPresent(); if ((status < 0) ||(status > 1)) { base->labelCardStatus->setText(i18n("Unknown")); + base->labelCardCertificates->setText(""); + base->groupCardCerts->hide(); } else if (status == 0) { base->labelCardStatus->setText(i18n("Empty")); + base->labelCardCertificates->setText(""); + base->groupCardCerts->hide(); } else if (status == 1) { base->labelCardStatus->setText(i18n("Inserted") + TQString("
") + i18n("ATR: %1").arg(cdevice->cardATR())); + + X509CertificatePtrList certList = cdevice->cardX509Certificates(); + + if (certList.count() > 0) { + // Assemble list of certificates on card + unsigned int certificate_number = 1; + TQString certInfo = ""; + X509CertificatePtrList::iterator it; + for (it = certList.begin(); it != certList.end(); ++it) { + KSSLCertificate* tdeCert = KSSLCertificate::fromX509(*it); + KSSLCertificate::KSSLValidation validationStatus = tdeCert->validate(); + certInfo += i18n("Certificate #%1").arg(certificate_number) + ":
"; + certInfo += i18n("Subject") + ": " + tdeCert->getSubject() + "
"; + certInfo += i18n("Issuer") + ": " + tdeCert->getIssuer() + "
"; + certInfo += i18n("Status") + ": " + KSSLCertificate::verifyText(validationStatus) + "
"; + certInfo += i18n("Valid From") + ": " + tdeCert->getNotBefore() + "
"; + certInfo += i18n("Valid Until") + ": " + tdeCert->getNotAfter() + "
"; + certInfo += i18n("Serial Number") + ": " + tdeCert->getSerialNumber() + "
"; + certInfo += i18n("MD5 Digest") + ": " + tdeCert->getMD5DigestText() + "
"; + certInfo += "

"; + delete tdeCert; + certificate_number++; + } + certInfo += ""; + base->labelCardCertificates->setText(certInfo); + base->groupCardCerts->show(); + } + else { + base->labelCardCertificates->setText(""); + base->groupCardCerts->hide(); + } } } @@ -879,27 +915,169 @@ void DevicePropertiesDialog::unmountDisk() { } void DevicePropertiesDialog::cryptLUKSAddKey() { + int retcode; + if (m_device->type() == TDEGenericDeviceType::Disk) { TDEStorageDevice* sdevice = static_cast(m_device); TQListViewItem* lvi = base->cryptLUKSKeySlotList->selectedItem(); if (lvi) { + TDECryptographicCardDevice* cdevice = NULL; + unsigned int key_slot = lvi->text(0).toUInt(); + bool allow_card = false; + bool use_card = false; + KSSLCertificate* card_cert = NULL; + X509* card_cert_x509; + TQString disk_uuid = sdevice->diskUUID(); + TDEGenericDevice *hwdevice; + TDEHardwareDevices *hwdevices = TDEGlobal::hardwareDevices(); + TDEGenericHardwareList cardReaderList = hwdevices->listByDeviceClass(TDEGenericDeviceType::CryptographicCard); + for (hwdevice = cardReaderList.first(); hwdevice; hwdevice = cardReaderList.next()) { + cdevice = static_cast(hwdevice); + X509CertificatePtrList certList = cdevice->cardX509Certificates(); + if (certList.count() > 0) { + allow_card = true; + card_cert_x509 = certList[0]; + card_cert = KSSLCertificate::fromX509(certList[0]); + } + } TQByteArray new_password; - CryptPasswordDialog* passDlg = new CryptPasswordDialog(this, i18n("Enter the new LUKS password for key slot %1").arg(lvi->text(0))); + CryptPasswordDialog* passDlg = new CryptPasswordDialog(this, i18n("Enter the new LUKS password for key slot %1").arg(key_slot), TQString::null, allow_card, card_cert, &use_card); if (passDlg->exec() == TQDialog::Accepted) { new_password = passDlg->password(); + if (allow_card && use_card) { + // Create new private key for disk device + if (!TQDir("/etc/trinity/luks").exists()) { + TQDir directory; + if (!directory.mkdir("/etc/trinity/luks", true)) { + KMessageBox::error(this, i18n("Key creation failed
Please check that you have write access to /etc/trinity and try again
"), i18n("Key creation failure")); + delete card_cert; + return; + } + } + if (!TQDir("/etc/trinity/luks/card").exists()) { + TQDir directory; + if (!directory.mkdir("/etc/trinity/luks/card", true)) { + KMessageBox::error(this, i18n("Key creation failed
Please check that you have write access to /etc/trinity/luks and try again
"), i18n("Key creation failure")); + delete card_cert; + return; + } + } + TQString cryptoFileName = TQString("/etc/trinity/luks/card/%1_slot%2").arg(disk_uuid).arg(key_slot); + TQFile file(cryptoFileName); + if (file.exists()) { + if (KMessageBox::warningYesNo(this, i18n("You are about to overwrite an existing card key for LUKS key slot %1
This action cannot be undone

Are you sure you want to proceed?").arg(key_slot), i18n("Confirmation Required")) != KMessageBox::Yes) { + delete card_cert; + return; + } + } + if (file.open(IO_WriteOnly)) { + TQByteArray randomKey; + TQByteArray encryptedRandomKey; + + // Create a new secret key using the public key from the card certificate + if (TDECryptographicCardDevice::createNewSecretRSAKeyFromCertificate(randomKey, encryptedRandomKey, card_cert_x509) < 0) { + KMessageBox::error(this, i18n("Key creation failed
Unable to create new secret key using the provided X509 certificate
"), i18n("Key creation failure")); + delete card_cert; + return; + } + + // Write the encrypted key file to disk + file.writeBlock(encryptedRandomKey, encryptedRandomKey.size()); + file.close(); + + // Use the secret key as the LUKS passcode + new_password = randomKey; + } + else { + KMessageBox::error(this, i18n("Key creation failed
Please check that you have write access to /etc/trinity/luks/card and try again
"), i18n("Key creation failure")); + delete card_cert; + return; + } + } delete passDlg; if (!sdevice->cryptOperationsUnlockPasswordSet()) { TQCString password; - passDlg = new CryptPasswordDialog(this, i18n("Enter the LUKS device unlock password")); + passDlg = new CryptPasswordDialog(this, i18n("Enter the LUKS device unlock password"), TQString::null, allow_card, card_cert, &use_card); if (passDlg->exec() == TQDialog::Accepted) { - sdevice->cryptSetOperationsUnlockPassword(passDlg->password()); + TQByteArray unlockPassword = passDlg->password(); + if (use_card) { + // List all matching keys in directory and try each in turn... + TQDir luksKeyDir("/etc/trinity/luks/card/"); + luksKeyDir.setFilter(TQDir::Files); + luksKeyDir.setSorting(TQDir::Unsorted); + + TQValueList luksCryptedList; + TQValueList luksDecryptedList; + TQValueList luksSlotNumberList; + + const TQFileInfoList *luksKeyDirList = luksKeyDir.entryInfoList(); + TQFileInfoListIterator it(*luksKeyDirList); + TQFileInfo *luksKeyFileInfo; + TQString errstr; + while ((luksKeyFileInfo = it.current()) != 0) { + if (luksKeyFileInfo->fileName().startsWith(disk_uuid) && luksKeyFileInfo->fileName().contains("_slot")) { + // Found candidate, try decryption + TQFile luksKeyFile(luksKeyFileInfo->absFilePath()); + if (luksKeyFile.open(IO_ReadOnly)) { + TQByteArray keycrypted = luksKeyFile.readAll(); + luksCryptedList.append(keycrypted); + + // Parse the file name and find the matching key slot + int current_card_keyslot = -1; + TQString fileName = luksKeyFile.name(); + int pos = fileName.find("_slot"); + if (pos >= 0) { + fileName.remove(0, pos + strlen("_slot")); + current_card_keyslot = fileName.toInt(); + luksSlotNumberList.append(current_card_keyslot); + } + } + } + ++it; + } + + // Decrypt LUKS keys + TQValueList retCodeList; + retcode = cdevice->decryptDataEncryptedWithCertPublicKey(luksCryptedList, luksDecryptedList, retCodeList, &errstr); + TQValueList::iterator it2; + TQValueList::iterator it3; + TQValueList::iterator it4; + for (it2 = luksDecryptedList.begin(), it3 = retCodeList.begin(), it4 = luksSlotNumberList.begin(); it2 != luksDecryptedList.end(); ++it2, ++it3, ++it4) { + TQByteArray luksKeyData = *it2; + retcode = *it3; + int current_card_keyslot = *it4; + if (retcode == -3) { + // User cancelled + break; + } + if (retcode < 0) { + // ERROR + } + else { + // Key decryption successful, try to open LUKS device... + sdevice->cryptSetOperationsUnlockPassword(luksKeyData); + if (sdevice->cryptCheckKey(current_card_keyslot) == TDELUKSResult::Success) { + break; + } + else { + sdevice->cryptClearOperationsUnlockPassword(); + } + } + } + if (!sdevice->cryptOperationsUnlockPasswordSet()) { + KMessageBox::error(this, i18n("Key write failed
Please check the LUKS password and try again
"), i18n("Key write failure")); + } + } + else { + sdevice->cryptSetOperationsUnlockPassword(unlockPassword); + } } delete passDlg; } if (sdevice->cryptOperationsUnlockPasswordSet()) { - if ((lvi->text(1) == sdevice->cryptKeySlotFriendlyName(TDELUKSKeySlotStatus::Inactive)) || (KMessageBox::warningYesNo(this, i18n("You are about to overwrite the key in key slot %1
This action cannot be undone

Are you sure you want to proceed?").arg(lvi->text(0)), i18n("Confirmation Required")) == KMessageBox::Yes)) { - if (sdevice->cryptAddKey(lvi->text(0).toUInt(), new_password) != TDELUKSResult::Success) { + if ((lvi->text(1) == sdevice->cryptKeySlotFriendlyName(TDELUKSKeySlotStatus::Inactive)) || (KMessageBox::warningYesNo(this, i18n("You are about to overwrite the key in key slot %1
This action cannot be undone

Are you sure you want to proceed?").arg(key_slot), i18n("Confirmation Required")) == KMessageBox::Yes)) { + if (sdevice->cryptAddKey(key_slot, new_password) != TDELUKSResult::Success) { sdevice->cryptClearOperationsUnlockPassword(); KMessageBox::error(this, i18n("Key write failed
Please check the LUKS password and try again
"), i18n("Key write failure")); } @@ -909,6 +1087,7 @@ void DevicePropertiesDialog::cryptLUKSAddKey() { else { delete passDlg; } + delete card_cert; } } @@ -921,17 +1100,52 @@ void DevicePropertiesDialog::cryptLUKSDelKey() { TQListViewItem* lvi = base->cryptLUKSKeySlotList->selectedItem(); if (lvi) { + unsigned int key_slot = lvi->text(0).toUInt(); if (KMessageBox::warningYesNo(this, i18n("You are about to purge the key in key slot %1
This action cannot be undone

Are you sure you want to proceed?").arg(lvi->text(0)), i18n("Confirmation Required")) == KMessageBox::Yes) { - if (sdevice->cryptKeySlotStatus()[lvi->text(0).toUInt()] & TDELUKSKeySlotStatus::Last) { + if (sdevice->cryptKeySlotStatus()[key_slot] & TDELUKSKeySlotStatus::Last) { if (KMessageBox::warningYesNo(this, i18n("You are about to purge the last active key from the device!

This action will render the contents of the encrypted device permanently inaccessable and cannot be undone

Are you sure you want to proceed?"), i18n("Confirmation Required")) != KMessageBox::Yes) { cryptLUKSPopulateList(); return; } } - if (sdevice->cryptDelKey(lvi->text(0).toUInt()) != TDELUKSResult::Success) { + if (sdevice->cryptDelKey(key_slot) != TDELUKSResult::Success) { sdevice->cryptClearOperationsUnlockPassword(); KMessageBox::error(this, i18n("Key purge failed
The key in key slot %1 is still active
").arg(lvi->text(0)), i18n("Key purge failure")); } + else { + // See if there was a cryptographic card key associated with this device and slot + TQString disk_uuid = sdevice->diskUUID(); + TQDir luksKeyDir("/etc/trinity/luks/card/"); + luksKeyDir.setFilter(TQDir::Files); + luksKeyDir.setSorting(TQDir::Unsorted); + + const TQFileInfoList *luksKeyDirList = luksKeyDir.entryInfoList(); + TQFileInfoListIterator it(*luksKeyDirList); + TQFileInfo *luksKeyFileInfo; + TQString errstr; + while ((luksKeyFileInfo = it.current()) != 0) { + if (luksKeyFileInfo->fileName().startsWith(disk_uuid) && luksKeyFileInfo->fileName().contains("_slot")) { + // Parse the file name and find the matching key slot + int current_card_keyslot = -1; + TQString fileName = luksKeyFileInfo->absFilePath(); + TQString fileNameSlot = fileName; + int pos = fileNameSlot.find("_slot"); + if (pos >= 0) { + fileNameSlot.remove(0, pos + strlen("_slot")); + current_card_keyslot = fileNameSlot.toInt(); + if (current_card_keyslot >= 0) { + if ((unsigned int)current_card_keyslot == key_slot) { + if (!TQFile(fileName).remove()) { + KMessageBox::error(this, i18n("Card key purge failed
The card key for slot %1 has been fully deactivated but is still present on your system
This does not present a significant security risk
").arg(lvi->text(0)), i18n("Key purge failure")); + } + break; + } + } + } + } + ++it; + } + } } } } diff --git a/kcontrol/hwmanager/devicepropsdlgbase.ui b/kcontrol/hwmanager/devicepropsdlgbase.ui index de77d5f91..131cf69bf 100644 --- a/kcontrol/hwmanager/devicepropsdlgbase.ui +++ b/kcontrol/hwmanager/devicepropsdlgbase.ui @@ -1652,6 +1652,30 @@ + + + groupCardCerts + + + Card Certificates + + + + unnamed + + + + labelCardCertificates + + + + + + AlignTop|AlignLeft + + + + Spacer4 diff --git a/kcontrol/hwmanager/hwmanager.cpp b/kcontrol/hwmanager/hwmanager.cpp index 00b5143bf..1cd8b04e0 100644 --- a/kcontrol/hwmanager/hwmanager.cpp +++ b/kcontrol/hwmanager/hwmanager.cpp @@ -42,6 +42,7 @@ #include #include +#include #include #include #include @@ -147,7 +148,10 @@ void TDEHWManager::populateTreeView() TDEGenericDevice *hwdevice; for ( hwdevice = hwlist.first(); hwdevice; hwdevice = hwlist.next() ) { if (hwdevice->type() == TDEGenericDeviceType::CryptographicCard) { - static_cast(hwdevice)->enableCardMonitoring(true); + TDECryptographicCardDevice* cdevice = static_cast(hwdevice); + connect(cdevice, SIGNAL(pinRequested(TQString,TDECryptographicCardDevice*)), this, SLOT(cryptographicCardPinRequested(TQString,TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + cdevice->enablePINEntryCallbacks(true); } DeviceIconItem* item = new DeviceIconItem(base->deviceTree, hwdevice->detailedFriendlyName(), hwdevice->icon(base->deviceTree->iconSize()), hwdevice); if ((!selected_syspath.isNull()) && (hwdevice->systemPath() == selected_syspath)) { @@ -166,7 +170,10 @@ void TDEHWManager::populateTreeView() TDEGenericHardwareList hwlist = hwdevices->listByDeviceClass((TDEGenericDeviceType::TDEGenericDeviceType)i); for ( hwdevice = hwlist.first(); hwdevice; hwdevice = hwlist.next() ) { if (hwdevice->type() == TDEGenericDeviceType::CryptographicCard) { - static_cast(hwdevice)->enableCardMonitoring(true); + TDECryptographicCardDevice* cdevice = static_cast(hwdevice); + connect(cdevice, SIGNAL(pinRequested(TQString,TDECryptographicCardDevice*)), this, SLOT(cryptographicCardPinRequested(TQString,TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + cdevice->enablePINEntryCallbacks(true); } DeviceIconItem* item = new DeviceIconItem(rootitem, hwdevice->detailedFriendlyName(), hwdevice->icon(base->deviceTree->iconSize()), hwdevice); if ((!selected_syspath.isNull()) && (hwdevice->systemPath() == selected_syspath)) { @@ -186,7 +193,10 @@ void TDEHWManager::populateTreeViewLeaf(DeviceIconItem *parent, bool show_by_con TDEGenericDevice *hwdevice; for ( hwdevice = hwlist.first(); hwdevice; hwdevice = hwlist.next() ) { if (hwdevice->type() == TDEGenericDeviceType::CryptographicCard) { - static_cast(hwdevice)->enableCardMonitoring(true); + TDECryptographicCardDevice* cdevice = static_cast(hwdevice); + connect(cdevice, SIGNAL(pinRequested(TQString,TDECryptographicCardDevice*)), this, SLOT(cryptographicCardPinRequested(TQString,TDECryptographicCardDevice*))); + cdevice->enableCardMonitoring(true); + cdevice->enablePINEntryCallbacks(true); } if (hwdevice->parentDevice() == parent->device()) { DeviceIconItem* item = new DeviceIconItem(parent, hwdevice->detailedFriendlyName(), hwdevice->icon(base->deviceTree->iconSize()), hwdevice); @@ -218,6 +228,17 @@ void TDEHWManager::deviceChanged(TDEGenericDevice* device) { } } +void TDEHWManager::cryptographicCardPinRequested(TQString prompt, TDECryptographicCardDevice* cdevice) { + TQCString password; + int result = KPasswordDialog::getPassword(password, prompt); + if (result == KPasswordDialog::Accepted) { + cdevice->setProvidedPin(password); + } + else { + cdevice->setProvidedPin(TQString::null); + } +} + TQString TDEHWManager::quickHelp() const { return i18n("

TDE Hardware Device Manager

This module allows you to configure hardware devices on your system"); diff --git a/kcontrol/hwmanager/hwmanager.h b/kcontrol/hwmanager/hwmanager.h index b75a494d9..abc05fa54 100644 --- a/kcontrol/hwmanager/hwmanager.h +++ b/kcontrol/hwmanager/hwmanager.h @@ -61,6 +61,7 @@ private slots: void populateTreeView(); void populateTreeViewLeaf(DeviceIconItem *parent, bool show_by_connection, TQString selected_syspath); void deviceChanged(TDEGenericDevice*); + void cryptographicCardPinRequested(TQString prompt, TDECryptographicCardDevice* cdevice); private: TDEHWManagerBase *base; -- cgit v1.2.3