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 /* Messages being requested by PAM */
64 struct pam_message *messages;
66 /* Authentication result from PAM */
67 gboolean authentication_started;
68 gboolean authentication_complete;
69 int authentication_result;
70 gchar *authentication_result_string;
78 /* tty this session is running on */
81 /* X display connected to */
83 XAuthority *xauthority;
84 gboolean xauth_use_system_location;
86 /* Remote host this session is being controlled from */
87 gchar *remote_host_name;
89 /* Console kit cookie */
90 gchar *console_kit_cookie;
93 gchar *login1_session;
95 /* Environment to set in child */
99 /* Maximum length of a string to pass between daemon and session */
100 #define MAX_STRING_LENGTH 65535
102 G_DEFINE_TYPE (Session, session, G_TYPE_OBJECT);
105 session_set_log_file (Session *session, const gchar *filename)
107 g_return_if_fail (session != NULL);
108 g_free (session->priv->log_filename);
109 session->priv->log_filename = g_strdup (filename);
113 session_set_class (Session *session, const gchar *class)
115 g_return_if_fail (session != NULL);
116 g_free (session->priv->class);
117 session->priv->class = g_strdup (class);
121 session_real_set_display_server (Session *session, DisplayServer *display_server)
123 if (session->priv->display_server)
124 g_object_unref (session->priv->display_server);
125 session->priv->display_server = g_object_ref (display_server);
129 session_set_display_server (Session *session, DisplayServer *display_server)
131 g_return_if_fail (session != NULL);
132 g_return_if_fail (display_server != NULL);
133 SESSION_GET_CLASS (session)->set_display_server (session, display_server);
137 session_set_tty (Session *session, const gchar *tty)
139 g_return_if_fail (session != NULL);
140 g_free (session->priv->tty);
141 session->priv->tty = g_strdup (tty);
145 session_set_xdisplay (Session *session, const gchar *xdisplay)
147 g_return_if_fail (session != NULL);
148 g_free (session->priv->xdisplay);
149 session->priv->xdisplay = g_strdup (xdisplay);
153 session_set_xauthority (Session *session, XAuthority *authority, gboolean use_system_location)
155 g_return_if_fail (session != NULL);
156 if (session->priv->xauthority)
157 g_object_unref (session->priv->xauthority);
158 session->priv->xauthority = g_object_ref (authority);
159 session->priv->xauth_use_system_location = use_system_location;
163 session_set_remote_host_name (Session *session, const gchar *remote_host_name)
165 g_return_if_fail (session != NULL);
166 g_free (session->priv->remote_host_name);
167 session->priv->remote_host_name = g_strdup (remote_host_name);
171 session_set_env (Session *session, const gchar *name, const gchar *value)
173 g_return_if_fail (session != NULL);
174 session->priv->env = g_list_append (session->priv->env, g_strdup_printf ("%s=%s", name, value));
178 session_get_user (Session *session)
180 g_return_val_if_fail (session != NULL, NULL);
182 if (session->priv->username == NULL)
185 if (!session->priv->user)
186 session->priv->user = accounts_get_user_by_name (session->priv->username);
188 return session->priv->user;
192 write_data (Session *session, const void *buf, size_t count)
194 if (write (session->priv->to_child_input, buf, count) != count)
195 g_warning ("Error writing to session: %s", strerror (errno));
199 write_string (Session *session, const char *value)
203 length = value ? strlen (value) : -1;
204 write_data (session, &length, sizeof (length));
206 write_data (session, value, sizeof (char) * length);
210 write_xauth (Session *session, XAuthority *xauthority)
217 write_string (session, NULL);
221 write_string (session, xauth_get_authorization_name (session->priv->xauthority));
222 family = xauth_get_family (session->priv->xauthority);
223 write_data (session, &family, sizeof (family));
224 length = xauth_get_address_length (session->priv->xauthority);
225 write_data (session, &length, sizeof (length));
226 write_data (session, xauth_get_address (session->priv->xauthority), length);
227 write_string (session, xauth_get_number (session->priv->xauthority));
228 length = xauth_get_authorization_data_length (session->priv->xauthority);
229 write_data (session, &length, sizeof (length));
230 write_data (session, xauth_get_authorization_data (session->priv->xauthority), length);
234 read_from_child (Session *session, void *buf, size_t count)
237 n_read = read (session->priv->from_child_output, buf, count);
239 g_warning ("Error reading from session: %s", strerror (errno));
244 read_string_from_child (Session *session)
249 if (read_from_child (session, &length, sizeof (length)) <= 0)
253 if (length > MAX_STRING_LENGTH)
255 g_warning ("Invalid string length %d from child", length);
259 value = g_malloc (sizeof (char) * (length + 1));
260 read_from_child (session, value, length);
261 value[length] = '\0';
267 session_watch_cb (GPid pid, gint status, gpointer data)
269 Session *session = data;
271 session->priv->pid = 0;
273 if (WIFEXITED (status))
274 g_debug ("Session %d exited with return value %d", pid, WEXITSTATUS (status));
275 else if (WIFSIGNALED (status))
276 g_debug ("Session %d terminated with signal %d", pid, WTERMSIG (status));
278 /* If failed during authentication then report this as an authentication failure */
279 if (session->priv->authentication_started && !session->priv->authentication_complete)
281 g_debug ("Session %d failed during authentication", pid);
282 session->priv->authentication_complete = TRUE;
283 session->priv->authentication_result = PAM_CONV_ERR;
284 g_free (session->priv->authentication_result_string);
285 session->priv->authentication_result_string = g_strdup ("Authentication stopped before completion");
286 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
289 g_signal_emit (G_OBJECT (session), signals[STOPPED], 0);
291 /* Delete account if it is a guest one */
292 if (session->priv->is_guest)
293 guest_account_cleanup (session->priv->username);
295 /* Drop our reference on the child process, it has terminated */
296 g_object_unref (session);
300 from_child_cb (GIOChannel *source, GIOCondition condition, gpointer data)
302 Session *session = data;
305 gboolean auth_complete;
307 /* Remote end gone */
308 if (condition == G_IO_HUP)
310 session->priv->from_child_watch = 0;
314 /* Get the username currently being authenticated (may change during authentication) */
315 username = read_string_from_child (session);
316 if (g_strcmp0 (username, session->priv->username) != 0)
318 g_free (session->priv->username);
319 session->priv->username = username;
320 if (session->priv->user)
321 g_object_unref (session->priv->user);
322 session->priv->user = NULL;
327 /* Check if authentication completed */
328 n_read = read_from_child (session, &auth_complete, sizeof (auth_complete));
330 g_debug ("Error reading from child: %s", strerror (errno));
333 session->priv->from_child_watch = 0;
339 session->priv->authentication_complete = TRUE;
340 read_from_child (session, &session->priv->authentication_result, sizeof (session->priv->authentication_result));
341 g_free (session->priv->authentication_result_string);
342 session->priv->authentication_result_string = read_string_from_child (session);
344 g_debug ("Session %d authentication complete with return value %d: %s", session->priv->pid, session->priv->authentication_result, session->priv->authentication_result_string);
346 /* No longer expect any more messages */
347 session->priv->from_child_watch = 0;
349 g_signal_emit (G_OBJECT (session), signals[AUTHENTICATION_COMPLETE], 0);
357 session->priv->messages_length = 0;
358 read_from_child (session, &session->priv->messages_length, sizeof (session->priv->messages_length));
359 session->priv->messages = calloc (session->priv->messages_length, sizeof (struct pam_message));
360 for (i = 0; i < session->priv->messages_length; i++)
362 struct pam_message *m = &session->priv->messages[i];
363 read_from_child (session, &m->msg_style, sizeof (m->msg_style));
364 m->msg = read_string_from_child (session);
367 g_debug ("Session %d got %d message(s) from PAM", session->priv->pid, session->priv->messages_length);
369 g_signal_emit (G_OBJECT (session), signals[GOT_MESSAGES], 0);
376 session_start (Session *session, const gchar *service, const gchar *username, gboolean do_authenticate, gboolean is_interactive, gboolean is_guest)
379 int to_child_pipe[2], from_child_pipe[2];
380 int to_child_output, from_child_input;
382 g_return_val_if_fail (session != NULL, FALSE);
383 g_return_val_if_fail (service != NULL, FALSE);
384 g_return_val_if_fail (session->priv->pid == 0, FALSE);
386 /* Create pipes to talk to the child */
387 if (pipe (to_child_pipe) < 0 || pipe (from_child_pipe) < 0)
389 g_warning ("Failed to create pipe to communicate with session process: %s", strerror (errno));
392 to_child_output = to_child_pipe[0];
393 session->priv->to_child_input = to_child_pipe[1];
394 session->priv->from_child_output = from_child_pipe[0];
395 from_child_input = from_child_pipe[1];
396 session->priv->from_child_channel = g_io_channel_unix_new (session->priv->from_child_output);
397 session->priv->from_child_watch = g_io_add_watch (session->priv->from_child_channel, G_IO_IN | G_IO_HUP, from_child_cb, session);
399 /* Don't allow the daemon end of the pipes to be accessed in child processes */
400 fcntl (session->priv->to_child_input, F_SETFD, FD_CLOEXEC);
401 fcntl (session->priv->from_child_output, F_SETFD, FD_CLOEXEC);
403 /* Create the guest account if it is one */
404 session->priv->is_guest = is_guest;
405 if (is_guest && username == NULL)
406 username = guest_account_setup ();
408 /* Remember what username we started with - it will be updated by PAM during authentication */
409 session->priv->username = g_strdup (username);
412 session->priv->pid = fork ();
413 if (session->priv->pid < 0)
415 g_debug ("Failed to fork session child process: %s", strerror (errno));
419 if (session->priv->pid == 0)
421 /* Run us again in session child mode */
425 g_strdup_printf ("%d", to_child_output),
426 g_strdup_printf ("%d", from_child_input),
428 _exit (EXIT_FAILURE);
431 /* Hold a reference on this object until the child process terminates so we
432 * can handle the watch callback even if it is no longer used. Otherwise a
433 * zombie process will remain */
434 g_object_ref (session);
436 /* Listen for session termination */
437 session->priv->authentication_started = TRUE;
438 session->priv->child_watch = g_child_watch_add (session->priv->pid, session_watch_cb, session);
440 /* Close the ends of the pipes we don't need */
441 close (to_child_output);
442 close (from_child_input);
444 /* Indicate what version of the protocol we are using */
446 write_data (session, &version, sizeof (version));
448 /* Send configuration */
449 write_string (session, service);
450 write_string (session, username);
451 write_data (session, &do_authenticate, sizeof (do_authenticate));
452 write_data (session, &is_interactive, sizeof (is_interactive));
453 write_string (session, session->priv->class);
454 write_string (session, session->priv->tty);
455 write_string (session, session->priv->remote_host_name);
456 write_string (session, session->priv->xdisplay);
457 write_xauth (session, session->priv->xauthority);
459 g_debug ("Started session %d with service '%s', username '%s'", session->priv->pid, service, username);
465 session_get_username (Session *session)
467 g_return_val_if_fail (session != NULL, NULL);
468 return session->priv->username;
472 session_get_console_kit_cookie (Session *session)
474 g_return_val_if_fail (session != NULL, NULL);
475 return session->priv->console_kit_cookie;
479 session_respond (Session *session, struct pam_response *response)
481 int error = PAM_SUCCESS;
484 g_return_if_fail (session != NULL);
486 write_data (session, &error, sizeof (error));
487 for (i = 0; i < session->priv->messages_length; i++)
489 write_string (session, response[i].resp);
490 write_data (session, &response[i].resp_retcode, sizeof (response[i].resp_retcode));
493 /* Delete the old messages */
494 for (i = 0; i < session->priv->messages_length; i++)
495 g_free ((char *) session->priv->messages[i].msg);
496 g_free (session->priv->messages);
497 session->priv->messages = NULL;
498 session->priv->messages_length = 0;
502 session_respond_error (Session *session, int error)
504 g_return_if_fail (session != NULL);
505 g_return_if_fail (error != PAM_SUCCESS);
507 write_data (session, &error, sizeof (error));
511 session_get_messages_length (Session *session)
513 g_return_val_if_fail (session != NULL, 0);
514 return session->priv->messages_length;
517 const struct pam_message *
518 session_get_messages (Session *session)
520 g_return_val_if_fail (session != NULL, NULL);
521 return session->priv->messages;
525 session_get_is_authenticated (Session *session)
527 g_return_val_if_fail (session != NULL, FALSE);
528 return session->priv->authentication_complete && session->priv->authentication_result == PAM_SUCCESS;
532 session_get_authentication_result (Session *session)
534 g_return_val_if_fail (session != NULL, 0);
535 return session->priv->authentication_result;
539 session_get_authentication_result_string (Session *session)
541 g_return_val_if_fail (session != NULL, NULL);
542 return session->priv->authentication_result_string;
546 session_run (Session *session, gchar **argv)
549 gchar *command, *xauth_filename;
552 g_return_if_fail (session != NULL);
553 g_return_if_fail (session_get_is_authenticated (session));
555 command = g_strjoinv (" ", argv);
556 g_debug ("Session %d running command %s", session->priv->pid, command);
559 /* Create authority location */
560 if (session->priv->xauth_use_system_location)
562 gchar *run_dir, *dir;
564 run_dir = config_get_string (config_get_instance (), "LightDM", "run-directory");
565 dir = g_build_filename (run_dir, session->priv->username, NULL);
568 if (g_mkdir_with_parents (dir, S_IRWXU) < 0)
569 g_warning ("Failed to set create system authority dir %s: %s", dir, strerror (errno));
572 if (chown (dir, user_get_uid (session_get_user (session)), user_get_gid (session_get_user (session))) < 0)
573 g_warning ("Failed to set ownership of user authority dir: %s", strerror (errno));
576 xauth_filename = g_build_filename (dir, "xauthority", NULL);
580 xauth_filename = g_build_filename (user_get_home_directory (session_get_user (session)), ".Xauthority", NULL);
582 write_string (session, session->priv->log_filename);
583 write_string (session, session->priv->tty);
584 write_string (session, xauth_filename);
585 g_free (xauth_filename);
586 write_string (session, session->priv->xdisplay);
587 write_xauth (session, session->priv->xauthority);
588 argc = g_list_length (session->priv->env);
589 write_data (session, &argc, sizeof (argc));
590 for (link = session->priv->env; link; link = link->next)
591 write_string (session, (gchar *) link->data);
592 argc = g_strv_length (argv);
593 write_data (session, &argc, sizeof (argc));
594 for (i = 0; i < argc; i++)
595 write_string (session, argv[i]);
597 if (login1_is_running ())
598 session->priv->login1_session = read_string_from_child (session);
599 if (!session->priv->login1_session)
600 session->priv->console_kit_cookie = read_string_from_child (session);
604 session_lock (Session *session)
606 g_return_if_fail (session != NULL);
609 if (login1_is_running ())
610 login1_lock_session (session->priv->login1_session);
611 if (!session->priv->login1_session)
612 ck_lock_session (session->priv->console_kit_cookie);
617 session_unlock (Session *session)
619 g_return_if_fail (session != NULL);
622 if (login1_is_running ())
623 login1_unlock_session (session->priv->login1_session);
624 if (!session->priv->login1_session)
625 ck_unlock_session (session->priv->console_kit_cookie);
630 session_stop (Session *session)
632 g_return_if_fail (session != NULL);
634 if (session->priv->pid > 0)
636 g_debug ("Session %d: Sending SIGTERM", session->priv->pid);
637 kill (session->priv->pid, SIGTERM);
638 // FIXME: Handle timeout
643 session_get_is_stopped (Session *session)
645 g_return_val_if_fail (session != NULL, TRUE);
646 return session->priv->pid == 0;
650 session_init (Session *session)
652 session->priv = G_TYPE_INSTANCE_GET_PRIVATE (session, SESSION_TYPE, SessionPrivate);
656 session_finalize (GObject *object)
658 Session *self = SESSION (object);
661 if (self->priv->display_server)
662 g_object_unref (self->priv->display_server);
664 kill (self->priv->pid, SIGKILL);
665 if (self->priv->from_child_channel)
666 g_io_channel_unref (self->priv->from_child_channel);
667 if (self->priv->from_child_watch)
668 g_source_remove (self->priv->from_child_watch);
669 if (self->priv->child_watch)
670 g_source_remove (self->priv->child_watch);
671 g_free (self->priv->username);
672 if (self->priv->user)
673 g_object_unref (self->priv->user);
674 for (i = 0; i < self->priv->messages_length; i++)
675 g_free ((char *) self->priv->messages[i].msg);
676 g_free (self->priv->messages);
677 g_free (self->priv->authentication_result_string);
678 g_free (self->priv->log_filename);
679 g_free (self->priv->class);
680 g_free (self->priv->tty);
681 g_free (self->priv->xdisplay);
682 if (self->priv->xauthority)
683 g_object_unref (self->priv->xauthority);
684 g_free (self->priv->remote_host_name);
685 g_free (self->priv->login1_session);
686 g_free (self->priv->console_kit_cookie);
687 g_list_free_full (self->priv->env, g_free);
689 G_OBJECT_CLASS (session_parent_class)->finalize (object);
693 session_class_init (SessionClass *klass)
695 GObjectClass *object_class = G_OBJECT_CLASS (klass);
697 klass->set_display_server = session_real_set_display_server;
698 object_class->finalize = session_finalize;
700 g_type_class_add_private (klass, sizeof (SessionPrivate));
702 signals[GOT_MESSAGES] =
703 g_signal_new ("got-messages",
704 G_TYPE_FROM_CLASS (klass),
706 G_STRUCT_OFFSET (SessionClass, got_messages),
711 signals[AUTHENTICATION_COMPLETE] =
712 g_signal_new ("authentication-complete",
713 G_TYPE_FROM_CLASS (klass),
715 G_STRUCT_OFFSET (SessionClass, authentication_complete),
721 g_signal_new ("stopped",
722 G_TYPE_FROM_CLASS (klass),
724 G_STRUCT_OFFSET (SessionClass, stopped),