File indexing completed on 2024-04-21 04:43:51
0001 /* 0002 * Copyright (C) 2003-2008 Justin Karneges <justin@affinix.com> 0003 * Copyright (C) 2004,2005 Brad Hards <bradh@frogmouth.net> 0004 * 0005 * This library is free software; you can redistribute it and/or 0006 * modify it under the terms of the GNU Lesser General Public 0007 * License as published by the Free Software Foundation; either 0008 * version 2.1 of the License, or (at your option) any later version. 0009 * 0010 * This library is distributed in the hope that it will be useful, 0011 * but WITHOUT ANY WARRANTY; without even the implied warranty of 0012 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 0013 * Lesser General Public License for more details. 0014 * 0015 * You should have received a copy of the GNU Lesser General Public 0016 * License along with this library; if not, write to the Free Software 0017 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 0018 * 02110-1301 USA 0019 * 0020 */ 0021 0022 #include "qca_keystore.h" 0023 0024 #include <QAbstractEventDispatcher> 0025 #include <QCoreApplication> 0026 #include <QMutex> 0027 #include <QPointer> 0028 #include <QSet> 0029 #include <QWaitCondition> 0030 0031 #include <cstdio> // fprintf 0032 #include <cstdlib> // abort 0033 0034 #include "qcaprovider.h" 0035 0036 Q_DECLARE_METATYPE(QCA::KeyStoreEntry) 0037 Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry>) 0038 Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry::Type>) 0039 Q_DECLARE_METATYPE(QCA::KeyBundle) 0040 Q_DECLARE_METATYPE(QCA::Certificate) 0041 Q_DECLARE_METATYPE(QCA::CRL) 0042 Q_DECLARE_METATYPE(QCA::PGPKey) 0043 0044 namespace QCA { 0045 0046 Provider::Context *getContext(const QString &type, Provider *p); 0047 0048 // from qca_plugin.cpp 0049 QString truncate_log(const QString &in, int size); 0050 0051 /* 0052 How this stuff works: 0053 0054 KeyStoreListContext is queried for a list of store context ids. A signal 0055 is used to indicate when the list may have changed, so polling for changes 0056 is not necessary. Context ids change for every new presence of a store. 0057 Even if a user removes and inserts the same smart card device, which has 0058 the same storeId, the context id will ALWAYS be different. If a previously 0059 known context id is missing from a later queried list, then it means the 0060 associated store is unavailable. It is recommended that the provider just 0061 use a counter for the contextId, incrementing the value anytime a new 0062 context is made. 0063 0064 KeyStoreTracker manages all of the keystore stuff, and exists in its own 0065 thread (called the tracker thread). All of the KeyStoreListContext 0066 objects exist in the tracker thread. 0067 */ 0068 0069 /* 0070 scenarios to handle: 0071 - ksm.start shouldn't block 0072 - keystore in available list, but gone by the time it is requested 0073 - keystore is unavailable during a call to a keystoreentry method 0074 - keystore/keystoreentry methods called simultaneously from different threads 0075 - and of course, objects from keystores should work, despite being created 0076 in the keystore thread 0077 */ 0078 0079 //---------------------------------------------------------------------------- 0080 // KeyStoreTracker 0081 //---------------------------------------------------------------------------- 0082 static int tracker_id_at = 0; 0083 0084 class KeyStoreTracker : public QObject 0085 { 0086 Q_OBJECT 0087 public: 0088 static KeyStoreTracker *self; 0089 0090 class Item 0091 { 0092 public: 0093 // combine keystore owner and contextid into a single id 0094 int trackerId; 0095 0096 // number of times the keystore has been updated 0097 int updateCount; 0098 0099 // keystore context 0100 KeyStoreListContext *owner; 0101 int storeContextId; 0102 0103 // properties 0104 QString storeId; 0105 QString name; 0106 KeyStore::Type type; 0107 bool isReadOnly; 0108 0109 Item() 0110 : trackerId(-1) 0111 , updateCount(0) 0112 , owner(nullptr) 0113 , storeContextId(-1) 0114 , storeId(QLatin1String("")) 0115 , name(QLatin1String("")) 0116 , type(KeyStore::System) 0117 , isReadOnly(false) 0118 { 0119 } 0120 }; 0121 0122 QMutex m; 0123 QSet<KeyStoreListContext *> sources; 0124 QSet<KeyStoreListContext *> busySources; 0125 QList<Item> items; 0126 QString dtext; 0127 bool startedAll; 0128 bool busy; 0129 0130 QMutex updateMutex; 0131 0132 KeyStoreTracker() 0133 { 0134 self = this; 0135 0136 qRegisterMetaType<KeyStoreEntry>(); 0137 qRegisterMetaType<QList<KeyStoreEntry>>(); 0138 qRegisterMetaType<QList<KeyStoreEntry::Type>>(); 0139 qRegisterMetaType<KeyBundle>(); 0140 qRegisterMetaType<Certificate>(); 0141 qRegisterMetaType<CRL>(); 0142 qRegisterMetaType<PGPKey>(); 0143 0144 connect(this, &KeyStoreTracker::updated_p, this, &KeyStoreTracker::updated_locked, Qt::QueuedConnection); 0145 0146 startedAll = false; 0147 busy = true; // we start out busy 0148 } 0149 0150 ~KeyStoreTracker() override 0151 { 0152 qDeleteAll(sources); 0153 self = nullptr; 0154 } 0155 0156 static KeyStoreTracker *instance() 0157 { 0158 return self; 0159 } 0160 0161 // thread-safe 0162 bool isBusy() 0163 { 0164 QMutexLocker locker(&m); 0165 return busy; 0166 } 0167 0168 // thread-safe 0169 QList<Item> getItems() 0170 { 0171 QMutexLocker locker(&m); 0172 return items; 0173 } 0174 0175 // thread-safe 0176 QString getDText() 0177 { 0178 QMutexLocker locker(&m); 0179 return dtext; 0180 } 0181 0182 // thread-safe 0183 void clearDText() 0184 { 0185 QMutexLocker locker(&m); 0186 dtext.clear(); 0187 } 0188 0189 // thread-safe 0190 void addTarget(KeyStoreManagerPrivate *ksm); 0191 0192 // thread-safe 0193 void removeTarget(QObject *ksm) 0194 { 0195 QMutexLocker locker(&updateMutex); 0196 disconnect(ksm); 0197 } 0198 0199 public Q_SLOTS: 0200 void spinEventLoop() 0201 { 0202 QAbstractEventDispatcher::instance()->processEvents(QEventLoop::AllEvents); 0203 } 0204 0205 void start() 0206 { 0207 // grab providers (and default) 0208 ProviderList list = providers(); 0209 list.append(defaultProvider()); 0210 0211 for (int n = 0; n < list.count(); ++n) { 0212 Provider *p = list[n]; 0213 if (p->features().contains(QStringLiteral("keystorelist")) && !haveProviderSource(p)) 0214 startProvider(p); 0215 } 0216 0217 startedAll = true; 0218 } 0219 0220 void start(const QString &provider) 0221 { 0222 // grab providers (and default) 0223 ProviderList list = providers(); 0224 list.append(defaultProvider()); 0225 0226 Provider *p = nullptr; 0227 for (int n = 0; n < list.count(); ++n) { 0228 if (list[n]->name() == provider) { 0229 p = list[n]; 0230 break; 0231 } 0232 } 0233 0234 if (p && p->features().contains(QStringLiteral("keystorelist")) && !haveProviderSource(p)) 0235 startProvider(p); 0236 } 0237 0238 void scan() 0239 { 0240 if (startedAll) 0241 start(); 0242 } 0243 0244 QList<QCA::KeyStoreEntry> entryList(int trackerId) 0245 { 0246 QList<KeyStoreEntry> out; 0247 int at = findItem(trackerId); 0248 if (at == -1) 0249 return out; 0250 Item &i = items[at]; 0251 const QList<KeyStoreEntryContext *> list = i.owner->entryList(i.storeContextId); 0252 for (int n = 0; n < list.count(); ++n) { 0253 KeyStoreEntry entry; 0254 entry.change(list[n]); 0255 out.append(entry); 0256 } 0257 return out; 0258 } 0259 0260 QList<QCA::KeyStoreEntry::Type> entryTypes(int trackerId) 0261 { 0262 QList<KeyStoreEntry::Type> out; 0263 int at = findItem(trackerId); 0264 if (at == -1) 0265 return out; 0266 Item &i = items[at]; 0267 return i.owner->entryTypes(i.storeContextId); 0268 } 0269 0270 // hack with void * 0271 void *entry(const QString &storeId, const QString &entryId) 0272 { 0273 KeyStoreListContext *c = nullptr; 0274 int contextId = -1; 0275 m.lock(); 0276 foreach (const Item &i, items) { 0277 if (i.storeId == storeId) { 0278 c = i.owner; 0279 contextId = i.storeContextId; 0280 break; 0281 } 0282 } 0283 m.unlock(); 0284 if (!c) 0285 return nullptr; 0286 0287 return c->entry(contextId, entryId); 0288 } 0289 0290 // hack with void * 0291 void *entryPassive(const QString &serialized) 0292 { 0293 foreach (KeyStoreListContext *ksl, sources) { 0294 // "is this yours?" 0295 KeyStoreEntryContext *e = ksl->entryPassive(serialized); 0296 if (e) 0297 return e; 0298 } 0299 return nullptr; 0300 } 0301 0302 QString writeEntry(int trackerId, const QVariant &v) 0303 { 0304 int at = findItem(trackerId); 0305 if (at == -1) 0306 return QString(); 0307 Item &i = items[at]; 0308 if (v.canConvert<KeyBundle>()) 0309 return i.owner->writeEntry(i.storeContextId, v.value<KeyBundle>()); 0310 else if (v.canConvert<Certificate>()) 0311 return i.owner->writeEntry(i.storeContextId, v.value<Certificate>()); 0312 else if (v.canConvert<CRL>()) 0313 return i.owner->writeEntry(i.storeContextId, v.value<CRL>()); 0314 else if (v.canConvert<PGPKey>()) 0315 return i.owner->writeEntry(i.storeContextId, v.value<PGPKey>()); 0316 else 0317 return QString(); 0318 } 0319 0320 QString writeEntry(int trackerId, const QCA::KeyBundle &v) 0321 { 0322 int at = findItem(trackerId); 0323 if (at == -1) 0324 return QString(); 0325 Item &i = items[at]; 0326 0327 return i.owner->writeEntry(i.storeContextId, v); 0328 } 0329 0330 QString writeEntry(int trackerId, const QCA::Certificate &v) 0331 { 0332 int at = findItem(trackerId); 0333 if (at == -1) 0334 return QString(); 0335 Item &i = items[at]; 0336 0337 return i.owner->writeEntry(i.storeContextId, v); 0338 } 0339 0340 QString writeEntry(int trackerId, const QCA::CRL &v) 0341 { 0342 int at = findItem(trackerId); 0343 if (at == -1) 0344 return QString(); 0345 Item &i = items[at]; 0346 0347 return i.owner->writeEntry(i.storeContextId, v); 0348 } 0349 0350 QString writeEntry(int trackerId, const QCA::PGPKey &v) 0351 { 0352 int at = findItem(trackerId); 0353 if (at == -1) 0354 return QString(); 0355 Item &i = items[at]; 0356 0357 return i.owner->writeEntry(i.storeContextId, v); 0358 } 0359 0360 bool removeEntry(int trackerId, const QString &entryId) 0361 { 0362 int at = findItem(trackerId); 0363 if (at == -1) 0364 return false; 0365 Item &i = items[at]; 0366 return i.owner->removeEntry(i.storeContextId, entryId); 0367 } 0368 0369 Q_SIGNALS: 0370 // emit this when items or busy state changes 0371 void updated(); 0372 void updated_p(); 0373 0374 private Q_SLOTS: 0375 void updated_locked() 0376 { 0377 QMutexLocker locker(&updateMutex); 0378 emit updated(); 0379 } 0380 0381 private: 0382 bool haveProviderSource(Provider *p) const 0383 { 0384 foreach (KeyStoreListContext *ksl, sources) { 0385 if (ksl->provider() == p) 0386 return true; 0387 } 0388 return false; 0389 } 0390 0391 int findItem(int trackerId) 0392 { 0393 for (int n = 0; n < items.count(); ++n) { 0394 if (items[n].trackerId == trackerId) 0395 return n; 0396 } 0397 return -1; 0398 } 0399 0400 void startProvider(Provider *p) 0401 { 0402 KeyStoreListContext *c = static_cast<KeyStoreListContext *>(getContext(QStringLiteral("keystorelist"), p)); 0403 if (!c) 0404 return; 0405 0406 sources += c; 0407 busySources += c; 0408 connect(c, &KeyStoreListContext::busyStart, this, &KeyStoreTracker::ksl_busyStart); 0409 connect(c, &KeyStoreListContext::busyEnd, this, &KeyStoreTracker::ksl_busyEnd); 0410 connect(c, &KeyStoreListContext::updated, this, &KeyStoreTracker::ksl_updated); 0411 connect(c, &KeyStoreListContext::diagnosticText, this, &KeyStoreTracker::ksl_diagnosticText); 0412 connect(c, &KeyStoreListContext::storeUpdated, this, &KeyStoreTracker::ksl_storeUpdated); 0413 c->start(); 0414 c->setUpdatesEnabled(true); 0415 0416 QCA_logTextMessage(QStringLiteral("keystore: startProvider %1").arg(p->name()), Logger::Information); 0417 } 0418 0419 bool updateStores(KeyStoreListContext *c) 0420 { 0421 bool changed = false; 0422 0423 QMutexLocker locker(&m); 0424 0425 const QList<int> keyStores = c->keyStores(); 0426 0427 // remove any contexts that are gone 0428 for (int n = 0; n < items.count(); ++n) { 0429 if (items[n].owner == c && !keyStores.contains(items[n].storeContextId)) { 0430 QCA_logTextMessage(QStringLiteral("keystore: updateStores remove %1").arg(items[n].storeContextId), 0431 Logger::Information); 0432 0433 items.removeAt(n); 0434 --n; // adjust position 0435 0436 changed = true; 0437 } 0438 } 0439 0440 // handle add/updates 0441 foreach (int id, keyStores) { 0442 // do we have it already? 0443 int at = -1; 0444 for (int n = 0; n < items.count(); ++n) { 0445 if (items[n].owner == c && items[n].storeContextId == id) { 0446 at = n; 0447 break; 0448 } 0449 } 0450 0451 // if so, update it 0452 if (at != -1) { 0453 Item &i = items[at]; 0454 0455 QString name = c->name(id); 0456 bool isReadOnly = c->isReadOnly(id); 0457 if (i.name != name || i.isReadOnly != isReadOnly) { 0458 QCA_logTextMessage(QStringLiteral("keystore: updateStores update %1").arg(id), Logger::Information); 0459 i.name = name; 0460 i.isReadOnly = isReadOnly; 0461 changed = true; 0462 } 0463 } 0464 // otherwise, add it 0465 else { 0466 QCA_logTextMessage(QStringLiteral("keystore: updateStores add %1").arg(id), Logger::Information); 0467 0468 Item i; 0469 i.trackerId = tracker_id_at++; 0470 i.updateCount = 0; 0471 i.owner = c; 0472 i.storeContextId = id; 0473 i.storeId = c->storeId(id); 0474 i.name = c->name(id); 0475 i.type = c->type(id); 0476 i.isReadOnly = c->isReadOnly(id); 0477 items += i; 0478 0479 changed = true; 0480 } 0481 } 0482 0483 return changed; 0484 } 0485 0486 private Q_SLOTS: 0487 void ksl_busyStart() 0488 { 0489 KeyStoreListContext *c = (KeyStoreListContext *)sender(); 0490 0491 QCA_logTextMessage(QStringLiteral("keystore: ksl_busyStart %1").arg(c->provider()->name()), 0492 Logger::Information); 0493 0494 if (!busySources.contains(c)) { 0495 busySources += c; 0496 0497 QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); 0498 emit updated_p(); 0499 } 0500 } 0501 0502 void ksl_busyEnd() 0503 { 0504 KeyStoreListContext *c = (KeyStoreListContext *)sender(); 0505 0506 QCA_logTextMessage(QStringLiteral("keystore: ksl_busyEnd %1").arg(c->provider()->name()), Logger::Information); 0507 0508 busySources.remove(c); 0509 bool changed = updateStores(c); 0510 const bool any_busy = !busySources.isEmpty(); 0511 0512 if (!any_busy) { 0513 m.lock(); 0514 busy = false; 0515 m.unlock(); 0516 } 0517 0518 if (!any_busy || changed) { 0519 QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); 0520 emit updated_p(); 0521 } 0522 } 0523 0524 void ksl_updated() 0525 { 0526 KeyStoreListContext *c = (KeyStoreListContext *)sender(); 0527 0528 QCA_logTextMessage(QStringLiteral("keystore: ksl_updated %1").arg(c->provider()->name()), Logger::Information); 0529 0530 bool changed = updateStores(c); 0531 if (changed) { 0532 QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); 0533 emit updated_p(); 0534 } 0535 } 0536 0537 void ksl_diagnosticText(const QString &str) 0538 { 0539 QMutexLocker locker(&m); 0540 dtext += str; 0541 dtext = truncate_log(dtext, 100000); 0542 } 0543 0544 void ksl_storeUpdated(int id) 0545 { 0546 KeyStoreListContext *c = (KeyStoreListContext *)sender(); 0547 0548 QCA_logTextMessage( 0549 QStringLiteral("keystore: ksl_storeUpdated %1 %2").arg(c->provider()->name(), QString::number(id)), 0550 Logger::Information); 0551 0552 QMutexLocker locker(&m); 0553 for (int n = 0; n < items.count(); ++n) { 0554 Item &i = items[n]; 0555 if (i.owner == c && i.storeContextId == id) { 0556 ++i.updateCount; 0557 0558 QCA_logTextMessage( 0559 QStringLiteral("keystore: %1 updateCount = %2").arg(i.name, QString::number(i.updateCount)), 0560 Logger::Information); 0561 0562 QCA_logTextMessage(QStringLiteral("keystore: emitting updated"), Logger::Information); 0563 emit updated_p(); 0564 return; 0565 } 0566 } 0567 } 0568 }; 0569 0570 KeyStoreTracker *KeyStoreTracker::self = nullptr; 0571 0572 //---------------------------------------------------------------------------- 0573 // KeyStoreThread 0574 //---------------------------------------------------------------------------- 0575 class KeyStoreThread : public SyncThread 0576 { 0577 Q_OBJECT 0578 public: 0579 KeyStoreTracker *tracker; 0580 QMutex call_mutex; 0581 0582 KeyStoreThread(QObject *parent = nullptr) 0583 : SyncThread(parent) 0584 { 0585 } 0586 0587 ~KeyStoreThread() override 0588 { 0589 stop(); 0590 } 0591 0592 void atStart() override 0593 { 0594 tracker = new KeyStoreTracker; 0595 } 0596 0597 void atEnd() override 0598 { 0599 delete tracker; 0600 } 0601 }; 0602 0603 //---------------------------------------------------------------------------- 0604 // KeyStoreGlobal 0605 //---------------------------------------------------------------------------- 0606 class KeyStoreManagerGlobal; 0607 0608 Q_GLOBAL_STATIC(QMutex, ksm_mutex) 0609 static KeyStoreManagerGlobal *g_ksm = nullptr; 0610 0611 class KeyStoreManagerGlobal 0612 { 0613 public: 0614 KeyStoreThread *thread; 0615 0616 KeyStoreManagerGlobal() 0617 { 0618 thread = new KeyStoreThread; 0619 thread->moveToThread(QCoreApplication::instance()->thread()); 0620 thread->start(); 0621 } 0622 0623 ~KeyStoreManagerGlobal() 0624 { 0625 delete thread; 0626 } 0627 0628 KeyStoreManagerGlobal(const KeyStoreManagerGlobal &) = delete; 0629 KeyStoreManagerGlobal &operator=(const KeyStoreManagerGlobal &) = delete; 0630 }; 0631 0632 // this function is thread-safe 0633 static QVariant trackercall(const char *method, const QVariantList &args = QVariantList()) 0634 { 0635 QVariant ret; 0636 bool ok; 0637 0638 g_ksm->thread->call_mutex.lock(); 0639 ret = g_ksm->thread->call(KeyStoreTracker::instance(), method, args, &ok); 0640 g_ksm->thread->call_mutex.unlock(); 0641 0642 Q_ASSERT(ok); 0643 if (!ok) { 0644 fprintf(stderr, "QCA: KeyStoreTracker call [%s] failed.\n", method); 0645 abort(); 0646 return QVariant(); 0647 } 0648 return ret; 0649 } 0650 0651 //---------------------------------------------------------------------------- 0652 // KeyStoreEntry 0653 //---------------------------------------------------------------------------- 0654 class KeyStoreEntry::Private 0655 { 0656 public: 0657 bool accessible; 0658 0659 Private() 0660 { 0661 accessible = false; 0662 } 0663 }; 0664 0665 KeyStoreEntry::KeyStoreEntry() 0666 : d(new Private) 0667 { 0668 } 0669 0670 KeyStoreEntry::KeyStoreEntry(const QString &serialized) 0671 : d(new Private) 0672 { 0673 *this = fromString(serialized); 0674 } 0675 0676 KeyStoreEntry::KeyStoreEntry(const KeyStoreEntry &from) 0677 : Algorithm(from) 0678 , d(new Private(*from.d)) 0679 { 0680 } 0681 0682 KeyStoreEntry::~KeyStoreEntry() 0683 { 0684 delete d; 0685 } 0686 0687 KeyStoreEntry &KeyStoreEntry::operator=(const KeyStoreEntry &from) 0688 { 0689 Algorithm::operator=(from); 0690 *d = *from.d; 0691 return *this; 0692 } 0693 0694 bool KeyStoreEntry::isNull() const 0695 { 0696 return (!context() ? true : false); 0697 } 0698 0699 bool KeyStoreEntry::isAvailable() const 0700 { 0701 return static_cast<const KeyStoreEntryContext *>(context())->isAvailable(); 0702 } 0703 0704 bool KeyStoreEntry::isAccessible() const 0705 { 0706 return d->accessible; 0707 } 0708 0709 KeyStoreEntry::Type KeyStoreEntry::type() const 0710 { 0711 return static_cast<const KeyStoreEntryContext *>(context())->type(); 0712 } 0713 0714 QString KeyStoreEntry::name() const 0715 { 0716 return static_cast<const KeyStoreEntryContext *>(context())->name(); 0717 } 0718 0719 QString KeyStoreEntry::id() const 0720 { 0721 return static_cast<const KeyStoreEntryContext *>(context())->id(); 0722 } 0723 0724 QString KeyStoreEntry::storeName() const 0725 { 0726 return static_cast<const KeyStoreEntryContext *>(context())->storeName(); 0727 } 0728 0729 QString KeyStoreEntry::storeId() const 0730 { 0731 return static_cast<const KeyStoreEntryContext *>(context())->storeId(); 0732 } 0733 0734 QString KeyStoreEntry::toString() const 0735 { 0736 return static_cast<const KeyStoreEntryContext *>(context())->serialize(); 0737 } 0738 0739 KeyStoreEntry KeyStoreEntry::fromString(const QString &serialized) 0740 { 0741 KeyStoreEntry e; 0742 KeyStoreEntryContext *c = (KeyStoreEntryContext *)KeyStoreTracker::instance()->entryPassive(serialized); 0743 if (c) 0744 e.change(c); 0745 return e; 0746 } 0747 0748 KeyBundle KeyStoreEntry::keyBundle() const 0749 { 0750 return static_cast<const KeyStoreEntryContext *>(context())->keyBundle(); 0751 } 0752 0753 Certificate KeyStoreEntry::certificate() const 0754 { 0755 return static_cast<const KeyStoreEntryContext *>(context())->certificate(); 0756 } 0757 0758 CRL KeyStoreEntry::crl() const 0759 { 0760 return static_cast<const KeyStoreEntryContext *>(context())->crl(); 0761 } 0762 0763 PGPKey KeyStoreEntry::pgpSecretKey() const 0764 { 0765 return static_cast<const KeyStoreEntryContext *>(context())->pgpSecretKey(); 0766 } 0767 0768 PGPKey KeyStoreEntry::pgpPublicKey() const 0769 { 0770 return static_cast<const KeyStoreEntryContext *>(context())->pgpPublicKey(); 0771 } 0772 0773 bool KeyStoreEntry::ensureAvailable() 0774 { 0775 const QString storeId = this->storeId(); 0776 const QString entryId = id(); 0777 KeyStoreEntryContext *c = 0778 (KeyStoreEntryContext *)trackercall("entry", QVariantList() << storeId << entryId).value<void *>(); 0779 if (c) 0780 change(c); 0781 return isAvailable(); 0782 } 0783 0784 bool KeyStoreEntry::ensureAccess() 0785 { 0786 if (!ensureAvailable()) { 0787 d->accessible = false; 0788 return false; 0789 } 0790 const bool ok = static_cast<KeyStoreEntryContext *>(context())->ensureAccess(); 0791 d->accessible = ok; 0792 return d->accessible; 0793 } 0794 0795 //---------------------------------------------------------------------------- 0796 // KeyStoreEntryWatcher 0797 //---------------------------------------------------------------------------- 0798 class KeyStoreEntryWatcher::Private : public QObject 0799 { 0800 Q_OBJECT 0801 public: 0802 KeyStoreEntryWatcher *q; 0803 KeyStoreManager ksm; 0804 KeyStoreEntry entry; 0805 QString storeId, entryId; 0806 KeyStore *ks; 0807 bool avail; 0808 0809 Private(KeyStoreEntryWatcher *_q) 0810 : QObject(_q) 0811 , q(_q) 0812 , ksm(this) 0813 { 0814 ks = nullptr; 0815 avail = false; 0816 connect(&ksm, &KeyStoreManager::keyStoreAvailable, this, &KeyStoreEntryWatcher::Private::ksm_available); 0817 } 0818 0819 ~Private() override 0820 { 0821 delete ks; 0822 } 0823 0824 void start() 0825 { 0826 const QStringList list = ksm.keyStores(); 0827 foreach (const QString &storeId, list) 0828 ksm_available(storeId); 0829 } 0830 0831 private Q_SLOTS: 0832 void ksm_available(const QString &_storeId) 0833 { 0834 // we only care about one store 0835 if (_storeId == storeId) { 0836 ks = new KeyStore(storeId, &ksm); 0837 connect(ks, &KeyStore::updated, this, &Private::ks_updated); 0838 ks->startAsynchronousMode(); 0839 } 0840 } 0841 0842 void ks_updated() 0843 { 0844 bool found = false; 0845 const QList<KeyStoreEntry> list = ks->entryList(); 0846 foreach (const KeyStoreEntry &e, list) { 0847 if (e.id() == entryId && e.isAvailable()) { 0848 found = true; 0849 if (!avail) 0850 entry = e; 0851 break; 0852 } 0853 } 0854 0855 if (found && !avail) { 0856 avail = true; 0857 emit q->available(); 0858 } else if (!found && avail) { 0859 avail = false; 0860 emit q->unavailable(); 0861 } 0862 } 0863 0864 void ks_unavailable() 0865 { 0866 delete ks; 0867 ks = nullptr; 0868 0869 if (avail) { 0870 avail = false; 0871 emit q->unavailable(); 0872 } 0873 } 0874 }; 0875 0876 KeyStoreEntryWatcher::KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent) 0877 : QObject(parent) 0878 { 0879 d = new Private(this); 0880 if (!e.isNull()) { 0881 d->entry = e; 0882 d->storeId = e.storeId(); 0883 d->entryId = e.id(); 0884 d->start(); 0885 } 0886 } 0887 0888 KeyStoreEntryWatcher::~KeyStoreEntryWatcher() 0889 { 0890 delete d; 0891 } 0892 0893 KeyStoreEntry KeyStoreEntryWatcher::entry() const 0894 { 0895 return d->entry; 0896 } 0897 0898 //---------------------------------------------------------------------------- 0899 // KeyStore 0900 //---------------------------------------------------------------------------- 0901 // union thingy 0902 class KeyStoreWriteEntry 0903 { 0904 public: 0905 enum Type 0906 { 0907 TypeKeyBundle, 0908 TypeCertificate, 0909 TypeCRL, 0910 TypePGPKey 0911 }; 0912 0913 Type type; 0914 KeyBundle keyBundle; 0915 Certificate cert; 0916 CRL crl; 0917 PGPKey pgpKey; 0918 0919 KeyStoreWriteEntry() 0920 { 0921 } 0922 0923 KeyStoreWriteEntry(const KeyBundle &_keyBundle) 0924 : type(TypeKeyBundle) 0925 , keyBundle(_keyBundle) 0926 { 0927 } 0928 0929 KeyStoreWriteEntry(const Certificate &_cert) 0930 : type(TypeCertificate) 0931 , cert(_cert) 0932 { 0933 } 0934 0935 KeyStoreWriteEntry(const CRL &_crl) 0936 : type(TypeCRL) 0937 , crl(_crl) 0938 { 0939 } 0940 0941 KeyStoreWriteEntry(const PGPKey &_pgpKey) 0942 : type(TypePGPKey) 0943 , pgpKey(_pgpKey) 0944 { 0945 } 0946 }; 0947 0948 class KeyStoreOperation : public QThread 0949 { 0950 Q_OBJECT 0951 public: 0952 enum Type 0953 { 0954 EntryList, 0955 WriteEntry, 0956 RemoveEntry 0957 }; 0958 0959 Type type; 0960 int trackerId; 0961 0962 KeyStoreWriteEntry wentry; // in: WriteEntry 0963 QList<KeyStoreEntry> entryList; // out: EntryList 0964 QString entryId; // in: RemoveEntry, out: WriteEntry 0965 bool success; // out: RemoveEntry 0966 0967 KeyStoreOperation(QObject *parent = nullptr) 0968 : QThread(parent) 0969 { 0970 } 0971 0972 ~KeyStoreOperation() override 0973 { 0974 wait(); 0975 } 0976 0977 protected: 0978 void run() override 0979 { 0980 if (type == EntryList) 0981 entryList = trackercall("entryList", QVariantList() << trackerId).value<QList<KeyStoreEntry>>(); 0982 else if (type == WriteEntry) { 0983 QVariant arg; 0984 if (wentry.type == KeyStoreWriteEntry::TypeKeyBundle) 0985 arg = QVariant::fromValue<KeyBundle>(wentry.keyBundle); 0986 else if (wentry.type == KeyStoreWriteEntry::TypeCertificate) 0987 arg = QVariant::fromValue<Certificate>(wentry.cert); 0988 else if (wentry.type == KeyStoreWriteEntry::TypeCRL) 0989 arg = QVariant::fromValue<CRL>(wentry.crl); 0990 else if (wentry.type == KeyStoreWriteEntry::TypePGPKey) 0991 arg = QVariant::fromValue<PGPKey>(wentry.pgpKey); 0992 0993 // note: each variant in the argument list is resolved 0994 // to its native type. so even though it looks like 0995 // we're attempting to call a method named 0996 // writeEntry(QString,QVariant), we're actually 0997 // calling one of many possible methods, such as 0998 // writeEntry(QString,PGPKey) or 0999 // writeEntry(QString,Certificate), etc, depending 1000 // on the type of object we put in the variant. 1001 entryId = trackercall("writeEntry", QVariantList() << trackerId << arg).toString(); 1002 } else // RemoveEntry 1003 { 1004 success = trackercall("removeEntry", QVariantList() << trackerId << entryId).toBool(); 1005 } 1006 } 1007 }; 1008 1009 class KeyStorePrivate : public QObject 1010 { 1011 Q_OBJECT 1012 public: 1013 KeyStore *q; 1014 KeyStoreManager *ksm; 1015 int trackerId; 1016 KeyStoreTracker::Item item; 1017 bool async; 1018 bool need_update; 1019 QList<KeyStoreEntry> latestEntryList; 1020 QList<KeyStoreOperation *> ops; 1021 1022 KeyStorePrivate(KeyStore *_q) 1023 : QObject(_q) 1024 , q(_q) 1025 , async(false) 1026 { 1027 } 1028 1029 ~KeyStorePrivate() override 1030 { 1031 qDeleteAll(ops); 1032 } 1033 1034 // implemented below, after KeyStorePrivate is declared 1035 void reg(); 1036 void unreg(); 1037 KeyStoreTracker::Item *getItem(const QString &storeId); 1038 KeyStoreTracker::Item *getItem(int trackerId); 1039 1040 void invalidate() 1041 { 1042 trackerId = -1; 1043 unreg(); 1044 } 1045 1046 bool have_entryList_op() const 1047 { 1048 foreach (KeyStoreOperation *op, ops) { 1049 if (op->type == KeyStoreOperation::EntryList) 1050 return true; 1051 } 1052 return false; 1053 } 1054 1055 void handle_updated() 1056 { 1057 if (async) { 1058 if (!have_entryList_op()) 1059 async_entryList(); 1060 else 1061 need_update = true; 1062 } else 1063 emit q->updated(); 1064 } 1065 1066 void async_entryList() 1067 { 1068 KeyStoreOperation *op = new KeyStoreOperation(this); 1069 // use queued for signal-safety 1070 connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); 1071 op->type = KeyStoreOperation::EntryList; 1072 op->trackerId = trackerId; 1073 ops += op; 1074 op->start(); 1075 } 1076 1077 void async_writeEntry(const KeyStoreWriteEntry &wentry) 1078 { 1079 KeyStoreOperation *op = new KeyStoreOperation(this); 1080 // use queued for signal-safety 1081 connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); 1082 op->type = KeyStoreOperation::WriteEntry; 1083 op->trackerId = trackerId; 1084 op->wentry = wentry; 1085 ops += op; 1086 op->start(); 1087 } 1088 1089 void async_removeEntry(const QString &entryId) 1090 { 1091 KeyStoreOperation *op = new KeyStoreOperation(this); 1092 // use queued for signal-safety 1093 connect(op, &KeyStoreOperation::finished, this, &KeyStorePrivate::op_finished, Qt::QueuedConnection); 1094 op->type = KeyStoreOperation::RemoveEntry; 1095 op->trackerId = trackerId; 1096 op->entryId = entryId; 1097 ops += op; 1098 op->start(); 1099 } 1100 1101 private Q_SLOTS: 1102 void op_finished() 1103 { 1104 KeyStoreOperation *op = (KeyStoreOperation *)sender(); 1105 1106 if (op->type == KeyStoreOperation::EntryList) { 1107 latestEntryList = op->entryList; 1108 ops.removeAll(op); 1109 delete op; 1110 1111 if (need_update) { 1112 need_update = false; 1113 async_entryList(); 1114 } 1115 1116 emit q->updated(); 1117 } else if (op->type == KeyStoreOperation::WriteEntry) { 1118 QString entryId = op->entryId; 1119 ops.removeAll(op); 1120 delete op; 1121 1122 emit q->entryWritten(entryId); 1123 } else // RemoveEntry 1124 { 1125 bool success = op->success; 1126 ops.removeAll(op); 1127 delete op; 1128 1129 emit q->entryRemoved(success); 1130 } 1131 } 1132 }; 1133 1134 KeyStore::KeyStore(const QString &id, KeyStoreManager *keyStoreManager) 1135 : QObject(keyStoreManager) 1136 { 1137 d = new KeyStorePrivate(this); 1138 d->ksm = keyStoreManager; 1139 1140 KeyStoreTracker::Item *i = d->getItem(id); 1141 if (i) { 1142 d->trackerId = i->trackerId; 1143 d->item = *i; 1144 d->reg(); 1145 } else 1146 d->trackerId = -1; 1147 } 1148 1149 KeyStore::~KeyStore() 1150 { 1151 if (d->trackerId != -1) 1152 d->unreg(); 1153 delete d; 1154 } 1155 1156 bool KeyStore::isValid() const 1157 { 1158 return (d->getItem(d->trackerId) ? true : false); 1159 } 1160 1161 KeyStore::Type KeyStore::type() const 1162 { 1163 return d->item.type; 1164 } 1165 1166 QString KeyStore::name() const 1167 { 1168 return d->item.name; 1169 } 1170 1171 QString KeyStore::id() const 1172 { 1173 return d->item.storeId; 1174 } 1175 1176 bool KeyStore::isReadOnly() const 1177 { 1178 return d->item.isReadOnly; 1179 } 1180 1181 void KeyStore::startAsynchronousMode() 1182 { 1183 if (d->async) 1184 return; 1185 1186 d->async = true; 1187 1188 // initial entrylist 1189 d->need_update = false; 1190 d->async_entryList(); 1191 } 1192 1193 QList<KeyStoreEntry> KeyStore::entryList() const 1194 { 1195 if (d->async) 1196 return d->latestEntryList; 1197 1198 if (d->trackerId == -1) 1199 return QList<KeyStoreEntry>(); 1200 return trackercall("entryList", QVariantList() << d->trackerId).value<QList<KeyStoreEntry>>(); 1201 } 1202 1203 bool KeyStore::holdsTrustedCertificates() const 1204 { 1205 QList<KeyStoreEntry::Type> list; 1206 if (d->trackerId == -1) 1207 return false; 1208 list = trackercall("entryTypes", QVariantList() << d->trackerId).value<QList<KeyStoreEntry::Type>>(); 1209 if (list.contains(KeyStoreEntry::TypeCertificate) || list.contains(KeyStoreEntry::TypeCRL)) 1210 return true; 1211 return false; 1212 } 1213 1214 bool KeyStore::holdsIdentities() const 1215 { 1216 QList<KeyStoreEntry::Type> list; 1217 if (d->trackerId == -1) 1218 return false; 1219 list = trackercall("entryTypes", QVariantList() << d->trackerId).value<QList<KeyStoreEntry::Type>>(); 1220 if (list.contains(KeyStoreEntry::TypeKeyBundle) || list.contains(KeyStoreEntry::TypePGPSecretKey)) 1221 return true; 1222 return false; 1223 } 1224 1225 bool KeyStore::holdsPGPPublicKeys() const 1226 { 1227 QList<KeyStoreEntry::Type> list; 1228 if (d->trackerId == -1) 1229 return false; 1230 list = trackercall("entryTypes", QVariantList() << d->trackerId).value<QList<KeyStoreEntry::Type>>(); 1231 if (list.contains(KeyStoreEntry::TypePGPPublicKey)) 1232 return true; 1233 return false; 1234 } 1235 1236 QString KeyStore::writeEntry(const KeyBundle &kb) 1237 { 1238 if (d->async) { 1239 d->async_writeEntry(KeyStoreWriteEntry(kb)); 1240 return QString(); 1241 } else { 1242 const auto arg = QVariant::fromValue<KeyBundle>(kb); 1243 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); 1244 } 1245 } 1246 1247 QString KeyStore::writeEntry(const Certificate &cert) 1248 { 1249 if (d->async) { 1250 d->async_writeEntry(KeyStoreWriteEntry(cert)); 1251 return QString(); 1252 } else { 1253 const auto arg = QVariant::fromValue<Certificate>(cert); 1254 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); 1255 } 1256 } 1257 1258 QString KeyStore::writeEntry(const CRL &crl) 1259 { 1260 if (d->async) { 1261 d->async_writeEntry(KeyStoreWriteEntry(crl)); 1262 return QString(); 1263 } else { 1264 const auto arg = QVariant::fromValue<CRL>(crl); 1265 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); 1266 } 1267 } 1268 1269 QString KeyStore::writeEntry(const PGPKey &key) 1270 { 1271 if (d->async) { 1272 d->async_writeEntry(KeyStoreWriteEntry(key)); 1273 return QString(); 1274 } else { 1275 const auto arg = QVariant::fromValue<PGPKey>(key); 1276 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString(); 1277 } 1278 } 1279 1280 bool KeyStore::removeEntry(const QString &id) 1281 { 1282 if (d->async) { 1283 d->async_removeEntry(id); 1284 return false; 1285 } else { 1286 return trackercall("removeEntry", QVariantList() << d->trackerId << id).toBool(); 1287 } 1288 } 1289 1290 //---------------------------------------------------------------------------- 1291 // KeyStoreManager 1292 //---------------------------------------------------------------------------- 1293 static void ensure_init() 1294 { 1295 QMutexLocker locker(ksm_mutex()); 1296 if (!g_ksm) 1297 g_ksm = new KeyStoreManagerGlobal; 1298 } 1299 1300 // static functions 1301 void KeyStoreManager::start() 1302 { 1303 ensure_init(); 1304 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection); 1305 trackercall("spinEventLoop"); 1306 } 1307 1308 void KeyStoreManager::start(const QString &provider) 1309 { 1310 ensure_init(); 1311 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection, Q_ARG(QString, provider)); 1312 trackercall("spinEventLoop"); 1313 } 1314 1315 QString KeyStoreManager::diagnosticText() 1316 { 1317 ensure_init(); 1318 1319 // spin one event cycle in the tracker, to receive any pending text. 1320 // note that since trackercall also goes through the eventloop, 1321 // this may end up doing two rounds. probably no big deal. 1322 trackercall("spinEventLoop"); 1323 1324 return KeyStoreTracker::instance()->getDText(); 1325 } 1326 1327 void KeyStoreManager::clearDiagnosticText() 1328 { 1329 ensure_init(); 1330 KeyStoreTracker::instance()->clearDText(); 1331 } 1332 1333 void KeyStoreManager::scan() 1334 { 1335 ensure_init(); 1336 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "scan", Qt::QueuedConnection); 1337 } 1338 1339 void KeyStoreManager::shutdown() 1340 { 1341 QMutexLocker locker(ksm_mutex()); 1342 delete g_ksm; 1343 g_ksm = nullptr; 1344 } 1345 1346 // object 1347 class KeyStoreManagerPrivate : public QObject 1348 { 1349 Q_OBJECT 1350 public: 1351 KeyStoreManager *q; 1352 1353 QMutex m; 1354 QWaitCondition w; 1355 bool busy; 1356 QList<KeyStoreTracker::Item> items; 1357 bool pending, waiting; 1358 1359 QMultiHash<int, KeyStore *> keyStoreForTrackerId; 1360 QHash<KeyStore *, int> trackerIdForKeyStore; 1361 1362 KeyStoreManagerPrivate(KeyStoreManager *_q) 1363 : QObject(_q) 1364 , q(_q) 1365 { 1366 pending = false; 1367 waiting = false; 1368 } 1369 1370 ~KeyStoreManagerPrivate() override 1371 { 1372 // invalidate registered keystores 1373 QList<KeyStore *> list; 1374 QHashIterator<KeyStore *, int> it(trackerIdForKeyStore); 1375 while (it.hasNext()) { 1376 it.next(); 1377 list += it.key(); 1378 } 1379 foreach (KeyStore *ks, list) 1380 ks->d->invalidate(); 1381 } 1382 1383 // for keystore 1384 void reg(KeyStore *ks, int trackerId) 1385 { 1386 keyStoreForTrackerId.insert(trackerId, ks); 1387 trackerIdForKeyStore.insert(ks, trackerId); 1388 } 1389 1390 void unreg(KeyStore *ks) 1391 { 1392 int trackerId = trackerIdForKeyStore.take(ks); 1393 1394 // this is the only way I know to remove one item from a multihash 1395 QList<KeyStore *> vals = keyStoreForTrackerId.values(trackerId); 1396 keyStoreForTrackerId.remove(trackerId); 1397 vals.removeAll(ks); 1398 foreach (KeyStore *i, vals) 1399 keyStoreForTrackerId.insert(trackerId, i); 1400 } 1401 1402 KeyStoreTracker::Item *getItem(const QString &storeId) 1403 { 1404 for (int n = 0; n < items.count(); ++n) { 1405 KeyStoreTracker::Item *i = &items[n]; 1406 if (i->storeId == storeId) 1407 return i; 1408 } 1409 return nullptr; 1410 } 1411 1412 KeyStoreTracker::Item *getItem(int trackerId) 1413 { 1414 for (int n = 0; n < items.count(); ++n) { 1415 KeyStoreTracker::Item *i = &items[n]; 1416 if (i->trackerId == trackerId) 1417 return i; 1418 } 1419 return nullptr; 1420 } 1421 1422 void do_update() 1423 { 1424 // ksm doesn't have reset or state changes so we can 1425 // use QPointer here for full SS. 1426 QPointer<QObject> self(this); 1427 1428 const bool newbusy = KeyStoreTracker::instance()->isBusy(); 1429 const QList<KeyStoreTracker::Item> newitems = KeyStoreTracker::instance()->getItems(); 1430 1431 if (!busy && newbusy) { 1432 emit q->busyStarted(); 1433 if (!self) 1434 return; 1435 } 1436 if (busy && !newbusy) { 1437 emit q->busyFinished(); 1438 if (!self) 1439 return; 1440 } 1441 1442 QStringList here; 1443 QList<int> changed; 1444 QList<int> gone; 1445 1446 // removed 1447 for (int n = 0; n < items.count(); ++n) { 1448 KeyStoreTracker::Item &i = items[n]; 1449 bool found = false; 1450 for (int k = 0; k < newitems.count(); ++k) { 1451 if (i.trackerId == newitems[k].trackerId) { 1452 found = true; 1453 break; 1454 } 1455 } 1456 if (!found) 1457 gone += i.trackerId; 1458 } 1459 1460 // changed 1461 for (int n = 0; n < items.count(); ++n) { 1462 KeyStoreTracker::Item &i = items[n]; 1463 for (int k = 0; k < newitems.count(); ++k) { 1464 if (i.trackerId == newitems[k].trackerId) { 1465 if (i.updateCount < newitems[k].updateCount) 1466 changed += i.trackerId; 1467 break; 1468 } 1469 } 1470 } 1471 1472 // added 1473 for (int n = 0; n < newitems.count(); ++n) { 1474 const KeyStoreTracker::Item &i = newitems[n]; 1475 bool found = false; 1476 for (int k = 0; k < items.count(); ++k) { 1477 if (i.trackerId == items[k].trackerId) { 1478 found = true; 1479 break; 1480 } 1481 } 1482 if (!found) 1483 here += i.storeId; 1484 } 1485 1486 busy = newbusy; 1487 items = newitems; 1488 1489 // signals 1490 foreach (int trackerId, gone) { 1491 KeyStore *ks = keyStoreForTrackerId.value(trackerId); 1492 if (ks) { 1493 ks->d->invalidate(); 1494 emit ks->unavailable(); 1495 if (!self) 1496 return; 1497 } 1498 } 1499 1500 foreach (int trackerId, changed) { 1501 KeyStore *ks = keyStoreForTrackerId.value(trackerId); 1502 if (ks) { 1503 ks->d->handle_updated(); 1504 if (!self) 1505 return; 1506 } 1507 } 1508 1509 foreach (const QString &storeId, here) { 1510 emit q->keyStoreAvailable(storeId); 1511 if (!self) 1512 return; 1513 } 1514 } 1515 1516 public Q_SLOTS: 1517 void tracker_updated() 1518 { 1519 QCA_logTextMessage(QString::asprintf("keystore: %p: tracker_updated start", q), Logger::Information); 1520 1521 QMutexLocker locker(&m); 1522 if (!pending) { 1523 QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection); 1524 pending = true; 1525 } 1526 if (waiting && !KeyStoreTracker::instance()->isBusy()) { 1527 busy = false; 1528 items = KeyStoreTracker::instance()->getItems(); 1529 w.wakeOne(); 1530 } 1531 1532 QCA_logTextMessage(QString::asprintf("keystore: %p: tracker_updated end", q), Logger::Information); 1533 } 1534 1535 void update() 1536 { 1537 m.lock(); 1538 pending = false; 1539 m.unlock(); 1540 1541 do_update(); 1542 } 1543 }; 1544 1545 // from KeyStoreTracker 1546 void KeyStoreTracker::addTarget(KeyStoreManagerPrivate *ksm) 1547 { 1548 QMutexLocker locker(&updateMutex); 1549 connect(this, &KeyStoreTracker::updated, ksm, &KeyStoreManagerPrivate::tracker_updated, Qt::DirectConnection); 1550 } 1551 1552 // from KeyStorePrivate 1553 void KeyStorePrivate::reg() 1554 { 1555 ksm->d->reg(q, trackerId); 1556 } 1557 1558 void KeyStorePrivate::unreg() 1559 { 1560 ksm->d->unreg(q); 1561 } 1562 1563 KeyStoreTracker::Item *KeyStorePrivate::getItem(const QString &storeId) 1564 { 1565 return ksm->d->getItem(storeId); 1566 } 1567 1568 KeyStoreTracker::Item *KeyStorePrivate::getItem(int trackerId) 1569 { 1570 return ksm->d->getItem(trackerId); 1571 } 1572 1573 KeyStoreManager::KeyStoreManager(QObject *parent) 1574 : QObject(parent) 1575 { 1576 ensure_init(); 1577 d = new KeyStoreManagerPrivate(this); 1578 KeyStoreTracker::instance()->addTarget(d); 1579 sync(); 1580 } 1581 1582 KeyStoreManager::~KeyStoreManager() 1583 { 1584 Q_ASSERT(KeyStoreTracker::instance()); 1585 KeyStoreTracker::instance()->removeTarget(d); 1586 delete d; 1587 } 1588 1589 bool KeyStoreManager::isBusy() const 1590 { 1591 return d->busy; 1592 } 1593 1594 void KeyStoreManager::waitForBusyFinished() 1595 { 1596 d->m.lock(); 1597 d->busy = KeyStoreTracker::instance()->isBusy(); 1598 if (d->busy) { 1599 d->waiting = true; 1600 d->w.wait(&d->m); 1601 d->waiting = false; 1602 } 1603 d->m.unlock(); 1604 } 1605 1606 QStringList KeyStoreManager::keyStores() const 1607 { 1608 QStringList out; 1609 for (int n = 0; n < d->items.count(); ++n) 1610 out += d->items[n].storeId; 1611 return out; 1612 } 1613 1614 void KeyStoreManager::sync() 1615 { 1616 d->busy = KeyStoreTracker::instance()->isBusy(); 1617 d->items = KeyStoreTracker::instance()->getItems(); 1618 } 1619 1620 //---------------------------------------------------------------------------- 1621 // KeyStoreInfo 1622 //---------------------------------------------------------------------------- 1623 class KeyStoreInfo::Private : public QSharedData 1624 { 1625 public: 1626 KeyStore::Type type; 1627 QString id, name; 1628 }; 1629 1630 KeyStoreInfo::KeyStoreInfo() 1631 { 1632 } 1633 1634 KeyStoreInfo::KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name) 1635 : d(new Private) 1636 { 1637 d->type = type; 1638 d->id = id; 1639 d->name = name; 1640 } 1641 1642 KeyStoreInfo::KeyStoreInfo(const KeyStoreInfo &from) 1643 : d(from.d) 1644 { 1645 } 1646 1647 KeyStoreInfo::~KeyStoreInfo() 1648 { 1649 } 1650 1651 KeyStoreInfo &KeyStoreInfo::operator=(const KeyStoreInfo &from) 1652 { 1653 d = from.d; 1654 return *this; 1655 } 1656 1657 bool KeyStoreInfo::isNull() const 1658 { 1659 return (d ? false : true); 1660 } 1661 1662 KeyStore::Type KeyStoreInfo::type() const 1663 { 1664 return d->type; 1665 } 1666 1667 QString KeyStoreInfo::id() const 1668 { 1669 return d->id; 1670 } 1671 1672 QString KeyStoreInfo::name() const 1673 { 1674 return d->name; 1675 } 1676 1677 } 1678 1679 #include "qca_keystore.moc"