1 #include <config.h>
2 
3 #include <stdlib.h>
4 #include <stdio.h>
5 #include <unistd.h>
6 #include <string.h>
7 #include <errno.h>
8 #include <sys/types.h>
9 #include <sys/stat.h>
10 #include <sys/wait.h>
11 #include <fcntl.h>
12 #include <pwd.h>
13 #include <grp.h>
14 #include <glib.h>
15 #include <security/pam_appl.h>
16 #include <utmpx.h>
17 #include <sys/mman.h>
18 
19 #if HAVE_LIBAUDIT
20 #include <libaudit.h>
21 #endif
22 
23 #include "configuration.h"
24 #include "session-child.h"
25 #include "session.h"
26 #include "console-kit.h"
27 #include "login1.h"
28 #include "log-file.h"
29 #include "privileges.h"
30 #include "x-authority.h"
31 #include "configuration.h"
32 
33 /* Child process being run */
34 static GPid child_pid = 0;
35 
36 /* Pipe to communicate with daemon */
37 static int from_daemon_output = 0;
38 static int to_daemon_input = 0;
39 
40 static gboolean is_interactive;
41 static gboolean do_authenticate;
42 static gboolean authentication_complete = FALSE;
43 static pam_handle_t *pam_handle;
44 
45 /* Maximum length of a string to pass between daemon and session */
46 #define MAX_STRING_LENGTH 65535
47 
48 static void
write_data(const void * buf,size_t count)49 write_data (const void *buf, size_t count)
50 {
51     if (write (to_daemon_input, buf, count) != count)
52         g_printerr ("Error writing to daemon: %s\n", strerror (errno));
53 }
54 
55 static void
write_string(const char * value)56 write_string (const char *value)
57 {
58     int length = value ? strlen (value) : -1;
59     write_data (&length, sizeof (length));
60     if (value)
61         write_data (value, sizeof (char) * length);
62 }
63 
64 static ssize_t
read_data(void * buf,size_t count)65 read_data (void *buf, size_t count)
66 {
67     ssize_t n_read = read (from_daemon_output, buf, count);
68     if (n_read < 0)
69         g_printerr ("Error reading from daemon: %s\n", strerror (errno));
70 
71     return n_read;
72 }
73 
74 static gchar *
read_string_full(void * (* alloc_fn)(size_t n))75 read_string_full (void* (*alloc_fn)(size_t n))
76 {
77     int length;
78     if (read_data (&length, sizeof (length)) <= 0)
79         return NULL;
80     if (length < 0)
81         return NULL;
82     if (length > MAX_STRING_LENGTH)
83     {
84         g_printerr ("Invalid string length %d from daemon\n", length);
85         return NULL;
86     }
87 
88     gchar *value = (*alloc_fn) (sizeof (gchar) * (length + 1));
89     read_data (value, length);
90     value[length] = '\0';
91 
92     return value;
93 }
94 
95 static gchar *
read_string(void)96 read_string (void)
97 {
98     return read_string_full (g_malloc);
99 }
100 
101 static int
pam_conv_cb(int msg_length,const struct pam_message ** msg,struct pam_response ** resp,void * app_data)102 pam_conv_cb (int msg_length, const struct pam_message **msg, struct pam_response **resp, void *app_data)
103 {
104     /* FIXME: We don't support communication after pam_authenticate completes */
105     if (authentication_complete)
106         return PAM_SUCCESS;
107 
108     /* Cancel authentication if requiring input */
109     if (!is_interactive)
110     {
111         for (int i = 0; i < msg_length; i++)
112         {
113             if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON || msg[i]->msg_style == PAM_PROMPT_ECHO_OFF)
114             {
115                 g_printerr ("Stopping PAM conversation, interaction requested but not supported\n");
116                 return PAM_CONV_ERR;
117             }
118         }
119 
120         /* Ignore informational messages */
121         return PAM_SUCCESS;
122     }
123 
124     /* Check if we changed user */
125     gchar *username = NULL;
126     pam_get_item (pam_handle, PAM_USER, (const void **) &username);
127 
128     /* Notify the daemon */
129     write_string (username);
130     gboolean auth_complete = FALSE;
131     write_data (&auth_complete, sizeof (auth_complete));
132     write_data (&msg_length, sizeof (msg_length));
133     for (int i = 0; i < msg_length; i++)
134     {
135         const struct pam_message *m = msg[i];
136         write_data (&m->msg_style, sizeof (m->msg_style));
137         write_string (m->msg);
138     }
139 
140     /* Get response */
141     int error;
142     read_data (&error, sizeof (error));
143     if (error != PAM_SUCCESS)
144         return error;
145     struct pam_response *response = calloc (msg_length, sizeof (struct pam_response));
146     for (int i = 0; i < msg_length; i++)
147     {
148         struct pam_response *r = &response[i];
149         // callers of this function inside pam will expect to be able to call
150         // free() on the strings we give back.  So alloc with malloc.
151         r->resp = read_string_full (malloc);
152         read_data (&r->resp_retcode, sizeof (r->resp_retcode));
153     }
154 
155     *resp = response;
156     return PAM_SUCCESS;
157 }
158 
159 static void
signal_cb(int signum)160 signal_cb (int signum)
161 {
162     /* Pass on signal to child, otherwise just quit */
163     if (child_pid > 0)
164         kill (child_pid, signum);
165     else
166         exit (EXIT_SUCCESS);
167 }
168 
169 static XAuthority *
read_xauth(void)170 read_xauth (void)
171 {
172     g_autofree gchar *x_authority_name = read_string ();
173     if (!x_authority_name)
174         return NULL;
175 
176     guint16 x_authority_family;
177     read_data (&x_authority_family, sizeof (x_authority_family));
178 
179     gsize x_authority_address_length;
180     read_data (&x_authority_address_length, sizeof (x_authority_address_length));
181     g_autofree guint8 *x_authority_address = g_malloc (x_authority_address_length);
182     read_data (x_authority_address, x_authority_address_length);
183 
184     g_autofree gchar *x_authority_number = read_string ();
185 
186     gsize x_authority_data_length;
187     read_data (&x_authority_data_length, sizeof (x_authority_data_length));
188     g_autofree guint8 *x_authority_data = g_malloc (x_authority_data_length);
189     read_data (x_authority_data, x_authority_data_length);
190 
191     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);
192 }
193 
194 #if HAVE_LIBAUDIT
195 static void
audit_event(int type,const gchar * username,uid_t uid,const gchar * remote_host_name,const gchar * tty,gboolean success)196 audit_event (int type, const gchar *username, uid_t uid, const gchar *remote_host_name, const gchar *tty, gboolean success)
197 {
198     int auditfd = audit_open ();
199     if (auditfd < 0) {
200         g_printerr ("Error opening audit socket: %s\n", strerror (errno));
201         return;
202     }
203 
204     const char *op = NULL;
205     if (type == AUDIT_USER_LOGIN)
206         op = "login";
207     else if (type == AUDIT_USER_LOGOUT)
208         op = "logout";
209     int result = success == TRUE ? 1 : 0;
210 
211     if (audit_log_acct_message (auditfd, type, NULL, op, username, uid, remote_host_name, NULL, tty, result) <= 0)
212         g_printerr ("Error writing audit message: %s\n", strerror (errno));
213 
214     close (auditfd);
215 }
216 #endif
217 
218 int
session_child_run(int argc,char ** argv)219 session_child_run (int argc, char **argv)
220 {
221 #if !defined(GLIB_VERSION_2_36)
222     g_type_init ();
223 #endif
224 
225     if (config_get_boolean (config_get_instance (), "LightDM", "lock-memory"))
226     {
227         /* Protect memory from being paged to disk, as we deal with passwords */
228         mlockall (MCL_CURRENT | MCL_FUTURE);
229     }
230 
231     /* Make input non-blocking */
232     int fd = open ("/dev/null", O_RDONLY);
233     dup2 (fd, STDIN_FILENO);
234     close (fd);
235 
236     /* Close stdout */
237     fd = open ("/dev/null", O_WRONLY);
238     dup2 (fd, STDOUT_FILENO);
239     close (fd);
240 
241     /* Get the pipe from the daemon */
242     if (argc != 4)
243     {
244         g_printerr ("Usage: lightdm --session-child INPUTFD OUTPUTFD\n");
245         return EXIT_FAILURE;
246     }
247     from_daemon_output = atoi (argv[2]);
248     to_daemon_input = atoi (argv[3]);
249     if (from_daemon_output == 0 || to_daemon_input == 0)
250     {
251         g_printerr ("Invalid file descriptors %s %s\n", argv[2], argv[3]);
252         return EXIT_FAILURE;
253     }
254 
255     /* Don't let these pipes leak to the command we will run */
256     fcntl (from_daemon_output, F_SETFD, FD_CLOEXEC);
257     fcntl (to_daemon_input, F_SETFD, FD_CLOEXEC);
258 
259     /* Read a version number so we can handle upgrades (i.e. a newer version of session child is run for an old daemon */
260     int version;
261     read_data (&version, sizeof (version));
262 
263     g_autofree gchar *service = read_string ();
264     g_autofree gchar *username = read_string ();
265     read_data (&do_authenticate, sizeof (do_authenticate));
266     read_data (&is_interactive, sizeof (is_interactive));
267     g_autofree gchar *unused_class = read_string (); /* Used to be class, now we just use the environment variable */
268     g_autofree gchar *tty = read_string ();
269     g_autofree gchar *remote_host_name = read_string ();
270     g_autofree gchar *xdisplay = read_string ();
271     g_autoptr(XAuthority) x_authority = read_xauth ();
272 
273     /* Setup PAM */
274     struct pam_conv conversation = { pam_conv_cb, NULL };
275     int result = pam_start (service, username, &conversation, &pam_handle);
276     if (result != PAM_SUCCESS)
277     {
278         g_printerr ("Failed to start PAM: %s", pam_strerror (NULL, result));
279         return EXIT_FAILURE;
280     }
281     if (xdisplay)
282     {
283 #ifdef PAM_XDISPLAY
284         pam_set_item (pam_handle, PAM_XDISPLAY, xdisplay);
285 #endif
286         pam_set_item (pam_handle, PAM_TTY, xdisplay);
287     }
288     else if (tty)
289         pam_set_item (pam_handle, PAM_TTY, tty);
290 
291 #ifdef PAM_XAUTHDATA
292     if (x_authority)
293     {
294         struct pam_xauth_data value;
295 
296         value.name = (char *) x_authority_get_authorization_name (x_authority);
297         value.namelen = strlen (x_authority_get_authorization_name (x_authority));
298         value.data = (char *) x_authority_get_authorization_data (x_authority);
299         value.datalen = x_authority_get_authorization_data_length (x_authority);
300         pam_set_item (pam_handle, PAM_XAUTHDATA, &value);
301     }
302 #endif
303 
304     /* Authenticate */
305     int authentication_result = PAM_SUCCESS;
306     if (do_authenticate)
307     {
308         const gchar *new_username;
309 
310         authentication_result = pam_authenticate (pam_handle, 0);
311 
312         /* See what user we ended up as */
313         if (pam_get_item (pam_handle, PAM_USER, (const void **) &new_username) != PAM_SUCCESS)
314         {
315             pam_end (pam_handle, 0);
316             return EXIT_FAILURE;
317         }
318         g_free (username);
319         username = g_strdup (new_username);
320 
321         /* Write record to btmp database */
322         if (authentication_result == PAM_AUTH_ERR)
323         {
324             struct utmpx ut;
325             struct timeval tv;
326 
327             memset (&ut, 0, sizeof (ut));
328             ut.ut_type = USER_PROCESS;
329             ut.ut_pid = getpid ();
330             if (xdisplay)
331                 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
332             if (tty && g_str_has_prefix (tty, "/dev/"))
333                 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
334             strncpy (ut.ut_user, username, sizeof (ut.ut_user));
335             if (xdisplay)
336                 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
337             else if (remote_host_name)
338                 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
339             gettimeofday (&tv, NULL);
340             ut.ut_tv.tv_sec = tv.tv_sec;
341             ut.ut_tv.tv_usec = tv.tv_usec;
342 
343 
344 #if HAVE_LIBAUDIT
345             audit_event (AUDIT_USER_LOGIN, username, -1, remote_host_name, tty, FALSE);
346 #endif
347         }
348 
349         /* Check account is valid */
350         if (authentication_result == PAM_SUCCESS)
351             authentication_result = pam_acct_mgmt (pam_handle, 0);
352         if (authentication_result == PAM_NEW_AUTHTOK_REQD)
353             authentication_result = pam_chauthtok (pam_handle, PAM_CHANGE_EXPIRED_AUTHTOK);
354     }
355     else
356         authentication_result = PAM_SUCCESS;
357     authentication_complete = TRUE;
358 
359     User *user = NULL;
360     if (authentication_result == PAM_SUCCESS)
361     {
362         /* Fail authentication if user doesn't actually exist */
363         user = accounts_get_user_by_name (username);
364         if (!user)
365         {
366             g_printerr ("Failed to get information on user %s: %s\n", username, strerror (errno));
367             authentication_result = PAM_USER_UNKNOWN;
368         }
369         else
370         {
371             /* Set POSIX variables */
372             pam_putenv (pam_handle, "PATH=/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:~/bin");
373             pam_putenv (pam_handle, g_strdup_printf ("USER=%s", username));
374             pam_putenv (pam_handle, g_strdup_printf ("LOGNAME=%s", username));
375             pam_putenv (pam_handle, g_strdup_printf ("HOME=%s", user_get_home_directory (user)));
376             pam_putenv (pam_handle, g_strdup_printf ("SHELL=%s", user_get_shell (user)));
377 
378             /* Let the greeter and user session inherit the system default locale */
379             static const gchar * const locale_var_names[] = {
380                 "LC_PAPER",
381                 "LC_NAME",
382                 "LC_ADDRESS",
383                 "LC_TELEPHONE",
384                 "LC_MEASUREMENT",
385                 "LC_IDENTIFICATION",
386                 "LC_COLLATE",
387                 "LC_CTYPE",
388                 "LC_MONETARY",
389                 "LC_NUMERIC",
390                 "LC_TIME",
391                 "LC_MESSAGES",
392                 "LC_ALL",
393                 "LANG",
394                 NULL
395             };
396             for (int i = 0; locale_var_names[i] != NULL; i++)
397             {
398                 const gchar *locale_value;
399                 if ((locale_value = g_getenv (locale_var_names[i])) != NULL)
400                 {
401                     g_autofree gchar *locale_var = g_strdup_printf ("%s=%s", locale_var_names[i], locale_value);
402                     pam_putenv (pam_handle, locale_var);
403                 }
404             }
405         }
406     }
407 
408     g_autofree gchar *authentication_result_string = g_strdup (pam_strerror (pam_handle, authentication_result));
409 
410     /* Report authentication result */
411     write_string (username);
412     gboolean auth_complete = TRUE;
413     write_data (&auth_complete, sizeof (auth_complete));
414     write_data (&authentication_result, sizeof (authentication_result));
415     write_string (authentication_result_string);
416 
417     /* Check we got a valid user */
418     if (!username)
419     {
420         g_printerr ("No user selected during authentication\n");
421         pam_end (pam_handle, 0);
422         return EXIT_FAILURE;
423     }
424 
425     /* Stop if we didn't authenticated */
426     if (authentication_result != PAM_SUCCESS)
427     {
428         pam_end (pam_handle, 0);
429         return EXIT_FAILURE;
430     }
431 
432     /* Get the command to run (blocks) */
433     g_autofree gchar *log_filename = read_string ();
434     LogMode log_mode = LOG_MODE_BACKUP_AND_TRUNCATE;
435     if (version >= 3)
436         read_data (&log_mode, sizeof (log_mode));
437     if (version >= 1)
438     {
439         g_free (tty);
440         tty = read_string ();
441     }
442     g_autofree gchar *x_authority_filename = read_string ();
443     if (version >= 1)
444     {
445         g_free (xdisplay);
446         xdisplay = read_string ();
447         g_clear_object (&x_authority);
448         x_authority = read_xauth ();
449     }
450     gsize env_length;
451     read_data (&env_length, sizeof (env_length));
452     for (int i = 0; i < env_length; i++)
453         pam_putenv (pam_handle, read_string ());
454     gsize command_argc;
455     read_data (&command_argc, sizeof (command_argc));
456     g_auto(GStrv) command_argv = g_malloc (sizeof (gchar *) * (command_argc + 1));
457     int i;
458     for (i = 0; i < command_argc; i++)
459         command_argv[i] = read_string ();
460     command_argv[i] = NULL;
461 
462     /* If nothing to run just refresh credentials because we successfully authenticated */
463     if (command_argc == 0)
464     {
465         pam_setcred (pam_handle, PAM_REINITIALIZE_CRED);
466         pam_end (pam_handle, 0);
467         return EXIT_SUCCESS;
468     }
469 
470     /* Redirect stderr to a log file */
471     if (log_filename)
472     {
473         if (g_path_is_absolute (log_filename))
474         {
475             int fd = log_file_open (log_filename, log_mode);
476             dup2 (fd, STDERR_FILENO);
477             close (fd);
478             g_clear_pointer (&log_filename, g_free);
479         }
480     }
481     else
482     {
483         int fd = open ("/dev/null", O_WRONLY);
484         dup2 (fd, STDERR_FILENO);
485         close (fd);
486     }
487 
488     /* Set group membership - these can be overridden in pam_setcred */
489     if (getuid () == 0)
490     {
491         if (initgroups (username, user_get_gid (user)) < 0)
492         {
493             g_printerr ("Failed to initialize supplementary groups for %s: %s\n", username, strerror (errno));
494             _exit (EXIT_FAILURE);
495         }
496     }
497 
498     /* Set credentials */
499     result = pam_setcred (pam_handle, PAM_ESTABLISH_CRED);
500     if (result != PAM_SUCCESS)
501     {
502         g_printerr ("Failed to establish PAM credentials: %s\n", pam_strerror (pam_handle, result));
503         pam_end (pam_handle, 0);
504         return EXIT_FAILURE;
505     }
506 
507     /* Open the session */
508     result = pam_open_session (pam_handle, 0);
509     if (result != PAM_SUCCESS)
510     {
511         g_printerr ("Failed to open PAM session: %s\n", pam_strerror (pam_handle, result));
512         pam_end (pam_handle, 0);
513         return EXIT_FAILURE;
514     }
515 
516     /* Open a connection to the system bus for ConsoleKit - we must keep it open or CK will close the session */
517     g_autoptr(GError) error = NULL;
518     g_autoptr(GDBusConnection) bus = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, &error);
519     if (error)
520         g_printerr ("Unable to contact system bus: %s", error->message);
521     if (!bus)
522     {
523         pam_end (pam_handle, 0);
524         return EXIT_FAILURE;
525     }
526 
527     /* Check what logind session we are, or fallback to ConsoleKit */
528     const gchar *login1_session_id = pam_getenv (pam_handle, "XDG_SESSION_ID");
529     g_autofree gchar *console_kit_cookie = NULL;
530     if (login1_session_id)
531     {
532         write_string (login1_session_id);
533         if (version >= 2)
534             write_string (NULL);
535     }
536     else
537     {
538         GVariantBuilder ck_parameters;
539         g_variant_builder_init (&ck_parameters, G_VARIANT_TYPE ("(a(sv))"));
540         g_variant_builder_open (&ck_parameters, G_VARIANT_TYPE ("a(sv)"));
541         g_variant_builder_add (&ck_parameters, "(sv)", "unix-user", g_variant_new_int32 (user_get_uid (user)));
542         if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") == 0)
543             g_variant_builder_add (&ck_parameters, "(sv)", "session-type", g_variant_new_string ("LoginWindow"));
544         if (xdisplay)
545         {
546             g_variant_builder_add (&ck_parameters, "(sv)", "x11-display", g_variant_new_string (xdisplay));
547             if (tty)
548                 g_variant_builder_add (&ck_parameters, "(sv)", "x11-display-device", g_variant_new_string (tty));
549         }
550         if (remote_host_name)
551         {
552             g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (FALSE));
553             g_variant_builder_add (&ck_parameters, "(sv)", "remote-host-name", g_variant_new_string (remote_host_name));
554         }
555         else
556             g_variant_builder_add (&ck_parameters, "(sv)", "is-local", g_variant_new_boolean (TRUE));
557         console_kit_cookie = ck_open_session (&ck_parameters);
558         if (version >= 2)
559             write_string (NULL);
560         write_string (console_kit_cookie);
561         if (console_kit_cookie)
562         {
563             g_autofree gchar *value = NULL;
564             g_autofree gchar *runtime_dir = NULL;
565             value = g_strdup_printf ("XDG_SESSION_COOKIE=%s", console_kit_cookie);
566             pam_putenv (pam_handle, value);
567 
568             runtime_dir = ck_get_xdg_runtime_dir (console_kit_cookie);
569             if (runtime_dir)
570             {
571                 g_autofree gchar *v = g_strdup_printf ("XDG_RUNTIME_DIR=%s", runtime_dir);
572                 pam_putenv (pam_handle, v);
573             }
574         }
575     }
576 
577     /* Write X authority */
578     if (x_authority)
579     {
580         gboolean drop_privileges = geteuid () == 0;
581         if (drop_privileges)
582             privileges_drop (user_get_uid (user), user_get_gid (user));
583 
584         g_autoptr(GError) error = NULL;
585         gboolean result = x_authority_write (x_authority, XAUTH_WRITE_MODE_REPLACE, x_authority_filename, &error);
586         if (drop_privileges)
587             privileges_reclaim ();
588 
589         if (error)
590             g_printerr ("Error writing X authority: %s\n", error->message);
591         if (!result)
592         {
593             pam_end (pam_handle, 0);
594             return EXIT_FAILURE;
595         }
596 
597         g_autofree gchar *value = g_strdup_printf ("XAUTHORITY=%s", x_authority_filename);
598         pam_putenv (pam_handle, value);
599     }
600 
601     /* Catch terminate signal and pass it to the child */
602     signal (SIGTERM, signal_cb);
603 
604     /* Run the command as the authenticated user */
605     uid_t uid = user_get_uid (user);
606     gid_t gid = user_get_gid (user);
607     const gchar *home_directory = user_get_home_directory (user);
608     child_pid = fork ();
609     if (child_pid == 0)
610     {
611         /* Make this process its own session */
612         if (setsid () < 0)
613             _exit (errno);
614 
615         /* Change to this user */
616         if (getuid () == 0)
617         {
618             if (setgid (gid) != 0)
619                 _exit (errno);
620 
621             if (setuid (uid) != 0)
622                 _exit (errno);
623         }
624 
625         /* Change working directory */
626         /* NOTE: This must be done after the permissions are changed because NFS filesystems can
627          * be setup so the local root user accesses the NFS files as 'nobody'.  If the home directories
628          * are not system readable then the chdir can fail */
629         if (chdir (home_directory) != 0)
630             _exit (errno);
631 
632         if (log_filename)
633         {
634             int fd = log_file_open (log_filename, log_mode);
635             if (fd >= 0)
636             {
637                 dup2 (fd, STDERR_FILENO);
638                 close (fd);
639             }
640         }
641 
642         /* Reset SIGPIPE handler so the child has default behaviour (we disabled it at LightDM start) */
643         signal (SIGPIPE, SIG_DFL);
644 
645         /* Run the command */
646         execve (command_argv[0], command_argv, pam_getenvlist (pam_handle));
647         _exit (EXIT_FAILURE);
648     }
649 
650     /* Bail out if failed to fork */
651     int return_code = EXIT_SUCCESS;
652     if (child_pid < 0)
653     {
654         g_printerr ("Failed to fork session child process: %s\n", strerror (errno));
655         return_code = EXIT_FAILURE;
656     }
657 
658     /* Wait for the command to complete (blocks) */
659     if (child_pid > 0)
660     {
661         /* Log to utmp */
662         if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
663         {
664             struct utmpx ut;
665             memset (&ut, 0, sizeof (ut));
666             ut.ut_type = USER_PROCESS;
667             ut.ut_pid = child_pid;
668             if (xdisplay)
669                 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
670             if (tty && g_str_has_prefix (tty, "/dev/"))
671                 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
672             strncpy (ut.ut_user, username, sizeof (ut.ut_user));
673             if (xdisplay)
674                 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
675             else if (remote_host_name)
676                 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
677             struct timeval tv;
678             gettimeofday (&tv, NULL);
679             ut.ut_tv.tv_sec = tv.tv_sec;
680             ut.ut_tv.tv_usec = tv.tv_usec;
681 
682             /* Write records to utmp/wtmp databases */
683             setutxent ();
684             if (!pututxline (&ut))
685                 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
686             endutxent ();
687 
688 #if HAVE_LIBAUDIT
689             audit_event (AUDIT_USER_LOGIN, username, uid, remote_host_name, tty, TRUE);
690 #endif
691         }
692 
693         int child_status;
694         waitpid (child_pid, &child_status, 0);
695         child_pid = 0;
696         if (WIFEXITED (child_status))
697             return_code = WEXITSTATUS (child_status);
698         else
699             return_code = EXIT_FAILURE;
700 
701         /* Log to utmp */
702         if (g_strcmp0 (pam_getenv (pam_handle, "XDG_SESSION_CLASS"), "greeter") != 0)
703         {
704             struct utmpx ut;
705             memset (&ut, 0, sizeof (ut));
706             ut.ut_type = DEAD_PROCESS;
707             ut.ut_pid = child_pid;
708             if (xdisplay)
709                 strncpy (ut.ut_id, xdisplay, sizeof (ut.ut_id));
710             if (tty && g_str_has_prefix (tty, "/dev/"))
711                 strncpy (ut.ut_line, tty + strlen ("/dev/"), sizeof (ut.ut_line));
712             strncpy (ut.ut_user, username, sizeof (ut.ut_user));
713             if (xdisplay)
714                 strncpy (ut.ut_host, xdisplay, sizeof (ut.ut_host));
715             else if (remote_host_name)
716                 strncpy (ut.ut_host, remote_host_name, sizeof (ut.ut_host));
717             struct timeval tv;
718             gettimeofday (&tv, NULL);
719             ut.ut_tv.tv_sec = tv.tv_sec;
720             ut.ut_tv.tv_usec = tv.tv_usec;
721 
722             /* Write records to utmp/wtmp databases */
723             setutxent ();
724             if (!pututxline (&ut))
725                 g_printerr ("Failed to write utmpx: %s\n", strerror (errno));
726             endutxent ();
727 
728 #if HAVE_LIBAUDIT
729             audit_event (AUDIT_USER_LOGOUT, username, uid, remote_host_name, tty, TRUE);
730 #endif
731         }
732     }
733 
734     /* Remove X authority */
735     if (x_authority)
736     {
737         gboolean drop_privileges = geteuid () == 0;
738         if (drop_privileges)
739             privileges_drop (user_get_uid (user), user_get_gid (user));
740 
741         g_autoptr(GError) error = NULL;
742         x_authority_write (x_authority, XAUTH_WRITE_MODE_REMOVE, x_authority_filename, &error);
743         if (drop_privileges)
744             privileges_reclaim ();
745 
746         if (error)
747             g_printerr ("Error removing X authority: %s\n", error->message);
748         g_clear_error (&error);
749         /* Ignore this error, don't exit, continue closing the session. */
750     }
751 
752     /* Close the Console Kit session */
753     if (console_kit_cookie)
754         ck_close_session (console_kit_cookie);
755 
756     /* Close the session */
757     pam_close_session (pam_handle, 0);
758 
759     /* Remove credentials */
760     pam_setcred (pam_handle, PAM_DELETE_CRED);
761 
762     pam_end (pam_handle, 0);
763     pam_handle = NULL;
764 
765     /* Return result of session process to the daemon */
766     return return_code;
767 }
768