ssu
Loading...
Searching...
No Matches
ssu.cpp
Go to the documentation of this file.
1
8
9/*
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
14 *
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
22 *
23 */
24#include <QtNetwork>
25#include <QtXml/QDomDocument>
26#include <QDBusConnection>
27#include <QDBusMessage>
28#include <QDBusPendingReply>
29#include <QUrlQuery>
30
31#include <getdef.h>
32#include <pwd.h>
33#include <sys/types.h>
34#include <unistd.h>
35
36#include "ssu.h"
37#include "sandbox_p.h"
38#include "ssulog_p.h"
39#include "ssuvariables_p.h"
40#include "ssucoreconfig_p.h"
41#include "ssurepomanager.h"
42#include "ssudeviceinfo.h"
43
44#include "../constants.h"
45
46#define SSU_NETWORK_REQUEST_DOMAIN_DATA (static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1))
47
48static void restoreUid()
49{
50 if (getuid() == 0) {
51 seteuid(0);
52 setegid(0);
53 }
54}
55
56Ssu::Ssu()
57 : QObject()
58{
59 errorFlag = false;
60 pendingRequests = 0;
61
62#ifdef SSUCONFHACK
63 // dirty hack to make sure we can write to the configuration
64 // this is currently required since there's no global gconf,
65 // and we migth not yet have users on bootstrap
66 QFileInfo settingsInfo(SSU_CONFIGURATION);
67 if (settingsInfo.groupId() != SSU_GROUP_ID ||
68 !settingsInfo.permission(QFile::WriteGroup)) {
69 QProcess proc;
70 proc.start("/usr/bin/ssuconfperm");
71 proc.waitForFinished();
72 }
73#endif
74
75 SsuCoreConfig *settings = SsuCoreConfig::instance();
76
77#ifdef TARGET_ARCH
78 if (!settings->contains("arch"))
79 settings->setValue("arch", TARGET_ARCH);
80#else
81// FIXME, try to guess a matching architecture
82#warning "TARGET_ARCH not defined"
83#endif
84 settings->sync();
85
86
87
88 manager = new QNetworkAccessManager(this);
89 connect(manager, SIGNAL(finished(QNetworkReply *)),
90 SLOT(requestFinished(QNetworkReply *)));
91}
92
93// FIXME, the whole credentials stuff needs reworking
94// should probably be part of repo handling instead of core configuration
95QPair<QString, QString> Ssu::credentials(const QString &scope)
96{
97 SsuCoreConfig *settings = SsuCoreConfig::instance();
98 return settings->credentials(scope);
99}
100
101QString Ssu::credentialsScope(const QString &repoName, bool rndRepo)
102{
103 SsuCoreConfig *settings = SsuCoreConfig::instance();
105
106 // hardcoded magic for doing special privileges store repositories
107 if (repoName == "store" || repoName.startsWith("store-c-"))
108 return "store";
109
110 // check if some repos are marked for using store-credentials
111 // in current domain, checking first for rnd/release specific
112 // settings, and if not found in generic settings
113 QString storeAuthReposKey = QString("store-auth-repos-%1")
114 .arg(rndRepo ? "rnd" : "release");
115 QStringList storeAuthRepos =
116 SsuVariables::variable(&repoSettings,
117 domain() + "-domain",
118 storeAuthReposKey).toStringList();
119
120 if (storeAuthRepos.empty())
121 storeAuthRepos =
122 SsuVariables::variable(&repoSettings,
123 domain() + "-domain",
124 "store-auth-repos").toStringList();
125
126 if (storeAuthRepos.contains(repoName))
127 return "store";
128
129 // If we defined explicitly what credentials to use with which secure domain
130 // use those.
131 QHash<QString, QString> secureDomainAuth;
132 SsuVariables::variableSection(&repoSettings, "secure-domain-auth", &secureDomainAuth);
133 QHashIterator<QString, QString> i(secureDomainAuth);
134 while (i.hasNext()) {
135 i.next();
136 if (repoUrl(repoName, rndRepo).contains(i.key()) && !i.value().isEmpty()) {
137 return i.value();
138 }
139 }
140
141 return settings->credentialsScope(repoName, rndRepo);
142}
143
144QString Ssu::credentialsUrl(const QString &scope)
145{
146 SsuCoreConfig *settings = SsuCoreConfig::instance();
147 return settings->credentialsUrl(scope);
148}
149
151{
152 return errorFlag;
153}
154
155// Wrappers around SsuCoreConfig
157{
158 SsuCoreConfig *settings = SsuCoreConfig::instance();
159 return settings->flavour();
160}
161
162Ssu::DeviceModeFlags Ssu::deviceMode()
163{
164 SsuCoreConfig *settings = SsuCoreConfig::instance();
165 return settings->deviceMode();
166}
167
168QString Ssu::domain()
169{
170 SsuCoreConfig *settings = SsuCoreConfig::instance();
171 return settings->domain(true);
172}
173
174QString Ssu::brand() {
175 SsuCoreConfig *settings = SsuCoreConfig::instance();
176 return settings->brand();
177}
178
180{
181 SsuCoreConfig *settings = SsuCoreConfig::instance();
182 return settings->isRegistered();
183}
184
186{
187 SsuCoreConfig *settings = SsuCoreConfig::instance();
188 return settings->lastCredentialsUpdate();
189}
190
191QString Ssu::release(bool rnd)
192{
193 SsuCoreConfig *settings = SsuCoreConfig::instance();
194 return settings->release(rnd);
195}
196
197void Ssu::setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode)
198{
199 SsuCoreConfig *settings = SsuCoreConfig::instance();
200 settings->setDeviceMode(mode, editMode);
201}
202
203void Ssu::setFlavour(const QString &flavour)
204{
205 SsuCoreConfig *settings = SsuCoreConfig::instance();
206 settings->setFlavour(flavour);
207}
208
209void Ssu::setRelease(const QString &release, bool rnd)
210{
211 SsuCoreConfig *settings = SsuCoreConfig::instance();
212 settings->setRelease(release, rnd);
213}
214
215void Ssu::setDomain(const QString &domain)
216{
217 SsuCoreConfig *settings = SsuCoreConfig::instance();
218 settings->setDomain(domain);
219}
220
222{
223 SsuCoreConfig *settings = SsuCoreConfig::instance();
224 return settings->useSslVerify();
225}
226
227//...
228
229
230
232{
233 return errorString;
234}
235
236bool Ssu::registerDevice(QDomDocument *response)
237{
238 QString certificateString = response->elementsByTagName("certificate").at(0).toElement().text();
239 QSslCertificate certificate(certificateString.toLatin1());
240 SsuLog *ssuLog = SsuLog::instance();
241 SsuCoreConfig *settings = SsuCoreConfig::instance();
242
243 if (certificate.isNull()) {
244 // make sure device is in unregistered state on failed registration
245 settings->setValue("registered", false);
246 setError("Certificate is invalid");
247 return false;
248 } else {
249 settings->setValue("certificate", certificate.toPem());
250 }
251
252 QString privateKeyString = response->elementsByTagName("privateKey").at(0).toElement().text();
253 QSslKey privateKey(privateKeyString.toLatin1(), QSsl::Rsa);
254
255 if (privateKey.isNull()) {
256 settings->setValue("registered", false);
257 setError("Private key is invalid");
258 return false;
259 } else {
260 settings->setValue("privateKey", privateKey.toPem());
261 }
262
263 // oldUser is just for reference purposes, in case we want to notify
264 // about owner changes for the device
265 QString oldUser = response->elementsByTagName("user").at(0).toElement().text();
266 ssuLog->print(LOG_DEBUG, QString("Old user for your device was: %1").arg(oldUser));
267
268 // if we came that far everything required for device registration is done
269 settings->setValue("registered", true);
270 settings->sync();
271
272 if (!settings->isWritable()) {
273 setError("Configuration is not writable, device registration failed.");
274 return false;
275 }
276
278 return true;
279}
280
281QStringList Ssu::listDomains() {
282 SsuSettings repoSettings(SSU_REPO_CONFIGURATION, SSU_REPO_CONFIGURATION_DIR);
283 QRegExp domainFilter("-domain$");
284 return repoSettings.childGroups().filter(domainFilter).replaceInStrings(domainFilter, "");
285}
286
287void Ssu::setDomainConfig(const QString &domain, QVariantMap config) {
288 SsuSettings repoSettings(SSU_REPO_CONFIGURATION, SSU_REPO_CONFIGURATION_DIR);
289 repoSettings.beginGroup(domain + "-domain");
290 repoSettings.remove("");
291
292 for (QVariantMap::iterator i = config.begin(); i != config.end(); i++) {
293 repoSettings.setValue(i.key(), i.value());
294 }
295 repoSettings.endGroup();
296 repoSettings.sync();
297}
298
299QVariantMap Ssu::getDomainConfig(const QString &domain) {
300 SsuSettings repoSettings(SSU_REPO_CONFIGURATION, SSU_REPO_CONFIGURATION_DIR);
301 QVariantMap config;
302 repoSettings.beginGroup(domain + "-domain");
303 foreach(QString key, repoSettings.allKeys()) {
304 config.insert(key, repoSettings.value(key).toString());
305 }
306 repoSettings.endGroup();
307 return config;
308}
309
310// RND repos have flavour (devel, testing, release), and release (latest, next)
311// Release repos only have release (latest, next, version number)
312QString Ssu::repoUrl(const QString &repoName, bool rndRepo,
313 QHash<QString, QString> repoParameters,
314 QHash<QString, QString> parametersOverride)
315{
316 SsuRepoManager manager;
317 return manager.url(repoName, rndRepo, repoParameters, parametersOverride);
318}
319
320void Ssu::requestFinished(QNetworkReply *reply)
321{
322 QSslConfiguration sslConfiguration = reply->sslConfiguration();
323 SsuLog *ssuLog = SsuLog::instance();
324 SsuCoreConfig *settings = SsuCoreConfig::instance();
325 QNetworkRequest request = reply->request();
326 QVariant originalDomainVariant = request.attribute(SSU_NETWORK_REQUEST_DOMAIN_DATA);
327
328 ssuLog->print(LOG_DEBUG, QString("Certificate used was issued for '%1' by '%2'. Complete chain:")
329 .arg(sslConfiguration.peerCertificate().subjectInfo(QSslCertificate::CommonName).join(""))
330 .arg(sslConfiguration.peerCertificate().issuerInfo(QSslCertificate::CommonName).join("")));
331
332 foreach (const QSslCertificate cert, sslConfiguration.peerCertificateChain()) {
333 ssuLog->print(LOG_DEBUG, QString("-> %1").arg(cert.subjectInfo(QSslCertificate::CommonName).join("")));
334 }
335
336 pendingRequests--;
337
338 QString action;
339 QByteArray data;
340 QDomDocument doc;
341 QString xmlError;
342
344 if (settings->contains("home-url")) {
345 QString homeUrl = settings->value("home-url").toString().arg(QString());
346 homeUrl.remove(QRegExp("//+$"));
347
348 if (request.url().toString().startsWith(homeUrl, Qt::CaseInsensitive)) {
349 // we don't care about errors on download request
350 if (reply->error() == 0) {
351 QByteArray data = reply->readAll();
352 storeAuthorizedKeys(data);
353 }
354
355 goto success;
356 }
357 }
358
359 if (reply->error() > 0) {
360 setError(reply->errorString());
361 goto failure;
362 }
363
364 data = reply->readAll();
365 ssuLog->print(LOG_DEBUG, QString("RequestOutput %1")
366 .arg(data.data()));
367
368 if (!doc.setContent(data, &xmlError)) {
369 setError(tr("Unable to parse server response (%1)").arg(xmlError));
370 goto failure;
371 }
372
373 action = doc.elementsByTagName("action").at(0).toElement().text();
374
375 if (!verifyResponse(&doc)) {
376 goto failure;
377 }
378
379 ssuLog->print(LOG_DEBUG, QString("Handling request of type %1")
380 .arg(action));
381 if (action == "register") {
382 if (registerDevice(&doc)) {
383 goto success;
384 }
385 } else if (action == "credentials") {
386 if (setCredentials(&doc)) {
387 goto success;
388 }
389 } else {
390 setError(tr("Response to unknown action encountered: %1").arg(action));
391 }
392
393failure:
394 // Restore the original domain in case of failures with the registration
395 if (!originalDomainVariant.isNull()) {
396 QString originalDomain = originalDomainVariant.toString();
397 ssuLog->print(LOG_DEBUG, QString("Restoring domain on error: '%1'").arg(originalDomain));
398 setDomain(originalDomain);
399 }
400
401 // Fall through to cleanup handling in success from failure label
402success:
403 ssuLog->print(LOG_DEBUG, QString("Request finished, pending requests: %1").arg(pendingRequests));
404 if (pendingRequests == 0) {
405 emit done();
406 }
407}
408
409void Ssu::sendRegistration(const QString &usernameDomain, const QString &password)
410{
411 errorFlag = false;
412
413 QString ssuRegisterUrl;
414 QString username, domainName;
415
416 SsuLog *ssuLog = SsuLog::instance();
417 SsuCoreConfig *settings = SsuCoreConfig::instance();
418 SsuDeviceInfo deviceInfo;
419
420 QNetworkRequest request;
421 request.setAttribute(SSU_NETWORK_REQUEST_DOMAIN_DATA, domain());
422 ssuLog->print(LOG_DEBUG, QString("Saving current domain before request: '%1'").arg(domain()));
423
424 // Username can include also domain, (user@domain), separate those
425 if (usernameDomain.contains('@')) {
426 // separate domain/username and set domain
427 username = usernameDomain.section('@', 0, 0);
428 domainName = usernameDomain.section('@', 1, 1);
429 setDomain(domainName);
430 } else {
431 // No domain defined
432 username = usernameDomain;
433 if (settings->contains("default-rnd-domain"))
434 setDomain(settings->value("default-rnd-domain").toString());
435 }
436
437 if (!settings->contains("register-url")) {
438 ssuRegisterUrl = repoUrl("register-url");
439 if (ssuRegisterUrl.isEmpty()) {
440 setError("URL for ssu registration not set (config key 'register-url')");
441 return;
442 }
443 } else {
444 ssuRegisterUrl = settings->value("register-url").toString();
445 }
446
447 QString IMEI = deviceInfo.deviceUid();
448 if (IMEI.isEmpty()) {
449 setError("No valid UID available for your device. For phones: is your modem online?");
450 return;
451 }
452
453 QSslConfiguration sslConfiguration;
454 if (!useSslVerify())
455 sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
456
457 QString ssuCaCertificate = SsuRepoManager::caCertificatePath();
458 if (!ssuCaCertificate.isEmpty()) {
459 sslConfiguration.setCaCertificates(QSslCertificate::fromPath(ssuCaCertificate));
460 }
461
462 request.setUrl(QUrl(QString(ssuRegisterUrl)
463 .arg(IMEI)
464 ));
465 request.setSslConfiguration(sslConfiguration);
466 request.setRawHeader("Authorization", "Basic " +
467 QByteArray(QString("%1:%2")
468 .arg(username).arg(password)
469 .toLatin1()).toBase64());
470 request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
471
472 QUrl form;
473
474 QUrlQuery q;
475 q.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
476 q.addQueryItem("deviceModel", deviceInfo.deviceModel());
477 if (!domain().isEmpty()) {
478 q.addQueryItem("domain", domain());
479 }
480
481 form.setQuery(q);
482
483 ssuLog->print(LOG_DEBUG, QString("Sending request to %1")
484 .arg(request.url().url()));
485
486 pendingRequests++;
487 manager->post(request, form.query(QUrl::FullyEncoded).toStdString().c_str());
488 // we could expose downloadProgress() from reply in case we want progress info
489
490 QString homeUrl = settings->value("home-url").toString();
491 if (!homeUrl.isEmpty()) {
492 // clear header, the other request bits are reusable
493 request.setHeader(QNetworkRequest::ContentTypeHeader, 0);
494 request.setUrl(homeUrl.arg(username) + "/authorized_keys");
495 ssuLog->print(LOG_DEBUG, QString("Trying to get SSH keys from %1").arg(request.url().toString()));
496 pendingRequests++;
497 manager->get(request);
498 }
499}
500
501bool Ssu::setCredentials(QDomDocument *response)
502{
503 SsuCoreConfig *settings = SsuCoreConfig::instance();
504 // generate list with all scopes for generic section, add sections
505 QDomNodeList credentialsList = response->elementsByTagName("credentials");
506 QStringList credentialScopes;
507 for (int i = 0; i < credentialsList.size(); i++) {
508 QDomNode node = credentialsList.at(i);
509 QString scope;
510
511 QDomNamedNodeMap attributes = node.attributes();
512 if (attributes.contains("scope")) {
513 scope = attributes.namedItem("scope").toAttr().value();
514 } else {
515 setError(tr("Credentials element does not have scope"));
516 return false;
517 }
518
519 if (node.hasChildNodes()) {
520 QDomElement username = node.firstChildElement("username");
521 QDomElement password = node.firstChildElement("password");
522 if (username.isNull() || password.isNull()) {
523 setError(tr("Username and/or password not set"));
524 return false;
525 } else {
526 settings->beginGroup("credentials-" + scope);
527 settings->setValue("username", username.text());
528 settings->setValue("password", password.text());
529 settings->endGroup();
530 settings->sync();
531 credentialScopes.append(scope);
532 }
533 } else {
534 setError(QString());
535 return false;
536 }
537 }
538 settings->setValue("credentialScopes", credentialScopes);
539 settings->setValue("lastCredentialsUpdate", QDateTime::currentDateTime());
540 settings->sync();
541 emit credentialsChanged();
542
543 return true;
544}
545
546void Ssu::setError(const QString &errorMessage)
547{
548 errorFlag = true;
549 errorString = errorMessage;
550
551 SsuLog *ssuLog = SsuLog::instance();
552
553 // dump error message to systemd journal for easier debugging
554 ssuLog->print(LOG_WARNING, errorMessage);
555
556 // assume that we don't even need to wait for other pending requests,
557 // and just die. This is only relevant for CLI, which will exit after done()
558 emit done();
559}
560
561void Ssu::storeAuthorizedKeys(const QByteArray &data)
562{
563 QDir dir;
564 SsuLog *ssuLog = SsuLog::instance();
565
566 int uid_min = getdef_num("UID_MIN", -1);
567 QString homePath;
568
569 if (getuid() >= static_cast<uid_t>(uid_min)) {
570 homePath = dir.homePath();
571 } else if (getuid() == 0) {
572 // place authorized_keys in the default users home when run with uid0
573 struct passwd *pw = getpwuid(uid_min);
574 if (pw == NULL) {
575 ssuLog->print(LOG_DEBUG, QString("Unable to find password entry for uid %1")
576 .arg(uid_min));
577 return;
578 }
579
580 //homePath = QString(pw->pw_dir);
581 homePath = pw->pw_dir;
582
583 // use users uid/gid for creating the directories and files
584 setegid(pw->pw_gid);
585 seteuid(uid_min);
586 ssuLog->print(LOG_DEBUG, QString("Dropping to %1/%2 for writing authorized keys")
587 .arg(uid_min)
588 .arg(pw->pw_gid));
589 } else {
590 return;
591 }
592
593 homePath = Sandbox::map(homePath);
594
595 if (dir.exists(homePath + "/.ssh/authorized_keys")) {
596 ssuLog->print(LOG_DEBUG, QString(".ssh/authorized_keys already exists in %1")
597 .arg(homePath));
598 restoreUid();
599 return;
600 }
601
602 if (!dir.exists(homePath + "/.ssh")) {
603 if (!dir.mkdir(homePath + "/.ssh")) {
604 ssuLog->print(LOG_DEBUG, QString("Unable to create .ssh in %1")
605 .arg(homePath));
606 restoreUid();
607 return;
608 }
609 }
610
611 QFile::setPermissions(homePath + "/.ssh",
612 QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
613
614 QFile authorizedKeys(homePath + "/.ssh/authorized_keys");
615 authorizedKeys.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
616 authorizedKeys.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
617 QTextStream out(&authorizedKeys);
618 out << data;
619 out.flush();
620 authorizedKeys.close();
621
622 restoreUid();
623}
624
626{
627 SsuCoreConfig *settings = SsuCoreConfig::instance();
628 SsuDeviceInfo deviceInfo;
629 errorFlag = false;
630
631 SsuLog *ssuLog = SsuLog::instance();
632
633 if (deviceInfo.deviceUid().isEmpty()) {
634 setError("No valid UID available for your device. For phones: is your modem online?");
635 return;
636 }
637
638 QString ssuCaCertificate, ssuCredentialsUrl;
639 ssuCaCertificate = SsuRepoManager::caCertificatePath();
640
641 if (!settings->contains("credentials-url")) {
642 ssuCredentialsUrl = repoUrl("credentials-url");
643 if (ssuCredentialsUrl.isEmpty()) {
644 setError("URL for credentials update not set (config key 'credentials-url')");
645 return;
646 }
647 } else {
648 ssuCredentialsUrl = settings->value("credentials-url").toString();
649 }
650
651 if (!isRegistered()) {
652 setError("Device is not registered.");
653 return;
654 }
655
656 if (!force) {
657 // skip updating if the last update was less than 30 minutes ago
658 QDateTime now = QDateTime::currentDateTime();
659
660 if (settings->contains("lastCredentialsUpdate")) {
661 QDateTime last = settings->value("lastCredentialsUpdate").toDateTime();
662 if (last >= now.addSecs(-1800)) {
663 ssuLog->print(LOG_DEBUG, QString("Skipping credentials update, last update was at %1")
664 .arg(last.toString()));
665 emit done();
666 return;
667 }
668 }
669 }
670
671 // check when the last update was, decide if an update is required
672 QSslConfiguration sslConfiguration;
673 if (!useSslVerify())
674 sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
675
676 QSslKey privateKey(settings->value("privateKey").toByteArray(), QSsl::Rsa);
677 QSslCertificate certificate(settings->value("certificate").toByteArray());
678
679 QList<QSslCertificate> caCertificates;
680 if (ssuCaCertificate.isEmpty()) {
681 // When the localCertificate (i.e. client certificate) is used, the
682 // system CA certificates are not loaded automatically, like they
683 // normally are when CA certificates are not set in the configuration.
684 // So we add them here explicitly. This is possibly a bug in Qt or it's
685 // internaction with OpenSSL, something similar to what is described in
686 // https://bugreports.qt.io/browse/QTBUG-7200
687 caCertificates << sslConfiguration.systemCaCertificates();
688 } else {
689 caCertificates << QSslCertificate::fromPath(ssuCaCertificate);
690 }
691 sslConfiguration.setCaCertificates(caCertificates);
692
693 sslConfiguration.setPrivateKey(privateKey);
694 sslConfiguration.setLocalCertificate(certificate);
695
696 QNetworkRequest request;
697 request.setUrl(QUrl(ssuCredentialsUrl.arg(deviceInfo.deviceUid())));
698
699 ssuLog->print(LOG_DEBUG, QString("Sending credential update request to %1")
700 .arg(request.url().toString()));
701 request.setSslConfiguration(sslConfiguration);
702
703 pendingRequests++;
704 manager->get(request);
705}
706
708{
709 SsuCoreConfig *settings = SsuCoreConfig::instance();
710 SsuLog *ssuLog = SsuLog::instance();
711
712 QDBusMessage message = QDBusMessage::createMethodCall("com.jolla.jollastore",
713 "/StoreClient",
714 "com.jolla.jollastore",
715 "storeCredentials");
716 QDBusPendingReply<QString, QString> reply = SsuCoreConfig::userSessionBus().asyncCall(message);
717 reply.waitForFinished();
718 if (reply.isError()) {
719 if (settings->value("ignore-credential-errors").toBool() == true) {
720 ssuLog->print(LOG_WARNING, QString("Warning: ignore-credential-errors is set, passing auth errors down to libzypp"));
721 ssuLog->print(LOG_WARNING, QString("Store credentials not received. %1").arg(reply.error().message()));
722 } else {
723 setError(QString("Store credentials not received. %1").arg(reply.error().message()));
724 }
725 } else {
726 SsuCoreConfig *settings = SsuCoreConfig::instance();
727 settings->beginGroup("credentials-store");
728 settings->setValue("username", reply.argumentAt<0>());
729 settings->setValue("password", reply.argumentAt<1>());
730 settings->endGroup();
731 settings->sync();
732 }
733}
734
736{
737 SsuCoreConfig *settings = SsuCoreConfig::instance();
738 settings->setValue("privateKey", "");
739 settings->setValue("certificate", "");
740 settings->setValue("registered", false);
741 settings->sync();
743}
744
745bool Ssu::verifyResponse(QDomDocument *response)
746{
747 QString action = response->elementsByTagName("action").at(0).toElement().text();
748 QString deviceId = response->elementsByTagName("deviceId").at(0).toElement().text();
749 QString protocolVersion = response->elementsByTagName("protocolVersion").at(0).toElement().text();
750 // compare device ids
751
752 if (protocolVersion != SSU_PROTOCOL_VERSION) {
753 setError(
754 tr("Response has unsupported protocol version %1, client requires version %2")
755 .arg(protocolVersion)
757 );
758 return false;
759 }
760
761 return true;
762}
Q_INVOKABLE QString domain(bool pretty=false)
QString credentialsScope(const QString &repoName, bool rndRepo=false)
Q_INVOKABLE void setFlavour(const QString &flavour)
Q_INVOKABLE bool useSslVerify()
Q_INVOKABLE QDateTime lastCredentialsUpdate()
Q_INVOKABLE Ssu::DeviceModeFlags deviceMode()
Q_INVOKABLE void setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode=Ssu::Replace)
Q_INVOKABLE bool isRegistered()
Q_INVOKABLE void setDomain(const QString &domain)
QString credentialsUrl(const QString &scope)
static QDBusConnection userSessionBus()
Q_INVOKABLE QString release(bool rnd=false)
Q_INVOKABLE QString brand()
Q_INVOKABLE void setRelease(const QString &release, bool rnd=false)
Q_INVOKABLE QString flavour()
QPair< QString, QString > credentials(const QString &scope)
Q_INVOKABLE QString deviceUid()
Q_INVOKABLE QString deviceModel()
void print(int priority, const QString &message)
Definition ssulog.cpp:27
QString url(const QString &repoName, bool rndRepo=false, QHash< QString, QString > repoParameters=QHash< QString, QString >(), QHash< QString, QString > parametersOverride=QHash< QString, QString >())
static QString caCertificatePath(const QString &domain=QString())
QVariant variable(const QString &section, const QString &key)
void variableSection(const QString &section, QHash< QString, QString > *storageHash)
Q_INVOKABLE QDateTime lastCredentialsUpdate()
See SsuCoreConfig::lastCredentialsUpdate.
Definition ssu.cpp:185
QString repoUrl(const QString &repoName, bool rndRepo=false, QHash< QString, QString > repoParameters=QHash< QString, QString >(), QHash< QString, QString > parametersOverride=QHash< QString, QString >())
Definition ssu.cpp:312
void sendRegistration(const QString &username, const QString &password)
Definition ssu.cpp:409
void registrationStatusChanged()
EditMode
Definition ssu.h:91
Q_INVOKABLE QString flavour()
See SsuCoreConfig::flavour.
Definition ssu.cpp:156
Q_INVOKABLE void setRelease(const QString &release, bool rnd=false)
See SsuCoreConfig::setRelease.
Definition ssu.cpp:209
QPair< QString, QString > credentials(const QString &scope)
Definition ssu.cpp:95
void done()
Q_INVOKABLE QString domain()
See SsuCoreConfig::domain; returns printable version.
QString credentialsUrl(const QString &scope)
Definition ssu.cpp:144
void updateStoreCredentials()
Definition ssu.cpp:707
Q_INVOKABLE bool useSslVerify()
See SsuCoreConfig::useSslVerify.
Definition ssu.cpp:221
Q_INVOKABLE QString release(bool rnd=false)
See SsuCoreConfig::release.
Definition ssu.cpp:191
Q_INVOKABLE bool error()
Definition ssu.cpp:150
Q_INVOKABLE bool isRegistered()
See SsuCoreConfig::isRegistered.
Definition ssu.cpp:179
QString credentialsScope(const QString &repoName, bool rndRepo=false)
Definition ssu.cpp:101
Q_INVOKABLE void unregister()
Definition ssu.cpp:735
Q_INVOKABLE void setFlavour(const QString &flavour)
See SsuCoreConfig::setFlavour.
Definition ssu.cpp:203
void updateCredentials(bool force=false)
Definition ssu.cpp:625
Q_INVOKABLE void setDomain(const QString &domain)
See SsuCoreConfig::setDomain.
Definition ssu.cpp:215
Q_INVOKABLE void setDeviceMode(DeviceModeFlags mode, enum EditMode editMode=Replace)
See SsuCoreConfig::setDeviceMode.
Definition ssu.cpp:197
Q_INVOKABLE QString brand()
See SsuCoreConfig::brand.
Definition ssu.cpp:174
Q_INVOKABLE QString lastError()
Definition ssu.cpp:231
Q_INVOKABLE DeviceModeFlags deviceMode()
See SsuCoreConfig::deviceMode.
#define SSU_REPO_CONFIGURATION_DIR
Path to config.d for ssu domain configurations.
Definition constants.h:16
#define SSU_GROUP_ID
The group ID ssu expects to run as. This is usually the GID of the main phone user.
Definition constants.h:12
#define SSU_PROTOCOL_VERSION
The ssu protocol version used by the ssu client libraries.
Definition constants.h:24
#define SSU_REPO_CONFIGURATION
Path to the ssu domain configuration file.
Definition constants.h:14
#define SSU_CONFIGURATION
Path to the main ssu configuration file.