2 * Copyright (C) 2010-2011 Robert Ancell.
3 * Author: Robert Ancell <robert.ancell@canonical.com>
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
20 #include <glib/gstdio.h>
25 #include "configuration.h"
26 #include "console-kit.h"
28 #include "guest-account.h"
32 AUTHENTICATION_COMPLETE,
36 static guint signals[LAST_SIGNAL] = { 0 };
43 /* Display server running on */
44 DisplayServer *display_server;
46 /* PID of child process */
49 /* Pipes to talk to child */
51 int from_child_output;
52 GIOChannel *from_child_channel;
53 guint from_child_watch;
56 /* User to authenticate as */
59 /* TRUE if is a guest account */
62 /* User object that matches the current username */
65 /* PAM service to use */
68 /* TRUE if should run PAM authentication phase */
69 gboolean do_authenticate;
71 /* TRUE if can handle PAM prompts */
72 gboolean is_interactive;
74 /* Messages being requested by PAM */
76 struct pam_message *messages;
78 /* Authentication result from PAM */
79 gboolean authentication_started;
80 gboolean authentication_complete;
81 int authentication_result;
82 gchar *authentication_result_string;
87 /* tty this session is running on */
90 /* X display connected to */
92 XAuthority *x_authority;
93 gboolean x_authority_use_system_location;
95 /* Remote host this session is being controlled from */
96 gchar *remote_host_name;
98 /* Console kit cookie */
99 gchar *console_kit_cookie;
102 gchar *login1_session;
104 /* Environment to set in child */
107 /* Command to run in child */
110 /* True if have run command */
111 gboolean command_run;
113 /* TRUE if stopping this session */
117 /* Maximum length of a string to pass between daemon and session */
118 #define MAX_STRING_LENGTH 65535
120 static void session_logger_iface_init (LoggerInterface *iface);
122 G_DEFINE_TYPE_WITH_CODE (Session, session, G_TYPE_OBJECT,
123 G_IMPLEMENT_INTERFACE (
124 LOGGER_TYPE, session_logger_iface_init));
129 return g_object_new (SESSION_TYPE, NULL);
133 session_set_session_type (Session *session, const gchar *session_type)
135 g_return_if_fail (session != NULL);
136 g_free (session->priv->session_type);
137 session->priv->session_type = g_strdup (session_type);
141 session_get_session_type (Session *session)
143 g_return_val_if_fail (session != NULL, NULL);
144 return session->priv->session_type;
148 session_set_pam_service (Session *session, const gchar *pam_service)
150 g_return_if_fail (session != NULL);
151 g_free (session->priv->pam_service);
152 session->priv->pam_service = g_strdup (pam_service);
156 session_set_username (Session *session, const gchar *username)
158 g_return_if_fail (session != NULL);
159 g_free (session->priv->username);
160 session->priv->username = g_strdup (username);
164 session_set_do_authenticate (Session *session, gboolean do_authenticate)
166 g_return_if_fail (session != NULL);
167 session->priv->do_authenticate = do_authenticate;
171 session_set_is_interactive (Session *session, gboolean is_interactive)
173 g_return_if_fail (session != NULL);
174 session->priv->is_interactive = is_interactive;
178 session_set_is_guest (Session *session, gboolean is_guest)
180 g_return_if_fail (session != NULL);
181 session->priv->is_guest = is_guest;
185 session_get_is_guest (Session *session)
187 g_return_val_if_fail (session != NULL, FALSE);
188 return session->priv->is_guest;
192 session_set_log_file (Session *session, const gchar *filename)
194 g_return_if_fail (session != NULL);
195 g_free (session->priv->log_filename);
196 session->priv->log_filename = g_strdup (filename);
200 session_set_display_server (Session *session, DisplayServer *display_server)
202 g_return_if_fail (session != NULL);
203 g_return_if_fail (display_server != NULL);
204 if (session->priv->display_server)
206 display_server_disconnect_session (session->priv->display_server, session);
207 g_object_unref (session->priv->display_server);
209 session->priv->display_server = g_object_ref (display_server);
213 session_get_display_server (Session *session)
215 g_return_val_if_fail (session != NULL, NULL);
216 return session->priv->display_server;
220 session_set_tty (Session *session, const gchar *tty)
222 g_return_if_fail (session != NULL);
223 g_free (session->priv->tty);
224 session->priv->tty = g_strdup (tty);
228 session_set_xdisplay (Session *session, const gchar *xdisplay)
230 g_return_if_fail (session != NULL);
231 g_free (session->priv->xdisplay);
232 session->priv->xdisplay = g_strdup (xdisplay);
236 session_set_x_authority (Session *session, XAuthority *authority, gboolean use_system_location)
238 g_return_if_fail (session != NULL);
239 if (session->priv->x_authority)
241 g_object_unref (session->priv->x_authority);
242 session->priv->x_authority = NULL;
245 session->priv->x_authority = g_object_ref (authority);
246 session->priv->x_authority_use_system_location = use_system_location;
250 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
252 g_return_if_fail (session != NULL);
253 g_free (session->priv->remote_host_name);
254 session->priv->remote_host_name = g_strdup (remote_host_name);
258 find_env_entry (Session *session, const gchar *name)
262 for (link = session->priv->env; link; link = link->next)
264 const gchar *entry = link->data;
266 if (g_str_has_prefix (entry, name) && entry[strlen (name)] == '=')
274 session_set_env (Session *session, const gchar *name, const gchar *value)
279 g_return_if_fail (session != NULL);
280 g_return_if_fail (value != NULL);
282 entry = g_strdup_printf ("%s=%s", name, value);
284 link = find_env_entry (session, name);
291 session->priv->env = g_list_append (session->priv->env, entry);
295 session_get_env (Session *session, const gchar *name)
300 link = find_env_entry (session, name);
306 return entry + strlen (name) + 1;
310 session_unset_env (Session *session, const gchar *name)
314 g_return_if_fail (session != NULL);
316 link = find_env_entry (session, name);
321 session->priv->env = g_list_remove_link (session->priv->env, link);
325 session_set_argv (Session *session, gchar **argv)
327 g_return_if_fail (session != NULL);
328 session->priv->argv = g_strdupv (argv);
332 session_get_user (Session *session)
334 g_return_val_if_fail (session != NULL, NULL);
336 if (session->priv->username == NULL)
339 if (!session->priv->user)
340 session->priv->user = accounts_get_user_by_name (session->priv->username);
342 return session->priv->user;
346 write_data (Session *session, const void *buf, size_t count)
348 if (write (session->priv->to_child_input, buf, count) != count)
349 l_warning (session, "Error writing to session: %s", strerror (errno));
353 write_string (Session *session, const char *value)
357 length = value ? strlen (value) : -1;
358 write_data (session, &length, sizeof (length));
360 write_data (session, value, sizeof (char) * length);
364 write_xauth (Session *session, XAuthority *x_authority)
371 write_string (session, NULL);
375 write_string (session, x_authority_get_authorization_name (session->priv->x_authority));
376 family = x_authority_get_family (session->priv->x_authority);
377 write_data (session, &family, sizeof (family));
378 length = x_authority_get_address_length (session->priv->x_authority);
379 write_data (session, &length, sizeof (length));
380 write_data (session, x_authority_get_address (session->priv->x_authority), length);
381 write_string (session, x_authority_get_number (session->priv->x_authority));
382 length = x_authority_get_authorization_data_length (session->priv->x_authority);
383 write_data (session, &length, sizeof (length));
384 write_data (session, x_authority_get_authorization_data (session->priv->x_authority), length);
388 read_from_child (Session *session, void *buf, size_t count)
391 n_read = read (session->priv->from_child_output, buf, count);
393 l_warning (session, "Error reading from session: %s", strerror (errno));
398 read_string_from_child (Session *session)
403 if (read_from_child (session, &length, sizeof (length)) <= 0)
407 if (length > MAX_STRING_LENGTH)
409 l_warning (session, "Invalid string length %d from child", length);
413 value = g_malloc (sizeof (char) * (length + 1));
414 read_from_child (session, value, length);
415 value[length] = '\0';
421 session_watch_cb (GPid pid, gint status, gpointer data)
423 Session *session = data;
425 if (WIFEXITED (status))
426 l_debug (session, "Exited with return value %d", WEXITSTATUS (status));
427 else if (WIFSIGNALED (status))
428 l_debug (session, "Terminated with signal %d", WTERMSIG (status));
430 /* do this as late as possible for log messages prefix */
431 session->priv->pid = 0;
433 /* If failed during authentication then report this as an authentication failure */
434 if (session->priv->authentication_started && !session->priv->authentication_complete)
436 l_debug (session, "Failed during authentication");
437 session->priv->authentication_complete = TRUE;
438 session->priv->authentication_result = PAM_CONV_ERR;
439 g_free (session->priv->authentication_result_string);
440 session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
441 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
444 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
446 /* Delete account if it is a guest one */
447 if (session->priv->is_guest)
448 guest_account_cleanup (session->priv->username);
450 /* Drop our reference on the child process, it has terminated */
451 g_object_unref (session);
455 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
457 Session *session = data;
460 gboolean auth_complete;
462 /* Remote end gone */
463 if (condition == G_IO_HUP)
465 session->priv->from_child_watch = 0;
469 /* Get the username currently being authenticated (may change during authentication) */
470 username = read_string_from_child (session);
471 if (g_strcmp0 (username, session->priv->username) != 0)
473 g_free (session->priv->username);
474 session->priv->username = username;
475 if (session->priv->user)
476 g_object_unref (session->priv->user);
477 session->priv->user = NULL;
482 /* Check if authentication completed */
483 n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
485 l_debug (session, "Error reading from child: %s", strerror (errno));
488 session->priv->from_child_watch = 0;
494 session->priv->authentication_complete = TRUE;
495 read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
496 g_free (session->priv->authentication_result_string);
497 session->priv->authentication_result_string = read_string_from_child (session);
499 l_debug (session, "Authentication complete with return value %d: %s", session->priv->authentication_result, session->priv->authentication_result_string);
501 /* No longer expect any more messages */
502 session->priv->from_child_watch = 0;
504 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
512 session->priv->messages_length = 0;
513 read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
514 session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
515 for (i = 0; i < session->priv->messages_length; i++)
517 struct pam_message *m = &session->priv->messages[i];
518 read_from_child (session, &m->msg_style, sizeof (m->msg_style));
519 m->msg = read_string_from_child (session);
522 l_debug (session, "Got %d message(s) from PAM", session->priv->messages_length);
524 g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
531 session_start (Session *session)
533 g_return_val_if_fail (session != NULL, FALSE);
534 return SESSION_GET_CLASS (session)->start (session);
538 session_get_is_started (Session *session)
540 return session->priv->pid != 0;
544 session_real_start (Session *session)
547 int to_child_pipe[2], from_child_pipe[2];
548 int to_child_output, from_child_input;
550 g_return_val_if_fail (session->priv->pid == 0, FALSE);
552 if (session->priv->display_server)
553 display_server_connect_session (session->priv->display_server, session);
555 /* Create pipes to talk to the child */
556 if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
558 g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
561 to_child_output = to_child_pipe[0];
562 session->priv->to_child_input = to_child_pipe[1];
563 session->priv->from_child_output = from_child_pipe[0];
564 from_child_input = from_child_pipe[1];
565 session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
566 session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
568 /* Don't allow the daemon end of the pipes to be accessed in child processes */
569 fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
570 fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
572 /* Create the guest account if it is one */
573 if (session->priv->is_guest && session->priv->username == NULL)
575 session->priv->username = guest_account_setup ();
576 if (!session->priv->username)
581 session->priv->pid = fork ();
582 if (session->priv->pid < 0)
584 g_debug ("Failed to fork session child process: %s", strerror (errno));
588 if (session->priv->pid == 0)
590 /* Run us again in session child mode */
594 g_strdup_printf ("%d", to_child_output),
595 g_strdup_printf ("%d", from_child_input),
597 _exit (EXIT_FAILURE);
600 /* Hold a reference on this object until the child process terminates so we
601 * can handle the watch callback even if it is no longer used. Otherwise a
602 * zombie process will remain */
603 g_object_ref (session);
605 /* Listen for session termination */
606 session->priv->authentication_started = TRUE;
607 session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
609 /* Close the ends of the pipes we don't need */
610 close (to_child_output);
611 close (from_child_input);
613 /* Indicate what version of the protocol we are using */
615 write_data (session, &version, sizeof (version));
617 /* Send configuration */
618 write_string (session, session->priv->pam_service);
619 write_string (session, session->priv->username);
620 write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
621 write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
622 write_string (session, NULL); /* Used to be class, now we just use the environment variable */
623 write_string (session, session->priv->tty);
624 write_string (session, session->priv->remote_host_name);
625 write_string (session, session->priv->xdisplay);
626 write_xauth (session, session->priv->x_authority);
628 l_debug (session, "Started with service '%s', username '%s'", session->priv->pam_service, session->priv->username);
634 session_get_username (Session *session)
636 g_return_val_if_fail (session != NULL, NULL);
637 return session->priv->username;
641 session_get_console_kit_cookie (Session *session)
643 g_return_val_if_fail (session != NULL, NULL);
644 return session->priv->console_kit_cookie;
648 session_respond (Session *session, struct pam_response *response)
650 int error = PAM_SUCCESS;
653 g_return_if_fail (session != NULL);
655 write_data (session, &error, sizeof (error));
656 for (i = 0; i < session->priv->messages_length; i++)
658 write_string (session, response[i].resp);
659 write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
662 /* Delete the old messages */
663 for (i = 0; i < session->priv->messages_length; i++)
664 g_free ((char *) session->priv->messages[i].msg);
665 g_free (session->priv->messages);
666 session->priv->messages = NULL;
667 session->priv->messages_length = 0;
671 session_respond_error (Session *session, int error)
673 g_return_if_fail (session != NULL);
674 g_return_if_fail (error != PAM_SUCCESS);
676 write_data (session, &error, sizeof (error));
680 session_get_messages_length (Session *session)
682 g_return_val_if_fail (session != NULL, 0);
683 return session->priv->messages_length;
686 const struct pam_message *
687 session_get_messages (Session *session)
689 g_return_val_if_fail (session != NULL, NULL);
690 return session->priv->messages;
694 session_get_is_authenticated (Session *session)
696 g_return_val_if_fail (session != NULL, FALSE);
697 return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
701 session_get_authentication_result (Session *session)
703 g_return_val_if_fail (session != NULL, 0);
704 return session->priv->authentication_result;
708 session_get_authentication_result_string (Session *session)
710 g_return_val_if_fail (session != NULL, NULL);
711 return session->priv->authentication_result_string;
715 session_run (Session *session)
717 g_return_if_fail (session->priv->display_server != NULL);
718 return SESSION_GET_CLASS (session)->run (session);
722 session_real_run (Session *session)
725 gchar *command, *x_authority_filename;
728 g_return_if_fail (session != NULL);
729 g_return_if_fail (!session->priv->command_run);
730 g_return_if_fail (session_get_is_authenticated (session));
731 g_return_if_fail (session->priv->argv != NULL);
732 g_return_if_fail (session->priv->pid != 0);
734 display_server_connect_session (session->priv->display_server, session);
736 session->priv->command_run = TRUE;
738 command = g_strjoinv (" ", session->priv->argv);
739 l_debug (session, "Running command %s", command);
742 /* Create authority location */
743 if (session->priv->x_authority_use_system_location)
745 gchar *run_dir, *dir;
747 run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
748 dir = g_build_filename (run_dir, session->priv->username, NULL);
751 if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
752 l_warning (session, "Failed to set create system authority dir %s: %s", dir, strerror (errno));
755 if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
756 l_warning (session, "Failed to set ownership of user authority dir: %s", strerror (errno));
759 x_authority_filename = g_build_filename (dir, "xauthority", NULL);
763 x_authority_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
765 if (session->priv->log_filename)
766 l_debug (session, "Logging to %s", session->priv->log_filename);
767 write_string (session, session->priv->log_filename);
768 write_string (session, session->priv->tty);
769 write_string (session, x_authority_filename);
770 g_free (x_authority_filename);
771 write_string (session, session->priv->xdisplay);
772 write_xauth (session, session->priv->x_authority);
773 argc = g_list_length (session->priv->env);
774 write_data (session, &argc, sizeof (argc));
775 for (link = session->priv->env; link; link = link->next)
776 write_string (session, (gchar *) link->data);
777 argc = g_strv_length (session->priv->argv);
778 write_data (session, &argc, sizeof (argc));
779 for (i = 0; i < argc; i++)
780 write_string (session, session->priv->argv[i]);
782 if (login1_is_running ())
783 session->priv->login1_session = read_string_from_child (session);
784 if (!session->priv->login1_session)
785 session->priv->console_kit_cookie = read_string_from_child (session);
789 session_lock (Session *session)
791 g_return_if_fail (session != NULL);
794 if (session->priv->login1_session)
795 login1_lock_session (session->priv->login1_session);
796 else if (session->priv->console_kit_cookie)
797 ck_lock_session (session->priv->console_kit_cookie);
802 session_unlock (Session *session)
804 g_return_if_fail (session != NULL);
807 if (session->priv->login1_session)
808 login1_unlock_session (session->priv->login1_session);
809 else if (session->priv->console_kit_cookie)
810 ck_unlock_session (session->priv->console_kit_cookie);
815 session_stop (Session *session)
817 g_return_if_fail (session != NULL);
819 if (session->priv->stopping)
821 session->priv->stopping = TRUE;
823 return SESSION_GET_CLASS (session)->stop (session);
827 session_real_stop (Session *session)
829 g_return_if_fail (session != NULL);
831 if (session->priv->pid > 0)
833 l_debug (session, "Sending SIGTERM");
834 kill (session->priv->pid, SIGTERM);
835 // FIXME: Handle timeout
838 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
842 session_get_is_stopping (Session *session)
844 g_return_val_if_fail (session != NULL, FALSE);
845 return session->priv->stopping;
849 session_init (Session *session)
851 session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
852 session->priv->log_filename = g_strdup (".xsession-errors");
856 session_finalize (GObject *object)
858 Session *self = SESSION (object);
861 g_free (self->priv->session_type);
862 if (self->priv->display_server)
863 g_object_unref (self->priv->display_server);
865 kill (self->priv->pid, SIGKILL);
866 if (self->priv->from_child_channel)
867 g_io_channel_unref (self->priv->from_child_channel);
868 if (self->priv->from_child_watch)
869 g_source_remove (self->priv->from_child_watch);
870 if (self->priv->child_watch)
871 g_source_remove (self->priv->child_watch);
872 g_free (self->priv->username);
873 if (self->priv->user)
874 g_object_unref (self->priv->user);
875 g_free (self->priv->pam_service);
876 for (i = 0; i < self->priv->messages_length; i++)
877 g_free ((char *) self->priv->messages[i].msg);
878 g_free (self->priv->messages);
879 g_free (self->priv->authentication_result_string);
880 g_free (self->priv->log_filename);
881 g_free (self->priv->tty);
882 g_free (self->priv->xdisplay);
883 if (self->priv->x_authority)
884 g_object_unref (self->priv->x_authority);
885 g_free (self->priv->remote_host_name);
886 g_free (self->priv->login1_session);
887 g_free (self->priv->console_kit_cookie);
888 g_list_free_full (self->priv->env, g_free);
889 g_strfreev (self->priv->argv);
891 G_OBJECT_CLASS (session_parent_class)->finalize (object);
895 session_class_init (SessionClass *klass)
897 GObjectClass *object_class = G_OBJECT_CLASS (klass);
899 klass->start = session_real_start;
900 klass->run = session_real_run;
901 klass->stop = session_real_stop;
902 object_class->finalize = session_finalize;
904 g_type_class_add_private (klass, sizeof (SessionPrivate));
906 signals[GOT_MESSAGES] =
907 g_signal_new ("got-messages",
908 G_TYPE_FROM_CLASS (klass),
910 G_STRUCT_OFFSET (SessionClass, got_messages),
915 signals[AUTHENTICATION_COMPLETE] =
916 g_signal_new ("authentication-complete",
917 G_TYPE_FROM_CLASS (klass),
919 G_STRUCT_OFFSET (SessionClass, authentication_complete),
925 g_signal_new ("stopped",
926 G_TYPE_FROM_CLASS (klass),
928 G_STRUCT_OFFSET (SessionClass, stopped),
935 session_real_logprefix (Logger *self, gchar *buf, gulong buflen)
937 Session *session = SESSION (self);
938 if (session->priv->pid != 0)
939 return g_snprintf (buf, buflen, "Session pid=%d: ", session->priv->pid);
941 return g_snprintf (buf, buflen, "Session: ");
945 session_logger_iface_init (LoggerInterface *iface)
947 iface->logprefix = &session_real_logprefix;