*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation; either version 3 of the License, or (at your option) any
- * later version. See http://www.gnu.org/copyleft/lgpl.html the full text of the
- * license.
+ * Software Foundation; either version 2 or version 3 of the License.
+ * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
*/
#include "QLightDM/greeter.h"
-#include "config.h"
-
#include <QtCore/QDebug>
#include <QtCore/QDir>
#include <QtCore/QVariant>
#include <QtCore/QSettings>
-#include <QtCore/QUrl>
-#include <QtCore/QFile>
-#include <QtCore/QHash>
-#include <QtCore/QSocketNotifier>
-#include <QtDBus/QDBusPendingReply>
-#include <QtDBus/QDBusInterface>
-#include <QtDBus/QDBusReply>
-
-#include <security/pam_appl.h>
-
-
-/* Messages from the greeter to the server */
-typedef enum
-{
- GREETER_MESSAGE_CONNECT = 0,
- GREETER_MESSAGE_AUTHENTICATE,
- GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
- GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
- GREETER_MESSAGE_START_SESSION,
- GREETER_MESSAGE_CANCEL_AUTHENTICATION,
- GREETER_MESSAGE_SET_LANGUAGE
-} GreeterMessage;
-
-/* Messages from the server to the greeter */
-typedef enum
-{
- SERVER_MESSAGE_CONNECTED = 0,
- SERVER_MESSAGE_PROMPT_AUTHENTICATION,
- SERVER_MESSAGE_END_AUTHENTICATION,
- SERVER_MESSAGE_SESSION_RESULT
-} ServerMessage;
-#define HEADER_SIZE 8
+#include <lightdm.h>
using namespace QLightDM;
-class GreeterPrivate
+class QLightDM::GreeterPrivate
{
public:
- QHash<QString, QString> hints;
- int toServerFd;
- int fromServerFd;
- QSocketNotifier *n;
- char *readBuffer;
- int nRead;
- bool inAuthentication;
- bool isAuthenticated;
- QString authenticationUser;
- int authenticateSequenceNumber;
- bool cancellingAuthentication;
-
- void writeInt(int value);
- void writeString(QString value);
- void writeHeader(int id, int length);
- void flush();
- char *readMessage(int *length, bool block);
+ GreeterPrivate(Greeter *parent);
+ LightDMGreeter *ldmGreeter;
+protected:
+ Greeter* q_ptr;
+
+ static void cb_showPrompt(LightDMGreeter *greeter, const gchar *text, LightDMPromptType type, gpointer data);
+ static void cb_showMessage(LightDMGreeter *greeter, const gchar *text, LightDMMessageType type, gpointer data);
+ static void cb_authenticationComplete(LightDMGreeter *greeter, gpointer data);
+ static void cb_autoLoginExpired(LightDMGreeter *greeter, gpointer data);
+ static void cb_idle(LightDMGreeter *greeter, gpointer data);
+ static void cb_reset(LightDMGreeter *greeter, gpointer data);
+
+private:
+ Q_DECLARE_PUBLIC(Greeter)
};
-Greeter::Greeter(QObject *parent) :
- QObject(parent),
- d(new GreeterPrivate)
+GreeterPrivate::GreeterPrivate(Greeter *parent) :
+ q_ptr(parent)
{
- d->readBuffer = (char *)malloc(HEADER_SIZE);
- d->nRead = 0;
- d->authenticateSequenceNumber = 0;
-}
+#if !defined(GLIB_VERSION_2_36)
+ g_type_init();
+#endif
+ ldmGreeter = lightdm_greeter_new();
-Greeter::~Greeter()
-{
- delete d->readBuffer;
- delete d;
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT, G_CALLBACK (cb_showPrompt), this);
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE, G_CALLBACK (cb_showMessage), this);
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE, G_CALLBACK (cb_authenticationComplete), this);
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED, G_CALLBACK (cb_autoLoginExpired), this);
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_IDLE, G_CALLBACK (cb_idle), this);
+ g_signal_connect (ldmGreeter, LIGHTDM_GREETER_SIGNAL_RESET, G_CALLBACK (cb_reset), this);
}
-static int intLength()
+void GreeterPrivate::cb_showPrompt(LightDMGreeter *greeter, const gchar *text, LightDMPromptType type, gpointer data)
{
- return 4;
+ Q_UNUSED(greeter);
+
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ QString message = QString::fromUtf8(text);
+
+ Q_EMIT that->q_func()->showPrompt(message, type == LIGHTDM_PROMPT_TYPE_QUESTION ?
+ Greeter::PromptTypeQuestion : Greeter::PromptTypeSecret);
}
-static int stringLength(QString value)
+void GreeterPrivate::cb_showMessage(LightDMGreeter *greeter, const gchar *text, LightDMMessageType type, gpointer data)
{
- QByteArray a = value.toUtf8();
- return intLength() + a.size();
+ Q_UNUSED(greeter);
+
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ QString message = QString::fromUtf8(text);
+
+ Q_EMIT that->q_func()->showMessage(message, type == LIGHTDM_MESSAGE_TYPE_INFO ?
+ Greeter::MessageTypeInfo : Greeter::MessageTypeError);
}
-void GreeterPrivate::writeInt(int value)
+void GreeterPrivate::cb_authenticationComplete(LightDMGreeter *greeter, gpointer data)
{
- char buffer[4];
- buffer[0] = value >> 24;
- buffer[1] = (value >> 16) & 0xFF;
- buffer[2] = (value >> 8) & 0xFF;
- buffer[3] = value & 0xFF;
- if (write(toServerFd, buffer, intLength()) != intLength()) {
- qDebug() << "Error writing to server";
- }
+ Q_UNUSED(greeter);
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ Q_EMIT that->q_func()->authenticationComplete();
}
-void GreeterPrivate::writeString(QString value)
+void GreeterPrivate::cb_autoLoginExpired(LightDMGreeter *greeter, gpointer data)
{
- QByteArray a = value.toUtf8();
- writeInt(a.size());
- if (write(toServerFd, a.data(), a.size()) != a.size()) {
- qDebug() << "Error writing to server";
- }
+ Q_UNUSED(greeter);
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ Q_EMIT that->q_func()->autologinTimerExpired();
}
-void GreeterPrivate::writeHeader(int id, int length)
+void GreeterPrivate::cb_idle(LightDMGreeter *greeter, gpointer data)
{
- writeInt(id);
- writeInt(length);
+ Q_UNUSED(greeter);
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ Q_EMIT that->q_func()->idle();
}
-void GreeterPrivate::flush()
+void GreeterPrivate::cb_reset(LightDMGreeter *greeter, gpointer data)
{
- fsync(toServerFd);
+ Q_UNUSED(greeter);
+ GreeterPrivate *that = static_cast<GreeterPrivate*>(data);
+ Q_EMIT that->q_func()->reset();
}
-static int readInt(char *message, int messageLength, int *offset)
+Greeter::Greeter(QObject *parent) :
+ QObject(parent),
+ d_ptr(new GreeterPrivate(this))
{
- if(messageLength - *offset < intLength()) {
- qDebug() << "Not enough space for int, need " << intLength() << ", got " << (messageLength - *offset);
- return 0;
- }
-
- char *buffer = message + *offset;
- int value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
- *offset += intLength();
- return value;
}
-static int getMessageLength(char *message, int messageLength)
+Greeter::~Greeter()
{
- int offset = intLength();
- return readInt(message, messageLength, &offset);
+ delete d_ptr;
}
-static QString readString(char *message, int messageLength, int *offset)
+
+bool Greeter::connectToDaemonSync()
{
- int length = readInt(message, messageLength, offset);
- if(messageLength - *offset < length) {
- qDebug() << "Not enough space for string, need " << length << ", got " << (messageLength - *offset);
- return "";
- }
- char *start = message + *offset;
- *offset += length;
- return QString::fromUtf8(start, length);
+ Q_D(Greeter);
+ return lightdm_greeter_connect_to_daemon_sync(d->ldmGreeter, NULL);
}
bool Greeter::connectSync()
{
- QDBusConnection busType = QDBusConnection::systemBus();
- QString ldmBus(qgetenv("LIGHTDM_BUS"));
- if(ldmBus == QLatin1String("SESSION")) {
- busType = QDBusConnection::sessionBus();
- }
-
- char* fd = getenv("LIGHTDM_TO_SERVER_FD");
- if(!fd) {
- qDebug() << "No LIGHTDM_TO_SERVER_FD environment variable";
- return false;
- }
- d->toServerFd = atoi(fd);
-
- qDebug() << "***connecting to server";
- QFile toServer;
- qDebug() << toServer.open(d->toServerFd, QIODevice::WriteOnly);
-
- fd = getenv("LIGHTDM_FROM_SERVER_FD");
- if(!fd) {
- qDebug() << "No LIGHTDM_FROM_SERVER_FD environment variable";
- return false;
- }
- d->fromServerFd = atoi(fd);
-
- d->n = new QSocketNotifier(d->fromServerFd, QSocketNotifier::Read);
- connect(d->n, SIGNAL(activated(int)), this, SLOT(onRead(int)));
-
- qDebug() << "Connecting to display manager...";
- d->writeHeader(GREETER_MESSAGE_CONNECT, stringLength(VERSION));
- d->writeString(VERSION);
- d->flush();
-
- int responseLength;
- char *response = d->readMessage(&responseLength, false);
- if (!response)
- return false;
-
- int offset = 0;
- int id = readInt(response, responseLength, &offset);
- int length = readInt(response, responseLength, &offset);
- bool connected = false;
- if (id == SERVER_MESSAGE_CONNECTED)
- {
- QString version = readString(response, responseLength, &offset);
- QString hintString = "";
- while (offset < length)
- {
- QString name = readString(response, responseLength, &offset);
- QString value = readString(response, responseLength, &offset);
- hintString.append (" ");
- hintString.append (name);
- hintString.append ("=");
- hintString.append (value);
- }
-
- qDebug() << "Connected version=" << version << hintString;
- connected = true;
- }
- else
- qDebug() << "Expected CONNECTED message, got " << id;
- free(response);
-
- return connected;
+ Q_D(Greeter);
+ return lightdm_greeter_connect_to_daemon_sync(d->ldmGreeter, NULL);
}
void Greeter::authenticate(const QString &username)
{
- d->inAuthentication = true;
- d->isAuthenticated = false;
- d->cancellingAuthentication = false;
- d->authenticationUser = username;
- qDebug() << "Starting authentication for user " << username << "...";
- d->writeHeader(GREETER_MESSAGE_AUTHENTICATE, intLength() + stringLength(username));
- d->authenticateSequenceNumber++;
- d->writeInt(d->authenticateSequenceNumber);
- d->writeString(username);
- d->flush();
+ Q_D(Greeter);
+ lightdm_greeter_authenticate(d->ldmGreeter, username.toLocal8Bit().data(), NULL);
}
void Greeter::authenticateAsGuest()
{
- d->authenticateSequenceNumber++;
- d->inAuthentication = true;
- d->isAuthenticated = false;
- d->cancellingAuthentication = false;
- d->authenticationUser = "";
- qDebug() << "Starting authentication for guest account";
- d->writeHeader(GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, intLength());
- d->writeInt(d->authenticateSequenceNumber);
- d->flush();
+ Q_D(Greeter);
+ lightdm_greeter_authenticate_as_guest(d->ldmGreeter, NULL);
+}
+
+void Greeter::authenticateAutologin()
+{
+ Q_D(Greeter);
+ lightdm_greeter_authenticate_autologin(d->ldmGreeter, NULL);
+}
+
+void Greeter::authenticateRemote(const QString &session, const QString &username)
+{
+ Q_D(Greeter);
+ lightdm_greeter_authenticate_remote(d->ldmGreeter, session.toLocal8Bit().data(), username.toLocal8Bit().data(), NULL);
}
void Greeter::respond(const QString &response)
{
- qDebug() << "Providing response to display manager";
- d->writeHeader(GREETER_MESSAGE_CONTINUE_AUTHENTICATION, intLength() + stringLength(response));
- // FIXME: Could be multiple response required
- d->writeInt(1);
- d->writeString(response);
- d->flush();
+ Q_D(Greeter);
+ lightdm_greeter_respond(d->ldmGreeter, response.toLocal8Bit().data(), NULL);
}
void Greeter::cancelAuthentication()
{
- qDebug() << "Cancelling authentication";
- d->cancellingAuthentication = true;
- d->writeHeader(GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0);
- d->flush();
+ Q_D(Greeter);
+ lightdm_greeter_cancel_authentication(d->ldmGreeter, NULL);
+}
+
+void Greeter::cancelAutologin()
+{
+ Q_D(Greeter);
+ lightdm_greeter_cancel_autologin(d->ldmGreeter);
}
bool Greeter::inAuthentication() const
{
- return d->inAuthentication;
+ Q_D(const Greeter);
+ return lightdm_greeter_get_in_authentication(d->ldmGreeter);
}
bool Greeter::isAuthenticated() const
{
- return d->isAuthenticated;
+ Q_D(const Greeter);
+ return lightdm_greeter_get_is_authenticated(d->ldmGreeter);
}
QString Greeter::authenticationUser() const
{
- return d->authenticationUser;
+ Q_D(const Greeter);
+ return QString::fromUtf8(lightdm_greeter_get_authentication_user(d->ldmGreeter));
+}
+
+void Greeter::setLanguage (const QString &language)
+{
+ Q_D(Greeter);
+ lightdm_greeter_set_language(d->ldmGreeter, language.toLocal8Bit().constData(), NULL);
}
-void Greeter::setLanguage (QString language)
+void Greeter::setResettable (bool resettable)
{
- d->writeHeader(GREETER_MESSAGE_SET_LANGUAGE, stringLength(language));
- d->writeString (language);
- d->flush();
+ Q_D(Greeter);
+ lightdm_greeter_set_resettable(d->ldmGreeter, resettable);
}
bool Greeter::startSessionSync(const QString &session)
{
- if (session.isEmpty()) {
- qDebug() << "Starting default session";
- }
- else {
- qDebug() << "Starting session " << session;
- }
-
- d->writeHeader(GREETER_MESSAGE_START_SESSION, stringLength(session));
- d->writeString(session);
- d->flush();
-
- int responseLength;
- char *response = d->readMessage(&responseLength, false);
- if (!response) {
- return false;
- }
-
- int offset = 0;
- int id = readInt(response, responseLength, &offset);
- readInt(response, responseLength, &offset);
- int returnCode = -1;
- if (id == SERVER_MESSAGE_SESSION_RESULT) {
- returnCode = readInt(response, responseLength, &offset);
- }
- else {
- qDebug() << "Expected SESSION_RESULT message, got " << id;
- }
- free(response);
-
- return returnCode == 0;
-}
-
-char* GreeterPrivate::readMessage(int *length, bool block)
-{
- /* Read the header, or the whole message if we already have that */
- int nToRead = HEADER_SIZE;
- if(nRead >= HEADER_SIZE) {
- nToRead += getMessageLength(readBuffer, nRead);
- }
-
- do {
- ssize_t nRead = read(fromServerFd, readBuffer + nRead, nToRead - nRead);
- if(nRead < 0) {
- qDebug() << "Error reading from server";
- return NULL;
- }
-
- if (nRead == 0) {
- qDebug() << "EOF reading from server";
- return NULL;
- }
-
- qDebug() << "Read " << nRead << " octets from daemon";
- nRead += nRead;
- } while(nRead < nToRead && block);
-
- /* Stop if haven't got all the data we want */
- if(nRead != nToRead) {
- return NULL;
- }
-
- /* If have header, rerun for content */
- if(nRead == HEADER_SIZE) {
- nToRead = getMessageLength(readBuffer, nRead);
- if(nToRead > 0) {
- readBuffer = (char *)realloc(readBuffer, HEADER_SIZE + nToRead);
- return readMessage(length, block);
- }
- }
-
- char *buffer = readBuffer;
- *length = nRead;
-
- readBuffer = (char *)malloc(nRead);
- nRead = 0;
-
- return buffer;
-}
-
-void Greeter::onRead(int fd)
-{
- qDebug() << "Reading from server";
-
- int messageLength;
- char *message = d->readMessage(&messageLength, false);
- if (!message) {
- return;
- }
-
- int offset = 0;
- int id = readInt(message, messageLength, &offset);
- int length = readInt(message, messageLength, &offset);
- int nMessages, sequenceNumber, returnCode;
- QString version, username;
- switch(id) {
- case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
- sequenceNumber = readInt(message, messageLength, &offset);
- username = readString(message, messageLength, &offset);
-
- d->authenticationUser = username;
-
- if (sequenceNumber == d->authenticateSequenceNumber &&
- !d->cancellingAuthentication)
- {
- nMessages = readInt(message, messageLength, &offset);
- qDebug() << "Prompt user with " << nMessages << " message(s)";
- for(int i = 0; i < nMessages; i++)
- {
- int style = readInt(message, messageLength, &offset);
- QString text = readString(message, messageLength, &offset);
-
- // FIXME: Should stop on prompts?
- switch (style)
- {
- case PAM_PROMPT_ECHO_OFF:
- emit showPrompt(text, Greeter::PromptTypeSecret);
- break;
- case PAM_PROMPT_ECHO_ON:
- emit showPrompt(text, Greeter::PromptTypeQuestion);
- break;
- case PAM_ERROR_MSG:
- emit showMessage(text, Greeter::MessageTypeError);
- break;
- case PAM_TEXT_INFO:
- emit showMessage(text, Greeter::MessageTypeInfo);
- break;
- }
- }
- }
- break;
- case SERVER_MESSAGE_END_AUTHENTICATION:
- sequenceNumber = readInt(message, messageLength, &offset);
- username = readString(message, messageLength, &offset);
- returnCode = readInt(message, messageLength, &offset);
-
- if (sequenceNumber == d->authenticateSequenceNumber)
- {
- qDebug() << "Authentication complete with return code " << returnCode;
-
- d->cancellingAuthentication = false;
- d->isAuthenticated = (returnCode == 0);
- d->authenticationUser = username;
- d->inAuthentication = false;
- emit authenticationComplete();
- }
- else
- qDebug () << "Ignoring end authentication with invalid sequence number " << sequenceNumber;
- break;
- default:
- qDebug() << "Unknown message from server: " << id;
- }
- free(message);
-}
-
-QString Greeter::getHint(QString name) const
-{
- return d->hints.value (name);
+ Q_D(Greeter);
+ return lightdm_greeter_start_session_sync(d->ldmGreeter, session.toLocal8Bit().constData(), NULL);
+}
+
+QString Greeter::ensureSharedDataDirSync(const QString &username)
+{
+ Q_D(Greeter);
+ return QString::fromUtf8(lightdm_greeter_ensure_shared_data_dir_sync(d->ldmGreeter, username.toLocal8Bit().constData(), NULL));
+}
+
+
+QString Greeter::getHint(const QString &name) const
+{
+ Q_D(const Greeter);
+ return lightdm_greeter_get_hint(d->ldmGreeter, name.toLocal8Bit().constData());
}
QString Greeter::defaultSessionHint() const
{
- return getHint ("default-session");
+ Q_D(const Greeter);
+ return QString::fromUtf8(lightdm_greeter_get_default_session_hint(d->ldmGreeter));
}
bool Greeter::hideUsersHint() const
{
- return d->hints.value ("hide-users", "true") == "true";
+ Q_D(const Greeter);
+ return lightdm_greeter_get_hide_users_hint(d->ldmGreeter);
+}
+
+bool Greeter::showManualLoginHint() const
+{
+ Q_D(const Greeter);
+ return lightdm_greeter_get_show_manual_login_hint(d->ldmGreeter);
+}
+
+bool Greeter::showRemoteLoginHint() const
+{
+ Q_D(const Greeter);
+ return lightdm_greeter_get_show_remote_login_hint(d->ldmGreeter);
+}
+
+bool Greeter::lockHint() const
+{
+ Q_D(const Greeter);
+ return lightdm_greeter_get_lock_hint(d->ldmGreeter);
}
bool Greeter::hasGuestAccountHint() const
{
- return d->hints.value ("has-guest-account", "false") == "true";
+ Q_D(const Greeter);
+ return lightdm_greeter_get_has_guest_account_hint(d->ldmGreeter);
}
QString Greeter::selectUserHint() const
{
- return getHint ("select-user");
+ Q_D(const Greeter);
+ return QString::fromUtf8(lightdm_greeter_get_select_user_hint(d->ldmGreeter));
}
bool Greeter::selectGuestHint() const
{
- return d->hints.value ("select-guest", "false") == "true";
+ Q_D(const Greeter);
+ return lightdm_greeter_get_select_guest_hint(d->ldmGreeter);
}
QString Greeter::autologinUserHint() const
{
- return getHint ("autologin-user");
+ Q_D(const Greeter);
+ return QString::fromUtf8(lightdm_greeter_get_autologin_user_hint(d->ldmGreeter));
}
bool Greeter::autologinGuestHint() const
{
- return d->hints.value ("autologin-guest", "false") == "true";
+ Q_D(const Greeter);
+ return lightdm_greeter_get_autologin_guest_hint(d->ldmGreeter);
}
int Greeter::autologinTimeoutHint() const
{
- return d->hints.value ("autologin-timeout", "0").toInt ();
+ Q_D(const Greeter);
+ return lightdm_greeter_get_autologin_timeout_hint(d->ldmGreeter);
+}
+
+QString Greeter::hostname() const
+{
+ return QString::fromUtf8(lightdm_get_hostname());
}
-#include "greeter_moc.cpp"
+#if QT_VERSION >= QT_VERSION_CHECK(5, 0, 0)
+#include "greeter_moc5.cpp"
+#else
+#include "greeter_moc4.cpp"
+#endif