2 * Copyright (C) 2010-2011 David Edmundson
3 * Copyright (C) 2010-2011 Robert Ancell
4 * Author: David Edmundson <kde@davidedmundson.co.uk>
6 * This library is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by the Free
8 * Software Foundation; either version 3 of the License, or (at your option) any
9 * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
16 #include "sessionsmodel.h"
19 #include <security/pam_appl.h>
21 #include <QtNetwork/QHostInfo> //needed for localHostName
22 #include <QtCore/QDebug>
23 #include <QtCore/QDir>
24 #include <QtCore/QVariant>
25 #include <QtCore/QSettings>
26 #include <QtCore/QUrl>
27 #include <QtCore/QFile>
28 #include <QtCore/QHash>
29 #include <QtCore/QSocketNotifier>
30 #include <QtDBus/QDBusPendingReply>
31 #include <QtDBus/QDBusInterface>
32 #include <QtDBus/QDBusReply>
34 /* Messages from the greeter to the server */
37 GREETER_MESSAGE_CONNECT = 0,
38 GREETER_MESSAGE_LOGIN,
39 GREETER_MESSAGE_LOGIN_AS_GUEST,
40 GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
41 GREETER_MESSAGE_START_SESSION,
42 GREETER_MESSAGE_CANCEL_AUTHENTICATION
45 /* Messages from the server to the greeter */
48 SERVER_MESSAGE_CONNECTED = 0,
50 SERVER_MESSAGE_PROMPT_AUTHENTICATION,
51 SERVER_MESSAGE_END_AUTHENTICATION,
52 SERVER_MESSAGE_SESSION_FAILED,
57 using namespace QLightDM;
62 SessionsModel *sessionsModel;
64 QDBusInterface* lightdmInterface;
65 QDBusInterface* powerManagementInterface;
66 QDBusInterface* consoleKitInterface;
68 QHash<QString, QString> hints;
75 bool inAuthentication;
77 QString authenticationUser;
78 int authenticateSequenceNumber;
79 bool cancellingAuthentication;
83 Greeter::Greeter(QObject *parent) :
87 d->readBuffer = (char *)malloc (HEADER_SIZE);
89 d->sessionsModel = new SessionsModel(this);
90 d->authenticateSequenceNumber = 0;
99 static int intLength()
104 static int stringLength(QString value)
106 QByteArray a = value.toUtf8();
107 return intLength() + a.size();
110 void Greeter::writeInt(int value)
113 buffer[0] = value >> 24;
114 buffer[1] = (value >> 16) & 0xFF;
115 buffer[2] = (value >> 8) & 0xFF;
116 buffer[3] = value & 0xFF;
117 if (write(d->toServerFd, buffer, intLength()) != intLength()) {
118 qDebug() << "Error writing to server";
122 void Greeter::writeString(QString value)
124 QByteArray a = value.toUtf8();
126 if (write(d->toServerFd, a.data(), a.size()) != a.size()) {
127 qDebug() << "Error writing to server";
131 void Greeter::writeHeader(int id, int length)
137 void Greeter::flush()
139 fsync(d->toServerFd);
142 int Greeter::getPacketLength()
144 int offset = intLength();
145 return readInt(&offset);
148 int Greeter::readInt(int *offset)
150 if(d->nRead - *offset < intLength()) {
151 qDebug() << "Not enough space for int, need " << intLength() << ", got " << (d->nRead - *offset);
155 char *buffer = d->readBuffer + *offset;
156 int value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
157 *offset += intLength();
161 QString Greeter::readString(int *offset)
163 int length = readInt(offset);
164 if(d->nRead - *offset < length) {
165 qDebug() << "Not enough space for string, need " << length << ", got " << (d->nRead - *offset);
168 char *start = d->readBuffer + *offset;
170 return QString::fromUtf8(start, length);
173 void Greeter::connectToServer()
175 QDBusConnection busType = QDBusConnection::systemBus();
176 QString ldmBus(qgetenv("LDM_BUS"));
177 if(ldmBus == QLatin1String("SESSION")) {
178 busType = QDBusConnection::sessionBus();
181 d->lightdmInterface = new QDBusInterface("org.freedesktop.DisplayManager", "/org/freedesktop/DisplayManager", "org.freedesktop.DisplayManager", busType);
182 d->powerManagementInterface = new QDBusInterface("org.freedesktop.PowerManagement","/org/freedesktop/PowerManagement", "org.freedesktop.PowerManagement");
183 d->consoleKitInterface = new QDBusInterface("org.freedesktop.ConsoleKit", "/org/freedesktop/ConsoleKit/Manager", "org.freedesktop.ConsoleKit");
185 char* fd = getenv("LIGHTDM_TO_SERVER_FD");
187 qDebug() << "No LIGHTDM_TO_SERVER_FD environment variable";
190 d->toServerFd = atoi(fd);
192 qDebug() << "***connecting to server";
194 qDebug() << toServer.open(d->toServerFd, QIODevice::WriteOnly);
196 fd = getenv("LIGHTDM_FROM_SERVER_FD");
198 qDebug() << "No LIGHTDM_FROM_SERVER_FD environment variable";
201 d->fromServerFd = atoi(fd);
203 d->n = new QSocketNotifier(d->fromServerFd, QSocketNotifier::Read);
204 connect(d->n, SIGNAL(activated(int)), this, SLOT(onRead(int)));
206 qDebug() << "Connecting to display manager...";
207 writeHeader(GREETER_MESSAGE_CONNECT, stringLength(VERSION));
208 writeString(VERSION);
212 void Greeter::login(const QString &username)
214 d->inAuthentication = true;
215 d->isAuthenticated = false;
216 d->cancellingAuthentication = false;
217 d->authenticationUser = username;
218 qDebug() << "Starting authentication for user " << username << "...";
219 writeHeader(GREETER_MESSAGE_LOGIN, intLength() + stringLength(username));
220 d->authenticateSequenceNumber++;
221 writeInt(d->authenticateSequenceNumber);
222 writeString(username);
226 void Greeter::loginAsGuest()
228 d->authenticateSequenceNumber++;
229 d->inAuthentication = true;
230 d->isAuthenticated = false;
231 d->cancellingAuthentication = false;
232 d->authenticationUser = "";
233 qDebug() << "Starting authentication for guest account";
234 writeHeader(GREETER_MESSAGE_LOGIN_AS_GUEST, intLength());
235 writeInt(d->authenticateSequenceNumber);
239 void Greeter::respond(const QString &response)
241 qDebug() << "Providing response to display manager";
242 writeHeader(GREETER_MESSAGE_CONTINUE_AUTHENTICATION, intLength() + stringLength(response));
243 // FIXME: Could be multiple response required
245 writeString(response);
249 void Greeter::cancelAuthentication()
251 qDebug() << "Cancelling authentication";
252 d->cancellingAuthentication = true;
253 writeHeader(GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0);
257 bool Greeter::inAuthentication() const
259 return d->inAuthentication;
262 bool Greeter::isAuthenticated() const
264 return d->isAuthenticated;
267 QString Greeter::authenticationUser() const
269 return d->authenticationUser;
272 void Greeter::startSession(const QString &session)
274 qDebug() << "Starting session " << session;
275 writeHeader(GREETER_MESSAGE_START_SESSION, stringLength(session));
276 writeString(session);
280 void Greeter::onRead(int fd)
282 //qDebug() << "Reading from server";
284 int nToRead = HEADER_SIZE;
285 if(d->nRead >= HEADER_SIZE)
286 nToRead += getPacketLength();
289 nRead = read(fd, d->readBuffer + d->nRead, nToRead - d->nRead);
292 qDebug() << "Error reading from server";
297 qDebug() << "EOF reading from server";
301 //qDebug() << "Read " << nRead << "octets";
303 if(d->nRead != nToRead)
306 /* If have header, rerun for content */
307 if(d->nRead == HEADER_SIZE)
309 nToRead = getPacketLength();
312 d->readBuffer = (char *)realloc(d->readBuffer, HEADER_SIZE + nToRead);
319 int id = readInt(&offset);
320 int length = readInt(&offset);
321 int nMessages, sequenceNumber, returnCode;
322 QString version, username;
323 QString hintString = "";
326 case SERVER_MESSAGE_CONNECTED:
327 version = readString(&offset);
328 while (offset < length)
330 QString name = readString(&offset);
331 QString value = readString(&offset);
332 hintString.append (" ");
333 hintString.append (name);
334 hintString.append ("=");
335 hintString.append (value);
338 qDebug() << "Connected version=" << version << hintString;
342 case SERVER_MESSAGE_QUIT:
343 qDebug() << "Got quit request from server";
346 case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
347 sequenceNumber = readInt(&offset);
349 if (sequenceNumber == d->authenticateSequenceNumber &&
350 !d->cancellingAuthentication)
352 nMessages = readInt(&offset);
353 qDebug() << "Prompt user with " << nMessages << " message(s)";
354 for(int i = 0; i < nMessages; i++)
356 int msg_style = readInt (&offset);
357 QString msg = readString (&offset);
359 // FIXME: Should stop on prompts?
362 case PAM_PROMPT_ECHO_OFF:
363 case PAM_PROMPT_ECHO_ON:
364 emit showPrompt(msg);
370 emit showMessage(msg);
376 case SERVER_MESSAGE_END_AUTHENTICATION:
377 sequenceNumber = readInt(&offset);
378 returnCode = readInt(&offset);
380 if (sequenceNumber == d->authenticateSequenceNumber)
382 qDebug() << "Authentication complete with return code " << returnCode;
383 d->cancellingAuthentication = false;
384 d->isAuthenticated = (returnCode == 0);
385 if(!d->isAuthenticated) {
386 d->authenticationUser = "";
388 emit authenticationComplete(d->isAuthenticated);
389 d->inAuthentication = false;
392 qDebug () << "Ignoring end authentication with invalid sequence number " << sequenceNumber;
394 case SERVER_MESSAGE_SESSION_FAILED:
395 qDebug() << "Session failed to start";
396 emit sessionFailed();
399 qDebug() << "Unknown message from server: " << id;
405 QString Greeter::hostname() const
407 return QHostInfo::localHostName();
410 QString Greeter::defaultLanguage() const
412 return getenv("LANG");
415 QString Greeter::getHint(QString name) const
417 return d->hints.value (name);
420 QString Greeter::defaultSessionHint() const
422 return getHint ("default-session");
425 bool Greeter::hideUsersHint() const
427 return d->hints.value ("hide-users", "true") == "true";
430 bool Greeter::hasGuestAccountHint() const
432 return d->hints.value ("has-guest-account", "false") == "true";
435 QString Greeter::selectUserHint() const
437 return getHint ("select-user");
440 bool Greeter::selectGuestHint() const
442 return d->hints.value ("select-guest", "false") == "true";
445 QString Greeter::autologinUserHint() const
447 return getHint ("autologin-user");
450 bool Greeter::autologinGuestHint() const
452 return d->hints.value ("autologin-guest", "false") == "true";
455 int Greeter::autologinTimeoutHint() const
457 return d->hints.value ("autologin-timeout", "0").toInt ();
460 bool Greeter::canSuspend() const
462 QDBusReply<bool> reply = d->powerManagementInterface->call("CanSuspend");
464 return reply.value();
469 void Greeter::suspend()
471 d->powerManagementInterface->call("Suspend");
474 bool Greeter::canHibernate() const
476 QDBusReply<bool> reply = d->powerManagementInterface->call("CanHibernate");
478 return reply.value();
483 void Greeter::hibernate()
485 d->powerManagementInterface->call("Hibernate");
488 bool Greeter::canShutdown() const
490 QDBusReply<bool> reply = d->consoleKitInterface->call("CanStop");
492 return reply.value();
497 void Greeter::shutdown()
499 d->consoleKitInterface->call("stop");
502 bool Greeter::canRestart() const
504 QDBusReply<bool> reply = d->consoleKitInterface->call("CanRestart");
506 return reply.value();
511 void Greeter::restart()
513 d->consoleKitInterface->call("Restart");