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