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"
29 #include "shared-data-manager.h"
33 AUTHENTICATION_COMPLETE,
37 static guint signals[LAST_SIGNAL] = { 0 };
44 /* Display server running on */
45 DisplayServer *display_server;
47 /* PID of child process */
50 /* Pipes to talk to child */
52 int from_child_output;
53 GIOChannel *from_child_channel;
54 guint from_child_watch;
57 /* User to authenticate as */
60 /* TRUE if is a guest account */
63 /* User object that matches the current username */
66 /* PAM service to use */
69 /* TRUE if should run PAM authentication phase */
70 gboolean do_authenticate;
72 /* TRUE if can handle PAM prompts */
73 gboolean is_interactive;
75 /* Messages being requested by PAM */
77 struct pam_message *messages;
79 /* Authentication result from PAM */
80 gboolean authentication_started;
81 gboolean authentication_complete;
82 int authentication_result;
83 gchar *authentication_result_string;
88 /* tty this session is running on */
91 /* X display connected to */
93 XAuthority *x_authority;
94 gboolean x_authority_use_system_location;
96 /* Remote host this session is being controlled from */
97 gchar *remote_host_name;
99 /* Console kit cookie */
100 gchar *console_kit_cookie;
103 gchar *login1_session;
105 /* Environment to set in child */
108 /* Command to run in child */
111 /* True if have run command */
112 gboolean command_run;
114 /* TRUE if stopping this session */
118 /* Maximum length of a string to pass between daemon and session */
119 #define MAX_STRING_LENGTH 65535
121 static void session_logger_iface_init (LoggerInterface *iface);
123 G_DEFINE_TYPE_WITH_CODE (Session, session, G_TYPE_OBJECT,
124 G_IMPLEMENT_INTERFACE (
125 LOGGER_TYPE, session_logger_iface_init));
130 return g_object_new (SESSION_TYPE, NULL);
134 session_set_session_type (Session *session, const gchar *session_type)
136 g_return_if_fail (session != NULL);
137 g_free (session->priv->session_type);
138 session->priv->session_type = g_strdup (session_type);
142 session_get_session_type (Session *session)
144 g_return_val_if_fail (session != NULL, NULL);
145 return session->priv->session_type;
149 session_set_pam_service (Session *session, const gchar *pam_service)
151 g_return_if_fail (session != NULL);
152 g_free (session->priv->pam_service);
153 session->priv->pam_service = g_strdup (pam_service);
157 session_set_username (Session *session, const gchar *username)
159 g_return_if_fail (session != NULL);
160 g_free (session->priv->username);
161 session->priv->username = g_strdup (username);
165 session_set_do_authenticate (Session *session, gboolean do_authenticate)
167 g_return_if_fail (session != NULL);
168 session->priv->do_authenticate = do_authenticate;
172 session_set_is_interactive (Session *session, gboolean is_interactive)
174 g_return_if_fail (session != NULL);
175 session->priv->is_interactive = is_interactive;
179 session_set_is_guest (Session *session, gboolean is_guest)
181 g_return_if_fail (session != NULL);
182 session->priv->is_guest = is_guest;
186 session_get_is_guest (Session *session)
188 g_return_val_if_fail (session != NULL, FALSE);
189 return session->priv->is_guest;
193 session_set_log_file (Session *session, const gchar *filename)
195 g_return_if_fail (session != NULL);
196 g_free (session->priv->log_filename);
197 session->priv->log_filename = g_strdup (filename);
201 session_set_display_server (Session *session, DisplayServer *display_server)
203 g_return_if_fail (session != NULL);
204 g_return_if_fail (display_server != NULL);
205 if (session->priv->display_server)
207 display_server_disconnect_session (session->priv->display_server, session);
208 g_object_unref (session->priv->display_server);
210 session->priv->display_server = g_object_ref (display_server);
214 session_get_display_server (Session *session)
216 g_return_val_if_fail (session != NULL, NULL);
217 return session->priv->display_server;
221 session_set_tty (Session *session, const gchar *tty)
223 g_return_if_fail (session != NULL);
224 g_free (session->priv->tty);
225 session->priv->tty = g_strdup (tty);
229 session_set_xdisplay (Session *session, const gchar *xdisplay)
231 g_return_if_fail (session != NULL);
232 g_free (session->priv->xdisplay);
233 session->priv->xdisplay = g_strdup (xdisplay);
237 session_set_x_authority (Session *session, XAuthority *authority, gboolean use_system_location)
239 g_return_if_fail (session != NULL);
240 if (session->priv->x_authority)
242 g_object_unref (session->priv->x_authority);
243 session->priv->x_authority = NULL;
246 session->priv->x_authority = g_object_ref (authority);
247 session->priv->x_authority_use_system_location = use_system_location;
251 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
253 g_return_if_fail (session != NULL);
254 g_free (session->priv->remote_host_name);
255 session->priv->remote_host_name = g_strdup (remote_host_name);
259 find_env_entry (Session *session, const gchar *name)
263 for (link = session->priv->env; link; link = link->next)
265 const gchar *entry = link->data;
267 if (g_str_has_prefix (entry, name) && entry[strlen (name)] == '=')
275 session_set_env (Session *session, const gchar *name, const gchar *value)
280 g_return_if_fail (session != NULL);
281 g_return_if_fail (value != NULL);
283 entry = g_strdup_printf ("%s=%s", name, value);
285 link = find_env_entry (session, name);
292 session->priv->env = g_list_append (session->priv->env, entry);
296 session_get_env (Session *session, const gchar *name)
301 link = find_env_entry (session, name);
307 return entry + strlen (name) + 1;
311 session_unset_env (Session *session, const gchar *name)
315 g_return_if_fail (session != NULL);
317 link = find_env_entry (session, name);
322 session->priv->env = g_list_delete_link (session->priv->env, link);
326 session_set_argv (Session *session, gchar **argv)
328 g_return_if_fail (session != NULL);
329 session->priv->argv = g_strdupv (argv);
333 session_get_user (Session *session)
335 g_return_val_if_fail (session != NULL, NULL);
337 if (session->priv->username == NULL)
340 if (!session->priv->user)
341 session->priv->user = accounts_get_user_by_name (session->priv->username);
343 return session->priv->user;
347 write_data (Session *session, const void *buf, size_t count)
349 if (write (session->priv->to_child_input, buf, count) != count)
350 l_warning (session, "Error writing to session: %s", strerror (errno));
354 write_string (Session *session, const char *value)
358 length = value ? strlen (value) : -1;
359 write_data (session, &length, sizeof (length));
361 write_data (session, value, sizeof (char) * length);
365 write_xauth (Session *session, XAuthority *x_authority)
372 write_string (session, NULL);
376 write_string (session, x_authority_get_authorization_name (session->priv->x_authority));
377 family = x_authority_get_family (session->priv->x_authority);
378 write_data (session, &family, sizeof (family));
379 length = x_authority_get_address_length (session->priv->x_authority);
380 write_data (session, &length, sizeof (length));
381 write_data (session, x_authority_get_address (session->priv->x_authority), length);
382 write_string (session, x_authority_get_number (session->priv->x_authority));
383 length = x_authority_get_authorization_data_length (session->priv->x_authority);
384 write_data (session, &length, sizeof (length));
385 write_data (session, x_authority_get_authorization_data (session->priv->x_authority), length);
389 read_from_child (Session *session, void *buf, size_t count)
392 n_read = read (session->priv->from_child_output, buf, count);
394 l_warning (session, "Error reading from session: %s", strerror (errno));
399 read_string_from_child (Session *session)
404 if (read_from_child (session, &length, sizeof (length)) <= 0)
408 if (length > MAX_STRING_LENGTH)
410 l_warning (session, "Invalid string length %d from child", length);
414 value = g_malloc (sizeof (char) * (length + 1));
415 read_from_child (session, value, length);
416 value[length] = '\0';
422 session_watch_cb (GPid pid, gint status, gpointer data)
424 Session *session = data;
426 session->priv->child_watch = 0;
428 if (WIFEXITED (status))
429 l_debug (session, "Exited with return value %d", WEXITSTATUS (status));
430 else if (WIFSIGNALED (status))
431 l_debug (session, "Terminated with signal %d", WTERMSIG (status));
433 /* do this as late as possible for log messages prefix */
434 session->priv->pid = 0;
436 /* If failed during authentication then report this as an authentication failure */
437 if (session->priv->authentication_started && !session->priv->authentication_complete)
439 l_debug (session, "Failed during authentication");
440 session->priv->authentication_complete = TRUE;
441 session->priv->authentication_result = PAM_CONV_ERR;
442 g_free (session->priv->authentication_result_string);
443 session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
444 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
447 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
449 /* Delete account if it is a guest one */
450 if (session->priv->is_guest)
451 guest_account_cleanup (session->priv->username);
453 /* Drop our reference on the child process, it has terminated */
454 g_object_unref (session);
458 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
460 Session *session = data;
463 gboolean auth_complete;
465 /* Remote end gone */
466 if (condition == G_IO_HUP)
468 session->priv->from_child_watch = 0;
472 /* Get the username currently being authenticated (may change during authentication) */
473 username = read_string_from_child (session);
474 if (g_strcmp0 (username, session->priv->username) != 0)
476 g_free (session->priv->username);
477 session->priv->username = username;
478 if (session->priv->user)
479 g_object_unref (session->priv->user);
480 session->priv->user = NULL;
485 /* Check if authentication completed */
486 n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
488 l_debug (session, "Error reading from child: %s", strerror (errno));
491 session->priv->from_child_watch = 0;
497 session->priv->authentication_complete = TRUE;
498 read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
499 g_free (session->priv->authentication_result_string);
500 session->priv->authentication_result_string = read_string_from_child (session);
502 l_debug (session, "Authentication complete with return value %d: %s", session->priv->authentication_result, session->priv->authentication_result_string);
504 /* No longer expect any more messages */
505 session->priv->from_child_watch = 0;
507 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
515 session->priv->messages_length = 0;
516 read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
517 session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
518 for (i = 0; i < session->priv->messages_length; i++)
520 struct pam_message *m = &session->priv->messages[i];
521 read_from_child (session, &m->msg_style, sizeof (m->msg_style));
522 m->msg = read_string_from_child (session);
525 l_debug (session, "Got %d message(s) from PAM", session->priv->messages_length);
527 g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
534 session_start (Session *session)
536 g_return_val_if_fail (session != NULL, FALSE);
537 return SESSION_GET_CLASS (session)->start (session);
541 session_get_is_started (Session *session)
543 return session->priv->pid != 0;
547 session_real_start (Session *session)
550 int to_child_pipe[2], from_child_pipe[2];
551 int to_child_output, from_child_input;
554 g_return_val_if_fail (session->priv->pid == 0, FALSE);
556 if (session->priv->display_server)
557 display_server_connect_session (session->priv->display_server, session);
559 /* Create pipes to talk to the child */
560 if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
562 g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
565 to_child_output = to_child_pipe[0];
566 session->priv->to_child_input = to_child_pipe[1];
567 session->priv->from_child_output = from_child_pipe[0];
568 from_child_input = from_child_pipe[1];
569 session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
570 session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
572 /* Don't allow the daemon end of the pipes to be accessed in child processes */
573 fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
574 fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
576 /* Create the guest account if it is one */
577 if (session->priv->is_guest && session->priv->username == NULL)
579 session->priv->username = guest_account_setup ();
580 if (!session->priv->username)
585 arg0 = g_strdup_printf ("%d", to_child_output);
586 arg1 = g_strdup_printf ("%d", from_child_input);
587 session->priv->pid = fork ();
588 if (session->priv->pid == 0)
590 /* Run us again in session child mode */
595 _exit (EXIT_FAILURE);
600 if (session->priv->pid < 0)
602 g_debug ("Failed to fork session child process: %s", strerror (errno));
606 /* Hold a reference on this object until the child process terminates so we
607 * can handle the watch callback even if it is no longer used. Otherwise a
608 * zombie process will remain */
609 g_object_ref (session);
611 /* Listen for session termination */
612 session->priv->authentication_started = TRUE;
613 session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
615 /* Close the ends of the pipes we don't need */
616 close (to_child_output);
617 close (from_child_input);
619 /* Indicate what version of the protocol we are using */
621 write_data (session, &version, sizeof (version));
623 /* Send configuration */
624 write_string (session, session->priv->pam_service);
625 write_string (session, session->priv->username);
626 write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
627 write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
628 write_string (session, NULL); /* Used to be class, now we just use the environment variable */
629 write_string (session, session->priv->tty);
630 write_string (session, session->priv->remote_host_name);
631 write_string (session, session->priv->xdisplay);
632 write_xauth (session, session->priv->x_authority);
634 l_debug (session, "Started with service '%s', username '%s'", session->priv->pam_service, session->priv->username);
640 session_get_username (Session *session)
642 g_return_val_if_fail (session != NULL, NULL);
643 return session->priv->username;
647 session_get_console_kit_cookie (Session *session)
649 g_return_val_if_fail (session != NULL, NULL);
650 return session->priv->console_kit_cookie;
654 session_respond (Session *session, struct pam_response *response)
656 int error = PAM_SUCCESS;
659 g_return_if_fail (session != NULL);
661 write_data (session, &error, sizeof (error));
662 for (i = 0; i < session->priv->messages_length; i++)
664 write_string (session, response[i].resp);
665 write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
668 /* Delete the old messages */
669 for (i = 0; i < session->priv->messages_length; i++)
670 g_free ((char *) session->priv->messages[i].msg);
671 g_free (session->priv->messages);
672 session->priv->messages = NULL;
673 session->priv->messages_length = 0;
677 session_respond_error (Session *session, int error)
679 g_return_if_fail (session != NULL);
680 g_return_if_fail (error != PAM_SUCCESS);
682 write_data (session, &error, sizeof (error));
686 session_get_messages_length (Session *session)
688 g_return_val_if_fail (session != NULL, 0);
689 return session->priv->messages_length;
692 const struct pam_message *
693 session_get_messages (Session *session)
695 g_return_val_if_fail (session != NULL, NULL);
696 return session->priv->messages;
700 session_get_is_authenticated (Session *session)
702 g_return_val_if_fail (session != NULL, FALSE);
703 return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
707 session_get_authentication_result (Session *session)
709 g_return_val_if_fail (session != NULL, 0);
710 return session->priv->authentication_result;
714 session_get_authentication_result_string (Session *session)
716 g_return_val_if_fail (session != NULL, NULL);
717 return session->priv->authentication_result_string;
721 session_run (Session *session)
723 g_return_if_fail (session->priv->display_server != NULL);
724 return SESSION_GET_CLASS (session)->run (session);
728 session_real_run (Session *session)
731 gchar *command, *x_authority_filename;
734 g_return_if_fail (session != NULL);
735 g_return_if_fail (!session->priv->command_run);
736 g_return_if_fail (session_get_is_authenticated (session));
737 g_return_if_fail (session->priv->argv != NULL);
738 g_return_if_fail (session->priv->pid != 0);
740 display_server_connect_session (session->priv->display_server, session);
742 session->priv->command_run = TRUE;
744 command = g_strjoinv (" ", session->priv->argv);
745 l_debug (session, "Running command %s", command);
748 /* Create authority location */
749 if (session->priv->x_authority_use_system_location)
751 gchar *run_dir, *dir;
753 run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
754 dir = g_build_filename (run_dir, session->priv->username, NULL);
757 if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
758 l_warning (session, "Failed to set create system authority dir %s: %s", dir, strerror (errno));
761 if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
762 l_warning (session, "Failed to set ownership of user authority dir: %s", strerror (errno));
765 x_authority_filename = g_build_filename (dir, "xauthority", NULL);
769 x_authority_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
771 /* Make sure shared user directory for this user exists */
772 if (!session->priv->remote_host_name)
774 gchar *data_dir = shared_data_manager_ensure_user_dir (shared_data_manager_get_instance (), session->priv->username);
777 session_set_env (session, "XDG_GREETER_DATA_DIR", data_dir);
782 if (session->priv->log_filename)
783 l_debug (session, "Logging to %s", session->priv->log_filename);
784 write_string (session, session->priv->log_filename);
785 write_string (session, session->priv->tty);
786 write_string (session, x_authority_filename);
787 g_free (x_authority_filename);
788 write_string (session, session->priv->xdisplay);
789 write_xauth (session, session->priv->x_authority);
790 argc = g_list_length (session->priv->env);
791 write_data (session, &argc, sizeof (argc));
792 for (link = session->priv->env; link; link = link->next)
793 write_string (session, (gchar *) link->data);
794 argc = g_strv_length (session->priv->argv);
795 write_data (session, &argc, sizeof (argc));
796 for (i = 0; i < argc; i++)
797 write_string (session, session->priv->argv[i]);
799 if (login1_is_running ())
800 session->priv->login1_session = read_string_from_child (session);
801 if (!session->priv->login1_session)
802 session->priv->console_kit_cookie = read_string_from_child (session);
806 session_lock (Session *session)
808 g_return_if_fail (session != NULL);
811 if (session->priv->login1_session)
812 login1_lock_session (session->priv->login1_session);
813 else if (session->priv->console_kit_cookie)
814 ck_lock_session (session->priv->console_kit_cookie);
819 session_unlock (Session *session)
821 g_return_if_fail (session != NULL);
824 if (session->priv->login1_session)
825 login1_unlock_session (session->priv->login1_session);
826 else if (session->priv->console_kit_cookie)
827 ck_unlock_session (session->priv->console_kit_cookie);
832 session_activate (Session *session)
834 g_return_if_fail (session != NULL);
837 if (session->priv->login1_session)
838 login1_activate_session (session->priv->login1_session);
839 else if (session->priv->console_kit_cookie)
840 ck_activate_session (session->priv->console_kit_cookie);
845 session_stop (Session *session)
847 g_return_if_fail (session != NULL);
849 /* If can cleanly stop then do that */
850 if (session_get_is_authenticated (session) && !session->priv->command_run)
854 session->priv->command_run = TRUE;
855 write_string (session, NULL); // log filename
856 write_string (session, NULL); // tty
857 write_string (session, NULL); // xauth filename
858 write_string (session, NULL); // xdisplay
859 write_xauth (session, NULL); // xauth
860 write_data (session, &n, sizeof (n)); // environment
861 write_data (session, &n, sizeof (n)); // command
865 if (session->priv->stopping)
867 session->priv->stopping = TRUE;
869 return SESSION_GET_CLASS (session)->stop (session);
873 session_real_stop (Session *session)
875 g_return_if_fail (session != NULL);
877 if (session->priv->pid > 0)
879 l_debug (session, "Sending SIGTERM");
880 kill (session->priv->pid, SIGTERM);
881 // FIXME: Handle timeout
884 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
888 session_get_is_stopping (Session *session)
890 g_return_val_if_fail (session != NULL, FALSE);
891 return session->priv->stopping;
895 session_init (Session *session)
897 session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
898 session->priv->log_filename = g_strdup (".xsession-errors");
902 session_finalize (GObject *object)
904 Session *self = SESSION (object);
907 g_free (self->priv->session_type);
908 if (self->priv->display_server)
909 g_object_unref (self->priv->display_server);
911 kill (self->priv->pid, SIGKILL);
912 if (self->priv->from_child_channel)
913 g_io_channel_unref (self->priv->from_child_channel);
914 if (self->priv->from_child_watch)
915 g_source_remove (self->priv->from_child_watch);
916 if (self->priv->child_watch)
917 g_source_remove (self->priv->child_watch);
918 g_free (self->priv->username);
919 if (self->priv->user)
920 g_object_unref (self->priv->user);
921 g_free (self->priv->pam_service);
922 for (i = 0; i < self->priv->messages_length; i++)
923 g_free ((char *) self->priv->messages[i].msg);
924 g_free (self->priv->messages);
925 g_free (self->priv->authentication_result_string);
926 g_free (self->priv->log_filename);
927 g_free (self->priv->tty);
928 g_free (self->priv->xdisplay);
929 if (self->priv->x_authority)
930 g_object_unref (self->priv->x_authority);
931 g_free (self->priv->remote_host_name);
932 g_free (self->priv->login1_session);
933 g_free (self->priv->console_kit_cookie);
934 g_list_free_full (self->priv->env, g_free);
935 g_strfreev (self->priv->argv);
937 G_OBJECT_CLASS (session_parent_class)->finalize (object);
941 session_class_init (SessionClass *klass)
943 GObjectClass *object_class = G_OBJECT_CLASS (klass);
945 klass->start = session_real_start;
946 klass->run = session_real_run;
947 klass->stop = session_real_stop;
948 object_class->finalize = session_finalize;
950 g_type_class_add_private (klass, sizeof (SessionPrivate));
952 signals[GOT_MESSAGES] =
953 g_signal_new ("got-messages",
954 G_TYPE_FROM_CLASS (klass),
956 G_STRUCT_OFFSET (SessionClass, got_messages),
961 signals[AUTHENTICATION_COMPLETE] =
962 g_signal_new ("authentication-complete",
963 G_TYPE_FROM_CLASS (klass),
965 G_STRUCT_OFFSET (SessionClass, authentication_complete),
971 g_signal_new ("stopped",
972 G_TYPE_FROM_CLASS (klass),
974 G_STRUCT_OFFSET (SessionClass, stopped),
981 session_real_logprefix (Logger *self, gchar *buf, gulong buflen)
983 Session *session = SESSION (self);
984 if (session->priv->pid != 0)
985 return g_snprintf (buf, buflen, "Session pid=%d: ", session->priv->pid);
987 return g_snprintf (buf, buflen, "Session: ");
991 session_logger_iface_init (LoggerInterface *iface)
993 iface->logprefix = &session_real_logprefix;