~lightdm-team/lightdm/1.4

« back to all changes in this revision

Viewing changes to liblightdm-gobject/greeter.c

  • Committer: robert.ancell at canonical
  • Date: 2011-02-20 10:27:53 UTC
  • Revision ID: robert.ancell@canonical.com-20110220102753-2kehwju1amzcpoag
Use a private pipe for greeter<->server communication instead of D-Bus (needs to be fixed in liblightdm-qt)

Show diffs side-by-side

added added

removed removed

Lines of Context:
20
20
#include <libxklavier/xklavier.h>
21
21
 
22
22
#include "greeter.h"
 
23
#include "greeter-protocol.h"
23
24
 
24
25
enum {
25
26
    PROP_0,
26
 
    PROP_HOSTNAME,  
 
27
    PROP_HOSTNAME,
27
28
    PROP_NUM_USERS,
28
29
    PROP_USERS,
29
30
    PROP_DEFAULT_LANGUAGE,
42
43
};
43
44
 
44
45
enum {
 
46
    CONNECTED,
45
47
    SHOW_PROMPT,
46
48
    SHOW_MESSAGE,
47
49
    SHOW_ERROR,
58
60
 
59
61
    DBusGConnection *system_bus;
60
62
 
61
 
    DBusGProxy *display_proxy, *session_proxy, *user_proxy;
 
63
    DBusGProxy *session_proxy, *user_proxy;
 
64
 
 
65
    GIOChannel *to_server_channel, *from_server_channel;
62
66
 
63
67
    Display *display;
64
68
 
118
122
    return FALSE;
119
123
}
120
124
 
121
 
static void
122
 
quit_cb (DBusGProxy *proxy, LdmGreeter *greeter)
123
 
{
124
 
    g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
 
125
static guint32
 
126
read_int (LdmGreeter *greeter)
 
127
{
 
128
    guint32 value;
 
129
    g_io_channel_read_chars (greeter->priv->from_server_channel, (gchar *) &value, sizeof (value), NULL, NULL);
 
130
    return value;
 
131
}
 
132
 
 
133
static void
 
134
write_int (LdmGreeter *greeter, guint32 value)
 
135
{
 
136
    if (g_io_channel_write_chars (greeter->priv->to_server_channel, (const gchar *) &value, sizeof (value), NULL, NULL) != G_IO_STATUS_NORMAL)
 
137
        g_warning ("Error writing to server");
 
138
}
 
139
 
 
140
static gchar *
 
141
read_string (LdmGreeter *greeter)
 
142
{
 
143
    guint32 length;
 
144
    gchar *value;
 
145
 
 
146
    length = read_int (greeter);
 
147
    value = g_malloc (sizeof (gchar *) * (length + 1));
 
148
    g_io_channel_read_chars (greeter->priv->from_server_channel, value, length, NULL, NULL);    
 
149
    value[length] = '\0';
 
150
 
 
151
    return value;
 
152
}
 
153
 
 
154
static void
 
155
write_string (LdmGreeter *greeter, const gchar *value)
 
156
{
 
157
    write_int (greeter, strlen (value));
 
158
    g_io_channel_write_chars (greeter->priv->to_server_channel, value, -1, NULL, NULL);
 
159
}
 
160
 
 
161
static void
 
162
flush (LdmGreeter *greeter)
 
163
{
 
164
    g_io_channel_flush (greeter->priv->to_server_channel, NULL);  
 
165
}
 
166
 
 
167
static void
 
168
handle_prompt_authentication (LdmGreeter *greeter)
 
169
{
 
170
    int n_messages, i;
 
171
 
 
172
    n_messages = read_int (greeter);
 
173
    g_debug ("Prompt user with %d message(s)", n_messages);
 
174
 
 
175
    for (i = 0; i < n_messages; i++)
 
176
    {
 
177
        int msg_style;
 
178
        gchar *msg;
 
179
 
 
180
        msg_style = read_int (greeter);
 
181
        msg = read_string (greeter);
 
182
 
 
183
        // FIXME: Should stop on prompts?
 
184
        switch (msg_style)
 
185
        {
 
186
        case PAM_PROMPT_ECHO_OFF:
 
187
        case PAM_PROMPT_ECHO_ON:
 
188
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
 
189
            break;
 
190
        case PAM_ERROR_MSG:
 
191
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
 
192
            break;
 
193
        case PAM_TEXT_INFO:
 
194
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
 
195
            break;
 
196
        }
 
197
 
 
198
        g_free (msg);
 
199
    }
 
200
}
 
201
 
 
202
static gboolean
 
203
from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 
204
{
 
205
    LdmGreeter *greeter = data;
 
206
    int message, return_code;
 
207
 
 
208
    message = read_int (greeter);
 
209
    switch (message)
 
210
    {
 
211
    case GREETER_MESSAGE_CONNECTED:
 
212
        greeter->priv->theme = read_string (greeter);
 
213
        greeter->priv->default_layout = read_string (greeter);
 
214
        greeter->priv->default_session = read_string (greeter);
 
215
        greeter->priv->timed_user = read_string (greeter);
 
216
        greeter->priv->login_delay = read_int (greeter);
 
217
      
 
218
        g_debug ("Connected theme=%s default-layout=%s default-session=%s timed-user=%s login-delay=%d",
 
219
                 greeter->priv->theme,
 
220
                 greeter->priv->default_layout, greeter->priv->default_session,
 
221
                 greeter->priv->timed_user, greeter->priv->login_delay);
 
222
 
 
223
        /* Set timeout for default login */
 
224
        if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
 
225
        {
 
226
            g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
 
227
            greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
 
228
        }
 
229
        g_signal_emit (G_OBJECT (greeter), signals[CONNECTED], 0);      
 
230
        break;
 
231
    case GREETER_MESSAGE_QUIT:
 
232
        g_signal_emit (G_OBJECT (greeter), signals[QUIT], 0);
 
233
        break;
 
234
    case GREETER_MESSAGE_PROMPT_AUTHENTICATION:
 
235
        handle_prompt_authentication (greeter);
 
236
        break;
 
237
    case GREETER_MESSAGE_END_AUTHENTICATION:
 
238
        return_code = read_int (greeter);
 
239
        g_debug ("Authentication complete with return code %d", return_code);
 
240
        greeter->priv->is_authenticated = (return_code == 0);
 
241
        if (!greeter->priv->is_authenticated)
 
242
        {
 
243
            g_free (greeter->priv->authentication_user);
 
244
            greeter->priv->authentication_user = NULL;
 
245
        }
 
246
        g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
 
247
        break;
 
248
    default:
 
249
        g_warning ("Unknown message from server: %d", message);
 
250
        break;      
 
251
    }
 
252
 
 
253
    return TRUE;
125
254
}
126
255
 
127
256
/**
136
265
ldm_greeter_connect (LdmGreeter *greeter)
137
266
{
138
267
    GError *error = NULL;
139
 
    const gchar *bus_address, *object;
 
268
    const gchar *bus_address, *fd;
140
269
    DBusBusType bus_type = DBUS_BUS_SYSTEM;
141
 
    gboolean result;
142
270
 
143
271
    g_return_val_if_fail (greeter != NULL, FALSE);
144
272
 
160
288
    if (!greeter->priv->lightdm_bus)
161
289
        return FALSE;
162
290
 
163
 
    object = getenv ("LDM_DISPLAY");
164
 
    if (!object)
165
 
    {
166
 
        g_warning ("No LDM_DISPLAY enviroment variable");
167
 
        return FALSE;
168
 
    }
169
 
 
170
 
    greeter->priv->display_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
171
 
                                                              "org.lightdm.LightDisplayManager",
172
 
                                                              object,
173
 
                                                              "org.lightdm.LightDisplayManager.Greeter");
174
 
    dbus_g_proxy_add_signal (greeter->priv->display_proxy, "QuitGreeter", G_TYPE_INVALID);
175
 
    dbus_g_proxy_connect_signal (greeter->priv->display_proxy, "QuitGreeter", G_CALLBACK (quit_cb), greeter, NULL);
 
291
    fd = getenv ("LDM_TO_SERVER_FD");
 
292
    if (!fd)
 
293
    {
 
294
        g_warning ("No LDM_TO_SERVER_FD environment variable");
 
295
        return FALSE;
 
296
    }
 
297
    greeter->priv->to_server_channel = g_io_channel_unix_new (atoi (fd));
 
298
    g_io_channel_set_encoding (greeter->priv->to_server_channel, NULL, NULL);
 
299
 
 
300
    fd = getenv ("LDM_FROM_SERVER_FD");
 
301
    if (!fd)
 
302
    {
 
303
        g_warning ("No LDM_FROM_SERVER_FD environment variable");
 
304
        return FALSE;
 
305
    }
 
306
    greeter->priv->from_server_channel = g_io_channel_unix_new (atoi (fd));
 
307
    g_io_channel_set_encoding (greeter->priv->from_server_channel, NULL, NULL);
 
308
    g_io_add_watch (greeter->priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
 
309
 
176
310
    greeter->priv->session_proxy = dbus_g_proxy_new_for_name (greeter->priv->lightdm_bus,
177
311
                                                              "org.lightdm.LightDisplayManager",
178
312
                                                              "/org/lightdm/LightDisplayManager/Session",
183
317
                                                           "org.lightdm.LightDisplayManager.Users");
184
318
 
185
319
    g_debug ("Connecting to display manager...");
186
 
    result = dbus_g_proxy_call (greeter->priv->display_proxy, "Connect", &error,
187
 
                                G_TYPE_INVALID,
188
 
                                G_TYPE_STRING, &greeter->priv->theme,
189
 
                                G_TYPE_STRING, &greeter->priv->default_layout,
190
 
                                G_TYPE_STRING, &greeter->priv->default_session,
191
 
                                G_TYPE_STRING, &greeter->priv->timed_user,
192
 
                                G_TYPE_INT, &greeter->priv->login_delay,
193
 
                                G_TYPE_INVALID);
194
 
 
195
 
    if (result)
196
 
        g_debug ("Connected theme=%s default-layout=%s default-session=%s timed-user=%s login-delay=%d",
197
 
                 greeter->priv->theme,
198
 
                 greeter->priv->default_layout, greeter->priv->default_session,
199
 
                 greeter->priv->timed_user, greeter->priv->login_delay);
200
 
    else
201
 
        g_warning ("Failed to connect to display manager: %s", error->message);
202
 
    g_clear_error (&error);
203
 
    if (!result)
204
 
        return FALSE;
205
 
 
206
 
    /* Set timeout for default login */
207
 
    if (greeter->priv->timed_user[0] != '\0' && greeter->priv->login_delay > 0)
208
 
    {
209
 
        g_debug ("Logging in as %s in %d seconds", greeter->priv->timed_user, greeter->priv->login_delay);
210
 
        greeter->priv->login_timeout = g_timeout_add (greeter->priv->login_delay * 1000, timed_login_cb, greeter);
211
 
    }
212
 
 
213
 
    return result;
 
320
    write_int (greeter, GREETER_MESSAGE_CONNECT);
 
321
    flush (greeter);
 
322
 
 
323
    return TRUE;
214
324
}
215
325
 
216
326
/**
763
873
    greeter->priv->login_timeout = 0;
764
874
}
765
875
 
766
 
#define TYPE_MESSAGE dbus_g_type_get_struct ("GValueArray", G_TYPE_INT, G_TYPE_STRING, G_TYPE_INVALID)
767
 
#define TYPE_MESSAGE_LIST dbus_g_type_get_collection ("GPtrArray", TYPE_MESSAGE)
768
 
 
769
 
static void
770
 
auth_response_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer userdata)
771
 
{
772
 
    LdmGreeter *greeter = userdata;
773
 
    gboolean result;
774
 
    GError *error = NULL;
775
 
    gint return_code;
776
 
    GPtrArray *array;
777
 
    int i;
778
 
 
779
 
    result = dbus_g_proxy_end_call (proxy, call, &error, G_TYPE_INT, &return_code, TYPE_MESSAGE_LIST, &array, G_TYPE_INVALID);
780
 
    if (!result)
781
 
        g_warning ("Failed to complete StartAuthentication(): %s", error->message);
782
 
    g_clear_error (&error);
783
 
    if (!result)
784
 
        return;
785
 
 
786
 
    if (array->len > 0)
787
 
        g_debug ("Authentication continues with %d messages", array->len);
788
 
    else
789
 
        g_debug ("Authentication complete with return code %d", return_code);
790
 
 
791
 
    for (i = 0; i < array->len; i++)
792
 
    {
793
 
        GValue value = { 0 };
794
 
        gint msg_style;
795
 
        gchar *msg;
796
 
      
797
 
        g_value_init (&value, TYPE_MESSAGE);
798
 
        g_value_set_static_boxed (&value, array->pdata[i]);
799
 
        dbus_g_type_struct_get (&value, 0, &msg_style, 1, &msg, G_MAXUINT);
800
 
 
801
 
        // FIXME: Should stop on prompts?
802
 
        switch (msg_style)
803
 
        {
804
 
        case PAM_PROMPT_ECHO_OFF:
805
 
        case PAM_PROMPT_ECHO_ON:
806
 
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, msg);
807
 
            break;
808
 
        case PAM_ERROR_MSG:
809
 
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_ERROR], 0, msg);
810
 
            break;
811
 
        case PAM_TEXT_INFO:
812
 
            g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, msg);
813
 
            break;
814
 
        }
815
 
 
816
 
        g_free (msg);
817
 
 
818
 
        g_value_unset (&value);
819
 
    }
820
 
 
821
 
    if (array->len == 0)
822
 
    {
823
 
        greeter->priv->is_authenticated = (return_code == 0);
824
 
        if (!greeter->priv->is_authenticated)
825
 
        {
826
 
            g_free (greeter->priv->authentication_user);
827
 
            greeter->priv->authentication_user = NULL;
828
 
        }
829
 
        g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
830
 
    }
831
 
 
832
 
    g_ptr_array_unref (array);
833
 
}
834
 
 
835
876
/**
836
877
 * ldm_greeter_start_authentication:
837
878
 * @greeter: A #LdmGreeter
849
890
    g_free (greeter->priv->authentication_user);
850
891
    greeter->priv->authentication_user = g_strdup (username);
851
892
    g_debug ("Starting authentication for user %s...", username);
852
 
    dbus_g_proxy_begin_call (greeter->priv->display_proxy, "StartAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRING, username, G_TYPE_INVALID);
 
893
    write_int (greeter, GREETER_MESSAGE_START_AUTHENTICATION);
 
894
    write_string (greeter, username);
 
895
    flush (greeter);
853
896
}
854
897
 
855
898
/**
862
905
void
863
906
ldm_greeter_provide_secret (LdmGreeter *greeter, const gchar *secret)
864
907
{
865
 
    gchar **secrets;
866
 
 
867
908
    g_return_if_fail (LDM_IS_GREETER (greeter));
868
909
    g_return_if_fail (secret != NULL);
869
910
 
 
911
    g_debug ("Providing secret to display manager");
 
912
    write_int (greeter, GREETER_MESSAGE_CONTINUE_AUTHENTICATION);
870
913
    // FIXME: Could be multiple secrets required
871
 
    secrets = g_malloc (sizeof (char *) * 2);
872
 
    secrets[0] = g_strdup (secret);
873
 
    secrets[1] = NULL;
874
 
    g_debug ("Providing secret to display manager");  
875
 
    dbus_g_proxy_begin_call (greeter->priv->display_proxy, "ContinueAuthentication", auth_response_cb, greeter, NULL, G_TYPE_STRV, secrets, G_TYPE_INVALID);
 
914
    write_int (greeter, 1);
 
915
    write_string (greeter, secret);
 
916
    flush (greeter);
876
917
}
877
918
 
878
919
/**
929
970
void
930
971
ldm_greeter_login (LdmGreeter *greeter, const gchar *username, const gchar *session, const gchar *language)
931
972
{
932
 
    GError *error = NULL;
933
 
 
934
973
    g_return_if_fail (LDM_IS_GREETER (greeter));
935
974
    g_return_if_fail (username != NULL);
936
975
 
937
976
    g_debug ("Logging in");
938
 
    if (!dbus_g_proxy_call (greeter->priv->display_proxy, "Login", &error,
939
 
                            G_TYPE_STRING, username,
940
 
                            G_TYPE_STRING, session ? session : "",
941
 
                            G_TYPE_STRING, language ? language : "",
942
 
                            G_TYPE_INVALID,
943
 
                            G_TYPE_INVALID))
944
 
        g_warning ("Failed to login: %s", error->message);
945
 
    g_clear_error (&error);
 
977
    write_int (greeter, GREETER_MESSAGE_LOGIN);
 
978
    write_string (greeter, username);
 
979
    write_string (greeter, session ? session : "");
 
980
    write_string (greeter, language ? language : "");
 
981
    flush (greeter);
946
982
}
947
983
 
948
984
/**
1201
1237
                          GParamSpec   *pspec)
1202
1238
{
1203
1239
    LdmGreeter *self;
1204
 
    gint i, n_pages;
1205
1240
 
1206
1241
    self = LDM_GREETER (object);
1207
1242
 
1395
1430
                                                           G_PARAM_READABLE));
1396
1431
 
1397
1432
    /**
 
1433
     * LdmGreeter::connected:
 
1434
     * @greeter: A #LdmGreeter
 
1435
     * 
 
1436
     * The ::connected signal gets emitted when the greeter connects to the
 
1437
     * LightDM server.
 
1438
     **/
 
1439
    signals[CONNECTED] =
 
1440
        g_signal_new ("connected",
 
1441
                      G_TYPE_FROM_CLASS (klass),
 
1442
                      G_SIGNAL_RUN_LAST,
 
1443
                      G_STRUCT_OFFSET (LdmGreeterClass, connected),
 
1444
                      NULL, NULL,
 
1445
                      g_cclosure_marshal_VOID__VOID,
 
1446
                      G_TYPE_NONE, 0);
 
1447
 
 
1448
    /**
1398
1449
     * LdmGreeter::show-prompt:
1399
1450
     * @greeter: A #LdmGreeter
1400
1451
     * @text: Prompt text