15 #include <security/pam_appl.h>
20 #include "configuration.h"
21 #include "session-child.h"
23 #include "console-kit.h"
25 #include "privileges.h"
26 #include "x-authority.h"
27 #include "configuration.h"
29 /* Child process being run */
30 static GPid child_pid = 0;
32 /* Pipe to communicate with daemon */
33 static int from_daemon_output = 0;
34 static int to_daemon_input = 0;
36 static gboolean is_interactive;
37 static gboolean do_authenticate;
38 static gboolean authentication_complete = FALSE;
39 static pam_handle_t *pam_handle;
41 /* Maximum length of a string to pass between daemon and session */
42 #define MAX_STRING_LENGTH 65535
45 write_data (const void *buf, size_t count)
47 if (write (to_daemon_input, buf, count) != count)
48 g_printerr ("Error writing to daemon: %s\n", strerror (errno));
52 write_string (const char *value)
56 length = value ? strlen (value) : -1;
57 write_data (&length, sizeof (length));
59 write_data (value, sizeof (char) * length);
63 read_data (void *buf, size_t count)
67 n_read = read (from_daemon_output, buf, count);
69 g_printerr ("Error reading from daemon: %s\n", strerror (errno));
75 read_string_full (void* (*alloc_fn)(size_t n))
80 if (read_data (&length, sizeof (length)) <= 0)
84 if (length > MAX_STRING_LENGTH)
86 g_printerr ("Invalid string length %d from daemon\n", length);
90 value = (*alloc_fn) (sizeof (char) * (length + 1));
91 read_data (value, length);
100 return read_string_full (g_malloc);
104 pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
107 gboolean auth_complete = FALSE;
108 struct pam_response *response;
109 gchar *username = NULL;
111 /* FIXME: We don't support communication after pam_authenticate completes */
112 if (authentication_complete)
115 /* Cancel authentication if requiring input */
118 for (i = 0; i < msg_length; i++)
120 if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
122 g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
127 /* Ignore informational messages */
131 /* Check if we changed user */
132 pam_get_item (pam_handle, PAM_USER, (const void **) &username);
134 /* Notify the daemon */
135 write_string (username);
136 write_data (&auth_complete, sizeof (auth_complete));
137 write_data (&msg_length, sizeof (msg_length));
138 for (i = 0; i < msg_length; i++)
140 const struct pam_message *m = msg[i];
141 write_data (&m->msg_style, sizeof (m->msg_style));
142 write_string (m->msg);
146 read_data (&error, sizeof (error));
147 if (error != PAM_SUCCESS)
149 response = calloc (msg_length, sizeof (struct pam_response));
150 for (i = 0; i < msg_length; i++)
152 struct pam_response *r = &response[i];
153 // callers of this function inside pam will expect to be able to call
154 // free() on the strings we give back. So alloc with malloc.
155 r->resp = read_string_full (malloc);
156 read_data (&r->resp_retcode, sizeof (r->resp_retcode));
164 signal_cb (int signum)
166 /* Pass on signal to child, otherwise just quit */
168 kill (child_pid, signum);
176 gchar *x_authority_name;
177 guint16 x_authority_family;
178 guint8 *x_authority_address;
179 gsize x_authority_address_length;
180 gchar *x_authority_number;
181 guint8 *x_authority_data;
182 gsize x_authority_data_length;
184 x_authority_name = read_string ();
185 if (!x_authority_name)
188 read_data (&x_authority_family, sizeof (x_authority_family));
189 read_data (&x_authority_address_length, sizeof (x_authority_address_length));
190 x_authority_address = g_malloc (x_authority_address_length);
191 read_data (x_authority_address, x_authority_address_length);
192 x_authority_number = read_string ();
193 read_data (&x_authority_data_length, sizeof (x_authority_data_length));
194 x_authority_data = g_malloc (x_authority_data_length);
195 read_data (x_authority_data, x_authority_data_length);
197 return x_authority_new (x_authority_family, x_authority_address, x_authority_address_length, x_authority_number, x_authority_name, x_authority_data, x_authority_data_length);
200 /* GNU provides this but we can't rely on that so let's make our own version */
202 updwtmpx (const gchar *wtmp_file, struct utmpx *ut)
206 memset (&u, 0, sizeof (u));
207 u.ut_type = ut->ut_type;
208 u.ut_pid = ut->ut_pid;
210 strncpy (u.ut_line, ut->ut_line, sizeof (u.ut_line));
212 strncpy (u.ut_id, ut->ut_id, sizeof (u.ut_id));
214 strncpy (u.ut_user, ut->ut_user, sizeof (u.ut_user));
216 strncpy (u.ut_host, ut->ut_host, sizeof (u.ut_host));
217 u.ut_tv.tv_sec = ut->ut_tv.tv_sec;
218 u.ut_tv.tv_usec = ut->ut_tv.tv_usec;
220 updwtmp (wtmp_file, &u);
224 session_child_run (int argc, char **argv)
226 struct pam_conv conversation = { pam_conv_cb, NULL };
227 int i, version, fd, result;
228 gboolean auth_complete = TRUE;
230 gchar *log_filename, *log_backup_filename = NULL;
233 gchar **command_argv;
234 GVariantBuilder ck_parameters;
236 int authentication_result;
237 gchar *authentication_result_string;
241 gchar *remote_host_name;
243 XAuthority *x_authority = NULL;
244 gchar *x_authority_filename;
245 GDBusConnection *bus;
246 gchar *console_kit_cookie = NULL;
247 gchar *login1_session = NULL;
248 const gchar *locale_value;
250 static const gchar * const locale_var_names[] = {
263 const gchar *home_directory;
264 GError *error = NULL;
266 #if !defined(GLIB_VERSION_2_36)
270 if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
272 /* Protect memory from being paged to disk, as we deal with passwords */
273 mlockall (MCL_CURRENT | MCL_FUTURE);
276 /* Make input non-blocking */
277 fd = open ("/dev/null", O_RDONLY);
278 dup2 (fd, STDIN_FILENO);
282 fd = open ("/dev/null", O_WRONLY);
283 dup2 (fd, STDOUT_FILENO);
286 /* Get the pipe from the daemon */
289 g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
292 from_daemon_output = atoi (argv[2]);
293 to_daemon_input = atoi (argv[3]);
294 if (from_daemon_output == 0 || to_daemon_input == 0)
296 g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
300 /* Don't let these pipes leak to the command we will run */
301 fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
302 fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
304 /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
305 read_data (&version, sizeof (version));
307 service = read_string ();
308 username = read_string ();
309 read_data (&do_authenticate, sizeof (do_authenticate));
310 read_data (&is_interactive, sizeof (is_interactive));
311 read_string (); /* Used to be class, now we just use the environment variable */
312 tty = read_string ();
313 remote_host_name = read_string ();
314 xdisplay = read_string ();
315 x_authority = read_xauth ();
318 result = pam_start (service, username, &conversation, &pam_handle);
319 if (result != PAM_SUCCESS)
321 g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
327 pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
329 pam_set_item (pam_handle, PAM_TTY, xdisplay);
332 pam_set_item (pam_handle, PAM_TTY, tty);
337 struct pam_xauth_data value;
339 value.name = (char *) x_authority_get_authorization_name (x_authority);
340 value.namelen = strlen (x_authority_get_authorization_name (x_authority));
341 value.data = (char *) x_authority_get_authorization_data (x_authority);
342 value.datalen = x_authority_get_authorization_data_length (x_authority);
343 pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
350 const gchar *new_username;
352 authentication_result = pam_authenticate (pam_handle, 0);
354 /* See what user we ended up as */
355 if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
358 username = g_strdup (new_username);
360 /* Write record to btmp database */
361 if (authentication_result == PAM_AUTH_ERR)
366 memset (&ut, 0, sizeof (ut));
367 ut.ut_type = USER_PROCESS;
368 ut.ut_pid = getpid ();
371 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
372 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
375 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
376 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
378 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
379 else if (remote_host_name)
380 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
381 gettimeofday (&tv, NULL);
382 ut.ut_tv.tv_sec = tv.tv_sec;
383 ut.ut_tv.tv_usec = tv.tv_usec;
385 updwtmpx ("/var/log/btmp", &ut);
388 /* Check account is valid */
389 if (authentication_result == PAM_SUCCESS)
390 authentication_result = pam_acct_mgmt (pam_handle, 0);
391 if (authentication_result == PAM_NEW_AUTHTOK_REQD)
392 authentication_result = pam_chauthtok (pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
395 authentication_result = PAM_SUCCESS;
396 authentication_complete = TRUE;
398 if (authentication_result == PAM_SUCCESS)
400 /* Fail authentication if user doesn't actually exist */
401 user = accounts_get_user_by_name (username);
404 g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
405 authentication_result = PAM_USER_UNKNOWN;
409 /* Set POSIX variables */
410 pam_putenv (pam_handle, "PATH=/usr/local/bin:/usr/bin:/bin");
411 pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
412 pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
413 pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
414 pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
416 /* Let the greeter and user session inherit the system default locale */
417 for (i = 0; locale_var_names[i] != NULL; i++)
419 if ((locale_value = g_getenv (locale_var_names[i])) != NULL)
421 locale_var = g_strdup_printf ("%s=%s", locale_var_names[i], locale_value);
422 pam_putenv (pam_handle, locale_var);
429 authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
431 /* Report authentication result */
432 write_string (username);
433 write_data (&auth_complete, sizeof (auth_complete));
434 write_data (&authentication_result, sizeof (authentication_result));
435 write_string (authentication_result_string);
437 /* Check we got a valid user */
440 g_printerr ("No user selected during authentication\n");
444 /* Stop if we didn't authenticated */
445 if (authentication_result != PAM_SUCCESS)
448 /* Get the command to run (blocks) */
449 log_filename = read_string ();
453 tty = read_string ();
455 x_authority_filename = read_string ();
459 xdisplay = read_string ();
461 g_object_unref (x_authority);
462 x_authority = read_xauth ();
464 read_data (&env_length, sizeof (env_length));
465 for (i = 0; i < env_length; i++)
466 pam_putenv (pam_handle, read_string ());
467 read_data (&command_argc, sizeof (command_argc));
468 command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
469 for (i = 0; i < command_argc; i++)
470 command_argv[i] = read_string ();
471 command_argv[i] = NULL;
473 /* Redirect stderr to a log file */
476 log_backup_filename = g_strdup_printf ("%s.old", log_filename);
477 if (g_path_is_absolute (log_filename))
479 rename (log_filename, log_backup_filename);
480 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
481 dup2 (fd, STDERR_FILENO);
483 g_free (log_filename);
489 fd = open ("/dev/null", O_WRONLY);
490 dup2 (fd, STDERR_FILENO);
494 /* Set group membership - these can be overriden in pam_setcred */
497 if (initgroups (username, user_get_gid (user)) < 0)
499 g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
500 _exit (EXIT_FAILURE);
504 /* Set credentials */
505 result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
506 if (result != PAM_SUCCESS)
508 g_printerr ("Failed to establish PAM credentials: %s\n", pam_strerror (pam_handle, result));
512 /* Open the session */
513 result = pam_open_session (pam_handle, 0);
514 if (result != PAM_SUCCESS)
516 g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
520 /* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
521 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
523 g_printerr ("Unable to contact system bus: %s", error->message);
527 if (login1_is_running ())
529 login1_session = login1_get_session_id ();
530 write_string (login1_session);
535 /* Open a Console Kit session */
536 g_variant_builder_init (&ck_parameters, G_VARIANT_TYPE ("(a(sv))"));
537 g_variant_builder_open (&ck_parameters, G_VARIANT_TYPE ("a(sv)"));
538 g_variant_builder_add (&ck_parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
539 if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") == 0)
540 g_variant_builder_add (&ck_parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
543 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display", g_variant_new_string (xdisplay));
545 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display-device", g_variant_new_string (tty));
547 if (remote_host_name)
549 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (FALSE));
550 g_variant_builder_add (&ck_parameters, "(sv)", "remote-host-name", g_variant_new_string (remote_host_name));
553 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (TRUE));
554 console_kit_cookie = ck_open_session (&ck_parameters);
555 write_string (console_kit_cookie);
556 if (console_kit_cookie)
559 value = g_strdup_printf ("XDG_SESSION_COOKIE=%s", console_kit_cookie);
560 pam_putenv (pam_handle, value);
565 /* Write X authority */
568 gboolean drop_privileges, result;
570 GError *error = NULL;
572 drop_privileges = geteuid () == 0;
574 privileges_drop (user_get_uid (user), user_get_gid (user));
575 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REPLACE, x_authority_filename, &error);
577 privileges_reclaim ();
580 g_printerr ("Error writing X authority: %s\n", error->message);
581 g_clear_error (&error);
585 value = g_strdup_printf ("XAUTHORITY=%s", x_authority_filename);
586 pam_putenv (pam_handle, value);
590 /* Catch terminate signal and pass it to the child */
591 signal (SIGTERM, signal_cb);
593 /* Run the command as the authenticated user */
594 uid = user_get_uid (user);
595 gid = user_get_gid (user);
596 home_directory = user_get_home_directory (user);
600 /* Make this process its own session */
604 /* Change to this user */
607 if (setgid (gid) != 0)
610 if (setuid (uid) != 0)
614 /* Change working directory */
615 /* NOTE: This must be done after the permissions are changed because NFS filesystems can
616 * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
617 * are not system readable then the chdir can fail */
618 if (chdir (home_directory) != 0)
623 rename (log_filename, log_backup_filename);
624 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
627 dup2 (fd, STDERR_FILENO);
632 /* Run the command */
633 execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
634 _exit (EXIT_FAILURE);
637 /* Bail out if failed to fork */
640 g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
641 return_code = EXIT_FAILURE;
644 /* Wait for the command to complete (blocks) */
648 if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
653 memset (&ut, 0, sizeof (ut));
654 ut.ut_type = USER_PROCESS;
655 ut.ut_pid = child_pid;
658 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
659 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
662 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
663 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
665 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
666 else if (remote_host_name)
667 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
668 gettimeofday (&tv, NULL);
669 ut.ut_tv.tv_sec = tv.tv_sec;
670 ut.ut_tv.tv_usec = tv.tv_usec;
672 /* Write records to utmp/wtmp databases */
674 if (!pututxline (&ut))
675 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
677 updwtmpx ("/var/log/wtmp", &ut);
680 waitpid (child_pid, &return_code, 0);
684 if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
689 memset (&ut, 0, sizeof (ut));
690 ut.ut_type = DEAD_PROCESS;
691 ut.ut_pid = child_pid;
694 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
695 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
698 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
699 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
701 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
702 else if (remote_host_name)
703 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
704 gettimeofday (&tv, NULL);
705 ut.ut_tv.tv_sec = tv.tv_sec;
706 ut.ut_tv.tv_usec = tv.tv_usec;
708 /* Write records to utmp/wtmp databases */
710 if (!pututxline (&ut))
711 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
713 updwtmpx ("/var/log/wtmp", &ut);
717 /* Remove X authority */
720 gboolean drop_privileges, result;
721 GError *error = NULL;
723 drop_privileges = geteuid () == 0;
725 privileges_drop (user_get_uid (user), user_get_gid (user));
726 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REMOVE, x_authority_filename, &error);
728 privileges_reclaim ();
731 g_printerr ("Error removing X authority: %s\n", error->message);
732 g_clear_error (&error);
734 _exit (EXIT_FAILURE);
737 /* Close the Console Kit session */
738 if (console_kit_cookie)
739 ck_close_session (console_kit_cookie);
741 /* Close the session */
742 pam_close_session (pam_handle, 0);
744 /* Remove credentials */
745 result = pam_setcred (pam_handle, PAM_DELETE_CRED);
747 pam_end (pam_handle, 0);
750 /* Return result of session process to the daemon */