]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blobdiff - liblightdm-qt/greeter.cpp
Load all users only when really needed
[sojka/lightdm.git] / liblightdm-qt / greeter.cpp
index ecb812e947f61342cce793a3568e6f6738c7b606..d535a02222153752947a740243ac454a6a04dde9 100644 (file)
  *
  * 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