~lightdm-team/lightdm/1.4

« back to all changes in this revision

Viewing changes to src/greeter.c

  • Committer: Robert Ancell
  • Date: 2014-03-13 02:15:38 UTC
  • Revision ID: robert.ancell@canonical.com-20140313021538-u2mxfxrrfw5u58ic
Tags: 1.4.7
Releasing 1.4.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Copyright (C) 2010-2011 Robert Ancell.
 
3
 * Author: Robert Ancell <robert.ancell@canonical.com>
 
4
 * 
 
5
 * This program is free software: you can redistribute it and/or modify it under
 
6
 * the terms of the GNU General Public License as published by the Free Software
 
7
 * Foundation, either version 3 of the License, or (at your option) any later
 
8
 * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
 
9
 * license.
 
10
 */
 
11
 
 
12
#include <config.h>
 
13
 
 
14
#include <stdlib.h>
 
15
#include <string.h>
 
16
#include <errno.h>
 
17
#include <fcntl.h>
 
18
 
 
19
#include "greeter.h"
 
20
#include "ldm-marshal.h"
 
21
#include "configuration.h"
 
22
 
 
23
enum {
 
24
    CONNECTED,
 
25
    START_AUTHENTICATION,
 
26
    START_SESSION,
 
27
    LAST_SIGNAL
 
28
};
 
29
static guint signals[LAST_SIGNAL] = { 0 };
 
30
 
 
31
struct GreeterPrivate
 
32
{
 
33
    /* Session running on */
 
34
    Session *session;
 
35
 
 
36
    /* PAM service to authenticate with */
 
37
    gchar *pam_service;
 
38
    gchar *autologin_pam_service;
 
39
 
 
40
    /* Buffer for data read from greeter */
 
41
    guint8 *read_buffer;
 
42
    gsize n_read;
 
43
  
 
44
    /* Hints for the greeter */
 
45
    GHashTable *hints;
 
46
 
 
47
    /* Default session to use */   
 
48
    gchar *default_session;
 
49
 
 
50
    /* Sequence number of current PAM session */
 
51
    guint32 authentication_sequence_number;
 
52
 
 
53
    /* Remote session name */
 
54
    gchar *remote_session;
 
55
 
 
56
    /* PAM session being constructed by the greeter */
 
57
    Session *authentication_session;
 
58
 
 
59
    /* TRUE if a user has been authenticated and the session requested to start */
 
60
    gboolean start_session;
 
61
 
 
62
    /* TRUE if can log into guest accounts */
 
63
    gboolean allow_guest;
 
64
 
 
65
    /* TRUE if logging into guest session */
 
66
    gboolean guest_account_authenticated;
 
67
 
 
68
    /* Communication channels to communicate with */
 
69
    GIOChannel *to_greeter_channel;
 
70
    GIOChannel *from_greeter_channel;
 
71
    guint from_greeter_watch;
 
72
};
 
73
 
 
74
G_DEFINE_TYPE (Greeter, greeter, G_TYPE_OBJECT);
 
75
 
 
76
/* Messages from the greeter to the server */
 
77
typedef enum
 
78
{
 
79
    GREETER_MESSAGE_CONNECT = 0,
 
80
    GREETER_MESSAGE_AUTHENTICATE,
 
81
    GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
 
82
    GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
 
83
    GREETER_MESSAGE_START_SESSION,
 
84
    GREETER_MESSAGE_CANCEL_AUTHENTICATION,
 
85
    GREETER_MESSAGE_SET_LANGUAGE,
 
86
    GREETER_MESSAGE_AUTHENTICATE_REMOTE
 
87
} GreeterMessage;
 
88
 
 
89
/* Messages from the server to the greeter */
 
90
typedef enum
 
91
{
 
92
    SERVER_MESSAGE_CONNECTED = 0,
 
93
    SERVER_MESSAGE_PROMPT_AUTHENTICATION,
 
94
    SERVER_MESSAGE_END_AUTHENTICATION,
 
95
    SERVER_MESSAGE_SESSION_RESULT
 
96
} ServerMessage;
 
97
 
 
98
static gboolean read_cb (GIOChannel *source, GIOCondition condition, gpointer data);
 
99
 
 
100
Greeter *
 
101
greeter_new (Session *session, const gchar *pam_service, const gchar *autologin_pam_service)
 
102
{
 
103
    Greeter *greeter;
 
104
 
 
105
    greeter = g_object_new (GREETER_TYPE, NULL);
 
106
    greeter->priv->session = g_object_ref (session);
 
107
    greeter->priv->pam_service = g_strdup (pam_service);
 
108
    greeter->priv->autologin_pam_service = g_strdup (autologin_pam_service);
 
109
 
 
110
    return greeter;
 
111
}
 
112
 
 
113
void
 
114
greeter_set_allow_guest (Greeter *greeter, gboolean allow_guest)
 
115
{
 
116
    greeter->priv->allow_guest = allow_guest;
 
117
}
 
118
 
 
119
void
 
120
greeter_set_hint (Greeter *greeter, const gchar *name, const gchar *value)
 
121
{
 
122
    g_hash_table_insert (greeter->priv->hints, g_strdup (name), g_strdup (value));
 
123
}
 
124
 
 
125
static guint32
 
126
int_length (void)
 
127
{
 
128
    return 4;
 
129
}
 
130
 
 
131
#define HEADER_SIZE (sizeof (guint32) * 2)
 
132
#define MAX_MESSAGE_LENGTH 1024
 
133
 
 
134
static void
 
135
write_message (Greeter *greeter, guint8 *message, gsize message_length)
 
136
{
 
137
    GError *error = NULL;
 
138
 
 
139
    g_io_channel_write_chars (greeter->priv->to_greeter_channel, (gchar *) message, message_length, NULL, &error);
 
140
    if (error)
 
141
        g_warning ("Error writing to greeter: %s", error->message);
 
142
    g_clear_error (&error);
 
143
    g_io_channel_flush (greeter->priv->to_greeter_channel, NULL);
 
144
}
 
145
 
 
146
static void
 
147
write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset)
 
148
{
 
149
    if (*offset + 4 >= buffer_length)
 
150
        return;
 
151
    buffer[*offset] = value >> 24;
 
152
    buffer[*offset+1] = (value >> 16) & 0xFF;
 
153
    buffer[*offset+2] = (value >> 8) & 0xFF;
 
154
    buffer[*offset+3] = value & 0xFF;
 
155
    *offset += 4;
 
156
}
 
157
 
 
158
static void
 
159
write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset)
 
160
{
 
161
    gint length;
 
162
  
 
163
    if (value)
 
164
        length = strlen (value);
 
165
    else
 
166
        length = 0;
 
167
    write_int (buffer, buffer_length, length, offset);
 
168
    if (*offset + length >= buffer_length)
 
169
        return;
 
170
    if (length > 0)
 
171
    {
 
172
        memcpy (buffer + *offset, value, length);
 
173
        *offset += length;
 
174
    }
 
175
}
 
176
 
 
177
static void
 
178
write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset)
 
179
{
 
180
    write_int (buffer, buffer_length, id, offset);
 
181
    write_int (buffer, buffer_length, length, offset);
 
182
}
 
183
 
 
184
static guint32
 
185
string_length (const gchar *value)
 
186
{
 
187
    if (value == NULL)
 
188
        return int_length ();
 
189
    else
 
190
        return int_length () + strlen (value);
 
191
}
 
192
 
 
193
static void
 
194
handle_connect (Greeter *greeter, const gchar *version)
 
195
{
 
196
    guint8 message[MAX_MESSAGE_LENGTH];
 
197
    gsize offset = 0;
 
198
    guint32 length;
 
199
    GHashTableIter iter;
 
200
    gpointer key, value;
 
201
 
 
202
    g_debug ("Greeter connected version=%s", version);
 
203
 
 
204
    length = string_length (VERSION);
 
205
    g_hash_table_iter_init (&iter, greeter->priv->hints);
 
206
    while (g_hash_table_iter_next (&iter, &key, &value))
 
207
        length += string_length (key) + string_length (value);
 
208
 
 
209
    write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_CONNECTED, length, &offset);
 
210
    write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset);
 
211
    g_hash_table_iter_init (&iter, greeter->priv->hints);
 
212
    while (g_hash_table_iter_next (&iter, &key, &value))
 
213
    {
 
214
        write_string (message, MAX_MESSAGE_LENGTH, key, &offset);
 
215
        write_string (message, MAX_MESSAGE_LENGTH, value, &offset);
 
216
    }
 
217
    write_message (greeter, message, offset);
 
218
 
 
219
    g_signal_emit (greeter, signals[CONNECTED], 0);
 
220
}
 
221
 
 
222
static void
 
223
pam_messages_cb (Session *session, Greeter *greeter)
 
224
{
 
225
    int i;
 
226
    guint32 size;
 
227
    guint8 message[MAX_MESSAGE_LENGTH];
 
228
    const struct pam_message *messages;
 
229
    int messages_length;
 
230
    gsize offset = 0;
 
231
    int n_prompts = 0;
 
232
 
 
233
    messages = session_get_messages (session);
 
234
    messages_length = session_get_messages_length (session);
 
235
 
 
236
    /* Respond to d-bus query with messages */
 
237
    g_debug ("Prompt greeter with %d message(s)", messages_length);
 
238
    size = int_length () + string_length (session_get_username (session)) + int_length ();
 
239
    for (i = 0; i < messages_length; i++)
 
240
        size += int_length () + string_length (messages[i].msg);
 
241
  
 
242
    write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_PROMPT_AUTHENTICATION, size, &offset);
 
243
    write_int (message, MAX_MESSAGE_LENGTH, greeter->priv->authentication_sequence_number, &offset);
 
244
    write_string (message, MAX_MESSAGE_LENGTH, session_get_username (session), &offset);
 
245
    write_int (message, MAX_MESSAGE_LENGTH, messages_length, &offset);
 
246
    for (i = 0; i < messages_length; i++)
 
247
    {
 
248
        write_int (message, MAX_MESSAGE_LENGTH, messages[i].msg_style, &offset);
 
249
        write_string (message, MAX_MESSAGE_LENGTH, messages[i].msg, &offset);
 
250
 
 
251
        if (messages[i].msg_style == PAM_PROMPT_ECHO_OFF || messages[i].msg_style == PAM_PROMPT_ECHO_ON)
 
252
            n_prompts++;
 
253
    }
 
254
    write_message (greeter, message, offset);
 
255
 
 
256
    /* Continue immediately if nothing to respond with */
 
257
    // FIXME: Should probably give the greeter a chance to ack the message
 
258
    if (n_prompts == 0)
 
259
    {
 
260
        struct pam_response *response;
 
261
        response = calloc (messages_length, sizeof (struct pam_response));
 
262
        session_respond (greeter->priv->authentication_session, response);
 
263
    }
 
264
}
 
265
 
 
266
static void
 
267
send_end_authentication (Greeter *greeter, guint32 sequence_number, const gchar *username, int result)
 
268
{
 
269
    guint8 message[MAX_MESSAGE_LENGTH];
 
270
    gsize offset = 0;
 
271
 
 
272
    write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_END_AUTHENTICATION, int_length () + string_length (username) + int_length (), &offset);
 
273
    write_int (message, MAX_MESSAGE_LENGTH, sequence_number, &offset);
 
274
    write_string (message, MAX_MESSAGE_LENGTH, username, &offset);
 
275
    write_int (message, MAX_MESSAGE_LENGTH, result, &offset);
 
276
    write_message (greeter, message, offset); 
 
277
}
 
278
 
 
279
static void
 
280
authentication_complete_cb (Session *session, Greeter *greeter)
 
281
{
 
282
    int result;
 
283
 
 
284
    g_debug ("Authenticate result for user %s: %s", session_get_username (session), session_get_authentication_result_string (session));
 
285
 
 
286
    result = session_get_authentication_result (session);
 
287
    if (session_get_is_authenticated (session))
 
288
    {
 
289
        if (session_get_user (session))
 
290
            g_debug ("User %s authorized", session_get_username (session));
 
291
        else
 
292
        {
 
293
            g_debug ("User %s authorized, but no account of that name exists", session_get_username (session));          
 
294
            result = PAM_USER_UNKNOWN;
 
295
        }
 
296
    }
 
297
 
 
298
    send_end_authentication (greeter, greeter->priv->authentication_sequence_number, session_get_username (session), result);
 
299
}
 
300
 
 
301
static void
 
302
reset_session (Greeter *greeter)
 
303
{
 
304
    g_free (greeter->priv->remote_session);
 
305
    greeter->priv->remote_session = NULL;
 
306
    if (greeter->priv->authentication_session)
 
307
    {
 
308
        g_signal_handlers_disconnect_matched (greeter->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, greeter);
 
309
        session_stop (greeter->priv->authentication_session);
 
310
        g_object_unref (greeter->priv->authentication_session);
 
311
        greeter->priv->authentication_session = NULL;
 
312
    }
 
313
 
 
314
    greeter->priv->guest_account_authenticated = FALSE;
 
315
}
 
316
 
 
317
static void
 
318
handle_login (Greeter *greeter, guint32 sequence_number, const gchar *username)
 
319
{
 
320
    const gchar *autologin_username, *service;
 
321
    gboolean is_interactive;
 
322
 
 
323
    if (username[0] == '\0')
 
324
    {
 
325
        g_debug ("Greeter start authentication");
 
326
        username = NULL;
 
327
    }
 
328
    else
 
329
        g_debug ("Greeter start authentication for %s", username);
 
330
 
 
331
    reset_session (greeter);
 
332
 
 
333
    greeter->priv->authentication_sequence_number = sequence_number;
 
334
    g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
 
335
    if (!greeter->priv->authentication_session)
 
336
    {
 
337
        send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
 
338
        return;
 
339
    }
 
340
 
 
341
    g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
 
342
    g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
 
343
 
 
344
    /* Use non-interactive service for autologin user */
 
345
    autologin_username = g_hash_table_lookup (greeter->priv->hints, "autologin-user");
 
346
    if (autologin_username != NULL && g_strcmp0 (username, autologin_username) == 0)
 
347
    {
 
348
        service = greeter->priv->autologin_pam_service;
 
349
        is_interactive = FALSE;
 
350
    }
 
351
    else
 
352
    {
 
353
        service = greeter->priv->pam_service;
 
354
        is_interactive = TRUE;
 
355
    }
 
356
 
 
357
    /* Run the session process */
 
358
    session_start (greeter->priv->authentication_session, service, username, TRUE, is_interactive, FALSE);
 
359
}
 
360
 
 
361
static void
 
362
handle_login_as_guest (Greeter *greeter, guint32 sequence_number)
 
363
{
 
364
    g_debug ("Greeter start authentication for guest account");
 
365
 
 
366
    reset_session (greeter);
 
367
 
 
368
    if (!greeter->priv->allow_guest)
 
369
    {
 
370
        g_debug ("Guest account is disabled");
 
371
        send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
 
372
        return;
 
373
    }
 
374
 
 
375
    greeter->priv->guest_account_authenticated = TRUE;  
 
376
    send_end_authentication (greeter, sequence_number, "", PAM_SUCCESS);
 
377
}
 
378
 
 
379
static gchar *
 
380
get_remote_session_service (const gchar *session_name)
 
381
{
 
382
    GKeyFile *session_desktop_file;
 
383
    gboolean result;
 
384
    const gchar *c;
 
385
    gchar *remote_sessions_dir, *filename, *path, *service = NULL;
 
386
    GError *error = NULL;
 
387
 
 
388
    /* Validate session name doesn't contain directory separators */
 
389
    for (c = session_name; *c; c++)
 
390
    {
 
391
        if (*c == '/')
 
392
            return NULL;
 
393
    }
 
394
 
 
395
    /* Load the session file */
 
396
    session_desktop_file = g_key_file_new ();
 
397
    filename = g_strdup_printf ("%s.desktop", session_name);
 
398
    remote_sessions_dir = config_get_string (config_get_instance (), "LightDM", "remote-sessions-directory");
 
399
    path = g_build_filename (remote_sessions_dir, filename, NULL);
 
400
    g_free (remote_sessions_dir);
 
401
    g_free (filename);
 
402
    result = g_key_file_load_from_file (session_desktop_file, path, G_KEY_FILE_NONE, &error);
 
403
    if (error)
 
404
        g_debug ("Failed to load session file %s: %s", path, error->message);
 
405
    g_free (path);
 
406
    g_clear_error (&error);
 
407
    if (result)
 
408
        service = g_key_file_get_string (session_desktop_file, G_KEY_FILE_DESKTOP_GROUP, "X-LightDM-PAM-Service", NULL);
 
409
    g_key_file_free (session_desktop_file);
 
410
 
 
411
    return service;
 
412
}
 
413
 
 
414
static void
 
415
handle_login_remote (Greeter *greeter, const gchar *session_name, const gchar *username, guint32 sequence_number)
 
416
{
 
417
    gchar *service;
 
418
 
 
419
    if (username[0] == '\0')
 
420
    {
 
421
        g_debug ("Greeter start authentication for remote session %s", session_name);
 
422
        username = NULL;
 
423
    }
 
424
    else
 
425
        g_debug ("Greeter start authentication for remote session %s as user %s", session_name, username);
 
426
 
 
427
    reset_session (greeter);
 
428
 
 
429
    service = get_remote_session_service (session_name);
 
430
    if (!service)
 
431
    {
 
432
        send_end_authentication (greeter, sequence_number, "", PAM_SYSTEM_ERR);
 
433
        return;
 
434
    }
 
435
 
 
436
    greeter->priv->authentication_sequence_number = sequence_number;
 
437
    greeter->priv->remote_session = g_strdup (session_name);
 
438
    g_signal_emit (greeter, signals[START_AUTHENTICATION], 0, username, &greeter->priv->authentication_session);
 
439
    if (greeter->priv->authentication_session)
 
440
    {
 
441
        g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "got-messages", G_CALLBACK (pam_messages_cb), greeter);
 
442
        g_signal_connect (G_OBJECT (greeter->priv->authentication_session), "authentication-complete", G_CALLBACK (authentication_complete_cb), greeter);
 
443
 
 
444
        /* Run the session process */
 
445
        session_start (greeter->priv->authentication_session, service, username, TRUE, TRUE, TRUE);
 
446
    }
 
447
 
 
448
    g_free (service);
 
449
 
 
450
    if (!greeter->priv->authentication_session)
 
451
    {
 
452
        send_end_authentication (greeter, sequence_number, "", PAM_USER_UNKNOWN);
 
453
        return;
 
454
    }
 
455
}
 
456
 
 
457
static void
 
458
handle_continue_authentication (Greeter *greeter, gchar **secrets)
 
459
{
 
460
    int messages_length;
 
461
    const struct pam_message *messages;
 
462
    struct pam_response *response;
 
463
    int i, j, n_prompts = 0;
 
464
 
 
465
    /* Not in authentication */
 
466
    if (greeter->priv->authentication_session == NULL)
 
467
        return;
 
468
 
 
469
    messages_length = session_get_messages_length (greeter->priv->authentication_session);
 
470
    messages = session_get_messages (greeter->priv->authentication_session);
 
471
 
 
472
    /* Check correct number of responses */
 
473
    for (i = 0; i < messages_length; i++)
 
474
    {
 
475
        int msg_style = messages[i].msg_style;
 
476
        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
 
477
            n_prompts++;
 
478
    }
 
479
    if (g_strv_length (secrets) != n_prompts)
 
480
    {
 
481
        session_respond_error (greeter->priv->authentication_session, PAM_CONV_ERR);
 
482
        return;
 
483
    }
 
484
 
 
485
    g_debug ("Continue authentication");
 
486
 
 
487
    /* Build response */
 
488
    response = calloc (messages_length, sizeof (struct pam_response));
 
489
    for (i = 0, j = 0; i < messages_length; i++)
 
490
    {
 
491
        int msg_style = messages[i].msg_style;
 
492
        if (msg_style == PAM_PROMPT_ECHO_OFF || msg_style == PAM_PROMPT_ECHO_ON)
 
493
        {
 
494
            response[i].resp = strdup (secrets[j]); // FIXME: Need to convert from UTF-8
 
495
            j++;
 
496
        }
 
497
    }
 
498
 
 
499
    session_respond (greeter->priv->authentication_session, response);
 
500
}
 
501
 
 
502
static void
 
503
handle_cancel_authentication (Greeter *greeter)
 
504
{
 
505
    /* Not in authentication */
 
506
    if (greeter->priv->authentication_session == NULL)
 
507
        return;
 
508
 
 
509
    g_debug ("Cancel authentication");
 
510
    reset_session (greeter);
 
511
}
 
512
 
 
513
static void
 
514
handle_start_session (Greeter *greeter, const gchar *session)
 
515
{
 
516
    gboolean result;
 
517
    guint8 message[MAX_MESSAGE_LENGTH];
 
518
    gsize offset = 0;
 
519
    SessionType session_type = SESSION_TYPE_LOCAL;
 
520
 
 
521
    if (strcmp (session, "") == 0)
 
522
        session = NULL;
 
523
 
 
524
    /* Use session type chosen in remote session */
 
525
    if (greeter->priv->remote_session)
 
526
    {
 
527
        session_type = SESSION_TYPE_REMOTE;
 
528
        session = greeter->priv->remote_session;
 
529
    }
 
530
 
 
531
    if (greeter->priv->guest_account_authenticated || session_get_is_authenticated (greeter->priv->authentication_session))
 
532
    {
 
533
        if (session)
 
534
            g_debug ("Greeter requests session %s", session);
 
535
        else
 
536
            g_debug ("Greeter requests default session");
 
537
        greeter->priv->start_session = TRUE;
 
538
        g_signal_emit (greeter, signals[START_SESSION], 0, session_type, session, &result);
 
539
    }
 
540
    else
 
541
    {
 
542
        g_debug ("Ignoring start session request, user is not authorized");
 
543
        result = FALSE;
 
544
    }
 
545
 
 
546
    write_header (message, MAX_MESSAGE_LENGTH, SERVER_MESSAGE_SESSION_RESULT, int_length (), &offset);
 
547
    write_int (message, MAX_MESSAGE_LENGTH, result ? 0 : 1, &offset);
 
548
    write_message (greeter, message, offset);
 
549
}
 
550
 
 
551
static void
 
552
handle_set_language (Greeter *greeter, const gchar *language)
 
553
{
 
554
    User *user;
 
555
 
 
556
    if (!greeter->priv->guest_account_authenticated && !session_get_is_authenticated (greeter->priv->authentication_session))
 
557
    {
 
558
        g_debug ("Ignoring set language request, user is not authorized");
 
559
        return;
 
560
    }
 
561
 
 
562
    // FIXME: Could use this
 
563
    if (greeter->priv->guest_account_authenticated)
 
564
    {
 
565
        g_debug ("Ignoring set language request for guest user");
 
566
        return;
 
567
    }
 
568
 
 
569
    g_debug ("Greeter sets language %s", language);
 
570
    user = session_get_user (greeter->priv->authentication_session);
 
571
    user_set_language (user, language);
 
572
}
 
573
 
 
574
static guint32
 
575
read_int (Greeter *greeter, gsize *offset)
 
576
{
 
577
    guint32 value;
 
578
    guint8 *buffer;
 
579
    if (greeter->priv->n_read - *offset < sizeof (guint32))
 
580
    {
 
581
        g_warning ("Not enough space for int, need %zu, got %zu", sizeof (guint32), greeter->priv->n_read - *offset);
 
582
        return 0;
 
583
    }
 
584
    buffer = greeter->priv->read_buffer + *offset;
 
585
    value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
 
586
    *offset += int_length ();
 
587
    return value;
 
588
}
 
589
 
 
590
static gchar *
 
591
read_string (Greeter *greeter, gsize *offset)
 
592
{
 
593
    guint32 length;
 
594
    gchar *value;
 
595
 
 
596
    length = read_int (greeter, offset);
 
597
    if (greeter->priv->n_read - *offset < length)
 
598
    {
 
599
        g_warning ("Not enough space for string, need %u, got %zu", length, greeter->priv->n_read - *offset);
 
600
        return g_strdup ("");
 
601
    }
 
602
 
 
603
    value = g_malloc (sizeof (gchar) * (length + 1));
 
604
    memcpy (value, greeter->priv->read_buffer + *offset, length);
 
605
    value[length] = '\0';
 
606
    *offset += length;
 
607
 
 
608
    return value;
 
609
}
 
610
 
 
611
static gboolean
 
612
read_cb (GIOChannel *source, GIOCondition condition, gpointer data)
 
613
{
 
614
    Greeter *greeter = data;
 
615
    gsize n_to_read, n_read, offset;
 
616
    GIOStatus status;
 
617
    int id, n_secrets, i;
 
618
    guint32 sequence_number;
 
619
    gchar *version, *username, *session_name, *language;
 
620
    gchar **secrets;
 
621
    GError *error = NULL;
 
622
 
 
623
    if (condition == G_IO_HUP)
 
624
    {
 
625
        g_debug ("Greeter closed communication channel");
 
626
        greeter->priv->from_greeter_watch = 0;
 
627
        return FALSE;
 
628
    }
 
629
  
 
630
    n_to_read = HEADER_SIZE;
 
631
    if (greeter->priv->n_read >= HEADER_SIZE)
 
632
    {
 
633
        offset = int_length ();
 
634
        n_to_read += read_int (greeter, &offset);
 
635
    }
 
636
 
 
637
    status = g_io_channel_read_chars (greeter->priv->from_greeter_channel,
 
638
                                      (gchar *) greeter->priv->read_buffer + greeter->priv->n_read,
 
639
                                      n_to_read - greeter->priv->n_read,
 
640
                                      &n_read,
 
641
                                      &error);
 
642
    if (error)
 
643
        g_warning ("Error reading from greeter: %s", error->message);
 
644
    g_clear_error (&error);
 
645
    if (status != G_IO_STATUS_NORMAL)
 
646
        return TRUE;
 
647
 
 
648
    greeter->priv->n_read += n_read;
 
649
    if (greeter->priv->n_read != n_to_read)
 
650
        return TRUE;
 
651
 
 
652
    /* If have header, rerun for content */
 
653
    if (greeter->priv->n_read == HEADER_SIZE)
 
654
    {
 
655
        gsize offset = int_length ();
 
656
        n_to_read = read_int (greeter, &offset);
 
657
        if (n_to_read > 0)
 
658
        {
 
659
            greeter->priv->read_buffer = g_realloc (greeter->priv->read_buffer, HEADER_SIZE + n_to_read);
 
660
            read_cb (source, condition, greeter);
 
661
            return TRUE;
 
662
        }
 
663
    }
 
664
  
 
665
    offset = 0;
 
666
    id = read_int (greeter, &offset);
 
667
    read_int (greeter, &offset);
 
668
    switch (id)
 
669
    {
 
670
    case GREETER_MESSAGE_CONNECT:
 
671
        version = read_string (greeter, &offset);
 
672
        handle_connect (greeter, version);
 
673
        g_free (version);
 
674
        break;
 
675
    case GREETER_MESSAGE_AUTHENTICATE:
 
676
        sequence_number = read_int (greeter, &offset);
 
677
        username = read_string (greeter, &offset);
 
678
        handle_login (greeter, sequence_number, username);
 
679
        g_free (username);
 
680
        break;
 
681
    case GREETER_MESSAGE_AUTHENTICATE_AS_GUEST:
 
682
        sequence_number = read_int (greeter, &offset);
 
683
        handle_login_as_guest (greeter, sequence_number);
 
684
        break;
 
685
    case GREETER_MESSAGE_AUTHENTICATE_REMOTE:
 
686
        sequence_number = read_int (greeter, &offset);
 
687
        session_name = read_string (greeter, &offset);
 
688
        username = read_string (greeter, &offset);
 
689
        handle_login_remote (greeter, session_name, username, sequence_number);
 
690
        break;
 
691
    case GREETER_MESSAGE_CONTINUE_AUTHENTICATION:
 
692
        n_secrets = read_int (greeter, &offset);
 
693
        secrets = g_malloc (sizeof (gchar *) * (n_secrets + 1));
 
694
        for (i = 0; i < n_secrets; i++)
 
695
            secrets[i] = read_string (greeter, &offset);
 
696
        secrets[i] = NULL;
 
697
        handle_continue_authentication (greeter, secrets);
 
698
        g_strfreev (secrets);
 
699
        break;
 
700
    case GREETER_MESSAGE_CANCEL_AUTHENTICATION:
 
701
        handle_cancel_authentication (greeter);
 
702
        break;
 
703
    case GREETER_MESSAGE_START_SESSION:
 
704
        session_name = read_string (greeter, &offset);
 
705
        handle_start_session (greeter, session_name);
 
706
        g_free (session_name);
 
707
        break;
 
708
    case GREETER_MESSAGE_SET_LANGUAGE:
 
709
        language = read_string (greeter, &offset);
 
710
        handle_set_language (greeter, language);
 
711
        g_free (language);
 
712
        break;
 
713
    default:
 
714
        g_warning ("Unknown message from greeter: %d", id);
 
715
        break;
 
716
    }
 
717
 
 
718
    greeter->priv->n_read = 0;
 
719
 
 
720
    return TRUE;
 
721
}
 
722
 
 
723
gboolean
 
724
greeter_get_guest_authenticated (Greeter *greeter)
 
725
{
 
726
    g_return_val_if_fail (greeter != NULL, FALSE);
 
727
    return greeter->priv->guest_account_authenticated;
 
728
}
 
729
 
 
730
Session *
 
731
greeter_get_authentication_session (Greeter *greeter)
 
732
{
 
733
    g_return_val_if_fail (greeter != NULL, NULL);
 
734
    return greeter->priv->authentication_session;
 
735
}
 
736
 
 
737
gboolean
 
738
greeter_get_start_session (Greeter *greeter)
 
739
{
 
740
    g_return_val_if_fail (greeter != NULL, FALSE);
 
741
    return greeter->priv->start_session;
 
742
}
 
743
 
 
744
gboolean
 
745
greeter_start (Greeter *greeter, const gchar *service, const gchar *username)
 
746
{
 
747
    int to_greeter_pipe[2], from_greeter_pipe[2];
 
748
    gboolean result = FALSE;
 
749
    gchar *value;
 
750
 
 
751
    /* Create a pipe to talk with the greeter */
 
752
    if (pipe (to_greeter_pipe) != 0 || pipe (from_greeter_pipe) != 0)
 
753
    {
 
754
        g_warning ("Failed to create pipes: %s", strerror (errno));
 
755
        return FALSE;
 
756
    }
 
757
    greeter->priv->to_greeter_channel = g_io_channel_unix_new (to_greeter_pipe[1]);
 
758
    g_io_channel_set_encoding (greeter->priv->to_greeter_channel, NULL, NULL);
 
759
    greeter->priv->from_greeter_channel = g_io_channel_unix_new (from_greeter_pipe[0]);
 
760
    g_io_channel_set_encoding (greeter->priv->from_greeter_channel, NULL, NULL);
 
761
    g_io_channel_set_buffered (greeter->priv->from_greeter_channel, FALSE);
 
762
    greeter->priv->from_greeter_watch = g_io_add_watch (greeter->priv->from_greeter_channel, G_IO_IN | G_IO_HUP, read_cb, greeter);
 
763
 
 
764
    /* Let the greeter session know how to communicate with the daemon */
 
765
    value = g_strdup_printf ("%d", from_greeter_pipe[1]);
 
766
    session_set_env (greeter->priv->session, "LIGHTDM_TO_SERVER_FD", value);
 
767
    g_free (value);
 
768
    value = g_strdup_printf ("%d", to_greeter_pipe[0]);
 
769
    session_set_env (greeter->priv->session, "LIGHTDM_FROM_SERVER_FD", value);
 
770
    g_free (value);
 
771
 
 
772
    /* Don't allow the daemon end of the pipes to be accessed in child processes */
 
773
    fcntl (to_greeter_pipe[1], F_SETFD, FD_CLOEXEC);
 
774
    fcntl (from_greeter_pipe[0], F_SETFD, FD_CLOEXEC);
 
775
 
 
776
    result = session_start (greeter->priv->session, service, username, FALSE, FALSE, FALSE);
 
777
 
 
778
    /* Close the session ends of the pipe */
 
779
    close (to_greeter_pipe[0]);
 
780
    close (from_greeter_pipe[1]);
 
781
 
 
782
    return result;
 
783
}
 
784
 
 
785
static Session *
 
786
greeter_real_start_authentication (Greeter *greeter, const gchar *username)
 
787
{
 
788
    return NULL;
 
789
}
 
790
 
 
791
static gboolean
 
792
greeter_real_start_session (Greeter *greeter, SessionType type, const gchar *session)
 
793
{
 
794
    return FALSE;
 
795
}
 
796
 
 
797
static void
 
798
greeter_init (Greeter *greeter)
 
799
{
 
800
    greeter->priv = G_TYPE_INSTANCE_GET_PRIVATE (greeter, GREETER_TYPE, GreeterPrivate);
 
801
    greeter->priv->read_buffer = g_malloc (HEADER_SIZE);
 
802
    greeter->priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
 
803
}
 
804
 
 
805
static void
 
806
greeter_finalize (GObject *object)
 
807
{
 
808
    Greeter *self;
 
809
 
 
810
    self = GREETER (object);
 
811
 
 
812
    g_signal_handlers_disconnect_matched (self->priv->session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);    
 
813
    g_object_unref (self->priv->session);
 
814
    g_free (self->priv->pam_service);
 
815
    g_free (self->priv->autologin_pam_service);
 
816
    g_free (self->priv->read_buffer);
 
817
    g_hash_table_unref (self->priv->hints);
 
818
    g_free (self->priv->remote_session);
 
819
    if (self->priv->authentication_session)
 
820
    {
 
821
        g_signal_handlers_disconnect_matched (self->priv->authentication_session, G_SIGNAL_MATCH_DATA, 0, 0, NULL, NULL, self);
 
822
        g_object_unref (self->priv->authentication_session);
 
823
    }
 
824
    if (self->priv->to_greeter_channel)
 
825
        g_io_channel_unref (self->priv->to_greeter_channel);
 
826
    if (self->priv->from_greeter_channel)
 
827
        g_io_channel_unref (self->priv->from_greeter_channel);
 
828
    if (self->priv->from_greeter_watch)
 
829
        g_source_remove (self->priv->from_greeter_watch);
 
830
 
 
831
    G_OBJECT_CLASS (greeter_parent_class)->finalize (object);
 
832
}
 
833
 
 
834
static void
 
835
greeter_class_init (GreeterClass *klass)
 
836
{
 
837
    GObjectClass *object_class = G_OBJECT_CLASS (klass);
 
838
 
 
839
    klass->start_authentication = greeter_real_start_authentication;
 
840
    klass->start_session = greeter_real_start_session;
 
841
    object_class->finalize = greeter_finalize;
 
842
 
 
843
    signals[CONNECTED] =
 
844
        g_signal_new ("connected",
 
845
                      G_TYPE_FROM_CLASS (klass),
 
846
                      G_SIGNAL_RUN_LAST,
 
847
                      G_STRUCT_OFFSET (GreeterClass, connected),
 
848
                      NULL, NULL,
 
849
                      g_cclosure_marshal_VOID__VOID,
 
850
                      G_TYPE_NONE, 0);
 
851
 
 
852
    signals[START_AUTHENTICATION] =
 
853
        g_signal_new ("start-authentication",
 
854
                      G_TYPE_FROM_CLASS (klass),
 
855
                      G_SIGNAL_RUN_LAST,
 
856
                      G_STRUCT_OFFSET (GreeterClass, start_authentication),
 
857
                      g_signal_accumulator_first_wins,
 
858
                      NULL,
 
859
                      ldm_marshal_OBJECT__STRING,
 
860
                      SESSION_TYPE, 1, G_TYPE_STRING);
 
861
 
 
862
    signals[START_SESSION] =
 
863
        g_signal_new ("start-session",
 
864
                      G_TYPE_FROM_CLASS (klass),
 
865
                      G_SIGNAL_RUN_LAST,
 
866
                      G_STRUCT_OFFSET (GreeterClass, start_session),
 
867
                      g_signal_accumulator_true_handled,
 
868
                      NULL,
 
869
                      ldm_marshal_BOOLEAN__INT_STRING,
 
870
                      G_TYPE_BOOLEAN, 2, G_TYPE_INT, G_TYPE_STRING);
 
871
 
 
872
    g_type_class_add_private (klass, sizeof (GreeterPrivate));
 
873
}