1 /*
2  * Copyright (C) 2010 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This library is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Lesser General Public License as published by the Free
7  * Software Foundation; either version 2 or version 3 of the License.
8  * See http://www.gnu.org/copyleft/lgpl.html the full text of the license.
9  */
10 
11 #include <config.h>
12 
13 #include <stdlib.h>
14 #include <string.h>
15 #include <gio/gio.h>
16 #include <gio/gunixsocketaddress.h>
17 #include <security/pam_appl.h>
18 
19 #include "lightdm/greeter.h"
20 
21 /**
22  * SECTION:greeter
23  * @short_description: Make a connection to the LightDM daemon and authenticate users
24  * @include: lightdm.h
25  *
26  * #LightDMGreeter is an object that manages the connection to the LightDM server and provides common greeter functionality.
27  *
28  * An example of a simple greeter:
29  * |[
30  * int main ()
31  * {
32  *     GMainLoop *main_loop;
33  *     LightDMGreeter *greeter
34  *
35  *     main_loop = g_main_loop_new ();
36  *
37  *     greeter = lightdm_greeter_new ();
38  *     g_object_connect (greeter, "show-prompt", G_CALLBACK (show_prompt_cb), NULL);
39  *     g_object_connect (greeter, "authentication-complete", G_CALLBACK (authentication_complete_cb), NULL);
40  *
41  *     // Connect to LightDM daemon
42  *     if (!lightdm_greeter_connect_to_daemon_sync (greeter, NULL))
43  *         return EXIT_FAILURE;
44  *
45  *     // Start authentication
46  *     lightdm_greeter_authenticate (greeter, NULL);
47  *
48  *     g_main_loop_run (main_loop);
49  *
50  *     return EXIT_SUCCESS;
51  * }
52  *
53  * static void show_prompt_cb (LightDMGreeter *greeter, const char *text, LightDMPromptType type)
54  * {
55  *     // Show the user the message and prompt for some response
56  *     gchar *secret = prompt_user (text, type);
57  *
58  *     // Give the result to the user
59  *     lightdm_greeter_respond (greeter, response);
60  * }
61  *
62  * static void authentication_complete_cb (LightDMGreeter *greeter)
63  * {
64  *     // Start the session
65  *     if (!lightdm_greeter_get_is_authenticated (greeter) ||
66  *         !lightdm_greeter_start_session_sync (greeter, NULL))
67  *     {
68  *         // Failed authentication, try again
69  *         lightdm_greeter_authenticate (greeter, NULL);
70  *     }
71  * }
72  * ]|
73  */
74 
75 /**
76  * LightDMGreeter:
77  *
78  * #LightDMGreeter is an opaque data structure and can only be accessed
79  * using the provided functions.
80  */
81 
82 /**
83  * LightDMGreeterClass:
84  *
85  * Class structure for #LightDMGreeter.
86  */
87 
88 G_DEFINE_QUARK (lightdm_greeter_error, lightdm_greeter_error)
89 
90 enum {
91     PROP_DEFAULT_SESSION_HINT = 1,
92     PROP_HIDE_USERS_HINT,
93     PROP_SHOW_MANUAL_LOGIN_HINT,
94     PROP_SHOW_REMOTE_LOGIN_HINT,
95     PROP_LOCK_HINT,
96     PROP_HAS_GUEST_ACCOUNT_HINT,
97     PROP_SELECT_USER_HINT,
98     PROP_SELECT_GUEST_HINT,
99     PROP_AUTOLOGIN_USER_HINT,
100     PROP_AUTOLOGIN_GUEST_HINT,
101     PROP_AUTOLOGIN_TIMEOUT_HINT,
102     PROP_AUTHENTICATION_USER,
103     PROP_IN_AUTHENTICATION,
104     PROP_IS_AUTHENTICATED,
105     PROP_AUTOLOGIN_SESSION_HINT,
106 };
107 
108 enum {
109     SHOW_PROMPT,
110     SHOW_MESSAGE,
111     AUTHENTICATION_COMPLETE,
112     AUTOLOGIN_TIMER_EXPIRED,
113     IDLE,
114     RESET,
115     LAST_SIGNAL
116 };
117 static guint signals[LAST_SIGNAL] = { 0 };
118 
119 typedef struct
120 {
121     /* API version the daemon is using */
122     guint32 api_version;
123 
124     /* TRUE if the daemon can reuse this greeter */
125     gboolean resettable;
126 
127     /* Socket connection to daemon */
128     GSocket *socket;
129 
130     /* Channel to write to daemon */
131     GIOChannel *to_server_channel;
132 
133     /* Channel to read from daemon */
134     GIOChannel *from_server_channel;
135     guint from_server_watch;
136 
137     /* Data read from the daemon */
138     guint8 *read_buffer;
139     gsize n_read;
140 
141     gsize n_responses_waiting;
142     GList *responses_received;
143 
144     /* TRUE if have got a connect response */
145     gboolean connected;
146 
147     /* Pending connect requests */
148     GList *connect_requests;
149 
150     /* Pending start session requests */
151     GList *start_session_requests;
152 
153     /* Pending ensure shared data dir requests */
154     GList *ensure_shared_data_dir_requests;
155 
156     /* Hints provided by the daemon */
157     GHashTable *hints;
158 
159     /* Timeout source to notify greeter to autologin */
160     guint autologin_timeout;
161 
162     gchar *authentication_user;
163     gboolean in_authentication;
164     gboolean is_authenticated;
165     guint32 authenticate_sequence_number;
166     gboolean cancelling_authentication;
167 } LightDMGreeterPrivate;
168 
169 G_DEFINE_TYPE_WITH_PRIVATE (LightDMGreeter, lightdm_greeter, G_TYPE_OBJECT)
170 
171 #define GET_PRIVATE(obj) G_TYPE_INSTANCE_GET_PRIVATE ((obj), LIGHTDM_TYPE_GREETER, LightDMGreeterPrivate)
172 
173 #define HEADER_SIZE 8
174 #define MAX_MESSAGE_LENGTH 1024
175 #define API_VERSION 1
176 
177 /* Messages from the greeter to the server */
178 typedef enum
179 {
180     GREETER_MESSAGE_CONNECT = 0,
181     GREETER_MESSAGE_AUTHENTICATE,
182     GREETER_MESSAGE_AUTHENTICATE_AS_GUEST,
183     GREETER_MESSAGE_CONTINUE_AUTHENTICATION,
184     GREETER_MESSAGE_START_SESSION,
185     GREETER_MESSAGE_CANCEL_AUTHENTICATION,
186     GREETER_MESSAGE_SET_LANGUAGE,
187     GREETER_MESSAGE_AUTHENTICATE_REMOTE,
188     GREETER_MESSAGE_ENSURE_SHARED_DIR,
189 } GreeterMessage;
190 
191 /* Messages from the server to the greeter */
192 typedef enum
193 {
194     SERVER_MESSAGE_CONNECTED = 0,
195     SERVER_MESSAGE_PROMPT_AUTHENTICATION,
196     SERVER_MESSAGE_END_AUTHENTICATION,
197     SERVER_MESSAGE_SESSION_RESULT,
198     SERVER_MESSAGE_SHARED_DIR_RESULT,
199     SERVER_MESSAGE_IDLE,
200     SERVER_MESSAGE_RESET,
201     SERVER_MESSAGE_CONNECTED_V2,
202 } ServerMessage;
203 
204 /* Request sent to server */
205 typedef struct
206 {
207     GObject parent_instance;
208     LightDMGreeter *greeter;
209     GCancellable *cancellable;
210     GAsyncReadyCallback callback;
211     gpointer user_data;
212     gboolean complete;
213     gboolean result;
214     GError *error;
215     gchar *dir;
216 } Request;
217 typedef struct
218 {
219     GObjectClass parent_class;
220 } RequestClass;
221 GType request_get_type (void);
222 static void request_iface_init (GAsyncResultIface *iface);
223 #define REQUEST(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), request_get_type (), Request))
224 G_DEFINE_TYPE_WITH_CODE (Request, request, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ASYNC_RESULT, request_iface_init))
225 
226 static gboolean from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data);
227 
228 GType
lightdm_greeter_error_get_type(void)229 lightdm_greeter_error_get_type (void)
230 {
231     static GType enum_type = 0;
232 
233     if (G_UNLIKELY(enum_type == 0)) {
234         static const GEnumValue values[] = {
235             { LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR, "LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR", "communication-error" },
236             { LIGHTDM_GREETER_ERROR_CONNECTION_FAILED, "LIGHTDM_GREETER_ERROR_CONNECTION_FAILED", "connection-failed" },
237             { LIGHTDM_GREETER_ERROR_SESSION_FAILED, "LIGHTDM_GREETER_ERROR_SESSION_FAILED", "session-failed" },
238             { LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN, "LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN", "no-autologin" },
239             { LIGHTDM_GREETER_ERROR_INVALID_USER, "LIGHTDM_GREETER_ERROR_INVALID_USER", "invalid-user" },
240             { 0, NULL, NULL }
241         };
242         enum_type = g_enum_register_static (g_intern_static_string ("LightDMGreeterError"), values);
243     }
244 
245     return enum_type;
246 }
247 
248 GType
lightdm_prompt_type_get_type(void)249 lightdm_prompt_type_get_type (void)
250 {
251     static GType enum_type = 0;
252 
253     if (G_UNLIKELY(enum_type == 0)) {
254         static const GEnumValue values[] = {
255             { LIGHTDM_PROMPT_TYPE_QUESTION, "LIGHTDM_PROMPT_TYPE_QUESTION", "question" },
256             { LIGHTDM_PROMPT_TYPE_SECRET, "LIGHTDM_PROMPT_TYPE_SECRET", "secret" },
257             { 0, NULL, NULL }
258         };
259         enum_type = g_enum_register_static (g_intern_static_string ("LightDMPromptType"), values);
260     }
261 
262     return enum_type;
263 }
264 
265 GType
lightdm_message_type_get_type(void)266 lightdm_message_type_get_type (void)
267 {
268     static GType enum_type = 0;
269 
270     if (G_UNLIKELY(enum_type == 0)) {
271         static const GEnumValue values[] = {
272             { LIGHTDM_MESSAGE_TYPE_INFO, "LIGHTDM_MESSAGE_TYPE_INFO", "info" },
273             { LIGHTDM_MESSAGE_TYPE_ERROR, "LIGHTDM_MESSAGE_TYPE_ERROR", "error" },
274             { 0, NULL, NULL }
275         };
276         enum_type = g_enum_register_static (g_intern_static_string ("LightDMMessageType"), values);
277     }
278 
279     return enum_type;
280 }
281 
282 
283 /**
284  * lightdm_greeter_new:
285  *
286  * Create a new greeter.
287  *
288  * Return value: the new #LightDMGreeter
289  **/
290 LightDMGreeter *
lightdm_greeter_new(void)291 lightdm_greeter_new (void)
292 {
293     return g_object_new (LIGHTDM_TYPE_GREETER, NULL);
294 }
295 
296 /**
297  * lightdm_greeter_set_resettable:
298  * @greeter: A #LightDMGreeter
299  * @resettable: Whether the greeter wants to be reset instead of killed after the user logs in
300  *
301  * Set whether the greeter will be reset instead of killed after the user logs in.
302  * This must be called before lightdm_greeter_connect is called.
303  **/
304 void
lightdm_greeter_set_resettable(LightDMGreeter * greeter,gboolean resettable)305 lightdm_greeter_set_resettable (LightDMGreeter *greeter, gboolean resettable)
306 {
307     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
308 
309     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
310 
311     g_return_if_fail (!priv->connected);
312     priv->resettable = resettable;
313 }
314 
315 static Request *
request_new(LightDMGreeter * greeter,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)316 request_new (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
317 {
318     Request *request = g_object_new (request_get_type (), NULL);
319     request->greeter = greeter;
320     if (cancellable)
321         request->cancellable = g_object_ref (cancellable);
322     request->callback = callback;
323     request->user_data = user_data;
324 
325     return request;
326 }
327 
328 static gboolean
request_callback_cb(gpointer data)329 request_callback_cb (gpointer data)
330 {
331     Request *request = data;
332     if (request->callback)
333         request->callback (G_OBJECT (request->greeter), G_ASYNC_RESULT (request), request->user_data);
334     g_object_unref (request);
335     return G_SOURCE_REMOVE;
336 }
337 
338 static void
request_complete(Request * request)339 request_complete (Request *request)
340 {
341     request->complete = TRUE;
342 
343     if (!request->callback)
344         return;
345 
346     if (request->cancellable && g_cancellable_is_cancelled (request->cancellable))
347         return;
348 
349     g_idle_add (request_callback_cb, g_object_ref (request));
350 }
351 
352 static gboolean
timed_login_cb(gpointer data)353 timed_login_cb (gpointer data)
354 {
355     LightDMGreeter *greeter = data;
356     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
357 
358     priv->autologin_timeout = 0;
359     g_signal_emit (G_OBJECT (greeter), signals[AUTOLOGIN_TIMER_EXPIRED], 0);
360 
361     return FALSE;
362 }
363 
364 static guint32
int_length(void)365 int_length (void)
366 {
367     return 4;
368 }
369 
370 static gboolean
write_int(guint8 * buffer,gint buffer_length,guint32 value,gsize * offset,GError ** error)371 write_int (guint8 *buffer, gint buffer_length, guint32 value, gsize *offset, GError **error)
372 {
373     if (*offset + 4 >= buffer_length)
374     {
375         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
376                              "Not enough buffer space to write integer");
377         return FALSE;
378     }
379     buffer[*offset] = value >> 24;
380     buffer[*offset+1] = (value >> 16) & 0xFF;
381     buffer[*offset+2] = (value >> 8) & 0xFF;
382     buffer[*offset+3] = value & 0xFF;
383     *offset += 4;
384 
385     return TRUE;
386 }
387 
388 static gboolean
write_string(guint8 * buffer,gint buffer_length,const gchar * value,gsize * offset,GError ** error)389 write_string (guint8 *buffer, gint buffer_length, const gchar *value, gsize *offset, GError **error)
390 {
391     gint length = 0;
392     if (value)
393         length = strlen (value);
394     if (!write_int (buffer, buffer_length, length, offset, error))
395         return FALSE;
396     if (*offset + length >= buffer_length)
397     {
398         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
399                      "Not enough buffer space to write string of length %d octets", length);
400         return FALSE;
401     }
402     if (value)
403         memcpy (buffer + *offset, value, length);
404     *offset += length;
405 
406     return TRUE;
407 }
408 
409 static guint32
read_int(guint8 * message,gsize message_length,gsize * offset)410 read_int (guint8 *message, gsize message_length, gsize *offset)
411 {
412     if (message_length - *offset < int_length ())
413     {
414         g_warning ("Not enough space for int, need %i, got %zi", int_length (), message_length - *offset);
415         return 0;
416     }
417 
418     const guint8 *buffer = message + *offset;
419     guint32 value = buffer[0] << 24 | buffer[1] << 16 | buffer[2] << 8 | buffer[3];
420     *offset += int_length ();
421 
422     return value;
423 }
424 
425 static gchar *
read_string(guint8 * message,gsize message_length,gsize * offset)426 read_string (guint8 *message, gsize message_length, gsize *offset)
427 {
428     guint32 length = read_int (message, message_length, offset);
429     if (message_length - *offset < length)
430     {
431         g_warning ("Not enough space for string, need %u, got %zu", length, message_length - *offset);
432         return g_strdup ("");
433     }
434 
435     gchar *value = g_malloc (sizeof (gchar) * (length + 1));
436     memcpy (value, message + *offset, length);
437     value[length] = '\0';
438     *offset += length;
439 
440     return value;
441 }
442 
443 static guint32
string_length(const gchar * value)444 string_length (const gchar *value)
445 {
446     if (value)
447         return int_length () + strlen (value);
448     else
449         return int_length ();
450 }
451 
452 static gboolean
write_header(guint8 * buffer,gint buffer_length,guint32 id,guint32 length,gsize * offset,GError ** error)453 write_header (guint8 *buffer, gint buffer_length, guint32 id, guint32 length, gsize *offset, GError **error)
454 {
455     return write_int (buffer, buffer_length, id, offset, error) &&
456            write_int (buffer, buffer_length, length, offset, error);
457 }
458 
459 static guint32
get_message_length(guint8 * message,gsize message_length)460 get_message_length (guint8 *message, gsize message_length)
461 {
462     gsize offset = 4;
463     return read_int (message, message_length, &offset);
464 }
465 
466 static gboolean
connect_to_daemon(LightDMGreeter * greeter,GError ** error)467 connect_to_daemon (LightDMGreeter *greeter, GError **error)
468 {
469     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
470 
471     if (priv->to_server_channel || priv->from_server_channel)
472         return TRUE;
473 
474     /* Use private connection if one exists */
475     const gchar *to_server_fd = g_getenv ("LIGHTDM_TO_SERVER_FD");
476     const gchar *from_server_fd = g_getenv ("LIGHTDM_FROM_SERVER_FD");
477     const gchar *pipe_path = g_getenv ("LIGHTDM_GREETER_PIPE");
478     if (to_server_fd && from_server_fd)
479     {
480         priv->to_server_channel = g_io_channel_unix_new (atoi (to_server_fd));
481         priv->from_server_channel = g_io_channel_unix_new (atoi (from_server_fd));
482     }
483     else if (pipe_path)
484     {
485         priv->socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, error);
486         if (!priv->socket)
487             return FALSE;
488 
489         g_autoptr(GSocketAddress) address = g_unix_socket_address_new (pipe_path);
490         if (!g_socket_connect (priv->socket, address, NULL, error))
491             return FALSE;
492 
493         priv->from_server_channel = g_io_channel_unix_new (g_socket_get_fd (priv->socket));
494         priv->to_server_channel = g_io_channel_ref (priv->from_server_channel);
495     }
496     else
497     {
498         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_CONNECTION_FAILED,
499                              "Unable to determine socket to daemon");
500         return FALSE;
501     }
502 
503     priv->from_server_watch = g_io_add_watch (priv->from_server_channel, G_IO_IN, from_server_cb, greeter);
504 
505     if (!g_io_channel_set_encoding (priv->to_server_channel, NULL, error) ||
506         !g_io_channel_set_encoding (priv->from_server_channel, NULL, error))
507         return FALSE;
508 
509     return TRUE;
510 }
511 
512 static gboolean
send_message(LightDMGreeter * greeter,guint8 * message,gsize message_length,GError ** error)513 send_message (LightDMGreeter *greeter, guint8 *message, gsize message_length, GError **error)
514 {
515     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
516 
517     if (!connect_to_daemon (greeter, error))
518         return FALSE;
519 
520     /* Double check that we're sending well-formed messages.  If we say we're
521        sending more than we do, we end up DOS'ing lightdm as it waits for the
522        rest.  If we say we're sending less than we do, we confuse the heck out
523        of lightdm, as it starts reading headers from the middle of our
524        messages. */
525     guint32 stated_length = HEADER_SIZE + get_message_length (message, message_length);
526     if (stated_length != message_length)
527     {
528         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
529                      "Refusing to write malformed packet to daemon: declared size is %u, but actual size is %zu",
530                      stated_length, message_length);
531         return FALSE;
532     }
533 
534     gchar *data = (gchar *) message;
535     gsize data_length = message_length;
536     while (data_length > 0)
537     {
538         gsize n_written;
539         g_autoptr(GError) write_error = NULL;
540         GIOStatus status = g_io_channel_write_chars (priv->to_server_channel, data, data_length, &n_written, &write_error);
541         if (write_error)
542             g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
543                          "Failed to write to daemon: %s",
544                          write_error->message);
545         if (status == G_IO_STATUS_AGAIN)
546             continue;
547         if (status != G_IO_STATUS_NORMAL)
548             return FALSE;
549         data_length -= n_written;
550         data += n_written;
551     }
552 
553     g_debug ("Wrote %zi bytes to daemon", message_length);
554     g_autoptr(GError) flush_error = NULL;
555     if (!g_io_channel_flush (priv->to_server_channel, &flush_error))
556     {
557         g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
558                      "Failed to write to daemon: %s",
559                      flush_error->message);
560         return FALSE;
561     }
562 
563     return TRUE;
564 }
565 
566 static void
handle_connected(LightDMGreeter * greeter,gboolean v2,guint8 * message,gsize message_length,gsize * offset)567 handle_connected (LightDMGreeter *greeter, gboolean v2, guint8 *message, gsize message_length, gsize *offset)
568 {
569     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
570     int timeout;
571     Request *request;
572 
573     g_autoptr(GString) debug_string = g_string_new ("Connected");
574     if (v2)
575     {
576         priv->api_version = read_int (message, message_length, offset);
577         g_string_append_printf (debug_string, " api=%u", priv->api_version);
578         g_autofree gchar *version = read_string (message, message_length, offset);
579         g_string_append_printf (debug_string, " version=%s", version);
580         guint32 n_env = read_int (message, message_length, offset);
581         for (guint32 i = 0; i < n_env; i++)
582         {
583             gchar *name = read_string (message, message_length, offset);
584             gchar *value = read_string (message, message_length, offset);
585             g_hash_table_insert (priv->hints, name, value);
586             g_string_append_printf (debug_string, " %s=%s", name, value);
587         }
588     }
589     else
590     {
591         priv->api_version = 0;
592         g_autofree gchar *version = read_string (message, message_length, offset);
593         g_string_append_printf (debug_string, " version=%s", version);
594         while (*offset < message_length)
595         {
596             gchar *name = read_string (message, message_length, offset);
597             gchar *value = read_string (message, message_length, offset);
598             g_hash_table_insert (priv->hints, name, value);
599             g_string_append_printf (debug_string, " %s=%s", name, value);
600         }
601     }
602 
603     priv->connected = TRUE;
604     g_debug ("%s", debug_string->str);
605 
606     /* Set timeout for default login */
607     timeout = lightdm_greeter_get_autologin_timeout_hint (greeter);
608     if (timeout)
609     {
610         g_debug ("Setting autologin timer for %d seconds", timeout);
611         priv->autologin_timeout = g_timeout_add (timeout * 1000, timed_login_cb, greeter);
612     }
613 
614     /* Notify asynchronous caller */
615     request = g_list_nth_data (priv->connect_requests, 0);
616     if (request)
617     {
618         request->result = TRUE;
619         request_complete (request);
620         priv->connect_requests = g_list_remove (priv->connect_requests, request);
621         g_object_unref (request);
622     }
623 }
624 
625 static void
handle_prompt_authentication(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)626 handle_prompt_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
627 {
628     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
629 
630     guint32 sequence_number = read_int (message, message_length, offset);
631     if (sequence_number != priv->authenticate_sequence_number)
632     {
633         g_debug ("Ignoring prompt authentication with invalid sequence number %d", sequence_number);
634         return;
635     }
636 
637     if (priv->cancelling_authentication)
638     {
639         g_debug ("Ignoring prompt authentication as waiting for it to cancel");
640         return;
641     }
642 
643     /* Update username */
644     g_autofree gchar *username = read_string (message, message_length, offset);
645     if (strcmp (username, "") == 0)
646     {
647         g_free (username);
648         username = NULL;
649     }
650     g_free (priv->authentication_user);
651     priv->authentication_user = g_steal_pointer (&username);
652 
653     g_list_free_full (priv->responses_received, g_free);
654     priv->responses_received = NULL;
655     priv->n_responses_waiting = 0;
656 
657     guint32 n_messages = read_int (message, message_length, offset);
658     g_debug ("Prompt user with %d message(s)", n_messages);
659 
660     for (guint32 i = 0; i < n_messages; i++)
661     {
662         int style = read_int (message, message_length, offset);
663         g_autofree gchar *text = read_string (message, message_length, offset);
664 
665         // FIXME: Should stop on prompts?
666         switch (style)
667         {
668         case PAM_PROMPT_ECHO_OFF:
669             priv->n_responses_waiting++;
670             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_SECRET);
671             break;
672         case PAM_PROMPT_ECHO_ON:
673             priv->n_responses_waiting++;
674             g_signal_emit (G_OBJECT (greeter), signals[SHOW_PROMPT], 0, text, LIGHTDM_PROMPT_TYPE_QUESTION);
675             break;
676         case PAM_ERROR_MSG:
677             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_ERROR);
678             break;
679         case PAM_TEXT_INFO:
680             g_signal_emit (G_OBJECT (greeter), signals[SHOW_MESSAGE], 0, text, LIGHTDM_MESSAGE_TYPE_INFO);
681             break;
682         }
683     }
684 }
685 
686 static void
handle_end_authentication(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)687 handle_end_authentication (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
688 {
689     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
690 
691     guint32 sequence_number = read_int (message, message_length, offset);
692     if (sequence_number != priv->authenticate_sequence_number)
693     {
694         g_debug ("Ignoring end authentication with invalid sequence number %d", sequence_number);
695         return;
696     }
697 
698     g_autofree gchar *username = read_string (message, message_length, offset);
699     guint32 return_code = read_int (message, message_length, offset);
700 
701     g_debug ("Authentication complete for user %s with return code %d", username, return_code);
702 
703     /* Update username */
704     if (strcmp (username, "") == 0)
705     {
706         g_free (username);
707         username = NULL;
708     }
709     g_free (priv->authentication_user);
710     priv->authentication_user = g_steal_pointer (&username);
711 
712     priv->cancelling_authentication = FALSE;
713     priv->is_authenticated = (return_code == 0);
714 
715     priv->in_authentication = FALSE;
716     g_signal_emit (G_OBJECT (greeter), signals[AUTHENTICATION_COMPLETE], 0);
717 }
718 
719 static void
handle_idle(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)720 handle_idle (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
721 {
722     g_signal_emit (G_OBJECT (greeter), signals[IDLE], 0);
723 }
724 
725 static void
handle_reset(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)726 handle_reset (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
727 {
728     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
729 
730     g_hash_table_remove_all (priv->hints);
731 
732     g_autoptr(GString) hint_string = g_string_new ("");
733     while (*offset < message_length)
734     {
735         gchar *name = read_string (message, message_length, offset);
736         gchar *value = read_string (message, message_length, offset);
737         g_hash_table_insert (priv->hints, name, value);
738         g_string_append_printf (hint_string, " %s=%s", name, value);
739     }
740 
741     g_debug ("Reset%s", hint_string->str);
742 
743     g_signal_emit (G_OBJECT (greeter), signals[RESET], 0);
744 }
745 
746 static void
handle_session_result(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)747 handle_session_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
748 {
749     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
750 
751     /* Notify asynchronous caller */
752     Request *request = g_list_nth_data (priv->start_session_requests, 0);
753     if (request)
754     {
755         guint32 return_code = read_int (message, message_length, offset);
756         if (return_code == 0)
757             request->result = TRUE;
758         else
759             request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_SESSION_FAILED,
760                                           "Session returned error code %d", return_code);
761         request_complete (request);
762         priv->start_session_requests = g_list_remove (priv->start_session_requests, request);
763         g_object_unref (request);
764     }
765 }
766 
767 static void
handle_shared_dir_result(LightDMGreeter * greeter,guint8 * message,gsize message_length,gsize * offset)768 handle_shared_dir_result (LightDMGreeter *greeter, guint8 *message, gsize message_length, gsize *offset)
769 {
770     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
771 
772     /* Notify asynchronous caller */
773     Request *request = g_list_nth_data (priv->ensure_shared_data_dir_requests, 0);
774     if (request)
775     {
776         request->dir = read_string (message, message_length, offset);
777         /* Blank data dir means invalid user */
778         if (g_strcmp0 (request->dir, "") == 0)
779         {
780             g_free (request->dir);
781             request->dir = NULL;
782             request->error = g_error_new (LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_INVALID_USER,
783                                           "No such user");
784         }
785         request_complete (request);
786         priv->ensure_shared_data_dir_requests = g_list_remove (priv->ensure_shared_data_dir_requests, request);
787         g_object_unref (request);
788     }
789 }
790 
791 static void
handle_message(LightDMGreeter * greeter,guint8 * message,gsize message_length)792 handle_message (LightDMGreeter *greeter, guint8 *message, gsize message_length)
793 {
794     gsize offset = 0;
795     guint32 id = read_int (message, message_length, &offset);
796     read_int (message, message_length, &offset);
797     switch (id)
798     {
799     case SERVER_MESSAGE_CONNECTED:
800         handle_connected (greeter, FALSE, message, message_length, &offset);
801         break;
802     case SERVER_MESSAGE_PROMPT_AUTHENTICATION:
803         handle_prompt_authentication (greeter, message, message_length, &offset);
804         break;
805     case SERVER_MESSAGE_END_AUTHENTICATION:
806         handle_end_authentication (greeter, message, message_length, &offset);
807         break;
808     case SERVER_MESSAGE_SESSION_RESULT:
809         handle_session_result (greeter, message, message_length, &offset);
810         break;
811     case SERVER_MESSAGE_SHARED_DIR_RESULT:
812         handle_shared_dir_result (greeter, message, message_length, &offset);
813         break;
814     case SERVER_MESSAGE_IDLE:
815         handle_idle (greeter, message, message_length, &offset);
816         break;
817     case SERVER_MESSAGE_RESET:
818         handle_reset (greeter, message, message_length, &offset);
819         break;
820     case SERVER_MESSAGE_CONNECTED_V2:
821         handle_connected (greeter, TRUE, message, message_length, &offset);
822         break;
823     default:
824         g_warning ("Unknown message from server: %d", id);
825         break;
826     }
827 }
828 
829 static gboolean
recv_message(LightDMGreeter * greeter,gboolean block,guint8 ** message,gsize * length,GError ** error)830 recv_message (LightDMGreeter *greeter, gboolean block, guint8 **message, gsize *length, GError **error)
831 {
832     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
833 
834     if (!connect_to_daemon (greeter, error))
835         return FALSE;
836 
837     /* Read the header, or the whole message if we already have that */
838     gsize n_to_read = HEADER_SIZE;
839     if (priv->n_read >= HEADER_SIZE)
840         n_to_read += get_message_length (priv->read_buffer, priv->n_read);
841 
842     do
843     {
844         gsize n_read;
845         g_autoptr(GError) read_error = NULL;
846         GIOStatus status = g_io_channel_read_chars (priv->from_server_channel,
847                                           (gchar *) priv->read_buffer + priv->n_read,
848                                           n_to_read - priv->n_read,
849                                           &n_read,
850                                           &read_error);
851         if (status == G_IO_STATUS_AGAIN)
852         {
853             if (block)
854                 continue;
855         }
856         else if (status != G_IO_STATUS_NORMAL)
857         {
858             g_set_error (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_COMMUNICATION_ERROR,
859                          "Failed to read from daemon: %s",
860                          read_error->message);
861             return FALSE;
862         }
863 
864         g_debug ("Read %zi bytes from daemon", n_read);
865 
866         priv->n_read += n_read;
867     } while (priv->n_read < n_to_read && block);
868 
869     /* Stop if haven't got all the data we want */
870     if (priv->n_read != n_to_read)
871     {
872         if (message)
873             *message = NULL;
874         if (length)
875             *length = 0;
876         return TRUE;
877     }
878 
879     /* If have header, rerun for content */
880     if (priv->n_read == HEADER_SIZE)
881     {
882         n_to_read = get_message_length (priv->read_buffer, priv->n_read);
883         if (n_to_read > 0)
884         {
885             priv->read_buffer = g_realloc (priv->read_buffer, HEADER_SIZE + n_to_read);
886             return recv_message (greeter, block, message, length, error);
887         }
888     }
889 
890     if (message)
891         *message = priv->read_buffer;
892     else
893         g_free (priv->read_buffer);
894     if (length)
895         *length = priv->n_read;
896 
897     priv->read_buffer = g_malloc (priv->n_read);
898     priv->n_read = 0;
899 
900     return TRUE;
901 }
902 
903 static gboolean
from_server_cb(GIOChannel * source,GIOCondition condition,gpointer data)904 from_server_cb (GIOChannel *source, GIOCondition condition, gpointer data)
905 {
906     LightDMGreeter *greeter = data;
907 
908     /* Read one message and process it */
909     g_autofree guint8 *message = NULL;
910     gsize message_length;
911     g_autoptr(GError) error = NULL;
912     if (!recv_message (greeter, FALSE, &message, &message_length, &error))
913     {
914         // FIXME: Should push this up to the client somehow
915         g_warning ("Failed to read from daemon: %s\n", error->message);
916         return G_SOURCE_REMOVE;
917     }
918 
919     if (message)
920         handle_message (greeter, message, message_length);
921 
922     return G_SOURCE_CONTINUE;
923 }
924 
925 static gboolean
send_connect(LightDMGreeter * greeter,gboolean resettable,GError ** error)926 send_connect (LightDMGreeter *greeter, gboolean resettable, GError **error)
927 {
928     g_debug ("Connecting to display manager...");
929     guint8 message[MAX_MESSAGE_LENGTH];
930     gsize offset = 0;
931     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONNECT, string_length (VERSION) + int_length () * 2, &offset, error) &&
932            write_string (message, MAX_MESSAGE_LENGTH, VERSION, &offset, error) &&
933            write_int (message, MAX_MESSAGE_LENGTH, resettable ? 1 : 0, &offset, error) &&
934            write_int (message, MAX_MESSAGE_LENGTH, API_VERSION, &offset, error) &&
935            send_message (greeter, message, offset, error);
936 }
937 
938 static gboolean
send_start_session(LightDMGreeter * greeter,const gchar * session,GError ** error)939 send_start_session (LightDMGreeter *greeter, const gchar *session, GError **error)
940 {
941     if (session)
942         g_debug ("Starting session %s", session);
943     else
944         g_debug ("Starting default session");
945 
946     guint8 message[MAX_MESSAGE_LENGTH];
947     gsize offset = 0;
948     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_START_SESSION, string_length (session), &offset, error) &&
949            write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
950            send_message (greeter, message, offset, error);
951 }
952 
953 static gboolean
send_ensure_shared_data_dir(LightDMGreeter * greeter,const gchar * username,GError ** error)954 send_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GError **error)
955 {
956     g_debug ("Ensuring data directory for user %s", username);
957 
958     guint8 message[MAX_MESSAGE_LENGTH];
959     gsize offset = 0;
960     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_ENSURE_SHARED_DIR, string_length (username), &offset, error) &&
961            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
962            send_message (greeter, message, offset, error);
963 }
964 
965 /**
966  * lightdm_greeter_connect_to_daemon:
967  * @greeter: The greeter to connect
968  * @cancellable: (allow-none): A #GCancellable or %NULL.
969  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
970  * @user_data: (allow-none): data to pass to the @callback or %NULL.
971  *
972  * Asynchronously connects the greeter to the display manager.
973  *
974  * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_connect_to_daemon_finish() to get the result of the operation.
975  *
976  * See lightdm_greeter_connect_to_daemon_sync() for the synchronous version.
977  **/
978 void
lightdm_greeter_connect_to_daemon(LightDMGreeter * greeter,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)979 lightdm_greeter_connect_to_daemon (LightDMGreeter *greeter, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
980 {
981     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
982 
983     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
984 
985     Request *request = request_new (greeter, cancellable, callback, user_data);
986     GError *error = NULL;
987     if (send_connect (greeter, priv->resettable, &error))
988         priv->connect_requests = g_list_append (priv->connect_requests, request);
989     else
990     {
991         request->error = error;
992         request_complete (request);
993         g_object_unref (request);
994     }
995 }
996 
997 /**
998  * lightdm_greeter_connect_to_daemon_finish:
999  * @greeter: The greeter the the request was done with
1000  * @result: A #GAsyncResult.
1001  * @error: return location for a #GError, or %NULL
1002  *
1003  * Finishes an operation started with lightdm_greeter_connect_to_daemon().
1004  *
1005  * Return value: #TRUE if successfully connected
1006  **/
1007 gboolean
lightdm_greeter_connect_to_daemon_finish(LightDMGreeter * greeter,GAsyncResult * result,GError ** error)1008 lightdm_greeter_connect_to_daemon_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1009 {
1010     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1011 
1012     Request *request = REQUEST (result);
1013     if (request->error)
1014         g_propagate_error (error, request->error);
1015     return request->result;
1016 }
1017 
1018 /**
1019  * lightdm_greeter_connect_to_daemon_sync:
1020  * @greeter: The greeter to connect
1021  * @error: return location for a #GError, or %NULL
1022  *
1023  * Connects the greeter to the display manager.  Will block until connected.
1024  *
1025  * Return value: #TRUE if successfully connected
1026  **/
1027 gboolean
lightdm_greeter_connect_to_daemon_sync(LightDMGreeter * greeter,GError ** error)1028 lightdm_greeter_connect_to_daemon_sync (LightDMGreeter *greeter, GError **error)
1029 {
1030     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1031 
1032     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1033 
1034     /* Read until we are connected */
1035     if (!send_connect (greeter, priv->resettable, error))
1036         return FALSE;
1037     Request *request = request_new (greeter, NULL, NULL, NULL);
1038     priv->connect_requests = g_list_append (priv->connect_requests, g_object_ref (request));
1039     do
1040     {
1041         g_autofree guint8 *message = NULL;
1042         gsize message_length;
1043         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1044             return FALSE;
1045         handle_message (greeter, message, message_length);
1046     } while (!request->complete);
1047 
1048     return lightdm_greeter_connect_to_daemon_finish (greeter, G_ASYNC_RESULT (request), error);
1049 }
1050 
1051 /**
1052  * lightdm_greeter_connect_sync:
1053  * @greeter: The greeter to connect
1054  * @error: return location for a #GError, or %NULL
1055  *
1056  * Connects the greeter to the display manager.  Will block until connected.
1057  *
1058  * Return value: #TRUE if successfully connected
1059  *
1060  * Deprecated: 1.11.1: Use lightdm_greeter_connect_to_daemon_sync() instead
1061  **/
1062 gboolean
lightdm_greeter_connect_sync(LightDMGreeter * greeter,GError ** error)1063 lightdm_greeter_connect_sync (LightDMGreeter *greeter, GError **error)
1064 {
1065     return lightdm_greeter_connect_to_daemon_sync (greeter, error);
1066 }
1067 
1068 /**
1069  * lightdm_greeter_get_hint:
1070  * @greeter: A #LightDMGreeter
1071  * @name: The hint name to query.
1072  *
1073  * Get a hint.
1074  *
1075  * Return value: (nullable): The value for this hint or #NULL if not set.
1076  **/
1077 const gchar *
lightdm_greeter_get_hint(LightDMGreeter * greeter,const gchar * name)1078 lightdm_greeter_get_hint (LightDMGreeter *greeter, const gchar *name)
1079 {
1080     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1081     return g_hash_table_lookup (GET_PRIVATE (greeter)->hints, name);
1082 }
1083 
1084 /**
1085  * lightdm_greeter_get_default_session_hint:
1086  * @greeter: A #LightDMGreeter
1087  *
1088  * Get the default session to use.
1089  *
1090  * Return value: The session name
1091  **/
1092 const gchar *
lightdm_greeter_get_default_session_hint(LightDMGreeter * greeter)1093 lightdm_greeter_get_default_session_hint (LightDMGreeter *greeter)
1094 {
1095     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1096     return lightdm_greeter_get_hint (greeter, "default-session");
1097 }
1098 
1099 static gboolean
get_boolean_hint(LightDMGreeter * greeter,const gchar * name)1100 get_boolean_hint (LightDMGreeter *greeter, const gchar *name)
1101 {
1102     const gchar *value = lightdm_greeter_get_hint (greeter, name);
1103     return g_strcmp0 (value, "true") == 0;
1104 }
1105 
1106 /**
1107  * lightdm_greeter_get_hide_users_hint:
1108  * @greeter: A #LightDMGreeter
1109  *
1110  * Check if user accounts should be shown.  If this is TRUE then the list of
1111  * accounts should be taken from #LightDMUserList and displayed in the greeter
1112  * for the user to choose from.  Note that this list can be empty and it is
1113  * recommended you show a method for the user to enter a username manually.
1114  *
1115  * If this option is shown the greeter should only allow these users to be
1116  * chosen for login unless the manual login hint is set.
1117  *
1118  * Return value: #TRUE if the available users should not be shown.
1119  */
1120 gboolean
lightdm_greeter_get_hide_users_hint(LightDMGreeter * greeter)1121 lightdm_greeter_get_hide_users_hint (LightDMGreeter *greeter)
1122 {
1123     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1124     return get_boolean_hint (greeter, "hide-users");
1125 }
1126 
1127 /**
1128  * lightdm_greeter_get_show_manual_login_hint:
1129  * @greeter: A #LightDMGreeter
1130  *
1131  * Check if a manual login option should be shown.  If set the GUI
1132  * should provide a way for a username to be entered manually.
1133  * Without this hint a greeter which is showing a user list can
1134  * limit logins to only those users.
1135  *
1136  * Return value: #TRUE if a manual login option should be shown.
1137  */
1138 gboolean
lightdm_greeter_get_show_manual_login_hint(LightDMGreeter * greeter)1139 lightdm_greeter_get_show_manual_login_hint (LightDMGreeter *greeter)
1140 {
1141     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1142     return get_boolean_hint (greeter, "show-manual-login");
1143 }
1144 
1145 /**
1146  * lightdm_greeter_get_show_remote_login_hint:
1147  * @greeter: A #LightDMGreeter
1148  *
1149  * Check if a remote login option should be shown.  If set the GUI
1150  * should provide a way for a user to log into a remote desktop server.
1151  *
1152  * Return value: #TRUE if a remote login option should be shown.
1153  */
1154 gboolean
lightdm_greeter_get_show_remote_login_hint(LightDMGreeter * greeter)1155 lightdm_greeter_get_show_remote_login_hint (LightDMGreeter *greeter)
1156 {
1157     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1158     return get_boolean_hint (greeter, "show-remote-login");
1159 }
1160 
1161 /**
1162  * lightdm_greeter_get_lock_hint:
1163  * @greeter: A #LightDMGreeter
1164  *
1165  * Check if the greeter is acting as a lock screen.
1166  *
1167  * Return value: #TRUE if the greeter was triggered by locking the seat.
1168  */
1169 gboolean
lightdm_greeter_get_lock_hint(LightDMGreeter * greeter)1170 lightdm_greeter_get_lock_hint (LightDMGreeter *greeter)
1171 {
1172     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1173     return get_boolean_hint (greeter, "lock-screen");
1174 }
1175 
1176 /**
1177  * lightdm_greeter_get_has_guest_account_hint:
1178  * @greeter: A #LightDMGreeter
1179  *
1180  * Check if guest sessions are supported.
1181  *
1182  * Return value: #TRUE if guest sessions are supported.
1183  */
1184 gboolean
lightdm_greeter_get_has_guest_account_hint(LightDMGreeter * greeter)1185 lightdm_greeter_get_has_guest_account_hint (LightDMGreeter *greeter)
1186 {
1187     const gchar *value;
1188 
1189     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1190     value = lightdm_greeter_get_hint (greeter, "has-guest-account");
1191 
1192     return g_strcmp0 (value, "true") == 0;
1193 }
1194 
1195 /**
1196  * lightdm_greeter_get_select_user_hint:
1197  * @greeter: A #LightDMGreeter
1198  *
1199  * Get the user to select by default.
1200  *
1201  * Return value: (nullable): A username or %NULL if no particular user should be selected.
1202  */
1203 const gchar *
lightdm_greeter_get_select_user_hint(LightDMGreeter * greeter)1204 lightdm_greeter_get_select_user_hint (LightDMGreeter *greeter)
1205 {
1206     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1207     return lightdm_greeter_get_hint (greeter, "select-user");
1208 }
1209 
1210 /**
1211  * lightdm_greeter_get_select_guest_hint:
1212  * @greeter: A #LightDMGreeter
1213  *
1214  * Check if the guest account should be selected by default.
1215  *
1216  * Return value: #TRUE if the guest account should be selected by default.
1217  */
1218 gboolean
lightdm_greeter_get_select_guest_hint(LightDMGreeter * greeter)1219 lightdm_greeter_get_select_guest_hint (LightDMGreeter *greeter)
1220 {
1221     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1222     return get_boolean_hint (greeter, "select-guest");
1223 }
1224 
1225 /**
1226  * lightdm_greeter_get_autologin_user_hint:
1227  * @greeter: A #LightDMGreeter
1228  *
1229  * Get the user account to automatically log into when the timer expires.
1230  *
1231  * Return value: (nullable): The user account to automatically log into or %NULL if none configured.
1232  */
1233 const gchar *
lightdm_greeter_get_autologin_user_hint(LightDMGreeter * greeter)1234 lightdm_greeter_get_autologin_user_hint (LightDMGreeter *greeter)
1235 {
1236     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1237     return lightdm_greeter_get_hint (greeter, "autologin-user");
1238 }
1239 
1240 /**
1241  * lightdm_greeter_get_autologin_session_hint:
1242  * @greeter: A #LightDMGreeter
1243  *
1244  * Get the session used to automatically log into when the timer expires.
1245  *
1246  * Return value: (nullable): The session name or %NULL if configured to use the default.
1247  */
1248 const gchar *
lightdm_greeter_get_autologin_session_hint(LightDMGreeter * greeter)1249 lightdm_greeter_get_autologin_session_hint (LightDMGreeter *greeter)
1250 {
1251     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1252     return lightdm_greeter_get_hint (greeter, "autologin-session");
1253 }
1254 
1255 /**
1256  * lightdm_greeter_get_autologin_guest_hint:
1257  * @greeter: A #LightDMGreeter
1258  *
1259  * Check if the guest account should be automatically logged into when the timer expires.
1260  *
1261  * Return value: #TRUE if the guest account should be automatically logged into.
1262  */
1263 gboolean
lightdm_greeter_get_autologin_guest_hint(LightDMGreeter * greeter)1264 lightdm_greeter_get_autologin_guest_hint (LightDMGreeter *greeter)
1265 {
1266     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1267     return get_boolean_hint (greeter, "autologin-guest");
1268 }
1269 
1270 /**
1271  * lightdm_greeter_get_autologin_timeout_hint:
1272  * @greeter: A #LightDMGreeter
1273  *
1274  * Get the number of seconds to wait before automatically logging in.
1275  *
1276  * Return value: The number of seconds to wait before automatically logging in or 0 for no timeout.
1277  */
1278 gint
lightdm_greeter_get_autologin_timeout_hint(LightDMGreeter * greeter)1279 lightdm_greeter_get_autologin_timeout_hint (LightDMGreeter *greeter)
1280 {
1281     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1282 
1283     const gchar *value = lightdm_greeter_get_hint (greeter, "autologin-timeout");
1284     gint timeout = 0;
1285     if (value)
1286         timeout = atoi (value);
1287     if (timeout < 0)
1288         timeout = 0;
1289 
1290     return timeout;
1291 }
1292 
1293 /**
1294  * lightdm_greeter_cancel_autologin:
1295  * @greeter: A #LightDMGreeter
1296  *
1297  * Cancel the automatic login.
1298  */
1299 void
lightdm_greeter_cancel_autologin(LightDMGreeter * greeter)1300 lightdm_greeter_cancel_autologin (LightDMGreeter *greeter)
1301 {
1302     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1303 
1304     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1305 
1306     if (priv->autologin_timeout)
1307        g_source_remove (priv->autologin_timeout);
1308     priv->autologin_timeout = 0;
1309 }
1310 
1311 /**
1312  * lightdm_greeter_authenticate:
1313  * @greeter: A #LightDMGreeter
1314  * @username: (allow-none): A username or #NULL to prompt for a username.
1315  * @error: return location for a #GError, or %NULL
1316  *
1317  * Starts the authentication procedure for a user.
1318  *
1319  * Return value: #TRUE if authentication request sent.
1320  **/
1321 gboolean
lightdm_greeter_authenticate(LightDMGreeter * greeter,const gchar * username,GError ** error)1322 lightdm_greeter_authenticate (LightDMGreeter *greeter, const gchar *username, GError **error)
1323 {
1324     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1325 
1326     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1327 
1328     g_return_val_if_fail (priv->connected, FALSE);
1329 
1330     priv->cancelling_authentication = FALSE;
1331     priv->authenticate_sequence_number++;
1332     priv->in_authentication = TRUE;
1333     priv->is_authenticated = FALSE;
1334     if (username != priv->authentication_user)
1335     {
1336         g_free (priv->authentication_user);
1337         priv->authentication_user = g_strdup (username);
1338     }
1339 
1340     g_debug ("Starting authentication for user %s...", username);
1341     guint8 message[MAX_MESSAGE_LENGTH];
1342     gsize offset = 0;
1343     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE, int_length () + string_length (username), &offset, error) &&
1344            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1345            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1346            send_message (greeter, message, offset, error);
1347 }
1348 
1349 /**
1350  * lightdm_greeter_authenticate_as_guest:
1351  * @greeter: A #LightDMGreeter
1352  * @error: return location for a #GError, or %NULL
1353  *
1354  * Starts the authentication procedure for the guest user.
1355  *
1356  * Return value: #TRUE if authentication request sent.
1357  **/
1358 gboolean
lightdm_greeter_authenticate_as_guest(LightDMGreeter * greeter,GError ** error)1359 lightdm_greeter_authenticate_as_guest (LightDMGreeter *greeter, GError **error)
1360 {
1361     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1362 
1363     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1364 
1365     g_return_val_if_fail (priv->connected, FALSE);
1366 
1367     priv->cancelling_authentication = FALSE;
1368     priv->authenticate_sequence_number++;
1369     priv->in_authentication = TRUE;
1370     priv->is_authenticated = FALSE;
1371     g_free (priv->authentication_user);
1372     priv->authentication_user = NULL;
1373 
1374     g_debug ("Starting authentication for guest account...");
1375     guint8 message[MAX_MESSAGE_LENGTH];
1376     gsize offset = 0;
1377     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_AS_GUEST, int_length (), &offset, error) &&
1378            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1379            send_message (greeter, message, offset, error);
1380 }
1381 
1382 /**
1383  * lightdm_greeter_authenticate_autologin:
1384  * @greeter: A #LightDMGreeter
1385  * @error: return location for a #GError, or %NULL
1386  *
1387  * Starts the authentication procedure for the automatic login user.
1388  *
1389  * Return value: #TRUE if authentication request sent.
1390  **/
1391 gboolean
lightdm_greeter_authenticate_autologin(LightDMGreeter * greeter,GError ** error)1392 lightdm_greeter_authenticate_autologin (LightDMGreeter *greeter, GError **error)
1393 {
1394     const gchar *user = lightdm_greeter_get_autologin_user_hint (greeter);
1395     if (lightdm_greeter_get_autologin_guest_hint (greeter))
1396         return lightdm_greeter_authenticate_as_guest (greeter, error);
1397     else if (user)
1398         return lightdm_greeter_authenticate (greeter, user, error);
1399     else
1400     {
1401         g_set_error_literal (error, LIGHTDM_GREETER_ERROR, LIGHTDM_GREETER_ERROR_NO_AUTOLOGIN,
1402                              "Can't authenticate autologin; autologin not configured");
1403         return FALSE;
1404     }
1405 }
1406 
1407 /**
1408  * lightdm_greeter_authenticate_remote:
1409  * @greeter: A #LightDMGreeter
1410  * @session: The name of a remote session
1411  * @username: (allow-none): A username of #NULL to prompt for a username.
1412  * @error: return location for a #GError, or %NULL
1413  *
1414  * Start authentication for a remote session type.
1415  *
1416  * Return value: #TRUE if authentication request sent.
1417  **/
1418 gboolean
lightdm_greeter_authenticate_remote(LightDMGreeter * greeter,const gchar * session,const gchar * username,GError ** error)1419 lightdm_greeter_authenticate_remote (LightDMGreeter *greeter, const gchar *session, const gchar *username, GError **error)
1420 {
1421     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1422 
1423     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1424 
1425     g_return_val_if_fail (priv->connected, FALSE);
1426 
1427     priv->cancelling_authentication = FALSE;
1428     priv->authenticate_sequence_number++;
1429     priv->in_authentication = TRUE;
1430     priv->is_authenticated = FALSE;
1431     g_free (priv->authentication_user);
1432     priv->authentication_user = NULL;
1433 
1434     if (username)
1435         g_debug ("Starting authentication for remote session %s as user %s...", session, username);
1436     else
1437         g_debug ("Starting authentication for remote session %s...", session);
1438 
1439     guint8 message[MAX_MESSAGE_LENGTH];
1440     gsize offset = 0;
1441     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_AUTHENTICATE_REMOTE, int_length () + string_length (session) + string_length (username), &offset, error) &&
1442            write_int (message, MAX_MESSAGE_LENGTH, priv->authenticate_sequence_number, &offset, error) &&
1443            write_string (message, MAX_MESSAGE_LENGTH, session, &offset, error) &&
1444            write_string (message, MAX_MESSAGE_LENGTH, username, &offset, error) &&
1445            send_message (greeter, message, offset, error);
1446 }
1447 
1448 /**
1449  * lightdm_greeter_respond:
1450  * @greeter: A #LightDMGreeter
1451  * @response: Response to a prompt
1452  * @error: return location for a #GError, or %NULL
1453  *
1454  * Provide response to a prompt.  May be one in a series.
1455  *
1456  * Return value: #TRUE if response sent.
1457  **/
1458 gboolean
lightdm_greeter_respond(LightDMGreeter * greeter,const gchar * response,GError ** error)1459 lightdm_greeter_respond (LightDMGreeter *greeter, const gchar *response, GError **error)
1460 {
1461     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1462     g_return_val_if_fail (response != NULL, FALSE);
1463 
1464     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1465 
1466     g_return_val_if_fail (priv->connected, FALSE);
1467     g_return_val_if_fail (priv->n_responses_waiting > 0, FALSE);
1468 
1469     priv->n_responses_waiting--;
1470     priv->responses_received = g_list_append (priv->responses_received, g_strdup (response));
1471 
1472     guint8 message[MAX_MESSAGE_LENGTH];
1473     gsize offset = 0;
1474     if (priv->n_responses_waiting == 0)
1475     {
1476         g_debug ("Providing response to display manager");
1477 
1478         guint32 msg_length = int_length ();
1479         for (GList *iter = priv->responses_received; iter; iter = iter->next)
1480             msg_length += string_length ((gchar *)iter->data);
1481 
1482         if (!write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CONTINUE_AUTHENTICATION, msg_length, &offset, error) ||
1483             !write_int (message, MAX_MESSAGE_LENGTH, g_list_length (priv->responses_received), &offset, error))
1484             return FALSE;
1485         for (GList *iter = priv->responses_received; iter; iter = iter->next)
1486         {
1487             if (!write_string (message, MAX_MESSAGE_LENGTH, (gchar *)iter->data, &offset, error))
1488                 return FALSE;
1489         }
1490         if (!send_message (greeter, message, offset, error))
1491             return FALSE;
1492 
1493         g_list_free_full (priv->responses_received, g_free);
1494         priv->responses_received = NULL;
1495     }
1496 
1497     return TRUE;
1498 }
1499 
1500 /**
1501  * lightdm_greeter_cancel_authentication:
1502  * @greeter: A #LightDMGreeter
1503  * @error: return location for a #GError, or %NULL
1504  *
1505  * Cancel the current user authentication.
1506  *
1507  * Return value: #TRUE if cancel request sent.
1508  **/
1509 gboolean
lightdm_greeter_cancel_authentication(LightDMGreeter * greeter,GError ** error)1510 lightdm_greeter_cancel_authentication (LightDMGreeter *greeter, GError **error)
1511 {
1512     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1513 
1514     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1515 
1516     g_return_val_if_fail (priv->connected, FALSE);
1517 
1518     priv->cancelling_authentication = TRUE;
1519     guint8 message[MAX_MESSAGE_LENGTH];
1520     gsize offset = 0;
1521     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_CANCEL_AUTHENTICATION, 0, &offset, error) &&
1522            send_message (greeter, message, offset, error);
1523 }
1524 
1525 /**
1526  * lightdm_greeter_get_in_authentication:
1527  * @greeter: A #LightDMGreeter
1528  *
1529  * Checks if the greeter is in the process of authenticating.
1530  *
1531  * Return value: #TRUE if the greeter is authenticating a user.
1532  **/
1533 gboolean
lightdm_greeter_get_in_authentication(LightDMGreeter * greeter)1534 lightdm_greeter_get_in_authentication (LightDMGreeter *greeter)
1535 {
1536     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1537     return GET_PRIVATE (greeter)->in_authentication;
1538 }
1539 
1540 /**
1541  * lightdm_greeter_get_is_authenticated:
1542  * @greeter: A #LightDMGreeter
1543  *
1544  * Checks if the greeter has successfully authenticated.
1545  *
1546  * Return value: #TRUE if the greeter is authenticated for login.
1547  **/
1548 gboolean
lightdm_greeter_get_is_authenticated(LightDMGreeter * greeter)1549 lightdm_greeter_get_is_authenticated (LightDMGreeter *greeter)
1550 {
1551     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1552     return GET_PRIVATE (greeter)->is_authenticated;
1553 }
1554 
1555 /**
1556  * lightdm_greeter_get_authentication_user:
1557  * @greeter: A #LightDMGreeter
1558  *
1559  * Get the user that is being authenticated.
1560  *
1561  * Return value: (nullable): The username of the authentication user being authenticated or #NULL if no authentication in progress.
1562  */
1563 const gchar *
lightdm_greeter_get_authentication_user(LightDMGreeter * greeter)1564 lightdm_greeter_get_authentication_user (LightDMGreeter *greeter)
1565 {
1566     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1567     return GET_PRIVATE (greeter)->authentication_user;
1568 }
1569 
1570 /**
1571  * lightdm_greeter_set_language:
1572  * @greeter: A #LightDMGreeter
1573  * @language: The language to use for this user in the form of a locale specification (e.g. "de_DE.UTF-8").
1574  * @error: return location for a #GError, or %NULL
1575  *
1576  * Set the language for the currently authenticated user.
1577  *
1578  * Return value: #TRUE if set language request sent.
1579  **/
1580 gboolean
lightdm_greeter_set_language(LightDMGreeter * greeter,const gchar * language,GError ** error)1581 lightdm_greeter_set_language (LightDMGreeter *greeter, const gchar *language, GError **error)
1582 {
1583     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1584 
1585     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1586 
1587     g_return_val_if_fail (priv->connected, FALSE);
1588 
1589     guint8 message[MAX_MESSAGE_LENGTH];
1590     gsize offset = 0;
1591     return write_header (message, MAX_MESSAGE_LENGTH, GREETER_MESSAGE_SET_LANGUAGE, string_length (language), &offset, error) &&
1592            write_string (message, MAX_MESSAGE_LENGTH, language, &offset, error) &&
1593            send_message (greeter, message, offset, error);
1594 }
1595 
1596 /**
1597  * lightdm_greeter_start_session:
1598  * @greeter: A #LightDMGreeter
1599  * @session: (allow-none): The session to log into or #NULL to use the default.
1600  * @cancellable: (allow-none): A #GCancellable or %NULL.
1601  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1602  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1603  *
1604  * Asynchronously start a session for the authenticated user.
1605  *
1606  * When the operation is finished, @callback will be invoked. You can then call lightdm_greeter_start_session_finish() to get the result of the operation.
1607  *
1608  * See lightdm_greeter_start_session_sync() for the synchronous version.
1609  **/
1610 void
lightdm_greeter_start_session(LightDMGreeter * greeter,const gchar * session,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1611 lightdm_greeter_start_session (LightDMGreeter *greeter, const gchar *session, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1612 {
1613     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1614 
1615     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1616 
1617     Request *request = request_new (greeter, cancellable, callback, user_data);
1618     priv->start_session_requests = g_list_append (priv->start_session_requests, request);
1619     GError *error = NULL;
1620     if (!send_start_session (greeter, session, &error))
1621     {
1622         request->error = error;
1623         request_complete (request);
1624     }
1625 }
1626 
1627 /**
1628  * lightdm_greeter_start_session_finish:
1629  * @greeter: A #LightDMGreeter
1630  * @result: A #GAsyncResult.
1631  * @error: return location for a #GError, or %NULL
1632  *
1633  * Start a session for the authenticated user.
1634  *
1635  * Return value: TRUE if the session was started.
1636  **/
1637 gboolean
lightdm_greeter_start_session_finish(LightDMGreeter * greeter,GAsyncResult * result,GError ** error)1638 lightdm_greeter_start_session_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1639 {
1640     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1641 
1642     Request *request = REQUEST (result);
1643     if (request->error)
1644         g_propagate_error (error, request->error);
1645     return request->result;
1646 }
1647 
1648 /**
1649  * lightdm_greeter_start_session_sync:
1650  * @greeter: A #LightDMGreeter
1651  * @session: (allow-none): The session to log into or #NULL to use the default.
1652  * @error: return location for a #GError, or %NULL
1653  *
1654  * Start a session for the authenticated user.
1655  *
1656  * Return value: TRUE if the session was started.
1657  **/
1658 gboolean
lightdm_greeter_start_session_sync(LightDMGreeter * greeter,const gchar * session,GError ** error)1659 lightdm_greeter_start_session_sync (LightDMGreeter *greeter, const gchar *session, GError **error)
1660 {
1661     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), FALSE);
1662 
1663     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1664 
1665     g_return_val_if_fail (priv->connected, FALSE);
1666     g_return_val_if_fail (priv->is_authenticated, FALSE);
1667 
1668     /* Read until the session is started */
1669     if (!send_start_session (greeter, session, error))
1670         return FALSE;
1671     Request *request = request_new (greeter, NULL, NULL, NULL);
1672     priv->start_session_requests = g_list_append (priv->start_session_requests, g_object_ref (request));
1673     do
1674     {
1675         g_autofree guint8 *message = NULL;
1676         gsize message_length;
1677         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1678             return FALSE;
1679         handle_message (greeter, message, message_length);
1680     } while (!request->complete);
1681 
1682     return lightdm_greeter_start_session_finish (greeter, G_ASYNC_RESULT (request), error);
1683 }
1684 
1685 /**
1686  * lightdm_greeter_ensure_shared_data_dir:
1687  * @greeter: A #LightDMGreeter
1688  * @username: A username
1689  * @cancellable: (allow-none): A #GCancellable or %NULL.
1690  * @callback: (allow-none): A #GAsyncReadyCallback to call when completed or %NULL.
1691  * @user_data: (allow-none): data to pass to the @callback or %NULL.
1692  *
1693  * Ensure that a shared data dir for the given user is available.  Both the
1694  * greeter user and @username will have write access to that folder.  The
1695  * intention is that larger pieces of shared data would be stored there (files
1696  * that the greeter creates but wants to give to a user -- like camera
1697  * photos -- or files that the user creates but wants the greeter to
1698  * see -- like contact avatars).
1699  *
1700  * LightDM will automatically create these if the user actually logs in, so
1701  * greeters only need to call this method if they want to store something in
1702  * the directory themselves.
1703  **/
1704 void
lightdm_greeter_ensure_shared_data_dir(LightDMGreeter * greeter,const gchar * username,GCancellable * cancellable,GAsyncReadyCallback callback,gpointer user_data)1705 lightdm_greeter_ensure_shared_data_dir (LightDMGreeter *greeter, const gchar *username, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data)
1706 {
1707     g_return_if_fail (LIGHTDM_IS_GREETER (greeter));
1708 
1709     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1710 
1711     Request *request = request_new (greeter, cancellable, callback, user_data);
1712     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, request);
1713     GError *error = NULL;
1714     if (!send_ensure_shared_data_dir (greeter, username, &error))
1715     {
1716         request->error = error;
1717         request_complete (request);
1718     }
1719 }
1720 
1721 /**
1722  * lightdm_greeter_ensure_shared_data_dir_finish:
1723  * @result: A #GAsyncResult.
1724  * @greeter: A #LightDMGreeter
1725  * @error: return location for a #GError, or %NULL
1726  *
1727  * Function to call from lightdm_greeter_ensure_shared_data_dir callback.
1728  *
1729  * Return value: The path to the shared directory, free with g_free.
1730  **/
1731 gchar *
lightdm_greeter_ensure_shared_data_dir_finish(LightDMGreeter * greeter,GAsyncResult * result,GError ** error)1732 lightdm_greeter_ensure_shared_data_dir_finish (LightDMGreeter *greeter, GAsyncResult *result, GError **error)
1733 {
1734     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1735 
1736     Request *request = REQUEST (result);
1737     if (request->error)
1738         g_propagate_error (error, request->error);
1739     return g_strdup (request->dir);
1740 }
1741 
1742 /**
1743  * lightdm_greeter_ensure_shared_data_dir_sync:
1744  * @greeter: A #LightDMGreeter
1745  * @username: A username
1746  * @error: return location for a #GError, or %NULL
1747  *
1748  * Ensure that a shared data dir for the given user is available.  Both the
1749  * greeter user and @username will have write access to that folder.  The
1750  * intention is that larger pieces of shared data would be stored there (files
1751  * that the greeter creates but wants to give to a user -- like camera
1752  * photos -- or files that the user creates but wants the greeter to
1753  * see -- like contact avatars).
1754  *
1755  * LightDM will automatically create these if the user actually logs in, so
1756  * greeters only need to call this method if they want to store something in
1757  * the directory themselves.
1758  *
1759  * Return value: The path to the shared directory, free with g_free.
1760  **/
1761 gchar *
lightdm_greeter_ensure_shared_data_dir_sync(LightDMGreeter * greeter,const gchar * username,GError ** error)1762 lightdm_greeter_ensure_shared_data_dir_sync (LightDMGreeter *greeter, const gchar *username, GError **error)
1763 {
1764     g_return_val_if_fail (LIGHTDM_IS_GREETER (greeter), NULL);
1765 
1766     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1767 
1768     g_return_val_if_fail (priv->connected, NULL);
1769 
1770     /* Read until a response */
1771     if (!send_ensure_shared_data_dir (greeter, username, error))
1772         return NULL;
1773     Request *request = request_new (greeter, NULL, NULL, NULL);
1774     priv->ensure_shared_data_dir_requests = g_list_append (priv->ensure_shared_data_dir_requests, g_object_ref (request));
1775     do
1776     {
1777         g_autofree guint8 *message = NULL;
1778         gsize message_length;
1779         if (!recv_message (greeter, TRUE, &message, &message_length, error))
1780             return FALSE;
1781         handle_message (greeter, message, message_length);
1782     } while (!request->complete);
1783 
1784     return lightdm_greeter_ensure_shared_data_dir_finish (greeter, G_ASYNC_RESULT (request), error);
1785 }
1786 
1787 static void
lightdm_greeter_init(LightDMGreeter * greeter)1788 lightdm_greeter_init (LightDMGreeter *greeter)
1789 {
1790     LightDMGreeterPrivate *priv = GET_PRIVATE (greeter);
1791 
1792     priv->read_buffer = g_malloc (HEADER_SIZE);
1793     priv->hints = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1794 }
1795 
1796 static void
lightdm_greeter_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)1797 lightdm_greeter_set_property (GObject      *object,
1798                               guint         prop_id,
1799                               const GValue *value,
1800                               GParamSpec   *pspec)
1801 {
1802     G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1803 }
1804 
1805 static void
lightdm_greeter_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)1806 lightdm_greeter_get_property (GObject    *object,
1807                               guint       prop_id,
1808                               GValue     *value,
1809                               GParamSpec *pspec)
1810 {
1811     LightDMGreeter *self = LIGHTDM_GREETER (object);
1812 
1813     switch (prop_id) {
1814     case PROP_DEFAULT_SESSION_HINT:
1815         g_value_set_string (value, lightdm_greeter_get_default_session_hint (self));
1816         break;
1817     case PROP_HIDE_USERS_HINT:
1818         g_value_set_boolean (value, lightdm_greeter_get_hide_users_hint (self));
1819         break;
1820     case PROP_SHOW_MANUAL_LOGIN_HINT:
1821         g_value_set_boolean (value, lightdm_greeter_get_show_manual_login_hint (self));
1822         break;
1823     case PROP_SHOW_REMOTE_LOGIN_HINT:
1824         g_value_set_boolean (value, lightdm_greeter_get_show_remote_login_hint (self));
1825         break;
1826     case PROP_LOCK_HINT:
1827         g_value_set_boolean (value, lightdm_greeter_get_lock_hint (self));
1828         break;
1829     case PROP_HAS_GUEST_ACCOUNT_HINT:
1830         g_value_set_boolean (value, lightdm_greeter_get_has_guest_account_hint (self));
1831         break;
1832     case PROP_SELECT_USER_HINT:
1833         g_value_set_string (value, lightdm_greeter_get_select_user_hint (self));
1834         break;
1835     case PROP_SELECT_GUEST_HINT:
1836         g_value_set_boolean (value, lightdm_greeter_get_select_guest_hint (self));
1837         break;
1838     case PROP_AUTOLOGIN_USER_HINT:
1839         g_value_set_string (value, lightdm_greeter_get_autologin_user_hint (self));
1840         break;
1841     case PROP_AUTOLOGIN_SESSION_HINT:
1842         g_value_set_string (value, lightdm_greeter_get_autologin_session_hint (self));
1843         break;
1844     case PROP_AUTOLOGIN_GUEST_HINT:
1845         g_value_set_boolean (value, lightdm_greeter_get_autologin_guest_hint (self));
1846         break;
1847     case PROP_AUTOLOGIN_TIMEOUT_HINT:
1848         g_value_set_int (value, lightdm_greeter_get_autologin_timeout_hint (self));
1849         break;
1850     case PROP_AUTHENTICATION_USER:
1851         g_value_set_string (value, lightdm_greeter_get_authentication_user (self));
1852         break;
1853     case PROP_IN_AUTHENTICATION:
1854         g_value_set_boolean (value, lightdm_greeter_get_in_authentication (self));
1855         break;
1856     case PROP_IS_AUTHENTICATED:
1857         g_value_set_boolean (value, lightdm_greeter_get_is_authenticated (self));
1858         break;
1859     default:
1860         G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
1861         break;
1862     }
1863 }
1864 
1865 static void
lightdm_greeter_finalize(GObject * object)1866 lightdm_greeter_finalize (GObject *object)
1867 {
1868     LightDMGreeter *self = LIGHTDM_GREETER (object);
1869     LightDMGreeterPrivate *priv = GET_PRIVATE (self);
1870 
1871     g_clear_object (&priv->socket);
1872     if (priv->to_server_channel)
1873         g_io_channel_unref (priv->to_server_channel);
1874     if (priv->from_server_channel)
1875         g_io_channel_unref (priv->from_server_channel);
1876     if (priv->from_server_watch)
1877         g_source_remove (priv->from_server_watch);
1878     priv->from_server_watch = 0;
1879     g_clear_pointer (&priv->read_buffer, g_free);
1880     g_list_free_full (priv->responses_received, g_free);
1881     priv->responses_received = NULL;
1882     g_list_free_full (priv->connect_requests, g_object_unref);
1883     priv->connect_requests = NULL;
1884     g_list_free_full (priv->start_session_requests, g_object_unref);
1885     priv->start_session_requests = NULL;
1886     g_list_free_full (priv->ensure_shared_data_dir_requests, g_object_unref);
1887     priv->ensure_shared_data_dir_requests = NULL;
1888     g_clear_pointer (&priv->authentication_user, g_free);
1889     g_hash_table_unref (priv->hints);
1890     priv->hints = NULL;
1891 
1892     G_OBJECT_CLASS (lightdm_greeter_parent_class)->finalize (object);
1893 }
1894 
1895 static void
lightdm_greeter_class_init(LightDMGreeterClass * klass)1896 lightdm_greeter_class_init (LightDMGreeterClass *klass)
1897 {
1898     GObjectClass *object_class = G_OBJECT_CLASS (klass);
1899 
1900     object_class->set_property = lightdm_greeter_set_property;
1901     object_class->get_property = lightdm_greeter_get_property;
1902     object_class->finalize = lightdm_greeter_finalize;
1903 
1904     g_object_class_install_property (object_class,
1905                                      PROP_DEFAULT_SESSION_HINT,
1906                                      g_param_spec_string ("default-session-hint",
1907                                                           "default-session-hint",
1908                                                           "Default session hint",
1909                                                           NULL,
1910                                                           G_PARAM_READABLE));
1911 
1912     g_object_class_install_property (object_class,
1913                                      PROP_HIDE_USERS_HINT,
1914                                      g_param_spec_boolean ("hide-users-hint",
1915                                                            "hide-users-hint",
1916                                                            "Hide users hint",
1917                                                            FALSE,
1918                                                            G_PARAM_READABLE));
1919 
1920     g_object_class_install_property (object_class,
1921                                      PROP_SHOW_MANUAL_LOGIN_HINT,
1922                                      g_param_spec_boolean ("show-manual-login-hint",
1923                                                            "show-manual-login-hint",
1924                                                            "Show manual login hint",
1925                                                            FALSE,
1926                                                            G_PARAM_READABLE));
1927 
1928     g_object_class_install_property (object_class,
1929                                      PROP_SHOW_REMOTE_LOGIN_HINT,
1930                                      g_param_spec_boolean ("show-remote-login-hint",
1931                                                            "show-remote-login-hint",
1932                                                            "Show remote login hint",
1933                                                            FALSE,
1934                                                            G_PARAM_READABLE));
1935 
1936     g_object_class_install_property (object_class,
1937                                      PROP_LOCK_HINT,
1938                                      g_param_spec_boolean ("lock-hint",
1939                                                            "lock-hint",
1940                                                            "Lock hint",
1941                                                            FALSE,
1942                                                            G_PARAM_READABLE));
1943 
1944     g_object_class_install_property (object_class,
1945                                      PROP_HAS_GUEST_ACCOUNT_HINT,
1946                                      g_param_spec_boolean ("has-guest-account-hint",
1947                                                            "has-guest-account-hint",
1948                                                            "Has guest account hint",
1949                                                            FALSE,
1950                                                            G_PARAM_READABLE));
1951 
1952     g_object_class_install_property (object_class,
1953                                      PROP_SELECT_USER_HINT,
1954                                      g_param_spec_string ("select-user-hint",
1955                                                           "select-user-hint",
1956                                                           "Select user hint",
1957                                                           NULL,
1958                                                           G_PARAM_READABLE));
1959 
1960     g_object_class_install_property (object_class,
1961                                      PROP_SELECT_GUEST_HINT,
1962                                      g_param_spec_boolean ("select-guest-hint",
1963                                                            "select-guest-hint",
1964                                                            "Select guest account hint",
1965                                                            FALSE,
1966                                                            G_PARAM_READABLE));
1967 
1968     g_object_class_install_property (object_class,
1969                                      PROP_AUTOLOGIN_USER_HINT,
1970                                      g_param_spec_string ("autologin-user-hint",
1971                                                           "autologin-user-hint",
1972                                                           "Autologin user hint",
1973                                                           NULL,
1974                                                           G_PARAM_READABLE));
1975 
1976     g_object_class_install_property (object_class,
1977                                      PROP_AUTOLOGIN_SESSION_HINT,
1978                                      g_param_spec_string ("autologin-session-hint",
1979                                                           "autologin-session-hint",
1980                                                           "Autologin session hint",
1981                                                           NULL,
1982                                                           G_PARAM_READABLE));
1983 
1984     g_object_class_install_property (object_class,
1985                                      PROP_AUTOLOGIN_GUEST_HINT,
1986                                      g_param_spec_boolean ("autologin-guest-hint",
1987                                                            "autologin-guest-hint",
1988                                                            "Autologin guest account hint",
1989                                                            FALSE,
1990                                                            G_PARAM_READABLE));
1991 
1992     g_object_class_install_property (object_class,
1993                                      PROP_AUTOLOGIN_TIMEOUT_HINT,
1994                                      g_param_spec_int ("autologin-timeout-hint",
1995                                                        "autologin-timeout-hint",
1996                                                        "Autologin timeout hint",
1997                                                        0, G_MAXINT, 0,
1998                                                        G_PARAM_READABLE));
1999 
2000     g_object_class_install_property (object_class,
2001                                      PROP_AUTHENTICATION_USER,
2002                                      g_param_spec_string ("authentication-user",
2003                                                           "authentication-user",
2004                                                           "The user being authenticated",
2005                                                           NULL,
2006                                                           G_PARAM_READABLE));
2007     g_object_class_install_property (object_class,
2008                                      PROP_IN_AUTHENTICATION,
2009                                      g_param_spec_boolean ("in-authentication",
2010                                                            "in-authentication",
2011                                                            "TRUE if a user is being authenticated",
2012                                                            FALSE,
2013                                                            G_PARAM_READABLE));
2014     g_object_class_install_property (object_class,
2015                                      PROP_IS_AUTHENTICATED,
2016                                      g_param_spec_boolean ("is-authenticated",
2017                                                            "is-authenticated",
2018                                                            "TRUE if the selected user is authenticated",
2019                                                            FALSE,
2020                                                            G_PARAM_READABLE));
2021 
2022     /**
2023      * LightDMGreeter::show-prompt:
2024      * @greeter: A #LightDMGreeter
2025      * @text: Prompt text
2026      * @type: Prompt type
2027      *
2028      * The ::show-prompt signal gets emitted when the greeter should show a
2029      * prompt to the user.  The given text should be displayed and an input
2030      * field for the user to provide a response.
2031      *
2032      * Call lightdm_greeter_respond() with the resultant input or
2033      * lightdm_greeter_cancel_authentication() to abort the authentication.
2034      **/
2035     signals[SHOW_PROMPT] =
2036         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_PROMPT,
2037                       G_TYPE_FROM_CLASS (klass),
2038                       G_SIGNAL_RUN_LAST,
2039                       G_STRUCT_OFFSET (LightDMGreeterClass, show_prompt),
2040                       NULL, NULL,
2041                       NULL,
2042                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_prompt_type_get_type ());
2043 
2044     /**
2045      * LightDMGreeter::show-message:
2046      * @greeter: A #LightDMGreeter
2047      * @text: Message text
2048      * @type: Message type
2049      *
2050      * The ::show-message signal gets emitted when the greeter
2051      * should show a message to the user.
2052      **/
2053     signals[SHOW_MESSAGE] =
2054         g_signal_new (LIGHTDM_GREETER_SIGNAL_SHOW_MESSAGE,
2055                       G_TYPE_FROM_CLASS (klass),
2056                       G_SIGNAL_RUN_LAST,
2057                       G_STRUCT_OFFSET (LightDMGreeterClass, show_message),
2058                       NULL, NULL,
2059                       NULL,
2060                       G_TYPE_NONE, 2, G_TYPE_STRING, lightdm_message_type_get_type ());
2061 
2062     /**
2063      * LightDMGreeter::authentication-complete:
2064      * @greeter: A #LightDMGreeter
2065      *
2066      * The ::authentication-complete signal gets emitted when the greeter
2067      * has completed authentication.
2068      *
2069      * Call lightdm_greeter_get_is_authenticated() to check if the authentication
2070      * was successful.
2071      **/
2072     signals[AUTHENTICATION_COMPLETE] =
2073         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTHENTICATION_COMPLETE,
2074                       G_TYPE_FROM_CLASS (klass),
2075                       G_SIGNAL_RUN_LAST,
2076                       G_STRUCT_OFFSET (LightDMGreeterClass, authentication_complete),
2077                       NULL, NULL,
2078                       NULL,
2079                       G_TYPE_NONE, 0);
2080 
2081     /**
2082      * LightDMGreeter::autologin-timer-expired:
2083      * @greeter: A #LightDMGreeter
2084      *
2085      * The ::timed-login signal gets emitted when the automatic login timer has expired.
2086      * The application should then call lightdm_greeter_authenticate_autologin().
2087      **/
2088     signals[AUTOLOGIN_TIMER_EXPIRED] =
2089         g_signal_new (LIGHTDM_GREETER_SIGNAL_AUTOLOGIN_TIMER_EXPIRED,
2090                       G_TYPE_FROM_CLASS (klass),
2091                       G_SIGNAL_RUN_LAST,
2092                       G_STRUCT_OFFSET (LightDMGreeterClass, autologin_timer_expired),
2093                       NULL, NULL,
2094                       NULL,
2095                       G_TYPE_NONE, 0);
2096 
2097     /**
2098      * LightDMGreeter::idle:
2099      * @greeter: A #LightDMGreeter
2100      *
2101      * The ::idle signal gets emitted when the user has logged in and the
2102      * greeter is no longer needed.
2103      *
2104      * This signal only matters if the greeter has marked itself as
2105      * resettable using lightdm_greeter_set_resettable().
2106      **/
2107     signals[IDLE] =
2108         g_signal_new (LIGHTDM_GREETER_SIGNAL_IDLE,
2109                       G_TYPE_FROM_CLASS (klass),
2110                       G_SIGNAL_RUN_LAST,
2111                       G_STRUCT_OFFSET (LightDMGreeterClass, idle),
2112                       NULL, NULL,
2113                       NULL,
2114                       G_TYPE_NONE, 0);
2115 
2116     /**
2117      * LightDMGreeter::reset:
2118      * @greeter: A #LightDMGreeter
2119      *
2120      * The ::reset signal gets emitted when the user is returning to a greeter
2121      * that was previously marked idle.
2122      *
2123      * This signal only matters if the greeter has marked itself as
2124      * resettable using lightdm_greeter_set_resettable().
2125      **/
2126     signals[RESET] =
2127         g_signal_new (LIGHTDM_GREETER_SIGNAL_RESET,
2128                       G_TYPE_FROM_CLASS (klass),
2129                       G_SIGNAL_RUN_LAST,
2130                       G_STRUCT_OFFSET (LightDMGreeterClass, reset),
2131                       NULL, NULL,
2132                       NULL,
2133                       G_TYPE_NONE, 0);
2134 }
2135 
2136 static void
request_init(Request * request)2137 request_init (Request *request)
2138 {
2139 }
2140 
2141 static void
request_finalize(GObject * object)2142 request_finalize (GObject *object)
2143 {
2144     Request *request = REQUEST (object);
2145 
2146     g_clear_object (&request->cancellable);
2147     g_free (request->dir);
2148 
2149     G_OBJECT_CLASS (request_parent_class)->finalize (object);
2150 }
2151 
2152 static void
request_class_init(RequestClass * klass)2153 request_class_init (RequestClass *klass)
2154 {
2155     GObjectClass *object_class = G_OBJECT_CLASS (klass);
2156     object_class->finalize = request_finalize;
2157 }
2158 
2159 static gpointer
request_get_user_data(GAsyncResult * result)2160 request_get_user_data (GAsyncResult *result)
2161 {
2162     return REQUEST (result)->user_data;
2163 }
2164 
2165 static GObject *
request_get_source_object(GAsyncResult * result)2166 request_get_source_object (GAsyncResult *result)
2167 {
2168     return g_object_ref (G_OBJECT (REQUEST (result)->greeter));
2169 }
2170 
2171 static void
request_iface_init(GAsyncResultIface * iface)2172 request_iface_init (GAsyncResultIface *iface)
2173 {
2174     iface->get_user_data = request_get_user_data;
2175     iface->get_source_object = request_get_source_object;
2176 }
2177