1 | /* |
2 | SPDX-FileCopyrightText: 2009 Pino Toscano <pino@kde.org> |
3 | SPDX-FileCopyrightText: 2009-2012 Lukáš Tinkl <ltinkl@redhat.com> |
4 | |
5 | SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL |
6 | */ |
7 | |
8 | #include "udisksstorageaccess.h" |
9 | #include "udisks2.h" |
10 | #include "udisks_debug.h" |
11 | |
12 | #include <QDBusConnection> |
13 | #include <QDBusInterface> |
14 | #include <QDBusMetaType> |
15 | #include <QDir> |
16 | #include <QGuiApplication> |
17 | #include <QWindow> |
18 | |
19 | #include <config-solid.h> |
20 | #if HAVE_LIBMOUNT |
21 | #include <libmount.h> |
22 | #endif |
23 | |
24 | struct AvailableAnswer { |
25 | bool checkResult; |
26 | QString binaryName; |
27 | }; |
28 | Q_DECLARE_METATYPE(AvailableAnswer) |
29 | |
30 | QDBusArgument &operator<<(QDBusArgument &argument, const AvailableAnswer &answer) |
31 | { |
32 | argument.beginStructure(); |
33 | argument << answer.checkResult << answer.binaryName; |
34 | argument.endStructure(); |
35 | return argument; |
36 | } |
37 | |
38 | const QDBusArgument &operator>>(const QDBusArgument &argument, AvailableAnswer &answer) |
39 | { |
40 | argument.beginStructure(); |
41 | argument >> answer.checkResult >> answer.binaryName; |
42 | argument.endStructure(); |
43 | return argument; |
44 | } |
45 | |
46 | using namespace Solid::Backends::UDisks2; |
47 | |
48 | StorageAccess::StorageAccess(Device *device) |
49 | : DeviceInterface(device) |
50 | , m_setupInProgress(false) |
51 | , m_teardownInProgress(false) |
52 | , m_checkInProgress(false) |
53 | , m_repairInProgress(false) |
54 | , m_passphraseRequested(false) |
55 | { |
56 | qDBusRegisterMetaType<AvailableAnswer>(); |
57 | |
58 | connect(sender: device, SIGNAL(changed()), receiver: this, SLOT(checkAccessibility())); |
59 | updateCache(); |
60 | |
61 | // Delay connecting to DBus signals to avoid the related time penalty |
62 | // in hot paths such as predicate matching |
63 | QTimer::singleShot(msec: 0, receiver: this, SLOT(connectDBusSignals())); |
64 | } |
65 | |
66 | StorageAccess::~StorageAccess() |
67 | { |
68 | } |
69 | |
70 | void StorageAccess::connectDBusSignals() |
71 | { |
72 | m_device->registerAction(QStringLiteral("setup" ), dest: this, SLOT(slotSetupRequested()), SLOT(slotSetupDone(int, QString))); |
73 | |
74 | m_device->registerAction(QStringLiteral("teardown" ), dest: this, SLOT(slotTeardownRequested()), SLOT(slotTeardownDone(int, QString))); |
75 | |
76 | m_device->registerAction(QStringLiteral("check" ), dest: this, SLOT(slotCheckRequested()), SLOT(slotCheckDone(int, QString))); |
77 | |
78 | m_device->registerAction(QStringLiteral("repair" ), dest: this, SLOT(slotRepairRequested()), SLOT(slotRepairDone(int, QString))); |
79 | } |
80 | |
81 | bool StorageAccess::isLuksDevice() const |
82 | { |
83 | return m_device->isEncryptedContainer(); // encrypted device |
84 | } |
85 | |
86 | bool StorageAccess::isAccessible() const |
87 | { |
88 | if (isLuksDevice()) { // check if the cleartext slave is mounted |
89 | const QString path = clearTextPath(); |
90 | // qDebug() << Q_FUNC_INFO << "CLEARTEXT device path: " << path; |
91 | if (path.isEmpty() || path == QLatin1String("/" )) { |
92 | return false; |
93 | } |
94 | Device holderDevice(path); |
95 | return holderDevice.isMounted(); |
96 | } |
97 | |
98 | return m_device->isMounted(); |
99 | } |
100 | |
101 | bool StorageAccess::isEncrypted() const |
102 | { |
103 | // FIXME We should also check if physical device is encrypted |
104 | // FIXME Gocryptfs is not supported |
105 | return isLuksDevice() || m_device->isEncryptedCleartext(); |
106 | } |
107 | |
108 | bool StorageAccess::canCheck() const |
109 | { |
110 | const auto idType = m_device->prop(QStringLiteral("IdType" )).toString(); |
111 | auto c = QDBusConnection::systemBus(); |
112 | auto msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
113 | QStringLiteral(UD2_DBUS_PATH_MANAGER), |
114 | QStringLiteral("org.freedesktop.UDisks2.Manager" ), |
115 | QStringLiteral("CanCheck" )); |
116 | msg << idType; |
117 | QDBusReply<AvailableAnswer> r = c.call(message: msg); |
118 | if (!r.isValid()) { |
119 | qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << "DBus error, code" << r.error().type(); |
120 | return false; |
121 | } |
122 | |
123 | const bool ret = r.value().checkResult; |
124 | qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << ret << r.value().binaryName; |
125 | return ret; |
126 | } |
127 | |
128 | bool StorageAccess::check() |
129 | { |
130 | if (m_setupInProgress || m_teardownInProgress || m_checkInProgress || m_repairInProgress) { |
131 | return false; |
132 | } |
133 | m_checkInProgress = true; |
134 | m_device->broadcastActionRequested(QStringLiteral("check" )); |
135 | |
136 | const auto path = dbusPath(); |
137 | auto c = QDBusConnection::systemBus(); |
138 | auto msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral("Check" )); |
139 | msg << QVariantMap{}; |
140 | |
141 | return c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError))); |
142 | } |
143 | |
144 | bool StorageAccess::canRepair() const |
145 | { |
146 | const auto idType = m_device->prop(QStringLiteral("IdType" )).toString(); |
147 | auto c = QDBusConnection::systemBus(); |
148 | auto msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
149 | QStringLiteral(UD2_DBUS_PATH_MANAGER), |
150 | QStringLiteral("org.freedesktop.UDisks2.Manager" ), |
151 | QStringLiteral("CanRepair" )); |
152 | msg << idType; |
153 | QDBusReply<AvailableAnswer> r = c.call(message: msg); |
154 | if (!r.isValid()) { |
155 | qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << "DBus error, code" << r.error().type(); |
156 | return false; |
157 | } |
158 | |
159 | const bool ret = r.value().checkResult; |
160 | qCDebug(UDISKS2) << Q_FUNC_INFO << dbusPath() << idType << ret << r.value().binaryName; |
161 | return ret; |
162 | } |
163 | |
164 | bool StorageAccess::repair() |
165 | { |
166 | if (m_teardownInProgress || m_setupInProgress || m_checkInProgress || m_repairInProgress) { |
167 | return false; |
168 | } |
169 | m_repairInProgress = true; |
170 | m_device->broadcastActionRequested(QStringLiteral("repair" )); |
171 | |
172 | const auto path = dbusPath(); |
173 | auto c = QDBusConnection::systemBus(); |
174 | auto msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral("Repair" )); |
175 | QVariantMap options; |
176 | msg << options; |
177 | |
178 | qCDebug(UDISKS2) << Q_FUNC_INFO << path; |
179 | return c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError))); |
180 | } |
181 | |
182 | static QString baseMountPoint(const QByteArray &dev) |
183 | { |
184 | QString mountPoint; |
185 | |
186 | #if HAVE_LIBMOUNT |
187 | // UDisks "MountPoints" property contains multiple paths, this happens with |
188 | // devices with bind mounts; try finding the "base" mount point |
189 | if (struct libmnt_table *table = mnt_new_table()) { |
190 | // This parses "/etc/mtab" if present or "/proc/self/mountinfo" by default |
191 | if (mnt_table_parse_mtab(tb: table, filename: "/proc/self/mountinfo" ) == 0) { |
192 | // BACKWARD because the fs's we're interested in, /dev/sdXY, are typically at the end |
193 | struct libmnt_iter *itr = mnt_new_iter(direction: MNT_ITER_BACKWARD); |
194 | struct libmnt_fs *fs; |
195 | |
196 | const QByteArray devicePath = dev.endsWith(c: '\x00') ? dev.chopped(len: 1) : dev; |
197 | |
198 | while (mnt_table_next_fs(tb: table, itr, fs: &fs) == 0) { |
199 | if (mnt_fs_get_srcpath(fs) == devicePath // |
200 | && (qstrcmp(str1: mnt_fs_get_root(fs), str2: "/" ) == 0) // Base mount point will have "/" as root fs |
201 | ) { |
202 | mountPoint = QFile::decodeName(localFileName: mnt_fs_get_target(fs)); |
203 | break; |
204 | } |
205 | } |
206 | |
207 | mnt_free_iter(itr); |
208 | } |
209 | |
210 | mnt_free_table(tb: table); |
211 | } |
212 | #else |
213 | Q_UNUSED(dev); |
214 | #endif |
215 | |
216 | return mountPoint; |
217 | } |
218 | |
219 | QString StorageAccess::filePath() const |
220 | { |
221 | if (isLuksDevice()) { // encrypted (and unlocked) device |
222 | const QString path = clearTextPath(); |
223 | if (path.isEmpty() || path == QLatin1String("/" )) { |
224 | return QString(); |
225 | } |
226 | Device holderDevice(path); |
227 | const auto mntPoints = qdbus_cast<QByteArrayList>(v: holderDevice.prop(QStringLiteral("MountPoints" ))); |
228 | if (!mntPoints.isEmpty()) { |
229 | QByteArray first = mntPoints.first(); |
230 | if (first.endsWith(c: '\x00')) { |
231 | first.chop(n: 1); |
232 | } |
233 | return QFile::decodeName(localFileName: first); // FIXME Solid doesn't support multiple mount points |
234 | } else { |
235 | return QString(); |
236 | } |
237 | } |
238 | |
239 | const auto mntPoints = qdbus_cast<QByteArrayList>(v: m_device->prop(QStringLiteral("MountPoints" ))); |
240 | if (mntPoints.isEmpty()) { |
241 | return {}; |
242 | } |
243 | |
244 | QByteArray first = mntPoints.first(); |
245 | if (first.endsWith(c: '\x00')) { |
246 | first.chop(n: 1); |
247 | } |
248 | const QString potentialMountPoint = QFile::decodeName(localFileName: first); |
249 | |
250 | if (mntPoints.size() == 1) { |
251 | return potentialMountPoint; |
252 | } |
253 | |
254 | // Device has bind mounts? |
255 | const QString basePoint = baseMountPoint(dev: m_device->prop(QStringLiteral("Device" )).toByteArray()); |
256 | |
257 | return !basePoint.isEmpty() ? basePoint : potentialMountPoint; |
258 | } |
259 | |
260 | bool StorageAccess::isIgnored() const |
261 | { |
262 | if (m_device->prop(QStringLiteral("HintIgnore" )).toBool()) { |
263 | return true; |
264 | } |
265 | |
266 | const QStringList mountOptions = m_device->prop(QStringLiteral("UserspaceMountOptions" )).toStringList(); |
267 | if (mountOptions.contains(str: QLatin1String("x-gdu.hide" ))) { |
268 | return true; |
269 | } |
270 | |
271 | const QString path = filePath(); |
272 | |
273 | const bool inUserPath = (path.startsWith(s: QLatin1String("/media/" )) // |
274 | || path.startsWith(s: QLatin1String("/run/media/" )) // |
275 | || path.startsWith(s: QDir::homePath())); |
276 | return !inUserPath; |
277 | } |
278 | |
279 | bool StorageAccess::setup() |
280 | { |
281 | if (m_teardownInProgress || m_setupInProgress || m_checkInProgress || m_repairInProgress) { |
282 | return false; |
283 | } |
284 | m_setupInProgress = true; |
285 | m_device->broadcastActionRequested(QStringLiteral("setup" )); |
286 | |
287 | if (m_device->isEncryptedContainer() && clearTextPath().isEmpty()) { |
288 | return requestPassphrase(); |
289 | } else { |
290 | return mount(); |
291 | } |
292 | } |
293 | |
294 | bool StorageAccess::teardown() |
295 | { |
296 | if (m_teardownInProgress || m_setupInProgress || m_checkInProgress || m_repairInProgress) { |
297 | return false; |
298 | } |
299 | m_teardownInProgress = true; |
300 | m_device->broadcastActionRequested(QStringLiteral("teardown" )); |
301 | |
302 | return unmount(); |
303 | } |
304 | |
305 | void StorageAccess::updateCache() |
306 | { |
307 | m_isAccessible = isAccessible(); |
308 | } |
309 | |
310 | void StorageAccess::checkAccessibility() |
311 | { |
312 | const bool old_isAccessible = m_isAccessible; |
313 | updateCache(); |
314 | |
315 | if (old_isAccessible != m_isAccessible) { |
316 | Q_EMIT accessibilityChanged(accessible: m_isAccessible, udi: m_device->udi()); |
317 | } |
318 | } |
319 | |
320 | void StorageAccess::slotDBusReply(const QDBusMessage &reply) |
321 | { |
322 | if (m_setupInProgress) { |
323 | if (isLuksDevice() && !isAccessible()) { // unlocked device, now mount it |
324 | mount(); |
325 | } else { // Don't broadcast setupDone unless the setup is really done. (Fix kde#271156) |
326 | m_setupInProgress = false; |
327 | m_device->invalidateCache(); |
328 | m_device->broadcastActionDone(QStringLiteral("setup" )); |
329 | |
330 | checkAccessibility(); |
331 | } |
332 | } else if (m_teardownInProgress) { // FIXME |
333 | const QString ctPath = clearTextPath(); |
334 | qCDebug(UDISKS2) << "Successfully unmounted " << m_device->udi(); |
335 | if (isLuksDevice() && !ctPath.isEmpty() && ctPath != QStringLiteral("/" )) { // unlocked device, lock it |
336 | callCryptoTeardown(); |
337 | } else if (!ctPath.isEmpty() && ctPath != QStringLiteral("/" )) { |
338 | callCryptoTeardown(actOnParent: true); // Lock encrypted parent |
339 | } else { |
340 | // try to "eject" (aka safely remove) from the (parent) drive, e.g. SD card from a reader |
341 | QString drivePath = m_device->drivePath(); |
342 | if (!drivePath.isEmpty() || drivePath != QStringLiteral("/" )) { |
343 | Device drive(drivePath); |
344 | QDBusConnection c = QDBusConnection::systemBus(); |
345 | |
346 | if (drive.prop(QStringLiteral("MediaRemovable" )).toBool() // |
347 | && drive.prop(QStringLiteral("MediaAvailable" )).toBool() // |
348 | && !m_device->isOpticalDisc()) { // optical drives have their Eject method |
349 | QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
350 | path: drivePath, |
351 | QStringLiteral(UD2_DBUS_INTERFACE_DRIVE), |
352 | QStringLiteral("Eject" )); |
353 | msg << QVariantMap(); // options, unused now |
354 | c.call(message: msg, mode: QDBus::NoBlock); |
355 | } else if (drive.prop(QStringLiteral("CanPowerOff" )).toBool() // |
356 | && !m_device->isOpticalDisc()) { // avoid disconnecting optical drives from the bus |
357 | qCDebug(UDISKS2) << "Drive can power off:" << drivePath; |
358 | QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
359 | path: drivePath, |
360 | QStringLiteral(UD2_DBUS_INTERFACE_DRIVE), |
361 | QStringLiteral("PowerOff" )); |
362 | msg << QVariantMap(); // options, unused now |
363 | c.call(message: msg, mode: QDBus::NoBlock); |
364 | } |
365 | } |
366 | |
367 | m_teardownInProgress = false; |
368 | m_device->invalidateCache(); |
369 | m_device->broadcastActionDone(QStringLiteral("teardown" )); |
370 | |
371 | checkAccessibility(); |
372 | } |
373 | } else if (m_checkInProgress) { |
374 | QDBusReply<bool> r = reply; |
375 | qCDebug(UDISKS2) << "Check reply received " << m_device->udi() << r; |
376 | m_checkInProgress = false; |
377 | if (r.isValid()) { |
378 | m_device->broadcastActionDone(QStringLiteral("check" ), error: Solid::NoError, errorString: QString::number(r.value())); |
379 | } else { |
380 | m_device->broadcastActionDone(QStringLiteral("check" ), error: Solid::OperationFailed, errorString: reply.errorMessage()); |
381 | } |
382 | } else if (m_repairInProgress) { |
383 | qCDebug(UDISKS2) << "Successfully repaired " << m_device->udi(); |
384 | m_repairInProgress = false; |
385 | m_device->broadcastActionDone(QStringLiteral("repair" )); |
386 | } |
387 | } |
388 | |
389 | void StorageAccess::slotDBusError(const QDBusError &error) |
390 | { |
391 | // qDebug() << Q_FUNC_INFO << "DBUS ERROR:" << error.name() << error.message(); |
392 | |
393 | if (m_setupInProgress) { |
394 | m_setupInProgress = false; |
395 | m_device->broadcastActionDone(QStringLiteral("setup" ), // |
396 | error: m_device->errorToSolidError(error: error.name()), |
397 | errorString: m_device->errorToString(error: error.name()) + QStringLiteral(": " ) + error.message()); |
398 | |
399 | checkAccessibility(); |
400 | } else if (m_teardownInProgress) { |
401 | m_teardownInProgress = false; |
402 | m_device->broadcastActionDone(QStringLiteral("teardown" ), // |
403 | error: m_device->errorToSolidError(error: error.name()), |
404 | errorString: m_device->errorToString(error: error.name()) + QStringLiteral(": " ) + error.message()); |
405 | checkAccessibility(); |
406 | } else if (m_checkInProgress) { |
407 | m_checkInProgress = false; |
408 | m_device->broadcastActionDone(QStringLiteral("check" ), |
409 | error: m_device->errorToSolidError(error: error.name()), |
410 | errorString: m_device->errorToString(error: error.name()) + QStringLiteral(": " ) + error.message()); |
411 | } else if (m_repairInProgress) { |
412 | m_repairInProgress = false; |
413 | m_device->broadcastActionDone(QStringLiteral("repair" ), |
414 | error: m_device->errorToSolidError(error: error.name()), |
415 | errorString: m_device->errorToString(error: error.name()) + QStringLiteral(": " ) + error.message()); |
416 | } |
417 | } |
418 | |
419 | void StorageAccess::slotSetupRequested() |
420 | { |
421 | m_setupInProgress = true; |
422 | // qDebug() << "SETUP REQUESTED:" << m_device->udi(); |
423 | Q_EMIT setupRequested(m_device->udi()); |
424 | } |
425 | |
426 | void StorageAccess::slotSetupDone(int error, const QString &errorString) |
427 | { |
428 | m_setupInProgress = false; |
429 | // qDebug() << "SETUP DONE:" << m_device->udi(); |
430 | checkAccessibility(); |
431 | Q_EMIT setupDone(error: static_cast<Solid::ErrorType>(error), errorData: errorString, udi: m_device->udi()); |
432 | } |
433 | |
434 | void StorageAccess::slotTeardownRequested() |
435 | { |
436 | m_teardownInProgress = true; |
437 | Q_EMIT teardownRequested(udi: m_device->udi()); |
438 | } |
439 | |
440 | void StorageAccess::slotTeardownDone(int error, const QString &errorString) |
441 | { |
442 | m_teardownInProgress = false; |
443 | checkAccessibility(); |
444 | Q_EMIT teardownDone(error: static_cast<Solid::ErrorType>(error), errorData: errorString, udi: m_device->udi()); |
445 | } |
446 | |
447 | void StorageAccess::slotCheckRequested() |
448 | { |
449 | m_checkInProgress = true; |
450 | Q_EMIT checkRequested(udi: m_device->udi()); |
451 | } |
452 | |
453 | void StorageAccess::slotCheckDone(int error, const QString &errorString) |
454 | { |
455 | m_checkInProgress = false; |
456 | Q_EMIT checkDone(error: static_cast<Solid::ErrorType>(error), errorData: errorString, udi: m_device->udi()); |
457 | } |
458 | |
459 | void StorageAccess::slotRepairRequested() |
460 | { |
461 | m_repairInProgress = true; |
462 | Q_EMIT repairRequested(udi: m_device->udi()); |
463 | } |
464 | |
465 | void StorageAccess::slotRepairDone(int error, const QString &errorString) |
466 | { |
467 | m_repairInProgress = false; |
468 | Q_EMIT repairDone(error: static_cast<Solid::ErrorType>(error), errorData: errorString, udi: m_device->udi()); |
469 | } |
470 | |
471 | bool StorageAccess::mount() |
472 | { |
473 | const auto path = dbusPath(); |
474 | |
475 | QDBusConnection c = QDBusConnection::systemBus(); |
476 | QDBusMessage msg = |
477 | QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral("Mount" )); |
478 | QVariantMap options; |
479 | |
480 | if (m_device->prop(QStringLiteral("IdType" )).toString() == QLatin1String("vfat" )) { |
481 | options.insert(QStringLiteral("options" ), QStringLiteral("flush" )); |
482 | } |
483 | |
484 | msg << options; |
485 | |
486 | return c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError))); |
487 | } |
488 | |
489 | bool StorageAccess::unmount() |
490 | { |
491 | const auto path = dbusPath(); |
492 | |
493 | QDBusConnection c = QDBusConnection::systemBus(); |
494 | QDBusMessage msg = |
495 | QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), path, QStringLiteral(UD2_DBUS_INTERFACE_FILESYSTEM), QStringLiteral("Unmount" )); |
496 | |
497 | msg << QVariantMap(); // options, unused now |
498 | |
499 | qCDebug(UDISKS2) << "Initiating unmount of " << path; |
500 | return c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError)), timeout: s_unmountTimeout); |
501 | } |
502 | |
503 | QString StorageAccess::generateReturnObjectPath() |
504 | { |
505 | static QAtomicInt number = 1; |
506 | |
507 | return QStringLiteral("/org/kde/solid/UDisks2StorageAccess_" ) + QString::number(number++); |
508 | } |
509 | |
510 | QString StorageAccess::clearTextPath() const |
511 | { |
512 | const QString path = m_device->prop(QStringLiteral("CleartextDevice" )).value<QDBusObjectPath>().path(); |
513 | if (path != QLatin1String("/" )) { |
514 | return path; |
515 | } |
516 | return QString(); |
517 | } |
518 | |
519 | QString StorageAccess::dbusPath() const |
520 | { |
521 | QString path = m_device->udi(); |
522 | if (isLuksDevice()) { // mount options for the cleartext volume |
523 | const QString ctPath = clearTextPath(); |
524 | if (!ctPath.isEmpty()) { |
525 | path = ctPath; |
526 | } |
527 | } |
528 | return path; |
529 | } |
530 | |
531 | bool StorageAccess::requestPassphrase() |
532 | { |
533 | QString udi = m_device->udi(); |
534 | QString returnService = QDBusConnection::sessionBus().baseService(); |
535 | m_lastReturnObject = generateReturnObjectPath(); |
536 | |
537 | QDBusConnection::sessionBus().registerObject(path: m_lastReturnObject, object: this, options: QDBusConnection::ExportScriptableSlots); |
538 | |
539 | // TODO: this only works on X11, Wayland doesn't have global window ids. |
540 | // Passing ids to other processes doesn't make any sense |
541 | auto activeWindow = QGuiApplication::focusWindow(); |
542 | uint wId = 0; |
543 | if (activeWindow != nullptr) { |
544 | wId = (uint)activeWindow->winId(); |
545 | } |
546 | |
547 | QString appId = QCoreApplication::applicationName(); |
548 | |
549 | const auto plasmaVersionMajor = qEnvironmentVariable(varName: "KDE_SESSION_VERSION" , QStringLiteral("6" )); |
550 | |
551 | // TODO KF6: remove hard dep on Plasma here which provides the SolidUiServer kded plugin |
552 | QDBusInterface soliduiserver(QStringLiteral("org.kde.kded" ) + plasmaVersionMajor, |
553 | QStringLiteral("/modules/soliduiserver" ), |
554 | QStringLiteral("org.kde.SolidUiServer" )); |
555 | QDBusReply<void> reply = soliduiserver.call(QStringLiteral("showPassphraseDialog" ), args&: udi, args&: returnService, args&: m_lastReturnObject, args&: wId, args&: appId); |
556 | m_passphraseRequested = reply.isValid(); |
557 | if (!m_passphraseRequested) { |
558 | qCWarning(UDISKS2) << "Failed to call the SolidUiServer, D-Bus said:" << reply.error(); |
559 | } |
560 | |
561 | return m_passphraseRequested; |
562 | } |
563 | |
564 | void StorageAccess::passphraseReply(const QString &passphrase) |
565 | { |
566 | if (m_passphraseRequested) { |
567 | QDBusConnection::sessionBus().unregisterObject(path: m_lastReturnObject); |
568 | m_passphraseRequested = false; |
569 | if (!passphrase.isEmpty()) { |
570 | callCryptoSetup(passphrase); |
571 | } else { |
572 | m_setupInProgress = false; |
573 | m_device->broadcastActionDone(QStringLiteral("setup" ), error: Solid::UserCanceled); |
574 | } |
575 | } |
576 | } |
577 | |
578 | void StorageAccess::callCryptoSetup(const QString &passphrase) |
579 | { |
580 | QDBusConnection c = QDBusConnection::systemBus(); |
581 | QDBusMessage msg = QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
582 | path: m_device->udi(), |
583 | QStringLiteral(UD2_DBUS_INTERFACE_ENCRYPTED), |
584 | QStringLiteral("Unlock" )); |
585 | |
586 | msg << passphrase; |
587 | msg << QVariantMap(); // options, unused now |
588 | |
589 | c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError))); |
590 | } |
591 | |
592 | bool StorageAccess::callCryptoTeardown(bool actOnParent) |
593 | { |
594 | QDBusConnection c = QDBusConnection::systemBus(); |
595 | QDBusMessage msg = |
596 | QDBusMessage::createMethodCall(QStringLiteral(UD2_DBUS_SERVICE), |
597 | path: actOnParent ? (m_device->prop(QStringLiteral("CryptoBackingDevice" )).value<QDBusObjectPath>().path()) : m_device->udi(), |
598 | QStringLiteral(UD2_DBUS_INTERFACE_ENCRYPTED), |
599 | QStringLiteral("Lock" )); |
600 | msg << QVariantMap(); // options, unused now |
601 | |
602 | return c.callWithCallback(message: msg, receiver: this, SLOT(slotDBusReply(QDBusMessage)), SLOT(slotDBusError(QDBusError))); |
603 | } |
604 | |
605 | #include "moc_udisksstorageaccess.cpp" |
606 | |