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