]> rtime.felk.cvut.cz Git - sojka/lightdm.git/blob - src/session.c
f7f4ac09657065a94a70f22b57bb5a96e254bc58
[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 #include "shared-data-manager.h"
30
31 enum {
32     GOT_MESSAGES,
33     AUTHENTICATION_COMPLETE,
34     STOPPED,
35     LAST_SIGNAL
36 };
37 static guint signals[LAST_SIGNAL] = { 0 };
38
39 struct SessionPrivate
40 {
41     /* Configuration for this session */
42     SessionConfig *config;
43
44     /* Display server running on */
45     DisplayServer *display_server;
46
47     /* PID of child process */
48     GPid pid;
49
50     /* Pipes to talk to child */
51     int to_child_input;
52     int from_child_output;
53     GIOChannel *from_child_channel;
54     guint from_child_watch;
55     guint child_watch;
56
57     /* User to authenticate as */
58     gchar *username;
59
60     /* TRUE if is a guest account */
61     gboolean is_guest;
62
63     /* User object that matches the current username */
64     User *user;
65
66     /* PAM service to use */
67     gchar *pam_service;
68
69     /* TRUE if should run PAM authentication phase */
70     gboolean do_authenticate;
71
72     /* TRUE if can handle PAM prompts */
73     gboolean is_interactive;
74
75     /* Messages being requested by PAM */
76     int messages_length;
77     struct pam_message *messages;
78
79     /* Authentication result from PAM */
80     gboolean authentication_started;
81     gboolean authentication_complete;
82     int authentication_result;
83     gchar *authentication_result_string;
84
85     /* File to log to */
86     gchar *log_filename;
87
88     /* tty this session is running on */
89     gchar *tty;
90
91     /* X display connected to */
92     gchar *xdisplay;
93     XAuthority *x_authority;
94     gboolean x_authority_use_system_location;
95
96     /* Remote host this session is being controlled from */
97     gchar *remote_host_name;
98
99     /* Console kit cookie */
100     gchar *console_kit_cookie;
101
102     /* login1 session ID */
103     gchar *login1_session_id;
104
105     /* Environment to set in child */
106     GList *env;
107
108     /* Command to run in child */
109     gchar **argv;
110
111     /* True if have run command */
112     gboolean command_run;
113
114     /* TRUE if stopping this session */
115     gboolean stopping;
116 };
117
118 /* Maximum length of a string to pass between daemon and session */
119 #define MAX_STRING_LENGTH 65535
120
121 static void session_logger_iface_init (LoggerInterface *iface);
122
123 G_DEFINE_TYPE_WITH_CODE (Session, session, G_TYPE_OBJECT,
124                          G_IMPLEMENT_INTERFACE (
125                              LOGGER_TYPE, session_logger_iface_init));
126
127 Session *
128 session_new (void)
129 {
130     return g_object_new (SESSION_TYPE, NULL);
131 }
132
133 void
134 session_set_config (Session *session, SessionConfig *config)
135 {
136     g_return_if_fail (session != NULL);
137
138     g_clear_object (&session->priv->config);
139     session->priv->config = g_object_ref (config);
140 }
141
142 SessionConfig *
143 session_get_config (Session *session)
144 {
145     g_return_val_if_fail (session != NULL, NULL);
146     return session->priv->config;
147 }
148
149 const gchar *
150 session_get_session_type (Session *session)
151 {
152     g_return_val_if_fail (session != NULL, NULL);
153     return session_config_get_session_type (session_get_config (session));
154 }
155
156 void
157 session_set_pam_service (Session *session, const gchar *pam_service)
158 {
159     g_return_if_fail (session != NULL);
160     g_free (session->priv->pam_service);
161     session->priv->pam_service = g_strdup (pam_service);
162 }
163
164 void
165 session_set_username (Session *session, const gchar *username)
166 {
167     g_return_if_fail (session != NULL);
168     g_free (session->priv->username);
169     session->priv->username = g_strdup (username);
170 }
171
172 void
173 session_set_do_authenticate (Session *session, gboolean do_authenticate)
174 {
175     g_return_if_fail (session != NULL);
176     session->priv->do_authenticate = do_authenticate;
177 }
178
179 void
180 session_set_is_interactive (Session *session, gboolean is_interactive)
181 {
182     g_return_if_fail (session != NULL);
183     session->priv->is_interactive = is_interactive;
184 }
185
186 void
187 session_set_is_guest (Session *session, gboolean is_guest)
188 {
189     g_return_if_fail (session != NULL);
190     session->priv->is_guest = is_guest;
191 }
192
193 gboolean
194 session_get_is_guest (Session *session)
195 {
196     g_return_val_if_fail (session != NULL, FALSE);
197     return session->priv->is_guest;
198 }
199
200 void
201 session_set_log_file (Session *session, const gchar *filename)
202 {
203     g_return_if_fail (session != NULL);
204     g_free (session->priv->log_filename);
205     session->priv->log_filename = g_strdup (filename);
206 }
207
208 void
209 session_set_display_server (Session *session, DisplayServer *display_server)
210 {
211     g_return_if_fail (session != NULL);
212     g_return_if_fail (display_server != NULL);
213     if (session->priv->display_server)
214     {
215         display_server_disconnect_session (session->priv->display_server, session);
216         g_object_unref (session->priv->display_server);
217     }
218     session->priv->display_server = g_object_ref (display_server);
219 }
220
221 DisplayServer *
222 session_get_display_server (Session *session)
223 {
224     g_return_val_if_fail (session != NULL, NULL);
225     return session->priv->display_server;
226 }
227
228 void
229 session_set_tty (Session *session, const gchar *tty)
230 {
231     g_return_if_fail (session != NULL);
232     g_free (session->priv->tty);
233     session->priv->tty = g_strdup (tty);
234 }
235
236 void
237 session_set_xdisplay (Session *session, const gchar *xdisplay)
238 {
239     g_return_if_fail (session != NULL);
240     g_free (session->priv->xdisplay);
241     session->priv->xdisplay = g_strdup (xdisplay);
242 }
243
244 void
245 session_set_x_authority (Session *session, XAuthority *authority, gboolean use_system_location)
246 {
247     g_return_if_fail (session != NULL);
248     g_clear_object (&session->priv->x_authority);
249     if (authority)
250         session->priv->x_authority = g_object_ref (authority);
251     session->priv->x_authority_use_system_location = use_system_location;
252 }
253
254 void
255 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
256 {
257     g_return_if_fail (session != NULL);
258     g_free (session->priv->remote_host_name);
259     session->priv->remote_host_name = g_strdup (remote_host_name);
260 }
261
262 static GList *
263 find_env_entry (Session *session, const gchar *name)
264 {
265     GList *link;
266
267     for (link = session->priv->env; link; link = link->next)
268     {
269         const gchar *entry = link->data;
270
271         if (g_str_has_prefix (entry, name) && entry[strlen (name)] == '=')
272             return link;
273     }
274
275     return NULL;
276 }
277
278 void
279 session_set_env (Session *session, const gchar *name, const gchar *value)
280 {
281     GList *link;
282     gchar *entry;
283
284     g_return_if_fail (session != NULL);
285     g_return_if_fail (value != NULL);
286
287     entry = g_strdup_printf ("%s=%s", name, value);
288
289     link = find_env_entry (session, name);
290     if (link)
291     {
292         g_free (link->data);
293         link->data = entry;
294     }
295     else
296         session->priv->env = g_list_append (session->priv->env, entry);
297 }
298
299 const gchar *
300 session_get_env (Session *session, const gchar *name)
301 {
302     GList *link;
303     gchar *entry;
304
305     link = find_env_entry (session, name);
306     if (!link)
307         return NULL;
308
309     entry = link->data;
310
311     return entry + strlen (name) + 1;
312 }
313
314 void
315 session_unset_env (Session *session, const gchar *name)
316 {
317     GList *link;
318
319     g_return_if_fail (session != NULL);
320
321     link = find_env_entry (session, name);
322     if (!link)
323         return;
324
325     g_free (link->data);
326     session->priv->env = g_list_delete_link (session->priv->env, link);
327 }
328
329 void
330 session_set_argv (Session *session, gchar **argv)
331 {
332     g_return_if_fail (session != NULL);
333     session->priv->argv = g_strdupv (argv);
334 }
335
336 User *
337 session_get_user (Session *session)
338 {
339     g_return_val_if_fail (session != NULL, NULL);
340
341     if (session->priv->username == NULL)
342         return NULL;
343
344     if (!session->priv->user)
345         session->priv->user = accounts_get_user_by_name (session->priv->username);
346
347     return session->priv->user;
348 }
349
350 static void
351 write_data (Session *session, const void *buf, size_t count)
352 {
353     if (write (session->priv->to_child_input, buf, count) != count)
354         l_warning (session, "Error writing to session: %s", strerror (errno));
355 }
356
357 static void
358 write_string (Session *session, const char *value)
359 {
360     int length;
361
362     length = value ? strlen (value) : -1;
363     write_data (session, &length, sizeof (length));
364     if (value)
365         write_data (session, value, sizeof (char) * length);
366 }
367
368 static void
369 write_xauth (Session *session, XAuthority *x_authority)
370 {
371     guint16 family;
372     gsize length;
373
374     if (!x_authority)
375     {
376         write_string (session, NULL);
377         return;
378     }
379
380     write_string (session, x_authority_get_authorization_name (session->priv->x_authority));
381     family = x_authority_get_family (session->priv->x_authority);
382     write_data (session, &family, sizeof (family));
383     length = x_authority_get_address_length (session->priv->x_authority);
384     write_data (session, &length, sizeof (length));
385     write_data (session, x_authority_get_address (session->priv->x_authority), length);
386     write_string (session, x_authority_get_number (session->priv->x_authority));
387     length = x_authority_get_authorization_data_length (session->priv->x_authority);
388     write_data (session, &length, sizeof (length));
389     write_data (session, x_authority_get_authorization_data (session->priv->x_authority), length);
390 }
391
392 static ssize_t
393 read_from_child (Session *session, void *buf, size_t count)
394 {
395     ssize_t n_read;
396     n_read = read (session->priv->from_child_output, buf, count);
397     if (n_read < 0)
398         l_warning (session, "Error reading from session: %s", strerror (errno));
399     return n_read;
400 }
401
402 static gchar *
403 read_string_from_child (Session *session)
404 {
405     int length;
406     char *value;
407
408     if (read_from_child (session, &length, sizeof (length)) <= 0)
409         return NULL;
410     if (length < 0)
411         return NULL;
412     if (length > MAX_STRING_LENGTH)
413     {
414         l_warning (session, "Invalid string length %d from child", length);
415         return NULL;
416     }
417
418     value = g_malloc (sizeof (char) * (length + 1));
419     read_from_child (session, value, length);
420     value[length] = '\0';
421
422     return value;
423 }
424
425 static void
426 session_watch_cb (GPid pid, gint status, gpointer data)
427 {
428     Session *session = data;
429
430     session->priv->child_watch = 0;
431
432     if (WIFEXITED (status))
433         l_debug (session, "Exited with return value %d", WEXITSTATUS (status));
434     else if (WIFSIGNALED (status))
435         l_debug (session, "Terminated with signal %d", WTERMSIG (status));
436
437     /* do this as late as possible for log messages prefix */
438     session->priv->pid = 0;
439
440     /* If failed during authentication then report this as an authentication failure */
441     if (session->priv->authentication_started && !session->priv->authentication_complete)
442     {
443         l_debug (session, "Failed during authentication");
444         session->priv->authentication_complete = TRUE;
445         session->priv->authentication_result = PAM_CONV_ERR;
446         g_free (session->priv->authentication_result_string);
447         session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
448         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
449     }
450
451     g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
452
453     /* Delete account if it is a guest one */
454     if (session->priv->is_guest)
455         guest_account_cleanup (session->priv->username);
456
457     /* Drop our reference on the child process, it has terminated */
458     g_object_unref (session);
459 }
460
461 static gboolean
462 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
463 {
464     Session *session = data;
465     gchar *username;
466     ssize_t n_read;
467     gboolean auth_complete;
468
469     /* Remote end gone */
470     if (condition == G_IO_HUP)
471     {
472         session->priv->from_child_watch = 0;
473         return FALSE;
474     }
475
476     /* Get the username currently being authenticated (may change during authentication) */
477     username = read_string_from_child (session);
478     if (g_strcmp0 (username, session->priv->username) != 0)
479     {
480         g_free (session->priv->username);
481         session->priv->username = username;
482         g_clear_object (&session->priv->user);
483     }
484     else
485         g_free (username);
486
487     /* Check if authentication completed */
488     n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
489     if (n_read < 0)
490         l_debug (session, "Error reading from child: %s", strerror (errno));
491     if (n_read <= 0)
492     {
493         session->priv->from_child_watch = 0;
494         return FALSE;
495     }
496
497     if (auth_complete)
498     {
499         session->priv->authentication_complete = TRUE;
500         read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
501         g_free (session->priv->authentication_result_string);
502         session->priv->authentication_result_string = read_string_from_child (session);
503
504         l_debug (session, "Authentication complete with return value %d: %s", session->priv->authentication_result, session->priv->authentication_result_string);
505
506         /* No longer expect any more messages */
507         session->priv->from_child_watch = 0;
508
509         g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
510
511         return FALSE;
512     }
513     else
514     {
515         int i;
516
517         session->priv->messages_length = 0;
518         read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
519         session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
520         for (i = 0; i < session->priv->messages_length; i++)
521         {
522             struct pam_message *m = &session->priv->messages[i];
523             read_from_child (session, &m->msg_style, sizeof (m->msg_style));
524             m->msg = read_string_from_child (session);
525         }
526
527         l_debug (session, "Got %d message(s) from PAM", session->priv->messages_length);
528
529         g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
530     }
531
532     return TRUE;
533 }
534
535 gboolean
536 session_start (Session *session)
537 {
538     g_return_val_if_fail (session != NULL, FALSE);
539     return SESSION_GET_CLASS (session)->start (session);
540 }
541
542 gboolean
543 session_get_is_started (Session *session)
544 {
545     return session->priv->pid != 0;
546 }
547
548 static gboolean
549 session_real_start (Session *session)
550 {
551     int version;
552     int to_child_pipe[2], from_child_pipe[2];
553     int to_child_output, from_child_input;
554     gchar *arg0, *arg1;
555
556     g_return_val_if_fail (session->priv->pid == 0, FALSE);
557
558     if (session->priv->display_server)
559         display_server_connect_session (session->priv->display_server, session);
560
561     /* Create pipes to talk to the child */
562     if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
563     {
564         g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
565         return FALSE;
566     }
567     to_child_output = to_child_pipe[0];
568     session->priv->to_child_input = to_child_pipe[1];
569     session->priv->from_child_output = from_child_pipe[0];
570     from_child_input = from_child_pipe[1];
571     session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
572     session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
573
574     /* Don't allow the daemon end of the pipes to be accessed in child processes */
575     fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
576     fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
577
578     /* Create the guest account if it is one */
579     if (session->priv->is_guest && session->priv->username == NULL)
580     {
581         session->priv->username = guest_account_setup ();
582         if (!session->priv->username)
583             return FALSE;
584     }
585
586     /* Run the child */
587     arg0 = g_strdup_printf ("%d", to_child_output);
588     arg1 = g_strdup_printf ("%d", from_child_input);
589     session->priv->pid = fork ();
590     if (session->priv->pid == 0)
591     {
592         /* Run us again in session child mode */
593         execlp ("lightdm",
594                 "lightdm",
595                 "--session-child",
596                 arg0, arg1, NULL);
597         _exit (EXIT_FAILURE);
598     }
599     g_free (arg0);
600     g_free (arg1);
601
602     if (session->priv->pid < 0)
603     {
604         g_debug ("Failed to fork session child process: %s", strerror (errno));
605         return FALSE;
606     }
607
608     /* Hold a reference on this object until the child process terminates so we
609      * can handle the watch callback even if it is no longer used. Otherwise a
610      * zombie process will remain */
611     g_object_ref (session);
612
613     /* Listen for session termination */
614     session->priv->authentication_started = TRUE;
615     session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
616
617     /* Close the ends of the pipes we don't need */
618     close (to_child_output);
619     close (from_child_input);
620
621     /* Indicate what version of the protocol we are using */
622     version = 2;
623     write_data (session, &version, sizeof (version));
624
625     /* Send configuration */
626     write_string (session, session->priv->pam_service);
627     write_string (session, session->priv->username);
628     write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
629     write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
630     write_string (session, NULL); /* Used to be class, now we just use the environment variable */
631     write_string (session, session->priv->tty);
632     write_string (session, session->priv->remote_host_name);
633     write_string (session, session->priv->xdisplay);
634     write_xauth (session, session->priv->x_authority);
635
636     l_debug (session, "Started with service '%s', username '%s'", session->priv->pam_service, session->priv->username);
637
638     return TRUE;
639 }
640
641 const gchar *
642 session_get_username (Session *session)
643 {
644     g_return_val_if_fail (session != NULL, NULL);
645     return session->priv->username;
646 }
647
648 const gchar *
649 session_get_login1_session_id (Session *session)
650 {
651     g_return_val_if_fail (session != NULL, NULL);
652     return session->priv->login1_session_id;
653 }
654
655 const gchar *
656 session_get_console_kit_cookie (Session *session)
657 {
658     g_return_val_if_fail (session != NULL, NULL);
659     return session->priv->console_kit_cookie;
660 }
661
662 void
663 session_respond (Session *session, struct pam_response *response)
664 {
665     int error = PAM_SUCCESS;
666     int i;
667
668     g_return_if_fail (session != NULL);
669
670     write_data (session, &error, sizeof (error));
671     for (i = 0; i < session->priv->messages_length; i++)
672     {
673         write_string (session, response[i].resp);
674         write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
675     }
676
677     /* Delete the old messages */
678     for (i = 0; i < session->priv->messages_length; i++)
679         g_free ((char *) session->priv->messages[i].msg);
680     g_free (session->priv->messages);
681     session->priv->messages = NULL;
682     session->priv->messages_length = 0;
683 }
684
685 void
686 session_respond_error (Session *session, int error)
687 {
688     g_return_if_fail (session != NULL);
689     g_return_if_fail (error != PAM_SUCCESS);
690
691     write_data (session, &error, sizeof (error));
692 }
693
694 int
695 session_get_messages_length (Session *session)
696 {
697     g_return_val_if_fail (session != NULL, 0);
698     return session->priv->messages_length;
699 }
700
701 const struct pam_message *
702 session_get_messages (Session *session)
703 {
704     g_return_val_if_fail (session != NULL, NULL);
705     return session->priv->messages;
706 }
707
708 gboolean
709 session_get_is_authenticated (Session *session)
710 {
711     g_return_val_if_fail (session != NULL, FALSE);
712     return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
713 }
714
715 int
716 session_get_authentication_result (Session *session)
717 {
718     g_return_val_if_fail (session != NULL, 0);
719     return session->priv->authentication_result;
720 }
721
722 const gchar *
723 session_get_authentication_result_string (Session *session)
724 {
725     g_return_val_if_fail (session != NULL, NULL);
726     return session->priv->authentication_result_string;
727 }
728
729 void
730 session_run (Session *session)
731 {
732     g_return_if_fail (session->priv->display_server != NULL);
733     return SESSION_GET_CLASS (session)->run (session);
734 }
735
736 static void
737 session_real_run (Session *session)
738 {
739     gsize i, argc;
740     gchar *command, *x_authority_filename;
741     GList *link;
742
743     g_return_if_fail (session != NULL);
744     g_return_if_fail (!session->priv->command_run);
745     g_return_if_fail (session_get_is_authenticated (session));
746     g_return_if_fail (session->priv->argv != NULL);
747     g_return_if_fail (session->priv->pid != 0);
748
749     display_server_connect_session (session->priv->display_server, session);
750
751     session->priv->command_run = TRUE;
752
753     command = g_strjoinv (" ", session->priv->argv);
754     l_debug (session, "Running command %s", command);
755     g_free (command);
756
757     /* Create authority location */
758     if (session->priv->x_authority_use_system_location)
759     {
760         gchar *run_dir, *dir;
761
762         run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
763         dir = g_build_filename (run_dir, session->priv->username, NULL);
764         g_free (run_dir);
765
766         if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
767             l_warning (session, "Failed to set create system authority dir %s: %s", dir, strerror (errno));
768         if (getuid () == 0)
769         {
770             if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
771                 l_warning (session, "Failed to set ownership of user authority dir: %s", strerror (errno));
772         }
773
774         x_authority_filename = g_build_filename (dir, "xauthority", NULL);
775         g_free (dir);
776     }
777     else
778         x_authority_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
779
780     /* Make sure shared user directory for this user exists */
781     if (!session->priv->remote_host_name)
782     {
783         gchar *data_dir = shared_data_manager_ensure_user_dir (shared_data_manager_get_instance (), session->priv->username);
784         if (data_dir)
785         {
786             session_set_env (session, "XDG_GREETER_DATA_DIR", data_dir);
787             g_free (data_dir);
788         }
789     }
790
791     if (session->priv->log_filename)
792         l_debug (session, "Logging to %s", session->priv->log_filename);
793     write_string (session, session->priv->log_filename);
794     write_string (session, session->priv->tty);
795     write_string (session, x_authority_filename);
796     g_free (x_authority_filename);
797     write_string (session, session->priv->xdisplay);
798     write_xauth (session, session->priv->x_authority);
799     argc = g_list_length (session->priv->env);
800     write_data (session, &argc, sizeof (argc));
801     for (link = session->priv->env; link; link = link->next)
802         write_string (session, (gchar *) link->data);
803     argc = g_strv_length (session->priv->argv);
804     write_data (session, &argc, sizeof (argc));
805     for (i = 0; i < argc; i++)
806         write_string (session, session->priv->argv[i]);
807
808     session->priv->login1_session_id = read_string_from_child (session);
809     session->priv->console_kit_cookie = read_string_from_child (session);
810 }
811
812 void
813 session_lock (Session *session)
814 {
815     g_return_if_fail (session != NULL);
816     if (getuid () == 0)
817     {
818         if (session->priv->login1_session_id)
819             login1_service_lock_session (login1_service_get_instance (), session->priv->login1_session_id);
820         else if (session->priv->console_kit_cookie)
821             ck_lock_session (session->priv->console_kit_cookie);
822     }
823 }
824
825 void
826 session_unlock (Session *session)
827 {
828     g_return_if_fail (session != NULL);
829     if (getuid () == 0)
830     {
831         if (session->priv->login1_session_id)
832             login1_service_unlock_session (login1_service_get_instance (), session->priv->login1_session_id);
833         else if (session->priv->console_kit_cookie)
834             ck_unlock_session (session->priv->console_kit_cookie);
835     }
836 }
837
838 void
839 session_activate (Session *session)
840 {
841     g_return_if_fail (session != NULL);
842     if (getuid () == 0)
843     {
844         if (session->priv->login1_session_id)
845             login1_service_activate_session (login1_service_get_instance (), session->priv->login1_session_id);
846         else if (session->priv->console_kit_cookie)
847             ck_activate_session (session->priv->console_kit_cookie);
848     }
849 }
850
851 void
852 session_stop (Session *session)
853 {
854     g_return_if_fail (session != NULL);
855
856     /* If can cleanly stop then do that */
857     if (session_get_is_authenticated (session) && !session->priv->command_run)
858     {
859         gsize n = 0;
860
861         session->priv->command_run = TRUE;
862         write_string (session, NULL); // log filename
863         write_string (session, NULL); // tty
864         write_string (session, NULL); // xauth filename
865         write_string (session, NULL); // xdisplay
866         write_xauth (session, NULL); // xauth
867         write_data (session, &n, sizeof (n)); // environment
868         write_data (session, &n, sizeof (n)); // command
869         return;
870     }
871
872     if (session->priv->stopping)
873         return;
874     session->priv->stopping = TRUE;
875
876     return SESSION_GET_CLASS (session)->stop (session);
877 }
878
879 static void
880 session_real_stop (Session *session)
881 {
882     g_return_if_fail (session != NULL);
883
884     if (session->priv->pid > 0)
885     {
886         l_debug (session, "Sending SIGTERM");
887         kill (session->priv->pid, SIGTERM);
888         // FIXME: Handle timeout
889     }
890     else
891         g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
892 }
893
894 gboolean
895 session_get_is_stopping (Session *session)
896 {
897     g_return_val_if_fail (session != NULL, FALSE);
898     return session->priv->stopping;
899 }
900
901 static void
902 session_init (Session *session)
903 {
904     session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
905     session->priv->log_filename = g_strdup (".xsession-errors");
906     session->priv->to_child_input = -1;
907     session->priv->from_child_output = -1;
908 }
909
910 static void
911 session_finalize (GObject *object)
912 {
913     Session *self = SESSION (object);
914     int i;
915
916     g_clear_object (&self->priv->config);
917     g_clear_object (&self->priv->display_server);
918     if (self->priv->pid)
919         kill (self->priv->pid, SIGKILL);
920     close (self->priv->to_child_input);
921     close (self->priv->from_child_output);
922     if (self->priv->from_child_channel)
923         g_io_channel_unref (self->priv->from_child_channel);
924     if (self->priv->from_child_watch)
925         g_source_remove (self->priv->from_child_watch);
926     if (self->priv->child_watch)
927         g_source_remove (self->priv->child_watch);
928     g_free (self->priv->username);
929     g_clear_object (&self->priv->user);
930     g_free (self->priv->pam_service);
931     for (i = 0; i < self->priv->messages_length; i++)
932         g_free ((char *) self->priv->messages[i].msg);
933     g_free (self->priv->messages);
934     g_free (self->priv->authentication_result_string);
935     g_free (self->priv->log_filename);
936     g_free (self->priv->tty);
937     g_free (self->priv->xdisplay);
938     g_clear_object (&self->priv->x_authority);
939     g_free (self->priv->remote_host_name);
940     g_free (self->priv->login1_session_id);
941     g_free (self->priv->console_kit_cookie);
942     g_list_free_full (self->priv->env, g_free);
943     g_strfreev (self->priv->argv);
944
945     G_OBJECT_CLASS (session_parent_class)->finalize (object);
946 }
947
948 static void
949 session_class_init (SessionClass *klass)
950 {
951     GObjectClass *object_class = G_OBJECT_CLASS (klass);
952
953     klass->start = session_real_start;
954     klass->run = session_real_run;
955     klass->stop = session_real_stop;
956     object_class->finalize = session_finalize;
957
958     g_type_class_add_private (klass, sizeof (SessionPrivate));
959
960     signals[GOT_MESSAGES] =
961         g_signal_new (SESSION_SIGNAL_GOT_MESSAGES,
962                       G_TYPE_FROM_CLASS (klass),
963                       G_SIGNAL_RUN_LAST,
964                       G_STRUCT_OFFSET (SessionClass, got_messages),
965                       NULL, NULL,
966                       NULL,
967                       G_TYPE_NONE, 0);
968
969     signals[AUTHENTICATION_COMPLETE] =
970         g_signal_new (SESSION_SIGNAL_AUTHENTICATION_COMPLETE,
971                       G_TYPE_FROM_CLASS (klass),
972                       G_SIGNAL_RUN_LAST,
973                       G_STRUCT_OFFSET (SessionClass, authentication_complete),
974                       NULL, NULL,
975                       NULL,
976                       G_TYPE_NONE, 0);
977
978     signals[STOPPED] =
979         g_signal_new (SESSION_SIGNAL_STOPPED,
980                       G_TYPE_FROM_CLASS (klass),
981                       G_SIGNAL_RUN_LAST,
982                       G_STRUCT_OFFSET (SessionClass, stopped),
983                       NULL, NULL,
984                       NULL,
985                       G_TYPE_NONE, 0);
986 }
987
988 static gint
989 session_real_logprefix (Logger *self, gchar *buf, gulong buflen)
990 {
991     Session *session = SESSION (self);
992     if (session->priv->pid != 0)
993         return g_snprintf (buf, buflen, "Session pid=%d: ", session->priv->pid);
994     else
995         return g_snprintf (buf, buflen, "Session: ");
996 }
997
998 static void
999 session_logger_iface_init (LoggerInterface *iface)
1000 {
1001     iface->logprefix = &session_real_logprefix;
1002 }