13 #include <security/pam_appl.h>
17 #include "session-child.h"
19 #include "console-kit.h"
20 #include "privileges.h"
21 #include "xauthority.h"
22 #include "configuration.h"
24 /* Child process being run */
25 static GPid child_pid = 0;
27 /* Pipe to communicate with daemon */
28 static int from_daemon_output = 0;
29 static int to_daemon_input = 0;
31 static gboolean is_interactive;
32 static gboolean do_authenticate;
33 static gboolean authentication_complete = FALSE;
34 static pam_handle_t *pam_handle;
36 /* Maximum length of a string to pass between daemon and session */
37 #define MAX_STRING_LENGTH 65535
40 write_data (const void *buf, size_t count)
42 if (write (to_daemon_input, buf, count) != count)
43 g_printerr ("Error writing to daemon: %s\n", strerror (errno));
47 write_string (const char *value)
51 length = value ? strlen (value) : -1;
52 write_data (&length, sizeof (length));
54 write_data (value, sizeof (char) * length);
58 read_data (void *buf, size_t count)
62 n_read = read (from_daemon_output, buf, count);
64 g_printerr ("Error reading from daemon: %s\n", strerror (errno));
70 read_string_full (void* (*alloc_fn)(size_t n))
75 if (read_data (&length, sizeof (length)) <= 0)
79 if (length > MAX_STRING_LENGTH)
81 g_printerr ("Invalid string length %d from daemon\n", length);
85 value = (*alloc_fn) (sizeof (char) * (length + 1));
86 read_data (value, length);
95 return read_string_full (g_malloc);
99 pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
102 gboolean auth_complete = FALSE;
103 struct pam_response *response;
104 gchar *username = NULL;
106 /* FIXME: We don't support communication after pam_authenticate completes */
107 if (authentication_complete)
110 /* Cancel authentication if requiring input */
113 for (i = 0; i < msg_length; i++)
115 if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
117 g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
122 /* Ignore informational messages */
126 /* Check if we changed user */
127 pam_get_item (pam_handle, PAM_USER, (const void **) &username);
129 /* Notify the daemon */
130 write_string (username);
131 write_data (&auth_complete, sizeof (auth_complete));
132 write_data (&msg_length, sizeof (msg_length));
133 for (i = 0; i < msg_length; i++)
135 const struct pam_message *m = msg[i];
136 write_data (&m->msg_style, sizeof (m->msg_style));
137 write_string (m->msg);
141 read_data (&error, sizeof (error));
142 if (error != PAM_SUCCESS)
144 response = calloc (msg_length, sizeof (struct pam_response));
145 for (i = 0; i < msg_length; i++)
147 struct pam_response *r = &response[i];
148 // callers of this function inside pam will expect to be able to call
149 // free() on the strings we give back. So alloc with malloc.
150 r->resp = read_string_full (malloc);
151 read_data (&r->resp_retcode, sizeof (r->resp_retcode));
159 signal_cb (int signum)
161 /* Pass on signal to child, otherwise just quit */
163 kill (child_pid, signum);
169 session_child_run (int argc, char **argv)
171 struct pam_conv conversation = { pam_conv_cb, NULL };
172 int i, version, fd, result;
173 gboolean auth_complete = TRUE;
175 gchar *log_filename, *log_backup_filename = NULL;
178 gchar **command_argv;
179 GVariantBuilder ck_parameters;
181 int authentication_result;
182 gchar *authentication_result_string;
187 gchar *remote_host_name;
190 XAuthority *xauthority = NULL;
191 gchar *xauth_filename;
192 GDBusConnection *bus;
193 gchar *console_kit_cookie;
195 GError *error = NULL;
196 const gchar *locale_value;
198 static const gchar * const locale_var_names[] = {
210 #if !defined(GLIB_VERSION_2_36)
214 if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
216 /* Protect memory from being paged to disk, as we deal with passwords */
217 mlockall (MCL_CURRENT | MCL_FUTURE);
220 /* Make input non-blocking */
221 fd = open ("/dev/null", O_RDONLY);
222 dup2 (fd, STDIN_FILENO);
226 fd = open ("/dev/null", O_WRONLY);
227 dup2 (fd, STDOUT_FILENO);
230 /* Get the pipe from the daemon */
233 g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
236 from_daemon_output = atoi (argv[2]);
237 to_daemon_input = atoi (argv[3]);
238 if (from_daemon_output == 0 || to_daemon_input == 0)
240 g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
244 /* Don't let these pipes leak to the command we will run */
245 fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
246 fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
248 /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
249 read_data (&version, sizeof (version));
251 service = read_string ();
252 username = read_string ();
253 read_data (&do_authenticate, sizeof (do_authenticate));
254 read_data (&is_interactive, sizeof (is_interactive));
255 class = read_string ();
256 tty = read_string ();
257 remote_host_name = read_string ();
258 xdisplay = read_string ();
259 xauth_name = read_string ();
262 guint16 xauth_family;
263 guint8 *xauth_address;
264 gsize xauth_address_length;
267 gsize xauth_data_length;
269 read_data (&xauth_family, sizeof (xauth_family));
270 read_data (&xauth_address_length, sizeof (xauth_address_length));
271 xauth_address = g_malloc (xauth_address_length);
272 read_data (xauth_address, xauth_address_length);
273 xauth_number = read_string ();
274 read_data (&xauth_data_length, sizeof (xauth_data_length));
275 xauth_data = g_malloc (xauth_data_length);
276 read_data (xauth_data, xauth_data_length);
278 xauthority = xauth_new (xauth_family, xauth_address, xauth_address_length, xauth_number, xauth_name, xauth_data, xauth_data_length);
282 result = pam_start (service, username, &conversation, &pam_handle);
283 if (result != PAM_SUCCESS)
285 g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
291 pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
293 pam_set_item (pam_handle, PAM_TTY, xdisplay);
296 pam_set_item (pam_handle, PAM_TTY, tty);
301 struct pam_xauth_data value;
303 value.name = (char *) xauth_get_authorization_name (xauthority);
304 value.namelen = strlen (xauth_get_authorization_name (xauthority));
305 value.data = (char *) xauth_get_authorization_data (xauthority);
306 value.datalen = xauth_get_authorization_data_length (xauthority);
307 pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
314 const gchar *new_username;
316 authentication_result = pam_authenticate (pam_handle, 0);
318 /* See what user we ended up as */
319 if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
322 username = g_strdup (new_username);
324 /* Check account is valid */
325 if (authentication_result == PAM_SUCCESS)
326 authentication_result = pam_acct_mgmt (pam_handle, 0);
327 if (authentication_result == PAM_NEW_AUTHTOK_REQD)
328 authentication_result = pam_chauthtok (pam_handle, 0);
331 authentication_result = PAM_SUCCESS;
332 authentication_complete = TRUE;
334 if (authentication_result == PAM_SUCCESS)
336 /* Fail authentication if user doesn't actually exist */
337 user = accounts_get_user_by_name (username);
340 g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
341 authentication_result = PAM_USER_UNKNOWN;
345 /* Set POSIX variables */
346 pam_putenv (pam_handle, "PATH=/usr/local/bin:/usr/bin:/bin");
347 pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
348 pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
349 pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
350 pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
352 /* Let the greeter and user session inherit the system default locale */
353 for (i = 0; locale_var_names[i] != NULL; i++)
355 if ((locale_value = g_getenv (locale_var_names[i])) != NULL)
357 locale_var = g_strdup_printf ("%s=%s", locale_var_names[i], locale_value);
358 pam_putenv (pam_handle, locale_var);
365 authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
367 /* Report authentication result */
368 write_string (username);
369 write_data (&auth_complete, sizeof (auth_complete));
370 write_data (&authentication_result, sizeof (authentication_result));
371 write_string (authentication_result_string);
373 /* Check we got a valid user */
376 g_printerr ("No user selected during authentication\n");
380 /* Stop if we didn't authenticated */
381 if (authentication_result != PAM_SUCCESS)
384 /* Get the command to run (blocks) */
385 log_filename = read_string ();
386 xauth_filename = read_string ();
387 read_data (&env_length, sizeof (env_length));
388 for (i = 0; i < env_length; i++)
389 pam_putenv (pam_handle, read_string ());
390 read_data (&command_argc, sizeof (command_argc));
391 command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
392 for (i = 0; i < command_argc; i++)
393 command_argv[i] = read_string ();
394 command_argv[i] = NULL;
396 /* Redirect stderr to a log file */
398 log_backup_filename = g_strdup_printf ("%s.old", log_filename);
401 fd = open ("/dev/null", O_WRONLY);
402 dup2 (fd, STDERR_FILENO);
405 else if (g_path_is_absolute (log_filename))
407 rename (log_filename, log_backup_filename);
408 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
409 dup2 (fd, STDERR_FILENO);
413 /* Set group membership - these can be overriden in pam_setcred */
416 if (initgroups (username, user_get_gid (user)) < 0)
418 g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
419 _exit (EXIT_FAILURE);
423 /* Set credentials */
424 result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
425 if (result != PAM_SUCCESS)
427 g_printerr ("Failed to establish PAM credentials: %s\n", pam_strerror (pam_handle, result));
431 /* Open the session */
432 result = pam_open_session (pam_handle, 0);
433 if (result != PAM_SUCCESS)
435 g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
439 /* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
440 bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
442 g_printerr ("Unable to contact system bus: %s", error->message);
446 /* Open a Console Kit session */
447 g_variant_builder_init (&ck_parameters, G_VARIANT_TYPE ("(a(sv))"));
448 g_variant_builder_open (&ck_parameters, G_VARIANT_TYPE ("a(sv)"));
449 g_variant_builder_add (&ck_parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
450 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) == 0)
451 g_variant_builder_add (&ck_parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
454 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display", g_variant_new_string (xdisplay));
456 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display-device", g_variant_new_string (tty));
458 if (remote_host_name)
460 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (FALSE));
461 g_variant_builder_add (&ck_parameters, "(sv)", "remote-host-name", g_variant_new_string (remote_host_name));
464 g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (TRUE));
465 console_kit_cookie = ck_open_session (&ck_parameters);
466 write_string (console_kit_cookie);
467 if (console_kit_cookie)
470 value = g_strdup_printf ("XDG_SESSION_COOKIE=%s", console_kit_cookie);
471 pam_putenv (pam_handle, value);
475 /* Write X authority */
478 gboolean drop_privileges, result;
480 GError *error = NULL;
482 drop_privileges = geteuid () == 0;
484 privileges_drop (user);
485 result = xauth_write (xauthority, XAUTH_WRITE_MODE_REPLACE, xauth_filename, &error);
487 privileges_reclaim ();
490 g_printerr ("Error writing X authority: %s\n", error->message);
491 g_clear_error (&error);
495 value = g_strdup_printf ("XAUTHORITY=%s", xauth_filename);
496 pam_putenv (pam_handle, value);
500 /* Put our tools directory in the path as a hack so we can use the legacy gdmflexiserver interface */
501 path = pam_getenv (pam_handle, "PATH");
503 pam_putenv (pam_handle, g_strdup_printf ("PATH=%s:%s", PKGLIBEXEC_DIR, path));
505 /* Catch terminate signal and pass it to the child */
506 signal (SIGTERM, signal_cb);
508 /* Run the command as the authenticated user */
512 // FIXME: This is not thread safe (particularly the printfs)
514 /* Make this process its own session */
516 g_printerr ("Failed to make process a new session: %s\n", strerror (errno));
518 /* Change to this user */
521 if (setgid (user_get_gid (user)) != 0)
523 g_printerr ("Failed to set group ID to %d: %s\n", user_get_gid (user), strerror (errno));
524 _exit (EXIT_FAILURE);
527 if (setuid (user_get_uid (user)) != 0)
529 g_printerr ("Failed to set user ID to %d: %s\n", user_get_uid (user), strerror (errno));
530 _exit (EXIT_FAILURE);
534 /* Change working directory */
535 /* NOTE: This must be done after the permissions are changed because NFS filesystems can
536 * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
537 * are not system readable then the chdir can fail */
538 if (chdir (user_get_home_directory (user)) != 0)
540 g_printerr ("Failed to change to home directory %s: %s\n", user_get_home_directory (user), strerror (errno));
541 _exit (EXIT_FAILURE);
544 /* Redirect stderr to a log file */
545 if (log_filename && !g_path_is_absolute (log_filename))
547 rename (log_filename, log_backup_filename);
548 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
549 dup2 (fd, STDERR_FILENO);
553 /* Run the command */
554 execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
555 g_printerr ("Failed to run command: %s\n", strerror (errno));
556 _exit (EXIT_FAILURE);
559 /* Bail out if failed to fork */
562 g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
563 return_code = EXIT_FAILURE;
566 /* Wait for the command to complete (blocks) */
570 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) != 0)
575 memset (&ut, 0, sizeof (ut));
576 ut.ut_type = USER_PROCESS;
577 ut.ut_pid = child_pid;
578 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
579 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
580 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
582 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
583 else if (remote_host_name)
584 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
585 gettimeofday (&tv, NULL);
586 ut.ut_tv.tv_sec = tv.tv_sec;
587 ut.ut_tv.tv_usec = tv.tv_usec;
590 if (!pututxline (&ut))
591 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
595 waitpid (child_pid, &return_code, 0);
599 if (g_strcmp0 (class, XDG_SESSION_CLASS_GREETER) != 0)
604 memset (&ut, 0, sizeof (ut));
605 ut.ut_type = DEAD_PROCESS;
606 ut.ut_pid = child_pid;
607 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
608 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
609 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
611 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
612 else if (remote_host_name)
613 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
614 gettimeofday (&tv, NULL);
615 ut.ut_tv.tv_sec = tv.tv_sec;
616 ut.ut_tv.tv_usec = tv.tv_usec;
619 if (!pututxline (&ut))
620 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
625 /* Remove X authority */
628 gboolean drop_privileges, result;
629 GError *error = NULL;
631 drop_privileges = geteuid () == 0;
633 privileges_drop (user);
634 result = xauth_write (xauthority, XAUTH_WRITE_MODE_REMOVE, xauth_filename, &error);
636 privileges_reclaim ();
639 g_printerr ("Error removing X authority: %s\n", error->message);
640 g_clear_error (&error);
642 _exit (EXIT_FAILURE);
645 /* Close the Console Kit session */
646 if (console_kit_cookie)
647 ck_close_session (console_kit_cookie);
649 /* Close the session */
650 pam_close_session (pam_handle, 0);
652 /* Remove credentials */
653 result = pam_setcred (pam_handle, PAM_DELETE_CRED);
655 pam_end (pam_handle, 0);
658 /* Return result of session process to the daemon */