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