Skip to content

Latest commit

 

History

History
686 lines (565 loc) · 21.7 KB

ssu.cpp

File metadata and controls

686 lines (565 loc) · 21.7 KB
 
Oct 8, 2012
Oct 8, 2012
1
2
3
4
5
6
7
/**
* @file ssu.cpp
* @copyright 2012 Jolla Ltd.
* @author Bernd Wachter <bernd.wachter@jollamobile.com>
* @date 2012
*/
Apr 4, 2013
Apr 4, 2013
8
#include <QtNetwork>
Oct 8, 2012
Oct 8, 2012
9
#include <QtXml/QDomDocument>
Nov 6, 2013
Nov 6, 2013
10
11
12
#include <QDBusConnection>
#include <QDBusMessage>
#include <QDBusPendingReply>
Mar 11, 2013
Mar 11, 2013
13
May 23, 2013
May 23, 2013
14
15
16
17
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
#include <QUrlQuery>
#endif
Sep 9, 2013
Sep 9, 2013
18
19
#include <getdef.h>
#include <pwd.h>
Sep 7, 2014
Sep 7, 2014
20
21
#include <sys/types.h>
#include <unistd.h>
Sep 9, 2013
Sep 9, 2013
22
Oct 8, 2012
Oct 8, 2012
23
#include "ssu.h"
Oct 14, 2013
Oct 14, 2013
24
#include "sandbox_p.h"
Aug 21, 2015
Aug 21, 2015
25
26
27
#include "ssulog_p.h"
#include "ssuvariables_p.h"
#include "ssucoreconfig_p.h"
Mar 30, 2013
Mar 30, 2013
28
#include "ssurepomanager.h"
Oct 6, 2013
Oct 6, 2013
29
#include "ssudeviceinfo.h"
Oct 8, 2012
Oct 8, 2012
30
Mar 19, 2013
Mar 19, 2013
31
32
#include "../constants.h"
Dec 2, 2013
Dec 2, 2013
33
34
#define SSU_NETWORK_REQUEST_DOMAIN_DATA (static_cast<QNetworkRequest::Attribute>(QNetworkRequest::User + 1))
Sep 13, 2013
Sep 13, 2013
35
36
37
38
39
40
41
static void restoreUid(){
if (getuid() == 0){
seteuid(0);
setegid(0);
}
}
Mar 30, 2013
Mar 30, 2013
42
Ssu::Ssu(): QObject(){
Oct 8, 2012
Oct 8, 2012
43
errorFlag = false;
Mar 11, 2013
Mar 11, 2013
44
pendingRequests = 0;
Oct 8, 2012
Oct 8, 2012
45
Oct 21, 2012
Oct 21, 2012
46
#ifdef SSUCONFHACK
Oct 8, 2012
Oct 8, 2012
47
48
49
50
51
52
53
54
55
56
// 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();
}
Oct 21, 2012
Oct 21, 2012
57
#endif
Oct 8, 2012
Oct 8, 2012
58
Mar 30, 2013
Mar 30, 2013
59
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 8, 2012
Oct 8, 2012
60
61
62
63
64
65
66
67
68
69
#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();
Mar 30, 2013
Mar 30, 2013
70
71
Oct 8, 2012
Oct 8, 2012
72
73
74
75
76
manager = new QNetworkAccessManager(this);
connect(manager, SIGNAL(finished(QNetworkReply *)),
SLOT(requestFinished(QNetworkReply *)));
}
Mar 30, 2013
Mar 30, 2013
77
78
// FIXME, the whole credentials stuff needs reworking
// should probably be part of repo handling instead of core configuration
Oct 8, 2012
Oct 8, 2012
79
QPair<QString, QString> Ssu::credentials(QString scope){
Mar 30, 2013
Mar 30, 2013
80
81
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->credentials(scope);
Oct 8, 2012
Oct 8, 2012
82
83
84
}
QString Ssu::credentialsScope(QString repoName, bool rndRepo){
Mar 30, 2013
Mar 30, 2013
85
SsuCoreConfig *settings = SsuCoreConfig::instance();
Nov 8, 2013
Nov 8, 2013
86
SsuSettings repoSettings(SSU_REPO_CONFIGURATION, QSettings::IniFormat);
Nov 1, 2013
Nov 1, 2013
87
88
89
90
91
// hardcoded magic for doing special privileges store repositories
if (repoName == "store" || repoName.startsWith("store-c-"))
return "store";
Nov 8, 2013
Nov 8, 2013
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
// 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";
Mar 30, 2013
Mar 30, 2013
110
return settings->credentialsScope(repoName, rndRepo);
Oct 8, 2012
Oct 8, 2012
111
112
}
Oct 24, 2012
Oct 24, 2012
113
QString Ssu::credentialsUrl(QString scope){
Mar 30, 2013
Mar 30, 2013
114
115
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->credentialsUrl(scope);
Oct 24, 2012
Oct 24, 2012
116
117
}
Oct 8, 2012
Oct 8, 2012
118
119
120
121
bool Ssu::error(){
return errorFlag;
}
Mar 30, 2013
Mar 30, 2013
122
// Wrappers around SsuCoreConfig
Oct 8, 2012
Oct 8, 2012
123
QString Ssu::flavour(){
Mar 30, 2013
Mar 30, 2013
124
125
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->flavour();
Oct 8, 2012
Oct 8, 2012
126
127
}
Feb 2, 2015
Feb 2, 2015
128
Ssu::DeviceModeFlags Ssu::deviceMode(){
Mar 30, 2013
Mar 30, 2013
129
130
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->deviceMode();
Mar 28, 2013
Mar 28, 2013
131
132
}
Jan 15, 2013
Jan 15, 2013
133
QString Ssu::domain(){
Mar 30, 2013
Mar 30, 2013
134
SsuCoreConfig *settings = SsuCoreConfig::instance();
Jul 5, 2013
Jul 5, 2013
135
return settings->domain(true);
Jan 15, 2013
Jan 15, 2013
136
137
}
Oct 8, 2012
Oct 8, 2012
138
bool Ssu::isRegistered(){
Mar 30, 2013
Mar 30, 2013
139
140
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->isRegistered();
Oct 8, 2012
Oct 8, 2012
141
142
143
}
QDateTime Ssu::lastCredentialsUpdate(){
Mar 30, 2013
Mar 30, 2013
144
145
146
147
148
149
150
151
152
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->lastCredentialsUpdate();
}
QString Ssu::release(bool rnd){
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->release(rnd);
}
Feb 2, 2015
Feb 2, 2015
153
void Ssu::setDeviceMode(Ssu::DeviceModeFlags mode, enum Ssu::EditMode editMode){
Mar 30, 2013
Mar 30, 2013
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
SsuCoreConfig *settings = SsuCoreConfig::instance();
settings->setDeviceMode(mode, editMode);
}
void Ssu::setFlavour(QString flavour){
SsuCoreConfig *settings = SsuCoreConfig::instance();
settings->setFlavour(flavour);
}
void Ssu::setRelease(QString release, bool rnd){
SsuCoreConfig *settings = SsuCoreConfig::instance();
settings->setRelease(release, rnd);
}
void Ssu::setDomain(QString domain){
SsuCoreConfig *settings = SsuCoreConfig::instance();
Apr 2, 2013
Apr 2, 2013
170
settings->setDomain(domain);
Mar 30, 2013
Mar 30, 2013
171
172
173
174
175
}
bool Ssu::useSslVerify(){
SsuCoreConfig *settings = SsuCoreConfig::instance();
return settings->useSslVerify();
Oct 8, 2012
Oct 8, 2012
176
177
}
Mar 30, 2013
Mar 30, 2013
178
179
180
181
//...
Oct 8, 2012
Oct 8, 2012
182
183
184
185
186
187
QString Ssu::lastError(){
return errorString;
}
bool Ssu::registerDevice(QDomDocument *response){
QString certificateString = response->elementsByTagName("certificate").at(0).toElement().text();
May 23, 2013
May 23, 2013
188
QSslCertificate certificate(certificateString.toLatin1());
Mar 19, 2013
Mar 19, 2013
189
SsuLog *ssuLog = SsuLog::instance();
Mar 30, 2013
Mar 30, 2013
190
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 8, 2012
Oct 8, 2012
191
192
193
194
195
196
197
198
199
200
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();
May 23, 2013
May 23, 2013
201
QSslKey privateKey(privateKeyString.toLatin1(), QSsl::Rsa);
Oct 8, 2012
Oct 8, 2012
202
203
204
205
206
207
208
209
210
211
212
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();
Mar 19, 2013
Mar 19, 2013
213
ssuLog->print(LOG_DEBUG, QString("Old user for your device was: %1").arg(oldUser));
Oct 8, 2012
Oct 8, 2012
214
215
216
217
// if we came that far everything required for device registration is done
settings->setValue("registered", true);
settings->sync();
Sep 13, 2013
Sep 13, 2013
218
219
220
221
222
223
if (!settings->isWritable()){
setError("Configuration is not writable, device registration failed.");
return false;
}
Oct 8, 2012
Oct 8, 2012
224
225
226
227
228
229
emit registrationStatusChanged();
return true;
}
// RND repos have flavour (devel, testing, release), and release (latest, next)
// Release repos only have release (latest, next, version number)
Mar 28, 2013
Mar 28, 2013
230
231
232
QString Ssu::repoUrl(QString repoName, bool rndRepo,
QHash<QString, QString> repoParameters,
QHash<QString, QString> parametersOverride){
Mar 30, 2013
Mar 30, 2013
233
234
SsuRepoManager manager;
return manager.url(repoName, rndRepo, repoParameters, parametersOverride);
Oct 8, 2012
Oct 8, 2012
235
236
237
238
}
void Ssu::requestFinished(QNetworkReply *reply){
QSslConfiguration sslConfiguration = reply->sslConfiguration();
Mar 19, 2013
Mar 19, 2013
239
SsuLog *ssuLog = SsuLog::instance();
Mar 30, 2013
Mar 30, 2013
240
SsuCoreConfig *settings = SsuCoreConfig::instance();
Dec 2, 2013
Dec 2, 2013
241
242
QNetworkRequest request = reply->request();
QVariant originalDomainVariant = request.attribute(SSU_NETWORK_REQUEST_DOMAIN_DATA);
Oct 8, 2012
Oct 8, 2012
243
May 23, 2013
May 23, 2013
244
245
246
247
248
249
250
251
252
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
ssuLog->print(LOG_DEBUG, QString("Certificate used was issued for '%1' by '%2'. Complete chain:")
.arg(sslConfiguration.peerCertificate().subjectInfo(QSslCertificate::CommonName).join(""))
.arg(sslConfiguration.peerCertificate().issuerInfo(QSslCertificate::CommonName).join("")));
foreach (const QSslCertificate cert, sslConfiguration.peerCertificateChain()){
ssuLog->print(LOG_DEBUG, QString("-> %1").arg(cert.subjectInfo(QSslCertificate::CommonName).join("")));
}
#else
Mar 19, 2013
Mar 19, 2013
253
ssuLog->print(LOG_DEBUG, QString("Certificate used was issued for '%1' by '%2'. Complete chain:")
Mar 11, 2013
Mar 11, 2013
254
255
.arg(sslConfiguration.peerCertificate().subjectInfo(QSslCertificate::CommonName))
.arg(sslConfiguration.peerCertificate().issuerInfo(QSslCertificate::CommonName)));
Oct 8, 2012
Oct 8, 2012
256
257
foreach (const QSslCertificate cert, sslConfiguration.peerCertificateChain()){
Mar 19, 2013
Mar 19, 2013
258
ssuLog->print(LOG_DEBUG, QString("-> %1").arg(cert.subjectInfo(QSslCertificate::CommonName)));
Oct 8, 2012
Oct 8, 2012
259
}
May 23, 2013
May 23, 2013
260
#endif
Oct 8, 2012
Oct 8, 2012
261
Dec 2, 2013
Dec 2, 2013
262
263
264
265
266
267
268
pendingRequests--;
QString action;
QByteArray data;
QDomDocument doc;
QString xmlError;
May 23, 2013
May 23, 2013
269
/// @TODO: indicate that the device is not registered if there's a 404 on credentials update url
Dec 2, 2013
Dec 2, 2013
270
271
272
273
274
275
276
277
278
if (settings->contains("home-url")){
QString homeUrl = settings->value("home-url").toString().arg("");
homeUrl.remove(QRegExp("//+$"));
if (request.url().toString().startsWith(homeUrl, Qt::CaseInsensitive)){
// we don't care about errors on download request
if (reply->error() == 0) {
QByteArray data = reply->readAll();
storeAuthorizedKeys(data);
Nov 4, 2012
Nov 4, 2012
279
}
Dec 2, 2013
Dec 2, 2013
280
281
goto success;
Nov 4, 2012
Nov 4, 2012
282
}
Dec 2, 2013
Dec 2, 2013
283
}
Oct 8, 2012
Oct 8, 2012
284
Dec 2, 2013
Dec 2, 2013
285
286
287
288
if (reply->error() > 0){
setError(reply->errorString());
goto failure;
}
Oct 8, 2012
Oct 8, 2012
289
Dec 2, 2013
Dec 2, 2013
290
291
292
data = reply->readAll();
ssuLog->print(LOG_DEBUG, QString("RequestOutput %1")
.arg(data.data()));
Oct 8, 2012
Oct 8, 2012
293
Dec 2, 2013
Dec 2, 2013
294
295
296
297
if (!doc.setContent(data, &xmlError)){
setError(tr("Unable to parse server response (%1)").arg(xmlError));
goto failure;
}
Oct 8, 2012
Oct 8, 2012
298
Dec 2, 2013
Dec 2, 2013
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
action = doc.elementsByTagName("action").at(0).toElement().text();
if (!verifyResponse(&doc)) {
goto failure;
}
ssuLog->print(LOG_DEBUG, QString("Handling request of type %1")
.arg(action));
if (action == "register") {
if (registerDevice(&doc)) {
goto success;
}
} else if (action == "credentials") {
if (setCredentials(&doc)) {
goto success;
Oct 8, 2012
Oct 8, 2012
314
}
Dec 2, 2013
Dec 2, 2013
315
316
317
} else {
setError(tr("Response to unknown action encountered: %1").arg(action));
}
Oct 8, 2012
Oct 8, 2012
318
Dec 2, 2013
Dec 2, 2013
319
320
321
322
323
324
325
failure:
// Restore the original domain in case of failures with the registration
if (!originalDomainVariant.isNull()) {
QString originalDomain = originalDomainVariant.toString();
ssuLog->print(LOG_DEBUG, QString("Restoring domain on error: '%1'").arg(originalDomain));
setDomain(originalDomain);
}
Mar 11, 2013
Mar 11, 2013
326
Dec 2, 2013
Dec 2, 2013
327
328
// Fall through to cleanup handling in success from failure label
success:
Mar 19, 2013
Mar 19, 2013
329
ssuLog->print(LOG_DEBUG, QString("Request finished, pending requests: %1").arg(pendingRequests));
Dec 2, 2013
Dec 2, 2013
330
if (pendingRequests == 0) {
Oct 8, 2012
Oct 8, 2012
331
emit done();
Dec 2, 2013
Dec 2, 2013
332
}
Oct 8, 2012
Oct 8, 2012
333
334
}
Jan 16, 2013
Jan 16, 2013
335
void Ssu::sendRegistration(QString usernameDomain, QString password){
Oct 8, 2012
Oct 8, 2012
336
337
338
errorFlag = false;
QString ssuCaCertificate, ssuRegisterUrl;
Jan 16, 2013
Jan 16, 2013
339
QString username, domainName;
Jan 16, 2013
Jan 16, 2013
340
Mar 19, 2013
Mar 19, 2013
341
SsuLog *ssuLog = SsuLog::instance();
Mar 30, 2013
Mar 30, 2013
342
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 6, 2013
Oct 6, 2013
343
SsuDeviceInfo deviceInfo;
Mar 19, 2013
Mar 19, 2013
344
Dec 2, 2013
Dec 2, 2013
345
346
347
348
QNetworkRequest request;
request.setAttribute(SSU_NETWORK_REQUEST_DOMAIN_DATA, domain());
ssuLog->print(LOG_DEBUG, QString("Saving current domain before request: '%1'").arg(domain()));
Jan 16, 2013
Jan 16, 2013
349
350
351
352
// Username can include also domain, (user@domain), separate those
if (usernameDomain.contains('@')) {
// separate domain/username and set domain
username = usernameDomain.section('@', 0, 0);
Jan 16, 2013
Jan 16, 2013
353
354
domainName = usernameDomain.section('@', 1, 1);
setDomain(domainName);
Jan 16, 2013
Jan 16, 2013
355
356
357
} else {
// No domain defined
username = usernameDomain;
Nov 7, 2013
Nov 7, 2013
358
359
if (settings->contains("default-rnd-domain"))
setDomain(settings->value("default-rnd-domain").toString());
Jan 16, 2013
Jan 16, 2013
360
361
}
Jul 6, 2013
Jul 6, 2013
362
363
ssuCaCertificate = SsuRepoManager::caCertificatePath();
if (ssuCaCertificate.isEmpty()){
Oct 13, 2014
Oct 13, 2014
364
setError("CA certificate for ssu not set ('_ca-certificate in domain')");
Oct 8, 2012
Oct 8, 2012
365
return;
Jul 6, 2013
Jul 6, 2013
366
}
Oct 8, 2012
Oct 8, 2012
367
368
if (!settings->contains("register-url")){
Jan 15, 2013
Jan 15, 2013
369
370
ssuRegisterUrl = repoUrl("register-url");
if (ssuRegisterUrl.isEmpty()){
Oct 13, 2014
Oct 13, 2014
371
setError("URL for ssu registration not set (config key 'register-url')");
Jan 15, 2013
Jan 15, 2013
372
373
return;
}
Oct 8, 2012
Oct 8, 2012
374
375
376
} else
ssuRegisterUrl = settings->value("register-url").toString();
Mar 19, 2013
Mar 19, 2013
377
QString IMEI = deviceInfo.deviceUid();
Oct 21, 2012
Oct 21, 2012
378
379
380
381
if (IMEI == ""){
setError("No valid UID available for your device. For phones: is your modem online?");
return;
}
Oct 8, 2012
Oct 8, 2012
382
383
384
385
386
387
388
389
390
391
392
393
394
395
QSslConfiguration sslConfiguration;
if (!useSslVerify())
sslConfiguration.setPeerVerifyMode(QSslSocket::VerifyNone);
sslConfiguration.setCaCertificates(QSslCertificate::fromPath(ssuCaCertificate));
request.setUrl(QUrl(QString(ssuRegisterUrl)
.arg(IMEI)
));
request.setSslConfiguration(sslConfiguration);
request.setRawHeader("Authorization", "Basic " +
QByteArray(QString("%1:%2")
.arg(username).arg(password)
May 23, 2013
May 23, 2013
396
.toLatin1()).toBase64());
Oct 8, 2012
Oct 8, 2012
397
398
399
request.setHeader(QNetworkRequest::ContentTypeHeader, "application/x-www-form-urlencoded");
QUrl form;
May 23, 2013
May 23, 2013
400
401
402
403
404
405
406
407
408
409
410
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
QUrlQuery q;
q.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
q.addQueryItem("deviceModel", deviceInfo.deviceModel());
if (!domain().isEmpty()){
q.addQueryItem("domain", domain());
}
form.setQuery(q);
#else
Oct 8, 2012
Oct 8, 2012
411
form.addQueryItem("protocolVersion", SSU_PROTOCOL_VERSION);
Mar 19, 2013
Mar 19, 2013
412
form.addQueryItem("deviceModel", deviceInfo.deviceModel());
Jan 16, 2013
Jan 16, 2013
413
414
415
if (!domain().isEmpty()){
form.addQueryItem("domain", domain());
}
May 23, 2013
May 23, 2013
416
#endif
Oct 8, 2012
Oct 8, 2012
417
Sep 13, 2013
Sep 13, 2013
418
419
ssuLog->print(LOG_DEBUG, QString("Sending request to %1")
.arg(request.url().url()));
Jan 16, 2013
Jan 16, 2013
420
Oct 8, 2012
Oct 8, 2012
421
422
QNetworkReply *reply;
Nov 4, 2012
Nov 4, 2012
423
pendingRequests++;
May 23, 2013
May 23, 2013
424
425
426
#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
reply = manager->post(request, form.query(QUrl::FullyEncoded).toStdString().c_str());
#else
Oct 8, 2012
Oct 8, 2012
427
reply = manager->post(request, form.encodedQuery());
May 23, 2013
May 23, 2013
428
#endif
Oct 8, 2012
Oct 8, 2012
429
// we could expose downloadProgress() from reply in case we want progress info
Nov 4, 2012
Nov 4, 2012
430
431
432
433
434
435
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");
Mar 19, 2013
Mar 19, 2013
436
ssuLog->print(LOG_DEBUG, QString("Trying to get SSH keys from %1").arg(request.url().toString()));
Nov 4, 2012
Nov 4, 2012
437
438
439
pendingRequests++;
manager->get(request);
}
Oct 8, 2012
Oct 8, 2012
440
441
442
}
bool Ssu::setCredentials(QDomDocument *response){
Mar 30, 2013
Mar 30, 2013
443
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 8, 2012
Oct 8, 2012
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
// 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;
}
void Ssu::setError(QString errorMessage){
errorFlag = true;
errorString = errorMessage;
Nov 4, 2012
Nov 4, 2012
489
Mar 19, 2013
Mar 19, 2013
490
491
SsuLog *ssuLog = SsuLog::instance();
Mar 11, 2013
Mar 11, 2013
492
// dump error message to systemd journal for easier debugging
Mar 19, 2013
Mar 19, 2013
493
ssuLog->print(LOG_WARNING, errorMessage);
Mar 11, 2013
Mar 11, 2013
494
Nov 4, 2012
Nov 4, 2012
495
// assume that we don't even need to wait for other pending requests,
Mar 11, 2013
Mar 11, 2013
496
// and just die. This is only relevant for CLI, which will exit after done()
Oct 8, 2012
Oct 8, 2012
497
498
499
emit done();
}
Nov 4, 2012
Nov 4, 2012
500
501
void Ssu::storeAuthorizedKeys(QByteArray data){
QDir dir;
Sep 9, 2013
Sep 9, 2013
502
SsuLog *ssuLog = SsuLog::instance();
Nov 4, 2012
Nov 4, 2012
503
Sep 9, 2013
Sep 9, 2013
504
505
506
507
508
509
510
511
512
513
514
515
516
int uid_min = getdef_num("UID_MIN", -1);
QString homePath;
if (getuid() >= uid_min){
homePath = dir.homePath();
} else if (getuid() == 0){
// place authorized_keys in the default users home when run with uid0
struct passwd *pw = getpwuid(uid_min);
if (pw == NULL){
ssuLog->print(LOG_DEBUG, QString("Unable to find password entry for uid %1")
.arg(uid_min));
return;
}
Nov 4, 2012
Nov 4, 2012
517
Sep 9, 2013
Sep 9, 2013
518
519
520
521
522
523
524
525
526
527
//homePath = QString(pw->pw_dir);
homePath = pw->pw_dir;
// use users uid/gid for creating the directories and files
setegid(pw->pw_gid);
seteuid(uid_min);
ssuLog->print(LOG_DEBUG, QString("Dropping to %1/%2 for writing authorized keys")
.arg(uid_min)
.arg(pw->pw_gid));
} else
Nov 4, 2012
Nov 4, 2012
528
529
return;
Oct 14, 2013
Oct 14, 2013
530
531
homePath = Sandbox::map(homePath);
Sep 9, 2013
Sep 9, 2013
532
533
534
if (dir.exists(homePath + "/.ssh/authorized_keys")){
ssuLog->print(LOG_DEBUG, QString(".ssh/authorized_keys already exists in %1")
.arg(homePath));
Sep 13, 2013
Sep 13, 2013
535
restoreUid();
Sep 9, 2013
Sep 9, 2013
536
537
538
539
540
541
542
return;
}
if (!dir.exists(homePath + "/.ssh"))
if (!dir.mkdir(homePath + "/.ssh")){
ssuLog->print(LOG_DEBUG, QString("Unable to create .ssh in %1")
.arg(homePath));
Sep 13, 2013
Sep 13, 2013
543
restoreUid();
Sep 9, 2013
Sep 9, 2013
544
545
return;
}
Nov 4, 2012
Nov 4, 2012
546
Sep 9, 2013
Sep 9, 2013
547
QFile::setPermissions(homePath + "/.ssh",
Nov 4, 2012
Nov 4, 2012
548
549
QFile::ReadOwner | QFile::WriteOwner | QFile::ExeOwner);
Sep 9, 2013
Sep 9, 2013
550
QFile authorizedKeys(homePath + "/.ssh/authorized_keys");
Nov 4, 2012
Nov 4, 2012
551
552
553
554
555
556
authorizedKeys.open(QIODevice::WriteOnly | QIODevice::Text | QIODevice::Truncate);
authorizedKeys.setPermissions(QFile::ReadOwner | QFile::WriteOwner);
QTextStream out(&authorizedKeys);
out << data;
out.flush();
authorizedKeys.close();
Sep 9, 2013
Sep 9, 2013
557
Sep 13, 2013
Sep 13, 2013
558
restoreUid();
Nov 4, 2012
Nov 4, 2012
559
560
}
Oct 8, 2012
Oct 8, 2012
561
void Ssu::updateCredentials(bool force){
Mar 30, 2013
Mar 30, 2013
562
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 6, 2013
Oct 6, 2013
563
SsuDeviceInfo deviceInfo;
Oct 8, 2012
Oct 8, 2012
564
565
errorFlag = false;
Mar 19, 2013
Mar 19, 2013
566
567
SsuLog *ssuLog = SsuLog::instance();
Mar 19, 2013
Mar 19, 2013
568
if (deviceInfo.deviceUid() == ""){
Oct 21, 2012
Oct 21, 2012
569
570
571
572
setError("No valid UID available for your device. For phones: is your modem online?");
return;
}
Oct 8, 2012
Oct 8, 2012
573
QString ssuCaCertificate, ssuCredentialsUrl;
Jul 6, 2013
Jul 6, 2013
574
575
ssuCaCertificate = SsuRepoManager::caCertificatePath();
if (ssuCaCertificate.isEmpty()){
Oct 13, 2014
Oct 13, 2014
576
setError("CA certificate for ssu not set ('_ca-certificate in domain')");
Oct 8, 2012
Oct 8, 2012
577
return;
Jul 6, 2013
Jul 6, 2013
578
}
Oct 8, 2012
Oct 8, 2012
579
580
if (!settings->contains("credentials-url")){
Jan 15, 2013
Jan 15, 2013
581
582
583
584
585
ssuCredentialsUrl = repoUrl("credentials-url");
if (ssuCredentialsUrl.isEmpty()){
setError("URL for credentials update not set (config key 'credentials-url')");
return;
}
Oct 8, 2012
Oct 8, 2012
586
587
588
589
590
591
592
593
594
} else
ssuCredentialsUrl = settings->value("credentials-url").toString();
if (!isRegistered()){
setError("Device is not registered.");
return;
}
if (!force){
Mar 11, 2013
Mar 11, 2013
595
// skip updating if the last update was less than 30 minutes ago
Oct 8, 2012
Oct 8, 2012
596
597
598
599
QDateTime now = QDateTime::currentDateTime();
if (settings->contains("lastCredentialsUpdate")){
QDateTime last = settings->value("lastCredentialsUpdate").toDateTime();
Mar 11, 2013
Mar 11, 2013
600
if (last >= now.addSecs(-1800)){
Mar 19, 2013
Mar 19, 2013
601
ssuLog->print(LOG_DEBUG, QString("Skipping credentials update, last update was at %1")
Mar 11, 2013
Mar 11, 2013
602
.arg(last.toString()));
Oct 8, 2012
Oct 8, 2012
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
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;
Mar 19, 2013
Mar 19, 2013
625
request.setUrl(QUrl(ssuCredentialsUrl.arg(deviceInfo.deviceUid())));
Oct 8, 2012
Oct 8, 2012
626
Mar 19, 2013
Mar 19, 2013
627
ssuLog->print(LOG_DEBUG, QString("Sending credential update request to %1")
Mar 11, 2013
Mar 11, 2013
628
.arg(request.url().toString()));
Oct 8, 2012
Oct 8, 2012
629
630
request.setSslConfiguration(sslConfiguration);
Nov 4, 2012
Nov 4, 2012
631
632
pendingRequests++;
manager->get(request);
Oct 8, 2012
Oct 8, 2012
633
634
}
Nov 9, 2013
Nov 9, 2013
635
void Ssu::updateStoreCredentials(){
Dec 23, 2014
Dec 23, 2014
636
637
638
SsuCoreConfig *settings = SsuCoreConfig::instance();
SsuLog *ssuLog = SsuLog::instance();
Nov 9, 2013
Nov 9, 2013
639
640
641
642
QDBusMessage message = QDBusMessage::createMethodCall("com.jolla.jollastore",
"/StoreClient",
"com.jolla.jollastore",
"storeCredentials");
Nov 10, 2013
Nov 10, 2013
643
QDBusPendingReply<QString, QString> reply = SsuCoreConfig::userSessionBus().asyncCall(message);
Nov 9, 2013
Nov 9, 2013
644
645
reply.waitForFinished();
if (reply.isError()) {
Dec 23, 2014
Dec 23, 2014
646
647
648
649
650
if (settings->value("ignore-credential-errors").toBool() == true){
ssuLog->print(LOG_WARNING, QString("Warning: ignore-credential-errors is set, passing auth errors down to libzypp"));
ssuLog->print(LOG_WARNING, QString("Store credentials not received. %1").arg(reply.error().message()));
} else
setError(QString("Store credentials not received. %1").arg(reply.error().message()));
Nov 9, 2013
Nov 9, 2013
651
652
653
654
655
656
657
658
} 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();
}
Nov 1, 2013
Nov 1, 2013
659
}
Oct 8, 2012
Oct 8, 2012
660
661
void Ssu::unregister(){
Mar 30, 2013
Mar 30, 2013
662
SsuCoreConfig *settings = SsuCoreConfig::instance();
Oct 8, 2012
Oct 8, 2012
663
664
665
settings->setValue("privateKey", "");
settings->setValue("certificate", "");
settings->setValue("registered", false);
Mar 22, 2013
Mar 22, 2013
666
settings->sync();
Oct 8, 2012
Oct 8, 2012
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
emit registrationStatusChanged();
}
bool Ssu::verifyResponse(QDomDocument *response){
QString action = response->elementsByTagName("action").at(0).toElement().text();
QString deviceId = response->elementsByTagName("deviceId").at(0).toElement().text();
QString protocolVersion = response->elementsByTagName("protocolVersion").at(0).toElement().text();
// compare device ids
if (protocolVersion != SSU_PROTOCOL_VERSION){
setError(
tr("Response has unsupported protocol version %1, client requires version %2")
.arg(protocolVersion)
.arg(SSU_PROTOCOL_VERSION)
);
return false;
}
return true;
}