]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/session.c
Fixes for lightdm-set-defaults.
[sojka/lightdm.git] / src / session.c
1 /*
2  * Copyright (C) 2010-2011 Robert Ancell.
3  * Author: Robert Ancell <robert.ancell@canonical.com>
4  *
5  * This program is free software: you can redistribute it and/or modify it under
6  * the terms of the GNU General Public License as published by the Free Software
7  * Foundation, either version 3 of the License, or (at your option) any later
8  * version. See http://www.gnu.org/copyleft/gpl.html the full text of the
9  * license.
10  */
11
12 #include <config.h>
13
14 #include <stdlib.h>
15 #include <string.h>
16 #include <errno.h>
17 #include <unistd.h>
18 #include <sys/wait.h>
19 #include <fcntl.h>
20 #include <glib/gstdio.h>
21 #include <grp.h>
22 #include <pwd.h>
23
24 #include "session.h"
25 #include "configuration.h"
26 #include "console-kit.h"
27 #include "login1.h"
28 #include "guest-account.h"
29
30 enum {
31     GOT_MESSAGES,
32     AUTHENTICATION_COMPLETE,
33     STOPPED,
34     LAST_SIGNAL
35 };
36 static guint signals[LAST_SIGNAL] = { 0 };
37
38 struct SessionPrivate
39 {
40     /* PID of child process */
41     GPid pid;
42
43     /* Pipes to talk to child */
44     int to_child_input;
45     int from_child_output;
46     GIOChannel *from_child_channel;
47     guint from_child_watch;
48     guint child_watch;
49
50     /* User to authenticate as */
51     gchar *username;
52
53     /* TRUE if is a guest account */
54     gboolean is_guest;
55
56     /* User object that matches the current username */
57     User *user;
58
59     /* Messages being requested by PAM */
60     int messages_length;
61     struct pam_message *messages;
62
63     /* Authentication result from PAM */
64     gboolean authentication_started;
65     gboolean authentication_complete;
66     int authentication_result;
67     gchar *authentication_result_string;
68
69     /* File to log to */
70     gchar *log_filename;
71
72     /* Seat class */
73     gchar *class;
74
75     /* tty this session is running on */
76     gchar *tty;
77
78     /* X display connected to */
79     gchar *xdisplay;
80     XAuthority *xauthority;
81     gboolean xauth_use_system_location;
82
83     /* Remote host this session is being controlled from */
84     gchar *remote_host_name;
85
86     /* Console kit cookie */
87     gchar *console_kit_cookie;
88
89     /* login1 session */
90     gchar *login1_session;
91
92     /* Environment to set in child */
93     GList *env;
94 };
95
96 /* Maximum length of a string to pass between daemon and session */
97 #define MAX_STRING_LENGTH 65535
98
99 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
100
101 void
102 session_set_log_file (Session *session, const gchar *filename)
103 {
104     g_return_if_fail (session != NULL);
105     g_free (session->priv->log_filename);
106     session->priv->log_filename = g_strdup (filename);
107 }
108
109 void
110 session_set_class (Session *session, const gchar *class)
111 {
112     g_return_if_fail (session != NULL);
113     g_free (session->priv->class);
114     session->priv->class = g_strdup (class);
115 }
116
117 void
118 session_set_tty (Session *session, const gchar *tty)
119 {
120     g_return_if_fail (session != NULL);
121     g_free (session->priv->tty);
122     session->priv->tty = g_strdup (tty);
123 }
124
125 void
126 session_set_xdisplay (Session *session, const gchar *xdisplay)
127 {
128     g_return_if_fail (session != NULL);
129     g_free (session->priv->xdisplay);
130     session->priv->xdisplay = g_strdup (xdisplay);
131 }
132
133 void
134 session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
135 {
136     g_return_if_fail (session != NULL);
137     if (session->priv->xauthority)
138         g_object_unref (session->priv->xauthority);
139     session->priv->xauthority = g_object_ref (authority);
140     session->priv->xauth_use_system_location = use_system_location;
141 }
142
143 void
144 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
145 {
146     g_return_if_fail (session != NULL);
147     g_free (session->priv->remote_host_name);
148     session->priv->remote_host_name = g_strdup (remote_host_name);
149 }
150
151 void
152 session_set_env (Session *session, const gchar *name, const gchar *value)
153 {
154     g_return_if_fail (session != NULL);
155     session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
156 }
157
158 User *
159 session_get_user (Session *session)
160 {
161     g_return_val_if_fail (session != NULL, NULL);
162
163     if (session->priv->username == NULL)
164         return NULL;
165
166     if (!session->priv->user)
167         session->priv->user = accounts_get_user_by_name (session->priv->username);
168
169     return session->priv->user;
170 }
171
172 static void
173 write_data (Session *session, const void *buf, size_t count)
174 {
175     if (write (session->priv->to_child_input, buf, count) != count)
176         g_warning ("Error writing to session: %s", strerror (errno));
177 }
178
179 static void
180 write_string (Session *session, const char *value)
181 {
182     int length;
183
184     length = value ? strlen (value) : -1;
185     write_data (session, &length, sizeof (length));
186     if (value)
187         write_data (session, value, sizeof (char) * length);
188 }
189
190 static ssize_t
191 read_from_child (Session *session, void *buf, size_t count)
192 {
193     ssize_t n_read;
194     n_read = read (session->priv->from_child_output, buf, count);
195     if (n_read < 0)
196         g_warning ("Error reading from session: %s", strerror (errno));
197     return n_read;
198 }
199
200 static gchar *
201 read_string_from_child (Session *session)
202 {
203     int length;
204     char *value;
205
206     if (read_from_child (session, &length, sizeof (length)) <= 0)
207         return NULL;
208     if (length < 0)
209         return NULL;
210     if (length > MAX_STRING_LENGTH)
211     {
212         g_warning ("Invalid string length %d from child", length);
213         return NULL;
214     }
215
216     value = g_malloc (sizeof (char) * (length + 1));
217     read_from_child (session, value, length);
218     value[length] = '\0';
219
220     return value;
221 }
222
223 static void
224 session_watch_cb (GPid pid, gint status, gpointer data)
225 {
226     Session *session = data;
227
228     session->priv->pid = 0;
229
230     if (WIFEXITED (status))
231         g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
232     else if (WIFSIGNALED (status))
233         g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
234
235     /* If failed during authentication then report this as an authentication failure */
236     if (session->priv->authentication_started && !session->priv->authentication_complete)
237     {
238         g_debug ("Session %d failed during authentication", pid);
239         session->priv->authentication_complete = TRUE;
240         session->priv->authentication_result = PAM_CONV_ERR;
241         g_free (session->priv->authentication_result_string);
242         session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
243         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
244     }
245
246     g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
247
248     /* Delete account if it is a guest one */
249     if (session->priv->is_guest)
250         guest_account_cleanup (session->priv->username);
251
252     /* Drop our reference on the child process, it has terminated */
253     g_object_unref (session);
254 }
255
256 static gboolean
257 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
258 {
259     Session *session = data;
260     gchar *username;
261     ssize_t n_read;
262     gboolean auth_complete;
263
264     /* Remote end gone */
265     if (condition == G_IO_HUP)
266     {
267         session->priv->from_child_watch = 0;
268         return FALSE;
269     }
270
271     /* Get the username currently being authenticated (may change during authentication) */
272     username = read_string_from_child (session);
273     if (g_strcmp0 (username, session->priv->username) != 0)
274     {
275         g_free (session->priv->username);
276         session->priv->username = username;
277         if (session->priv->user)
278             g_object_unref (session->priv->user);
279         session->priv->user = NULL;
280     }
281     else
282         g_free (username);
283
284     /* Check if authentication completed */
285     n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
286     if (n_read < 0)
287         g_debug ("Error reading from child: %s", strerror (errno));
288     if (n_read <= 0)
289     {
290         session->priv->from_child_watch = 0;
291         return FALSE;
292     }
293
294     if (auth_complete)
295     {
296         session->priv->authentication_complete = TRUE;
297         read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
298         g_free (session->priv->authentication_result_string);
299         session->priv->authentication_result_string = read_string_from_child (session);
300
301         g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
302
303         /* No longer expect any more messages */
304         session->priv->from_child_watch = 0;
305
306         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
307
308         return FALSE;
309     }
310     else
311     {
312         int i;
313
314         session->priv->messages_length = 0;
315         read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
316         session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
317         for (i = 0; i < session->priv->messages_length; i++)
318         {
319             struct pam_message *m = &session->priv->messages[i];
320             read_from_child (session, &m->msg_style, sizeof (m->msg_style));
321             m->msg = read_string_from_child (session);
322         }
323
324         g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
325
326         g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
327     }
328
329     return TRUE;
330 }
331
332 gboolean
333 session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive, gboolean is_guest)
334 {
335     int version;
336     int to_child_pipe[2], from_child_pipe[2];
337     int to_child_output, from_child_input;
338
339     g_return_val_if_fail (session != NULL, FALSE);
340     g_return_val_if_fail (service != NULL, FALSE);
341     g_return_val_if_fail (session->priv->pid == 0, FALSE);
342
343     /* Create pipes to talk to the child */
344     if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
345     {
346         g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
347         return FALSE;
348     }
349     to_child_output = to_child_pipe[0];
350     session->priv->to_child_input = to_child_pipe[1];
351     session->priv->from_child_output = from_child_pipe[0];
352     from_child_input = from_child_pipe[1];
353     session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
354     session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
355
356     /* Don't allow the daemon end of the pipes to be accessed in child processes */
357     fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
358     fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
359
360     /* Create the guest account if it is one */
361     session->priv->is_guest = is_guest;
362     if (is_guest && username == NULL)
363         username = guest_account_setup ();
364
365     /* Remember what username we started with - it will be updated by PAM during authentication */
366     session->priv->username = g_strdup (username);
367
368     /* Run the child */
369     session->priv->pid = fork ();
370     if (session->priv->pid < 0)
371     {
372         g_debug ("Failed to fork session child process: %s", strerror (errno));
373         return FALSE;
374     }
375
376     if (session->priv->pid == 0)
377     {
378         /* Run us again in session child mode */
379         execlp ("lightdm",
380                 "lightdm",
381                 "--session-child",
382                 g_strdup_printf ("%d", to_child_output),
383                 g_strdup_printf ("%d", from_child_input),
384                 NULL);
385         _exit (EXIT_FAILURE);
386     }
387
388     /* Hold a reference on this object until the child process terminates so we
389      * can handle the watch callback even if it is no longer used. Otherwise a
390      * zombie process will remain */
391     g_object_ref (session);
392
393     /* Listen for session termination */
394     session->priv->authentication_started = TRUE;
395     session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
396
397     /* Close the ends of the pipes we don't need */
398     close (to_child_output);
399     close (from_child_input);
400
401     /* Indicate what version of the protocol we are using */
402     version = 0;
403     write_data (session, &version, sizeof (version));
404
405     /* Send configuration */
406     write_string (session, service);
407     write_string (session, username);
408     write_data (session, &do_authenticate, sizeof (do_authenticate));
409     write_data (session, &is_interactive, sizeof (is_interactive));
410     write_string (session, session->priv->class);
411     write_string (session, session->priv->tty);
412     write_string (session, session->priv->remote_host_name);
413     write_string (session, session->priv->xdisplay);
414     if (session->priv->xauthority)
415     {
416         guint16 family;
417         gsize length;
418
419         write_string (session, xauth_get_authorization_name (session->priv->xauthority));
420         family = xauth_get_family (session->priv->xauthority);
421         write_data (session, &family, sizeof (family));
422         length = xauth_get_address_length (session->priv->xauthority);
423         write_data (session, &length, sizeof (length));
424         write_data (session, xauth_get_address (session->priv->xauthority), length);
425         write_string (session, xauth_get_number (session->priv->xauthority));
426         length = xauth_get_authorization_data_length (session->priv->xauthority);
427         write_data (session, &length, sizeof (length));
428         write_data (session, xauth_get_authorization_data (session->priv->xauthority), length);
429     }
430     else
431         write_string (session, NULL);
432
433     g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, service, username);
434
435     return TRUE;
436 }
437
438 const gchar *
439 session_get_username (Session *session)
440 {
441     g_return_val_if_fail (session != NULL, NULL);
442     return session->priv->username;
443 }
444
445 const gchar *
446 session_get_console_kit_cookie (Session *session)
447 {
448     g_return_val_if_fail (session != NULL, NULL);
449     return session->priv->console_kit_cookie;
450 }
451
452 void
453 session_respond (Session *session, struct pam_response *response)
454 {
455     int error = PAM_SUCCESS;
456     int i;
457
458     g_return_if_fail (session != NULL);
459
460     write_data (session, &error, sizeof (error));
461     for (i = 0; i < session->priv->messages_length; i++)
462     {
463         write_string (session, response[i].resp);
464         write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
465     }
466
467     /* Delete the old messages */
468     for (i = 0; i < session->priv->messages_length; i++)
469         g_free ((char *) session->priv->messages[i].msg);
470     g_free (session->priv->messages);
471     session->priv->messages = NULL;
472     session->priv->messages_length = 0;
473 }
474
475 void
476 session_respond_error (Session *session, int error)
477 {
478     g_return_if_fail (session != NULL);
479     g_return_if_fail (error != PAM_SUCCESS);
480
481     write_data (session, &error, sizeof (error));
482 }
483
484 int
485 session_get_messages_length (Session *session)
486 {
487     g_return_val_if_fail (session != NULL, 0);
488     return session->priv->messages_length;
489 }
490
491 const struct pam_message *
492 session_get_messages (Session *session)
493 {
494     g_return_val_if_fail (session != NULL, NULL);
495     return session->priv->messages;
496 }
497
498 gboolean
499 session_get_is_authenticated (Session *session)
500 {
501     g_return_val_if_fail (session != NULL, FALSE);
502     return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
503 }
504
505 int
506 session_get_authentication_result (Session *session)
507 {
508     g_return_val_if_fail (session != NULL, 0);
509     return session->priv->authentication_result;
510 }
511
512 const gchar *
513 session_get_authentication_result_string (Session *session)
514 {
515     g_return_val_if_fail (session != NULL, NULL);
516     return session->priv->authentication_result_string;
517 }
518
519 void
520 session_run (Session *session, gchar **argv)
521 {
522     gsize i, argc;
523     gchar *command, *filename;
524     GList *link;
525
526     g_return_if_fail (session != NULL);
527     g_return_if_fail (session_get_is_authenticated (session));
528
529     command = g_strjoinv (" ", argv);
530     g_debug ("Session %d running command %s", session->priv->pid, command);
531     g_free (command);
532
533     /* Create authority location */
534     if (session->priv->xauth_use_system_location)
535     {
536         gchar *run_dir, *dir;
537
538         run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
539         dir = g_build_filename (run_dir, session->priv->username, NULL);
540         g_free (run_dir);
541
542         if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
543             g_warning ("Failed to set create system authority dir %s: %s", dir, strerror (errno));          
544         if (getuid () == 0)
545         {
546             if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
547                 g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
548         }
549
550         filename = g_build_filename (dir, "xauthority", NULL);
551         g_free (dir);
552     }
553     else
554         filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
555
556     write_string (session, session->priv->log_filename);
557     write_string (session, filename);
558     g_free (filename);
559     argc = g_list_length (session->priv->env);
560     write_data (session, &argc, sizeof (argc));
561     for (link = session->priv->env; link; link = link->next)
562         write_string (session, (gchar *) link->data);
563     argc = g_strv_length (argv);
564     write_data (session, &argc, sizeof (argc));
565     for (i = 0; i < argc; i++)
566         write_string (session, argv[i]);
567
568     if (login1_is_running ())
569       session->priv->login1_session = read_string_from_child (session);
570     if (!session->priv->login1_session)
571       session->priv->console_kit_cookie = read_string_from_child (session);
572 }
573
574 void
575 session_lock (Session *session)
576 {
577     g_return_if_fail (session != NULL);
578     if (getuid () == 0)
579     {
580         if (login1_is_running ())
581             login1_lock_session (session->priv->login1_session);
582         if (!session->priv->login1_session)
583             ck_lock_session (session->priv->console_kit_cookie);
584     }
585 }
586
587 void
588 session_unlock (Session *session)
589 {
590     g_return_if_fail (session != NULL);
591     if (getuid () == 0)
592     {
593         if (login1_is_running ())
594             login1_unlock_session (session->priv->login1_session);
595         if (!session->priv->login1_session)
596             ck_unlock_session (session->priv->console_kit_cookie);
597     }
598 }
599
600 void
601 session_stop (Session *session)
602 {
603     g_return_if_fail (session != NULL);
604
605     if (session->priv->pid > 0)
606     {
607         g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
608         kill (session->priv->pid, SIGTERM);
609         // FIXME: Handle timeout
610     }
611 }
612
613 gboolean
614 session_get_is_stopped (Session *session)
615 {
616     g_return_val_if_fail (session != NULL, TRUE);
617     return session->priv->pid == 0;
618 }
619
620 static void
621 session_init (Session *session)
622 {
623     session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
624 }
625
626 static void
627 session_finalize (GObject *object)
628 {
629     Session *self = SESSION (object);
630     int i;
631
632     if (self->priv->pid)
633         kill (self->priv->pid, SIGKILL);
634     if (self->priv->from_child_channel)
635         g_io_channel_unref (self->priv->from_child_channel);
636     if (self->priv->from_child_watch)
637         g_source_remove (self->priv->from_child_watch);
638     if (self->priv->child_watch)
639         g_source_remove (self->priv->child_watch);
640     g_free (self->priv->username);
641     if (self->priv->user)
642         g_object_unref (self->priv->user);
643     for (i = 0; i < self->priv->messages_length; i++)
644         g_free ((char *) self->priv->messages[i].msg);
645     g_free (self->priv->messages);
646     g_free (self->priv->authentication_result_string);
647     g_free (self->priv->log_filename);
648     g_free (self->priv->class);
649     g_free (self->priv->tty);
650     g_free (self->priv->xdisplay);
651     if (self->priv->xauthority)
652         g_object_unref (self->priv->xauthority);
653     g_free (self->priv->remote_host_name);
654     g_free (self->priv->login1_session);
655     g_free (self->priv->console_kit_cookie);
656     g_list_free_full (self->priv->env, g_free);
657
658     G_OBJECT_CLASS (session_parent_class)->finalize (object);
659 }
660
661 static void
662 session_class_init (SessionClass *klass)
663 {
664     GObjectClass *object_class = G_OBJECT_CLASS (klass);
665
666     object_class->finalize = session_finalize;
667
668     g_type_class_add_private (klass, sizeof (SessionPrivate));
669
670     signals[GOT_MESSAGES] =
671         g_signal_new ("got-messages",
672                       G_TYPE_FROM_CLASS (klass),
673                       G_SIGNAL_RUN_LAST,
674                       G_STRUCT_OFFSET (SessionClass, got_messages),
675                       NULL, NULL,
676                       g_cclosure_marshal_VOID__VOID,
677                       G_TYPE_NONE, 0);
678
679     signals[AUTHENTICATION_COMPLETE] =
680         g_signal_new ("authentication-complete",
681                       G_TYPE_FROM_CLASS (klass),
682                       G_SIGNAL_RUN_LAST,
683                       G_STRUCT_OFFSET (SessionClass, authentication_complete),
684                       NULL, NULL,
685                       g_cclosure_marshal_VOID__VOID,
686                       G_TYPE_NONE, 0);
687
688     signals[STOPPED] =
689         g_signal_new ("stopped",
690                       G_TYPE_FROM_CLASS (klass),
691                       G_SIGNAL_RUN_LAST,
692                       G_STRUCT_OFFSET (SessionClass, stopped),
693                       NULL, NULL,
694                       g_cclosure_marshal_VOID__VOID,
695                       G_TYPE_NONE, 0);
696 }