15 #include <security/pam_appl.h>
19 #include "configuration.h"
20 #include "session-child.h"
22 #include "console-kit.h"
24 #include "privileges.h"
25 #include "xauthority.h"
26 #include "configuration.h"
28 /* Child process being run */
29 static GPid child_pid = 0;
31 /* Pipe to communicate with daemon */
32 static int from_daemon_output = 0;
33 static int to_daemon_input = 0;
35 static gboolean is_interactive;
36 static gboolean do_authenticate;
37 static gboolean authentication_complete = FALSE;
38 static pam_handle_t *pam_handle;
40 /* Maximum length of a string to pass between daemon and session */
41 #define MAX_STRING_LENGTH 65535
44 write_data (const void *buf, size_t count)
46 if (write (to_daemon_input, buf, count) != count)
47 g_printerr ("Error writing to daemon: %s\n", strerror (errno));
51 write_string (const char *value)
55 length = value ? strlen (value) : -1;
56 write_data (&length, sizeof (length));
58 write_data (value, sizeof (char) * length);
62 read_data (void *buf, size_t count)
66 n_read = read (from_daemon_output, buf, count);
68 g_printerr ("Error reading from daemon: %s\n", strerror (errno));
74 read_string_full (void* (*alloc_fn)(size_t n))
79 if (read_data (&length, sizeof (length)) <= 0)
83 if (length > MAX_STRING_LENGTH)
85 g_printerr ("Invalid string length %d from daemon\n", length);
89 value = (*alloc_fn) (sizeof (char) * (length + 1));
90 read_data (value, length);
99 return read_string_full (g_malloc);
103 pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
106 gboolean auth_complete = FALSE;
107 struct pam_response *response;
108 gchar *username = NULL;
110 /* FIXME: We don't support communication after pam_authenticate completes */
111 if (authentication_complete)
114 /* Cancel authentication if requiring input */
117 for (i = 0; i < msg_length; i++)
119 if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
121 g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
126 /* Ignore informational messages */
130 /* Check if we changed user */
131 pam_get_item (pam_handle, PAM_USER, (const void **) &username);
133 /* Notify the daemon */
134 write_string (username);
135 write_data (&auth_complete, sizeof (auth_complete));
136 write_data (&msg_length, sizeof (msg_length));
137 for (i = 0; i < msg_length; i++)
139 const struct pam_message *m = msg[i];
140 write_data (&m->msg_style, sizeof (m->msg_style));
141 write_string (m->msg);
145 read_data (&error, sizeof (error));
146 if (error != PAM_SUCCESS)
148 response = calloc (msg_length, sizeof (struct pam_response));
149 for (i = 0; i < msg_length; i++)
151 struct pam_response *r = &response[i];
152 // callers of this function inside pam will expect to be able to call
153 // free() on the strings we give back. So alloc with malloc.
154 r->resp = read_string_full (malloc);
155 read_data (&r->resp_retcode, sizeof (r->resp_retcode));
163 signal_cb (int signum)
165 /* Pass on signal to child, otherwise just quit */
167 kill (child_pid, signum);
176 guint16 xauth_family;
177 guint8 *xauth_address;
178 gsize xauth_address_length;
181 gsize xauth_data_length;
183 xauth_name = read_string ();
187 read_data (&xauth_family, sizeof (xauth_family));
188 read_data (&xauth_address_length, sizeof (xauth_address_length));
189 xauth_address = g_malloc (xauth_address_length);
190 read_data (xauth_address, xauth_address_length);
191 xauth_number = read_string ();
192 read_data (&xauth_data_length, sizeof (xauth_data_length));
193 xauth_data = g_malloc (xauth_data_length);
194 read_data (xauth_data, xauth_data_length);
196 return xauth_new (xauth_family, xauth_address, xauth_address_length, xauth_number, xauth_name, xauth_data, xauth_data_length);
200 session_child_run (int argc, char **argv)
202 struct pam_conv conversation = { pam_conv_cb, NULL };
203 int i, version, fd, result;
204 gboolean auth_complete = TRUE;
206 gchar *log_filename, *log_backup_filename = NULL;
209 gchar **command_argv;
210 GVariantBuilder ck_parameters;
212 int authentication_result;
213 gchar *authentication_result_string;
218 gchar *remote_host_name;
220 XAuthority *xauthority = NULL;
221 gchar *xauth_filename;
222 GDBusConnection *bus;
223 gchar *console_kit_cookie = NULL;
224 gchar *login1_session = NULL;
227 GError *error = NULL;
228 const gchar *locale_value;
230 static const gchar * const locale_var_names[] = {
242 #if !defined(GLIB_VERSION_2_36)
246 if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
248 /* Protect memory from being paged to disk, as we deal with passwords */
249 mlockall (MCL_CURRENT | MCL_FUTURE);
252 /* Make input non-blocking */
253 fd = open ("/dev/null", O_RDONLY);
254 dup2 (fd, STDIN_FILENO);
258 fd = open ("/dev/null", O_WRONLY);
259 dup2 (fd, STDOUT_FILENO);
262 /* Get the pipe from the daemon */
265 g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
268 from_daemon_output = atoi (argv[2]);
269 to_daemon_input = atoi (argv[3]);
270 if (from_daemon_output == 0 || to_daemon_input == 0)
272 g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
276 /* Don't let these pipes leak to the command we will run */
277 fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
278 fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
280 /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
281 read_data (&version, sizeof (version));
283 service = read_string ();
284 username = read_string ();
285 read_data (&do_authenticate, sizeof (do_authenticate));
286 read_data (&is_interactive, sizeof (is_interactive));
287 class = read_string ();
288 tty = read_string ();
289 remote_host_name = read_string ();
290 xdisplay = read_string ();
291 xauthority = read_xauth ();
294 result = pam_start (service, username, &conversation, &pam_handle);
295 if (result != PAM_SUCCESS)
297 g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
303 pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
305 pam_set_item (pam_handle, PAM_TTY, xdisplay);
308 pam_set_item (pam_handle, PAM_TTY, tty);
313 struct pam_xauth_data value;
315 value.name = (char *) xauth_get_authorization_name (xauthority);
316 value.namelen = strlen (xauth_get_authorization_name (xauthority));
317 value.data = (char *) xauth_get_authorization_data (xauthority);
318 value.datalen = xauth_get_authorization_data_length (xauthority);
319 pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
326 const gchar *new_username;
328 authentication_result = pam_authenticate (pam_handle, 0);
330 /* See what user we ended up as */
331 if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
334 username = g_strdup (new_username);
336 /* Check account is valid */
337 if (authentication_result == PAM_SUCCESS)
338 authentication_result = pam_acct_mgmt (pam_handle, 0);
339 if (authentication_result == PAM_NEW_AUTHTOK_REQD)
340 authentication_result = pam_chauthtok (pam_handle, 0);
343 authentication_result = PAM_SUCCESS;
344 authentication_complete = TRUE;
346 if (authentication_result == PAM_SUCCESS)
348 /* Fail authentication if user doesn't actually exist */
349 user = accounts_get_user_by_name (username);
352 g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
353 authentication_result = PAM_USER_UNKNOWN;
357 /* Set POSIX variables */
358 pam_putenv (pam_handle, "PATH=/usr/local/bin:/usr/bin:/bin");
359 pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
360 pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
361 pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
362 pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
364 /* Let the greeter and user session inherit the system default locale */
365 for (i = 0; locale_var_names[i] != NULL; i++)
367 if ((locale_value = g_getenv (locale_var_names[i])) != NULL)
369 locale_var = g_strdup_printf ("%s=%s", locale_var_names[i], locale_value);
370 pam_putenv (pam_handle, locale_var);
377 authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
379 /* Report authentication result */
380 write_string (username);
381 write_data (&auth_complete, sizeof (auth_complete));
382 write_data (&authentication_result, sizeof (authentication_result));
383 write_string (authentication_result_string);
385 /* Check we got a valid user */
388 g_printerr ("No user selected during authentication\n");
392 /* Stop if we didn't authenticated */
393 if (authentication_result != PAM_SUCCESS)
396 /* Get the command to run (blocks) */
397 log_filename = read_string ();
401 tty = read_string ();
403 xauth_filename = read_string ();
407 xdisplay = read_string ();
409 g_object_unref (xauthority);
410 xauthority = read_xauth ();
412 read_data (&env_length, sizeof (env_length));
413 for (i = 0; i < env_length; i++)
414 pam_putenv (pam_handle, read_string ());
415 read_data (&command_argc, sizeof (command_argc));
416 command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
417 for (i = 0; i < command_argc; i++)
418 command_argv[i] = read_string ();
419 command_argv[i] = NULL;
421 /* Redirect stderr to a log file */
423 log_backup_filename = g_strdup_printf ("%s.old", log_filename);
426 fd = open ("/dev/null", O_WRONLY);
427 dup2 (fd, STDERR_FILENO);
430 else if (g_path_is_absolute (log_filename))
432 rename (log_filename, log_backup_filename);
433 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
434 dup2 (fd, STDERR_FILENO);
438 /* Set group membership - these can be overriden in pam_setcred */
441 if (initgroups (username, user_get_gid (user)) < 0)
443 g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
444 _exit (EXIT_FAILURE);
448 /* Set credentials */
449 result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
450 if (result != PAM_SUCCESS)
452 g_printerr ("Failed to establish PAM credentials: %s\n", pam_strerror (pam_handle, result));
456 /* Open the session */
457 result = pam_open_session (pam_handle, 0);
458 if (result != PAM_SUCCESS)
460 g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
464 /* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
465 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
467 g_printerr ("Unable to contact system bus: %s", error->message);
471 if (login1_is_running ())
473 login1_session = login1_get_session_id ();
474 write_string (login1_session);
479 /* Open a Console Kit session */
480 g_variant_builder_init (&ck_parameters, G_VARIANT_TYPE ("(a(sv))"));
481 g_variant_builder_open (&ck_parameters, G_VARIANT_TYPE ("a(sv)"));
482 g_variant_builder_add (&ck_parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
483 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) == 0)
484 g_variant_builder_add (&ck_parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
487 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display", g_variant_new_string (xdisplay));
489 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display-device", g_variant_new_string (tty));
491 if (remote_host_name)
493 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (FALSE));
494 g_variant_builder_add (&ck_parameters, "(sv)", "remote-host-name", g_variant_new_string (remote_host_name));
497 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (TRUE));
498 console_kit_cookie = ck_open_session (&ck_parameters);
499 write_string (console_kit_cookie);
500 if (console_kit_cookie)
503 value = g_strdup_printf ("XDG_SESSION_COOKIE=%s", console_kit_cookie);
504 pam_putenv (pam_handle, value);
509 /* Write X authority */
512 gboolean drop_privileges, result;
514 GError *error = NULL;
516 drop_privileges = geteuid () == 0;
518 privileges_drop (user);
519 result = xauth_write (xauthority, XAUTH_WRITE_MODE_REPLACE, xauth_filename, &error);
521 privileges_reclaim ();
524 g_printerr ("Error writing X authority: %s\n", error->message);
525 g_clear_error (&error);
529 value = g_strdup_printf ("XAUTHORITY=%s", xauth_filename);
530 pam_putenv (pam_handle, value);
534 /* Put our tools directory in the path as a hack so we can use the legacy gdmflexiserver interface */
535 path = pam_getenv (pam_handle, "PATH");
537 pam_putenv (pam_handle, g_strdup_printf ("PATH=%s:%s", PKGLIBEXEC_DIR, path));
539 /* Catch terminate signal and pass it to the child */
540 signal (SIGTERM, signal_cb);
542 /* Run the command as the authenticated user */
546 // FIXME: This is not thread safe (particularly the printfs)
548 /* Make this process its own session */
550 g_printerr ("Failed to make process a new session: %s\n", strerror (errno));
552 /* Change to this user */
555 if (setgid (user_get_gid (user)) != 0)
557 g_printerr ("Failed to set group ID to %d: %s\n", user_get_gid (user), strerror (errno));
558 _exit (EXIT_FAILURE);
561 if (setuid (user_get_uid (user)) != 0)
563 g_printerr ("Failed to set user ID to %d: %s\n", user_get_uid (user), strerror (errno));
564 _exit (EXIT_FAILURE);
568 /* Change working directory */
569 /* NOTE: This must be done after the permissions are changed because NFS filesystems can
570 * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
571 * are not system readable then the chdir can fail */
572 if (chdir (user_get_home_directory (user)) != 0)
574 g_printerr ("Failed to change to home directory %s: %s\n", user_get_home_directory (user), strerror (errno));
575 _exit (EXIT_FAILURE);
578 /* Redirect stderr to a log file */
579 if (log_filename && !g_path_is_absolute (log_filename))
581 rename (log_filename, log_backup_filename);
582 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
583 dup2 (fd, STDERR_FILENO);
587 /* Run the command */
588 execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
589 g_printerr ("Failed to run command: %s\n", strerror (errno));
590 _exit (EXIT_FAILURE);
593 /* Bail out if failed to fork */
596 g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
597 return_code = EXIT_FAILURE;
600 /* Wait for the command to complete (blocks) */
604 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) != 0)
609 memset (&ut, 0, sizeof (ut));
610 ut.ut_type = USER_PROCESS;
611 ut.ut_pid = child_pid;
612 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
613 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
614 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
616 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
617 else if (remote_host_name)
618 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
619 gettimeofday (&tv, NULL);
620 ut.ut_tv.tv_sec = tv.tv_sec;
621 ut.ut_tv.tv_usec = tv.tv_usec;
624 if (!pututxline (&ut))
625 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
629 waitpid (child_pid, &return_code, 0);
633 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) != 0)
638 memset (&ut, 0, sizeof (ut));
639 ut.ut_type = DEAD_PROCESS;
640 ut.ut_pid = child_pid;
641 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
642 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
643 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
645 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
646 else if (remote_host_name)
647 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
648 gettimeofday (&tv, NULL);
649 ut.ut_tv.tv_sec = tv.tv_sec;
650 ut.ut_tv.tv_usec = tv.tv_usec;
653 if (!pututxline (&ut))
654 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
659 /* Remove X authority */
662 gboolean drop_privileges, result;
663 GError *error = NULL;
665 drop_privileges = geteuid () == 0;
667 privileges_drop (user);
668 result = xauth_write (xauthority, XAUTH_WRITE_MODE_REMOVE, xauth_filename, &error);
670 privileges_reclaim ();
673 g_printerr ("Error removing X authority: %s\n", error->message);
674 g_clear_error (&error);
676 _exit (EXIT_FAILURE);
679 /* Close the Console Kit session */
680 if (console_kit_cookie)
681 ck_close_session (console_kit_cookie);
683 /* Close the session */
684 pam_close_session (pam_handle, 0);
686 /* Remove credentials */
687 result = pam_setcred (pam_handle, PAM_DELETE_CRED);
689 pam_end (pam_handle, 0);
692 /* Return result of session process to the daemon */