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