[gdm-list] GDM utmp support




Jon:

Attached please find a patch which fixes the utmp/wtmp processing quite
a bit.  When you forked D-Bus, this code was still under a lot of
development and it took quite some time to get it right.  The stable
GDM code has been reworked so it better supports how utmp/wtmp works
on a variety of platforms.

In summary, the following changes are in the patch:

+ configure.ac wasn't properly setting HAVE_GETUTXENT, etc. because it
  was using AC_CHECK_FUNC instead of AC_CHECK_FUNCS.  With this change
  it works properly.  Also, need to check for logwtmp for FreeBSD
  support.

+ The previous code was only doing wtmp/btmp processing.  This patch
  adds utmp proccessing.  Also, now utmpx.h is used in preference
  to utmp.h if found on the system, so systems using extended utmp
  are better supported.

+ This code uses #if checks to better ensure that the code compiles
  across all platforms.  For example, will use UT_NAME instead of
  UT_USER if UT_USER isn't present on the system.  Also added back
  login(), logout(), and logwtmp() #ifdef's needed by FreeBSD.

+ Support ut_tv or ut_time, based on what is supported on the system.
  Also support setting ut_syslen if supported on the system.

+ ut_type should be set to DEAD_PROCESS on logout.  The previous code
  was always setting it to USER_PROCESS.

+ ut_id is now set to x11_display_name and ut_host is now set to
  hostname and x11_display_name or just x11_display_name if hostname
  is not set.  This matches what is in stable GDM.  Unless there is
  a good reason, I think we should probably try to stay consistent
  with what people are currently using with GDM 2.20.

  If we think we should set ut_host or ut_id differently, then we
  should discuss if this should impact the GDM 2.20 code, I guess.

Brian


Index: configure.ac
===================================================================
--- configure.ac	(revision 5373)
+++ configure.ac	(working copy)
@@ -474,9 +474,10 @@
 dnl ---------------------------------------------------------------------------
 
 AC_CHECK_HEADERS(utmp.h utmpx.h libutil.h sys/param.h)
-AC_CHECK_FUNC(getutmpx updwtmpx)
+AC_CHECK_FUNCS([getutxent updwtmpx updwtmp])
 AC_CHECK_LIB(util,login)
 AC_CHECK_LIB(util,logout)
+AC_CHECK_LIB(util,logwtmp)
 GDM_CHECK_UTMP
 
 AC_MSG_CHECKING(if utmpx structure has ut_syslen field)
Index: daemon/gdm-session.c
===================================================================
--- daemon/gdm-session.c	(revision 5373)
+++ daemon/gdm-session.c	(working copy)
@@ -40,7 +40,12 @@
 #include <sys/types.h>
 #include <sys/wait.h>
 #include <unistd.h>
+
+#if defined(HAVE_UTMPX_H)
+#include <utmpx.h>
+#elif defined(HAVE_UTMP_H)
 #include <utmp.h>
+#endif
 
 #include <glib.h>
 #include <glib/gi18n.h>
@@ -179,110 +184,243 @@
 gdm_session_write_record (GdmSession           *session,
                           GdmSessionRecordType  record_type)
 {
+#if defined(HAVE_UTMPX_H)
+        struct utmpx session_record = { 0 };
+        struct utmpx *u = NULL;
+#elif defined(HAVE_UTMP_H)
         struct utmp session_record = { 0 };
+#endif
         GTimeVal now = { 0 };
-        char *hostname;
+        char *hostname, *username;
 
-        g_debug ("writing %s record",
-                 record_type == GDM_SESSION_RECORD_TYPE_LOGIN? "session" :
-                 record_type == GDM_SESSION_RECORD_TYPE_LOGOUT? "logout" :
+        g_debug ("Writing %s utmp/wtmp record",
+                 record_type == GDM_SESSION_RECORD_TYPE_LOGIN  ? "session" :
+                 record_type == GDM_SESSION_RECORD_TYPE_LOGOUT ? "logout"  :
                  "failed session attempt");
 
         if (record_type != GDM_SESSION_RECORD_TYPE_LOGOUT) {
-                /* it's possible that PAM failed before it mapped the user input
-                 * into a valid username, so we fallback to try using "(unknown)"
+                /*
+                 * It is possible that PAM failed before it mapped the user
+                 * input into a valid username, so we fallback to try using
+                 * "(unknown)"
                  */
                 if (session->priv->username != NULL)
-                        strncpy (session_record.ut_user, session->priv->username,
-                                 sizeof (session_record.ut_user));
+                         username = session->priv->username;
                 else
-                        strncpy (session_record.ut_user, "(unknown)",
-                                 sizeof (session_record.ut_user));
+                         username = "(unknown)";
+
+#if defined(HAVE_UT_UT_USER)
+                strncpy (session_record.ut_user,
+                         username,
+                         sizeof (session_record.ut_user));
+                g_debug ("using ut_user %.*s",
+                         sizeof (session_record.ut_user),
+                         session_record.ut_user);
+#elif defined(HAVE_UT_UT_NAME)
+                strncpy (session_record.ut_name,
+                         username
+                         sizeof (session_record.ut_name));
+                g_debug ("using ut_name %.*s",
+                         sizeof (session_record.ut_name),
+                         session_record.ut_name);
+#endif
         }
 
-        g_debug ("using username %.*s",
-                 sizeof (session_record.ut_user),
-                 session_record.ut_user);
+#if defined(HAVE_UT_UT_TYPE)
+        /*
+         * Set type to DEAD_PROCESS when logging out, otherwise
+         * set to USER_PROCESS.
+         */
+        if (record_type == GDM_SESSION_RECORD_TYPE_LOGOUT) {
+                session_record.ut_type = DEAD_PROCESS;
+                g_debug ("using ut_type DEAD_PROCESS");
+        } else {
+                session_record.ut_type = USER_PROCESS;
+                g_debug ("using ut_type USER_PROCESS");
+        }
+#endif
 
-        /* FIXME: I have no idea what to do for ut_id.
-         */
+#if defined(HAVE_UT_UT_PID)
+        /* Set pid */
+        if (session->priv->session_pid != 0) {
+                session_record.ut_pid = session->priv->session_pid;
+        }
+        g_debug ("using ut_pid %d", (int) session_record.ut_pid);
+#endif
+
+#if defined(HAVE_UT_UT_TV)
+        /* Set time in TV format */
+        g_get_current_time (&now);
+        session_record.ut_tv.tv_sec  = now.tv_sec;
+        session_record.ut_tv.tv_usec = now.tv_usec;
+        g_debug ("using ut_tv time %ld",
+                 (glong) session_record.ut_tv.tv_sec);
+#elif defined(HAVE_UT_UT_TIME)
+        /* Set time in time format */
+        time (&session_record.ut_time);
+        g_debug ("using ut_time %ld",
+                 (glong) session_record.ut_time);
+#endif
+
+#if defined(HAVE_UT_UT_ID)
+        /* Set ut_id to the $DISPLAY value */
         strncpy (session_record.ut_id,
-                 session->priv->display_device +
-                 strlen (session->priv->display_device) -
+                 session->priv->x11_display_name,
+                 sizeof (session_record.ut_id));
+        g_debug ("using ut_id %.*s",
                  sizeof (session_record.ut_id),
-                 sizeof (session_record.ut_id));
+                 session_record.ut_id);
+#endif
 
-        g_debug ("using id %.*s", sizeof (session_record.ut_id), session_record.ut_id);
+#if defined(HAVE_UT_UT_HOST)
+        hostname = NULL;
 
-        if (g_str_has_prefix (session->priv->display_device, "/dev/")) {
-                strncpy (session_record.ut_line,
-                         session->priv->display_device + strlen ("/dev/"),
-                         sizeof (session_record.ut_line));
-        } else if (g_str_has_prefix (session->priv->display_device, ":")) {
-                strncpy (session_record.ut_line,
-                         session->priv->display_device,
-                         sizeof (session_record.ut_line));
-        }
-
-        g_debug ("using line %.*s",
-                 sizeof (session_record.ut_line),
-                 session_record.ut_line);
-
-        /* FIXME: this is a bit of a mess. Figure out how
-         * wrong the logic is
+        /*
+         * Set ut_host to hostname:$DISPLAY if remote, otherwise set
+         * to $DISPLAY
          */
-        hostname = NULL;
         if ((session->priv->hostname != NULL) &&
-            g_str_has_prefix (session->priv->display_device, ":"))
+            g_str_has_prefix (session->priv->x11_display_name, ":"))
                 hostname = g_strdup_printf ("%s%s", session->priv->hostname,
-                                            session->priv->display_device);
-        else if ((session->priv->hostname != NULL) &&
-                 !strstr (session->priv->display_device, ":"))
-                hostname = g_strdup (session->priv->hostname);
-        else if (!g_str_has_prefix (session->priv->display_device, ":") &&
-                 strstr (session->priv->display_device, ":"))
-                hostname = g_strdup (session->priv->display_device);
+                                            session->priv->x11_display_name);
+        else
+                hostname = g_strdup (session->priv->x11_display_name);
 
         if (hostname) {
-                g_debug ("using hostname %.*s",
+                strncpy (session_record.ut_host,
+                         hostname, sizeof (session_record.ut_host));
+                g_debug ("using ut_host %.*s",
                          sizeof (session_record.ut_host),
                          session_record.ut_host);
-                strncpy (session_record.ut_host,
-                         hostname, sizeof (session_record.ut_host));
                 g_free (hostname);
+
+#ifdef HAVE_UT_UT_SYSLEN
+                session_record.ut_syslen = MIN (strlen (hostname),
+                                                sizeof (session_record.ut_host));
+#endif
         }
+#endif
 
-        g_get_current_time (&now);
-        session_record.ut_tv.tv_sec = now.tv_sec;
-        session_record.ut_tv.tv_usec = now.tv_usec;
+        /*
+         * Set ut_line to the device name associated with this display
+         * but remove the "/dev/" prefix.  If no device, then use the
+         * $DISPLAY value.
+         */
+        if (g_str_has_prefix (session->priv->display_device, "/dev/")) {
+                strncpy (session_record.ut_line,
+                         session->priv->display_device + strlen ("/dev/"),
+                         sizeof (session_record.ut_line));
+        } else if (g_str_has_prefix (session->priv->x11_display_name, ":")) {
+                strncpy (session_record.ut_line,
+                         session->priv->x11_display_name,
+                         sizeof (session_record.ut_line));
+        }
+        g_debug ("using ut_line %.*s",
+                 sizeof (session_record.ut_line),
+                 session_record.ut_line);
 
-        g_debug ("using time %ld",
-                 (glong) session_record.ut_tv.tv_sec);
+        switch (record_type) {
+        case GDM_SESSION_RECORD_TYPE_LOGIN:
 
-        session_record.ut_type = USER_PROCESS;
-        g_debug ("using type USER_PROCESS");
+                /* Handle wtmp */
+                g_debug ("Writing wtmp session record to " GDM_NEW_SESSION_RECORDS_FILE);
+#if defined(HAVE_UPDWTMPX)
+                updwtmpx (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
+#elif defined(HAVE_UPDWTMP)
+                updwtmp (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
+#elif defined(HAVE_LOGWTMP) && defined(HAVE_UT_UT_HOST) && !defined(HAVE_LOGIN)
+#if defined(HAVE_UT_UT_USER)
+                logwtmp (record.ut_line, record.ut_user, record.ut_host);
+#elif defined(HAVE_UT_UT_NAME)
+                logwtmp (record.ut_line, record.ut_name, record.ut_host);
+#endif
+#endif
 
-        if (session->priv->session_pid != 0) {
-                session_record.ut_pid = session->priv->session_pid;
-        }
+#if defined(HAVE_GETUTXENT)
+                /*
+                 * Handle utmp
+                 * Update if entry already exists
+                 */
+                while ((u = getutxent ()) != NULL) {
+                        if (u->ut_type == USER_PROCESS &&
+                           (session_record.ut_line != NULL &&
+                           (strncmp (u->ut_line, session_record.ut_line,
+                                     sizeof (u->ut_line)) == 0 ||
+                            u->ut_pid == session_record.ut_pid))) {
+                                g_debug ("Updating existing utmp record");
+                                pututxline (&session_record);
+                                break;
+                        }
+                }
+                endutxent ();
 
-        g_debug ("using pid %d", (int) session_record.ut_pid);
+                /* Add new entry if update did not work */
+                if (u == (struct utmpx *)NULL) {
+                        g_debug ("Adding new utmp record");
+                        pututxline (&session_record);
+                }
+#elif defined(HAVE_LOGIN)
+                login (&session_record);
+#endif
 
-        switch (record_type) {
-        case GDM_SESSION_RECORD_TYPE_LOGIN:
-                g_debug ("writing session record to " GDM_NEW_SESSION_RECORDS_FILE);
-                updwtmp (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
                 break;
 
         case GDM_SESSION_RECORD_TYPE_LOGOUT:
-                g_debug ("writing logout record to " GDM_NEW_SESSION_RECORDS_FILE);
+
+                /* Handle wtmp */
+                g_debug ("Writing wtmp logout record to " GDM_NEW_SESSION_RECORDS_FILE);
+#if defined(HAVE_UPDWTMPX)
+                updwtmpx (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
+#elif defined (HAVE_UPDWTMP)
                 updwtmp (GDM_NEW_SESSION_RECORDS_FILE, &session_record);
+#elif defined(HAVE_LOGWTMP)
+                logwtmp (record.ut_line, "", "");
+#endif
+
+                /* Hande utmp */
+#if defined(HAVE_GETUTXENT)
+                setutxent ();
+
+                while ((u = getutxent ()) != NULL &&
+                       (u = getutxid (&session_record)) != NULL) {
+
+                        g_debug ("Removing utmp record");
+                        if (u->ut_pid == session->priv->session_pid &&
+                            u->ut_type == DEAD_PROCESS) {
+                                /* Already done */
+                                break;
+                        }
+
+                        u->ut_type = DEAD_PROCESS;
+#if defined(HAVE_UT_UT_TV)
+                        u->ut_tv.tv_sec = session_record.ut_tv.tv_sec;
+#elif defined(HAVE_UT_UT_TIME)
+                        u->ut_time = session_record.ut_time;
+#endif
+                        u->ut_exit.e_termination = 0;
+                        u->ut_exit.e_exit = 0;
+
+                        pututxline (u);
+
+                        break;
+                }
+
+                endutxent ();
+#elif defined(HAVE_LOGOUT)
+                logout (session_record.ut_line);
+#endif
+
                 break;
 
         case GDM_SESSION_RECORD_TYPE_FAILED_ATTEMPT:
-                g_debug ("writing failed session attempt record to "
+                /* Handle btmp */
+                g_debug ("Writing btmp failed session attempt record to "
                          GDM_BAD_SESSION_RECORDS_FILE);
+#if defined(HAVE_UPDWTMPX)
+                updwtmpx (GDM_BAD_SESSION_RECORDS_FILE, &session_record);
+#elif defined(HAVE_UPDWTMP)
                 updwtmp (GDM_BAD_SESSION_RECORDS_FILE, &session_record);
+#endif
                 break;
         }
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]