Example #1
0
File: ssu.cpp Project: jvihrial/ssu
QString Ssu::credentialsScope(QString repoName, bool rndRepo){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  SsuSettings repoSettings(SSU_REPO_CONFIGURATION, QSettings::IniFormat);

  // hardcoded magic for doing special privileges store repositories
  if (repoName == "store" || repoName.startsWith("store-c-"))
    return "store";

  // check if some repos are marked for using store-credentials
  // in current domain, checking first for rnd/release specific
  // settings, and if not found in generic settings
  QString storeAuthReposKey = QString("store-auth-repos-%1")
    .arg(rndRepo ? "rnd" : "release");
  QStringList storeAuthRepos =
    SsuVariables::variable(&repoSettings,
                           domain() + "-domain",
                           storeAuthReposKey).toStringList();
  if (storeAuthRepos.empty())
    storeAuthRepos =
      SsuVariables::variable(&repoSettings,
                             domain() + "-domain",
                             "store-auth-repos").toStringList();

  if (storeAuthRepos.contains(repoName))
    return "store";

  return settings->credentialsScope(repoName, rndRepo);
}
Example #2
0
File: ssu.cpp Project: lbt/ssu
Ssu::Ssu(): QObject(){
  errorFlag = false;
  pendingRequests = 0;

#ifdef SSUCONFHACK
  // dirty hack to make sure we can write to the configuration
  // this is currently required since there's no global gconf,
  // and we migth not yet have users on bootstrap
  QFileInfo settingsInfo(SSU_CONFIGURATION);
  if (settingsInfo.groupId() != SSU_GROUP_ID ||
      !settingsInfo.permission(QFile::WriteGroup)){
    QProcess proc;
    proc.start("/usr/bin/ssuconfperm");
    proc.waitForFinished();
  }
#endif

  SsuCoreConfig *settings = SsuCoreConfig::instance();

#ifdef TARGET_ARCH
  if (!settings->contains("arch"))
    settings->setValue("arch", TARGET_ARCH);
#else
// FIXME, try to guess a matching architecture
#warning "TARGET_ARCH not defined"
#endif
  settings->sync();



  manager = new QNetworkAccessManager(this);
  connect(manager, SIGNAL(finished(QNetworkReply *)),
          SLOT(requestFinished(QNetworkReply *)));
}
Example #3
0
File: ssu.cpp Project: lbt/ssu
void Ssu::unregister(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  settings->setValue("privateKey", "");
  settings->setValue("certificate", "");
  settings->setValue("registered", false);
  settings->sync();
  emit registrationStatusChanged();
}
Example #4
0
QStringList SsuRepoManager::repos(int filter){
  SsuDeviceInfo deviceInfo;
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();
  bool rnd = false;

  if ((ssuSettings->deviceMode() & Ssu::RndMode) == Ssu::RndMode)
    rnd = true;

  return repos(rnd, deviceInfo, filter);
}
Example #5
0
int SsuRepoManager::remove(QString repo){
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();

  // removing a repo is a noop when device is in update mode...
  if ((ssuSettings->deviceMode() & Ssu::UpdateMode) == Ssu::UpdateMode)
    return -1;

  // ... or AppInstallMode
  if ((ssuSettings->deviceMode() & Ssu::AppInstallMode) == Ssu::AppInstallMode)
    return -1;

  if (ssuSettings->contains("repository-urls/" + repo))
    ssuSettings->remove("repository-urls/" + repo);

  if (ssuSettings->contains("enabled-repos")){
    QStringList enabledRepos = ssuSettings->value("enabled-repos").toStringList();
    if (enabledRepos.contains(repo)){
      enabledRepos.removeAll(repo);
      enabledRepos.removeDuplicates();
      ssuSettings->setValue("enabled-repos", enabledRepos);
    }
  }

  ssuSettings->sync();

  return 0;
}
Example #6
0
int SsuRepoManager::add(QString repo, QString repoUrl){
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();

  // adding a repo is a noop when device is in update mode...
  if ((ssuSettings->deviceMode() & Ssu::UpdateMode) == Ssu::UpdateMode)
    return -1;

  // ... or in AppInstallMode
  if ((ssuSettings->deviceMode() & Ssu::AppInstallMode) == Ssu::AppInstallMode)
    return -1;

  if (repoUrl == ""){
    // just enable a repository which has URL in repos.ini
    QStringList enabledRepos;
    if (ssuSettings->contains("enabled-repos"))
      enabledRepos = ssuSettings->value("enabled-repos").toStringList();

    enabledRepos.append(repo);
    enabledRepos.removeDuplicates();
    ssuSettings->setValue("enabled-repos", enabledRepos);
  } else
    ssuSettings->setValue("repository-urls/" + repo, repoUrl);

  ssuSettings->sync();
  return 0;
}
Example #7
0
int SsuRepoManager::enable(QString repo){
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();
  QStringList disabledRepos;

  if (ssuSettings->contains("disabled-repos"))
    disabledRepos = ssuSettings->value("disabled-repos").toStringList();

  disabledRepos.removeAll(repo);
  disabledRepos.removeDuplicates();

  ssuSettings->setValue("disabled-repos", disabledRepos);
  ssuSettings->sync();

  return 0;
}
Example #8
0
File: ssu.cpp Project: lbt/ssu
bool Ssu::registerDevice(QDomDocument *response){
  QString certificateString = response->elementsByTagName("certificate").at(0).toElement().text();
  QSslCertificate certificate(certificateString.toAscii());
  SsuLog *ssuLog = SsuLog::instance();
  SsuCoreConfig *settings = SsuCoreConfig::instance();

  if (certificate.isNull()){
    // make sure device is in unregistered state on failed registration
    settings->setValue("registered", false);
    setError("Certificate is invalid");
    return false;
  } else
    settings->setValue("certificate", certificate.toPem());

  QString privateKeyString = response->elementsByTagName("privateKey").at(0).toElement().text();
  QSslKey privateKey(privateKeyString.toAscii(), QSsl::Rsa);

  if (privateKey.isNull()){
    settings->setValue("registered", false);
    setError("Private key is invalid");
    return false;
  } else
    settings->setValue("privateKey", privateKey.toPem());

  // oldUser is just for reference purposes, in case we want to notify
  // about owner changes for the device
  QString oldUser = response->elementsByTagName("user").at(0).toElement().text();
  ssuLog->print(LOG_DEBUG, QString("Old user for your device was: %1").arg(oldUser));

  // if we came that far everything required for device registration is done
  settings->setValue("registered", true);
  settings->sync();
  emit registrationStatusChanged();
  return true;
}
Example #9
0
QString SsuRepoManager::caCertificatePath(QString domain){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  SsuSettings repoSettings(SSU_REPO_CONFIGURATION, QSettings::IniFormat);

  if (domain.isEmpty())
    domain = settings->domain();

  QString ca = SsuVariables::variable(&repoSettings, domain + "-domain",
                                      "_ca-certificate").toString();
  if (!ca.isEmpty())
    return ca;

  // compat setting, can go away after some time
  if (settings->contains("ca-certificate"))
    return settings->value("ca-certificate").toString();

  return "";
}
Example #10
0
File: ssu.cpp Project: jvihrial/ssu
void Ssu::updateStoreCredentials(){
  QDBusMessage message = QDBusMessage::createMethodCall("com.jolla.jollastore",
                                                        "/StoreClient",
                                                        "com.jolla.jollastore",
                                                        "storeCredentials");
  QDBusPendingReply<QString, QString> reply = SsuCoreConfig::userSessionBus().asyncCall(message);
  reply.waitForFinished();
  if (reply.isError()) {
    setError(QString("Store credentials not received. %1").arg(reply.error().message()));
  } else {
    SsuCoreConfig *settings = SsuCoreConfig::instance();
    settings->beginGroup("credentials-store");
    settings->setValue("username", reply.argumentAt<0>());
    settings->setValue("password", reply.argumentAt<1>());
    settings->endGroup();
    settings->sync();
  }
}
Example #11
0
void SsuCli::optRegister(QStringList opt){
  /*
   * register a new device
   */

  QString username, password;
  QTextStream qin(stdin);
  QTextStream qout(stdout);
  QTextStream qerr(stderr);
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();

  struct termios termNew, termOld;

  qout << "Username: "******"WARNING: Unable to disable echo on your terminal, password will echo!" << endl;

  qout << "Password: "******"-h")
    ssuSettings->setValue("repository-url-variables/user", username);

  QDBusPendingReply<> reply = ssuProxy->registerDevice(username, password);
  reply.waitForFinished();
  if (reply.isError()){
    qerr << "DBus call failed, falling back to libssu" << endl;
    qerr << reply.error().message() << endl;
    ssu.sendRegistration(username, password);
  }

  state = Busy;
}
Example #12
0
File: ssu.cpp Project: lbt/ssu
bool Ssu::setCredentials(QDomDocument *response){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  // generate list with all scopes for generic section, add sections
  QDomNodeList credentialsList = response->elementsByTagName("credentials");
  QStringList credentialScopes;
  for (int i=0;i<credentialsList.size();i++){
    QDomNode node = credentialsList.at(i);
    QString scope;

    QDomNamedNodeMap attributes = node.attributes();
    if (attributes.contains("scope")){
      scope = attributes.namedItem("scope").toAttr().value();
    } else {
      setError(tr("Credentials element does not have scope"));
      return false;
    }

    if (node.hasChildNodes()){
      QDomElement username = node.firstChildElement("username");
      QDomElement password = node.firstChildElement("password");
      if (username.isNull() || password.isNull()){
        setError(tr("Username and/or password not set"));
        return false;
      } else {
        settings->beginGroup("credentials-" + scope);
        settings->setValue("username", username.text());
        settings->setValue("password", password.text());
        settings->endGroup();
        settings->sync();
        credentialScopes.append(scope);
      }
    } else {
      setError("");
      return false;
    }
  }
  settings->setValue("credentialScopes", credentialScopes);
  settings->setValue("lastCredentialsUpdate", QDateTime::currentDateTime());
  settings->sync();
  emit credentialsChanged();

  return true;
}
Example #13
0
// @todo the non-device specific repository resolving should move from deviceInfo to repomanager
QStringList SsuRepoManager::repos(bool rnd, SsuDeviceInfo &deviceInfo, int filter){
  QStringList result;

  // read the adaptation specific repositories, as well as the default
  // repositories; default repos are read through deviceInfo as an
  // adaptation is allowed to disable core repositories
  result = deviceInfo.repos(rnd, filter);

  // read the repositories of the available features. While devices have
  // a default list of features to be installed those are only relevant
  // for bootstrapping, so this code just operates on installed features
  SsuFeatureManager featureManager;
  result.append(featureManager.repos(rnd, filter));

  // read user-defined repositories from ssu.ini. This step needs to
  // happen at the end, after all other required repositories are
  // added already

  // TODO: in strict mode, filter the repository list from there
  SsuCoreConfig *ssuSettings = SsuCoreConfig::instance();

  bool updateMode = false;
  bool appInstallMode = false;

  if ((ssuSettings->deviceMode() & Ssu::UpdateMode) == Ssu::UpdateMode)
    updateMode = true;

  if ((ssuSettings->deviceMode() & Ssu::AppInstallMode) == Ssu::AppInstallMode){
    updateMode = true;
    appInstallMode = true;
  }

  if (filter == Ssu::NoFilter ||
      filter == Ssu::UserFilter){
    // user defined repositories, or ones overriding URLs for default ones
    // -> in update mode we need to check for each of those if it already
    //    exists. If it exists, keep it, if it does not, disable it
    ssuSettings->beginGroup("repository-urls");
    QStringList repoUrls = ssuSettings->allKeys();
    ssuSettings->endGroup();

    if (updateMode){
      foreach(const QString &key, repoUrls){
        if (result.contains(key))
          result.append(key);
      }
    } else {
Example #14
0
File: ssu.cpp Project: lbt/ssu
// Wrappers around SsuCoreConfig
QString Ssu::flavour(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->flavour();
}
Example #15
0
File: ssu.cpp Project: lbt/ssu
QString Ssu::credentialsUrl(QString scope){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->credentialsUrl(scope);
}
Example #16
0
File: ssu.cpp Project: lbt/ssu
QString Ssu::credentialsScope(QString repoName, bool rndRepo){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->credentialsScope(repoName, rndRepo);
}
Example #17
0
File: ssu.cpp Project: lbt/ssu
// FIXME, the whole credentials stuff needs reworking
// should probably be part of repo handling instead of core configuration
QPair<QString, QString> Ssu::credentials(QString scope){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->credentials(scope);
}
Example #18
0
File: ssu.cpp Project: lbt/ssu
void Ssu::setFlavour(QString flavour){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  settings->setFlavour(flavour);
}
Example #19
0
File: ssu.cpp Project: lbt/ssu
bool Ssu::isRegistered(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->isRegistered();
}
Example #20
0
File: ssu.cpp Project: lbt/ssu
void Ssu::sendRegistration(QString usernameDomain, QString password){
  errorFlag = false;

  QString ssuCaCertificate, ssuRegisterUrl;
  QString username, domainName;

  SsuLog *ssuLog = SsuLog::instance();
  SsuCoreConfig *settings = SsuCoreConfig::instance();

  // Username can include also domain, (user@domain), separate those
  if (usernameDomain.contains('@')) {
      // separate domain/username and set domain
      username = usernameDomain.section('@', 0, 0);
      domainName = usernameDomain.section('@', 1, 1);
      setDomain(domainName);
  } else {
      // No domain defined
      username = usernameDomain;
  }

  if (!settings->contains("ca-certificate")){
    setError("CA certificate for SSU not set (config key 'ca-certificate')");
    return;
  } else
    ssuCaCertificate = settings->value("ca-certificate").toString();

  if (!settings->contains("register-url")){
    ssuRegisterUrl = repoUrl("register-url");
    if (ssuRegisterUrl.isEmpty()){
      setError("URL for SSU registration not set (config key 'register-url')");
      return;
    }
  } else
    ssuRegisterUrl = settings->value("register-url").toString();

  QString IMEI = deviceInfo.deviceUid();
  if (IMEI == ""){
    setError("No valid UID available for your device. For phones: is your modem online?");
    return;
  }

  QSslConfiguration sslConfiguration;
  if (!useSslVerify())
    sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);

  sslConfiguration.setCaCertificates(QSslCertificate::fromPath(ssuCaCertificate));

  QNetworkRequest request;
  request.setUrl(QUrl(QString(ssuRegisterUrl)
                      .arg(IMEI)
                   ));
  request.setSslConfiguration(sslConfiguration);
  request.setRawHeader("Authorization", "Basic " +
                       QByteArray(QString("%1:%2")
                                  .arg(username).arg(password)
                                  .toAscii()).toBase64());
  request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");

  QUrl form;
  form.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
  form.addQueryItem("deviceModel", deviceInfo.deviceModel());
  if (!domain().isEmpty()){
    form.addQueryItem("domain", domain());
  }

  qDebug() << "Sending request to " << request.url();
  qDebug() << form.encodedQueryItems();

  QNetworkReply *reply;

  pendingRequests++;
  reply = manager->post(request, form.encodedQuery());
  // we could expose downloadProgress() from reply in case we want progress info

  QString homeUrl = settings->value("home-url").toString().arg(username);
  if (!homeUrl.isEmpty()){
    // clear header, the other request bits are reusable
    request.setHeader(QNetworkRequest::ContentTypeHeader, 0);
    request.setUrl(homeUrl + "/authorized_keys");
    ssuLog->print(LOG_DEBUG, QString("Trying to get SSH keys from %1").arg(request.url().toString()));
    pendingRequests++;
    manager->get(request);
  }
}
Example #21
0
File: ssu.cpp Project: lbt/ssu
void Ssu::requestFinished(QNetworkReply *reply){
  QSslConfiguration sslConfiguration = reply->sslConfiguration();
  SsuLog *ssuLog = SsuLog::instance();
  SsuCoreConfig *settings = SsuCoreConfig::instance();

  ssuLog->print(LOG_DEBUG, QString("Certificate used was issued for '%1' by '%2'. Complete chain:")
               .arg(sslConfiguration.peerCertificate().subjectInfo(QSslCertificate::CommonName))
               .arg(sslConfiguration.peerCertificate().issuerInfo(QSslCertificate::CommonName)));

  foreach (const QSslCertificate cert, sslConfiguration.peerCertificateChain()){
    ssuLog->print(LOG_DEBUG, QString("-> %1").arg(cert.subjectInfo(QSslCertificate::CommonName)));
  }

  // what sucks more, this or goto?
  do {
    if (settings->contains("home-url")){
      QString homeUrl = settings->value("home-url").toString().arg("");
      homeUrl.remove(QRegExp("//+$"));
      QNetworkRequest request = reply->request();

      if (request.url().toString().startsWith(homeUrl, Qt::CaseInsensitive)){
        // we don't care about errors on download request
        if (reply->error() > 0) break;
        QByteArray data = reply->readAll();
        storeAuthorizedKeys(data);
        break;
      }
    }

    if (reply->error() > 0){
      pendingRequests--;
      setError(reply->errorString());
      return;
    } else {
      QByteArray data = reply->readAll();
      qDebug() << "RequestOutput" << data;

      QDomDocument doc;
      QString xmlError;
      if (!doc.setContent(data, &xmlError)){
        pendingRequests--;
        setError(tr("Unable to parse server response (%1)").arg(xmlError));
        return;
      }

      QString action = doc.elementsByTagName("action").at(0).toElement().text();

      if (!verifyResponse(&doc)) break;

      if (action == "register"){
        if (!registerDevice(&doc)) break;
      } else if (action == "credentials"){
        if (!setCredentials(&doc)) break;
      } else {
        pendingRequests--;
        setError(tr("Response to unknown action encountered: %1").arg(action));
        return;
      }
    }
  } while (false);

  pendingRequests--;

  ssuLog->print(LOG_DEBUG, QString("Request finished, pending requests: %1").arg(pendingRequests));
  if (pendingRequests == 0)
    emit done();
}
Example #22
0
File: ssu.cpp Project: lbt/ssu
QString Ssu::release(bool rnd){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->release(rnd);
}
Example #23
0
File: ssu.cpp Project: lbt/ssu
bool Ssu::useSslVerify(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->useSslVerify();
}
Example #24
0
File: ssu.cpp Project: lbt/ssu
void Ssu::setDomain(QString domain){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  settings->setDomain(domain);
}
Example #25
0
File: ssu.cpp Project: lbt/ssu
void Ssu::setRelease(QString release, bool rnd){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  settings->setRelease(release, rnd);
}
Example #26
0
File: ssu.cpp Project: lbt/ssu
int Ssu::deviceMode(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->deviceMode();
}
Example #27
0
File: ssu.cpp Project: lbt/ssu
QString Ssu::domain(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->domain();
}
Example #28
0
File: ssu.cpp Project: lbt/ssu
void Ssu::updateCredentials(bool force){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  errorFlag = false;

  SsuLog *ssuLog = SsuLog::instance();

  if (deviceInfo.deviceUid() == ""){
    setError("No valid UID available for your device. For phones: is your modem online?");
    return;
  }

  QString ssuCaCertificate, ssuCredentialsUrl;
  if (!settings->contains("ca-certificate")){
    setError("CA certificate for SSU not set (config key 'ca-certificate')");
    return;
  } else
    ssuCaCertificate = settings->value("ca-certificate").toString();

  if (!settings->contains("credentials-url")){
    ssuCredentialsUrl = repoUrl("credentials-url");
    if (ssuCredentialsUrl.isEmpty()){
      setError("URL for credentials update not set (config key 'credentials-url')");
      return;
    }
  } else
    ssuCredentialsUrl = settings->value("credentials-url").toString();

  if (!isRegistered()){
    setError("Device is not registered.");
    return;
  }

  if (!force){
    // skip updating if the last update was less than 30 minutes ago
    QDateTime now = QDateTime::currentDateTime();

    if (settings->contains("lastCredentialsUpdate")){
      QDateTime last = settings->value("lastCredentialsUpdate").toDateTime();
      if (last >= now.addSecs(-1800)){
        ssuLog->print(LOG_DEBUG, QString("Skipping credentials update, last update was at %1")
                     .arg(last.toString()));
        emit done();
        return;
      }
    }
  }

  // check when the last update was, decide if an update is required
  QSslConfiguration sslConfiguration;
  if (!useSslVerify())
    sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);

  QSslKey privateKey(settings->value("privateKey").toByteArray(), QSsl::Rsa);
  QSslCertificate certificate(settings->value("certificate").toByteArray());

  QList<QSslCertificate> caCertificates;
  caCertificates << QSslCertificate::fromPath(ssuCaCertificate);
  sslConfiguration.setCaCertificates(caCertificates);

  sslConfiguration.setPrivateKey(privateKey);
  sslConfiguration.setLocalCertificate(certificate);

  QNetworkRequest request;
  request.setUrl(QUrl(ssuCredentialsUrl.arg(deviceInfo.deviceUid())));

  ssuLog->print(LOG_DEBUG, QString("Sending credential update request to %1")
               .arg(request.url().toString()));
  request.setSslConfiguration(sslConfiguration);

  pendingRequests++;
  manager->get(request);
}
Example #29
0
File: ssu.cpp Project: lbt/ssu
QDateTime Ssu::lastCredentialsUpdate(){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  return settings->lastCredentialsUpdate();
}
Example #30
0
File: ssu.cpp Project: lbt/ssu
void Ssu::setDeviceMode(int mode, int editMode){
  SsuCoreConfig *settings = SsuCoreConfig::instance();
  settings->setDeviceMode(mode, editMode);
}