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 };
40 /* Display server running on */
41 DisplayServer *display_server;
43 /* PID of child process */
46 /* Pipes to talk to child */
48 int from_child_output;
49 GIOChannel *from_child_channel;
50 guint from_child_watch;
53 /* User to authenticate as */
56 /* TRUE if is a guest account */
59 /* User object that matches the current username */
62 /* PAM service to use */
65 /* TRUE if should run PAM authentication phase */
66 gboolean do_authenticate;
68 /* TRUE if can handle PAM prompts */
69 gboolean is_interactive;
71 /* Messages being requested by PAM */
73 struct pam_message *messages;
75 /* Authentication result from PAM */
76 gboolean authentication_started;
77 gboolean authentication_complete;
78 int authentication_result;
79 gchar *authentication_result_string;
87 /* tty this session is running on */
90 /* X display connected to */
92 XAuthority *xauthority;
93 gboolean xauth_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 */
111 /* Maximum length of a string to pass between daemon and session */
112 #define MAX_STRING_LENGTH 65535
114 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
117 session_set_pam_service (Session *session, const gchar *pam_service)
119 g_return_if_fail (session != NULL);
120 g_free (session->priv->pam_service);
121 session->priv->pam_service = g_strdup (pam_service);
125 session_set_username (Session *session, const gchar *username)
127 g_return_if_fail (session != NULL);
128 g_free (session->priv->username);
129 session->priv->username = g_strdup (username);
133 session_set_do_authenticate (Session *session, gboolean do_authenticate)
135 g_return_if_fail (session != NULL);
136 session->priv->do_authenticate = do_authenticate;
140 session_set_is_interactive (Session *session, gboolean is_interactive)
142 g_return_if_fail (session != NULL);
143 session->priv->is_interactive = is_interactive;
147 session_set_is_guest (Session *session, gboolean is_guest)
149 g_return_if_fail (session != NULL);
150 session->priv->is_guest = is_guest;
154 session_set_log_file (Session *session, const gchar *filename)
156 g_return_if_fail (session != NULL);
157 g_free (session->priv->log_filename);
158 session->priv->log_filename = g_strdup (filename);
162 session_set_class (Session *session, const gchar *class)
164 g_return_if_fail (session != NULL);
165 g_free (session->priv->class);
166 session->priv->class = g_strdup (class);
170 session_real_set_display_server (Session *session, DisplayServer *display_server)
172 if (session->priv->display_server)
173 g_object_unref (session->priv->display_server);
174 session->priv->display_server = g_object_ref (display_server);
178 session_set_display_server (Session *session, DisplayServer *display_server)
180 g_return_if_fail (session != NULL);
181 g_return_if_fail (display_server != NULL);
182 SESSION_GET_CLASS (session)->set_display_server (session, display_server);
186 session_get_display_server (Session *session)
188 g_return_val_if_fail (session != NULL, NULL);
189 return session->priv->display_server;
193 session_set_tty (Session *session, const gchar *tty)
195 g_return_if_fail (session != NULL);
196 g_free (session->priv->tty);
197 session->priv->tty = g_strdup (tty);
201 session_set_xdisplay (Session *session, const gchar *xdisplay)
203 g_return_if_fail (session != NULL);
204 g_free (session->priv->xdisplay);
205 session->priv->xdisplay = g_strdup (xdisplay);
209 session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
211 g_return_if_fail (session != NULL);
212 if (session->priv->xauthority)
213 g_object_unref (session->priv->xauthority);
214 session->priv->xauthority = g_object_ref (authority);
215 session->priv->xauth_use_system_location = use_system_location;
219 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
221 g_return_if_fail (session != NULL);
222 g_free (session->priv->remote_host_name);
223 session->priv->remote_host_name = g_strdup (remote_host_name);
227 session_set_env (Session *session, const gchar *name, const gchar *value)
229 g_return_if_fail (session != NULL);
230 session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
234 session_set_argv (Session *session, gchar **argv)
236 g_return_if_fail (session != NULL);
237 session->priv->argv = g_strdupv (argv);
241 session_get_user (Session *session)
243 g_return_val_if_fail (session != NULL, NULL);
245 if (session->priv->username == NULL)
248 if (!session->priv->user)
249 session->priv->user = accounts_get_user_by_name (session->priv->username);
251 return session->priv->user;
255 write_data (Session *session, const void *buf, size_t count)
257 if (write (session->priv->to_child_input, buf, count) != count)
258 g_warning ("Error writing to session: %s", strerror (errno));
262 write_string (Session *session, const char *value)
266 length = value ? strlen (value) : -1;
267 write_data (session, &length, sizeof (length));
269 write_data (session, value, sizeof (char) * length);
273 write_xauth (Session *session, XAuthority *xauthority)
280 write_string (session, NULL);
284 write_string (session, xauth_get_authorization_name (session->priv->xauthority));
285 family = xauth_get_family (session->priv->xauthority);
286 write_data (session, &family, sizeof (family));
287 length = xauth_get_address_length (session->priv->xauthority);
288 write_data (session, &length, sizeof (length));
289 write_data (session, xauth_get_address (session->priv->xauthority), length);
290 write_string (session, xauth_get_number (session->priv->xauthority));
291 length = xauth_get_authorization_data_length (session->priv->xauthority);
292 write_data (session, &length, sizeof (length));
293 write_data (session, xauth_get_authorization_data (session->priv->xauthority), length);
297 read_from_child (Session *session, void *buf, size_t count)
300 n_read = read (session->priv->from_child_output, buf, count);
302 g_warning ("Error reading from session: %s", strerror (errno));
307 read_string_from_child (Session *session)
312 if (read_from_child (session, &length, sizeof (length)) <= 0)
316 if (length > MAX_STRING_LENGTH)
318 g_warning ("Invalid string length %d from child", length);
322 value = g_malloc (sizeof (char) * (length + 1));
323 read_from_child (session, value, length);
324 value[length] = '\0';
330 session_watch_cb (GPid pid, gint status, gpointer data)
332 Session *session = data;
334 session->priv->pid = 0;
336 if (WIFEXITED (status))
337 g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
338 else if (WIFSIGNALED (status))
339 g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
341 /* If failed during authentication then report this as an authentication failure */
342 if (session->priv->authentication_started && !session->priv->authentication_complete)
344 g_debug ("Session %d failed during authentication", pid);
345 session->priv->authentication_complete = TRUE;
346 session->priv->authentication_result = PAM_CONV_ERR;
347 g_free (session->priv->authentication_result_string);
348 session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
349 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
352 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
354 /* Delete account if it is a guest one */
355 if (session->priv->is_guest)
356 guest_account_cleanup (session->priv->username);
358 /* Drop our reference on the child process, it has terminated */
359 g_object_unref (session);
363 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
365 Session *session = data;
368 gboolean auth_complete;
370 /* Remote end gone */
371 if (condition == G_IO_HUP)
373 session->priv->from_child_watch = 0;
377 /* Get the username currently being authenticated (may change during authentication) */
378 username = read_string_from_child (session);
379 if (g_strcmp0 (username, session->priv->username) != 0)
381 g_free (session->priv->username);
382 session->priv->username = username;
383 if (session->priv->user)
384 g_object_unref (session->priv->user);
385 session->priv->user = NULL;
390 /* Check if authentication completed */
391 n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
393 g_debug ("Error reading from child: %s", strerror (errno));
396 session->priv->from_child_watch = 0;
402 session->priv->authentication_complete = TRUE;
403 read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
404 g_free (session->priv->authentication_result_string);
405 session->priv->authentication_result_string = read_string_from_child (session);
407 g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
409 /* No longer expect any more messages */
410 session->priv->from_child_watch = 0;
412 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
420 session->priv->messages_length = 0;
421 read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
422 session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
423 for (i = 0; i < session->priv->messages_length; i++)
425 struct pam_message *m = &session->priv->messages[i];
426 read_from_child (session, &m->msg_style, sizeof (m->msg_style));
427 m->msg = read_string_from_child (session);
430 g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
432 g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
439 session_start (Session *session)
442 int to_child_pipe[2], from_child_pipe[2];
443 int to_child_output, from_child_input;
445 g_return_val_if_fail (session != NULL, FALSE);
446 g_return_val_if_fail (session->priv->pid == 0, FALSE);
448 /* Create pipes to talk to the child */
449 if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
451 g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
454 to_child_output = to_child_pipe[0];
455 session->priv->to_child_input = to_child_pipe[1];
456 session->priv->from_child_output = from_child_pipe[0];
457 from_child_input = from_child_pipe[1];
458 session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
459 session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
461 /* Don't allow the daemon end of the pipes to be accessed in child processes */
462 fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
463 fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
465 /* Create the guest account if it is one */
466 if (session->priv->is_guest && session->priv->username == NULL)
467 session->priv->username = guest_account_setup ();
470 session->priv->pid = fork ();
471 if (session->priv->pid < 0)
473 g_debug ("Failed to fork session child process: %s", strerror (errno));
477 if (session->priv->pid == 0)
479 /* Run us again in session child mode */
483 g_strdup_printf ("%d", to_child_output),
484 g_strdup_printf ("%d", from_child_input),
486 _exit (EXIT_FAILURE);
489 /* Hold a reference on this object until the child process terminates so we
490 * can handle the watch callback even if it is no longer used. Otherwise a
491 * zombie process will remain */
492 g_object_ref (session);
494 /* Listen for session termination */
495 session->priv->authentication_started = TRUE;
496 session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
498 /* Close the ends of the pipes we don't need */
499 close (to_child_output);
500 close (from_child_input);
502 /* Indicate what version of the protocol we are using */
504 write_data (session, &version, sizeof (version));
506 /* Send configuration */
507 write_string (session, session->priv->pam_service);
508 write_string (session, session->priv->username);
509 write_data (session, &session->priv->do_authenticate, sizeof (session->priv->do_authenticate));
510 write_data (session, &session->priv->is_interactive, sizeof (session->priv->is_interactive));
511 write_string (session, session->priv->class);
512 write_string (session, session->priv->tty);
513 write_string (session, session->priv->remote_host_name);
514 write_string (session, session->priv->xdisplay);
515 write_xauth (session, session->priv->xauthority);
517 g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, session->priv->pam_service, session->priv->username);
523 session_get_username (Session *session)
525 g_return_val_if_fail (session != NULL, NULL);
526 return session->priv->username;
530 session_get_console_kit_cookie (Session *session)
532 g_return_val_if_fail (session != NULL, NULL);
533 return session->priv->console_kit_cookie;
537 session_respond (Session *session, struct pam_response *response)
539 int error = PAM_SUCCESS;
542 g_return_if_fail (session != NULL);
544 write_data (session, &error, sizeof (error));
545 for (i = 0; i < session->priv->messages_length; i++)
547 write_string (session, response[i].resp);
548 write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
551 /* Delete the old messages */
552 for (i = 0; i < session->priv->messages_length; i++)
553 g_free ((char *) session->priv->messages[i].msg);
554 g_free (session->priv->messages);
555 session->priv->messages = NULL;
556 session->priv->messages_length = 0;
560 session_respond_error (Session *session, int error)
562 g_return_if_fail (session != NULL);
563 g_return_if_fail (error != PAM_SUCCESS);
565 write_data (session, &error, sizeof (error));
569 session_get_messages_length (Session *session)
571 g_return_val_if_fail (session != NULL, 0);
572 return session->priv->messages_length;
575 const struct pam_message *
576 session_get_messages (Session *session)
578 g_return_val_if_fail (session != NULL, NULL);
579 return session->priv->messages;
583 session_get_is_authenticated (Session *session)
585 g_return_val_if_fail (session != NULL, FALSE);
586 return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
590 session_get_authentication_result (Session *session)
592 g_return_val_if_fail (session != NULL, 0);
593 return session->priv->authentication_result;
597 session_get_authentication_result_string (Session *session)
599 g_return_val_if_fail (session != NULL, NULL);
600 return session->priv->authentication_result_string;
604 session_run (Session *session)
607 gchar *command, *xauth_filename;
610 g_return_if_fail (session != NULL);
611 g_return_if_fail (session_get_is_authenticated (session));
612 g_return_if_fail (session->priv->argv != NULL);
614 command = g_strjoinv (" ", session->priv->argv);
615 g_debug ("Session %d running command %s", session->priv->pid, command);
618 /* Create authority location */
619 if (session->priv->xauth_use_system_location)
621 gchar *run_dir, *dir;
623 run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
624 dir = g_build_filename (run_dir, session->priv->username, NULL);
627 if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
628 g_warning ("Failed to set create system authority dir %s: %s", dir, strerror (errno));
631 if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
632 g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
635 xauth_filename = g_build_filename (dir, "xauthority", NULL);
639 xauth_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
641 write_string (session, session->priv->log_filename);
642 write_string (session, session->priv->tty);
643 write_string (session, xauth_filename);
644 g_free (xauth_filename);
645 write_string (session, session->priv->xdisplay);
646 write_xauth (session, session->priv->xauthority);
647 argc = g_list_length (session->priv->env);
648 write_data (session, &argc, sizeof (argc));
649 for (link = session->priv->env; link; link = link->next)
650 write_string (session, (gchar *) link->data);
651 argc = g_strv_length (session->priv->argv);
652 write_data (session, &argc, sizeof (argc));
653 for (i = 0; i < argc; i++)
654 write_string (session, session->priv->argv[i]);
656 if (login1_is_running ())
657 session->priv->login1_session = read_string_from_child (session);
658 if (!session->priv->login1_session)
659 session->priv->console_kit_cookie = read_string_from_child (session);
663 session_lock (Session *session)
665 g_return_if_fail (session != NULL);
668 if (login1_is_running ())
669 login1_lock_session (session->priv->login1_session);
670 if (!session->priv->login1_session)
671 ck_lock_session (session->priv->console_kit_cookie);
676 session_unlock (Session *session)
678 g_return_if_fail (session != NULL);
681 if (login1_is_running ())
682 login1_unlock_session (session->priv->login1_session);
683 if (!session->priv->login1_session)
684 ck_unlock_session (session->priv->console_kit_cookie);
689 session_stop (Session *session)
691 g_return_if_fail (session != NULL);
693 if (session->priv->pid > 0)
695 g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
696 kill (session->priv->pid, SIGTERM);
697 // FIXME: Handle timeout
702 session_get_is_stopped (Session *session)
704 g_return_val_if_fail (session != NULL, TRUE);
705 return session->priv->pid == 0;
709 session_init (Session *session)
711 session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
715 session_finalize (GObject *object)
717 Session *self = SESSION (object);
720 if (self->priv->display_server)
721 g_object_unref (self->priv->display_server);
723 kill (self->priv->pid, SIGKILL);
724 if (self->priv->from_child_channel)
725 g_io_channel_unref (self->priv->from_child_channel);
726 if (self->priv->from_child_watch)
727 g_source_remove (self->priv->from_child_watch);
728 if (self->priv->child_watch)
729 g_source_remove (self->priv->child_watch);
730 g_free (self->priv->username);
731 if (self->priv->user)
732 g_object_unref (self->priv->user);
733 g_free (self->priv->pam_service);
734 for (i = 0; i < self->priv->messages_length; i++)
735 g_free ((char *) self->priv->messages[i].msg);
736 g_free (self->priv->messages);
737 g_free (self->priv->authentication_result_string);
738 g_free (self->priv->log_filename);
739 g_free (self->priv->class);
740 g_free (self->priv->tty);
741 g_free (self->priv->xdisplay);
742 if (self->priv->xauthority)
743 g_object_unref (self->priv->xauthority);
744 g_free (self->priv->remote_host_name);
745 g_free (self->priv->login1_session);
746 g_free (self->priv->console_kit_cookie);
747 g_list_free_full (self->priv->env, g_free);
748 g_strfreev (self->priv->argv);
750 G_OBJECT_CLASS (session_parent_class)->finalize (object);
754 session_class_init (SessionClass *klass)
756 GObjectClass *object_class = G_OBJECT_CLASS (klass);
758 klass->set_display_server = session_real_set_display_server;
759 object_class->finalize = session_finalize;
761 g_type_class_add_private (klass, sizeof (SessionPrivate));
763 signals[GOT_MESSAGES] =
764 g_signal_new ("got-messages",
765 G_TYPE_FROM_CLASS (klass),
767 G_STRUCT_OFFSET (SessionClass, got_messages),
769 g_cclosure_marshal_VOID__VOID,
772 signals[AUTHENTICATION_COMPLETE] =
773 g_signal_new ("authentication-complete",
774 G_TYPE_FROM_CLASS (klass),
776 G_STRUCT_OFFSET (SessionClass, authentication_complete),
778 g_cclosure_marshal_VOID__VOID,
782 g_signal_new ("stopped",
783 G_TYPE_FROM_CLASS (klass),
785 G_STRUCT_OFFSET (SessionClass, stopped),
787 g_cclosure_marshal_VOID__VOID,