keepassxc

Форк
0
681 строка · 24.2 Кб
1
/*
2
 *  Copyright (C) 2020 Aetf <aetf@unlimitedcode.works>
3
 *
4
 *  This program is free software: you can redistribute it and/or modify
5
 *  it under the terms of the GNU General Public License as published by
6
 *  the Free Software Foundation, either version 2 or (at your option)
7
 *  version 3 of the License.
8
 *
9
 *  This program is distributed in the hope that it will be useful,
10
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
 *  GNU General Public License for more details.
13
 *
14
 *  You should have received a copy of the GNU General Public License
15
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
16
 */
17

18
#include "DBusMgr.h"
19

20
#include "fdosecrets/objects/Collection.h"
21
#include "fdosecrets/objects/Item.h"
22
#include "fdosecrets/objects/Prompt.h"
23
#include "fdosecrets/objects/Service.h"
24
#include "fdosecrets/objects/Session.h"
25

26
#include "core/Entry.h"
27
#include "core/Tools.h"
28

29
#ifdef __FreeBSD__
30
#include <string.h>
31
#include <sys/sysctl.h>
32
#endif
33

34
namespace FdoSecrets
35
{
36
    static const auto IntrospectionService = R"xml(
37
<interface name="org.freedesktop.Secret.Service">
38
    <property name="Collections" type="ao" access="read"/>
39
    <signal name="CollectionCreated">
40
        <arg name="collection" type="o" direction="out"/>
41
    </signal>
42
    <signal name="CollectionDeleted">
43
        <arg name="collection" type="o" direction="out"/>
44
    </signal>
45
    <signal name="CollectionChanged">
46
        <arg name="collection" type="o" direction="out"/>
47
    </signal>
48
    <method name="OpenSession">
49
        <arg type="v" direction="out"/>
50
        <arg name="algorithm" type="s" direction="in"/>
51
        <arg name="input" type="v" direction="in"/>
52
        <arg name="result" type="o" direction="out"/>
53
    </method>
54
    <method name="CreateCollection">
55
        <arg type="o" direction="out"/>
56
        <arg name="properties" type="a{sv}" direction="in"/>
57
        <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
58
        <arg name="alias" type="s" direction="in"/>
59
        <arg name="prompt" type="o" direction="out"/>
60
    </method>
61
    <method name="SearchItems">
62
        <arg type="ao" direction="out"/>
63
        <arg name="attributes" type="a{ss}" direction="in"/>
64
        <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StringStringMap"/>
65
        <arg name="locked" type="ao" direction="out"/>
66
    </method>
67
    <method name="Unlock">
68
        <arg type="ao" direction="out"/>
69
        <arg name="paths" type="ao" direction="in"/>
70
        <arg name="prompt" type="o" direction="out"/>
71
    </method>
72
    <method name="Lock">
73
        <arg type="ao" direction="out"/>
74
        <arg name="paths" type="ao" direction="in"/>
75
        <arg name="prompt" type="o" direction="out"/>
76
    </method>
77
    <method name="GetSecrets">
78
        <arg type="a{o(oayays)}" direction="out"/>
79
        <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="ObjectPathSecretMap"/>
80
        <arg name="items" type="ao" direction="in"/>
81
        <arg name="session" type="o" direction="in"/>
82
    </method>
83
    <method name="ReadAlias">
84
        <arg type="o" direction="out"/>
85
        <arg name="name" type="s" direction="in"/>
86
    </method>
87
    <method name="SetAlias">
88
        <arg name="name" type="s" direction="in"/>
89
        <arg name="collection" type="o" direction="in"/>
90
    </method>
91
</interface>
92
)xml";
93

94
    static const auto IntrospectionCollection = R"xml(
95
<interface name="org.freedesktop.Secret.Collection">
96
    <property name="Items" type="ao" access="read"/>
97
    <property name="Label" type="s" access="readwrite"/>
98
    <property name="Locked" type="b" access="read"/>
99
    <property name="Created" type="t" access="read"/>
100
    <property name="Modified" type="t" access="read"/>
101
    <signal name="ItemCreated">
102
        <arg name="item" type="o" direction="out"/>
103
    </signal>
104
    <signal name="ItemDeleted">
105
        <arg name="item" type="o" direction="out"/>
106
    </signal>
107
    <signal name="ItemChanged">
108
        <arg name="item" type="o" direction="out"/>
109
    </signal>
110
    <method name="Delete">
111
        <arg type="o" direction="out"/>
112
    </method>
113
    <method name="SearchItems">
114
        <arg type="ao" direction="out"/>
115
        <arg name="attributes" type="a{ss}" direction="in"/>
116
        <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="StringStringMap"/>
117
    </method>
118
    <method name="CreateItem">
119
        <arg type="o" direction="out"/>
120
        <arg name="properties" type="a{sv}" direction="in"/>
121
        <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="QVariantMap"/>
122
        <arg name="secret" type="(oayays)" direction="in"/>
123
        <annotation name="org.qtproject.QtDBus.QtTypeName.In1" value="FdoSecrets::wire::Secret"/>
124
        <arg name="replace" type="b" direction="in"/>
125
        <arg name="prompt" type="o" direction="out"/>
126
    </method>
127
</interface>
128
)xml";
129

130
    static const auto IntrospectionItem = R"xml(
131
<interface name="org.freedesktop.Secret.Item">
132
    <property name="Locked" type="b" access="read"/>
133
    <property name="Attributes" type="a{ss}" access="readwrite">
134
        <annotation name="org.qtproject.QtDBus.QtTypeName" value="StringStringMap"/>
135
    </property>
136
    <property name="Label" type="s" access="readwrite"/>
137
    <property name="Created" type="t" access="read"/>
138
    <property name="Modified" type="t" access="read"/>
139
    <method name="Delete">
140
        <arg type="o" direction="out"/>
141
    </method>
142
    <method name="GetSecret">
143
        <arg type="(oayays)" direction="out"/>
144
        <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="FdoSecrets::wire::Secret"/>
145
        <arg name="session" type="o" direction="in"/>
146
    </method>
147
    <method name="SetSecret">
148
        <arg name="secret" type="(oayays)" direction="in"/>
149
        <annotation name="org.qtproject.QtDBus.QtTypeName.In0" value="FdoSecrets::wire::Secret"/>
150
    </method>
151
</interface>
152
)xml";
153

154
    static const auto IntrospectionSession = R"xml(
155
<interface name="org.freedesktop.Secret.Session">
156
    <method name="Close">
157
    </method>
158
</interface>
159
)xml";
160

161
    static const auto IntrospectionPrompt = R"xml(
162
<interface name="org.freedesktop.Secret.Prompt">
163
    <signal name="Completed">
164
        <arg name="dismissed" type="b" direction="out"/>
165
        <arg name="result" type="v" direction="out"/>
166
    </signal>
167
    <method name="Prompt">
168
        <arg name="windowId" type="s" direction="in"/>
169
    </method>
170
    <method name="Dismiss">
171
    </method>
172
</interface>
173
)xml";
174

175
    // read /proc, each field except pid may be empty
176
    ProcInfo readProc(uint pid)
177
    {
178
        ProcInfo info{};
179
        info.pid = pid;
180

181
        // The /proc/pid/exe link is more reliable than /proc/pid/cmdline
182
        // It's still weak and if the application does a prctl(PR_SET_DUMPABLE, 0) this link cannot be accessed.
183

184
#ifdef __FreeBSD__
185
        const int mib[] = {CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, static_cast<int>(info.pid)};
186
        char buffer[2048];
187
        size_t size = sizeof(buffer);
188
        if (sysctl(mib, 4, buffer, &size, NULL, 0) != 0) {
189
            strlcpy(buffer, "Invalid path", sizeof(buffer));
190
        }
191
        QFileInfo exe(buffer);
192
#else
193
        QFileInfo exe(QStringLiteral("/proc/%1/exe").arg(pid));
194
#endif
195
        info.exePath = exe.canonicalFilePath();
196

197
        // /proc/pid/cmdline gives full command line
198
        QFile cmdline(QStringLiteral("/proc/%1/cmdline").arg(pid));
199
        if (cmdline.open(QFile::ReadOnly)) {
200
            info.command = QString::fromLocal8Bit(cmdline.readAll().replace('\0', ' ')).trimmed();
201
        }
202

203
        // /proc/pid/stat gives ppid, name
204
        QFile stat(QStringLiteral("/proc/%1/stat").arg(pid));
205
        if (stat.open(QIODevice::ReadOnly)) {
206
            auto line = stat.readAll();
207
            // find comm field without looking in what's inside as it's user controlled
208
            auto commStart = line.indexOf('(');
209
            auto commEnd = line.lastIndexOf(')');
210
            if (commStart != -1 && commEnd != -1 && commStart < commEnd) {
211
                // start past '(', and subtract 2 from total length
212
                info.name = QString::fromLocal8Bit(line.mid(commStart + 1, commEnd + 1 - commStart - 2));
213

214
                auto parts = line.mid(commEnd + 1).trimmed().split(' ');
215
                if (parts.size() >= 2) {
216
                    info.ppid = parts[1].toUInt();
217
                }
218
            }
219
        }
220

221
        return info;
222
    }
223

224
    DBusMgr::DBusMgr()
225
        : m_conn(QDBusConnection::sessionBus())
226
    {
227
        // remove client when it disappears on the bus
228
        m_watcher.setWatchMode(QDBusServiceWatcher::WatchForUnregistration);
229
        connect(&m_watcher, &QDBusServiceWatcher::serviceUnregistered, this, &DBusMgr::dbusServiceUnregistered);
230
        m_watcher.setConnection(m_conn);
231
    }
232

233
    void DBusMgr::populateMethodCache()
234
    {
235
        // these are the methods we expose on DBus
236
        populateMethodCache(Service::staticMetaObject);
237
        populateMethodCache(Collection::staticMetaObject);
238
        populateMethodCache(Item::staticMetaObject);
239
        populateMethodCache(PromptBase::staticMetaObject);
240
        populateMethodCache(Session::staticMetaObject);
241
    }
242

243
    DBusMgr::~DBusMgr() = default;
244

245
    void DBusMgr::overrideClient(const DBusClientPtr& fake)
246
    {
247
        m_overrideClient = fake;
248
    }
249

250
    QList<DBusClientPtr> DBusMgr::clients() const
251
    {
252
        return m_clients.values();
253
    }
254

255
    bool DBusMgr::serviceInfo(const QString& addr, PeerInfo& info) const
256
    {
257
        info.address = addr;
258
        auto pid = m_conn.interface()->servicePid(addr);
259
        if (!pid.isValid()) {
260
            return false;
261
        }
262
        info.pid = pid.value();
263

264
        // get the whole hierarchy
265
        uint ppid = info.pid;
266
        while (ppid != 0) {
267
            auto proc = readProc(ppid);
268
            info.hierarchy.append(proc);
269
            ppid = proc.ppid;
270
        }
271

272
        // check if the exe file is valid
273
        // (assuming for now that an accessible file is valid)
274
        info.valid = QFileInfo::exists(info.exePath());
275

276
        // ask again to double-check and protect against pid reuse
277
        auto newPid = m_conn.interface()->servicePid(addr);
278
        if (!newPid.isValid() || newPid.value() != pid.value()) {
279
            // either the peer already gone or the pid changed to something else
280
            return false;
281
        }
282
        return true;
283
    }
284

285
    bool DBusMgr::sendDBusSignal(const QString& path,
286
                                 const QString& interface,
287
                                 const QString& name,
288
                                 const QVariantList& arguments)
289
    {
290
        auto msg = QDBusMessage::createSignal(path, interface, name);
291
        msg.setArguments(arguments);
292
        return sendDBus(msg);
293
    }
294

295
    bool DBusMgr::sendDBus(const QDBusMessage& reply)
296
    {
297
        bool ok = m_conn.send(reply);
298
        if (!ok) {
299
            qDebug() << "Failed to send on DBus:" << reply;
300
            emit error(tr("Failed to send reply on DBus"));
301
        }
302
        return ok;
303
    }
304

305
    // `this` object is registered at multiple paths:
306
    // /org/freedesktop/secrets
307
    // /org/freedesktop/secrets/collection/xxx
308
    // /org/freedesktop/secrets/collection/xxx/yyy
309
    // /org/freedesktop/secrets/aliases/xxx
310
    // /org/freedesktop/secrets/session/xxx
311
    // /org/freedesktop/secrets/prompt/xxx
312
    //
313
    // The path validation is left to Qt, this method only do the minimum
314
    // required to differentiate the paths.
315
    DBusMgr::ParsedPath DBusMgr::parsePath(const QString& path)
316
    {
317
        Q_ASSERT(path.startsWith('/'));
318
        Q_ASSERT(path == "/" || !path.endsWith('/'));
319

320
        static const QString DBusPathSecrets = DBUS_PATH_SECRETS;
321

322
        if (!path.startsWith(DBusPathSecrets)) {
323
            return ParsedPath{};
324
        }
325
        auto parts = path.mid(DBusPathSecrets.size()).split('/');
326
        // the first part is always empty
327
        if (parts.isEmpty() || parts.first() != "") {
328
            return ParsedPath{};
329
        }
330
        parts.takeFirst();
331

332
        if (parts.isEmpty()) {
333
            return ParsedPath{PathType::Service};
334
        } else if (parts.size() == 2) {
335
            if (parts.at(0) == "collection") {
336
                return ParsedPath{PathType::Collection, parts.at(1)};
337
            } else if (parts.at(0) == "aliases") {
338
                return ParsedPath{PathType::Aliases, parts.at(1)};
339
            } else if (parts.at(0) == "prompt") {
340
                return ParsedPath{PathType::Prompt, parts.at(1)};
341
            } else if (parts.at(0) == "session") {
342
                return ParsedPath{PathType::Session, parts.at(1)};
343
            }
344
        } else if (parts.size() == 3) {
345
            if (parts.at(0) == "collection") {
346
                return ParsedPath{PathType::Item, parts.at(2), parts.at(1)};
347
            }
348
        }
349
        return ParsedPath{};
350
    }
351

352
    QString DBusMgr::introspect(const QString& path) const
353
    {
354
        auto parsed = parsePath(path);
355
        switch (parsed.type) {
356
        case PathType::Service:
357
            return IntrospectionService;
358
        case PathType::Collection:
359
        case PathType::Aliases:
360
            return IntrospectionCollection;
361
        case PathType::Prompt:
362
            return IntrospectionPrompt;
363
        case PathType::Session:
364
            return IntrospectionSession;
365
        case PathType::Item:
366
            return IntrospectionItem;
367
        case PathType::Unknown:
368
        default:
369
            return "";
370
        }
371
    }
372

373
    bool DBusMgr::serviceOccupied() const
374
    {
375
        auto reply = m_conn.interface()->isServiceRegistered(DBUS_SERVICE_SECRET);
376
        if (!reply.isValid()) {
377
            return false;
378
        }
379
        if (reply.value()) {
380
            auto pid = m_conn.interface()->servicePid(DBUS_SERVICE_SECRET);
381
            if (pid.isValid() && pid.value() != qApp->applicationPid()) {
382
                return true;
383
            }
384
        }
385
        return false;
386
    }
387

388
    QString DBusMgr::reportExistingService() const
389
    {
390
        auto pidStr = tr("Unknown", "Unknown PID");
391
        auto exeStr = tr("Unknown", "Unknown executable path");
392

393
        PeerInfo info{};
394
        if (serviceInfo(DBUS_SERVICE_SECRET, info)) {
395
            pidStr = QString::number(info.pid);
396
            if (!info.exePath().isEmpty()) {
397
                exeStr = info.exePath();
398
            }
399
        }
400

401
        auto otherService = tr("<i>PID: %1, Executable: %2</i>", "<i>PID: 1234, Executable: /path/to/exe</i>")
402
                                .arg(pidStr, exeStr.toHtmlEscaped());
403
        return tr("Another secret service is running (%1).<br/>"
404
                  "Please stop/remove it before re-enabling the Secret Service Integration.")
405
            .arg(otherService);
406
    }
407

408
    bool DBusMgr::registerObject(const QString& path, DBusObject* obj, bool primary)
409
    {
410
        if (!m_conn.registerVirtualObject(path, this)) {
411
            qDebug() << "failed to register" << obj << "at" << path;
412
            return false;
413
        }
414
        connect(obj, &DBusObject::destroyed, this, &DBusMgr::unregisterObject);
415
        m_objects.insert(path, obj);
416
        if (primary) {
417
            obj->setObjectPath(path);
418
        }
419
        return true;
420
    }
421

422
    bool DBusMgr::registerObject(Service* service)
423
    {
424
        if (!m_conn.registerService(DBUS_SERVICE_SECRET)) {
425
            const auto existing = reportExistingService();
426
            qDebug() << "Failed to register DBus service at " << DBUS_SERVICE_SECRET;
427
            qDebug() << existing;
428
            emit error(tr("Failed to register DBus service at %1.<br/>").arg(DBUS_SERVICE_SECRET) + existing);
429
            return false;
430
        }
431
        connect(service, &DBusObject::destroyed, this, [this]() { m_conn.unregisterService(DBUS_SERVICE_SECRET); });
432

433
        if (!registerObject(DBUS_PATH_SECRETS, service)) {
434
            qDebug() << "Failed to register service on DBus at path" << DBUS_PATH_SECRETS;
435
            emit error(tr("Failed to register service on DBus at path '%1'").arg(DBUS_PATH_SECRETS));
436
            return false;
437
        }
438

439
        connect(service, &Service::collectionCreated, this, &DBusMgr::emitCollectionCreated);
440
        connect(service, &Service::collectionChanged, this, &DBusMgr::emitCollectionChanged);
441
        connect(service, &Service::collectionDeleted, this, &DBusMgr::emitCollectionDeleted);
442

443
        return true;
444
    }
445

446
    bool DBusMgr::registerObject(Collection* coll)
447
    {
448
        auto name = encodePath(coll->name());
449
        auto path = DBUS_PATH_TEMPLATE_COLLECTION.arg(DBUS_PATH_SECRETS, name);
450
        if (!registerObject(path, coll)) {
451
            // try again with a suffix
452
            name.append(QString("_%1").arg(Tools::uuidToHex(QUuid::createUuid()).left(4)));
453
            path = DBUS_PATH_TEMPLATE_COLLECTION.arg(DBUS_PATH_SECRETS, name);
454

455
            if (!registerObject(path, coll)) {
456
                qDebug() << "Failed to register database on DBus under name" << name;
457
                emit error(tr("Failed to register database on DBus under the name '%1'").arg(name));
458
                return false;
459
            }
460
        }
461

462
        connect(coll, &Collection::itemCreated, this, &DBusMgr::emitItemCreated);
463
        connect(coll, &Collection::itemChanged, this, &DBusMgr::emitItemChanged);
464
        connect(coll, &Collection::itemDeleted, this, &DBusMgr::emitItemDeleted);
465

466
        return true;
467
    }
468

469
    bool DBusMgr::registerObject(Session* sess)
470
    {
471
        auto path = DBUS_PATH_TEMPLATE_SESSION.arg(DBUS_PATH_SECRETS, sess->id());
472
        if (!registerObject(path, sess)) {
473
            emit error(tr("Failed to register session on DBus at path '%1'").arg(path));
474
            return false;
475
        }
476
        return true;
477
    }
478

479
    bool DBusMgr::registerObject(Item* item)
480
    {
481
        auto path = DBUS_PATH_TEMPLATE_ITEM.arg(item->collection()->objectPath().path(), item->backend()->uuidToHex());
482
        if (!registerObject(path, item)) {
483
            emit error(tr("Failed to register item on DBus at path '%1'").arg(path));
484
            return false;
485
        }
486
        return true;
487
    }
488

489
    bool DBusMgr::registerObject(PromptBase* prompt)
490
    {
491
        auto path = DBUS_PATH_TEMPLATE_PROMPT.arg(DBUS_PATH_SECRETS, Tools::uuidToHex(QUuid::createUuid()));
492
        if (!registerObject(path, prompt)) {
493
            emit error(tr("Failed to register prompt object on DBus at path '%1'").arg(path));
494
            return false;
495
        }
496

497
        connect(prompt, &PromptBase::completed, this, &DBusMgr::emitPromptCompleted);
498

499
        return true;
500
    }
501

502
    void DBusMgr::unregisterObject(DBusObject* obj)
503
    {
504
        auto count = m_objects.remove(obj->objectPath().path());
505
        if (count > 0) {
506
            m_conn.unregisterObject(obj->objectPath().path());
507
            obj->setObjectPath("/");
508
        }
509
    }
510

511
    bool DBusMgr::registerAlias(Collection* coll, const QString& alias)
512
    {
513
        auto path = DBUS_PATH_TEMPLATE_ALIAS.arg(DBUS_PATH_SECRETS, alias);
514
        if (!registerObject(path, coll, false)) {
515
            qDebug() << "Failed to register database on DBus under alias" << alias;
516
            // usually this is reported back directly on dbus, so no need to show in UI
517
            return false;
518
        }
519
        // alias signals are handled together with collections' primary path in emitCollection*
520
        // but we need to handle object destroy here
521
        connect(coll, &DBusObject::destroyed, this, [this, alias]() { unregisterAlias(alias); });
522
        return true;
523
    }
524

525
    void DBusMgr::unregisterAlias(const QString& alias)
526
    {
527
        auto path = DBUS_PATH_TEMPLATE_ALIAS.arg(DBUS_PATH_SECRETS, alias);
528
        // DBusMgr::unregisterObject only handles primary path
529
        m_objects.remove(path);
530
        m_conn.unregisterObject(path);
531
    }
532

533
    void DBusMgr::emitCollectionCreated(Collection* coll)
534
    {
535
        QVariantList args;
536
        args += QVariant::fromValue(coll->objectPath());
537
        sendDBusSignal(DBUS_PATH_SECRETS, DBUS_INTERFACE_SECRET_SERVICE, QStringLiteral("CollectionCreated"), args);
538
    }
539

540
    void DBusMgr::emitCollectionChanged(Collection* coll)
541
    {
542
        QVariantList args;
543
        args += QVariant::fromValue(coll->objectPath());
544
        sendDBusSignal(DBUS_PATH_SECRETS, DBUS_INTERFACE_SECRET_SERVICE, "CollectionChanged", args);
545
    }
546

547
    void DBusMgr::emitCollectionDeleted(Collection* coll)
548
    {
549
        QVariantList args;
550
        args += QVariant::fromValue(coll->objectPath());
551
        sendDBusSignal(DBUS_PATH_SECRETS, DBUS_INTERFACE_SECRET_SERVICE, QStringLiteral("CollectionDeleted"), args);
552
    }
553

554
    void DBusMgr::emitItemCreated(Item* item)
555
    {
556
        auto coll = item->collection();
557
        QVariantList args;
558
        args += QVariant::fromValue(item->objectPath());
559
        // send on primary path
560
        sendDBusSignal(
561
            coll->objectPath().path(), DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemCreated"), args);
562
        // also send on all alias path
563
        for (const auto& alias : coll->aliases()) {
564
            auto path = DBUS_PATH_TEMPLATE_ALIAS.arg(DBUS_PATH_SECRETS, alias);
565
            sendDBusSignal(path, DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemCreated"), args);
566
        }
567
    }
568

569
    void DBusMgr::emitItemChanged(Item* item)
570
    {
571
        auto coll = item->collection();
572
        QVariantList args;
573
        args += QVariant::fromValue(item->objectPath());
574
        // send on primary path
575
        sendDBusSignal(
576
            coll->objectPath().path(), DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemChanged"), args);
577
        // also send on all alias path
578
        for (const auto& alias : coll->aliases()) {
579
            auto path = DBUS_PATH_TEMPLATE_ALIAS.arg(DBUS_PATH_SECRETS, alias);
580
            sendDBusSignal(path, DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemChanged"), args);
581
        }
582
    }
583

584
    void DBusMgr::emitItemDeleted(Item* item)
585
    {
586
        auto coll = item->collection();
587
        QVariantList args;
588
        args += QVariant::fromValue(item->objectPath());
589
        // send on primary path
590
        sendDBusSignal(
591
            coll->objectPath().path(), DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemDeleted"), args);
592
        // also send on all alias path
593
        for (const auto& alias : coll->aliases()) {
594
            auto path = DBUS_PATH_TEMPLATE_ALIAS.arg(DBUS_PATH_SECRETS, alias);
595
            sendDBusSignal(path, DBUS_INTERFACE_SECRET_COLLECTION, QStringLiteral("ItemDeleted"), args);
596
        }
597
    }
598

599
    void DBusMgr::emitPromptCompleted(bool dismissed, QVariant result)
600
    {
601
        auto prompt = qobject_cast<PromptBase*>(sender());
602
        if (!prompt) {
603
            qDebug() << "Wrong sender in emitPromptCompleted";
604
            return;
605
        }
606

607
        // make sure the result contains a valid value, otherwise QDBusVariant refuses to marshall it.
608
        if (!result.isValid()) {
609
            result = QString{};
610
        }
611

612
        QVariantList args;
613
        args += QVariant::fromValue(dismissed);
614
        args += QVariant::fromValue(QDBusVariant(result));
615
        sendDBusSignal(prompt->objectPath().path(), DBUS_INTERFACE_SECRET_PROMPT, QStringLiteral("Completed"), args);
616
    }
617

618
    DBusClientPtr DBusMgr::findClient(const QString& addr)
619
    {
620
        if (m_overrideClient) {
621
            return m_overrideClient;
622
        }
623

624
        auto it = m_clients.find(addr);
625
        if (it == m_clients.end()) {
626
            auto client = createClient(addr);
627
            if (!client) {
628
                return {};
629
            }
630
            it = m_clients.insert(addr, client);
631
        }
632
        return it.value();
633
    }
634

635
    DBusClientPtr DBusMgr::createClient(const QString& addr)
636
    {
637
        PeerInfo info{};
638
        if (!serviceInfo(addr, info)) {
639
            return {};
640
        }
641

642
        auto client = DBusClientPtr(new DBusClient(this, info));
643

644
        emit clientConnected(client);
645
        m_watcher.addWatchedService(addr);
646

647
        return client;
648
    }
649

650
    void DBusMgr::removeClient(DBusClient* client)
651
    {
652
        if (!client) {
653
            return;
654
        }
655

656
        auto it = m_clients.find(client->address());
657
        if (it == m_clients.end()) {
658
            return;
659
        }
660

661
        emit clientDisconnected(*it);
662
        m_clients.erase(it);
663
    }
664

665
    void DBusMgr::dbusServiceUnregistered(const QString& service)
666
    {
667
        auto removed = m_watcher.removeWatchedService(service);
668
        if (!removed) {
669
            qDebug("FdoSecrets: Failed to remove service watcher");
670
        }
671

672
        auto it = m_clients.find(service);
673
        if (it == m_clients.end()) {
674
            return;
675
        }
676
        auto client = it.value();
677

678
        // client will notify DBusMgr and call DBusMgr::removeClient
679
        client->disconnectDBus();
680
    }
681
} // namespace FdoSecrets
682

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.