ssu
ssu.cpp
Go to the documentation of this file.
1 
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 
48 static void restoreUid()
49 {
50  if (getuid() == 0) {
51  seteuid(0);
52  setegid(0);
53  }
54 }
55 
56 Ssu::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
95 QPair<QString, QString> Ssu::credentials(const QString &scope)
96 {
97  SsuCoreConfig *settings = SsuCoreConfig::instance();
98  return settings->credentials(scope);
99 }
100 
101 QString 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 
144 QString 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
156 QString Ssu::flavour()
157 {
158  SsuCoreConfig *settings = SsuCoreConfig::instance();
159  return settings->flavour();
160 }
161 
162 Ssu::DeviceModeFlags Ssu::deviceMode()
163 {
164  SsuCoreConfig *settings = SsuCoreConfig::instance();
165  return settings->deviceMode();
166 }
167 
168 QString Ssu::domain()
169 {
170  SsuCoreConfig *settings = SsuCoreConfig::instance();
171  return settings->domain(true);
172 }
173 
174 QString 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 
191 QString Ssu::release(bool rnd)
192 {
193  SsuCoreConfig *settings = SsuCoreConfig::instance();
194  return settings->release(rnd);
195 }
196 
197 void Ssu::setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode)
198 {
199  SsuCoreConfig *settings = SsuCoreConfig::instance();
200  settings->setDeviceMode(mode, editMode);
201 }
202 
203 void Ssu::setFlavour(const QString &flavour)
204 {
205  SsuCoreConfig *settings = SsuCoreConfig::instance();
206  settings->setFlavour(flavour);
207 }
208 
209 void Ssu::setRelease(const QString &release, bool rnd)
210 {
211  SsuCoreConfig *settings = SsuCoreConfig::instance();
212  settings->setRelease(release, rnd);
213 }
214 
215 void 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 
231 QString Ssu::lastError()
232 {
233  return errorString;
234 }
235 
236 bool 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 
281 QStringList Ssu::listDomains() {
283  QRegExp domainFilter("-domain$");
284  return repoSettings.childGroups().filter(domainFilter).replaceInStrings(domainFilter, "");
285 }
286 
287 void Ssu::setDomainConfig(const QString &domain, QVariantMap config) {
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 
299 QVariantMap Ssu::getDomainConfig(const QString &domain) {
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)
312 QString 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 
320 void 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 
393 failure:
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
402 success:
403  ssuLog->print(LOG_DEBUG, QString("Request finished, pending requests: %1").arg(pendingRequests));
404  if (pendingRequests == 0) {
405  emit done();
406  }
407 }
408 
409 void 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  QString ssuCaCertificate = SsuRepoManager::caCertificatePath();
438  if (ssuCaCertificate.isEmpty()) {
439  setError("CA certificate for ssu not set ('_ca-certificate in domain')");
440  return;
441  }
442 
443  if (!settings->contains("register-url")) {
444  ssuRegisterUrl = repoUrl("register-url");
445  if (ssuRegisterUrl.isEmpty()) {
446  setError("URL for ssu registration not set (config key 'register-url')");
447  return;
448  }
449  } else {
450  ssuRegisterUrl = settings->value("register-url").toString();
451  }
452 
453  QString IMEI = deviceInfo.deviceUid();
454  if (IMEI.isEmpty()) {
455  setError("No valid UID available for your device. For phones: is your modem online?");
456  return;
457  }
458 
459  QSslConfiguration sslConfiguration;
460  if (!useSslVerify())
461  sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
462 
463  sslConfiguration.setCaCertificates(QSslCertificate::fromPath(ssuCaCertificate));
464 
465  request.setUrl(QUrl(QString(ssuRegisterUrl)
466  .arg(IMEI)
467  ));
468  request.setSslConfiguration(sslConfiguration);
469  request.setRawHeader("Authorization", "Basic " +
470  QByteArray(QString("%1:%2")
471  .arg(username).arg(password)
472  .toLatin1()).toBase64());
473  request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
474 
475  QUrl form;
476 
477  QUrlQuery q;
478  q.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
479  q.addQueryItem("deviceModel", deviceInfo.deviceModel());
480  if (!domain().isEmpty()) {
481  q.addQueryItem("domain", domain());
482  }
483 
484  form.setQuery(q);
485 
486  ssuLog->print(LOG_DEBUG, QString("Sending request to %1")
487  .arg(request.url().url()));
488 
489  pendingRequests++;
490  manager->post(request, form.query(QUrl::FullyEncoded).toStdString().c_str());
491  // we could expose downloadProgress() from reply in case we want progress info
492 
493  QString homeUrl = settings->value("home-url").toString().arg(username);
494  if (!homeUrl.isEmpty()) {
495  // clear header, the other request bits are reusable
496  request.setHeader(QNetworkRequest::ContentTypeHeader, 0);
497  request.setUrl(homeUrl + "/authorized_keys");
498  ssuLog->print(LOG_DEBUG, QString("Trying to get SSH keys from %1").arg(request.url().toString()));
499  pendingRequests++;
500  manager->get(request);
501  }
502 }
503 
504 bool Ssu::setCredentials(QDomDocument *response)
505 {
506  SsuCoreConfig *settings = SsuCoreConfig::instance();
507  // generate list with all scopes for generic section, add sections
508  QDomNodeList credentialsList = response->elementsByTagName("credentials");
509  QStringList credentialScopes;
510  for (int i = 0; i < credentialsList.size(); i++) {
511  QDomNode node = credentialsList.at(i);
512  QString scope;
513 
514  QDomNamedNodeMap attributes = node.attributes();
515  if (attributes.contains("scope")) {
516  scope = attributes.namedItem("scope").toAttr().value();
517  } else {
518  setError(tr("Credentials element does not have scope"));
519  return false;
520  }
521 
522  if (node.hasChildNodes()) {
523  QDomElement username = node.firstChildElement("username");
524  QDomElement password = node.firstChildElement("password");
525  if (username.isNull() || password.isNull()) {
526  setError(tr("Username and/or password not set"));
527  return false;
528  } else {
529  settings->beginGroup("credentials-" + scope);
530  settings->setValue("username", username.text());
531  settings->setValue("password", password.text());
532  settings->endGroup();
533  settings->sync();
534  credentialScopes.append(scope);
535  }
536  } else {
537  setError(QString());
538  return false;
539  }
540  }
541  settings->setValue("credentialScopes", credentialScopes);
542  settings->setValue("lastCredentialsUpdate", QDateTime::currentDateTime());
543  settings->sync();
544  emit credentialsChanged();
545 
546  return true;
547 }
548 
549 void Ssu::setError(const QString &errorMessage)
550 {
551  errorFlag = true;
552  errorString = errorMessage;
553 
554  SsuLog *ssuLog = SsuLog::instance();
555 
556  // dump error message to systemd journal for easier debugging
557  ssuLog->print(LOG_WARNING, errorMessage);
558 
559  // assume that we don't even need to wait for other pending requests,
560  // and just die. This is only relevant for CLI, which will exit after done()
561  emit done();
562 }
563 
564 void Ssu::storeAuthorizedKeys(const QByteArray &data)
565 {
566  QDir dir;
567  SsuLog *ssuLog = SsuLog::instance();
568 
569  int uid_min = getdef_num("UID_MIN", -1);
570  QString homePath;
571 
572  if (getuid() >= static_cast<uid_t>(uid_min)) {
573  homePath = dir.homePath();
574  } else if (getuid() == 0) {
575  // place authorized_keys in the default users home when run with uid0
576  struct passwd *pw = getpwuid(uid_min);
577  if (pw == NULL) {
578  ssuLog->print(LOG_DEBUG, QString("Unable to find password entry for uid %1")
579  .arg(uid_min));
580  return;
581  }
582 
583  //homePath = QString(pw->pw_dir);
584  homePath = pw->pw_dir;
585 
586  // use users uid/gid for creating the directories and files
587  setegid(pw->pw_gid);
588  seteuid(uid_min);
589  ssuLog->print(LOG_DEBUG, QString("Dropping to %1/%2 for writing authorized keys")
590  .arg(uid_min)
591  .arg(pw->pw_gid));
592  } else {
593  return;
594  }
595 
596  homePath = Sandbox::map(homePath);
597 
598  if (dir.exists(homePath + "/.ssh/authorized_keys")) {
599  ssuLog->print(LOG_DEBUG, QString(".ssh/authorized_keys already exists in %1")
600  .arg(homePath));
601  restoreUid();
602  return;
603  }
604 
605  if (!dir.exists(homePath + "/.ssh")) {
606  if (!dir.mkdir(homePath + "/.ssh")) {
607  ssuLog->print(LOG_DEBUG, QString("Unable to create .ssh in %1")
608  .arg(homePath));
609  restoreUid();
610  return;
611  }
612  }
613 
614  QFile::setPermissions(homePath + "/.ssh",
615  QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
616 
617  QFile authorizedKeys(homePath + "/.ssh/authorized_keys");
618  authorizedKeys.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
619  authorizedKeys.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
620  QTextStream out(&authorizedKeys);
621  out << data;
622  out.flush();
623  authorizedKeys.close();
624 
625  restoreUid();
626 }
627 
628 void Ssu::updateCredentials(bool force)
629 {
630  SsuCoreConfig *settings = SsuCoreConfig::instance();
631  SsuDeviceInfo deviceInfo;
632  errorFlag = false;
633 
634  SsuLog *ssuLog = SsuLog::instance();
635 
636  if (deviceInfo.deviceUid().isEmpty()) {
637  setError("No valid UID available for your device. For phones: is your modem online?");
638  return;
639  }
640 
641  QString ssuCaCertificate, ssuCredentialsUrl;
642  ssuCaCertificate = SsuRepoManager::caCertificatePath();
643  if (ssuCaCertificate.isEmpty()) {
644  setError("CA certificate for ssu not set ('_ca-certificate in domain')");
645  return;
646  }
647 
648  if (!settings->contains("credentials-url")) {
649  ssuCredentialsUrl = repoUrl("credentials-url");
650  if (ssuCredentialsUrl.isEmpty()) {
651  setError("URL for credentials update not set (config key 'credentials-url')");
652  return;
653  }
654  } else {
655  ssuCredentialsUrl = settings->value("credentials-url").toString();
656  }
657 
658  if (!isRegistered()) {
659  setError("Device is not registered.");
660  return;
661  }
662 
663  if (!force) {
664  // skip updating if the last update was less than 30 minutes ago
665  QDateTime now = QDateTime::currentDateTime();
666 
667  if (settings->contains("lastCredentialsUpdate")) {
668  QDateTime last = settings->value("lastCredentialsUpdate").toDateTime();
669  if (last >= now.addSecs(-1800)) {
670  ssuLog->print(LOG_DEBUG, QString("Skipping credentials update, last update was at %1")
671  .arg(last.toString()));
672  emit done();
673  return;
674  }
675  }
676  }
677 
678  // check when the last update was, decide if an update is required
679  QSslConfiguration sslConfiguration;
680  if (!useSslVerify())
681  sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
682 
683  QSslKey privateKey(settings->value("privateKey").toByteArray(), QSsl::Rsa);
684  QSslCertificate certificate(settings->value("certificate").toByteArray());
685 
686  QList<QSslCertificate> caCertificates;
687  caCertificates << QSslCertificate::fromPath(ssuCaCertificate);
688  sslConfiguration.setCaCertificates(caCertificates);
689 
690  sslConfiguration.setPrivateKey(privateKey);
691  sslConfiguration.setLocalCertificate(certificate);
692 
693  QNetworkRequest request;
694  request.setUrl(QUrl(ssuCredentialsUrl.arg(deviceInfo.deviceUid())));
695 
696  ssuLog->print(LOG_DEBUG, QString("Sending credential update request to %1")
697  .arg(request.url().toString()));
698  request.setSslConfiguration(sslConfiguration);
699 
700  pendingRequests++;
701  manager->get(request);
702 }
703 
705 {
706  SsuCoreConfig *settings = SsuCoreConfig::instance();
707  SsuLog *ssuLog = SsuLog::instance();
708 
709  QDBusMessage message = QDBusMessage::createMethodCall("com.jolla.jollastore",
710  "/StoreClient",
711  "com.jolla.jollastore",
712  "storeCredentials");
713  QDBusPendingReply<QString, QString> reply = SsuCoreConfig::userSessionBus().asyncCall(message);
714  reply.waitForFinished();
715  if (reply.isError()) {
716  if (settings->value("ignore-credential-errors").toBool() == true) {
717  ssuLog->print(LOG_WARNING, QString("Warning: ignore-credential-errors is set, passing auth errors down to libzypp"));
718  ssuLog->print(LOG_WARNING, QString("Store credentials not received. %1").arg(reply.error().message()));
719  } else {
720  setError(QString("Store credentials not received. %1").arg(reply.error().message()));
721  }
722  } else {
723  SsuCoreConfig *settings = SsuCoreConfig::instance();
724  settings->beginGroup("credentials-store");
725  settings->setValue("username", reply.argumentAt<0>());
726  settings->setValue("password", reply.argumentAt<1>());
727  settings->endGroup();
728  settings->sync();
729  }
730 }
731 
733 {
734  SsuCoreConfig *settings = SsuCoreConfig::instance();
735  settings->setValue("privateKey", "");
736  settings->setValue("certificate", "");
737  settings->setValue("registered", false);
738  settings->sync();
740 }
741 
742 bool Ssu::verifyResponse(QDomDocument *response)
743 {
744  QString action = response->elementsByTagName("action").at(0).toElement().text();
745  QString deviceId = response->elementsByTagName("deviceId").at(0).toElement().text();
746  QString protocolVersion = response->elementsByTagName("protocolVersion").at(0).toElement().text();
747  // compare device ids
748 
749  if (protocolVersion != SSU_PROTOCOL_VERSION) {
750  setError(
751  tr("Response has unsupported protocol version %1, client requires version %2")
752  .arg(protocolVersion)
754  );
755  return false;
756  }
757 
758  return true;
759 }
SsuCoreConfig::setDeviceMode
Q_INVOKABLE void setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode=Ssu::Replace)
Definition: ssucoreconfig.cpp:111
Ssu::updateCredentials
void updateCredentials(bool force=false)
Definition: ssu.cpp:628
SsuCoreConfig::userSessionBus
static QDBusConnection userSessionBus()
Definition: ssucoreconfig.cpp:164
SsuCoreConfig::credentials
QPair< QString, QString > credentials(const QString &scope)
Definition: ssucoreconfig.cpp:28
SsuRepoManager::url
QString url(const QString &repoName, bool rndRepo=false, QHash< QString, QString > repoParameters=QHash< QString, QString >(), QHash< QString, QString > parametersOverride=QHash< QString, QString >())
Definition: ssurepomanager.cpp:424
Ssu::flavour
Q_INVOKABLE QString flavour()
See SsuCoreConfig::flavour.
Definition: ssu.cpp:156
SsuVariables::variableSection
void variableSection(const QString &section, QHash< QString, QString > *storageHash)
Definition: ssuvariables.cpp:173
SsuSettings
Definition: ssusettings_p.h:30
Ssu::credentialsUrl
QString credentialsUrl(const QString &scope)
Definition: ssu.cpp:144
Ssu::brand
Q_INVOKABLE QString brand()
See SsuCoreConfig::brand.
Definition: ssu.cpp:174
Ssu::sendRegistration
void sendRegistration(const QString &username, const QString &password)
Definition: ssu.cpp:409
SsuCoreConfig::domain
Q_INVOKABLE QString domain(bool pretty=false)
Definition: ssucoreconfig.cpp:73
Ssu::setFlavour
Q_INVOKABLE void setFlavour(const QString &flavour)
See SsuCoreConfig::setFlavour.
Definition: ssu.cpp:203
SsuCoreConfig::setRelease
Q_INVOKABLE void setRelease(const QString &release, bool rnd=false)
Definition: ssucoreconfig.cpp:135
SsuCoreConfig::setDomain
Q_INVOKABLE void setDomain(const QString &domain)
Definition: ssucoreconfig.cpp:148
SsuDeviceInfo::deviceUid
Q_INVOKABLE QString deviceUid()
Definition: ssudeviceinfo.cpp:320
SsuLog
Definition: ssulog_p.h:15
Ssu::setDeviceMode
Q_INVOKABLE void setDeviceMode(DeviceModeFlags mode, enum EditMode editMode=Replace)
See SsuCoreConfig::setDeviceMode.
Definition: ssu.cpp:197
ssuvariables_p.h
SsuVariables::variable
QVariant variable(const QString &section, const QString &key)
Definition: ssuvariables.cpp:150
Ssu::useSslVerify
Q_INVOKABLE bool useSslVerify()
See SsuCoreConfig::useSslVerify.
Definition: ssu.cpp:221
SsuRepoManager
Definition: ssurepomanager.h:18
SsuCoreConfig::useSslVerify
Q_INVOKABLE bool useSslVerify()
Definition: ssucoreconfig.cpp:156
Ssu::isRegistered
Q_INVOKABLE bool isRegistered()
See SsuCoreConfig::isRegistered.
Definition: ssu.cpp:179
Ssu::credentials
QPair< QString, QString > credentials(const QString &scope)
Definition: ssu.cpp:95
Ssu::lastCredentialsUpdate
Q_INVOKABLE QDateTime lastCredentialsUpdate()
See SsuCoreConfig::lastCredentialsUpdate.
Definition: ssu.cpp:185
ssu.h
Ssu::updateStoreCredentials
void updateStoreCredentials()
Definition: ssu.cpp:704
Ssu::done
void done()
Ssu::setDomain
Q_INVOKABLE void setDomain(const QString &domain)
See SsuCoreConfig::setDomain.
Definition: ssu.cpp:215
ssurepomanager.h
SSU_REPO_CONFIGURATION
#define SSU_REPO_CONFIGURATION
Path to the ssu domain configuration file.
Definition: constants.h:14
Ssu::EditMode
EditMode
Definition: ssu.h:90
ssucoreconfig_p.h
SsuRepoManager::caCertificatePath
static QString caCertificatePath(const QString &domain=QString())
Definition: ssurepomanager.cpp:78
SsuCoreConfig::isRegistered
Q_INVOKABLE bool isRegistered()
Definition: ssucoreconfig.cpp:89
Ssu::repoUrl
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
SsuCoreConfig
Definition: ssucoreconfig_p.h:27
Ssu::unregister
Q_INVOKABLE void unregister()
Definition: ssu.cpp:732
Ssu::credentialsScope
QString credentialsScope(const QString &repoName, bool rndRepo=false)
Definition: ssu.cpp:101
Ssu::lastError
Q_INVOKABLE QString lastError()
Definition: ssu.cpp:231
SsuCoreConfig::brand
Q_INVOKABLE QString brand()
Definition: ssucoreconfig.cpp:85
SsuLog::print
void print(int priority, const QString &message)
Definition: ssulog.cpp:27
SSU_CONFIGURATION
#define SSU_CONFIGURATION
Path to the main ssu configuration file.
Definition: ssucoreconfig_p.h:17
Ssu::release
Q_INVOKABLE QString release(bool rnd=false)
See SsuCoreConfig::release.
Definition: ssu.cpp:191
Ssu::registrationStatusChanged
void registrationStatusChanged()
SsuCoreConfig::setFlavour
Q_INVOKABLE void setFlavour(const QString &flavour)
Definition: ssucoreconfig.cpp:127
sandbox_p.h
SsuCoreConfig::flavour
Q_INVOKABLE QString flavour()
Definition: ssucoreconfig.cpp:57
SsuCoreConfig::credentialsScope
QString credentialsScope(const QString &repoName, bool rndRepo=false)
Definition: ssucoreconfig.cpp:38
SsuDeviceInfo
Definition: ssudeviceinfo.h:17
ssudeviceinfo.h
SsuCoreConfig::deviceMode
Q_INVOKABLE Ssu::DeviceModeFlags deviceMode()
Definition: ssucoreconfig.cpp:65
Ssu::error
Q_INVOKABLE bool error()
Definition: ssu.cpp:150
SsuCoreConfig::release
Q_INVOKABLE QString release(bool rnd=false)
Definition: ssucoreconfig.cpp:103
SsuDeviceInfo::deviceModel
Q_INVOKABLE QString deviceModel()
Definition: ssudeviceinfo.cpp:185
SsuCoreConfig::credentialsUrl
QString credentialsUrl(const QString &scope)
Definition: ssucoreconfig.cpp:49
Ssu::setRelease
Q_INVOKABLE void setRelease(const QString &release, bool rnd=false)
See SsuCoreConfig::setRelease.
Definition: ssu.cpp:209
SsuCoreConfig::lastCredentialsUpdate
Q_INVOKABLE QDateTime lastCredentialsUpdate()
Definition: ssucoreconfig.cpp:98
ssulog_p.h
SSU_REPO_CONFIGURATION_DIR
#define SSU_REPO_CONFIGURATION_DIR
Path to config.d for ssu domain configurations.
Definition: constants.h:16
SSU_PROTOCOL_VERSION
#define SSU_PROTOCOL_VERSION
The ssu protocol version used by the ssu client libraries.
Definition: constants.h:24
SSU_GROUP_ID
#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