00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "qca_keystore.h"
00023
00024 #include <QCoreApplication>
00025 #include <QAbstractEventDispatcher>
00026 #include <QPointer>
00027 #include <QSet>
00028 #include <QMutex>
00029 #include <QWaitCondition>
00030
00031 #include <stdlib.h>
00032 #include <stdio.h>
00033
00034 #include "qcaprovider.h"
00035
00036 Q_DECLARE_METATYPE(QCA::KeyStoreEntry)
00037 Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry>)
00038 Q_DECLARE_METATYPE(QList<QCA::KeyStoreEntry::Type>)
00039 Q_DECLARE_METATYPE(QCA::KeyBundle)
00040 Q_DECLARE_METATYPE(QCA::Certificate)
00041 Q_DECLARE_METATYPE(QCA::CRL)
00042 Q_DECLARE_METATYPE(QCA::PGPKey)
00043
00044 namespace QCA {
00045
00046 Provider::Context *getContext(const QString &type, Provider *p);
00047
00048
00049 QString truncate_log(const QString &in, int size);
00050
00051
00052
00053
00054
00055
00056
00057
00058
00059
00060
00061
00062
00063
00064
00065
00066
00067
00068
00069
00070
00071
00072
00073
00074
00075
00076
00077
00078
00079
00080
00081
00082 static int tracker_id_at = 0;
00083
00084 class KeyStoreTracker : public QObject
00085 {
00086 Q_OBJECT
00087 public:
00088 static KeyStoreTracker *self;
00089
00090 class Item
00091 {
00092 public:
00093
00094 int trackerId;
00095
00096
00097 int updateCount;
00098
00099
00100 KeyStoreListContext *owner;
00101 int storeContextId;
00102
00103
00104 QString storeId;
00105 QString name;
00106 KeyStore::Type type;
00107 bool isReadOnly;
00108
00109 Item() : trackerId(-1), updateCount(0), owner(0), storeContextId(-1)
00110 {
00111 }
00112 };
00113
00114 QMutex m;
00115 QSet<KeyStoreListContext*> sources;
00116 QSet<KeyStoreListContext*> busySources;
00117 QList<Item> items;
00118 QString dtext;
00119 bool startedAll;
00120 bool busy;
00121
00122 QMutex updateMutex;
00123
00124 KeyStoreTracker()
00125 {
00126 self = this;
00127
00128 qRegisterMetaType<KeyStoreEntry>();
00129 qRegisterMetaType< QList<KeyStoreEntry> >();
00130 qRegisterMetaType< QList<KeyStoreEntry::Type> >();
00131 qRegisterMetaType<KeyBundle>();
00132 qRegisterMetaType<Certificate>();
00133 qRegisterMetaType<CRL>();
00134 qRegisterMetaType<PGPKey>();
00135
00136 connect(this, SIGNAL(updated_p()), SLOT(updated_locked()), Qt::QueuedConnection);
00137
00138 startedAll = false;
00139 busy = true;
00140 }
00141
00142 ~KeyStoreTracker()
00143 {
00144 qDeleteAll(sources);
00145 self = 0;
00146 }
00147
00148 static KeyStoreTracker *instance()
00149 {
00150 return self;
00151 }
00152
00153
00154 bool isBusy()
00155 {
00156 QMutexLocker locker(&m);
00157 return busy;
00158 }
00159
00160
00161 QList<Item> getItems()
00162 {
00163 QMutexLocker locker(&m);
00164 return items;
00165 }
00166
00167
00168 QString getDText()
00169 {
00170 QMutexLocker locker(&m);
00171 return dtext;
00172 }
00173
00174
00175 void clearDText()
00176 {
00177 QMutexLocker locker(&m);
00178 dtext.clear();
00179 }
00180
00181
00182 void addTarget(QObject *ksm)
00183 {
00184 QMutexLocker locker(&updateMutex);
00185 ksm->connect(this, SIGNAL(updated()), SLOT(tracker_updated()), Qt::DirectConnection);
00186 }
00187
00188
00189 void removeTarget(QObject *ksm)
00190 {
00191 QMutexLocker locker(&updateMutex);
00192 disconnect(ksm);
00193 }
00194
00195 public slots:
00196 void spinEventLoop()
00197 {
00198 QAbstractEventDispatcher::instance()->processEvents(QEventLoop::AllEvents);
00199 }
00200
00201 void start()
00202 {
00203
00204 ProviderList list = providers();
00205 list.append(defaultProvider());
00206
00207 for(int n = 0; n < list.count(); ++n)
00208 {
00209 Provider *p = list[n];
00210 if(p->features().contains("keystorelist") && !haveProviderSource(p))
00211 startProvider(p);
00212 }
00213
00214 startedAll = true;
00215 }
00216
00217 void start(const QString &provider)
00218 {
00219
00220 ProviderList list = providers();
00221 list.append(defaultProvider());
00222
00223 Provider *p = 0;
00224 for(int n = 0; n < list.count(); ++n)
00225 {
00226 if(list[n]->name() == provider)
00227 {
00228 p = list[n];
00229 break;
00230 }
00231 }
00232
00233 if(p && p->features().contains("keystorelist") && !haveProviderSource(p))
00234 startProvider(p);
00235 }
00236
00237 void scan()
00238 {
00239 if(startedAll)
00240 start();
00241 }
00242
00243 QList<QCA::KeyStoreEntry> entryList(int trackerId)
00244 {
00245 QList<KeyStoreEntry> out;
00246 int at = findItem(trackerId);
00247 if(at == -1)
00248 return out;
00249 Item &i = items[at];
00250 QList<KeyStoreEntryContext*> list = i.owner->entryList(i.storeContextId);
00251 for(int n = 0; n < list.count(); ++n)
00252 {
00253 KeyStoreEntry entry;
00254 entry.change(list[n]);
00255 out.append(entry);
00256 }
00257 return out;
00258 }
00259
00260 QList<QCA::KeyStoreEntry::Type> entryTypes(int trackerId)
00261 {
00262 QList<KeyStoreEntry::Type> out;
00263 int at = findItem(trackerId);
00264 if(at == -1)
00265 return out;
00266 Item &i = items[at];
00267 return i.owner->entryTypes(i.storeContextId);
00268 }
00269
00270
00271 void *entry(const QString &storeId, const QString &entryId)
00272 {
00273 KeyStoreListContext *c = 0;
00274 int contextId = -1;
00275 m.lock();
00276 foreach(const Item &i, items)
00277 {
00278 if(i.storeId == storeId)
00279 {
00280 c = i.owner;
00281 contextId = i.storeContextId;
00282 break;
00283 }
00284 }
00285 m.unlock();
00286 if(!c)
00287 return 0;
00288
00289 return c->entry(contextId, entryId);
00290 }
00291
00292
00293 void *entryPassive(const QString &serialized)
00294 {
00295 foreach(KeyStoreListContext *ksl, sources)
00296 {
00297
00298 KeyStoreEntryContext *e = ksl->entryPassive(serialized);
00299 if(e)
00300 return e;
00301 }
00302 return 0;
00303 }
00304
00305 QString writeEntry(int trackerId, const QVariant &v)
00306 {
00307 int at = findItem(trackerId);
00308 if(at == -1)
00309 return QString();
00310 Item &i = items[at];
00311 if(qVariantCanConvert<KeyBundle>(v))
00312 return i.owner->writeEntry(i.storeContextId, qVariantValue<KeyBundle>(v));
00313 else if(qVariantCanConvert<Certificate>(v))
00314 return i.owner->writeEntry(i.storeContextId, qVariantValue<Certificate>(v));
00315 else if(qVariantCanConvert<CRL>(v))
00316 return i.owner->writeEntry(i.storeContextId, qVariantValue<CRL>(v));
00317 else if(qVariantCanConvert<PGPKey>(v))
00318 return i.owner->writeEntry(i.storeContextId, qVariantValue<PGPKey>(v));
00319 else
00320 return QString();
00321 }
00322
00323 QString writeEntry(int trackerId, const QCA::KeyBundle &v)
00324 {
00325 int at = findItem(trackerId);
00326 if(at == -1)
00327 return QString();
00328 Item &i = items[at];
00329
00330 return i.owner->writeEntry(i.storeContextId, v);
00331 }
00332
00333 QString writeEntry(int trackerId, const QCA::Certificate &v)
00334 {
00335 int at = findItem(trackerId);
00336 if(at == -1)
00337 return QString();
00338 Item &i = items[at];
00339
00340 return i.owner->writeEntry(i.storeContextId, v);
00341 }
00342
00343 QString writeEntry(int trackerId, const QCA::CRL &v)
00344 {
00345 int at = findItem(trackerId);
00346 if(at == -1)
00347 return QString();
00348 Item &i = items[at];
00349
00350 return i.owner->writeEntry(i.storeContextId, v);
00351 }
00352
00353 QString writeEntry(int trackerId, const QCA::PGPKey &v)
00354 {
00355 int at = findItem(trackerId);
00356 if(at == -1)
00357 return QString();
00358 Item &i = items[at];
00359
00360 return i.owner->writeEntry(i.storeContextId, v);
00361 }
00362
00363 bool removeEntry(int trackerId, const QString &entryId)
00364 {
00365 int at = findItem(trackerId);
00366 if(at == -1)
00367 return false;
00368 Item &i = items[at];
00369 return i.owner->removeEntry(i.storeContextId, entryId);
00370 }
00371
00372 signals:
00373
00374 void updated();
00375 void updated_p();
00376
00377 private slots:
00378 void updated_locked()
00379 {
00380 QMutexLocker locker(&updateMutex);
00381 emit updated();
00382 }
00383
00384 private:
00385 bool haveProviderSource(Provider *p) const
00386 {
00387 foreach(KeyStoreListContext *ksl, sources)
00388 {
00389 if(ksl->provider() == p)
00390 return true;
00391 }
00392 return false;
00393 }
00394
00395 int findItem(int trackerId)
00396 {
00397 for(int n = 0; n < items.count(); ++n)
00398 {
00399 if(items[n].trackerId == trackerId)
00400 return n;
00401 }
00402 return -1;
00403 }
00404
00405 void startProvider(Provider *p)
00406 {
00407 KeyStoreListContext *c = static_cast<KeyStoreListContext *>(getContext("keystorelist", p));
00408 if(!c)
00409 return;
00410
00411 sources += c;
00412 busySources += c;
00413 connect(c, SIGNAL(busyStart()), SLOT(ksl_busyStart()));
00414 connect(c, SIGNAL(busyEnd()), SLOT(ksl_busyEnd()));
00415 connect(c, SIGNAL(updated()), SLOT(ksl_updated()));
00416 connect(c, SIGNAL(diagnosticText(const QString &)), SLOT(ksl_diagnosticText(const QString &)));
00417 connect(c, SIGNAL(storeUpdated(int)), SLOT(ksl_storeUpdated(int)));
00418 c->start();
00419 c->setUpdatesEnabled(true);
00420
00421 QCA_logTextMessage(QString("keystore: startProvider %1").arg(p->name()), Logger::Information);
00422 }
00423
00424 bool updateStores(KeyStoreListContext *c)
00425 {
00426 bool changed = false;
00427
00428 QMutexLocker locker(&m);
00429
00430 QList<int> keyStores = c->keyStores();
00431
00432
00433 for(int n = 0; n < items.count(); ++n)
00434 {
00435 if(items[n].owner == c && !keyStores.contains(items[n].storeContextId))
00436 {
00437 QCA_logTextMessage(QString("keystore: updateStores remove %1").arg(items[n].storeContextId), Logger::Information);
00438
00439 items.removeAt(n);
00440 --n;
00441
00442 changed = true;
00443 }
00444 }
00445
00446
00447 foreach(int id, keyStores)
00448 {
00449
00450 int at = -1;
00451 for(int n = 0; n < items.count(); ++n)
00452 {
00453 if(items[n].owner == c && items[n].storeContextId == id)
00454 {
00455 at = n;
00456 break;
00457 }
00458 }
00459
00460
00461 if(at != -1)
00462 {
00463 Item &i = items[at];
00464
00465 QString name = c->name(id);
00466 bool isReadOnly = c->isReadOnly(id);
00467 if(i.name != name || i.isReadOnly != isReadOnly)
00468 {
00469 QCA_logTextMessage(QString("keystore: updateStores update %1").arg(id), Logger::Information);
00470 i.name = name;
00471 i.isReadOnly = isReadOnly;
00472 changed = true;
00473 }
00474 }
00475
00476 else
00477 {
00478 QCA_logTextMessage(QString("keystore: updateStores add %1").arg(id), Logger::Information);
00479
00480 Item i;
00481 i.trackerId = tracker_id_at++;
00482 i.updateCount = 0;
00483 i.owner = c;
00484 i.storeContextId = id;
00485 i.storeId = c->storeId(id);
00486 i.name = c->name(id);
00487 i.type = c->type(id);
00488 i.isReadOnly = c->isReadOnly(id);
00489 items += i;
00490
00491 changed = true;
00492 }
00493 }
00494
00495 return changed;
00496 }
00497
00498 private slots:
00499 void ksl_busyStart()
00500 {
00501 KeyStoreListContext *c = (KeyStoreListContext *)sender();
00502
00503 QCA_logTextMessage(QString("keystore: ksl_busyStart %1").arg(c->provider()->name()), Logger::Information);
00504
00505 if(!busySources.contains(c))
00506 {
00507 busySources += c;
00508
00509 QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
00510 emit updated_p();
00511 }
00512 }
00513
00514 void ksl_busyEnd()
00515 {
00516 KeyStoreListContext *c = (KeyStoreListContext *)sender();
00517
00518 QCA_logTextMessage(QString("keystore: ksl_busyEnd %1").arg(c->provider()->name()), Logger::Information);
00519
00520 busySources.remove(c);
00521 bool changed = updateStores(c);
00522 bool any_busy = !busySources.isEmpty();
00523
00524 if(!any_busy)
00525 {
00526 m.lock();
00527 busy = false;
00528 m.unlock();
00529 }
00530
00531 if(!any_busy || changed)
00532 {
00533 QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
00534 emit updated_p();
00535 }
00536 }
00537
00538 void ksl_updated()
00539 {
00540 KeyStoreListContext *c = (KeyStoreListContext *)sender();
00541
00542 QCA_logTextMessage(QString("keystore: ksl_updated %1").arg(c->provider()->name()), Logger::Information);
00543
00544 bool changed = updateStores(c);
00545 if(changed)
00546 {
00547 QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
00548 emit updated_p();
00549 }
00550 }
00551
00552 void ksl_diagnosticText(const QString &str)
00553 {
00554 QMutexLocker locker(&m);
00555 dtext += str;
00556 dtext = truncate_log(dtext, 100000);
00557 }
00558
00559 void ksl_storeUpdated(int id)
00560 {
00561 KeyStoreListContext *c = (KeyStoreListContext *)sender();
00562
00563 QCA_logTextMessage(QString("keystore: ksl_storeUpdated %1 %2").arg(c->provider()->name(), QString::number(id)), Logger::Information);
00564
00565 QMutexLocker locker(&m);
00566 for(int n = 0; n < items.count(); ++n)
00567 {
00568 Item &i = items[n];
00569 if(i.owner == c && i.storeContextId == id)
00570 {
00571 ++i.updateCount;
00572
00573 QCA_logTextMessage(QString("keystore: %1 updateCount = %2").arg(i.name, QString::number(i.updateCount)), Logger::Information);
00574
00575 QCA_logTextMessage(QString("keystore: emitting updated"), Logger::Information);
00576 emit updated_p();
00577 return;
00578 }
00579 }
00580 }
00581 };
00582
00583 KeyStoreTracker *KeyStoreTracker::self = 0;
00584
00585
00586
00587
00588 class KeyStoreThread : public SyncThread
00589 {
00590 Q_OBJECT
00591 public:
00592 KeyStoreTracker *tracker;
00593 QMutex call_mutex;
00594
00595 KeyStoreThread(QObject *parent = 0) : SyncThread(parent)
00596 {
00597 }
00598
00599 ~KeyStoreThread()
00600 {
00601 stop();
00602 }
00603
00604 void atStart()
00605 {
00606 tracker = new KeyStoreTracker;
00607 }
00608
00609 void atEnd()
00610 {
00611 delete tracker;
00612 }
00613 };
00614
00615
00616
00617
00618 class KeyStoreManagerGlobal;
00619
00620 Q_GLOBAL_STATIC(QMutex, ksm_mutex)
00621 static KeyStoreManagerGlobal *g_ksm = 0;
00622
00623 class KeyStoreManagerGlobal
00624 {
00625 public:
00626 KeyStoreThread *thread;
00627
00628 KeyStoreManagerGlobal()
00629 {
00630 thread = new KeyStoreThread;
00631 thread->moveToThread(QCoreApplication::instance()->thread());
00632 thread->start();
00633 }
00634
00635 ~KeyStoreManagerGlobal()
00636 {
00637 delete thread;
00638 }
00639 };
00640
00641
00642 static QVariant trackercall(const char *method, const QVariantList &args = QVariantList())
00643 {
00644 QVariant ret;
00645 bool ok;
00646
00647 g_ksm->thread->call_mutex.lock();
00648 ret = g_ksm->thread->call(KeyStoreTracker::instance(), method, args, &ok);
00649 g_ksm->thread->call_mutex.unlock();
00650
00651 Q_ASSERT(ok);
00652 if(!ok)
00653 {
00654 fprintf(stderr, "QCA: KeyStoreTracker call [%s] failed.\n", method);
00655 abort();
00656 return QVariant();
00657 }
00658 return ret;
00659 }
00660
00661
00662
00663
00664 class KeyStoreEntry::Private
00665 {
00666 public:
00667 bool accessible;
00668
00669 Private()
00670 {
00671 accessible = false;
00672 }
00673 };
00674
00675 KeyStoreEntry::KeyStoreEntry()
00676 :d(new Private)
00677 {
00678 }
00679
00680 KeyStoreEntry::KeyStoreEntry(const QString &serialized)
00681 :d(new Private)
00682 {
00683 *this = fromString(serialized);
00684 }
00685
00686 KeyStoreEntry::KeyStoreEntry(const KeyStoreEntry &from)
00687 :Algorithm(from), d(new Private(*from.d))
00688 {
00689 }
00690
00691 KeyStoreEntry::~KeyStoreEntry()
00692 {
00693 delete d;
00694 }
00695
00696 KeyStoreEntry & KeyStoreEntry::operator=(const KeyStoreEntry &from)
00697 {
00698 Algorithm::operator=(from);
00699 *d = *from.d;
00700 return *this;
00701 }
00702
00703 bool KeyStoreEntry::isNull() const
00704 {
00705 return (!context() ? true : false);
00706 }
00707
00708 bool KeyStoreEntry::isAvailable() const
00709 {
00710 return static_cast<const KeyStoreEntryContext *>(context())->isAvailable();
00711 }
00712
00713 bool KeyStoreEntry::isAccessible() const
00714 {
00715 return d->accessible;
00716 }
00717
00718 KeyStoreEntry::Type KeyStoreEntry::type() const
00719 {
00720 return static_cast<const KeyStoreEntryContext *>(context())->type();
00721 }
00722
00723 QString KeyStoreEntry::name() const
00724 {
00725 return static_cast<const KeyStoreEntryContext *>(context())->name();
00726 }
00727
00728 QString KeyStoreEntry::id() const
00729 {
00730 return static_cast<const KeyStoreEntryContext *>(context())->id();
00731 }
00732
00733 QString KeyStoreEntry::storeName() const
00734 {
00735 return static_cast<const KeyStoreEntryContext *>(context())->storeName();
00736 }
00737
00738 QString KeyStoreEntry::storeId() const
00739 {
00740 return static_cast<const KeyStoreEntryContext *>(context())->storeId();
00741 }
00742
00743 QString KeyStoreEntry::toString() const
00744 {
00745 return static_cast<const KeyStoreEntryContext *>(context())->serialize();
00746 }
00747
00748 KeyStoreEntry KeyStoreEntry::fromString(const QString &serialized)
00749 {
00750 KeyStoreEntry e;
00751 KeyStoreEntryContext *c = (KeyStoreEntryContext *)KeyStoreTracker::instance()->entryPassive(serialized);
00752 if(c)
00753 e.change(c);
00754 return e;
00755 }
00756
00757 KeyBundle KeyStoreEntry::keyBundle() const
00758 {
00759 return static_cast<const KeyStoreEntryContext *>(context())->keyBundle();
00760 }
00761
00762 Certificate KeyStoreEntry::certificate() const
00763 {
00764 return static_cast<const KeyStoreEntryContext *>(context())->certificate();
00765 }
00766
00767 CRL KeyStoreEntry::crl() const
00768 {
00769 return static_cast<const KeyStoreEntryContext *>(context())->crl();
00770 }
00771
00772 PGPKey KeyStoreEntry::pgpSecretKey() const
00773 {
00774 return static_cast<const KeyStoreEntryContext *>(context())->pgpSecretKey();
00775 }
00776
00777 PGPKey KeyStoreEntry::pgpPublicKey() const
00778 {
00779 return static_cast<const KeyStoreEntryContext *>(context())->pgpPublicKey();
00780 }
00781
00782 bool KeyStoreEntry::ensureAvailable()
00783 {
00784 QString storeId = this->storeId();
00785 QString entryId = id();
00786 KeyStoreEntryContext *c = (KeyStoreEntryContext *)qVariantValue<void*>(trackercall("entry", QVariantList() << storeId << entryId));
00787 if(c)
00788 change(c);
00789 return isAvailable();
00790 }
00791
00792 bool KeyStoreEntry::ensureAccess()
00793 {
00794 if(!ensureAvailable())
00795 {
00796 d->accessible = false;
00797 return false;
00798 }
00799 bool ok = static_cast<KeyStoreEntryContext *>(context())->ensureAccess();
00800 d->accessible = ok;
00801 return d->accessible;
00802 }
00803
00804
00805
00806
00807 class KeyStoreEntryWatcher::Private : public QObject
00808 {
00809 Q_OBJECT
00810 public:
00811 KeyStoreEntryWatcher *q;
00812 KeyStoreManager ksm;
00813 KeyStoreEntry entry;
00814 QString storeId, entryId;
00815 KeyStore *ks;
00816 bool avail;
00817
00818 Private(KeyStoreEntryWatcher *_q) : QObject(_q), q(_q), ksm(this)
00819 {
00820 ks = 0;
00821 avail = false;
00822 connect(&ksm, SIGNAL(keyStoreAvailable(const QString &)), SLOT(ksm_available(const QString &)));
00823 }
00824
00825 ~Private()
00826 {
00827 delete ks;
00828 }
00829
00830 void start()
00831 {
00832 QStringList list = ksm.keyStores();
00833 foreach(const QString &storeId, list)
00834 ksm_available(storeId);
00835 }
00836
00837 private slots:
00838 void ksm_available(const QString &_storeId)
00839 {
00840
00841 if(_storeId == storeId)
00842 {
00843 ks = new KeyStore(storeId, &ksm);
00844 connect(ks, SIGNAL(updated()), SLOT(ks_updated()));
00845 ks->startAsynchronousMode();
00846 }
00847 }
00848
00849 void ks_updated()
00850 {
00851 bool found = false;
00852 QList<KeyStoreEntry> list = ks->entryList();
00853 foreach(const KeyStoreEntry &e, list)
00854 {
00855 if(e.id() == entryId && e.isAvailable())
00856 {
00857 found = true;
00858 if(!avail)
00859 entry = e;
00860 break;
00861 }
00862 }
00863
00864 if(found && !avail)
00865 {
00866 avail = true;
00867 emit q->available();
00868 }
00869 else if(!found && avail)
00870 {
00871 avail = false;
00872 emit q->unavailable();
00873 }
00874 }
00875
00876 void ks_unavailable()
00877 {
00878 delete ks;
00879 ks = 0;
00880
00881 if(avail)
00882 {
00883 avail = false;
00884 emit q->unavailable();
00885 }
00886 }
00887 };
00888
00889 KeyStoreEntryWatcher::KeyStoreEntryWatcher(const KeyStoreEntry &e, QObject *parent)
00890 :QObject(parent)
00891 {
00892 d = new Private(this);
00893 if(!e.isNull())
00894 {
00895 d->entry = e;
00896 d->storeId = e.storeId();
00897 d->entryId = e.id();
00898 d->start();
00899 }
00900 }
00901
00902 KeyStoreEntryWatcher::~KeyStoreEntryWatcher()
00903 {
00904 delete d;
00905 }
00906
00907 KeyStoreEntry KeyStoreEntryWatcher::entry() const
00908 {
00909 return d->entry;
00910 }
00911
00912
00913
00914
00915
00916 class KeyStoreWriteEntry
00917 {
00918 public:
00919 enum Type { TypeKeyBundle, TypeCertificate, TypeCRL, TypePGPKey };
00920
00921 Type type;
00922 KeyBundle keyBundle;
00923 Certificate cert;
00924 CRL crl;
00925 PGPKey pgpKey;
00926
00927 KeyStoreWriteEntry()
00928 {
00929 }
00930
00931 KeyStoreWriteEntry(const KeyBundle &_keyBundle)
00932 :type(TypeKeyBundle), keyBundle(_keyBundle)
00933 {
00934 }
00935
00936 KeyStoreWriteEntry(const Certificate &_cert)
00937 :type(TypeCertificate), cert(_cert)
00938 {
00939 }
00940
00941 KeyStoreWriteEntry(const CRL &_crl)
00942 :type(TypeCRL), crl(_crl)
00943 {
00944 }
00945
00946 KeyStoreWriteEntry(const PGPKey &_pgpKey)
00947 :type(TypePGPKey), pgpKey(_pgpKey)
00948 {
00949 }
00950 };
00951
00952 class KeyStoreOperation : public QThread
00953 {
00954 Q_OBJECT
00955 public:
00956 enum Type { EntryList, WriteEntry, RemoveEntry };
00957
00958 Type type;
00959 int trackerId;
00960
00961 KeyStoreWriteEntry wentry;
00962 QList<KeyStoreEntry> entryList;
00963 QString entryId;
00964 bool success;
00965
00966 KeyStoreOperation(QObject *parent = 0)
00967 :QThread(parent)
00968 {
00969 }
00970
00971 ~KeyStoreOperation()
00972 {
00973 wait();
00974 }
00975
00976 protected:
00977 virtual void run()
00978 {
00979 if(type == EntryList)
00980 entryList = qVariantValue< QList<KeyStoreEntry> >(trackercall("entryList", QVariantList() << trackerId));
00981 else if(type == WriteEntry)
00982 {
00983 QVariant arg;
00984 if(wentry.type == KeyStoreWriteEntry::TypeKeyBundle)
00985 qVariantSetValue<KeyBundle>(arg, wentry.keyBundle);
00986 else if(wentry.type == KeyStoreWriteEntry::TypeCertificate)
00987 qVariantSetValue<Certificate>(arg, wentry.cert);
00988 else if(wentry.type == KeyStoreWriteEntry::TypeCRL)
00989 qVariantSetValue<CRL>(arg, wentry.crl);
00990 else if(wentry.type == KeyStoreWriteEntry::TypePGPKey)
00991 qVariantSetValue<PGPKey>(arg, wentry.pgpKey);
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001 entryId = trackercall("writeEntry", QVariantList() << trackerId << arg).toString();
01002 }
01003 else
01004 {
01005 success = trackercall("removeEntry", QVariantList() << trackerId << entryId).toBool();
01006 }
01007 }
01008 };
01009
01010 class KeyStorePrivate : public QObject
01011 {
01012 Q_OBJECT
01013 public:
01014 KeyStore *q;
01015 KeyStoreManager *ksm;
01016 int trackerId;
01017 KeyStoreTracker::Item item;
01018 bool async;
01019 bool need_update;
01020 QList<KeyStoreEntry> latestEntryList;
01021 QList<KeyStoreOperation*> ops;
01022
01023 KeyStorePrivate(KeyStore *_q) : QObject(_q), q(_q), async(false)
01024 {
01025 }
01026
01027 ~KeyStorePrivate()
01028 {
01029 qDeleteAll(ops);
01030 }
01031
01032
01033 void reg();
01034 void unreg();
01035 KeyStoreTracker::Item *getItem(const QString &storeId);
01036 KeyStoreTracker::Item *getItem(int trackerId);
01037
01038 void invalidate()
01039 {
01040 trackerId = -1;
01041 unreg();
01042 }
01043
01044 bool have_entryList_op() const
01045 {
01046 foreach(KeyStoreOperation *op, ops)
01047 {
01048 if(op->type == KeyStoreOperation::EntryList)
01049 return true;
01050 }
01051 return false;
01052 }
01053
01054 void handle_updated()
01055 {
01056 if(async)
01057 {
01058 if(!have_entryList_op())
01059 async_entryList();
01060 else
01061 need_update = true;
01062 }
01063 else
01064 emit q->updated();
01065 }
01066
01067 void async_entryList()
01068 {
01069 KeyStoreOperation *op = new KeyStoreOperation(this);
01070
01071 connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
01072 op->type = KeyStoreOperation::EntryList;
01073 op->trackerId = trackerId;
01074 ops += op;
01075 op->start();
01076 }
01077
01078 void async_writeEntry(const KeyStoreWriteEntry &wentry)
01079 {
01080 KeyStoreOperation *op = new KeyStoreOperation(this);
01081
01082 connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
01083 op->type = KeyStoreOperation::WriteEntry;
01084 op->trackerId = trackerId;
01085 op->wentry = wentry;
01086 ops += op;
01087 op->start();
01088 }
01089
01090 void async_removeEntry(const QString &entryId)
01091 {
01092 KeyStoreOperation *op = new KeyStoreOperation(this);
01093
01094 connect(op, SIGNAL(finished()), SLOT(op_finished()), Qt::QueuedConnection);
01095 op->type = KeyStoreOperation::RemoveEntry;
01096 op->trackerId = trackerId;
01097 op->entryId = entryId;
01098 ops += op;
01099 op->start();
01100 }
01101
01102 private slots:
01103 void op_finished()
01104 {
01105 KeyStoreOperation *op = (KeyStoreOperation *)sender();
01106
01107 if(op->type == KeyStoreOperation::EntryList)
01108 {
01109 latestEntryList = op->entryList;
01110 ops.removeAll(op);
01111 delete op;
01112
01113 if(need_update)
01114 {
01115 need_update = false;
01116 async_entryList();
01117 }
01118
01119 emit q->updated();
01120 }
01121 else if(op->type == KeyStoreOperation::WriteEntry)
01122 {
01123 QString entryId = op->entryId;
01124 ops.removeAll(op);
01125 delete op;
01126
01127 emit q->entryWritten(entryId);
01128 }
01129 else
01130 {
01131 bool success = op->success;
01132 ops.removeAll(op);
01133 delete op;
01134
01135 emit q->entryRemoved(success);
01136 }
01137 }
01138 };
01139
01140 KeyStore::KeyStore(const QString &id, KeyStoreManager *keyStoreManager)
01141 :QObject(keyStoreManager)
01142 {
01143 d = new KeyStorePrivate(this);
01144 d->ksm = keyStoreManager;
01145
01146 KeyStoreTracker::Item *i = d->getItem(id);
01147 if(i)
01148 {
01149 d->trackerId = i->trackerId;
01150 d->item = *i;
01151 d->reg();
01152 }
01153 else
01154 d->trackerId = -1;
01155 }
01156
01157 KeyStore::~KeyStore()
01158 {
01159 if(d->trackerId != -1)
01160 d->unreg();
01161 delete d;
01162 }
01163
01164 bool KeyStore::isValid() const
01165 {
01166 return (d->getItem(d->trackerId) ? true : false);
01167 }
01168
01169 KeyStore::Type KeyStore::type() const
01170 {
01171 return d->item.type;
01172 }
01173
01174 QString KeyStore::name() const
01175 {
01176 return d->item.name;
01177 }
01178
01179 QString KeyStore::id() const
01180 {
01181 return d->item.storeId;
01182 }
01183
01184 bool KeyStore::isReadOnly() const
01185 {
01186 return d->item.isReadOnly;
01187 }
01188
01189 void KeyStore::startAsynchronousMode()
01190 {
01191 if(d->async)
01192 return;
01193
01194 d->async = true;
01195
01196
01197 d->need_update = false;
01198 d->async_entryList();
01199 }
01200
01201 QList<KeyStoreEntry> KeyStore::entryList() const
01202 {
01203 if(d->async)
01204 return d->latestEntryList;
01205
01206 if(d->trackerId == -1)
01207 return QList<KeyStoreEntry>();
01208 return qVariantValue< QList<KeyStoreEntry> >(trackercall("entryList", QVariantList() << d->trackerId));
01209 }
01210
01211 bool KeyStore::holdsTrustedCertificates() const
01212 {
01213 QList<KeyStoreEntry::Type> list;
01214 if(d->trackerId == -1)
01215 return false;
01216 list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
01217 if(list.contains(KeyStoreEntry::TypeCertificate) || list.contains(KeyStoreEntry::TypeCRL))
01218 return true;
01219 return false;
01220 }
01221
01222 bool KeyStore::holdsIdentities() const
01223 {
01224 QList<KeyStoreEntry::Type> list;
01225 if(d->trackerId == -1)
01226 return false;
01227 list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
01228 if(list.contains(KeyStoreEntry::TypeKeyBundle) || list.contains(KeyStoreEntry::TypePGPSecretKey))
01229 return true;
01230 return false;
01231 }
01232
01233 bool KeyStore::holdsPGPPublicKeys() const
01234 {
01235 QList<KeyStoreEntry::Type> list;
01236 if(d->trackerId == -1)
01237 return false;
01238 list = qVariantValue< QList<KeyStoreEntry::Type> >(trackercall("entryTypes", QVariantList() << d->trackerId));
01239 if(list.contains(KeyStoreEntry::TypePGPPublicKey))
01240 return true;
01241 return false;
01242 }
01243
01244 QString KeyStore::writeEntry(const KeyBundle &kb)
01245 {
01246 if(d->async)
01247 {
01248 d->async_writeEntry(KeyStoreWriteEntry(kb));
01249 return QString();
01250 }
01251 else
01252 {
01253 QVariant arg;
01254 qVariantSetValue<KeyBundle>(arg, kb);
01255 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
01256 }
01257 }
01258
01259 QString KeyStore::writeEntry(const Certificate &cert)
01260 {
01261 if(d->async)
01262 {
01263 d->async_writeEntry(KeyStoreWriteEntry(cert));
01264 return QString();
01265 }
01266 else
01267 {
01268 QVariant arg;
01269 qVariantSetValue<Certificate>(arg, cert);
01270 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
01271 }
01272 }
01273
01274 QString KeyStore::writeEntry(const CRL &crl)
01275 {
01276 if(d->async)
01277 {
01278 d->async_writeEntry(KeyStoreWriteEntry(crl));
01279 return QString();
01280 }
01281 else
01282 {
01283 QVariant arg;
01284 qVariantSetValue<CRL>(arg, crl);
01285 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
01286 }
01287 }
01288
01289 QString KeyStore::writeEntry(const PGPKey &key)
01290 {
01291 if(d->async)
01292 {
01293 d->async_writeEntry(KeyStoreWriteEntry(key));
01294 return QString();
01295 }
01296 else
01297 {
01298 QVariant arg;
01299 qVariantSetValue<PGPKey>(arg, key);
01300 return trackercall("writeEntry", QVariantList() << d->trackerId << arg).toString();
01301 }
01302 }
01303
01304 bool KeyStore::removeEntry(const QString &id)
01305 {
01306 if(d->async)
01307 {
01308 d->async_removeEntry(id);
01309 return false;
01310 }
01311 else
01312 {
01313 return trackercall("removeEntry", QVariantList() << d->trackerId << id).toBool();
01314 }
01315 }
01316
01317
01318
01319
01320 static void ensure_init()
01321 {
01322 QMutexLocker locker(ksm_mutex());
01323 if(!g_ksm)
01324 g_ksm = new KeyStoreManagerGlobal;
01325 }
01326
01327
01328 void KeyStoreManager::start()
01329 {
01330 ensure_init();
01331 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection);
01332 trackercall("spinEventLoop");
01333 }
01334
01335 void KeyStoreManager::start(const QString &provider)
01336 {
01337 ensure_init();
01338 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "start", Qt::QueuedConnection, Q_ARG(QString, provider));
01339 trackercall("spinEventLoop");
01340 }
01341
01342 QString KeyStoreManager::diagnosticText()
01343 {
01344 ensure_init();
01345
01346
01347
01348
01349 trackercall("spinEventLoop");
01350
01351 return KeyStoreTracker::instance()->getDText();
01352 }
01353
01354 void KeyStoreManager::clearDiagnosticText()
01355 {
01356 ensure_init();
01357 KeyStoreTracker::instance()->clearDText();
01358 }
01359
01360 void KeyStoreManager::scan()
01361 {
01362 ensure_init();
01363 QMetaObject::invokeMethod(KeyStoreTracker::instance(), "scan", Qt::QueuedConnection);
01364 }
01365
01366 void KeyStoreManager::shutdown()
01367 {
01368 QMutexLocker locker(ksm_mutex());
01369 delete g_ksm;
01370 g_ksm = 0;
01371 }
01372
01373
01374 class KeyStoreManagerPrivate : public QObject
01375 {
01376 Q_OBJECT
01377 public:
01378 KeyStoreManager *q;
01379
01380 QMutex m;
01381 QWaitCondition w;
01382 bool busy;
01383 QList<KeyStoreTracker::Item> items;
01384 bool pending, waiting;
01385
01386 QMultiHash<int,KeyStore*> keyStoreForTrackerId;
01387 QHash<KeyStore*,int> trackerIdForKeyStore;
01388
01389 KeyStoreManagerPrivate(KeyStoreManager *_q) : QObject(_q), q(_q)
01390 {
01391 pending = false;
01392 waiting = false;
01393 }
01394
01395 ~KeyStoreManagerPrivate()
01396 {
01397
01398 QList<KeyStore*> list;
01399 QHashIterator<KeyStore*,int> it(trackerIdForKeyStore);
01400 while(it.hasNext())
01401 {
01402 it.next();
01403 list += it.key();
01404 }
01405 foreach(KeyStore *ks, list)
01406 ks->d->invalidate();
01407 }
01408
01409
01410 void reg(KeyStore *ks, int trackerId)
01411 {
01412 keyStoreForTrackerId.insert(trackerId, ks);
01413 trackerIdForKeyStore.insert(ks, trackerId);
01414 }
01415
01416 void unreg(KeyStore *ks)
01417 {
01418 int trackerId = trackerIdForKeyStore.take(ks);
01419
01420
01421 QList<KeyStore*> vals = keyStoreForTrackerId.values(trackerId);
01422 keyStoreForTrackerId.remove(trackerId);
01423 vals.removeAll(ks);
01424 foreach(KeyStore *i, vals)
01425 keyStoreForTrackerId.insert(trackerId, i);
01426 }
01427
01428 KeyStoreTracker::Item *getItem(const QString &storeId)
01429 {
01430 for(int n = 0; n < items.count(); ++n)
01431 {
01432 KeyStoreTracker::Item *i = &items[n];
01433 if(i->storeId == storeId)
01434 return i;
01435 }
01436 return 0;
01437 }
01438
01439 KeyStoreTracker::Item *getItem(int trackerId)
01440 {
01441 for(int n = 0; n < items.count(); ++n)
01442 {
01443 KeyStoreTracker::Item *i = &items[n];
01444 if(i->trackerId == trackerId)
01445 return i;
01446 }
01447 return 0;
01448 }
01449
01450 void do_update()
01451 {
01452
01453
01454 QPointer<QObject> self(this);
01455
01456 bool newbusy = KeyStoreTracker::instance()->isBusy();
01457 QList<KeyStoreTracker::Item> newitems = KeyStoreTracker::instance()->getItems();
01458
01459 if(!busy && newbusy)
01460 {
01461 emit q->busyStarted();
01462 if(!self)
01463 return;
01464 }
01465 if(busy && !newbusy)
01466 {
01467 emit q->busyFinished();
01468 if(!self)
01469 return;
01470 }
01471
01472 QStringList here;
01473 QList<int> changed;
01474 QList<int> gone;
01475
01476
01477 for(int n = 0; n < items.count(); ++n)
01478 {
01479 KeyStoreTracker::Item &i = items[n];
01480 bool found = false;
01481 for(int k = 0; k < newitems.count(); ++k)
01482 {
01483 if(i.trackerId == newitems[k].trackerId)
01484 {
01485 found = true;
01486 break;
01487 }
01488 }
01489 if(!found)
01490 gone += i.trackerId;
01491 }
01492
01493
01494 for(int n = 0; n < items.count(); ++n)
01495 {
01496 KeyStoreTracker::Item &i = items[n];
01497 for(int k = 0; k < newitems.count(); ++k)
01498 {
01499 if(i.trackerId == newitems[k].trackerId)
01500 {
01501 if(i.updateCount < newitems[k].updateCount)
01502 changed += i.trackerId;
01503 break;
01504 }
01505 }
01506 }
01507
01508
01509 for(int n = 0; n < newitems.count(); ++n)
01510 {
01511 KeyStoreTracker::Item &i = newitems[n];
01512 bool found = false;
01513 for(int k = 0; k < items.count(); ++k)
01514 {
01515 if(i.trackerId == items[k].trackerId)
01516 {
01517 found = true;
01518 break;
01519 }
01520 }
01521 if(!found)
01522 here += i.storeId;
01523 }
01524
01525 busy = newbusy;
01526 items = newitems;
01527
01528
01529 foreach(int trackerId, gone)
01530 {
01531 KeyStore *ks = keyStoreForTrackerId.value(trackerId);
01532 if(ks)
01533 {
01534 ks->d->invalidate();
01535 emit ks->unavailable();
01536 if(!self)
01537 return;
01538 }
01539 }
01540
01541 foreach(int trackerId, changed)
01542 {
01543 KeyStore *ks = keyStoreForTrackerId.value(trackerId);
01544 if(ks)
01545 {
01546 ks->d->handle_updated();
01547 if(!self)
01548 return;
01549 }
01550 }
01551
01552 foreach(const QString &storeId, here)
01553 {
01554 emit q->keyStoreAvailable(storeId);
01555 if(!self)
01556 return;
01557 }
01558 }
01559
01560 public slots:
01561 void tracker_updated()
01562 {
01563 QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated start", q), Logger::Information);
01564
01565 QMutexLocker locker(&m);
01566 if(!pending)
01567 {
01568 QMetaObject::invokeMethod(this, "update", Qt::QueuedConnection);
01569 pending = true;
01570 }
01571 if(waiting && !KeyStoreTracker::instance()->isBusy())
01572 {
01573 busy = false;
01574 items = KeyStoreTracker::instance()->getItems();
01575 w.wakeOne();
01576 }
01577
01578 QCA_logTextMessage(QString().sprintf("keystore: %p: tracker_updated end", q), Logger::Information);
01579 }
01580
01581 void update()
01582 {
01583 m.lock();
01584 pending = false;
01585 m.unlock();
01586
01587 do_update();
01588 }
01589 };
01590
01591
01592 void KeyStorePrivate::reg()
01593 {
01594 ksm->d->reg(q, trackerId);
01595 }
01596
01597 void KeyStorePrivate::unreg()
01598 {
01599 ksm->d->unreg(q);
01600 }
01601
01602 KeyStoreTracker::Item *KeyStorePrivate::getItem(const QString &storeId)
01603 {
01604 return ksm->d->getItem(storeId);
01605 }
01606
01607 KeyStoreTracker::Item *KeyStorePrivate::getItem(int trackerId)
01608 {
01609 return ksm->d->getItem(trackerId);
01610 }
01611
01612 KeyStoreManager::KeyStoreManager(QObject *parent)
01613 :QObject(parent)
01614 {
01615 ensure_init();
01616 d = new KeyStoreManagerPrivate(this);
01617 KeyStoreTracker::instance()->addTarget(d);
01618 sync();
01619 }
01620
01621 KeyStoreManager::~KeyStoreManager()
01622 {
01623 Q_ASSERT(KeyStoreTracker::instance());
01624 KeyStoreTracker::instance()->removeTarget(d);
01625 delete d;
01626 }
01627
01628 bool KeyStoreManager::isBusy() const
01629 {
01630 return d->busy;
01631 }
01632
01633 void KeyStoreManager::waitForBusyFinished()
01634 {
01635 d->m.lock();
01636 d->busy = KeyStoreTracker::instance()->isBusy();
01637 if(d->busy)
01638 {
01639 d->waiting = true;
01640 d->w.wait(&d->m);
01641 d->waiting = false;
01642 }
01643 d->m.unlock();
01644 }
01645
01646 QStringList KeyStoreManager::keyStores() const
01647 {
01648 QStringList out;
01649 for(int n = 0; n < d->items.count(); ++n)
01650 out += d->items[n].storeId;
01651 return out;
01652 }
01653
01654 void KeyStoreManager::sync()
01655 {
01656 d->busy = KeyStoreTracker::instance()->isBusy();
01657 d->items = KeyStoreTracker::instance()->getItems();
01658 }
01659
01660
01661
01662
01663 class KeyStoreInfo::Private : public QSharedData
01664 {
01665 public:
01666 KeyStore::Type type;
01667 QString id, name;
01668 };
01669
01670 KeyStoreInfo::KeyStoreInfo()
01671 {
01672 }
01673
01674 KeyStoreInfo::KeyStoreInfo(KeyStore::Type type, const QString &id, const QString &name)
01675 :d(new Private)
01676 {
01677 d->type = type;
01678 d->id = id;
01679 d->name = name;
01680 }
01681
01682 KeyStoreInfo::KeyStoreInfo(const KeyStoreInfo &from)
01683 :d(from.d)
01684 {
01685 }
01686
01687 KeyStoreInfo::~KeyStoreInfo()
01688 {
01689 }
01690
01691 KeyStoreInfo & KeyStoreInfo::operator=(const KeyStoreInfo &from)
01692 {
01693 d = from.d;
01694 return *this;
01695 }
01696
01697 bool KeyStoreInfo::isNull() const
01698 {
01699 return (d ? false: true);
01700 }
01701
01702 KeyStore::Type KeyStoreInfo::type() const
01703 {
01704 return d->type;
01705 }
01706
01707 QString KeyStoreInfo::id() const
01708 {
01709 return d->id;
01710 }
01711
01712 QString KeyStoreInfo::name() const
01713 {
01714 return d->name;
01715 }
01716
01717 }
01718
01719 #include "qca_keystore.moc"