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