15 #include <security/pam_appl.h>
20 #include "configuration.h"
21 #include "session-child.h"
24 #include "privileges.h"
25 #include "x-authority.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);
175 gchar *x_authority_name;
176 guint16 x_authority_family;
177 guint8 *x_authority_address;
178 gsize x_authority_address_length;
179 gchar *x_authority_number;
180 guint8 *x_authority_data;
181 gsize x_authority_data_length;
183 x_authority_name = read_string ();
184 if (!x_authority_name)
187 read_data (&x_authority_family, sizeof (x_authority_family));
188 read_data (&x_authority_address_length, sizeof (x_authority_address_length));
189 x_authority_address = g_malloc (x_authority_address_length);
190 read_data (x_authority_address, x_authority_address_length);
191 x_authority_number = read_string ();
192 read_data (&x_authority_data_length, sizeof (x_authority_data_length));
193 x_authority_data = g_malloc (x_authority_data_length);
194 read_data (x_authority_data, x_authority_data_length);
196 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);
199 /* GNU provides this but we can't rely on that so let's make our own version */
201 updwtmpx (const gchar *wtmp_file, struct utmpx *ut)
205 memset (&u, 0, sizeof (u));
206 u.ut_type = ut->ut_type;
207 u.ut_pid = ut->ut_pid;
209 strncpy (u.ut_line, ut->ut_line, sizeof (u.ut_line));
211 strncpy (u.ut_id, ut->ut_id, sizeof (u.ut_id));
213 strncpy (u.ut_user, ut->ut_user, sizeof (u.ut_user));
215 strncpy (u.ut_host, ut->ut_host, sizeof (u.ut_host));
216 u.ut_tv.tv_sec = ut->ut_tv.tv_sec;
217 u.ut_tv.tv_usec = ut->ut_tv.tv_usec;
219 updwtmp (wtmp_file, &u);
223 session_child_run (int argc, char **argv)
225 struct pam_conv conversation = { pam_conv_cb, NULL };
226 int i, version, fd, result;
227 gboolean auth_complete = TRUE;
229 gchar *log_filename, *log_backup_filename = NULL;
232 gchar **command_argv;
234 int authentication_result;
235 gchar *authentication_result_string;
239 gchar *remote_host_name;
241 XAuthority *x_authority = NULL;
242 gchar *x_authority_filename;
243 const gchar *login1_session = NULL;
244 const gchar *locale_value;
246 static const gchar * const locale_var_names[] = {
259 const gchar *home_directory;
261 #if !defined(GLIB_VERSION_2_36)
265 if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
267 /* Protect memory from being paged to disk, as we deal with passwords */
268 mlockall (MCL_CURRENT | MCL_FUTURE);
271 /* Make input non-blocking */
272 fd = open ("/dev/null", O_RDONLY);
273 dup2 (fd, STDIN_FILENO);
277 fd = open ("/dev/null", O_WRONLY);
278 dup2 (fd, STDOUT_FILENO);
281 /* Get the pipe from the daemon */
284 g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
287 from_daemon_output = atoi (argv[2]);
288 to_daemon_input = atoi (argv[3]);
289 if (from_daemon_output == 0 || to_daemon_input == 0)
291 g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
295 /* Don't let these pipes leak to the command we will run */
296 fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
297 fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
299 /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
300 read_data (&version, sizeof (version));
302 service = read_string ();
303 username = read_string ();
304 read_data (&do_authenticate, sizeof (do_authenticate));
305 read_data (&is_interactive, sizeof (is_interactive));
306 read_string (); /* Used to be class, now we just use the environment variable */
307 tty = read_string ();
308 remote_host_name = read_string ();
309 xdisplay = read_string ();
310 x_authority = read_xauth ();
313 result = pam_start (service, username, &conversation, &pam_handle);
314 if (result != PAM_SUCCESS)
316 g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
322 pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
324 pam_set_item (pam_handle, PAM_TTY, xdisplay);
327 pam_set_item (pam_handle, PAM_TTY, tty);
332 struct pam_xauth_data value;
334 value.name = (char *) x_authority_get_authorization_name (x_authority);
335 value.namelen = strlen (x_authority_get_authorization_name (x_authority));
336 value.data = (char *) x_authority_get_authorization_data (x_authority);
337 value.datalen = x_authority_get_authorization_data_length (x_authority);
338 pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
345 const gchar *new_username;
347 authentication_result = pam_authenticate (pam_handle, 0);
349 /* See what user we ended up as */
350 if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
352 pam_end (pam_handle, 0);
356 username = g_strdup (new_username);
358 /* Write record to btmp database */
359 if (authentication_result == PAM_AUTH_ERR)
364 memset (&ut, 0, sizeof (ut));
365 ut.ut_type = USER_PROCESS;
366 ut.ut_pid = getpid ();
369 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
370 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
373 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
374 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
376 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
377 else if (remote_host_name)
378 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
379 gettimeofday (&tv, NULL);
380 ut.ut_tv.tv_sec = tv.tv_sec;
381 ut.ut_tv.tv_usec = tv.tv_usec;
383 updwtmpx ("/var/log/btmp", &ut);
386 /* Check account is valid */
387 if (authentication_result == PAM_SUCCESS)
388 authentication_result = pam_acct_mgmt (pam_handle, 0);
389 if (authentication_result == PAM_NEW_AUTHTOK_REQD)
390 authentication_result = pam_chauthtok (pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
393 authentication_result = PAM_SUCCESS;
394 authentication_complete = TRUE;
396 if (authentication_result == PAM_SUCCESS)
398 /* Fail authentication if user doesn't actually exist */
399 user = accounts_get_user_by_name (username);
402 g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
403 authentication_result = PAM_USER_UNKNOWN;
407 /* Set POSIX variables */
408 pam_putenv (pam_handle, "PATH=/usr/local/bin:/usr/bin:/bin");
409 pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
410 pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
411 pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
412 pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
414 /* Let the greeter and user session inherit the system default locale */
415 for (i = 0; locale_var_names[i] != NULL; i++)
417 if ((locale_value = g_getenv (locale_var_names[i])) != NULL)
419 locale_var = g_strdup_printf ("%s=%s", locale_var_names[i], locale_value);
420 pam_putenv (pam_handle, locale_var);
427 authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
429 /* Report authentication result */
430 write_string (username);
431 write_data (&auth_complete, sizeof (auth_complete));
432 write_data (&authentication_result, sizeof (authentication_result));
433 write_string (authentication_result_string);
435 /* Check we got a valid user */
438 g_printerr ("No user selected during authentication\n");
439 pam_end (pam_handle, 0);
443 /* Stop if we didn't authenticated */
444 if (authentication_result != PAM_SUCCESS)
446 pam_end (pam_handle, 0);
450 /* Get the command to run (blocks) */
451 log_filename = read_string ();
455 tty = read_string ();
457 x_authority_filename = read_string ();
461 xdisplay = read_string ();
463 g_object_unref (x_authority);
464 x_authority = read_xauth ();
466 read_data (&env_length, sizeof (env_length));
467 for (i = 0; i < env_length; i++)
468 pam_putenv (pam_handle, read_string ());
469 read_data (&command_argc, sizeof (command_argc));
470 command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
471 for (i = 0; i < command_argc; i++)
472 command_argv[i] = read_string ();
473 command_argv[i] = NULL;
475 /* If nothing to run just refresh credentials because we successfully authenticated */
476 if (command_argc == 0)
478 pam_setcred (pam_handle, PAM_REINITIALIZE_CRED);
479 pam_end (pam_handle, 0);
483 /* Redirect stderr to a log file */
486 log_backup_filename = g_strdup_printf ("%s.old", log_filename);
487 if (g_path_is_absolute (log_filename))
489 rename (log_filename, log_backup_filename);
490 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
491 dup2 (fd, STDERR_FILENO);
493 g_free (log_filename);
499 fd = open ("/dev/null", O_WRONLY);
500 dup2 (fd, STDERR_FILENO);
504 /* Set group membership - these can be overriden in pam_setcred */
507 if (initgroups (username, user_get_gid (user)) < 0)
509 g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
510 _exit (EXIT_FAILURE);
514 /* Set credentials */
515 result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
516 if (result != PAM_SUCCESS)
518 g_printerr ("Failed to establish PAM credentials: %s\n", pam_strerror (pam_handle, result));
519 pam_end (pam_handle, 0);
523 /* Open the session */
524 result = pam_open_session (pam_handle, 0);
525 if (result != PAM_SUCCESS)
527 g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
528 pam_end (pam_handle, 0);
532 /* Check what logind session we are, or fallback to ConsoleKit */
533 login1_session = pam_getenv (pam_handle, "XDG_SESSION_ID");
536 write_string (login1_session);
537 /* Write what was a ConsoleKit cookie */
545 /* Write what was a ConsoleKit cookie */
549 /* Write X authority */
552 gboolean drop_privileges, result;
554 GError *error = NULL;
556 drop_privileges = geteuid () == 0;
558 privileges_drop (user_get_uid (user), user_get_gid (user));
559 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REPLACE, x_authority_filename, &error);
561 privileges_reclaim ();
564 g_printerr ("Error writing X authority: %s\n", error->message);
565 g_clear_error (&error);
568 pam_end (pam_handle, 0);
572 value = g_strdup_printf ("XAUTHORITY=%s", x_authority_filename);
573 pam_putenv (pam_handle, value);
577 /* Catch terminate signal and pass it to the child */
578 signal (SIGTERM, signal_cb);
580 /* Run the command as the authenticated user */
581 uid = user_get_uid (user);
582 gid = user_get_gid (user);
583 home_directory = user_get_home_directory (user);
587 /* Make this process its own session */
591 /* Change to this user */
594 if (setgid (gid) != 0)
597 if (setuid (uid) != 0)
601 /* Change working directory */
602 /* NOTE: This must be done after the permissions are changed because NFS filesystems can
603 * be setup so the local root user accesses the NFS files as 'nobody'. If the home directories
604 * are not system readable then the chdir can fail */
605 if (chdir (home_directory) != 0)
610 rename (log_filename, log_backup_filename);
611 fd = open (log_filename, O_WRONLY | O_APPEND | O_CREAT, 0600);
614 dup2 (fd, STDERR_FILENO);
619 /* Run the command */
620 execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
621 _exit (EXIT_FAILURE);
624 /* Bail out if failed to fork */
627 g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
628 return_code = EXIT_FAILURE;
631 /* Wait for the command to complete (blocks) */
635 if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
640 memset (&ut, 0, sizeof (ut));
641 ut.ut_type = USER_PROCESS;
642 ut.ut_pid = child_pid;
645 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
646 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
649 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
650 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
652 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
653 else if (remote_host_name)
654 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
655 gettimeofday (&tv, NULL);
656 ut.ut_tv.tv_sec = tv.tv_sec;
657 ut.ut_tv.tv_usec = tv.tv_usec;
659 /* Write records to utmp/wtmp databases */
661 if (!pututxline (&ut))
662 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
664 updwtmpx ("/var/log/wtmp", &ut);
667 waitpid (child_pid, &return_code, 0);
671 if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
676 memset (&ut, 0, sizeof (ut));
677 ut.ut_type = DEAD_PROCESS;
678 ut.ut_pid = child_pid;
681 strncpy (ut.ut_line, xdisplay, sizeof (ut.ut_line));
682 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
685 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
686 strncpy (ut.ut_user, username, sizeof (ut.ut_user));
688 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
689 else if (remote_host_name)
690 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
691 gettimeofday (&tv, NULL);
692 ut.ut_tv.tv_sec = tv.tv_sec;
693 ut.ut_tv.tv_usec = tv.tv_usec;
695 /* Write records to utmp/wtmp databases */
697 if (!pututxline (&ut))
698 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
700 updwtmpx ("/var/log/wtmp", &ut);
704 /* Remove X authority */
707 gboolean drop_privileges, result;
708 GError *error = NULL;
710 drop_privileges = geteuid () == 0;
712 privileges_drop (user_get_uid (user), user_get_gid (user));
713 result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REMOVE, x_authority_filename, &error);
715 privileges_reclaim ();
718 g_printerr ("Error removing X authority: %s\n", error->message);
719 g_clear_error (&error);
721 _exit (EXIT_FAILURE);
724 /* Close the session */
725 pam_close_session (pam_handle, 0);
727 /* Remove credentials */
728 result = pam_setcred (pam_handle, PAM_DELETE_CRED);
730 pam_end (pam_handle, 0);
733 /* Return result of session process to the daemon */