2014-11-15 04:16:00 +02:00
|
|
|
/* This file is part of the KDE Project
|
|
|
|
Copyright (c) 2005 Jean-Remy Falleri <jr.falleri@laposte.net>
|
|
|
|
Copyright (c) 2005-2007 Kevin Ottens <ervin@kde.org>
|
|
|
|
Copyright (c) 2007 Alexis Ménard <darktears31@gmail.com>
|
|
|
|
Copyright (c) 2011 Lukas Tinkl <ltinkl@redhat.com>
|
|
|
|
|
|
|
|
This library is free software; you can redistribute it and/or
|
|
|
|
modify it under the terms of the GNU Library General Public
|
|
|
|
License version 2 as published by the Free Software Foundation.
|
|
|
|
|
|
|
|
This library is distributed in the hope that it will be useful,
|
|
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
Library General Public License for more details.
|
|
|
|
|
|
|
|
You should have received a copy of the GNU Library General Public License
|
|
|
|
along with this library; see the file COPYING.LIB. If not, write to
|
|
|
|
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
|
|
|
Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "soliduiserver.h"
|
|
|
|
|
|
|
|
#include <kapplication.h>
|
|
|
|
#include <kdebug.h>
|
|
|
|
#include <klocale.h>
|
|
|
|
#include <kstandarddirs.h>
|
|
|
|
#include <kdesktopfileactions.h>
|
2021-07-21 14:01:48 +03:00
|
|
|
#include <kpassworddialog.h>
|
2022-09-25 18:49:42 +03:00
|
|
|
#include <kauthorization.h>
|
2021-07-21 02:43:37 +03:00
|
|
|
#include <kpluginfactory.h>
|
|
|
|
#include <kpluginloader.h>
|
|
|
|
#include <solid/block.h>
|
2014-11-15 04:16:00 +02:00
|
|
|
#include <solid/storagevolume.h>
|
2021-07-21 02:43:37 +03:00
|
|
|
#include <solid/storageaccess.h>
|
|
|
|
#include <solid/solidnamespace.h>
|
2014-11-15 04:16:00 +02:00
|
|
|
|
|
|
|
#include "deviceactionsdialog.h"
|
|
|
|
#include "deviceaction.h"
|
|
|
|
#include "deviceserviceaction.h"
|
|
|
|
#include "devicenothingaction.h"
|
|
|
|
|
2021-07-21 02:43:37 +03:00
|
|
|
#include <QDir>
|
2014-11-15 04:16:00 +02:00
|
|
|
|
|
|
|
K_PLUGIN_FACTORY(SolidUiServerFactory,
|
|
|
|
registerPlugin<SolidUiServer>();
|
|
|
|
)
|
|
|
|
K_EXPORT_PLUGIN(SolidUiServerFactory("soliduiserver"))
|
|
|
|
|
|
|
|
|
|
|
|
SolidUiServer::SolidUiServer(QObject* parent, const QList<QVariant>&)
|
|
|
|
: KDEDModule(parent)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
SolidUiServer::~SolidUiServer()
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
void SolidUiServer::showActionsDialog(const QString &udi,
|
|
|
|
const QStringList &desktopFiles)
|
|
|
|
{
|
|
|
|
if (m_udiToActionsDialog.contains(udi)) {
|
|
|
|
DeviceActionsDialog *dialog = m_udiToActionsDialog[udi];
|
|
|
|
dialog->activateWindow();
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QList<DeviceAction*> actions;
|
|
|
|
|
|
|
|
foreach (const QString &desktop, desktopFiles) {
|
|
|
|
QString filePath = KStandardDirs::locate("data", "solid/actions/"+desktop);
|
|
|
|
|
|
|
|
QList<KServiceAction> services
|
|
|
|
= KDesktopFileActions::userDefinedServices(filePath, true);
|
|
|
|
|
|
|
|
foreach (const KServiceAction &service, services) {
|
|
|
|
DeviceServiceAction *action = new DeviceServiceAction();
|
|
|
|
action->setService(service);
|
|
|
|
actions << action;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Only one action, execute directly
|
|
|
|
if (actions.size()==1) {
|
|
|
|
DeviceAction *action = actions.takeFirst();
|
|
|
|
Solid::Device device(udi);
|
|
|
|
action->execute(device);
|
|
|
|
delete action;
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
actions << new DeviceNothingAction();
|
|
|
|
|
|
|
|
DeviceActionsDialog *dialog = new DeviceActionsDialog();
|
|
|
|
dialog->setDevice(Solid::Device(udi));
|
|
|
|
dialog->setActions(actions);
|
|
|
|
|
|
|
|
connect(dialog, SIGNAL(finished()),
|
|
|
|
this, SLOT(onActionDialogFinished()));
|
|
|
|
|
|
|
|
m_udiToActionsDialog[udi] = dialog;
|
|
|
|
|
|
|
|
// Update user activity timestamp, otherwise the notification dialog will be shown
|
|
|
|
// in the background due to focus stealing prevention. Entering a new media can
|
|
|
|
// be seen as a kind of user activity after all. It'd be better to update the timestamp
|
|
|
|
// as soon as the media is entered, but it apparently takes some time to get here.
|
|
|
|
kapp->updateUserTimestamp();
|
|
|
|
|
|
|
|
dialog->show();
|
|
|
|
}
|
|
|
|
|
|
|
|
void SolidUiServer::onActionDialogFinished()
|
|
|
|
{
|
|
|
|
DeviceActionsDialog *dialog = qobject_cast<DeviceActionsDialog*>(sender());
|
|
|
|
|
|
|
|
if (dialog) {
|
|
|
|
QString udi = dialog->device().udi();
|
|
|
|
m_udiToActionsDialog.remove(udi);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-06-15 22:11:22 +03:00
|
|
|
int SolidUiServer::mountDevice(const QString &device, const QString &mountpoint, bool readonly)
|
|
|
|
{
|
|
|
|
QVariantMap mountarguments;
|
|
|
|
mountarguments.insert("device", device);
|
|
|
|
mountarguments.insert("mountpoint", mountpoint);
|
|
|
|
mountarguments.insert("readonly", readonly);
|
|
|
|
int mountreply = KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "mount", mountarguments
|
|
|
|
);
|
|
|
|
// qDebug() << "mount" << mountreply;
|
|
|
|
|
|
|
|
if (mountreply == KAuthorization::NoError) {
|
|
|
|
return int(Solid::ErrorType::NoError);
|
|
|
|
} else if (mountreply == KAuthorization::AuthorizationError) {
|
|
|
|
return int(Solid::ErrorType::UnauthorizedOperation);
|
|
|
|
}
|
|
|
|
return int(Solid::ErrorType::OperationFailed);
|
|
|
|
}
|
|
|
|
|
|
|
|
int SolidUiServer::unmountDevice(const QString &mountpoint)
|
|
|
|
{
|
|
|
|
QVariantMap unmountarguments;
|
|
|
|
unmountarguments.insert("mountpoint", mountpoint);
|
|
|
|
int unmountreply = KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "unmount", unmountarguments
|
|
|
|
);
|
|
|
|
// qDebug() << "unmount" << unmountreply;
|
|
|
|
|
|
|
|
if (unmountreply == KAuthorization::NoError) {
|
|
|
|
return int(Solid::ErrorType::NoError);
|
|
|
|
} else if (unmountreply == KAuthorization::AuthorizationError) {
|
|
|
|
return int(Solid::ErrorType::UnauthorizedOperation);
|
|
|
|
}
|
|
|
|
return int(Solid::ErrorType::OperationFailed);
|
|
|
|
}
|
|
|
|
|
|
|
|
int SolidUiServer::mountUdi(const QString &udi)
|
2021-07-21 02:43:37 +03:00
|
|
|
{
|
|
|
|
Solid::Device device(udi);
|
|
|
|
Solid::StorageVolume *storagevolume = device.as<Solid::StorageVolume>();
|
|
|
|
Solid::Block *block = device.as<Solid::Block>();
|
|
|
|
if (!storagevolume || !block) {
|
2023-06-29 08:07:29 +03:00
|
|
|
kWarning() << "invalid storage device" << udi;
|
2021-07-21 02:43:37 +03:00
|
|
|
return int(Solid::ErrorType::InvalidOption);
|
2021-11-16 23:29:33 +02:00
|
|
|
} else if (storagevolume->fsType() == "zfs_member") {
|
|
|
|
// create pool on USB stick, put some bad stuff on it, set mount point to / and watch it
|
|
|
|
// unfold when mounted
|
2023-06-29 08:07:29 +03:00
|
|
|
kWarning() << "storage device is insecure" << udi;
|
2021-11-16 23:29:33 +02:00
|
|
|
return int(Solid::ErrorType::Insecure);
|
2021-07-21 02:43:37 +03:00
|
|
|
}
|
|
|
|
|
2021-07-21 14:01:48 +03:00
|
|
|
QString devicenode = block->device();
|
2021-07-21 16:53:43 +03:00
|
|
|
const QString deviceuuid(storagevolume->uuid());
|
2021-07-22 18:07:09 +03:00
|
|
|
|
|
|
|
bool didcryptopen = false;
|
|
|
|
#ifdef Q_OS_LINUX
|
2021-07-21 16:53:43 +03:00
|
|
|
const QString dmnode = QLatin1String("/dev/mapper/") + deviceuuid;
|
2021-07-21 14:01:48 +03:00
|
|
|
if (storagevolume->usage() == Solid::StorageVolume::Encrypted) {
|
|
|
|
KPasswordDialog passworddialog(0, KPasswordDialog::NoFlags);
|
|
|
|
|
2021-07-23 09:33:26 +03:00
|
|
|
passworddialog.setPrompt(i18n("'%1' needs a password to be accessed. Please enter a password.", device.description()));
|
2021-07-21 14:01:48 +03:00
|
|
|
passworddialog.setPixmap(KIcon(device.icon()).pixmap(64, 64));
|
|
|
|
if (!passworddialog.exec()) {
|
|
|
|
return int(Solid::ErrorType::UserCanceled);
|
|
|
|
}
|
|
|
|
|
2022-09-25 18:49:42 +03:00
|
|
|
QVariantMap cryptopenarguments;
|
|
|
|
cryptopenarguments.insert("device", devicenode);
|
|
|
|
cryptopenarguments.insert("name", deviceuuid);
|
|
|
|
cryptopenarguments.insert("password", passworddialog.password().toLocal8Bit().toHex());
|
|
|
|
int cryptopenreply = KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "cryptopen", cryptopenarguments
|
|
|
|
);
|
|
|
|
// qDebug() << "cryptopen" << cryptopenreply;
|
2021-07-21 14:01:48 +03:00
|
|
|
|
2022-09-25 18:49:42 +03:00
|
|
|
if (cryptopenreply == KAuthorization::AuthorizationError) {
|
2021-07-21 14:01:48 +03:00
|
|
|
return int(Solid::ErrorType::UnauthorizedOperation);
|
2022-09-25 18:49:42 +03:00
|
|
|
} else if (cryptopenreply != KAuthorization::NoError) {
|
2021-07-21 14:01:48 +03:00
|
|
|
return int(Solid::ErrorType::OperationFailed);
|
|
|
|
}
|
|
|
|
|
2021-07-22 18:07:09 +03:00
|
|
|
didcryptopen = true;
|
2021-07-21 14:01:48 +03:00
|
|
|
// NOTE: keep in sync with kdelibs/solid/solid/backends/udev/udevstorageaccess.cpp
|
2021-07-21 16:53:43 +03:00
|
|
|
devicenode = dmnode;
|
2021-07-21 14:01:48 +03:00
|
|
|
}
|
2021-07-22 18:07:09 +03:00
|
|
|
#else
|
|
|
|
#warning crypto storage devices are not supported on this platform
|
|
|
|
#endif
|
2021-07-21 14:01:48 +03:00
|
|
|
|
2023-06-15 22:11:22 +03:00
|
|
|
// permission denied on /run/mount so.. using base directory that is writable
|
|
|
|
const QString mountbase = KGlobal::dirs()->saveLocation("tmp");
|
|
|
|
const QString mountpoint = mountbase + QLatin1Char('/') + deviceuuid;
|
|
|
|
QDir mountdir(mountbase);
|
|
|
|
if (!mountdir.exists(mountpoint) && !mountdir.mkdir(mountpoint)) {
|
2023-06-29 08:07:29 +03:00
|
|
|
kWarning() << "could not create" << mountpoint;
|
2023-06-15 22:11:22 +03:00
|
|
|
if (didcryptopen) {
|
|
|
|
QVariantMap cryptclosearguments;
|
|
|
|
cryptclosearguments.insert("name", deviceuuid);
|
|
|
|
(void)KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "cryptclose", cryptclosearguments
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return int(Solid::ErrorType::OperationFailed);
|
|
|
|
}
|
|
|
|
|
|
|
|
const int mountresult = mountDevice(devicenode, mountpoint);
|
2022-05-11 03:31:02 +03:00
|
|
|
if (mountresult != int(Solid::ErrorType::NoError) && didcryptopen) {
|
2022-09-25 18:49:42 +03:00
|
|
|
QVariantMap cryptclosearguments;
|
|
|
|
cryptclosearguments.insert("name", deviceuuid);
|
|
|
|
(void)KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "cryptclose", cryptclosearguments
|
|
|
|
);
|
2021-07-22 18:07:09 +03:00
|
|
|
}
|
2022-05-11 03:31:02 +03:00
|
|
|
return mountresult;
|
2021-07-21 02:43:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-15 22:11:22 +03:00
|
|
|
int SolidUiServer::unmountUdi(const QString &udi)
|
2021-07-21 02:43:37 +03:00
|
|
|
{
|
|
|
|
Solid::Device device(udi);
|
|
|
|
Solid::StorageAccess *storageaccess = device.as<Solid::StorageAccess>();
|
2022-05-17 22:36:56 +03:00
|
|
|
Solid::StorageVolume *storagevolume = device.as<Solid::StorageVolume>();
|
2021-07-21 14:01:48 +03:00
|
|
|
if (!storagevolume || !storageaccess) {
|
2023-06-29 08:07:29 +03:00
|
|
|
kWarning() << "invalid storage device" << udi;
|
2021-07-21 02:43:37 +03:00
|
|
|
return int(Solid::ErrorType::InvalidOption);
|
|
|
|
}
|
|
|
|
|
2023-06-15 22:11:22 +03:00
|
|
|
const int unmountresult = unmountDevice(storageaccess->filePath());
|
2022-05-17 22:36:56 +03:00
|
|
|
if (unmountresult != int(Solid::ErrorType::NoError)) {
|
|
|
|
return unmountresult;
|
2021-07-21 02:43:37 +03:00
|
|
|
}
|
|
|
|
|
2021-07-21 14:01:48 +03:00
|
|
|
if (storagevolume->usage() == Solid::StorageVolume::Encrypted) {
|
2022-09-25 18:49:42 +03:00
|
|
|
QVariantMap cryptclosearguments;
|
|
|
|
cryptclosearguments.insert("name", storagevolume->uuid());
|
|
|
|
int cryptclosereply = KAuthorization::execute(
|
|
|
|
"org.kde.soliduiserver.mountunmounthelper", "cryptclose", cryptclosearguments
|
|
|
|
);
|
|
|
|
// qDebug() << "cryptclose" << cryptclosereply;
|
|
|
|
|
|
|
|
if (cryptclosereply == KAuthorization::AuthorizationError) {
|
2021-07-21 14:01:48 +03:00
|
|
|
return int(Solid::ErrorType::UnauthorizedOperation);
|
2022-09-25 18:49:42 +03:00
|
|
|
} else if (cryptclosereply != KAuthorization::NoError) {
|
2021-07-21 14:01:48 +03:00
|
|
|
return int(Solid::ErrorType::OperationFailed);
|
|
|
|
}
|
2021-07-21 02:43:37 +03:00
|
|
|
}
|
2021-07-21 14:01:48 +03:00
|
|
|
|
|
|
|
return int(Solid::ErrorType::NoError);
|
2021-07-21 02:43:37 +03:00
|
|
|
}
|
|
|
|
|
2023-06-18 01:08:26 +03:00
|
|
|
QString SolidUiServer::errorString(const int error)
|
|
|
|
{
|
|
|
|
return Solid::errorString(static_cast<Solid::ErrorType>(error));
|
|
|
|
}
|
|
|
|
|
2015-02-27 09:28:46 +00:00
|
|
|
#include "moc_soliduiserver.cpp"
|